[Rubygems-developers] [PATCH] RubyGems 0.9.0 Signing Updates

Paul Duncan pabs at pablotron.org
Thu Aug 31 03:44:11 EDT 2006


Hi All,

Attached is a small patch against RubyGems 0.9.0 which adds the
following:

  * Ensures that the trust directory exists and is a directory
    before trying to add a certificate to the trust store.
  * Ensures that permissions on the trust directory and generated
    certificates and keys are sufficiently restrictive.

On the off-chance that this patch gets mangled in transit, it's also
available on the web at the following URL:

  http://pablotron.org/files/rubygems-0.9.0-signing_updates.diff

For the security-conscious among you, an OpenPGP signature of the
aforementioned patch can be found here:

  http://pablotron.org/files/rubygems-0.9.0-signing_updates.diff.asc

It's a relatively small set of changes. That said, questions, comments,
and unadulterated vitriol are always appreciated. :)

-- 
Paul Duncan <pabs at pablotron.org>        OpenPGP Key ID: 0x82C29562
http://www.pablotron.org/               http://www.paulduncan.org/
-------------- next part --------------
diff -ur rubygems-0.9.0/lib/rubygems/security.rb rubygems-0.9.0-fix_add_cert/lib/rubygems/security.rb
--- rubygems-0.9.0/lib/rubygems/security.rb	2006-06-06 23:39:54.000000000 -0400
+++ rubygems-0.9.0-fix_add_cert/lib/rubygems/security.rb	2006-08-31 03:17:32.000000000 -0400
@@ -95,6 +95,14 @@
 
       # output directory for trusted certificate checksums
       :trust_dir => File::join(Gem.user_home, '.gem', 'trust'),
+
+      # default permissions for trust directory and certs
+      :perms => {
+        :trust_dir      => 0700,
+        :trusted_cert   => 0600,
+        :signing_cert   => 0600,
+        :signing_key    => 0600,
+      },
     }
 
     #
@@ -342,6 +350,32 @@
     end
     
     #
+    # Make sure the trust directory exists.  If it does exist, make sure
+    # it's actually a directory.  If not, then create it with the
+    # appropriate permissions.
+    #
+    def self.verify_trust_dir(opt)
+      # grab path from options
+      path = opt[:trust_dir]
+
+      # if the directory exists, then make sure it is in fact a
+      # directory.  if it doesn't exist, then create it with the
+      # appropriate permissions
+      if File.exists?(path)
+        # verify that the trust directory is actually a directory
+        unless File.directory?(path)
+          err = "trust directory #{path} isn't a directory"
+          raise Gem::Security::Exception, err
+        end
+      else
+        # trust directory doesn't exist, so create it with 
+        # permissions
+        FileUtils.mkdir_p(path)
+        FileUtils.chmod(opt[:perms][:trust_dir], path)
+      end
+    end
+
+    #
     # Build a certificate from the given DN and private key.
     # 
     def self.build_cert(name, key, opt = {})
@@ -394,13 +428,16 @@
       # build private key
       key = opt[:key_algo].new(opt[:key_size])
 
-      # create the trust directory if it doesn't exist
-      FileUtils::mkdir_p(opt[:trust_dir]) unless File.exists?(opt[:trust_dir])
+      # method name pretty much says it all :)
+      verify_trust_dir(opt)
 
       # if we're saving the key, then write it out
       if opt[:save_key]
         path[:key] = opt[:save_key_path] || (opt[:output_fmt] % 'private_key')
-        File.open(path[:key], 'wb') { |file| file.write(key.to_pem) }
+        File.open(path[:key], 'wb') do |file| 
+          file.chmod(opt[:perms][:signing_key])
+          file.write(key.to_pem) 
+        end
       end
       
       # build self-signed public cert from key
@@ -409,7 +446,10 @@
       # if we're saving the cert, then write it out
       if opt[:save_cert]
         path[:cert] = opt[:save_cert_path] || (opt[:output_fmt] % 'public_cert')
-        File.open(path[:cert], 'wb') { |file| file.write(cert.to_pem) }
+        File.open(path[:cert], 'wb') do |file| 
+          file.chmod(opt[:perms][:signing_cert])
+          file.write(cert.to_pem)
+        end
       end
 
       # return key, cert, and paths (if applicable)
@@ -429,8 +469,14 @@
       # get destination path 
       path = Gem::Security::Policy.trusted_cert_path(cert, opt)
 
+      # verify trust directory (can't write to nowhere, you know)
+      verify_trust_dir(opt)
+
       # write cert to output file
-      File.open(path, 'wb') { |file| file.write(cert.to_pem) }
+      File.open(path, 'wb') do |file| 
+        file.chmod(opt[:perms][:trusted_cert])
+        file.write(cert.to_pem)
+      end
 
       # return nil
       nil
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: Digital signature
Url : http://rubyforge.org/pipermail/rubygems-developers/attachments/20060831/3ff112a2/attachment.bin 


More information about the Rubygems-developers mailing list