1#--
2# Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.
3# All rights reserved.
4# See LICENSE.txt for permissions.
5#++
6
7require 'rubygems/exceptions'
8require 'fileutils'
9
10begin
11  require 'openssl'
12rescue LoadError => e
13  raise unless (e.respond_to?(:path) && e.path == 'openssl') ||
14               e.message =~ / -- openssl$/
15
16  module OpenSSL # :nodoc:
17    class Digest # :nodoc:
18      class SHA1 # :nodoc:
19        def name
20          'SHA1'
21        end
22      end
23    end
24    module PKey # :nodoc:
25      class RSA # :nodoc:
26      end
27    end
28  end
29end
30
31##
32# = Signing gems
33#
34# The Gem::Security implements cryptographic signatures for gems.  The section
35# below is a step-by-step guide to using signed gems and generating your own.
36#
37# == Walkthrough
38#
39# === Building your certificate
40#
41# In order to start signing your gems, you'll need to build a private key and
42# a self-signed certificate.  Here's how:
43#
44#   # build a private key and certificate for yourself:
45#   $ gem cert --build you@example.com
46#
47# This could take anywhere from a few seconds to a minute or two, depending on
48# the speed of your computer (public key algorithms aren't exactly the
49# speediest crypto algorithms in the world).  When it's finished, you'll see
50# the files "gem-private_key.pem" and "gem-public_cert.pem" in the current
51# directory.
52#
53# First things first: Move both files to ~/.gem if you don't already have a
54# key and certificate in that directory.  Ensure the file permissions make the
55# key unreadable by others (by default the file is saved securely).
56#
57# Keep your private key hidden; if it's compromised, someone can sign packages
58# as you (note: PKI has ways of mitigating the risk of stolen keys; more on
59# that later).
60#
61# === Signing Gems
62#
63# In RubyGems 2 and newer there is no extra work to sign a gem.  RubyGems will
64# automatically find your key and certificate in your home directory and use
65# them to sign newly packaged gems.
66#
67# If your certificate is not self-signed (signed by a third party) RubyGems
68# will attempt to load the certificate chain from the trusted certificates.
69# Use <code>gem cert --add signing_cert.pem</code> to add your signers as
70# trusted certificates.  See below for further information on certificate
71# chains.
72#
73# If you build your gem it will automatically be signed.  If you peek inside
74# your gem file, you'll see a couple of new files have been added:
75#
76#   $ tar tf your-gem-1.0.gem
77#   metadata.gz
78#   metadata.gz.sum
79#   metadata.gz.sig # metadata signature
80#   data.tar.gz
81#   data.tar.gz.sum
82#   data.tar.gz.sig # data signature
83#
84# === Manually signing gems
85#
86# If you wish to store your key in a separate secure location you'll need to
87# set your gems up for signing by hand.  To do this, set the
88# <code>signing_key</code> and <code>cert_chain</code> in the gemspec before
89# packaging your gem:
90#
91#   s.signing_key = '/secure/path/to/gem-private_key.pem'
92#   s.cert_chain = %w[/secure/path/to/gem-public_cert.pem]
93#
94# When you package your gem with these options set RubyGems will automatically
95# load your key and certificate from the secure paths.
96#
97# === Signed gems and security policies
98#
99# Now let's verify the signature.  Go ahead and install the gem, but add the
100# following options: <code>-P HighSecurity</code>, like this:
101#
102#   # install the gem with using the security policy "HighSecurity"
103#   $ sudo gem install your.gem -P HighSecurity
104#
105# The <code>-P</code> option sets your security policy -- we'll talk about
106# that in just a minute.  Eh, what's this?
107#
108#   $ gem install -P HighSecurity your-gem-1.0.gem
109#   ERROR:  While executing gem ... (Gem::Security::Exception)
110#       root cert /CN=you/DC=example is not trusted
111#
112# The culprit here is the security policy.  RubyGems has several different
113# security policies.  Let's take a short break and go over the security
114# policies.  Here's a list of the available security policies, and a brief
115# description of each one:
116#
117# * NoSecurity - Well, no security at all.  Signed packages are treated like
118#   unsigned packages.
119# * LowSecurity - Pretty much no security.  If a package is signed then
120#   RubyGems will make sure the signature matches the signing
121#   certificate, and that the signing certificate hasn't expired, but
122#   that's it.  A malicious user could easily circumvent this kind of
123#   security.
124# * MediumSecurity - Better than LowSecurity and NoSecurity, but still
125#   fallible.  Package contents are verified against the signing
126#   certificate, and the signing certificate is checked for validity,
127#   and checked against the rest of the certificate chain (if you don't
128#   know what a certificate chain is, stay tuned, we'll get to that).
129#   The biggest improvement over LowSecurity is that MediumSecurity
130#   won't install packages that are signed by untrusted sources.
131#   Unfortunately, MediumSecurity still isn't totally secure -- a
132#   malicious user can still unpack the gem, strip the signatures, and
133#   distribute the gem unsigned.
134# * HighSecurity - Here's the bugger that got us into this mess.
135#   The HighSecurity policy is identical to the MediumSecurity policy,
136#   except that it does not allow unsigned gems.  A malicious user
137#   doesn't have a whole lot of options here; he can't modify the
138#   package contents without invalidating the signature, and he can't
139#   modify or remove signature or the signing certificate chain, or
140#   RubyGems will simply refuse to install the package.  Oh well, maybe
141#   he'll have better luck causing problems for CPAN users instead :).
142#
143# The reason RubyGems refused to install your shiny new signed gem was because
144# it was from an untrusted source.  Well, your code is infallible (naturally),
145# so you need to add yourself as a trusted source:
146#
147#   # add trusted certificate
148#   gem cert --add ~/.gem/gem-public_cert.pem
149#
150# You've now added your public certificate as a trusted source.  Now you can
151# install packages signed by your private key without any hassle.  Let's try
152# the install command above again:
153#
154#   # install the gem with using the HighSecurity policy (and this time
155#   # without any shenanigans)
156#   $ gem install -P HighSecurity your-gem-1.0.gem
157#   Successfully installed your-gem-1.0
158#   1 gem installed
159#
160# This time RubyGems will accept your signed package and begin installing.
161#
162# While you're waiting for RubyGems to work it's magic, have a look at some of
163# the other security commands by running <code>gem help cert</code>:
164#
165#   Options:
166#     -a, --add CERT                   Add a trusted certificate.
167#     -l, --list [FILTER]              List trusted certificates where the
168#                                      subject contains FILTER
169#     -r, --remove FILTER              Remove trusted certificates where the
170#                                      subject contains FILTER
171#     -b, --build EMAIL_ADDR           Build private key and self-signed
172#                                      certificate for EMAIL_ADDR
173#     -C, --certificate CERT           Signing certificate for --sign
174#     -K, --private-key KEY            Key for --sign or --build
175#     -s, --sign CERT                  Signs CERT with the key from -K
176#                                      and the certificate from -C
177#
178# We've already covered the <code>--build</code> option, and the
179# <code>--add</code>, <code>--list</code>, and <code>--remove</code> commands
180# seem fairly straightforward; they allow you to add, list, and remove the
181# certificates in your trusted certificate list.  But what's with this
182# <code>--sign</code> option?
183#
184# === Certificate chains
185#
186# To answer that question, let's take a look at "certificate chains", a
187# concept I mentioned earlier.  There are a couple of problems with
188# self-signed certificates: first of all, self-signed certificates don't offer
189# a whole lot of security.  Sure, the certificate says Yukihiro Matsumoto, but
190# how do I know it was actually generated and signed by matz himself unless he
191# gave me the certificate in person?
192#
193# The second problem is scalability.  Sure, if there are 50 gem authors, then
194# I have 50 trusted certificates, no problem.  What if there are 500 gem
195# authors?  1000?  Having to constantly add new trusted certificates is a
196# pain, and it actually makes the trust system less secure by encouraging
197# RubyGems users to blindly trust new certificates.
198#
199# Here's where certificate chains come in.  A certificate chain establishes an
200# arbitrarily long chain of trust between an issuing certificate and a child
201# certificate.  So instead of trusting certificates on a per-developer basis,
202# we use the PKI concept of certificate chains to build a logical hierarchy of
203# trust.  Here's a hypothetical example of a trust hierarchy based (roughly)
204# on geography:
205#
206#                         --------------------------
207#                         | rubygems@rubygems.org |
208#                         --------------------------
209#                                     |
210#                   -----------------------------------
211#                   |                                 |
212#       ----------------------------    -----------------------------
213#       |  seattlerb@seattlerb.org |    | dcrubyists@richkilmer.com |
214#       ----------------------------    -----------------------------
215#            |                |                 |             |
216#     ---------------   ----------------   -----------   --------------
217#     |   drbrain   |   |   zenspider  |   | pabs@dc |   | tomcope@dc |
218#     ---------------   ----------------   -----------   --------------
219#
220#
221# Now, rather than having 4 trusted certificates (one for drbrain, zenspider,
222# pabs@dc, and tomecope@dc), a user could actually get by with one
223# certificate, the "rubygems@rubygems.org" certificate.
224#
225# Here's how it works:
226#
227# I install "rdoc-3.12.gem", a package signed by "drbrain".  I've never heard
228# of "drbrain", but his certificate has a valid signature from the
229# "seattle.rb@seattlerb.org" certificate, which in turn has a valid signature
230# from the "rubygems@rubygems.org" certificate.  Voila!  At this point, it's
231# much more reasonable for me to trust a package signed by "drbrain", because
232# I can establish a chain to "rubygems@rubygems.org", which I do trust.
233#
234# === Signing certificates
235#
236# The <code>--sign</code> option allows all this to happen.  A developer
237# creates their build certificate with the <code>--build</code> option, then
238# has their certificate signed by taking it with them to their next regional
239# Ruby meetup (in our hypothetical example), and it's signed there by the
240# person holding the regional RubyGems signing certificate, which is signed at
241# the next RubyConf by the holder of the top-level RubyGems certificate.  At
242# each point the issuer runs the same command:
243#
244#   # sign a certificate with the specified key and certificate
245#   # (note that this modifies client_cert.pem!)
246#   $ gem cert -K /mnt/floppy/issuer-priv_key.pem -C issuer-pub_cert.pem
247#      --sign client_cert.pem
248#
249# Then the holder of issued certificate (in this case, your buddy "drbrain"),
250# can start using this signed certificate to sign RubyGems.  By the way, in
251# order to let everyone else know about his new fancy signed certificate,
252# "drbrain" would save his newly signed certificate as
253# <code>~/.gem/gem-public_cert.pem</code>
254#
255# Obviously this RubyGems trust infrastructure doesn't exist yet.  Also, in
256# the "real world", issuers actually generate the child certificate from a
257# certificate request, rather than sign an existing certificate.  And our
258# hypothetical infrastructure is missing a certificate revocation system.
259# These are that can be fixed in the future...
260#
261# At this point you should know how to do all of these new and interesting
262# things:
263#
264# * build a gem signing key and certificate
265# * adjust your security policy
266# * modify your trusted certificate list
267# * sign a certificate
268#
269# == Manually verifying signatures
270#
271# In case you don't trust RubyGems you can verify gem signatures manually:
272#
273# 1. Fetch and unpack the gem
274#
275#      gem fetch some_signed_gem
276#      tar -xf some_signed_gem-1.0.gem
277#
278# 2. Grab the public key from the gemspec
279#
280#      gem spec some_signed_gem-1.0.gem cert_chain | \
281#        ruby -ryaml -e 'puts YAML.load_documents($stdin)' > public_key.crt
282#
283# 3. Generate a SHA1 hash of the data.tar.gz
284#
285#      openssl dgst -sha1 < data.tar.gz > my.hash
286#
287# 4. Verify the signature
288#
289#      openssl rsautl -verify -inkey public_key.crt -certin \
290#        -in data.tar.gz.sig > verified.hash
291#
292# 5. Compare your hash to the verified hash
293#
294#      diff -s verified.hash my.hash
295#
296# 6. Repeat 5 and 6 with metadata.gz
297#
298# == OpenSSL Reference
299#
300# The .pem files generated by --build and --sign are PEM files.  Here's a
301# couple of useful OpenSSL commands for manipulating them:
302#
303#   # convert a PEM format X509 certificate into DER format:
304#   # (note: Windows .cer files are X509 certificates in DER format)
305#   $ openssl x509 -in input.pem -outform der -out output.der
306#
307#   # print out the certificate in a human-readable format:
308#   $ openssl x509 -in input.pem -noout -text
309#
310# And you can do the same thing with the private key file as well:
311#
312#   # convert a PEM format RSA key into DER format:
313#   $ openssl rsa -in input_key.pem -outform der -out output_key.der
314#
315#   # print out the key in a human readable format:
316#   $ openssl rsa -in input_key.pem -noout -text
317#
318# == Bugs/TODO
319#
320# * There's no way to define a system-wide trust list.
321# * custom security policies (from a YAML file, etc)
322# * Simple method to generate a signed certificate request
323# * Support for OCSP, SCVP, CRLs, or some other form of cert status check
324#   (list is in order of preference)
325# * Support for encrypted private keys
326# * Some sort of semi-formal trust hierarchy (see long-winded explanation
327#   above)
328# * Path discovery (for gem certificate chains that don't have a self-signed
329#   root) -- by the way, since we don't have this, THE ROOT OF THE CERTIFICATE
330#   CHAIN MUST BE SELF SIGNED if Policy#verify_root is true (and it is for the
331#   MediumSecurity and HighSecurity policies)
332# * Better explanation of X509 naming (ie, we don't have to use email
333#   addresses)
334# * Honor AIA field (see note about OCSP above)
335# * Honor extension restrictions
336# * Might be better to store the certificate chain as a PKCS#7 or PKCS#12
337#   file, instead of an array embedded in the metadata.
338# * Flexible signature and key algorithms, not hard-coded to RSA and SHA1.
339#
340# == Original author
341#
342# Paul Duncan <pabs@pablotron.org>
343# http://pablotron.org/
344
345module Gem::Security
346
347  ##
348  # Gem::Security default exception type
349
350  class Exception < Gem::Exception; end
351
352  ##
353  # Digest algorithm used to sign gems
354
355  DIGEST_ALGORITHM = OpenSSL::Digest::SHA1
356
357  ##
358  # Used internally to select the signing digest from all computed digests
359
360  DIGEST_NAME = DIGEST_ALGORITHM.new.name # :nodoc:
361
362  ##
363  # Algorithm for creating the key pair used to sign gems
364
365  KEY_ALGORITHM = OpenSSL::PKey::RSA
366
367  ##
368  # Length of keys created by KEY_ALGORITHM
369
370  KEY_LENGTH = 2048
371
372  ##
373  # One year in seconds
374
375  ONE_YEAR = 86400 * 365
376
377  ##
378  # The default set of extensions are:
379  #
380  # * The certificate is not a certificate authority
381  # * The key for the certificate may be used for key and data encipherment
382  #   and digital signatures
383  # * The certificate contains a subject key identifier
384
385  EXTENSIONS = {
386    'basicConstraints'     => 'CA:FALSE',
387    'keyUsage'             =>
388      'keyEncipherment,dataEncipherment,digitalSignature',
389    'subjectKeyIdentifier' => 'hash',
390  }
391
392  def self.alt_name_or_x509_entry certificate, x509_entry
393    alt_name = certificate.extensions.find do |extension|
394      extension.oid == "#{x509_entry}AltName"
395    end
396
397    return alt_name.value if alt_name
398
399    certificate.send x509_entry
400  end
401
402  ##
403  # Creates an unsigned certificate for +subject+ and +key+.  The lifetime of
404  # the key is from the current time to +age+ which defaults to one year.
405  #
406  # The +extensions+ restrict the key to the indicated uses.
407
408  def self.create_cert subject, key, age = ONE_YEAR, extensions = EXTENSIONS,
409                       serial = 1
410    cert = OpenSSL::X509::Certificate.new
411
412    cert.public_key = key.public_key
413    cert.version    = 2
414    cert.serial     = serial
415
416    cert.not_before = Time.now
417    cert.not_after  = Time.now + age
418
419    cert.subject    = subject
420
421    ef = OpenSSL::X509::ExtensionFactory.new nil, cert
422
423    cert.extensions = extensions.map do |ext_name, value|
424      ef.create_extension ext_name, value
425    end
426
427    cert
428  end
429
430  ##
431  # Creates a self-signed certificate with an issuer and subject from +email+,
432  # a subject alternative name of +email+ and the given +extensions+ for the
433  # +key+.
434
435  def self.create_cert_email email, key, age = ONE_YEAR, extensions = EXTENSIONS
436    subject = email_to_name email
437
438    extensions = extensions.merge "subjectAltName" => "email:#{email}"
439
440    create_cert_self_signed subject, key, age, extensions
441  end
442
443  ##
444  # Creates a self-signed certificate with an issuer and subject of +subject+
445  # and the given +extensions+ for the +key+.
446
447  def self.create_cert_self_signed subject, key, age = ONE_YEAR,
448                                   extensions = EXTENSIONS, serial = 1
449    certificate = create_cert subject, key, age, extensions
450
451    sign certificate, key, certificate, age, extensions, serial
452  end
453
454  ##
455  # Creates a new key pair of the specified +length+ and +algorithm+.  The
456  # default is a 2048 bit RSA key.
457
458  def self.create_key length = KEY_LENGTH, algorithm = KEY_ALGORITHM
459    algorithm.new length
460  end
461
462  ##
463  # Turns +email_address+ into an OpenSSL::X509::Name
464
465  def self.email_to_name email_address
466    email_address = email_address.gsub(/[^\w@.-]+/i, '_')
467
468    cn, dcs = email_address.split '@'
469
470    dcs = dcs.split '.'
471
472    name = "CN=#{cn}/#{dcs.map { |dc| "DC=#{dc}" }.join '/'}"
473
474    OpenSSL::X509::Name.parse name
475  end
476
477  ##
478  # Signs +expired_certificate+ with +private_key+ if the keys match and the
479  # expired certificate was self-signed.
480  #--
481  # TODO increment serial
482
483  def self.re_sign expired_certificate, private_key, age = ONE_YEAR,
484                   extensions = EXTENSIONS
485    raise Gem::Security::Exception,
486          "incorrect signing key for re-signing " +
487          "#{expired_certificate.subject}" unless
488      expired_certificate.public_key.to_pem == private_key.public_key.to_pem
489
490    unless expired_certificate.subject.to_s ==
491           expired_certificate.issuer.to_s then
492      subject = alt_name_or_x509_entry expired_certificate, :subject
493      issuer  = alt_name_or_x509_entry expired_certificate, :issuer
494
495      raise Gem::Security::Exception,
496            "#{subject} is not self-signed, contact #{issuer} " +
497            "to obtain a valid certificate"
498    end
499
500    serial = expired_certificate.serial + 1
501
502    create_cert_self_signed(expired_certificate.subject, private_key, age,
503                            extensions, serial)
504  end
505
506  ##
507  # Resets the trust directory for verifying gems.
508
509  def self.reset
510    @trust_dir = nil
511  end
512
513  ##
514  # Sign the public key from +certificate+ with the +signing_key+ and
515  # +signing_cert+, using the Gem::Security::DIGEST_ALGORITHM.  Uses the
516  # default certificate validity range and extensions.
517  #
518  # Returns the newly signed certificate.
519
520  def self.sign certificate, signing_key, signing_cert,
521                age = ONE_YEAR, extensions = EXTENSIONS, serial = 1
522    signee_subject = certificate.subject
523    signee_key     = certificate.public_key
524
525    alt_name = certificate.extensions.find do |extension|
526      extension.oid == 'subjectAltName'
527    end
528
529    extensions = extensions.merge 'subjectAltName' => alt_name.value if
530      alt_name
531
532    issuer_alt_name = signing_cert.extensions.find do |extension|
533      extension.oid == 'subjectAltName'
534    end
535
536    extensions = extensions.merge 'issuerAltName' => issuer_alt_name.value if
537      issuer_alt_name
538
539    signed = create_cert signee_subject, signee_key, age, extensions, serial
540    signed.issuer = signing_cert.subject
541
542    signed.sign signing_key, Gem::Security::DIGEST_ALGORITHM.new
543  end
544
545  ##
546  # Returns a Gem::Security::TrustDir which wraps the directory where trusted
547  # certificates live.
548
549  def self.trust_dir
550    return @trust_dir if @trust_dir
551
552    dir = File.join Gem.user_home, '.gem', 'trust'
553
554    @trust_dir ||= Gem::Security::TrustDir.new dir
555  end
556
557  ##
558  # Enumerates the trusted certificates via Gem::Security::TrustDir.
559
560  def self.trusted_certificates &block
561    trust_dir.each_certificate(&block)
562  end
563
564  ##
565  # Writes +pemmable+, which must respond to +to_pem+ to +path+ with the given
566  # +permissions+.
567
568  def self.write pemmable, path, permissions = 0600
569    path = File.expand_path path
570
571    open path, 'wb', permissions do |io|
572      io.write pemmable.to_pem
573    end
574
575    path
576  end
577
578  reset
579
580end
581
582require 'rubygems/security/policy'
583require 'rubygems/security/policies'
584require 'rubygems/security/signer'
585require 'rubygems/security/trust_dir'
586
587