rubygems-openpgp 0.2.1 → 0.3.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.tar.gz.asc +8 -8
- data/README.md +42 -228
- data/lib/rubygems/commands/sign_command.rb +1 -2
- data/lib/rubygems/commands/verify_command.rb +6 -2
- data/lib/rubygems/gem_openpgp.rb +23 -19
- data/lib/rubygems_plugin.rb +52 -2
- data/test/test_rubygems-openpgp.rb +4 -3
- metadata +27 -25
- metadata.gz.asc +8 -8
- data/lib/rubygems/commands/sbuild_command.rb +0 -35
- data/lib/rubygems/commands/vinstall_command.rb +0 -37
data.tar.gz.asc
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
-----BEGIN PGP SIGNATURE-----
|
2
|
-
Version: GnuPG
|
2
|
+
Version: GnuPG/MacGPG2 v2.0.17 (Darwin)
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
=
|
4
|
+
iQEcBAABCgAGBQJRF6UkAAoJEP5F5V2hilTWp4EH/Ah94Ny5XMyjejkTuTAZPZw8
|
5
|
+
6jG5gQ0dl5l8c6VyXgLNwSDmCt0Rj5J1ZVvkz8LXj7xJpDyXu77Gk2FCDS30R7vH
|
6
|
+
4C3LbUdIGv5FhMGQ2CiVgPNbi8CRsNmnFg15otY782Uvu8sMbspkrVi31wFvWCz7
|
7
|
+
Ik9tHle42aNwg5sYhYWi4gIHiLfQ3l+g6C2YJ38R/hKdU9J3Vu9RWxk3aAsSsuTp
|
8
|
+
aEDxGvTkX+N9vUEdDIvpkZ7iuhATxiP4TpZo3vFORe0iwo44XQaZJQPb4jMKmnJt
|
9
|
+
b9Q7a1o/WpmcPrnGDaHvsjPj4P5dFzaktDaafBCo7GUsws7JhN1sKZX1F4GSVjc=
|
10
|
+
=FURw
|
11
11
|
-----END PGP SIGNATURE-----
|
data/README.md
CHANGED
@@ -1,52 +1,45 @@
|
|
1
1
|
rubygems-openpgp
|
2
2
|
================
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
much better choice than X509 certificates for verifying open source
|
7
|
-
components.
|
8
|
-
|
9
|
-
My proposal as to why we should do so, and how to add certification
|
10
|
-
infrastructure into place, follows. Note this project doesn't attempt
|
11
|
-
to address the issue of creating a ruby gem Signing Authority.
|
12
|
-
|
13
|
-
Prerequisites
|
14
|
-
-------------
|
15
|
-
|
16
|
-
A working installation of gpg.
|
4
|
+
Software Assurance
|
5
|
+
------------------
|
17
6
|
|
18
|
-
|
7
|
+
To assure the validity of any software package, you need to:
|
19
8
|
|
20
|
-
|
21
|
-
|
9
|
+
* Verify that the package has not been corrupted or maliciously
|
10
|
+
tampered with by verifying the file's checksum.
|
22
11
|
|
23
|
-
|
24
|
-
|
25
|
-
lazy or impatient to do so, you can get started quickly by:
|
12
|
+
* Verify that the checksum has not been tampered with by validating a
|
13
|
+
digital signature of that checksum.
|
26
14
|
|
27
|
-
|
28
|
-
|
15
|
+
* Verify that the digital signature was produced by the package's
|
16
|
+
publisher by authenticating the public key that was used to generate
|
17
|
+
the digital signature.
|
29
18
|
|
30
|
-
|
19
|
+
If you can't do this, you can't verify the integrity of the package.
|
31
20
|
|
32
|
-
|
21
|
+
This gem allows cryptographic signing of ruby gems with OpenPGP
|
22
|
+
instead of the current built-in signing method involving X.509.
|
33
23
|
|
34
|
-
|
35
|
-
|
24
|
+
[Read more about why we should use OpenPGP.](./doc/motivation.md)
|
25
|
+
Here's the [slides](http://bit.ly/TUtT3S) and
|
26
|
+
[video](http://vimeo.com/album/2255908/video/59297058) from a
|
27
|
+
lightning talk I did at [Pittsburgh.rb](http://pghrb.heroku.com/).
|
28
|
+
|
29
|
+
Prerequisites
|
30
|
+
-------------
|
36
31
|
|
37
|
-
|
32
|
+
A working installation of gpg.
|
38
33
|
|
39
|
-
|
40
|
-
key if a malicious user gains access.
|
34
|
+
An OpenPGP private key is required to sign gems, but not to verify.
|
41
35
|
|
42
|
-
|
36
|
+
[Getting started with gpg.](./doc/getting-started-with-gpg.md)
|
43
37
|
|
44
38
|
Signing example
|
45
39
|
---------------
|
46
40
|
|
47
|
-
|
48
|
-
|
49
|
-
gem push opnepgp_signed_hola-0.0.0.gemspec
|
41
|
+
gem build openpgp_signed_hola.gemspec --sign
|
42
|
+
gem push opnepgp_signed_hola-0.0.0.gem
|
50
43
|
|
51
44
|
Verification Example
|
52
45
|
--------------------
|
@@ -54,209 +47,30 @@ Verification Example
|
|
54
47
|
A test gem **openpgp_signed_hola** is on rubygems.org. To try out
|
55
48
|
this extension:
|
56
49
|
|
57
|
-
|
58
|
-
gem verify openpgp_signed_hola-0.0.0.gem
|
59
|
-
gem install openpgp_signed_hola-0.0.0.gem
|
50
|
+
gem install openpgp_signed_hola-0.0.0.gem --verify
|
60
51
|
|
61
52
|
But That Just Failed!
|
62
53
|
---------------------
|
63
54
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
gem verify --get-key openpgp_signed_hola-0.0.0.gem
|
69
|
-
|
70
|
-
The key will be automatically downloaded, and verification should now
|
71
|
-
succeed.
|
72
|
-
|
73
|
-
There are security implications here. You've downloaded the key based
|
74
|
-
on the information contained in the gem itself. If a malicious user
|
75
|
-
has tampered with the gem, they could easily provide a forged OpenPGP
|
76
|
-
key as well. This is why your output includes the following warning:
|
77
|
-
|
78
|
-
gpg: WARNING: This key is not certified with a trusted signature!
|
79
|
-
gpg: There is no indication that the signature belongs to the owner.
|
80
|
-
|
81
|
-
You still don't know if this key *really* belongs to me. If possible,
|
82
|
-
you should verify the key signature through an out-band-channel. This
|
83
|
-
may be the project page, a release email from the author, or some
|
84
|
-
other means.
|
85
|
-
|
86
|
-
For example, you can obtain the fingerprint on my key from [my
|
87
|
-
personal website](http://www.grant-olson.net/openpgp-key).
|
88
|
-
|
89
|
-
I've also included it right here in the README hosted on github:
|
90
|
-
|
91
|
-
pub 2048R/E3B5806F 2010-01-11 [expires: 2012-01-04]
|
92
|
-
Key fingerprint = A530 C31C D762 0D26 E2BA C384 B6F6 FFD0 E3B5 806F
|
93
|
-
uid Grant T. Olson (Personal email) <kgo@grant-olson.net>
|
94
|
-
uid Grant T. Olson (pikimal) <grant@pikimal.com>
|
95
|
-
sub 2048R/6A8F7CF6 2010-01-11 [expires: 2012-01-04]
|
96
|
-
sub 2048R/A18A54D6 2010-03-01 [expires: 2012-01-04]
|
97
|
-
sub 2048R/D53982CE 2010-08-31 [expires: 2012-01-04]
|
98
|
-
|
99
|
-
Even better would be obtaining the key fingerprint from me personally,
|
100
|
-
but this can often be impractical.
|
101
|
-
|
102
|
-
In any case, you should verify the key fingerprint listed in the
|
103
|
-
message from one of these alternate sources. If they match, the
|
104
|
-
signature is (hopefully) valid, assuming an attacker hasn't managed to
|
105
|
-
compromise rubygems, github, and my personal website.
|
106
|
-
|
107
|
-
If the fingerprints DO NOT match, you probably want to delete the
|
108
|
-
invalid key from your keyring:
|
109
|
-
|
110
|
-
gpg --delete-key <<KEY_ID>>
|
111
|
-
|
112
|
-
If you feel confident that the key is valid based on your external
|
113
|
-
fingerprint checks, you can make a signature on your gpg keyring. I
|
114
|
-
would advise making a local signature unless you've validated the
|
115
|
-
fingerprint in person. This means that you feel confident that the
|
116
|
-
key is valid, but you're not making any representations to the outside
|
117
|
-
world. To do so, run:
|
118
|
-
|
119
|
-
gpg --lsign <<KEY_ID>>
|
120
|
-
|
121
|
-
After this, you will no longer receive WARNINGs about untrusted
|
122
|
-
sources for any gems signed by this key/author.
|
123
|
-
|
124
|
-
Unfortunately, authentication is a hard problem. See my proposal
|
125
|
-
below for a potential solution to provide reasonable assurances about
|
126
|
-
key validity without having to manually confirm everything.
|
127
|
-
|
128
|
-
Motivation
|
129
|
-
----------
|
130
|
-
|
131
|
-
### Why we should sign gems with gpg
|
132
|
-
|
133
|
-
Gems are currently signed via X509 certificates generated by OpenSSL.
|
134
|
-
I don't think X509 signatures are the way to go. I think we should use
|
135
|
-
OpenPGP signatures instead.
|
136
|
-
|
137
|
-
1. Self-signed X509 certificates are basically worthless. There's no
|
138
|
-
easy way to verify that the key is legitimate. OpenPGP certificates
|
139
|
-
are designed to be generated by you, and then signed by other people
|
140
|
-
to validate their authenticity.
|
141
|
-
|
142
|
-
2. Setting up an X509 CA will take some resources. OpenPGP already
|
143
|
-
has a dedicated pool of servers run by volunteers at
|
144
|
-
pool.sks-keyservers.net.
|
145
|
-
|
146
|
-
3. The current generation policy isn't so good. Your private key
|
147
|
-
isn't encrypted. It's a strange file in a strange location that could
|
148
|
-
easily be lost. In gpg, all files are stored in ~/.gnupg. Private
|
149
|
-
keys are encrypted by default.
|
150
|
-
|
151
|
-
4. gpg has better tooling and documentation than openssl. There are
|
152
|
-
plenty of things like Seahorse or GPA to examine your keys. Policies
|
153
|
-
are documented and explained.
|
154
|
-
|
155
|
-
5. gpg allows the user to decide their default threat model and key
|
156
|
-
verification model. X509 assumes you trust the powers that be.
|
157
|
-
|
158
|
-
6. The OpenPGP certificate will (optionally) be tied to the owner's
|
159
|
-
real life id, if (for example) they sign release emails, use git's
|
160
|
-
signing functionality on release tags, sign binary releases. This
|
161
|
-
makes it easier to verify that the key isn't forged. (See trust model
|
162
|
-
3 below.)
|
163
|
-
|
164
|
-
The way I envision it, a gem maintainer would generate and publish a
|
165
|
-
key with gpg if they didn't already have one. He would put the key id
|
166
|
-
in the gem configuration file. When he builds the gem, gpg kicks in
|
167
|
-
and signs it.
|
168
|
-
|
169
|
-
An end user who wants to verify the key runs a command after fetching
|
170
|
-
the gem. If they have the key, we run gpg and verify the signature.
|
171
|
-
If not, we provide the key id so they can download it manually with
|
172
|
-
gpg.
|
173
|
-
|
174
|
-
The code to implement this should be pretty simple.
|
175
|
-
|
176
|
-
### Authenticating keys / Certificate authority
|
177
|
-
|
178
|
-
With gpg, the user can determine their trust model.
|
179
|
-
|
180
|
-
1. The current model. The user doesn't care. They don't check gpg
|
181
|
-
sigs. All is well. I imagine this will still be the model used by a
|
182
|
-
strong majority of users.
|
183
|
-
|
184
|
-
2. The user uses the OpenPGP web of trust. To be honest, this is a
|
185
|
-
PITA. It involves getting into the strong set by meeting people in
|
186
|
-
person and exchanging key fingerprints to make sure that there's no
|
187
|
-
man-in-the-middle attack. And even if the user is in the strong set,
|
188
|
-
there's no guarantee the gem maintainer is.
|
189
|
-
|
190
|
-
3. Continuity model. I downloaded the signing key for Ubuntu about four
|
191
|
-
releases ago. Even though I haven't done full verification, there
|
192
|
-
haven't been any reports of problems, and the next three releases were
|
193
|
-
signed by the same key. If the key changed and gpg couldn't verify the
|
194
|
-
next Ubuntu release, it would raise some eyebrows. You can use the same
|
195
|
-
philosophy with gems.
|
196
|
-
|
197
|
-
4. Simulated CA. Similar to the way a distributed source control system
|
198
|
-
can be used as a centralized system, the OpenPGP web of trust can be
|
199
|
-
setup to act as if there's a certificate authority.
|
200
|
-
|
201
|
-
For an example of option 4, look at the PGP Corp Global Directory[1].
|
202
|
-
You go to the website and submit your public key. It sends you an email
|
203
|
-
that you need to reply to. If you reply, signs your key and
|
204
|
-
publishes the information. If another user trusts the Global Directory
|
205
|
-
key, they will now trust your key.
|
206
|
-
|
207
|
-
Technically, this is subject to a man-in-the-middle attack. But it's
|
208
|
-
the same policy that gets used when I forget my password at something
|
209
|
-
like Amazon. And Amazon has my credit card info. I think the
|
210
|
-
procedure is valid against all but the most exotic attacks as long as
|
211
|
-
its limitations are known and documented.
|
212
|
-
|
213
|
-
[For conciseness' sake, I'm just going to pretend we've agreed that
|
214
|
-
rubygems.org is the Signing Authority. It will probably be a more
|
215
|
-
beta application, at least at first. Right now I'm more concerned
|
216
|
-
with presenting the model.]
|
217
|
-
|
218
|
-
rubygems.org could:
|
219
|
-
|
220
|
-
1. Allow gem publisher to upload a private key from their account page.
|
221
|
-
|
222
|
-
2. Upon receipt of key, send an email to the gem publisher's email
|
223
|
-
containing an encrypted token.
|
224
|
-
|
225
|
-
3. The gem publisher decrypts the token,
|
226
|
-
|
227
|
-
4. The gem publisher posts the decrypted token onto a form at the
|
228
|
-
website and submits. This establishes the gem publisher has control of
|
229
|
-
(a) the email address, and (b) the OpenPGP key. (Excluding a possible
|
230
|
-
mitm at the network level.)
|
231
|
-
|
232
|
-
5. rubygems.org signs the key with it's own signing key, possibly with a
|
233
|
-
6 month or 1 year expiration date.
|
234
|
-
|
235
|
-
6. The new signature is submitted to the keyservers at
|
236
|
-
pool.sks-keyservers.net, making the verification available world-wide.
|
55
|
+
You probably don't have my public key yet. You need my public key to
|
56
|
+
verify the digital signature. You also want to perform some
|
57
|
+
authentication of that public key.
|
237
58
|
|
238
|
-
|
239
|
-
signing key. When they download the gem from above and retrieve the gem
|
240
|
-
publisher's key, they will see that the key is valid because it's
|
241
|
-
trusted by rubygems. If it's not trusted, it's up to User B to
|
242
|
-
investigate and determine if they trust the gem or not.
|
59
|
+
[Notes on retrieving and authenticating public keys.](./doc/retrieving-and-authenticating-keys.md)
|
243
60
|
|
244
|
-
|
245
|
-
|
246
|
-
provides the same gem with the same signature, it will still show up as
|
247
|
-
valid, assuming the gem user trusts the rubygems.org signing key.
|
61
|
+
Verifying your initial install
|
62
|
+
------------------------------
|
248
63
|
|
249
|
-
|
64
|
+
All versions of this gem should be signed. But the first time you
|
65
|
+
install the package you run into a bit of a chicken-and-the-egg
|
66
|
+
problem. You can't verify the package until you've installed a copy.
|
67
|
+
But if that copy isn't verified, if could already be compromised.
|
250
68
|
|
251
|
-
|
252
|
-
|
253
|
-
|
69
|
+
But don't worry. You can use a stand-alone signature to verify your
|
70
|
+
initial install. Since the stand-alone signature is on github, and
|
71
|
+
the software package is on rubygems.org, a malicious user would need
|
72
|
+
to compromise both sites to publish a compromised gem and
|
73
|
+
compromised/forged digital signature.
|
254
74
|
|
255
|
-
|
256
|
-
installation. When downloading a new gem, verification will happen
|
257
|
-
automatically. If the key isn't on the gem keyring it will be
|
258
|
-
downloaded automatically. If the key isn't trusted, the user will
|
259
|
-
receive a warning and asked if they want to continue. If the signature
|
260
|
-
check fails, the gem will not be installed.
|
75
|
+
[Notes on verifying the initial install.](./doc/verifying-initial-install.md)
|
261
76
|
|
262
|
-
[1] https://keyserver.pgp.com/vkd/GetWelcomeScreen.event
|
@@ -38,8 +38,7 @@ class Gem::Commands::SignCommand < Gem::Command
|
|
38
38
|
def execute # :nodoc:
|
39
39
|
version = options[:version] || Gem::Requirement.default
|
40
40
|
gem, specs = get_one_gem_name, []
|
41
|
-
|
42
|
-
say output.join("\n")
|
41
|
+
Gem::OpenPGP.sign_gem gem, key=options[:key]
|
43
42
|
end
|
44
43
|
|
45
44
|
end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'rubygems/command'
|
2
2
|
require 'rubygems/package'
|
3
|
+
require 'rubygems/user_interaction'
|
3
4
|
require 'rubygems/version_option'
|
4
5
|
require 'rubygems/gem_openpgp'
|
5
6
|
|
@@ -12,6 +13,7 @@ require 'rubygems/gem_openpgp'
|
|
12
13
|
class Gem::Commands::VerifyCommand < Gem::Command
|
13
14
|
|
14
15
|
include Gem::VersionOption
|
16
|
+
include Gem::UserInteraction
|
15
17
|
|
16
18
|
def initialize # :nodoc:
|
17
19
|
super 'verify', 'Verifies a local gem that has been signed via OpenPGP. This helps to ensure the gem has not been tampered with in transit.'
|
@@ -39,8 +41,10 @@ class Gem::Commands::VerifyCommand < Gem::Command
|
|
39
41
|
def execute # :nodoc:
|
40
42
|
version = options[:version] || Gem::Requirement.default
|
41
43
|
gem, specs = get_one_gem_name, []
|
42
|
-
|
43
|
-
|
44
|
+
Gem::OpenPGP.verify_gem gem, get_key=options[:get_key]
|
45
|
+
rescue Gem::OpenPGPException => ex
|
46
|
+
alert_error(ex.message)
|
47
|
+
terminate_interaction(1)
|
44
48
|
end
|
45
49
|
|
46
50
|
end
|
data/lib/rubygems/gem_openpgp.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'rubygems/package'
|
3
|
+
require 'rubygems/user_interaction'
|
4
|
+
require 'shellwords'
|
3
5
|
require 'open3'
|
4
6
|
require 'tempfile'
|
5
7
|
|
@@ -9,6 +11,8 @@ class Gem::OpenPGPException < RuntimeError; end
|
|
9
11
|
# A wrapper that shells out the real OpenPGP crypto work
|
10
12
|
# to gpg.
|
11
13
|
module Gem::OpenPGP
|
14
|
+
extend Shellwords
|
15
|
+
extend Gem::UserInteraction
|
12
16
|
|
13
17
|
# Given a string of data, generate and return a detached
|
14
18
|
# signature. By defualt, this will use your primary secret key.
|
@@ -20,10 +24,10 @@ module Gem::OpenPGP
|
|
20
24
|
is_homedir_valid homedir if homedir
|
21
25
|
|
22
26
|
key_flag = ""
|
23
|
-
key_flag = "-u #{key_id}" if key_id
|
27
|
+
key_flag = "-u #{shellescape(key_id)}" if key_id
|
24
28
|
|
25
29
|
homedir_flag = ""
|
26
|
-
homedir_flag = "--homedir #{homedir}" if homedir
|
30
|
+
homedir_flag = "--homedir #{shellescape(homedir)}" if homedir
|
27
31
|
|
28
32
|
cmd = "gpg #{key_flag} #{homedir_flag} --detach-sign --armor"
|
29
33
|
sig, err = run_gpg_command cmd, data
|
@@ -61,8 +65,6 @@ module Gem::OpenPGP
|
|
61
65
|
# Optional param "key" allows you to use a different private
|
62
66
|
# key than the GPG default.
|
63
67
|
def self.sign_gem gem, key=nil, homedir=nil
|
64
|
-
output = []
|
65
|
-
|
66
68
|
unsigned_gem = gem + ".unsigned"
|
67
69
|
|
68
70
|
begin
|
@@ -77,14 +79,14 @@ module Gem::OpenPGP
|
|
77
79
|
signed_gem = Gem::Package::TarWriter.new(signed_gem_file)
|
78
80
|
|
79
81
|
Gem::Package::TarReader.new(unsigned_gem_file).each do |f|
|
80
|
-
|
82
|
+
say(f.full_name.inspect)
|
81
83
|
|
82
84
|
if f.full_name[-4..-1] == ".asc"
|
83
|
-
|
85
|
+
say("Skipping old signature file #{f.full_name}")
|
84
86
|
next
|
85
87
|
end
|
86
88
|
|
87
|
-
|
89
|
+
say("Signing #{f.full_name.inspect}...")
|
88
90
|
|
89
91
|
file_contents = f.read()
|
90
92
|
|
@@ -102,7 +104,6 @@ module Gem::OpenPGP
|
|
102
104
|
unsigned_gem_file.close
|
103
105
|
File.delete unsigned_gem_file
|
104
106
|
|
105
|
-
output
|
106
107
|
rescue Exception => ex
|
107
108
|
if unsigned_gem_file
|
108
109
|
FileUtils.mv unsigned_gem_file, gem
|
@@ -112,7 +113,6 @@ module Gem::OpenPGP
|
|
112
113
|
end
|
113
114
|
|
114
115
|
def self.verify_gem gem, get_key=false, homedir=nil
|
115
|
-
output =[]
|
116
116
|
|
117
117
|
begin
|
118
118
|
file = File.open(gem,"r")
|
@@ -128,28 +128,28 @@ module Gem::OpenPGP
|
|
128
128
|
|
129
129
|
tar_files.keys.each do |file_name|
|
130
130
|
next if file_name[-4..-1] == ".asc"
|
131
|
-
|
131
|
+
say "Verifying #{file_name}..."
|
132
132
|
|
133
133
|
sig_file_name = file_name + ".asc"
|
134
134
|
if !tar_files.has_key? sig_file_name
|
135
|
-
|
136
|
-
|
135
|
+
say add_color("WARNING!!! No sig found for #{file_name}", :red)
|
136
|
+
raise Gem::OpenPGPException, "Can't verify without sig, aborting!!!"
|
137
137
|
end
|
138
138
|
|
139
139
|
begin
|
140
140
|
err, res = Gem::OpenPGP.verify(tar_files[file_name], tar_files[sig_file_name], get_key, homedir)
|
141
141
|
|
142
|
-
|
143
|
-
|
142
|
+
say add_color(err, :green)
|
143
|
+
say add_color(res, :green)
|
144
144
|
rescue Gem::OpenPGPException => ex
|
145
145
|
color_code = "31"
|
146
|
-
|
146
|
+
say add_color(ex.message, :red)
|
147
|
+
raise
|
147
148
|
end
|
148
149
|
end
|
149
150
|
|
150
|
-
|
151
|
-
|
152
|
-
output
|
151
|
+
ensure
|
152
|
+
file.close unless file.nil?
|
153
153
|
end
|
154
154
|
|
155
155
|
private
|
@@ -209,5 +209,9 @@ private
|
|
209
209
|
#TODO - NO-OP on windows
|
210
210
|
"\033[#{color_code}m#{s}\033[0m"
|
211
211
|
end
|
212
|
-
|
212
|
+
|
213
|
+
def self.options
|
214
|
+
@options ||= {}
|
215
|
+
@options
|
216
|
+
end
|
213
217
|
end
|
data/lib/rubygems_plugin.rb
CHANGED
@@ -1,6 +1,56 @@
|
|
1
1
|
require 'rubygems/command_manager'
|
2
|
+
require 'rubygems/gem_openpgp'
|
2
3
|
|
3
4
|
Gem::CommandManager.instance.register_command :sign
|
4
5
|
Gem::CommandManager.instance.register_command :verify
|
5
|
-
|
6
|
-
#
|
6
|
+
|
7
|
+
# gem build hooks
|
8
|
+
b = Gem::CommandManager.instance[:build]
|
9
|
+
b.add_option("--sign", "Sign gem with OpenPGP.") do |value, options|
|
10
|
+
Gem::OpenPGP.options[:sign] = true
|
11
|
+
end
|
12
|
+
|
13
|
+
b.add_option('--key KEY', "Specify key id if you don't want to use your default gpg key") do |key, options|
|
14
|
+
Gem::OpenPGP.options[:key] = key
|
15
|
+
end
|
16
|
+
|
17
|
+
class Gem::Commands::BuildCommand
|
18
|
+
alias_method :original_execute, :execute
|
19
|
+
def execute
|
20
|
+
original_execute
|
21
|
+
|
22
|
+
if Gem::OpenPGP.options[:sign]
|
23
|
+
gemspec = get_one_gem_name
|
24
|
+
if File.exist? gemspec then
|
25
|
+
spec = Gem::Specification.load gemspec
|
26
|
+
file_name = File.join(".", File.basename(spec.cache_file))
|
27
|
+
Gem::OpenPGP.sign_gem file_name, key=Gem::OpenPGP.options[:key]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# gem install hooks
|
34
|
+
i = Gem::CommandManager.instance[:install]
|
35
|
+
i.add_option("--verify",
|
36
|
+
'Verifies a local gem that has been signed via OpenPGP.' +
|
37
|
+
'This helps to ensure the gem has not been tampered with in transit.') do |value, options|
|
38
|
+
Gem::OpenPGP.options[:verify] = true
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
i.add_option('--get-key', "If the key is not available, download it from a keyserver") do |key, options|
|
43
|
+
Gem::OpenPGP.options[:get_key] = true
|
44
|
+
end
|
45
|
+
|
46
|
+
Gem.pre_install do |installer|
|
47
|
+
begin
|
48
|
+
if Gem::OpenPGP.options[:verify]
|
49
|
+
Gem::OpenPGP.verify_gem(installer.gem,
|
50
|
+
Gem::OpenPGP.options[:get_key])
|
51
|
+
end
|
52
|
+
rescue Gem::OpenPGPException => ex
|
53
|
+
installer.alert_error(ex.message)
|
54
|
+
installer.terminate_interaction(1)
|
55
|
+
end
|
56
|
+
end
|
@@ -20,8 +20,9 @@ class RubygemsPluginTest < Test::Unit::TestCase
|
|
20
20
|
|
21
21
|
def test_gem_sign_and_verify
|
22
22
|
in_tmp_gpg_homedir do |gpg_home|
|
23
|
-
|
24
|
-
|
23
|
+
assert_raise Gem::OpenPGPException do
|
24
|
+
Gem::OpenPGP.verify_gem UNSIGNED_GEM, false, gpg_home
|
25
|
+
end
|
25
26
|
|
26
27
|
FileUtils.cp UNSIGNED_GEM, SIGNED_GEM
|
27
28
|
|
@@ -31,7 +32,7 @@ class RubygemsPluginTest < Test::Unit::TestCase
|
|
31
32
|
end
|
32
33
|
end
|
33
34
|
ensure
|
34
|
-
File.delete SIGNED_GEM
|
35
|
+
File.delete(SIGNED_GEM) if File.exists?(SIGNED_GEM)
|
35
36
|
end
|
36
37
|
|
37
38
|
def test_basic_sign_and_verify
|
metadata
CHANGED
@@ -1,30 +1,31 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: rubygems-openpgp
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.1
|
3
|
+
version: !ruby/object:Gem::Version
|
5
4
|
prerelease:
|
5
|
+
version: 0.3.0
|
6
6
|
platform: ruby
|
7
|
-
authors:
|
7
|
+
authors:
|
8
8
|
- Grant Olson
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
|
13
|
-
|
12
|
+
|
13
|
+
date: 2013-02-10 00:00:00 Z
|
14
14
|
dependencies: []
|
15
|
+
|
15
16
|
description: Digitally sign gems via OpenPGP instead of OpenSSL
|
16
17
|
email: kgo@grant-olson.net
|
17
18
|
executables: []
|
19
|
+
|
18
20
|
extensions: []
|
19
|
-
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
20
23
|
- README.md
|
21
|
-
files:
|
24
|
+
files:
|
22
25
|
- LICENSE
|
23
26
|
- Rakefile
|
24
27
|
- lib/rubygems_plugin.rb
|
25
28
|
- lib/rubygems/commands/verify_command.rb
|
26
|
-
- lib/rubygems/commands/vinstall_command.rb
|
27
|
-
- lib/rubygems/commands/sbuild_command.rb
|
28
29
|
- lib/rubygems/commands/sign_command.rb
|
29
30
|
- lib/rubygems/gem_openpgp.rb
|
30
31
|
- README.md
|
@@ -32,33 +33,34 @@ files:
|
|
32
33
|
- test/pablo_escobar_seckey.asc
|
33
34
|
- test/pablo_escobar_pubkey.asc
|
34
35
|
- test/unsigned_hola-0.0.0.gem
|
35
|
-
has_rdoc: true
|
36
36
|
homepage: https://github.com/grant-olson/rubygems-openpgp
|
37
|
-
licenses:
|
37
|
+
licenses:
|
38
38
|
- BSD 3 Clause
|
39
39
|
post_install_message:
|
40
40
|
rdoc_options: []
|
41
|
-
|
41
|
+
|
42
|
+
require_paths:
|
42
43
|
- lib
|
43
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
44
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
44
45
|
none: false
|
45
|
-
requirements:
|
46
|
-
- -
|
47
|
-
- !ruby/object:Gem::Version
|
48
|
-
version:
|
49
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - ">="
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: "0"
|
50
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
50
51
|
none: false
|
51
|
-
requirements:
|
52
|
-
- -
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
version:
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: "0"
|
55
56
|
requirements: []
|
57
|
+
|
56
58
|
rubyforge_project:
|
57
|
-
rubygems_version: 1.
|
59
|
+
rubygems_version: 1.8.24
|
58
60
|
signing_key:
|
59
61
|
specification_version: 3
|
60
62
|
summary: Sign gems via OpenPGP
|
61
|
-
test_files:
|
63
|
+
test_files:
|
62
64
|
- test/test_rubygems-openpgp.rb
|
63
65
|
- test/pablo_escobar_seckey.asc
|
64
66
|
- test/pablo_escobar_pubkey.asc
|
metadata.gz.asc
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
-----BEGIN PGP SIGNATURE-----
|
2
|
-
Version: GnuPG
|
2
|
+
Version: GnuPG/MacGPG2 v2.0.17 (Darwin)
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
=
|
4
|
+
iQEcBAABCgAGBQJRF6UqAAoJEP5F5V2hilTW4WgIAL4AJ1PPxZv+AuAwxBOFgIqR
|
5
|
+
m8tM5N9bNM+KVwBplbIpl1cP/VJFN6onDeNlEY0YlCSR/EHuCOvtjCB8AFquAy72
|
6
|
+
+zNxniM0d9zcEL0JRx2SLl44EBQOaFAYZ6VgLbkox9OuwUjSeEfdo66gfMtgdkHN
|
7
|
+
+Tl5XKjnu5cnszfBXqfHKLdSjhAYbk0TeGRicffFDLMn7jzwwmOd9uLMmG3CrPg0
|
8
|
+
mZiZpYWoazFPDnQ+KKj12ojcUCjFc/D8Xy77e2G2PP8kVOKb79Gn6Fd+npJuXL1X
|
9
|
+
/8Uzkrpwc3EGCpMzT0/q4EyHc35CkaFtdbAhd4n33Rob4j+yIhi0j72tttfv1Jk=
|
10
|
+
=VFwb
|
11
11
|
-----END PGP SIGNATURE-----
|
@@ -1,35 +0,0 @@
|
|
1
|
-
require "rubygems/command"
|
2
|
-
require 'rubygems/version_option'
|
3
|
-
|
4
|
-
# currently unimplemented.
|
5
|
-
# This will build and sign with a single command.
|
6
|
-
class Gem::Commands::SbuildCommand < Gem::Command # :nodoc:
|
7
|
-
|
8
|
-
include Gem::VersionOption
|
9
|
-
|
10
|
-
def initialize # :nodoc:
|
11
|
-
super 'sbuild', 'Build your gem, then sign it with OpenPGP'
|
12
|
-
|
13
|
-
add_version_option
|
14
|
-
|
15
|
-
end
|
16
|
-
|
17
|
-
def arguments # :nodoc:
|
18
|
-
"GEMNAME name of gem to build"
|
19
|
-
end
|
20
|
-
|
21
|
-
def defaults_str # :nodoc:
|
22
|
-
""
|
23
|
-
end
|
24
|
-
|
25
|
-
def usage # :nodoc:
|
26
|
-
"blah blah"
|
27
|
-
end
|
28
|
-
|
29
|
-
def execute # :nodoc:
|
30
|
-
version = options[:version] || Gem::Requirement.default
|
31
|
-
|
32
|
-
raise "Not implemented yet"
|
33
|
-
end
|
34
|
-
|
35
|
-
end
|
@@ -1,37 +0,0 @@
|
|
1
|
-
require "rubygems/command"
|
2
|
-
require 'rubygems/version_option'
|
3
|
-
|
4
|
-
# Currently unimplemented.
|
5
|
-
# This will fetch, verify and install a gem. Ideally it will do the
|
6
|
-
# same with any dependencies that are downloaded, but this might be
|
7
|
-
# difficult in a gem.
|
8
|
-
class Gem::Commands::VinstallCommand < Gem::Command # :nodoc:
|
9
|
-
|
10
|
-
include Gem::VersionOption
|
11
|
-
|
12
|
-
def initialize # :nodoc:
|
13
|
-
super 'vinstall', 'verify gem with GPG, and only install if sig check passes'
|
14
|
-
|
15
|
-
add_version_option
|
16
|
-
|
17
|
-
end
|
18
|
-
|
19
|
-
def arguments # :nodoc:
|
20
|
-
"GEMNAME name of gem to build"
|
21
|
-
end
|
22
|
-
|
23
|
-
def defaults_str # :nodoc:
|
24
|
-
""
|
25
|
-
end
|
26
|
-
|
27
|
-
def usage # :nodoc:
|
28
|
-
"blah blah"
|
29
|
-
end
|
30
|
-
|
31
|
-
def execute # :nodoc:
|
32
|
-
version = options[:version] || Gem::Requirement.default
|
33
|
-
|
34
|
-
puts "Not implemented yet."
|
35
|
-
end
|
36
|
-
|
37
|
-
end
|