gpgme 1.0.8 → 2.0.0
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/examples/genkey.rb +1 -1
- data/examples/keylist.rb +2 -1
- data/examples/roundtrip.rb +7 -4
- data/examples/sign.rb +5 -3
- data/examples/verify.rb +4 -2
- data/ext/gpgme/extconf.rb +58 -0
- data/ext/gpgme/gpgme-1.3.1.tar.bz2 +0 -0
- data/{gpgme_n.c → ext/gpgme/gpgme_n.c} +8 -8
- data/ext/gpgme/libassuan-2.0.2.tar.bz2 +0 -0
- data/ext/gpgme/libgpg-error-1.10.tar.bz2 +0 -0
- data/lib/gpgme.rb +88 -1541
- data/lib/gpgme/compat.rb +2 -0
- data/lib/gpgme/constants.rb +23 -0
- data/lib/gpgme/crypto.rb +357 -0
- data/lib/gpgme/ctx.rb +462 -0
- data/lib/gpgme/data.rb +177 -0
- data/lib/gpgme/engine.rb +76 -0
- data/lib/gpgme/error.rb +66 -0
- data/lib/gpgme/io_callbacks.rb +21 -0
- data/lib/gpgme/key.rb +242 -0
- data/lib/gpgme/key_common.rb +43 -0
- data/lib/gpgme/key_sig.rb +35 -0
- data/lib/gpgme/misc.rb +66 -0
- data/lib/gpgme/signature.rb +85 -0
- data/lib/gpgme/sub_key.rb +58 -0
- data/lib/gpgme/user_id.rb +20 -0
- data/lib/gpgme/version.rb +3 -0
- data/test/crypto_test.rb +242 -0
- data/test/ctx_test.rb +426 -0
- data/test/data_test.rb +116 -0
- data/test/files/testkey_pub.gpg +52 -0
- data/test/files/testkey_sec.gpg +54 -0
- data/test/gpgme_test.rb +12 -0
- data/test/key_test.rb +201 -0
- data/test/signature_test.rb +48 -0
- data/test/sub_key_test.rb +45 -0
- data/test/support/resources.rb +516 -0
- data/test/test_helper.rb +83 -0
- metadata +144 -65
- data.tar.gz.sig +0 -3
- data/COPYING +0 -340
- data/COPYING.LESSER +0 -510
- data/Makefile +0 -172
- data/Manifest.txt +0 -18
- data/README +0 -86
- data/Rakefile +0 -17
- data/THANKS +0 -15
- data/extconf.rb +0 -26
- metadata.gz.sig +0 -0
data/examples/genkey.rb
CHANGED
data/examples/keylist.rb
CHANGED
data/examples/roundtrip.rb
CHANGED
@@ -28,12 +28,15 @@ plain = 'test test test'
|
|
28
28
|
puts("Plaintext:\n#{plain}")
|
29
29
|
|
30
30
|
# Perform symmetric encryption on PLAIN.
|
31
|
-
|
31
|
+
crypto = GPGME::Crypto.new(:armor => true)
|
32
|
+
cipher = crypto.encrypt(plain, {:symmetric => true,
|
32
33
|
# :passphrase_callback => method(:passfunc)
|
33
34
|
})
|
34
|
-
|
35
|
+
str = cipher.read
|
36
|
+
puts("Ciphertext:\n#{str}")
|
35
37
|
|
36
|
-
|
38
|
+
cipher = GPGME::Data.new(str)
|
39
|
+
plain = crypto.decrypt(cipher, {
|
37
40
|
# :passphrase_callback => method(:passfunc)
|
38
41
|
})
|
39
|
-
puts("Plaintext:\n#{plain}")
|
42
|
+
puts("Plaintext:\n#{plain.read}")
|
data/examples/sign.rb
CHANGED
@@ -24,6 +24,8 @@ unless ENV['GPG_AGENT_INFO']
|
|
24
24
|
exit(1)
|
25
25
|
end
|
26
26
|
|
27
|
-
|
28
|
-
|
29
|
-
|
27
|
+
crypto = GPGME::Crypto.new
|
28
|
+
signature = crypto.clearsign('test test test', {
|
29
|
+
# :passphrase_callback => method(:passfunc)
|
30
|
+
})
|
31
|
+
puts signature.read
|
data/examples/verify.rb
CHANGED
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'mkmf'
|
2
|
+
|
3
|
+
BUILD = Dir::pwd
|
4
|
+
SRC = File.expand_path(File.dirname(__FILE__))
|
5
|
+
PREFIX = "#{BUILD}/dst/"
|
6
|
+
|
7
|
+
def sys(*cmd)
|
8
|
+
puts " -- #{cmd.join(' ')}"
|
9
|
+
|
10
|
+
unless ret = xsystem(cmd.join(' '))
|
11
|
+
raise "#{cmd.join(' ')} failed!"
|
12
|
+
end
|
13
|
+
|
14
|
+
ret
|
15
|
+
end
|
16
|
+
|
17
|
+
def build(tgz, *flags)
|
18
|
+
sys("tar xjvf #{tgz}")
|
19
|
+
|
20
|
+
Dir.chdir(File.basename(tgz, '.tar.bz2')) do
|
21
|
+
sys("./configure --prefix=#{PREFIX} --disable-shared --enable-static --with-pic", *flags)
|
22
|
+
sys("make")
|
23
|
+
sys("make install")
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
libgpg_error_tgz = File.join(SRC, 'libgpg-error-1.10.tar.bz2')
|
28
|
+
libassuan_tgz = File.join(SRC, 'libassuan-2.0.2.tar.bz2')
|
29
|
+
gpgme_tgz = File.join(SRC, 'gpgme-1.3.1.tar.bz2')
|
30
|
+
|
31
|
+
# build deps
|
32
|
+
|
33
|
+
build(libgpg_error_tgz, "--disable-nls")
|
34
|
+
build(libassuan_tgz, "--with-gpg-error-prefix=#{PREFIX}")
|
35
|
+
build(gpgme_tgz, "--with-gpg-error-prefix=#{PREFIX}", "--with-libassuan-prefix=#{PREFIX}")
|
36
|
+
|
37
|
+
# copy gpgme
|
38
|
+
|
39
|
+
|
40
|
+
%w[ libassuan libgpg-error libgpgme ].each do |lib|
|
41
|
+
FileUtils.cp "#{PREFIX}/lib/#{lib}.a", "#{BUILD}/#{lib}_ext.a"
|
42
|
+
end
|
43
|
+
|
44
|
+
$INCFLAGS[0,0] = " -I#{PREFIX}/include "
|
45
|
+
#$LDFLAGS << " -L#{PREFIX}/lib "
|
46
|
+
$CFLAGS << " -fPIC "
|
47
|
+
|
48
|
+
# build gpgme extension
|
49
|
+
|
50
|
+
unless have_library 'gpg-error_ext' and have_library 'gpgme_ext' and have_library 'assuan_ext' and have_library 'gpg-error_ext' and have_header 'gpgme.h'
|
51
|
+
STDERR.puts "\n\n"
|
52
|
+
STDERR.puts "*********************************************************"
|
53
|
+
STDERR.puts "********* error compiling and linking libgpgme. *********"
|
54
|
+
STDERR.puts "*********************************************************"
|
55
|
+
exit(1)
|
56
|
+
end
|
57
|
+
|
58
|
+
create_makefile ('gpgme_n')
|
Binary file
|
@@ -228,7 +228,7 @@ rb_s_gpgme_data_new (VALUE dummy, VALUE rdh)
|
|
228
228
|
if (gpgme_err_code(err) == GPG_ERR_NO_ERROR)
|
229
229
|
rb_ary_store (rdh, 0, WRAP_GPGME_DATA(dh));
|
230
230
|
return LONG2NUM(err);
|
231
|
-
}
|
231
|
+
}
|
232
232
|
|
233
233
|
static VALUE
|
234
234
|
rb_s_gpgme_data_new_from_mem (VALUE dummy, VALUE rdh, VALUE vbuffer,
|
@@ -249,7 +249,7 @@ rb_s_gpgme_data_new_from_mem (VALUE dummy, VALUE rdh, VALUE vbuffer,
|
|
249
249
|
rb_ary_store (rdh, 0, vdh);
|
250
250
|
}
|
251
251
|
return LONG2NUM(err);
|
252
|
-
}
|
252
|
+
}
|
253
253
|
|
254
254
|
static VALUE
|
255
255
|
rb_s_gpgme_data_new_from_fd (VALUE dummy, VALUE rdh, VALUE vfd)
|
@@ -494,7 +494,7 @@ rb_s_gpgme_set_textmode (VALUE dummy, VALUE vctx, VALUE vyes)
|
|
494
494
|
rb_raise (rb_eArgError, "released ctx");
|
495
495
|
gpgme_set_textmode (ctx, NUM2INT(vyes));
|
496
496
|
return Qnil;
|
497
|
-
}
|
497
|
+
}
|
498
498
|
|
499
499
|
static VALUE
|
500
500
|
rb_s_gpgme_get_textmode (VALUE dummy, VALUE vctx)
|
@@ -507,7 +507,7 @@ rb_s_gpgme_get_textmode (VALUE dummy, VALUE vctx)
|
|
507
507
|
rb_raise (rb_eArgError, "released ctx");
|
508
508
|
yes = gpgme_get_textmode (ctx);
|
509
509
|
return INT2FIX(yes);
|
510
|
-
}
|
510
|
+
}
|
511
511
|
|
512
512
|
static VALUE
|
513
513
|
rb_s_gpgme_set_include_certs (VALUE dummy, VALUE vctx, VALUE vnr_of_certs)
|
@@ -609,7 +609,7 @@ rb_s_gpgme_get_passphrase_cb (VALUE dummy, VALUE vctx, VALUE rpassfunc,
|
|
609
609
|
return Qnil;
|
610
610
|
}
|
611
611
|
|
612
|
-
static void
|
612
|
+
static void
|
613
613
|
progress_cb (void *hook, const char *what, int type, int current, int total)
|
614
614
|
{
|
615
615
|
VALUE vcb = (VALUE)hook, vprogfunc, vhook_value;
|
@@ -657,7 +657,7 @@ rb_s_gpgme_set_locale (VALUE dummy, VALUE vctx, VALUE vcategory, VALUE vvalue)
|
|
657
657
|
{
|
658
658
|
gpgme_ctx_t ctx;
|
659
659
|
gpgme_error_t err;
|
660
|
-
|
660
|
+
|
661
661
|
UNWRAP_GPGME_CTX(vctx, ctx);
|
662
662
|
if (!ctx)
|
663
663
|
rb_raise (rb_eArgError, "released ctx");
|
@@ -1518,7 +1518,7 @@ rb_s_gpgme_op_verify_result (VALUE dummy, VALUE vctx)
|
|
1518
1518
|
gpgme_verify_result_t verify_result;
|
1519
1519
|
gpgme_signature_t signature;
|
1520
1520
|
VALUE vverify_result, vsignatures = rb_ary_new ();
|
1521
|
-
|
1521
|
+
|
1522
1522
|
UNWRAP_GPGME_CTX(vctx, ctx);
|
1523
1523
|
if (!ctx)
|
1524
1524
|
rb_raise (rb_eArgError, "released ctx");
|
@@ -1924,7 +1924,7 @@ rb_s_gpgme_wait (VALUE dummy, VALUE vctx, VALUE rstatus, VALUE vhang)
|
|
1924
1924
|
return Qnil;
|
1925
1925
|
}
|
1926
1926
|
|
1927
|
-
void
|
1927
|
+
void
|
1928
1928
|
Init_gpgme_n (void)
|
1929
1929
|
{
|
1930
1930
|
VALUE mGPGME;
|
Binary file
|
Binary file
|
data/lib/gpgme.rb
CHANGED
@@ -1,1561 +1,108 @@
|
|
1
|
-
|
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
|
1
|
+
$:.push File.expand_path("../..", __FILE__) # C extension is in the root
|
98
2
|
|
99
3
|
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
4
|
|
519
|
-
|
520
|
-
|
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
|
5
|
+
# TODO without this call one can't GPGME::Ctx.new, find out why
|
6
|
+
GPGME::gpgme_check_version(nil)
|
595
7
|
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
|
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
|
8
|
+
require 'gpgme/constants'
|
9
|
+
require 'gpgme/ctx'
|
10
|
+
require 'gpgme/data'
|
11
|
+
require 'gpgme/error'
|
12
|
+
require 'gpgme/io_callbacks'
|
13
|
+
require 'gpgme/key_common'
|
14
|
+
require 'gpgme/key'
|
15
|
+
require 'gpgme/sub_key'
|
16
|
+
require 'gpgme/key_sig'
|
17
|
+
require 'gpgme/misc'
|
18
|
+
require 'gpgme/signature'
|
19
|
+
require 'gpgme/user_id'
|
20
|
+
require 'gpgme/engine'
|
21
|
+
require 'gpgme/crypto'
|
618
22
|
|
619
23
|
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
24
|
class << self
|
25
|
+
|
26
|
+
# From the c extension
|
747
27
|
alias pubkey_algo_name gpgme_pubkey_algo_name
|
748
28
|
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
29
|
|
843
|
-
|
844
|
-
#
|
845
|
-
|
846
|
-
|
847
|
-
|
30
|
+
##
|
31
|
+
# Auxiliary method used by all the library to generate exceptions
|
32
|
+
# from error codes returned by the C extension.
|
33
|
+
def error_to_exception(err)
|
34
|
+
case GPGME::gpgme_err_code(err)
|
35
|
+
when GPG_ERR_EOF
|
36
|
+
EOFError.new
|
37
|
+
when GPG_ERR_NO_ERROR
|
38
|
+
nil
|
39
|
+
when GPG_ERR_GENERAL
|
40
|
+
Error::General.new(err)
|
41
|
+
when GPG_ERR_ENOMEM
|
42
|
+
Errno::ENOMEM.new
|
43
|
+
when GPG_ERR_INV_VALUE
|
44
|
+
Error::InvalidValue.new(err)
|
45
|
+
when GPG_ERR_UNUSABLE_PUBKEY
|
46
|
+
Error::UnusablePublicKey.new(err)
|
47
|
+
when GPG_ERR_UNUSABLE_SECKEY
|
48
|
+
Error::UnusableSecretKey.new(err)
|
49
|
+
when GPG_ERR_NO_DATA
|
50
|
+
Error::NoData.new(err)
|
51
|
+
when GPG_ERR_CONFLICT
|
52
|
+
Error::Conflict.new(err)
|
53
|
+
when GPG_ERR_NOT_IMPLEMENTED
|
54
|
+
Error::NotImplemented.new(err)
|
55
|
+
when GPG_ERR_DECRYPT_FAILED
|
56
|
+
Error::DecryptFailed.new(err)
|
57
|
+
when GPG_ERR_BAD_PASSPHRASE
|
58
|
+
Error::BadPassphrase.new(err)
|
59
|
+
when GPG_ERR_CANCELED
|
60
|
+
Error::Canceled.new(err)
|
61
|
+
when GPG_ERR_INV_ENGINE
|
62
|
+
Error::InvalidEngine.new(err)
|
63
|
+
when GPG_ERR_AMBIGUOUS_NAME
|
64
|
+
Error::AmbiguousName.new(err)
|
65
|
+
when GPG_ERR_WRONG_KEY_USAGE
|
66
|
+
Error::WrongKeyUsage.new(err)
|
67
|
+
when GPG_ERR_CERT_REVOKED
|
68
|
+
Error::CertificateRevoked.new(err)
|
69
|
+
when GPG_ERR_CERT_EXPIRED
|
70
|
+
Error::CertificateExpired.new(err)
|
71
|
+
when GPG_ERR_NO_CRL_KNOWN
|
72
|
+
Error::NoCRLKnown.new(err)
|
73
|
+
when GPG_ERR_NO_POLICY_MATCH
|
74
|
+
Error::NoPolicyMatch.new(err)
|
75
|
+
when GPG_ERR_NO_SECKEY
|
76
|
+
Error::NoSecretKey.new(err)
|
77
|
+
when GPG_ERR_MISSING_CERT
|
78
|
+
Error::MissingCertificate.new(err)
|
79
|
+
when GPG_ERR_BAD_CERT_CHAIN
|
80
|
+
Error::BadCertificateChain.new(err)
|
81
|
+
when GPG_ERR_UNSUPPORTED_ALGORITHM
|
82
|
+
Error::UnsupportedAlgorithm.new(err)
|
83
|
+
when GPG_ERR_BAD_SIGNATURE
|
84
|
+
Error::BadSignature.new(err)
|
85
|
+
when GPG_ERR_NO_PUBKEY
|
86
|
+
Error::NoPublicKey.new(err)
|
848
87
|
else
|
849
|
-
|
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]
|
88
|
+
Error.new(err)
|
1362
89
|
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
90
|
end
|
1442
91
|
|
1443
|
-
|
1444
|
-
|
1445
|
-
|
1446
|
-
|
1447
|
-
|
1448
|
-
|
1449
|
-
|
1450
|
-
|
1451
|
-
|
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
|
92
|
+
##
|
93
|
+
# TODO find out what it does, can't seem to find a proper parameter that
|
94
|
+
# returns something other than nil.
|
95
|
+
def check_version(options = nil)
|
96
|
+
version = nil
|
97
|
+
if options.kind_of?(String)
|
98
|
+
version = options
|
99
|
+
elsif options.include?(:version)
|
100
|
+
version = options[:version]
|
1492
101
|
end
|
1493
|
-
|
1494
|
-
|
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}"
|
102
|
+
unless GPGME::gpgme_check_version(version)
|
103
|
+
raise Error::InvalidVersion.new
|
1506
104
|
end
|
1507
105
|
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
106
|
|
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
107
|
end
|
1561
108
|
end
|