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.
Files changed (49) hide show
  1. data/examples/genkey.rb +1 -1
  2. data/examples/keylist.rb +2 -1
  3. data/examples/roundtrip.rb +7 -4
  4. data/examples/sign.rb +5 -3
  5. data/examples/verify.rb +4 -2
  6. data/ext/gpgme/extconf.rb +58 -0
  7. data/ext/gpgme/gpgme-1.3.1.tar.bz2 +0 -0
  8. data/{gpgme_n.c → ext/gpgme/gpgme_n.c} +8 -8
  9. data/ext/gpgme/libassuan-2.0.2.tar.bz2 +0 -0
  10. data/ext/gpgme/libgpg-error-1.10.tar.bz2 +0 -0
  11. data/lib/gpgme.rb +88 -1541
  12. data/lib/gpgme/compat.rb +2 -0
  13. data/lib/gpgme/constants.rb +23 -0
  14. data/lib/gpgme/crypto.rb +357 -0
  15. data/lib/gpgme/ctx.rb +462 -0
  16. data/lib/gpgme/data.rb +177 -0
  17. data/lib/gpgme/engine.rb +76 -0
  18. data/lib/gpgme/error.rb +66 -0
  19. data/lib/gpgme/io_callbacks.rb +21 -0
  20. data/lib/gpgme/key.rb +242 -0
  21. data/lib/gpgme/key_common.rb +43 -0
  22. data/lib/gpgme/key_sig.rb +35 -0
  23. data/lib/gpgme/misc.rb +66 -0
  24. data/lib/gpgme/signature.rb +85 -0
  25. data/lib/gpgme/sub_key.rb +58 -0
  26. data/lib/gpgme/user_id.rb +20 -0
  27. data/lib/gpgme/version.rb +3 -0
  28. data/test/crypto_test.rb +242 -0
  29. data/test/ctx_test.rb +426 -0
  30. data/test/data_test.rb +116 -0
  31. data/test/files/testkey_pub.gpg +52 -0
  32. data/test/files/testkey_sec.gpg +54 -0
  33. data/test/gpgme_test.rb +12 -0
  34. data/test/key_test.rb +201 -0
  35. data/test/signature_test.rb +48 -0
  36. data/test/sub_key_test.rb +45 -0
  37. data/test/support/resources.rb +516 -0
  38. data/test/test_helper.rb +83 -0
  39. metadata +144 -65
  40. data.tar.gz.sig +0 -3
  41. data/COPYING +0 -340
  42. data/COPYING.LESSER +0 -510
  43. data/Makefile +0 -172
  44. data/Manifest.txt +0 -18
  45. data/README +0 -86
  46. data/Rakefile +0 -17
  47. data/THANKS +0 -15
  48. data/extconf.rb +0 -26
  49. metadata.gz.sig +0 -0
