mirror of
				https://github.com/ruby/ruby.git
				synced 2022-11-09 12:17:21 -05:00 
			
		
		
		
	 a21d403f21
			
		
	
	
		a21d403f21
		
	
	
	
	
		
			
			It supports to enable frozen string literal and add `--norc` option for
  disable to `.gemrc` configuration.
  See 2.5.2 release notes for other fixes and enhancements.
  a8aa3bac72/History.txt (L3)
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@53707 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
		
	
			
		
			
				
	
	
		
			596 lines
		
	
	
	
		
			21 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
			
		
		
	
	
			596 lines
		
	
	
	
		
			21 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
| # frozen_string_literal: true
 | |
| #--
 | |
| # Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.
 | |
| # All rights reserved.
 | |
| # See LICENSE.txt for permissions.
 | |
| #++
 | |
| 
 | |
| require 'rubygems/exceptions'
 | |
| require 'fileutils'
 | |
| 
 | |
| begin
 | |
|   require 'openssl'
 | |
| rescue LoadError => e
 | |
|   raise unless (e.respond_to?(:path) && e.path == 'openssl') ||
 | |
|                e.message =~ / -- openssl$/
 | |
| end
 | |
| 
 | |
| ##
 | |
| # = Signing gems
 | |
| #
 | |
| # The Gem::Security implements cryptographic signatures for gems.  The section
 | |
| # below is a step-by-step guide to using signed gems and generating your own.
 | |
| #
 | |
| # == Walkthrough
 | |
| #
 | |
| # === Building your certificate
 | |
| #
 | |
| # In order to start signing your gems, you'll need to build a private key and
 | |
| # a self-signed certificate.  Here's how:
 | |
| #
 | |
| #   # build a private key and certificate for yourself:
 | |
| #   $ gem cert --build you@example.com
 | |
| #
 | |
| # This could take anywhere from a few seconds to a minute or two, depending on
 | |
| # the speed of your computer (public key algorithms aren't exactly the
 | |
| # speediest crypto algorithms in the world).  When it's finished, you'll see
 | |
| # the files "gem-private_key.pem" and "gem-public_cert.pem" in the current
 | |
| # directory.
 | |
| #
 | |
| # First things first: Move both files to ~/.gem if you don't already have a
 | |
| # key and certificate in that directory.  Ensure the file permissions make the
 | |
| # key unreadable by others (by default the file is saved securely).
 | |
| #
 | |
| # Keep your private key hidden; if it's compromised, someone can sign packages
 | |
| # as you (note: PKI has ways of mitigating the risk of stolen keys; more on
 | |
| # that later).
 | |
| #
 | |
| # === Signing Gems
 | |
| #
 | |
| # In RubyGems 2 and newer there is no extra work to sign a gem.  RubyGems will
 | |
| # automatically find your key and certificate in your home directory and use
 | |
| # them to sign newly packaged gems.
 | |
| #
 | |
| # If your certificate is not self-signed (signed by a third party) RubyGems
 | |
| # will attempt to load the certificate chain from the trusted certificates.
 | |
| # Use <code>gem cert --add signing_cert.pem</code> to add your signers as
 | |
| # trusted certificates.  See below for further information on certificate
 | |
| # chains.
 | |
| #
 | |
| # If you build your gem it will automatically be signed.  If you peek inside
 | |
| # your gem file, you'll see a couple of new files have been added:
 | |
| #
 | |
| #   $ tar tf your-gem-1.0.gem
 | |
| #   metadata.gz
 | |
| #   metadata.gz.sum
 | |
| #   metadata.gz.sig # metadata signature
 | |
| #   data.tar.gz
 | |
| #   data.tar.gz.sum
 | |
| #   data.tar.gz.sig # data signature
 | |
| #
 | |
| # === Manually signing gems
 | |
| #
 | |
| # If you wish to store your key in a separate secure location you'll need to
 | |
| # set your gems up for signing by hand.  To do this, set the
 | |
| # <code>signing_key</code> and <code>cert_chain</code> in the gemspec before
 | |
| # packaging your gem:
 | |
| #
 | |
| #   s.signing_key = '/secure/path/to/gem-private_key.pem'
 | |
