ruby-gpgme 1.0.1

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