@@ -0,0 +1,177 @@
1
+ module GPGME
2
+
3
+ ##
4
+ # A class whose purpose is to unify the way we work with the data (both input
5
+ # and output). Most of the calls expect instances of this class, or will try
6
+ # to create one from your parameters.
7
+ #
8
+ # Read the {#read}, {#write} and {#seek} methods for the most commonly used
9
+ # methods.
10
+ class Data
11
+
12
+ BLOCK_SIZE = 4096
13
+
14
+ class << self
15
+
16
+ ##
17
+ # We implement +self.new+ instead of initialize because objects are actually
18
+ # instantiated through the C API with stuff like +gpgme_data_new+.
19
+ #
20
+ # We try to create a {GPGME::Data} smartly depending on the object passed, and if
21
+ # another {GPGME::Data} object is passed, it just returns it, so when in
22
+ # doubt, you can always pass a {GPGME::Data} object.
23
+ #
24
+ # @example empty
25
+ # data = GPGME::Data.new
26
+ # data.write("stuff")
27
+ #
28
+ # @example from a string
29
+ # data = GPGME::Data.new("From a string")
30
+ #
31
+ # @example from a file
32
+ # data = GPGME::Data.new(File.open("secure.pass"))
33
+ #
34
+ # @example from a file descriptor
35
+ # data = GPGME::Data.new(0) # Standard input
36
+ # data = GPGME::Data.new(1) # Standard output
37
+ #
38
+ # file = File.open("secure.pass")
39
+ # data = GPGME::Data.new(file.fileno) # file descriptor
40
+ #
41
+ def new(object = nil)
42
+ if object.nil?
43
+ empty!
44
+ elsif object.is_a?(Data)
45
+ object
46
+ elsif object.is_a?(Integer)
47
+ from_fd(object)
48
+ elsif object.respond_to? :to_str
49
+ from_str(object.to_str)
50
+ elsif object.respond_to? :to_io
51
+ from_io(object.to_io)
52
+ elsif object.respond_to? :open
53
+ from_io(object.open)
54
+ end
55
+ end
56
+
57
+ # Create a new instance with an empty buffer.
58
+ def empty!
59
+ rdh = []
60
+ err = GPGME::gpgme_data_new(rdh)
61
+ exc = GPGME::error_to_exception(err)
62
+ raise exc if exc
63
+ rdh.first
64
+ end
65
+
66
+ # Create a new instance with internal buffer.
67
+ def from_str(string)
68
+ rdh = []
69
+ err = GPGME::gpgme_data_new_from_mem(rdh, string, string.length)
70
+ exc = GPGME::error_to_exception(err)
71
+ raise exc if exc
72
+ rdh.first
73
+ end
74
+
75
+ # Create a new instance associated with a given IO.
76
+ def from_io(io)
77
+ from_callbacks(IOCallbacks.new(io))
78
+ end
79
+
80
+ # Create a new instance from the specified file descriptor.
81
+ def from_fd(fd)
82
+ rdh = []
83
+ err = GPGME::gpgme_data_new_from_fd(rdh, fd)
84
+ exc = GPGME::error_to_exception(err)
85
+ raise exc if exc
86
+ rdh.first
87
+ end
88
+
89
+ # Create a new instance from the specified callbacks.
90
+ def from_callbacks(callbacks, hook_value = nil)
91
+ rdh = []
92
+ err = GPGME::gpgme_data_new_from_cbs(rdh, callbacks, hook_value)
93
+ exc = GPGME::error_to_exception(err)
94
+ raise exc if exc
95
+ rdh.first
96
+ end
97
+ end # class << self
98
+
99
+ # Read at most +length+ bytes from the data object, or to the end
100
+ # of file if +length+ is omitted or is +nil+.
101
+ #
102
+ # @example
103
+ # data = GPGME::Data.new("From a string")
104
+ # data.read # => "From a string"
105
+ #
106
+ # @example
107
+ # data = GPGME::Data.new("From a string")
108
+ # data.read(4) # => "From"
109
+ #
110
+ def read(length = nil)
111
+ if length
112
+ GPGME::gpgme_data_read(self, length)
113
+ else
114
+ buf = String.new
115
+ loop do
116
+ s = GPGME::gpgme_data_read(self, BLOCK_SIZE)
117
+ break unless s
118
+ buf << s
119
+ end
120
+ buf
121
+ end
122
+ end
123
+
124
+ ##
125
+ # Seek to a given +offset+ in the data object according to the
126
+ # value of +whence+.
127
+ #
128
+ # @example going to the beginning of the buffer after writing something
129
+ # data = GPGME::Data.new("Some data")
130
+ # data.read # => "Some data"
131
+ # data.read # => ""
132
+ # data.seek 0
133
+ # data.read # => "Some data"
134
+ #
135
+ def seek(offset, whence = IO::SEEK_SET)
136
+ GPGME::gpgme_data_seek(self, offset, IO::SEEK_SET)
137
+ end
138
+
139
+ ##
140
+ # Writes +length+ bytes from +buffer+ into the data object.
141
+ # Writes the full buffer if no length passed.
142
+ #
143
+ # @example
144
+ # data = GPGME::Data.new
145
+ # data.write "hola"
146
+ # data.seek 0
147
+ # data.read # => "hola"
148
+ #
149
+ # @example
150
+ # data = GPGME::Data.new
151
+ # data.write "hola", 2
152
+ # data.seek 0
153
+ # data.read # => "ho"
154
+ #
155
+ def write(buffer, length = buffer.length)
156
+ GPGME::gpgme_data_write(self, buffer, length)
157
+ end
158
+
159
+ ##
160
+ # Return the encoding of the underlying data.
161
+ def encoding
162
+ GPGME::gpgme_data_get_encoding(self)
163
+ end
164
+
165
+ ##
166
+ # Sets the encoding for this buffer. Accepts only values in one of the
167
+ # DATA_ENCODING_* constants.
168
+ #
169
+ # @raise [GPGME::Error::InvalidValue] if the value isn't accepted.
170
+ def encoding=(encoding)
171
+ err = GPGME::gpgme_data_set_encoding(self, encoding)
172
+ exc = GPGME::error_to_exception(err)
173
+ raise exc if exc
174
+ encoding
175
+ end
176
+ end
177
+ end
@@ -0,0 +1,76 @@
1
+ module GPGME
2
+
3
+ ##
4
+ # Convenience methods to check different aspects of the gpg system
5
+ # installation.
6
+ module Engine
7
+ class << self
8
+
9
+ ##
10
+ # Verify that the engine implementing the protocol +proto+ is installed in
11
+ # the system. Can be one of +PROTOCOL_OpenPGP+ or +PROTOCOL_CMS+.
12
+ #
13
+ # @return [Boolean] true if the engine is installed.
14
+ #
15
+ # @example
16
+ # GPGME::Engine.check_version(GPGME::PROTOCOL_OpenPGP) # => true
17
+ #
18
+ def check_version(proto)
19
+ err = GPGME::gpgme_engine_check_version(proto)
20
+ exc = GPGME::error_to_exception(err)
21
+ !exc
22
+ end
23
+
24
+ ##
25
+ # Return an array of {GPGME::EngineInfo} structures of enabled engines.
26
+ #
27
+ # @example
28
+ # GPGME::Engine.engine_info.first
29
+ # # => #<GPGME::EngineInfo:0x00000100d4fbd8
30
+ # @file_name="/usr/local/bin/gpg",
31
+ # @protocol=0,
32
+ # @req_version="1.3.0",
33
+ # @version="1.4.11">
34
+ #
35
+ def info
36
+ rinfo = []
37
+ GPGME::gpgme_get_engine_info(rinfo)
38
+ rinfo
39
+ end
40
+
41
+ ##
42
+ # Change the default configuration of the crypto engine implementing
43
+ # protocol +proto+.
44
+ #
45
+ # @param proto
46
+ # Can be one of +PROTOCOL_OpenPGP+ or +PROTOCOL_CMS+.
47
+ #
48
+ # @param file_name
49
+ # The file name of the executable program implementing the protocol.
50
+ #
51
+ # @param home_dir
52
+ # The directory name of the configuration directory.
53
+ #
54
+ # @example
55
+ # GPGME::Engine.set
56
+ #
57
+ def set_info(proto, file_name, home_dir)
58
+ err = GPGME::gpgme_set_engine_info(proto, file_name, home_dir)
59
+ exc = GPGME::error_to_exception(err)
60
+ raise exc if exc
61
+ end
62
+
63
+ ##
64
+ # Sets the home dir for the configuration options. This way one could,
65
+ # for example, load the keys from a customized keychain.
66
+ #
67
+ # @example
68
+ # GPGME::Engine.home_dir = '/tmp'
69
+ #
70
+ def home_dir=(home_dir)
71
+ current = info.first
72
+ set_info current.protocol, current.file_name, home_dir
73
+ end
74
+ end # class << self
75
+ end # class Engine
76
+ end # module GPGME
@@ -0,0 +1,66 @@
1
+ module GPGME
2
+ class Error < StandardError
3
+ def initialize(error)
4
+ @error = error
5
+ end
6
+ attr_reader :error
7
+
8
+ # Return the error code.
9
+ #
10
+ # The error code indicates the type of an error, or the reason why
11
+ # an operation failed.
12
+ def code
13
+ GPGME::gpgme_err_code(@error)
14
+ end
15
+
16
+ # Return the error source.
17
+ #
18
+ # The error source has not a precisely defined meaning. Sometimes
19
+ # it is the place where the error happened, sometimes it is the
20
+ # place where an error was encoded into an error value. Usually
21
+ # the error source will give an indication to where to look for
22
+ # the problem. This is not always true, but it is attempted to
23
+ # achieve this goal.
24
+ def source
25
+ GPGME::gpgme_err_source(@error)
26
+ end
27
+
28
+ # Return a description of the error code.
29
+ def message
30
+ GPGME::gpgme_strerror(@error)
31
+ end
32
+
33
+ class General < self; end
34
+ class InvalidValue < self; end
35
+ class UnusablePublicKey < self
36
+ attr_accessor :keys
37
+ end
38
+ class UnusableSecretKey < self
39
+ attr_accessor :keys
40
+ end
41
+ class NoData < self; end
42
+ class Conflict < self; end
43
+ class NotImplemented < self; end
44
+ class DecryptFailed < self; end
45
+ class BadPassphrase < self; end
46
+ class Canceled < self; end
47
+ class InvalidEngine < self; end
48
+ class AmbiguousName < self; end
49
+ class WrongKeyUsage < self
50
+ attr_accessor :key_usage
51
+ end
52
+ class CertificateRevoked < self; end
53
+ class CertificateExpired < self; end
54
+ class NoCRLKnown < self; end
55
+ class NoPolicyMatch < self; end
56
+ class NoSecretKey < self; end
57
+ class MissingCertificate < self; end
58
+ class BadCertificateChain < self; end
59
+ class UnsupportedAlgorithm < self
60
+ attr_accessor :algorithm
61
+ end
62
+ class BadSignature < self; end
63
+ class NoPublicKey < self; end
64
+ class InvalidVersion < self; end
65
+ end
66
+ end
@@ -0,0 +1,21 @@
1
+ module GPGME
2
+ class IOCallbacks
3
+ def initialize(io)
4
+ @io = io
5
+ end
6
+
7
+ def read(hook, length)
8
+ @io.read(length)
9
+ end
10
+
11
+ def write(hook, buffer, length)
12
+ @io.write(buffer[0 .. length])
13
+ end
14
+
15
+ def seek(hook, offset, whence)
16
+ return @io.pos if offset == 0 && whence == IO::SEEK_CUR
17
+ @io.seek(offset, whence)
18
+ @io.pos
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,242 @@
1
+ module GPGME
2
+
3
+ ##
4
+ # A ruby representation of a public or a secret key.
5
+ #
6
+ # Every key has two instances of {GPGME::SubKey}, accessible through
7
+ # {.subkeys}, and with a {.primary_subkey} where most attributes are
8
+ # derived from, like the +fingerprint+.
9
+ #
10
+ # Also, every key has at least a {GPGME::UserID}, accessible through
11
+ # {.uids}, with a {.primary_uid}, where other attributes are derived from,
12
+ # like +email+ or +name+
13
+ class Key
14
+ private_class_method :new
15
+
16
+ attr_reader :keylist_mode, :protocol, :owner_trust
17
+ attr_reader :issuer_serial, :issuer_name, :chain_id
18
+ attr_reader :subkeys, :uids
19
+
20
+ include KeyCommon
21
+
22
+ class << self
23
+
24
+ ##
25
+ # Returns an array of {GPGME::Key} objects that match the parameters.
26
+ # * +secret+ set to +:secret+ to get only secret keys, or to +:public+ to
27
+ # get only public keys.
28
+ # * +keys_or_names+ an array or an item that can be either {GPGME::Key}
29
+ # elements, or string identifiers like the email or the sha. Leave
30
+ # blank to get all.
31
+ # * +purposes+ get only keys that are usable for any of these purposes.
32
+ # See {GPGME::Key} for a list of possible key capabilities.
33
+ #
34
+ # @example
35
+ # GPGME::Key.find :secret # => first secret key found
36
+ #
37
+ # @example
38
+ # GPGME::Key.find(:public, "mrsimo@example.com")
39
+ # # => return only public keys that match mrsimo@example.com
40
+ #
41
+ # @example
42
+ # GPGME::Key.find(:public, "mrsimo@example.com", :sign)
43
+ # # => return the public keys that match mrsimo@example.com and are
44
+ # # capable of signing
45
+ def find(secret, keys_or_names = nil, purposes = [])
46
+ secret = (secret == :secret)
47
+ keys_or_names = [""] if keys_or_names.nil? || (keys_or_names.is_a?(Array) && keys_or_names.empty?)
48
+ keys_or_names = [keys_or_names].flatten
49
+ purposes = [purposes].flatten.compact.uniq
50
+
51
+ keys = []
52
+ keys_or_names.each do |key_or_name|
53
+ case key_or_name
54
+ when Key then keys << key_or_name
55
+ when String
56
+ GPGME::Ctx.new do |ctx|
57
+ keys += ctx.keys(key_or_name, secret).select do |k|
58
+ k.usable_for?(purposes)
59
+ end
60
+ end
61
+ end
62
+ end
63
+ keys
64
+ end
65
+
66
+ def get(fingerprint)
67
+ Ctx.new do |ctx|
68
+ ctx.get_key(fingerprint)
69
+ end
70
+ end
71
+
72
+ # Exports public keys
73
+ #
74
+ # GPGME::Key.export pattern, options
75
+ #
76
+ # Private keys cannot be exported due to GPGME restrictions.
77
+ #
78
+ # @param pattern
79
+ # Identifier of the key to export.
80
+ #
81
+ # @param [Hash] options
82
+ # * +:output+ specify where to write the key to. It will be converted to
83
+ # a {GPGME::Data}, so it could be a file, for example.
84
+ # * Any other option accepted by {GPGME::Ctx.new}
85
+ #
86
+ # @return [GPGME::Data] the exported key.
87
+ #
88
+ # @example
89
+ # key = GPGME::Key.export "mrsimo@example.com"
90
+ #
91
+ # @example writing to a file
92
+ # out = File.open("my.key", "w+")
93
+ # GPGME::Key.export "mrsimo@example.com", :output => out
94
+ #
95
+ def export(pattern, options = {})
96
+ output = Data.new(options[:output])
97
+
98
+ GPGME::Ctx.new(options) do |ctx|
99
+ ctx.export_keys(pattern, output)
100
+ end
101
+
102
+ output.seek(0)
103
+ output
104
+ end
105
+
106
+ # Imports a key
107
+ #
108
+ # GPGME::Key.import keydata, options
109
+ #
110
+ # @param keydata
111
+ # The key to import. It will be converted to a {GPGME::Data} object,
112
+ # so could be a file, for example.
113
+ # @param options
114
+ # Any other option accepted by {GPGME::Ctx.new}
115
+ #
116
+ # @example
117
+ # GPGME::Key.import(File.open("my.key"))
118
+ #
119
+ def import(keydata, options = {})
120
+ GPGME::Ctx.new(options) do |ctx|
121
+ ctx.import_keys(Data.new(keydata))
122
+ ctx.import_result
123
+ end
124
+ end
125
+ end
126
+
127
+ ##
128
+ # Exports this key. Accepts the same options as {GPGME::Ctx.new}, and
129
+ # +options[:output]+, where you can specify something that can become a
130
+ # {GPGME::Data}, where the output will go.
131
+ #
132
+ # @example
133
+ # key.export(:armor => true)
134
+ # # => GPGME::Data you can read with ASCII armored format
135
+ #
136
+ # @example
137
+ # file = File.open("key.asc", "w+")
138
+ # key.export(:output => file)
139
+ # # => the key will be written to the file.
140
+ #
141
+ def export(options = {})
142
+ Key.export self.sha, options
143
+ end
144
+
145
+ ##
146
+ # Delete this key. If it's public, and has a secret one it will fail unless
147
+ # +allow_secret+ is specified as true.
148
+ def delete!(allow_secret = false)
149
+ GPGME::Ctx.new do |ctx|
150
+ ctx.delete_key self, allow_secret
151
+ end
152
+ end
153
+
154
+ ##
155
+ # Returns the expiry date for this key
156
+ def expires
157
+ primary_subkey.expires
158
+ end
159
+
160
+ ##
161
+ # Returns true if the key is expired
162
+ def expired
163
+ subkeys.any?(&:expired)
164
+ end
165
+
166
+ def primary_subkey
167
+ @primary_subkey ||= subkeys.first
168
+ end
169
+
170
+ ##
171
+ # Short descriptive value. Can be used to identify the key.
172
+ def sha
173
+ primary_subkey.sha
174
+ end
175
+
176
+ ##
177
+ # Longer descriptive value. Can be used to identify the key.
178
+ def fingerprint
179
+ primary_subkey.fingerprint
180
+ end
181
+
182
+ ##
183
+ # Returns the main {GPGME::UserID} for this key.
184
+ def primary_uid
185
+ uids.first
186
+ end
187
+
188
+ ##
189
+ # Returns the email for this key.
190
+ def email
191
+ primary_uid.email
192
+ end
193
+
194
+ ##
195
+ # Returns the issuer name for this key.
196
+ def name
197
+ primary_uid.name
198
+ end
199
+
200
+ ##
201
+ # Returns the issuer comment for this key.
202
+ def comment
203
+ primary_uid.comment
204
+ end
205
+
206
+ def ==(another_key)
207
+ fingerprint == another_key.fingerprint
208
+ end
209
+
210
+ def inspect
211
+ sprintf("#<#{self.class} %s %4d%s/%s %s trust=%s, owner_trust=%s, \
212
+ capability=%s, subkeys=%s, uids=%s>",
213
+ primary_subkey.secret? ? 'sec' : 'pub',
214
+ primary_subkey.length,
215
+ primary_subkey.pubkey_algo_letter,
216
+ primary_subkey.fingerprint[-8 .. -1],
217
+ primary_subkey.timestamp.strftime('%Y-%m-%d'),
218
+ trust.inspect,
219
+ VALIDITY_NAMES[@owner_trust].inspect,
220
+ capability.inspect,
221
+ subkeys.inspect,
222
+ uids.inspect)
223
+ end
224
+
225
+ def to_s
226
+ primary_subkey = subkeys[0]
227
+ s = sprintf("%s %4d%s/%s %s\n",
228
+ primary_subkey.secret? ? 'sec' : 'pub',
229
+ primary_subkey.length,
230
+ primary_subkey.pubkey_algo_letter,
231
+ primary_subkey.fingerprint[-8 .. -1],
232
+ primary_subkey.timestamp.strftime('%Y-%m-%d'))
233
+ uids.each do |user_id|
234
+ s << "uid\t\t#{user_id.name} <#{user_id.email}>\n"
235
+ end
236
+ subkeys.each do |subkey|
237
+ s << subkey.to_s
238
+ end
239
+ s
240
+ end
241
+ end
242
+ end