| #   s.cert_chain = %w[/secure/path/to/gem-public_cert.pem]
 | |
| #
 | |
| # When you package your gem with these options set RubyGems will automatically
 | |
| # load your key and certificate from the secure paths.
 | |
| #
 | |
| # === Signed gems and security policies
 | |
| #
 | |
| # Now let's verify the signature.  Go ahead and install the gem, but add the
 | |
| # following options: <code>-P HighSecurity</code>, like this:
 | |
| #
 | |
| #   # install the gem with using the security policy "HighSecurity"
 | |
| #   $ sudo gem install your.gem -P HighSecurity
 | |
| #
 | |
| # The <code>-P</code> option sets your security policy -- we'll talk about
 | |
| # that in just a minute.  Eh, what's this?
 | |
| #
 | |
| #   $ gem install -P HighSecurity your-gem-1.0.gem
 | |
| #   ERROR:  While executing gem ... (Gem::Security::Exception)
 | |
| #       root cert /CN=you/DC=example is not trusted
 | |
| #
 | |
| # The culprit here is the security policy.  RubyGems has several different
 | |
| # security policies.  Let's take a short break and go over the security
 | |
| # policies.  Here's a list of the available security policies, and a brief
 | |
| # description of each one:
 | |
| #
 | |
| # * NoSecurity - Well, no security at all.  Signed packages are treated like
 | |
| #   unsigned packages.
 | |
| # * LowSecurity - Pretty much no security.  If a package is signed then
 | |
| #   RubyGems will make sure the signature matches the signing
 | |
| #   certificate, and that the signing certificate hasn't expired, but
 | |
| #   that's it.  A malicious user could easily circumvent this kind of
 | |
| #   security.
 | |
| # * MediumSecurity - Better than LowSecurity and NoSecurity, but still
 | |
| #   fallible.  Package contents are verified against the signing
 | |
| #   certificate, and the signing certificate is checked for validity,
 | |
| #   and checked against the rest of the certificate chain (if you don't
 | |
| #   know what a certificate chain is, stay tuned, we'll get to that).
 | |
| #   The biggest improvement over LowSecurity is that MediumSecurity
 | |
| #   won't install packages that are signed by untrusted sources.
 | |
| #   Unfortunately, MediumSecurity still isn't totally secure -- a
 | |
| #   malicious user can still unpack the gem, strip the signatures, and
 | |
| #   distribute the gem unsigned.
 | |
| # * HighSecurity - Here's the bugger that got us into this mess.
 | |
| #   The HighSecurity policy is identical to the MediumSecurity policy,
 | |
| #   except that it does not allow unsigned gems.  A malicious user
 | |
| #   doesn't have a whole lot of options here; they can't modify the
 | |
| #   package contents without invalidating the signature, and they can't
 | |
| #   modify or remove signature or the signing certificate chain, or
 | |
| #   RubyGems will simply refuse to install the package.  Oh well, maybe
 | |
| #   they'll have better luck causing problems for CPAN users instead :).
 | |
| #
 | |
| # The reason RubyGems refused to install your shiny new signed gem was because
 | |
| # it was from an untrusted source.  Well, your code is infallible (naturally),
 | |
| # so you need to add yourself as a trusted source:
 | |
| #
 | |
| #   # add trusted certificate
 | |
| #   gem cert --add ~/.gem/gem-public_cert.pem
 | |
| #
 | |
| # You've now added your public certificate as a trusted source.  Now you can
 | |
| # install packages signed by your private key without any hassle.  Let's try
 | |
| # the install command above again:
 | |
| #
 | |
| #   # install the gem with using the HighSecurity policy (and this time
 | |
| #   # without any shenanigans)
 | |
| #   $ gem install -P HighSecurity your-gem-1.0.gem
 | |
| #   Successfully installed your-gem-1.0
 | |
| #   1 gem installed
 | |
| #
 | |
| # This time RubyGems will accept your signed package and begin installing.
 | |
| #
 | |
| # While you're waiting for RubyGems to work it's magic, have a look at some of
 | |
| # the other security commands by running <code>gem help cert</code>:
 | |
| #
 | |
| #   Options:
 | |
| #     -a, --add CERT                   Add a trusted certificate.
 | |
