gpgme 1.0.8

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,1561 @@
1
+ =begin rdoc
2
+ = What's this?
3
+
4
+ Ruby-GPGME is a Ruby language binding of GPGME (GnuPG Made Easy).
5
+
6
+ = Requirements
7
+
8
+ - Ruby 1.8 or later
9
+ - GPGME 1.1.2 or later http://www.gnupg.org/(en)/related_software/gpgme/index.html
10
+ - gpg-agent (optional, but recommended)
11
+
12
+ = Installation
13
+
14
+ $ gem install ruby-gpgme
15
+
16
+ or
17
+
18
+ $ ruby extconf.rb
19
+ $ make
20
+ $ make install
21
+
22
+ = Examples
23
+
24
+ <tt>examples/genkey.rb</tt>:: Generate a key pair in your keyring.
25
+ <tt>examples/keylist.rb</tt>:: List your keyring like gpg --list-keys.
26
+ <tt>examples/roundtrip.rb</tt>:: Encrypt and decrypt a plain text.
27
+ <tt>examples/sign.rb</tt>:: Create a clear text signature.
28
+ <tt>examples/verify.rb</tt>:: Verify a clear text signature given from stdin.
29
+
30
+ = API
31
+
32
+ Ruby-GPGME provides three levels of API. The highest level API is
33
+ close to the command line interface of GnuPG. The mid level API looks
34
+ object-oriented (or rubyish). The lowest level API is close to the C
35
+ interface of GPGME.
36
+
37
+ == The highest level API
38
+
39
+ It can be written in the highest level API to create a cleartext
40
+ signature of the plaintext from stdin as follows.
41
+
42
+ $ ruby -rgpgme -e 'GPGME.clearsign($stdin, $stdout)'
43
+
44
+ == The mid level API
45
+
46
+ The same example can be rewritten in the mid level API as follows.
47
+
48
+ $ ruby -rgpgme -e <<End
49
+ ctx = GPGME::Ctx.new
50
+ plain = GPGME::Data.from_io($stdin)
51
+ sig = GPGME::Data.from_io($stdout)
52
+ ctx.sign(plain, sig, GPGME::SIG_MODE_CLEAR)
53
+ End
54
+
55
+ == The lowest level API
56
+
57
+ The same example can be rewritten in the lowest level API as follows.
58
+
59
+ $ ruby -rgpgme -e <<End
60
+ ret = Array.new
61
+ GPGME::gpgme_new(ret)
62
+ ctx = ret.shift
63
+ GPGME::gpgme_data_new_from_fd(ret, 0)
64
+ plain = ret.shift
65
+ GPGME::gpgme_data_new_from_fd(ret, 1)
66
+ sig = ret.shift
67
+ GPGME::gpgme_op_sign(ctx, plain, sig, GPGME::SIG_MODE_CLEAR)
68
+ End
69
+
70
+ As you see, it's much harder to write a program in this API than the
71
+ higher level API. However, if you are already familier with the C
72
+ interface of GPGME and/or want to control detailed behavior of GPGME,
73
+ it might be useful.
74
+
75
+ = License
76
+
77
+ Copyright (C) 2003,2006,2007,2008,2009 Daiki Ueno
78
+
79
+ This file is a part of Ruby-GPGME.
80
+
81
+ Ruby-GPGME is free software; you can redistribute it and/or
82
+ modify it under the terms of the GNU Lesser General Public
83
+ License as published by the Free Software Foundation; either
84
+ version 2.1 of the License, or (at your option) any later version.
85
+
86
+ Ruby-GPGME is distributed in the hope that it will be useful,
87
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
88
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
89
+ Lesser General Public License for more details.
90
+
91
+ You should have received a copy of the GNU Lesser General Public
92
+ License along with this library; if not, write to the Free Software
93
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
94
+ =end
95
+ module GPGME
96
+ VERSION = "1.0.8"
97
+ end
98
+
99
+ require 'gpgme_n'
100
+ require 'gpgme/constants'
101
+
102
+ # call-seq:
103
+ # GPGME.decrypt(cipher, plain=nil, options=Hash.new){|signature| ...}
104
+ #
105
+ # <code>GPGME.decrypt</code> performs decryption.
106
+ #
107
+ # The arguments should be specified as follows.
108
+ #
109
+ # - GPGME.decrypt(<i>cipher</i>, <i>plain</i>, <i>options</i>)
110
+ # - GPGME.decrypt(<i>cipher</i>, <i>options</i>) -> <i>plain</i>
111
+ #
112
+ # All arguments except <i>cipher</i> are optional. <i>cipher</i> is
113
+ # input, and <i>plain</i> is output. If the last argument is a
114
+ # Hash, options will be read from it.
115
+ #
116
+ # An input argument is specified by an IO like object (which responds
117
+ # to <code>read</code>), a string, or a GPGME::Data object.
118
+ #
119
+ # An output argument is specified by an IO like object (which responds
120
+ # to <code>write</code>) or a GPGME::Data object.
121
+ #
122
+ # <i>options</i> are same as <code>GPGME::Ctx.new()</code>.
123
+ #
124
+ def GPGME.decrypt(cipher, *args_options)
125
+ raise ArgumentError, 'wrong number of arguments' if args_options.length > 2
126
+ args, options = split_args(args_options)
127
+ plain = args[0]
128
+
129
+ check_version(options)
130
+ GPGME::Ctx.new(options) do |ctx|
131
+ cipher_data = input_data(cipher)
132
+ plain_data = output_data(plain)
133
+ begin
134
+ ctx.decrypt_verify(cipher_data, plain_data)
135
+ rescue GPGME::Error::UnsupportedAlgorithm => exc
136
+ exc.algorithm = ctx.decrypt_result.unsupported_algorithm
137
+ raise exc
138
+ rescue GPGME::Error::WrongKeyUsage => exc
139
+ exc.key_usage = ctx.decrypt_result.wrong_key_usage
140
+ raise exc
141
+ end
142
+
143
+ verify_result = ctx.verify_result
144
+ if verify_result && block_given?
145
+ verify_result.signatures.each do |signature|
146
+ yield signature
147
+ end
148
+ end
149
+
150
+ unless plain
151
+ plain_data.seek(0, IO::SEEK_SET)
152
+ plain_data.read
153
+ end
154
+ end
155
+ end
156
+
157
+ # call-seq:
158
+ # GPGME.verify(sig, signed_text=nil, plain=nil, options=Hash.new){|signature| ...}
159
+ #
160
+ # <code>GPGME.verify</code> verifies a signature.
161
+ #
162
+ # The arguments should be specified as follows.
163
+ #
164
+ # - GPGME.verify(<i>sig</i>, <i>signed_text</i>, <i>plain</i>, <i>options</i>)
165
+ # - GPGME.verify(<i>sig</i>, <i>signed_text</i>, <i>options</i>) -> <i>plain</i>
166
+ #
167
+ # All arguments except <i>sig</i> are optional. <i>sig</i> and
168
+ # <i>signed_text</i> are input. <i>plain</i> is output. If the last
169
+ # argument is a Hash, options will be read from it.
170
+ #
171
+ # An input argument is specified by an IO like object (which responds
172
+ # to <code>read</code>), a string, or a GPGME::Data object.
173
+ #
174
+ # An output argument is specified by an IO like object (which responds
175
+ # to <code>write</code>) or a GPGME::Data object.
176
+ #
177
+ # If <i>sig</i> is a detached signature, then the signed text should
178
+ # be provided in <i>signed_text</i> and <i>plain</i> should be
179
+ # <tt>nil</tt>. Otherwise, if <i>sig</i> is a normal (or cleartext)
180
+ # signature, <i>signed_text</i> should be <tt>nil</tt>.
181
+ #
182
+ # <i>options</i> are same as <code>GPGME::Ctx.new()</code>.
183
+ #
184
+ def GPGME.verify(sig, *args_options) # :yields: signature
185
+ raise ArgumentError, 'wrong number of arguments' if args_options.length > 3
186
+ args, options = split_args(args_options)
187
+ signed_text, plain = args
188
+
189
+ check_version(options)
190
+ GPGME::Ctx.new(options) do |ctx|
191
+ sig_data = input_data(sig)
192
+ if signed_text
193
+ signed_text_data = input_data(signed_text)
194
+ plain_data = nil
195
+ else
196
+ signed_text_data = nil
197
+ plain_data = output_data(plain)
198
+ end
199
+ ctx.verify(sig_data, signed_text_data, plain_data)
200
+ ctx.verify_result.signatures.each do |signature|
201
+ yield signature
202
+ end
203
+ if !signed_text && !plain
204
+ plain_data.seek(0, IO::SEEK_SET)
205
+ plain_data.read
206
+ end
207
+ end
208
+ end
209
+
210
+ # call-seq:
211
+ # GPGME.sign(plain, sig=nil, options=Hash.new)
212
+ #
213
+ # <code>GPGME.sign</code> creates a signature of the plaintext.
214
+ #
215
+ # The arguments should be specified as follows.
216
+ #
217
+ # - GPGME.sign(<i>plain</i>, <i>sig</i>, <i>options</i>)
218
+ # - GPGME.sign(<i>plain</i>, <i>options</i>) -> <i>sig</i>
219
+ #
220
+ # All arguments except <i>plain</i> are optional. <i>plain</i> is
221
+ # input and <i>sig</i> is output. If the last argument is a Hash,
222
+ # options will be read from it.
223
+ #
224
+ # An input argument is specified by an IO like object (which responds
225
+ # to <code>read</code>), a string, or a GPGME::Data object.
226
+ #
227
+ # An output argument is specified by an IO like object (which responds
228
+ # to <code>write</code>) or a GPGME::Data object.
229
+ #
230
+ # <i>options</i> are same as <code>GPGME::Ctx.new()</code> except for
231
+ #
232
+ # - <tt>:signers</tt> Signing keys. If specified, it is an array
233
+ # whose elements are a GPGME::Key object or a string.
234
+ # - <tt>:mode</tt> Desired type of a signature. Either
235
+ # <tt>GPGME::SIG_MODE_NORMAL</tt> for a normal signature,
236
+ # <tt>GPGME::SIG_MODE_DETACH</tt> for a detached signature, or
237
+ # <tt>GPGME::SIG_MODE_CLEAR</tt> for a cleartext signature.
238
+ #
239
+ def GPGME.sign(plain, *args_options)
240
+ raise ArgumentError, 'wrong number of arguments' if args_options.length > 2
241
+ args, options = split_args(args_options)
242
+ sig = args[0]
243
+
244
+ check_version(options)
245
+ GPGME::Ctx.new(options) do |ctx|
246
+ ctx.add_signer(*resolve_keys(options[:signers], true, [:sign])) if options[:signers]
247
+ mode = options[:mode] || GPGME::SIG_MODE_NORMAL
248
+ plain_data = input_data(plain)
249
+ sig_data = output_data(sig)
250
+ begin
251
+ ctx.sign(plain_data, sig_data, mode)
252
+ rescue GPGME::Error::UnusableSecretKey => exc
253
+ exc.keys = ctx.sign_result.invalid_signers
254
+ raise exc
255
+ end
256
+
257
+ unless sig
258
+ sig_data.seek(0, IO::SEEK_SET)
259
+ sig_data.read
260
+ end
261
+ end
262
+ end
263
+
264
+ # call-seq:
265
+ # GPGME.clearsign(plain, sig=nil, options=Hash.new)
266
+ #
267
+ # <code>GPGME.clearsign</code> creates a cleartext signature of the plaintext.
268
+ #
269
+ # The arguments should be specified as follows.
270
+ #
271
+ # - GPGME.clearsign(<i>plain</i>, <i>sig</i>, <i>options</i>)
272
+ # - GPGME.clearsign(<i>plain</i>, <i>options</i>) -> <i>sig</i>
273
+ #
274
+ # All arguments except <i>plain</i> are optional. <i>plain</i> is
275
+ # input and <i>sig</i> is output. If the last argument is a Hash,
276
+ # options will be read from it.
277
+ #
278
+ # An input argument is specified by an IO like object (which responds
279
+ # to <code>read</code>), a string, or a GPGME::Data object.
280
+ #
281
+ # An output argument is specified by an IO like object (which responds
282
+ # to <code>write</code>) or a GPGME::Data object.
283
+ #
284
+ # <i>options</i> are same as <code>GPGME::Ctx.new()</code> except for
285
+ #
286
+ # - <tt>:signers</tt> Signing keys. If specified, it is an array
287
+ # whose elements are a GPGME::Key object or a string.
288
+ #
289
+ def GPGME.clearsign(plain, *args_options)
290
+ raise ArgumentError, 'wrong number of arguments' if args_options.length > 2
291
+ args, options = split_args(args_options)
292
+ args.push(options.merge({:mode => GPGME::SIG_MODE_CLEAR}))
293
+ GPGME.sign(plain, *args)
294
+ end
295
+
296
+ # call-seq:
297
+ # GPGME.detach_sign(plain, sig=nil, options=Hash.new)
298
+ #
299
+ # <code>GPGME.detach_sign</code> creates a detached signature of the plaintext.
300
+ #
301
+ # The arguments should be specified as follows.
302
+ #
303
+ # - GPGME.detach_sign(<i>plain</i>, <i>sig</i>, <i>options</i>)
304
+ # - GPGME.detach_sign(<i>plain</i>, <i>options</i>) -> <i>sig</i>
305
+ #
306
+ # All arguments except <i>plain</i> are optional. <i>plain</i> is
307
+ # input and <i>sig</i> is output. If the last argument is a Hash,
308
+ # options will be read from it.
309
+ #
310
+ # An input argument is specified by an IO like object (which responds
311
+ # to <code>read</code>), a string, or a GPGME::Data object.
312
+ #
313
+ # An output argument is specified by an IO like object (which responds
314
+ # to <code>write</code>) or a GPGME::Data object.
315
+ #
316
+ # <i>options</i> are same as <code>GPGME::Ctx.new()</code> except for
317
+ #
318
+ # - <tt>:signers</tt> Signing keys. If specified, it is an array
319
+ # whose elements are a GPGME::Key object or a string.
320
+ #
321
+ def GPGME.detach_sign(plain, *args_options)
322
+ raise ArgumentError, 'wrong number of arguments' if args_options.length > 2
323
+ args, options = split_args(args_options)
324
+ args.push(options.merge({:mode => GPGME::SIG_MODE_DETACH}))
325
+ GPGME.sign(plain, *args)
326
+ end
327
+
328
+ # call-seq:
329
+ # GPGME.encrypt(recipients, plain, cipher=nil, options=Hash.new)
330
+ #
331
+ # <code>GPGME.encrypt</code> performs encryption.
332
+ #
333
+ # The arguments should be specified as follows.
334
+ #
335
+ # - GPGME.encrypt(<i>recipients</i>, <i>plain</i>, <i>cipher</i>, <i>options</i>)
336
+ # - GPGME.encrypt(<i>recipients</i>, <i>plain</i>, <i>options</i>) -> <i>cipher</i>
337
+ #
338
+ # All arguments except <i>recipients</i> and <i>plain</i> are
339
+ # optional. <i>plain</i> is input and <i>cipher</i> is output. If
340
+ # the last argument is a Hash, options will be read from it.
341
+ #
342
+ # The recipients are specified by an array whose elements are a string
343
+ # or a GPGME::Key object. If <i>recipients</i> is <tt>nil</tt>, it
344
+ # performs symmetric encryption.
345
+ #
346
+ # An input argument is specified by an IO like object (which responds
347
+ # to <code>read</code>), a string, or a GPGME::Data object.
348
+ #
349
+ # An output argument is specified by an IO like object (which responds
350
+ # to <code>write</code>) or a GPGME::Data object.
351
+ #
352
+ # <i>options</i> are same as <code>GPGME::Ctx.new()</code> except for
353
+ #
354
+ # - <tt>:sign</tt> If <tt>true</tt>, it performs a combined sign and
355
+ # encrypt operation.
356
+ # - <tt>:signers</tt> Signing keys. If specified, it is an array
357
+ # whose elements are a GPGME::Key object or a string.
358
+ # - <tt>:always_trust</tt> Setting this to <tt>true</tt> specifies all
359
+ # the recipients should be trusted.
360
+ #
361
+ def GPGME.encrypt(recipients, plain, *args_options)
362
+ raise ArgumentError, 'wrong number of arguments' if args_options.length > 3
363
+ args, options = split_args(args_options)
364
+ cipher = args[0]
365
+ recipient_keys = recipients ? resolve_keys(recipients, false, [:encrypt]) : nil
366
+
367
+ check_version(options)
368
+ GPGME::Ctx.new(options) do |ctx|
369
+ plain_data = input_data(plain)
370
+ cipher_data = output_data(cipher)
371
+ begin
372
+ flags = 0
373
+ if options[:always_trust]
374
+ flags |= GPGME::ENCRYPT_ALWAYS_TRUST
375
+ end
376
+ if options[:sign]
377
+ if options[:signers]
378
+ ctx.add_signer(*resolve_keys(options[:signers], true, [:sign]))
379
+ end
380
+ ctx.encrypt_sign(recipient_keys, plain_data, cipher_data, flags)
381
+ else
382
+ ctx.encrypt(recipient_keys, plain_data, cipher_data, flags)
383
+ end
384
+ rescue GPGME::Error::UnusablePublicKey => exc
385
+ exc.keys = ctx.encrypt_result.invalid_recipients
386
+ raise exc
387
+ rescue GPGME::Error::UnusableSecretKey => exc
388
+ exc.keys = ctx.sign_result.invalid_signers
389
+ raise exc
390
+ end
391
+
392
+ unless cipher
393
+ cipher_data.seek(0, IO::SEEK_SET)
394
+ cipher_data.read
395
+ end
396
+ end
397
+ end
398
+
399
+ # call-seq:
400
+ # GPGME.list_keys(pattern=nil, secret_only=false, options=Hash.new){|key| ...}
401
+ #
402
+ # <code>GPGME.list_keys</code> iterates over the key ring.
403
+ #
404
+ # The arguments should be specified as follows.
405
+ #
406
+ # - GPGME.list_keys(<i>pattern</i>, <i>secret_only</i>, <i>options</i>)
407
+ #
408
+ # All arguments are optional. If the last argument is a Hash, options
409
+ # will be read from it.
410
+ #
411
+ # <i>pattern</i> is a string or <tt>nil</tt>. If <i>pattern</i> is
412
+ # <tt>nil</tt>, all available keys are returned. If
413
+ # <i>secret_only</i> is <tt>true</tt>, the only secret keys are
414
+ # returned.
415
+ #
416
+ # <i>options</i> are same as <code>GPGME::Ctx.new()</code>.
417
+ #
418
+ def GPGME.list_keys(*args_options) # :yields: key
419
+ raise ArgumentError, 'wrong number of arguments' if args_options.length > 3
420
+ args, options = split_args(args_options)
421
+ pattern, secret_only = args
422
+ check_version(options)
423
+ GPGME::Ctx.new do |ctx|
424
+ if block_given?
425
+ ctx.each_key(pattern, secret_only || false) do |key|
426
+ yield key
427
+ end
428
+ else
429
+ ctx.keys(pattern, secret_only || false)
430
+ end
431
+ end
432
+ end
433
+
434
+ # call-seq:
435
+ # GPGME.export(pattern)
436
+ #
437
+ # <code>GPGME.export</code> extracts public keys from the key ring.
438
+ #
439
+ # The arguments should be specified as follows.
440
+ #
441
+ # - GPGME.export(<i>pattern</i>, <i>options</i>) -> <i>keydata</i>
442
+ # - GPGME.export(<i>pattern</i>, <i>keydata</i>, <i>options</i>)
443
+ #
444
+ # All arguments are optional. If the last argument is a Hash, options
445
+ # will be read from it.
446
+ #
447
+ # <i>pattern</i> is a string or <tt>nil</tt>. If <i>pattern</i> is
448
+ # <tt>nil</tt>, all available public keys are returned.
449
+ # <i>keydata</i> is output.
450
+ #
451
+ # An output argument is specified by an IO like object (which responds
452
+ # to <code>write</code>) or a GPGME::Data object.
453
+ #
454
+ # <i>options</i> are same as <code>GPGME::Ctx.new()</code>.
455
+ #
456
+ def GPGME.export(*args_options)
457
+ raise ArgumentError, 'wrong number of arguments' if args_options.length > 2
458
+ args, options = split_args(args_options)
459
+ pattern, key = args[0]
460
+ key_data = output_data(key)
461
+ check_version(options)
462
+ GPGME::Ctx.new(options) do |ctx|
463
+ ctx.export_keys(pattern, key_data)
464
+
465
+ unless key
466
+ key_data.seek(0, IO::SEEK_SET)
467
+ key_data.read
468
+ end
469
+ end
470
+ end
471
+
472
+ # call-seq:
473
+ # GPGME.import(keydata)
474
+ #
475
+ # <code>GPGME.import</code> adds the keys to the key ring.
476
+ #
477
+ # The arguments should be specified as follows.
478
+ #
479
+ # - GPGME.import(<i>keydata</i>, <i>options</i>)
480
+ #
481
+ # All arguments are optional. If the last argument is a Hash, options
482
+ # will be read from it.
483
+ #
484
+ # <i>keydata</i> is input.
485
+ #
486
+ # An input argument is specified by an IO like object (which responds
487
+ # to <code>read</code>), a string, or a GPGME::Data object.
488
+ #
489
+ # <i>options</i> are same as <code>GPGME::Ctx.new()</code>.
490
+ #
491
+ def GPGME.import(*args_options)
492
+ raise ArgumentError, 'wrong number of arguments' if args_options.length > 2
493
+ args, options = split_args(args_options)
494
+ key = args[0]
495
+ key_data = input_data(key)
496
+ check_version(options)
497
+ GPGME::Ctx.new(options) do |ctx|
498
+ ctx.import_keys(key_data)
499
+ ctx.import_result
500
+ end
501
+ end
502
+
503
+ module GPGME
504
+ # :stopdoc:
505
+ private
506
+
507
+ def split_args(args_options)
508
+ if args_options.length > 0 and args_options[-1].respond_to? :to_hash
509
+ args = args_options[0 ... -1]
510
+ options = args_options[-1].to_hash
511
+ else
512
+ args = args_options
513
+ options = Hash.new
514
+ end
515
+ [args, options]
516
+ end
517
+ module_function :split_args
518
+
519
+ def check_version(options = nil)
520
+ version = nil
521
+ if options.kind_of?(String)
522
+ version = options
523
+ elsif options.include?(:version)
524
+ version = options[:version]
525
+ end
526
+ unless GPGME::gpgme_check_version(version)
527
+ raise Error::InvalidVersion.new
528
+ end
529
+ end
530
+ module_function :check_version
531
+
532
+ def resolve_keys(keys_or_names, secret_only, purposes = Array.new)
533
+ keys = Array.new
534
+ keys_or_names.each do |key_or_name|
535
+ if key_or_name.kind_of? Key
536
+ keys << key_or_name
537
+ elsif key_or_name.kind_of? String
538
+ GPGME::Ctx.new do |ctx|
539
+ key = ctx.keys(key_or_name, secret_only).find {|k|
540
+ k.usable_for?(purposes)
541
+ }
542
+ keys << key if key
543
+ end
544
+ end
545
+ end
546
+ keys
547
+ end
548
+ module_function :resolve_keys
549
+
550
+ def input_data(input)
551
+ if input.kind_of? GPGME::Data
552
+ input
553
+ elsif input.respond_to? :to_str
554
+ GPGME::Data.from_str(input.to_str)
555
+ elsif input.respond_to? :read
556
+ GPGME::Data.from_callbacks(IOCallbacks.new(input))
557
+ else
558
+ raise ArgumentError, input.inspect
559
+ end
560
+ end
561
+ module_function :input_data
562
+
563
+ def output_data(output)
564
+ if output.kind_of? GPGME::Data
565
+ output
566
+ elsif output.respond_to? :write
567
+ GPGME::Data.from_callbacks(IOCallbacks.new(output))
568
+ elsif !output
569
+ GPGME::Data.empty
570
+ else
571
+ raise ArgumentError, output.inspect
572
+ end
573
+ end
574
+ module_function :output_data
575
+
576
+ class IOCallbacks
577
+ def initialize(io)
578
+ @io = io
579
+ end
580
+
581
+ def read(hook, length)
582
+ @io.read(length)
583
+ end
584
+
585
+ def write(hook, buffer, length)
586
+ @io.write(buffer[0 .. length])
587
+ end
588
+
589
+ def seek(hook, offset, whence)
590
+ return @io.pos if offset == 0 && whence == IO::SEEK_CUR
591
+ @io.seek(offset, whence)
592
+ @io.pos
593
+ end
594
+ end
595
+
596
+ PROTOCOL_NAMES = {
597
+ PROTOCOL_OpenPGP => :OpenPGP,
598
+ PROTOCOL_CMS => :CMS
599
+ }
600
+
601
+ KEYLIST_MODE_NAMES = {
602
+ KEYLIST_MODE_LOCAL => :local,
603
+ KEYLIST_MODE_EXTERN => :extern,
604
+ KEYLIST_MODE_SIGS => :sigs,
605
+ KEYLIST_MODE_VALIDATE => :validate
606
+ }
607
+
608
+ VALIDITY_NAMES = {
609
+ VALIDITY_UNKNOWN => :unknown,
610
+ VALIDITY_UNDEFINED => :undefined,
611
+ VALIDITY_NEVER => :never,
612
+ VALIDITY_MARGINAL => :marginal,
613
+ VALIDITY_FULL => :full,
614
+ VALIDITY_ULTIMATE => :ultimate
615
+ }
616
+ # :startdoc:
617
+ end
618
+
619
+ module GPGME
620
+ class Error < StandardError
621
+ def initialize(error)
622
+ @error = error
623
+ end
624
+ attr_reader :error
625
+
626
+ # Return the error code.
627
+ #
628
+ # The error code indicates the type of an error, or the reason why
629
+ # an operation failed.
630
+ def code
631
+ GPGME::gpgme_err_code(@error)
632
+ end
633
+
634
+ # Return the error source.
635
+ #
636
+ # The error source has not a precisely defined meaning. Sometimes
637
+ # it is the place where the error happened, sometimes it is the
638
+ # place where an error was encoded into an error value. Usually
639
+ # the error source will give an indication to where to look for
640
+ # the problem. This is not always true, but it is attempted to
641
+ # achieve this goal.
642
+ def source
643
+ GPGME::gpgme_err_source(@error)
644
+ end
645
+
646
+ # Return a description of the error code.
647
+ def message
648
+ GPGME::gpgme_strerror(@error)
649
+ end
650
+
651
+ class General < self; end
652
+ class InvalidValue < self; end
653
+ class UnusablePublicKey < self
654
+ attr_accessor :keys
655
+ end
656
+ class UnusableSecretKey < self
657
+ attr_accessor :keys
658
+ end
659
+ class NoData < self; end
660
+ class Conflict < self; end
661
+ class NotImplemented < self; end
662
+ class DecryptFailed < self; end
663
+ class BadPassphrase < self; end
664
+ class Canceled < self; end
665
+ class InvalidEngine < self; end
666
+ class AmbiguousName < self; end
667
+ class WrongKeyUsage < self
668
+ attr_accessor :key_usage
669
+ end
670
+ class CertificateRevoked < self; end
671
+ class CertificateExpired < self; end
672
+ class NoCRLKnown < self; end
673
+ class NoPolicyMatch < self; end
674
+ class NoSecretKey < self; end
675
+ class MissingCertificate < self; end
676
+ class BadCertificateChain < self; end
677
+ class UnsupportedAlgorithm < self
678
+ attr_accessor :algorithm
679
+ end
680
+ class BadSignature < self; end
681
+ class NoPublicKey < self; end
682
+ class InvalidVersion < self; end
683
+ end
684
+
685
+ def error_to_exception(err) # :nodoc:
686
+ case GPGME::gpgme_err_code(err)
687
+ when GPG_ERR_EOF
688
+ EOFError.new
689
+ when GPG_ERR_NO_ERROR
690
+ nil
691
+ when GPG_ERR_GENERAL
692
+ Error::General.new(err)
693
+ when GPG_ERR_ENOMEM
694
+ Errno::ENOMEM.new
695
+ when GPG_ERR_INV_VALUE
696
+ Error::InvalidValue.new(err)
697
+ when GPG_ERR_UNUSABLE_PUBKEY
698
+ Error::UnusablePublicKey.new(err)
699
+ when GPG_ERR_UNUSABLE_SECKEY
700
+ Error::UnusableSecretKey.new(err)
701
+ when GPG_ERR_NO_DATA
702
+ Error::NoData.new(err)
703
+ when GPG_ERR_CONFLICT
704
+ Error::Conflict.new(err)
705
+ when GPG_ERR_NOT_IMPLEMENTED
706
+ Error::NotImplemented.new(err)
707
+ when GPG_ERR_DECRYPT_FAILED
708
+ Error::DecryptFailed.new(err)
709
+ when GPG_ERR_BAD_PASSPHRASE
710
+ Error::BadPassphrase.new(err)
711
+ when GPG_ERR_CANCELED
712
+ Error::Canceled.new(err)
713
+ when GPG_ERR_INV_ENGINE
714
+ Error::InvalidEngine.new(err)
715
+ when GPG_ERR_AMBIGUOUS_NAME
716
+ Error::AmbiguousName.new(err)
717
+ when GPG_ERR_WRONG_KEY_USAGE
718
+ Error::WrongKeyUsage.new(err)
719
+ when GPG_ERR_CERT_REVOKED
720
+ Error::CertificateRevoked.new(err)
721
+ when GPG_ERR_CERT_EXPIRED
722
+ Error::CertificateExpired.new(err)
723
+ when GPG_ERR_NO_CRL_KNOWN
724
+ Error::NoCRLKnown.new(err)
725
+ when GPG_ERR_NO_POLICY_MATCH
726
+ Error::NoPolicyMatch.new(err)
727
+ when GPG_ERR_NO_SECKEY
728
+ Error::NoSecretKey.new(err)
729
+ when GPG_ERR_MISSING_CERT
730
+ Error::MissingCertificate.new(err)
731
+ when GPG_ERR_BAD_CERT_CHAIN
732
+ Error::BadCertificateChain.new(err)
733
+ when GPG_ERR_UNSUPPORTED_ALGORITHM
734
+ Error::UnsupportedAlgorithm.new(err)
735
+ when GPG_ERR_BAD_SIGNATURE
736
+ Error::BadSignature.new(err)
737
+ when GPG_ERR_NO_PUBKEY
738
+ Error::NoPublicKey.new(err)
739
+ else
740
+ Error.new(err)
741
+ end
742
+ end
743
+ module_function :error_to_exception
744
+ private :error_to_exception
745
+
746
+ class << self
747
+ alias pubkey_algo_name gpgme_pubkey_algo_name
748
+ alias hash_algo_name gpgme_hash_algo_name
749
+ end
750
+
751
+ # Verify that the engine implementing the protocol <i>proto</i> is
752
+ # installed in the system.
753
+ def engine_check_version(proto)
754
+ err = GPGME::gpgme_engine_check_version(proto)
755
+ exc = GPGME::error_to_exception(err)
756
+ raise exc if exc
757
+ end
758
+ module_function :engine_check_version
759
+
760
+ # Return a list of info structures of enabled engines.
761
+ def engine_info
762
+ rinfo = Array.new
763
+ GPGME::gpgme_get_engine_info(rinfo)
764
+ rinfo
765
+ end
766
+ module_function :engine_info
767
+
768
+ # Change the default configuration of the crypto engine implementing
769
+ # protocol <i>proto</i>.
770
+ #
771
+ # <i>file_name</i> is the file name of the executable program
772
+ # implementing the protocol.
773
+ # <i>home_dir</i> is the directory name of the configuration directory.
774
+ def set_engine_info(proto, file_name, home_dir)
775
+ err = GPGME::gpgme_set_engine_info(proto, file_name, home_dir)
776
+ exc = GPGME::error_to_exception(err)
777
+ raise exc if exc
778
+ end
779
+ module_function :set_engine_info
780
+
781
+ # A class for managing data buffers.
782
+ class Data
783
+ BLOCK_SIZE = 4096
784
+
785
+ # Create a new instance.
786
+ #
787
+ # The created data types depend on <i>arg</i>. If <i>arg</i> is
788
+ # <tt>nil</tt>, it creates an instance with an empty buffer.
789
+ # Otherwise, <i>arg</i> is either a string, an IO, or a Pathname.
790
+ def self.new(arg = nil, copy = false)
791
+ if arg.nil?
792
+ return empty
793
+ elsif arg.respond_to? :to_str
794
+ return from_str(arg.to_str, copy)
795
+ elsif arg.respond_to? :to_io
796
+ return from_io(arg.to_io)
797
+ elsif arg.respond_to? :open
798
+ return from_io(arg.open)
799
+ end
800
+ end
801
+
802
+ # Create a new instance with an empty buffer.
803
+ def self.empty
804
+ rdh = Array.new
805
+ err = GPGME::gpgme_data_new(rdh)
806
+ exc = GPGME::error_to_exception(err)
807
+ raise exc if exc
808
+ rdh[0]
809
+ end
810
+
811
+ # Create a new instance with internal buffer.
812
+ def self.from_str(buf, copy = true)
813
+ rdh = Array.new
814
+ err = GPGME::gpgme_data_new_from_mem(rdh, buf, buf.length)
815
+ exc = GPGME::error_to_exception(err)
816
+ raise exc if exc
817
+ rdh[0]
818
+ end
819
+
820
+ # Create a new instance associated with a given IO.
821
+ def self.from_io(io)
822
+ from_callbacks(IOCallbacks.new(arg))
823
+ end
824
+
825
+ # Create a new instance from the specified file descriptor.
826
+ def self.from_fd(fd)
827
+ rdh = Array.new
828
+ err = GPGME::gpgme_data_new_from_fd(rdh, fd)
829
+ exc = GPGME::error_to_exception(err)
830
+ raise exc if exc
831
+ rdh[0]
832
+ end
833
+
834
+ # Create a new instance from the specified callbacks.
835
+ def self.from_callbacks(callbacks, hook_value = nil)
836
+ rdh = Array.new
837
+ err = GPGME::gpgme_data_new_from_cbs(rdh, callbacks, hook_value)
838
+ exc = GPGME::error_to_exception(err)
839
+ raise exc if exc
840
+ rdh[0]
841
+ end
842
+
843
+ # Read at most <i>length</i> bytes from the data object, or to the end
844
+ # of file if <i>length</i> is omitted or is <tt>nil</tt>.
845
+ def read(length = nil)
846
+ if length
847
+ GPGME::gpgme_data_read(self, length)
848
+ else
849
+ buf = String.new
850
+ loop do
851
+ s = GPGME::gpgme_data_read(self, BLOCK_SIZE)
852
+ break unless s
853
+ buf << s
854
+ end
855
+ buf
856
+ end
857
+ end
858
+
859
+ # Seek to a given <i>offset</i> in the data object according to the
860
+ # value of <i>whence</i>.
861
+ def seek(offset, whence = IO::SEEK_SET)
862
+ GPGME::gpgme_data_seek(self, offset, IO::SEEK_SET)
863
+ end
864
+
865
+ # Write <i>length</i> bytes from <i>buffer</i> into the data object.
866
+ def write(buffer, length = buffer.length)
867
+ GPGME::gpgme_data_write(self, buffer, length)
868
+ end
869
+
870
+ # Return the encoding of the underlying data.
871
+ def encoding
872
+ GPGME::gpgme_data_get_encoding(self)
873
+ end
874
+
875
+ # Set the encoding to a given <i>encoding</i> of the underlying
876
+ # data object.
877
+ def encoding=(encoding)
878
+ err = GPGME::gpgme_data_set_encoding(self, encoding)
879
+ exc = GPGME::error_to_exception(err)
880
+ raise exc if exc
881
+ encoding
882
+ end
883
+ end
884
+
885
+ class EngineInfo
886
+ private_class_method :new
887
+
888
+ attr_reader :protocol, :file_name, :version, :req_version, :home_dir
889
+ alias required_version req_version
890
+ end
891
+
892
+ # A context within which all cryptographic operations are performed.
893
+ class Ctx
894
+ # Create a new instance from the given <i>options</i>.
895
+ # <i>options</i> is a Hash whose keys are
896
+ #
897
+ # * <tt>:protocol</tt> Either <tt>PROTOCOL_OpenPGP</tt> or
898
+ # <tt>PROTOCOL_CMS</tt>.
899
+ #
900
+ # * <tt>:armor</tt> If <tt>true</tt>, the output should be ASCII armored.
901
+ #
902
+ # * <tt>:textmode</tt> If <tt>true</tt>, inform the recipient that the
903
+ # input is text.
904
+ #
905
+ # * <tt>:keylist_mode</tt> Either
906
+ # <tt>KEYLIST_MODE_LOCAL</tt>,
907
+ # <tt>KEYLIST_MODE_EXTERN</tt>,
908
+ # <tt>KEYLIST_MODE_SIGS</tt>, or
909
+ # <tt>KEYLIST_MODE_VALIDATE</tt>.
910
+ # * <tt>:passphrase_callback</tt> A callback function.
911
+ # * <tt>:passphrase_callback_value</tt> An object passed to
912
+ # passphrase_callback.
913
+ # * <tt>:progress_callback</tt> A callback function.
914
+ # * <tt>:progress_callback_value</tt> An object passed to
915
+ # progress_callback.
916
+ #
917
+ def self.new(options = Hash.new)
918
+ rctx = Array.new
919
+ err = GPGME::gpgme_new(rctx)
920
+ exc = GPGME::error_to_exception(err)
921
+ raise exc if exc
922
+ ctx = rctx[0]
923
+ options.each_pair do |key, value|
924
+ case key
925
+ when :protocol
926
+ ctx.protocol = value
927
+ when :armor
928
+ ctx.armor = value
929
+ when :textmode
930
+ ctx.textmode = value
931
+ when :keylist_mode
932
+ ctx.keylist_mode = value
933
+ when :passphrase_callback
934
+ ctx.set_passphrase_callback(value,
935
+ options[:passphrase_callback_value])
936
+ when :progress_callback
937
+ ctx.set_progress_callback(value,
938
+ options[:progress_callback_value])
939
+ end
940
+ end
941
+ if block_given?
942
+ begin
943
+ yield ctx
944
+ ensure
945
+ GPGME::gpgme_release(ctx)
946
+ end
947
+ else
948
+ ctx
949
+ end
950
+ end
951
+
952
+ # Set the <i>protocol</i> used within this context.
953
+ def protocol=(proto)
954
+ err = GPGME::gpgme_set_protocol(self, proto)
955
+ exc = GPGME::error_to_exception(err)
956
+ raise exc if exc
957
+ proto
958
+ end
959
+
960
+ # Return the protocol used within this context.
961
+ def protocol
962
+ GPGME::gpgme_get_protocol(self)
963
+ end
964
+
965
+ # Tell whether the output should be ASCII armored.
966
+ def armor=(yes)
967
+ GPGME::gpgme_set_armor(self, yes ? 1 : 0)
968
+ yes
969
+ end
970
+
971
+ # Return true if the output is ASCII armored.
972
+ def armor
973
+ GPGME::gpgme_get_armor(self) == 1 ? true : false
974
+ end
975
+
976
+ # Tell whether canonical text mode should be used.
977
+ def textmode=(yes)
978
+ GPGME::gpgme_set_textmode(self, yes ? 1 : 0)
979
+ yes
980
+ end
981
+
982
+ # Return true if canonical text mode is enabled.
983
+ def textmode
984
+ GPGME::gpgme_get_textmode(self) == 1 ? true : false
985
+ end
986
+
987
+ # Change the default behaviour of the key listing functions.
988
+ def keylist_mode=(mode)
989
+ GPGME::gpgme_set_keylist_mode(self, mode)
990
+ mode
991
+ end
992
+
993
+ # Return the current key listing mode.
994
+ def keylist_mode
995
+ GPGME::gpgme_get_keylist_mode(self)
996
+ end
997
+
998
+ def inspect
999
+ "#<#{self.class} protocol=#{PROTOCOL_NAMES[protocol] || protocol}, \
1000
+ armor=#{armor}, textmode=#{textmode}, \
1001
+ keylist_mode=#{KEYLIST_MODE_NAMES[keylist_mode]}>"
1002
+ end
1003
+
1004
+ # Set the passphrase callback with given hook value.
1005
+ # <i>passfunc</i> should respond to <code>call</code> with 5 arguments.
1006
+ #
1007
+ # def passfunc(hook, uid_hint, passphrase_info, prev_was_bad, fd)
1008
+ # $stderr.write("Passphrase for #{uid_hint}: ")
1009
+ # $stderr.flush
1010
+ # begin
1011
+ # system('stty -echo')
1012
+ # io = IO.for_fd(fd, 'w')
1013
+ # io.puts(gets)
1014
+ # io.flush
1015
+ # ensure
1016
+ # (0 ... $_.length).each do |i| $_[i] = ?0 end if $_
1017
+ # system('stty echo')
1018
+ # end
1019
+ # $stderr.puts
1020
+ # end
1021
+ #
1022
+ # ctx.set_passphrase_callback(method(:passfunc))
1023
+ #
1024
+ def set_passphrase_callback(passfunc, hook_value = nil)
1025
+ GPGME::gpgme_set_passphrase_cb(self, passfunc, hook_value)
1026
+ end
1027
+ alias set_passphrase_cb set_passphrase_callback
1028
+
1029
+ # Set the progress callback with given hook value.
1030
+ # <i>progfunc</i> should respond to <code>call</code> with 5 arguments.
1031
+ #
1032
+ # def progfunc(hook, what, type, current, total)
1033
+ # $stderr.write("#{what}: #{current}/#{total}\r")
1034
+ # $stderr.flush
1035
+ # end
1036
+ #
1037
+ # ctx.set_progress_callback(method(:progfunc))
1038
+ #
1039
+ def set_progress_callback(progfunc, hook_value = nil)
1040
+ GPGME::gpgme_set_progress_cb(self, progfunc, hook_value)
1041
+ end
1042
+ alias set_progress_cb set_progress_callback
1043
+
1044
+ # Initiate a key listing operation for given pattern.
1045
+ # If <i>pattern</i> is <tt>nil</tt>, all available keys are
1046
+ # returned. If <i>secret_only</i> is <tt>true</tt>, the only
1047
+ # secret keys are returned.
1048
+ def keylist_start(pattern = nil, secret_only = false)
1049
+ err = GPGME::gpgme_op_keylist_start(self, pattern, secret_only ? 1 : 0)
1050
+ exc = GPGME::error_to_exception(err)
1051
+ raise exc if exc
1052
+ end
1053
+
1054
+ # Advance to the next key in the key listing operation.
1055
+ def keylist_next
1056
+ rkey = Array.new
1057
+ err = GPGME::gpgme_op_keylist_next(self, rkey)
1058
+ exc = GPGME::error_to_exception(err)
1059
+ raise exc if exc
1060
+ rkey[0]
1061
+ end
1062
+
1063
+ # End a pending key list operation.
1064
+ def keylist_end
1065
+ err = GPGME::gpgme_op_keylist_end(self)
1066
+ exc = GPGME::error_to_exception(err)
1067
+ raise exc if exc
1068
+ end
1069
+
1070
+ # Convenient method to iterate over keys.
1071
+ # If <i>pattern</i> is <tt>nil</tt>, all available keys are
1072
+ # returned. If <i>secret_only</i> is <tt>true</tt>, the only
1073
+ # secret keys are returned.
1074
+ def each_key(pattern = nil, secret_only = false, &block) # :yields: key
1075
+ keylist_start(pattern, secret_only)
1076
+ begin
1077
+ loop do
1078
+ yield keylist_next
1079
+ end
1080
+ keys
1081
+ rescue EOFError
1082
+ # The last key in the list has already been returned.
1083
+ ensure
1084
+ keylist_end
1085
+ end
1086
+ end
1087
+ alias each_keys each_key
1088
+
1089
+ def keys(pattern = nil, secret_only = nil)
1090
+ keys = Array.new
1091
+ each_key(pattern, secret_only) do |key|
1092
+ keys << key
1093
+ end
1094
+ keys
1095
+ end
1096
+
1097
+ # Get the key with the <i>fingerprint</i>.
1098
+ # If <i>secret</i> is <tt>true</tt>, secret key is returned.
1099
+ def get_key(fingerprint, secret = false)
1100
+ rkey = Array.new
1101
+ err = GPGME::gpgme_get_key(self, fingerprint, rkey, secret ? 1 : 0)
1102
+ exc = GPGME::error_to_exception(err)
1103
+ raise exc if exc
1104
+ rkey[0]
1105
+ end
1106
+
1107
+ # Generate a new key pair.
1108
+ # <i>parms</i> is a string which looks like
1109
+ #
1110
+ # <GnupgKeyParms format="internal">
1111
+ # Key-Type: DSA
1112
+ # Key-Length: 1024
1113
+ # Subkey-Type: ELG-E
1114
+ # Subkey-Length: 1024
1115
+ # Name-Real: Joe Tester
1116
+ # Name-Comment: with stupid passphrase
1117
+ # Name-Email: joe@foo.bar
1118
+ # Expire-Date: 0
1119
+ # Passphrase: abc
1120
+ # </GnupgKeyParms>
1121
+ #
1122
+ # If <i>pubkey</i> and <i>seckey</i> are both set to <tt>nil</tt>,
1123
+ # it stores the generated key pair into your key ring.
1124
+ def generate_key(parms, pubkey = Data.new, seckey = Data.new)
1125
+ err = GPGME::gpgme_op_genkey(self, parms, pubkey, seckey)
1126
+ exc = GPGME::error_to_exception(err)
1127
+ raise exc if exc
1128
+ end
1129
+ alias genkey generate_key
1130
+
1131
+ # Extract the public keys of the recipients.
1132
+ def export_keys(recipients, keydata = Data.new)
1133
+ err = GPGME::gpgme_op_export(self, recipients, 0, keydata)
1134
+ exc = GPGME::error_to_exception(err)
1135
+ raise exc if exc
1136
+ keydata
1137
+ end
1138
+ alias export export_keys
1139
+
1140
+ # Add the keys in the data buffer to the key ring.
1141
+ def import_keys(keydata)
1142
+ err = GPGME::gpgme_op_import(self, keydata)
1143
+ exc = GPGME::error_to_exception(err)
1144
+ raise exc if exc
1145
+ end
1146
+ alias import import_keys
1147
+
1148
+ def import_result
1149
+ GPGME::gpgme_op_import_result(self)
1150
+ end
1151
+
1152
+ # Delete the key from the key ring.
1153
+ # If allow_secret is false, only public keys are deleted,
1154
+ # otherwise secret keys are deleted as well.
1155
+ def delete_key(key, allow_secret = false)
1156
+ err = GPGME::gpgme_op_delete(self, key, allow_secret ? 1 : 0)
1157
+ exc = GPGME::error_to_exception(err)
1158
+ raise exc if exc
1159
+ end
1160
+ alias delete delete_key
1161
+
1162
+ # Edit attributes of the key in the local key ring.
1163
+ def edit_key(key, editfunc, hook_value = nil, out = Data.new)
1164
+ err = GPGME::gpgme_op_edit(self, key, editfunc, hook_value, out)
1165
+ exc = GPGME::error_to_exception(err)
1166
+ raise exc if exc
1167
+ end
1168
+ alias edit edit_key
1169
+
1170
+ # Edit attributes of the key on the card.
1171
+ def edit_card_key(key, editfunc, hook_value = nil, out = Data.new)
1172
+ err = GPGME::gpgme_op_card_edit(self, key, editfunc, hook_value, out)
1173
+ exc = GPGME::error_to_exception(err)
1174
+ raise exc if exc
1175
+ end
1176
+ alias edit_card edit_card_key
1177
+ alias card_edit edit_card_key
1178
+
1179
+ # Decrypt the ciphertext and return the plaintext.
1180
+ def decrypt(cipher, plain = Data.new)
1181
+ err = GPGME::gpgme_op_decrypt(self, cipher, plain)
1182
+ exc = GPGME::error_to_exception(err)
1183
+ raise exc if exc
1184
+ plain
1185
+ end
1186
+
1187
+ def decrypt_verify(cipher, plain = Data.new)
1188
+ err = GPGME::gpgme_op_decrypt_verify(self, cipher, plain)
1189
+ exc = GPGME::error_to_exception(err)
1190
+ raise exc if exc
1191
+ plain
1192
+ end
1193
+
1194
+ def decrypt_result
1195
+ GPGME::gpgme_op_decrypt_result(self)
1196
+ end
1197
+
1198
+ # Verify that the signature in the data object is a valid signature.
1199
+ def verify(sig, signed_text = nil, plain = Data.new)
1200
+ err = GPGME::gpgme_op_verify(self, sig, signed_text, plain)
1201
+ exc = GPGME::error_to_exception(err)
1202
+ raise exc if exc
1203
+ plain
1204
+ end
1205
+
1206
+ def verify_result
1207
+ GPGME::gpgme_op_verify_result(self)
1208
+ end
1209
+
1210
+ # Decrypt the ciphertext and return the plaintext.
1211
+ def decrypt_verify(cipher, plain = Data.new)
1212
+ err = GPGME::gpgme_op_decrypt_verify(self, cipher, plain)
1213
+ exc = GPGME::error_to_exception(err)
1214
+ raise exc if exc
1215
+ plain
1216
+ end
1217
+
1218
+ # Remove the list of signers from this object.
1219
+ def clear_signers
1220
+ GPGME::gpgme_signers_clear(self)
1221
+ end
1222
+
1223
+ # Add _keys_ to the list of signers.
1224
+ def add_signer(*keys)
1225
+ keys.each do |key|
1226
+ err = GPGME::gpgme_signers_add(self, key)
1227
+ exc = GPGME::error_to_exception(err)
1228
+ raise exc if exc
1229
+ end
1230
+ end
1231
+
1232
+ # Create a signature for the text.
1233
+ # <i>plain</i> is a data object which contains the text.
1234
+ # <i>sig</i> is a data object where the generated signature is stored.
1235
+ def sign(plain, sig = Data.new, mode = GPGME::SIG_MODE_NORMAL)
1236
+ err = GPGME::gpgme_op_sign(self, plain, sig, mode)
1237
+ exc = GPGME::error_to_exception(err)
1238
+ raise exc if exc
1239
+ sig
1240
+ end
1241
+
1242
+ def sign_result
1243
+ GPGME::gpgme_op_sign_result(self)
1244
+ end
1245
+
1246
+ # Encrypt the plaintext in the data object for the recipients and
1247
+ # return the ciphertext.
1248
+ def encrypt(recp, plain, cipher = Data.new, flags = 0)
1249
+ err = GPGME::gpgme_op_encrypt(self, recp, flags, plain, cipher)
1250
+ exc = GPGME::error_to_exception(err)
1251
+ raise exc if exc
1252
+ cipher
1253
+ end
1254
+
1255
+ def encrypt_result
1256
+ GPGME::gpgme_op_encrypt_result(self)
1257
+ end
1258
+
1259
+ def encrypt_sign(recp, plain, cipher = Data.new, flags = 0)
1260
+ err = GPGME::gpgme_op_encrypt_sign(self, recp, flags, plain, cipher)
1261
+ exc = GPGME::error_to_exception(err)
1262
+ raise exc if exc
1263
+ cipher
1264
+ end
1265
+ end
1266
+
1267
+ # A public or secret key.
1268
+ class Key
1269
+ private_class_method :new
1270
+
1271
+ attr_reader :keylist_mode, :protocol, :owner_trust
1272
+ attr_reader :issuer_serial, :issuer_name, :chain_id
1273
+ attr_reader :subkeys, :uids
1274
+
1275
+ def trust
1276
+ return :revoked if @revoked == 1
1277
+ return :expired if @expired == 1
1278
+ return :disabled if @disabled == 1
1279
+ return :invalid if @invalid == 1
1280
+ end
1281
+
1282
+ def capability
1283
+ caps = Array.new
1284
+ caps << :encrypt if @can_encrypt
1285
+ caps << :sign if @can_sign
1286
+ caps << :certify if @can_certify
1287
+ caps << :authenticate if @can_authenticate
1288
+ caps
1289
+ end
1290
+
1291
+ def usable_for?(purposes)
1292
+ unless purposes.kind_of? Array
1293
+ purposes = [purposes]
1294
+ end
1295
+ return false if [:revoked, :expired, :disabled, :invalid].include? trust
1296
+ return (purposes - capability).empty?
1297
+ end
1298
+
1299
+ def secret?
1300
+ @secret == 1
1301
+ end
1302
+
1303
+ def inspect
1304
+ primary_subkey = subkeys[0]
1305
+ sprintf("#<#{self.class} %s %4d%c/%s %s trust=%s, owner_trust=%s, \
1306
+ capability=%s, subkeys=%s, uids=%s>",
1307
+ primary_subkey.secret? ? 'sec' : 'pub',
1308
+ primary_subkey.length,
1309
+ primary_subkey.pubkey_algo_letter,
1310
+ primary_subkey.fingerprint[-8 .. -1],
1311
+ primary_subkey.timestamp.strftime('%Y-%m-%d'),
1312
+ trust.inspect,
1313
+ VALIDITY_NAMES[@owner_trust].inspect,
1314
+ capability.inspect,
1315
+ subkeys.inspect,
1316
+ uids.inspect)
1317
+ end
1318
+
1319
+ def to_s
1320
+ primary_subkey = subkeys[0]
1321
+ s = sprintf("%s %4d%c/%s %s\n",
1322
+ primary_subkey.secret? ? 'sec' : 'pub',
1323
+ primary_subkey.length,
1324
+ primary_subkey.pubkey_algo_letter,
1325
+ primary_subkey.fingerprint[-8 .. -1],
1326
+ primary_subkey.timestamp.strftime('%Y-%m-%d'))
1327
+ uids.each do |user_id|
1328
+ s << "uid\t\t#{user_id.name} <#{user_id.email}>\n"
1329
+ end
1330
+ subkeys.each do |subkey|
1331
+ s << subkey.to_s
1332
+ end
1333
+ s
1334
+ end
1335
+ end
1336
+
1337
+ class SubKey
1338
+ private_class_method :new
1339
+
1340
+ attr_reader :pubkey_algo, :length, :keyid, :fpr
1341
+ alias fingerprint fpr
1342
+
1343
+ def trust
1344
+ return :revoked if @revoked == 1
1345
+ return :expired if @expired == 1
1346
+ return :disabled if @disabled == 1
1347
+ return :invalid if @invalid == 1
1348
+ end
1349
+
1350
+ def capability
1351
+ caps = Array.new
1352
+ caps << :encrypt if @can_encrypt
1353
+ caps << :sign if @can_sign
1354
+ caps << :certify if @can_certify
1355
+ caps << :authenticate if @can_authenticate
1356
+ caps
1357
+ end
1358
+
1359
+ def usable_for?(purposes)
1360
+ unless purposes.kind_of? Array
1361
+ purposes = [purposes]
1362
+ end
1363
+ return false if [:revoked, :expired, :disabled, :invalid].include? trust
1364
+ return (purposes - capability).empty?
1365
+ end
1366
+
1367
+ def secret?
1368
+ @secret == 1
1369
+ end
1370
+
1371
+ def timestamp
1372
+ Time.at(@timestamp)
1373
+ end
1374
+
1375
+ def expires
1376
+ Time.at(@expires)
1377
+ end
1378
+
1379
+ PUBKEY_ALGO_LETTERS = {
1380
+ PK_RSA => ?R,
1381
+ PK_ELG_E => ?g,
1382
+ PK_ELG => ?G,
1383
+ PK_DSA => ?D
1384
+ }
1385
+
1386
+ def pubkey_algo_letter
1387
+ PUBKEY_ALGO_LETTERS[@pubkey_algo] || ??
1388
+ end
1389
+
1390
+ def inspect
1391
+ sprintf("#<#{self.class} %s %4d%c/%s %s trust=%s, capability=%s>",
1392
+ secret? ? 'ssc' : 'sub',
1393
+ length,
1394
+ pubkey_algo_letter,
1395
+ (@fingerprint || @keyid)[-8 .. -1],
1396
+ timestamp.strftime('%Y-%m-%d'),
1397
+ trust.inspect,
1398
+ capability.inspect)
1399
+ end
1400
+
1401
+ def to_s
1402
+ sprintf("%s %4d%c/%s %s\n",
1403
+ secret? ? 'ssc' : 'sub',
1404
+ length,
1405
+ pubkey_algo_letter,
1406
+ (@fingerprint || @keyid)[-8 .. -1],
1407
+ timestamp.strftime('%Y-%m-%d'))
1408
+ end
1409
+ end
1410
+
1411
+ class UserID
1412
+ private_class_method :new
1413
+
1414
+ attr_reader :validity, :uid, :name, :comment, :email, :signatures
1415
+
1416
+ def revoked?
1417
+ @revoked == 1
1418
+ end
1419
+
1420
+ def invalid?
1421
+ @invalid == 1
1422
+ end
1423
+
1424
+ def inspect
1425
+ "#<#{self.class} #{name} <#{email}> \
1426
+ validity=#{VALIDITY_NAMES[validity]}, signatures=#{signatures.inspect}>"
1427
+ end
1428
+ end
1429
+
1430
+ class KeySig
1431
+ private_class_method :new
1432
+
1433
+ attr_reader :pubkey_algo, :keyid
1434
+
1435
+ def revoked?
1436
+ @revoked == 1
1437
+ end
1438
+
1439
+ def expired?
1440
+ @expired == 1
1441
+ end
1442
+
1443
+ def invalid?
1444
+ @invalid == 1
1445
+ end
1446
+
1447
+ def exportable?
1448
+ @exportable == 1
1449
+ end
1450
+
1451
+ def timestamp
1452
+ Time.at(@timestamp)
1453
+ end
1454
+
1455
+ def expires
1456
+ Time.at(@expires)
1457
+ end
1458
+
1459
+ def inspect
1460
+ "#<#{self.class} #{keyid} timestamp=#{timestamp}, expires=#{expires}>"
1461
+ end
1462
+ end
1463
+
1464
+ class VerifyResult
1465
+ private_class_method :new
1466
+
1467
+ attr_reader :signatures
1468
+ end
1469
+
1470
+ class Signature
1471
+ private_class_method :new
1472
+
1473
+ attr_reader :summary, :fpr, :status, :notations, :wrong_key_usage
1474
+ attr_reader :validity, :validity_reason
1475
+ attr_reader :pka_trust, :pka_address
1476
+ alias fingerprint fpr
1477
+
1478
+ def timestamp
1479
+ Time.at(@timestamp)
1480
+ end
1481
+
1482
+ def exp_timestamp
1483
+ Time.at(@exp_timestamp)
1484
+ end
1485
+
1486
+ def to_s
1487
+ ctx = Ctx.new
1488
+ if from_key = ctx.get_key(fingerprint)
1489
+ from = "#{from_key.subkeys[0].keyid} #{from_key.uids[0].uid}"
1490
+ else
1491
+ from = fingerprint
1492
+ end
1493
+ case GPGME::gpgme_err_code(status)
1494
+ when GPGME::GPG_ERR_NO_ERROR
1495
+ "Good signature from #{from}"
1496
+ when GPGME::GPG_ERR_SIG_EXPIRED
1497
+ "Expired signature from #{from}"
1498
+ when GPGME::GPG_ERR_KEY_EXPIRED
1499
+ "Signature made from expired key #{from}"
1500
+ when GPGME::GPG_ERR_CERT_REVOKED
1501
+ "Signature made from revoked key #{from}"
1502
+ when GPGME::GPG_ERR_BAD_SIGNATURE
1503
+ "Bad signature from #{from}"
1504
+ when GPGME::GPG_ERR_NO_ERROR
1505
+ "No public key for #{from}"
1506
+ end
1507
+ end
1508
+ end
1509
+
1510
+ class DecryptResult
1511
+ private_class_method :new
1512
+
1513
+ attr_reader :unsupported_algorithm, :wrong_key_usage
1514
+ end
1515
+
1516
+ class SignResult
1517
+ private_class_method :new
1518
+
1519
+ attr_reader :invalid_signers, :signatures
1520
+ end
1521
+
1522
+ class EncryptResult
1523
+ private_class_method :new
1524
+
1525
+ attr_reader :invalid_recipients
1526
+ end
1527
+
1528
+ class InvalidKey
1529
+ private_class_method :new
1530
+
1531
+ attr_reader :fpr, :reason
1532
+ alias fingerprint fpr
1533
+ end
1534
+
1535
+ class NewSignature
1536
+ private_class_method :new
1537
+
1538
+ attr_reader :type, :pubkey_algo, :hash_algo, :sig_class, :fpr
1539
+ alias fingerprint fpr
1540
+
1541
+ def timestamp
1542
+ Time.at(@timestamp)
1543
+ end
1544
+ end
1545
+
1546
+ class ImportStatus
1547
+ private_class_method :new
1548
+
1549
+ attr_reader :fpr, :result, :status
1550
+ alias fingerprint fpr
1551
+ end
1552
+
1553
+ class ImportResult
1554
+ private_class_method :new
1555
+
1556
+ attr_reader :considered, :no_user_id, :imported, :imported_rsa, :unchanged
1557
+ attr_reader :new_user_ids, :new_sub_keys, :new_signatures, :new_revocations
1558
+ attr_reader :secret_read, :secret_imported, :secret_unchanged
1559
+ attr_reader :not_imported, :imports
1560
+ end
1561
+ end