rubygems-openpgp 0.2.1 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|