| #     -l, --list [FILTER]              List trusted certificates where the
 | |
| #                                      subject contains FILTER
 | |
| #     -r, --remove FILTER              Remove trusted certificates where the
 | |
| #                                      subject contains FILTER
 | |
| #     -b, --build EMAIL_ADDR           Build private key and self-signed
 | |
| #                                      certificate for EMAIL_ADDR
 | |
| #     -C, --certificate CERT           Signing certificate for --sign
 | |
| #     -K, --private-key KEY            Key for --sign or --build
 | |
| #     -s, --sign CERT                  Signs CERT with the key from -K
 | |
| #                                      and the certificate from -C
 | |
| #
 | |
| # We've already covered the <code>--build</code> option, and the
 | |
| # <code>--add</code>, <code>--list</code>, and <code>--remove</code> commands
 | |
| # seem fairly straightforward; they allow you to add, list, and remove the
 | |
| # certificates in your trusted certificate list.  But what's with this
 | |
| # <code>--sign</code> option?
 | |
| #
 | |
| # === Certificate chains
 | |
| #
 | |
| # To answer that question, let's take a look at "certificate chains", a
 | |
| # concept I mentioned earlier.  There are a couple of problems with
 | |
| # self-signed certificates: first of all, self-signed certificates don't offer
 | |
| # a whole lot of security.  Sure, the certificate says Yukihiro Matsumoto, but
 | |
| # how do I know it was actually generated and signed by matz himself unless he
 | |
| # gave me the certificate in person?
 | |
| #
 | |
| # The second problem is scalability.  Sure, if there are 50 gem authors, then
 | |
| # I have 50 trusted certificates, no problem.  What if there are 500 gem
 | |
| # authors?  1000?  Having to constantly add new trusted certificates is a
 | |
| # pain, and it actually makes the trust system less secure by encouraging
 | |
| # RubyGems users to blindly trust new certificates.
 | |
| #
 | |
| # Here's where certificate chains come in.  A certificate chain establishes an
 | |
| # arbitrarily long chain of trust between an issuing certificate and a child
 | |
| # certificate.  So instead of trusting certificates on a per-developer basis,
 | |
| # we use the PKI concept of certificate chains to build a logical hierarchy of
 | |
| # trust.  Here's a hypothetical example of a trust hierarchy based (roughly)
 | |
| # on geography:
 | |
| #
 | |
| #                         --------------------------
 | |
| #                         | rubygems@rubygems.org |
 | |
| #                         --------------------------
 | |
| #                                     |
 | |
| #                   -----------------------------------
 | |
| #                   |                                 |
 | |
| #       ----------------------------    -----------------------------
 | |
| #       |  seattlerb@seattlerb.org |    | dcrubyists@richkilmer.com |
 | |
| #       ----------------------------    -----------------------------
 | |
| #            |                |                 |             |
 | |
| #     ---------------   ----------------   -----------   --------------
 | |
| #     |   drbrain   |   |   zenspider  |   | pabs@dc |   | tomcope@dc |
 | |
| #     ---------------   ----------------   -----------   --------------
 | |
| #
 | |
| #
 | |
| # Now, rather than having 4 trusted certificates (one for drbrain, zenspider,
 | |
| # pabs@dc, and tomecope@dc), a user could actually get by with one
 | |
| # certificate, the "rubygems@rubygems.org" certificate.
 | |
| #
 | |
| # Here's how it works:
 | |
| #
 | |
| # I install "rdoc-3.12.gem", a package signed by "drbrain".  I've never heard
 | |
| # of "drbrain", but his certificate has a valid signature from the
 | |
| # "seattle.rb@seattlerb.org" certificate, which in turn has a valid signature
 | |
| # from the "rubygems@rubygems.org" certificate.  Voila!  At this point, it's
 | |
| # much more reasonable for me to trust a package signed by "drbrain", because
 | |
| # I can establish a chain to "rubygems@rubygems.org", which I do trust.
 | |
| #
 | |
| # === Signing certificates
 | |
| #
 | |
| # The <code>--sign</code> option allows all this to happen.  A developer
 | |
| # creates their build certificate with the <code>--build</code> option, then
 | |
| # has their certificate signed by taking it with them to their next regional
 | |
| # Ruby meetup (in our hypothetical example), and it's signed there by the
 | |
| # person holding the regional RubyGems signing certificate, which is signed at
 | |
| # the next RubyConf by the holder of the top-level RubyGems certificate.  At
 | |
| # each point the issuer runs the same command:
 | |
| #
 | |
| #   # sign a certificate with the specified key and certificate
 | |
| #   # (note that this modifies client_cert.pem!)
 | |
| #   $ gem cert -K /mnt/floppy/issuer-priv_key.pem -C issuer-pub_cert.pem
 | |
| #      --sign client_cert.pem
 | |
| #
 | |
| # Then the holder of issued certificate (in this case, your buddy "drbrain"),
 | |
| # can start using this signed certificate to sign RubyGems.  By the way, in
 | |
| # order to let everyone else know about his new fancy signed certificate,
 | |
| # "drbrain" would save his newly signed certificate as
 | |
| # <code>~/.gem/gem-public_cert.pem</code>
 | |
| #
 | |
| # Obviously this RubyGems trust infrastructure doesn't exist yet.  Also, in
 | |
| # the "real world", issuers actually generate the child certificate from a
 | |
| # certificate request, rather than sign an existing certificate.  And our
 | |
| # hypothetical infrastructure is missing a certificate revocation system.
 | |
| # These are that can be fixed in the future...
 | |
| #
 | |
| # At this point you should know how to do all of these new and interesting
 | |
| # things:
 | |
| #
 | |
| # * build a gem signing key and certificate
 | |
| # * adjust your security policy
 | |
| # * modify your trusted certificate list
 | |
| # * sign a certificate
 | |
| #
 | |
| # == Manually verifying signatures
 | |
| #
 | |
| # In case you don't trust RubyGems you can verify gem signatures manually:
 | |
| #
 | |
| # 1. Fetch and unpack the gem
 | |
| #
 | |
| #      gem fetch some_signed_gem
 | |
| #      tar -xf some_signed_gem-1.0.gem
 | |
| #
 | |
| # 2. Grab the public key from the gemspec
 | |
| #
 | |
| #      gem spec some_signed_gem-1.0.gem cert_chain | \
 | |
| #        ruby -ryaml -e 'puts YAML.load_documents($stdin)' > public_key.crt
 | |
| #
 | |
| # 3. Generate a SHA1 hash of the data.tar.gz
 | |
| #
 | |
| #      openssl dgst -sha1 < data.tar.gz > my.hash
 | |
| #
 | |
| # 4. Verify the signature
 | |
| #
 | |
| #      openssl rsautl -verify -inkey public_key.crt -certin \
 | |
| #        -in data.tar.gz.sig > verified.hash
 | |
| #
 | |
| # 5. Compare your hash to the verified hash
 | |
| #
 | |
| #      diff -s verified.hash my.hash
 | |
| #
 | |
| # 6. Repeat 5 and 6 with metadata.gz
 | |
| #
 | |
| # == OpenSSL Reference
 | |
| #
 | |
| # The .pem files generated by --build and --sign are PEM files.  Here's a
 | |
| # couple of useful OpenSSL commands for manipulating them:
 | |
| #
 | |
| #   # convert a PEM format X509 certificate into DER format:
 | |
| #   # (note: Windows .cer files are X509 certificates in DER format)
 | |
| #   $ openssl x509 -in input.pem -outform der -out output.der
 | |
| #
 | |
| #   # print out the certificate in a human-readable format:
 | |
| #   $ openssl x509 -in input.pem -noout -text
 | |
| #
 | |
| # And you can do the same thing with the private key file as well:
 | |
| #
 | |
| #   # convert a PEM format RSA key into DER format:
 | |
| #   $ openssl rsa -in input_key.pem -outform der -out output_key.der
 | |
| #
 | |
| #   # print out the key in a human readable format:
 | |
| #   $ openssl rsa -in input_key.pem -noout -text
 | |
| #
 | |
| # == Bugs/TODO
 | |
| #
 | |
| # * There's no way to define a system-wide trust list.
 | |
| # * custom security policies (from a YAML file, etc)
 | |
| # * Simple method to generate a signed certificate request
 | |
| # * Support for OCSP, SCVP, CRLs, or some other form of cert status check
 | |
| #   (list is in order of preference)
 | |
| # * Support for encrypted private keys
 | |
| # * Some sort of semi-formal trust hierarchy (see long-winded explanation
 | |
| #   above)
 | |
| # * Path discovery (for gem certificate chains that don't have a self-signed
 | |
| #   root) -- by the way, since we don't have this, THE ROOT OF THE CERTIFICATE
 | |
| #   CHAIN MUST BE SELF SIGNED if Policy#verify_root is true (and it is for the
 | |
| #   MediumSecurity and HighSecurity policies)
 | |
| # * Better explanation of X509 naming (ie, we don't have to use email
 | |
| #   addresses)
 | |
| # * Honor AIA field (see note about OCSP above)
 | |
| # * Honor extension restrictions
 | |
| # * Might be better to store the certificate chain as a PKCS#7 or PKCS#12
 | |
| #   file, instead of an array embedded in the metadata.
 | |
| # * Flexible signature and key algorithms, not hard-coded to RSA and SHA1.
 | |
| #
 | |
| # == Original author
 | |
| #
 | |
| # Paul Duncan <pabs@pablotron.org>
 | |
| # http://pablotron.org/
 | |
| 
 | |
| module Gem::Security
 | |
| 
 | |
|   ##
 | |
|   # Gem::Security default exception type
 | |
| 
 | |
|   class Exception < Gem::Exception; end
 | |
| 
 | |
|   ##
 | |
|   # Digest algorithm used to sign gems
 | |
| 
 | |
|   DIGEST_ALGORITHM =
 | |
|     if defined?(OpenSSL::Digest::SHA1) then
 | |
|       OpenSSL::Digest::SHA1
 | |
|     end
 | |
| 
 | |
|   ##
 | |
|   # Used internally to select the signing digest from all computed digests
 | |
| 
 | |
|   DIGEST_NAME = # :nodoc:
 | |
|     if DIGEST_ALGORITHM then
 | |
|       DIGEST_ALGORITHM.new.name
 | |
|     end
 | |
| 
 | |
|   ##
 | |
|   # Algorithm for creating the key pair used to sign gems
 | |
| 
 | |
|   KEY_ALGORITHM =
 | |
|     if defined?(OpenSSL::PKey::RSA) then
 | |
|       OpenSSL::PKey::RSA
 | |
|     end
 | |
| 
 | |
|   ##
 | |
|   # Length of keys created by KEY_ALGORITHM
 | |
| 
 | |
|   KEY_LENGTH = 2048
 | |
| 
 | |
|   ##
 | |
|   # Cipher used to encrypt the key pair used to sign gems.
 | |
|   # Must be in the list returned by OpenSSL::Cipher.ciphers
 | |
| 
 | |
|   KEY_CIPHER = OpenSSL::Cipher.new('AES-256-CBC') if defined?(OpenSSL::Cipher)
 | |
| 
 | |
|   ##
 | |
|   # One year in seconds
 | |
| 
 | |
|   ONE_YEAR = 86400 * 365
 | |
| 
 | |
|   ##
 | |
|   # The default set of extensions are:
 | |
|   #
 | |
|   # * The certificate is not a certificate authority
 | |
|   # * The key for the certificate may be used for key and data encipherment
 | |
|   #   and digital signatures
 | |
|   # * The certificate contains a subject key identifier
 | |
| 
 | |
|   EXTENSIONS = {
 | |
|     'basicConstraints'     => 'CA:FALSE',
 | |
|     'keyUsage'             =>
 | |
|       'keyEncipherment,dataEncipherment,digitalSignature',
 | |
|     'subjectKeyIdentifier' => 'hash',
 | |
|   }
 | |
| 
 | |
|   def self.alt_name_or_x509_entry certificate, x509_entry
 | |
|     alt_name = certificate.extensions.find do |extension|
 | |
|       extension.oid == "#{x509_entry}AltName"
 | |
|     end
 | |
| 
 | |
|     return alt_name.value if alt_name
 | |
| 
 | |
|     certificate.send x509_entry
 | |
|   end
 | |
| 
 | |
|   ##
 | |
|   # Creates an unsigned certificate for +subject+ and +key+.  The lifetime of
 | |
|   # the key is from the current time to +age+ which defaults to one year.
 | |
|   #
 | |
|   # The +extensions+ restrict the key to the indicated uses.
 | |
| 
 | |
|   def self.create_cert subject, key, age = ONE_YEAR, extensions = EXTENSIONS,
 | |
|                        serial = 1
 | |
|     cert = OpenSSL::X509::Certificate.new
 | |
| 
 | |
|     cert.public_key = key.public_key
 | |
|     cert.version    = 2
 | |
|     cert.serial     = serial
 | |
| 
 | |
|     cert.not_before = Time.now
 | |
|     cert.not_after  = Time.now + age
 | |
| 
 | |
|     cert.subject    = subject
 | |
| 
 | |
|     ef = OpenSSL::X509::ExtensionFactory.new nil, cert
 | |
| 
 | |
|     cert.extensions = extensions.map do |ext_name, value|
 | |
|       ef.create_extension ext_name, value
 | |
|     end
 | |
| 
 | |
|     cert
 | |
|   end
 | |
| 
 | |
|   ##
 | |
|   # Creates a self-signed certificate with an issuer and subject from +email+,
 | |
|   # a subject alternative name of +email+ and the given +extensions+ for the
 | |
|   # +key+.
 | |
| 
 | |
|   def self.create_cert_email email, key, age = ONE_YEAR, extensions = EXTENSIONS
 | |
|     subject = email_to_name email
 | |
| 
 | |
|     extensions = extensions.merge "subjectAltName" => "email:#{email}"
 | |
| 
 | |
|     create_cert_self_signed subject, key, age, extensions
 | |
|   end
 | |
| 
 | |
|   ##
 | |
|   # Creates a self-signed certificate with an issuer and subject of +subject+
 | |
|   # and the given +extensions+ for the +key+.
 | |
| 
 | |
|   def self.create_cert_self_signed subject, key, age = ONE_YEAR,
 | |
|                                    extensions = EXTENSIONS, serial = 1
 | |
|     certificate = create_cert subject, key, age, extensions
 | |
| 
 | |
|     sign certificate, key, certificate, age, extensions, serial
 | |
|   end
 | |
| 
 | |
|   ##
 | |
|   # Creates a new key pair of the specified +length+ and +algorithm+.  The
 | |
|   # default is a 2048 bit RSA key.
 | |
| 
 | |
|   def self.create_key length = KEY_LENGTH, algorithm = KEY_ALGORITHM
 | |
|     algorithm.new length
 | |
|   end
 | |
| 
 | |
|   ##
 | |
|   # Turns +email_address+ into an OpenSSL::X509::Name
 | |
| 
 | |
|   def self.email_to_name email_address
 | |
|     email_address = email_address.gsub(/[^\w@.-]+/i, '_')
 | |
| 
 | |
|     cn, dcs = email_address.split '@'
 | |
| 
 | |
|     dcs = dcs.split '.'
 | |
| 
 | |
|     name = "CN=#{cn}/#{dcs.map { |dc| "DC=#{dc}" }.join '/'}"
 | |
| 
 | |
|     OpenSSL::X509::Name.parse name
 | |
|   end
 | |
| 
 | |
|   ##
 | |
|   # Signs +expired_certificate+ with +private_key+ if the keys match and the
 | |
|   # expired certificate was self-signed.
 | |
|   #--
 | |
|   # TODO increment serial
 | |
| 
 | |
|   def self.re_sign expired_certificate, private_key, age = ONE_YEAR,
 | |
|                    extensions = EXTENSIONS
 | |
|     raise Gem::Security::Exception,
 | |
|           "incorrect signing key for re-signing " +
 | |
|           "#{expired_certificate.subject}" unless
 | |
|       expired_certificate.public_key.to_pem == private_key.public_key.to_pem
 | |
| 
 | |
|     unless expired_certificate.subject.to_s ==
 | |
|            expired_certificate.issuer.to_s then
 | |
|       subject = alt_name_or_x509_entry expired_certificate, :subject
 | |
|       issuer  = alt_name_or_x509_entry expired_certificate, :issuer
 | |
| 
 | |
|       raise Gem::Security::Exception,
 | |
|             "#{subject} is not self-signed, contact #{issuer} " +
 | |
|             "to obtain a valid certificate"
 | |
|     end
 | |
| 
 | |
|     serial = expired_certificate.serial + 1
 | |
| 
 | |
|     create_cert_self_signed(expired_certificate.subject, private_key, age,
 | |
|                             extensions, serial)
 | |
|   end
 | |
| 
 | |
|   ##
 | |
|   # Resets the trust directory for verifying gems.
 | |
| 
 | |
|   def self.reset
 | |
|     @trust_dir = nil
 | |
|   end
 | |
| 
 | |
|   ##
 | |
|   # Sign the public key from +certificate+ with the +signing_key+ and
 | |
|   # +signing_cert+, using the Gem::Security::DIGEST_ALGORITHM.  Uses the
 | |
|   # default certificate validity range and extensions.
 | |
|   #
 | |
|   # Returns the newly signed certificate.
 | |
| 
 | |
|   def self.sign certificate, signing_key, signing_cert,
 | |
|                 age = ONE_YEAR, extensions = EXTENSIONS, serial = 1
 | |
|     signee_subject = certificate.subject
 | |
|     signee_key     = certificate.public_key
 | |
| 
 | |
|     alt_name = certificate.extensions.find do |extension|
 | |
|       extension.oid == 'subjectAltName'
 | |
|     end
 | |
| 
 | |
|     extensions = extensions.merge 'subjectAltName' => alt_name.value if
 | |
|       alt_name
 | |
| 
 | |
|     issuer_alt_name = signing_cert.extensions.find do |extension|
 | |
|       extension.oid == 'subjectAltName'
 | |
|     end
 | |
| 
 | |
|     extensions = extensions.merge 'issuerAltName' => issuer_alt_name.value if
 | |
|       issuer_alt_name
 | |
| 
 | |
|     signed = create_cert signee_subject, signee_key, age, extensions, serial
 | |
|     signed.issuer = signing_cert.subject
 | |
| 
 | |
|     signed.sign signing_key, Gem::Security::DIGEST_ALGORITHM.new
 | |
|   end
 | |
| 
 | |
|   ##
 | |
|   # Returns a Gem::Security::TrustDir which wraps the directory where trusted
 | |
|   # certificates live.
 | |
| 
 | |
|   def self.trust_dir
 | |
|     return @trust_dir if @trust_dir
 | |
| 
 | |
|     dir = File.join Gem.user_home, '.gem', 'trust'
 | |
| 
 | |
|     @trust_dir ||= Gem::Security::TrustDir.new dir
 | |
|   end
 | |
| 
 | |
|   ##
 | |
|   # Enumerates the trusted certificates via Gem::Security::TrustDir.
 | |
| 
 | |
|   def self.trusted_certificates &block
 | |
|     trust_dir.each_certificate(&block)
 | |
|   end
 | |
| 
 | |
|   ##
 | |
|   # Writes +pemmable+, which must respond to +to_pem+ to +path+ with the given
 | |
|   # +permissions+. If passed +cipher+ and +passphrase+ those arguments will be
 | |
|   # passed to +to_pem+.
 | |
| 
 | |
|   def self.write pemmable, path, permissions = 0600, passphrase = nil, cipher = KEY_CIPHER
 | |
|     path = File.expand_path path
 | |
| 
 | |
|     open path, 'wb', permissions do |io|
 | |
|       if passphrase and cipher
 | |
|         io.write pemmable.to_pem cipher, passphrase
 | |
|       else
 | |
|         io.write pemmable.to_pem
 | |
|       end
 | |
|     end
 | |
| 
 | |
|     path
 | |
|   end
 | |
| 
 | |
|   reset
 | |
| 
 | |
| end
 | |
| 
 | |
| if defined?(OpenSSL::SSL) then
 | |
|   require 'rubygems/security/policy'
 | |
|   require 'rubygems/security/policies'
 | |
|   require 'rubygems/security/trust_dir'
 | |
| end
 | |
| 
 | |
| require 'rubygems/security/signer'
 | |
| 
 |