Module: Gem::Security
- Defined in:
- lib/rubygems/security.rb,
lib/rubygems/install_update_options.rb
Overview
forward-declare
Defined Under Namespace
Classes: Exception, Policy, Signer
Constant Summary collapse
- OPT =
Default options for most of the methods below
{ # private key options :key_algo => Gem::SSL::PKEY_RSA, :key_size => 2048, # public cert options :cert_age => 365 * 24 * 3600, # 1 year :dgst_algo => Gem::SSL::DIGEST_SHA1, # x509 certificate extensions :cert_exts => { 'basicConstraints' => 'CA:FALSE', 'subjectKeyIdentifier' => 'hash', 'keyUsage' => 'keyEncipherment,dataEncipherment,digitalSignature', }, # save the key and cert to a file in build_self_signed_cert()? :save_key => true, :save_cert => true, # if you define either of these, then they'll be used instead of # the output_fmt macro below :save_key_path => nil, :save_cert_path => nil, # output name format for self-signed certs :output_fmt => 'gem-%s.pem', :munge_re => Regexp.new(/[^a-z0-9_.-]+/), # 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, }, }
- NoSecurity =
No security policy: all package signature checks are disabled.
Policy.new( :verify_data => false, :verify_signer => false, :verify_chain => false, :verify_root => false, :only_trusted => false, :only_signed => false )
- AlmostNoSecurity =
AlmostNo security policy: only verify that the signing certificate is the one that actually signed the data. Make no attempt to verify the signing certificate chain.
This policy is basically useless. better than nothing, but can still be easily spoofed, and is not recommended.
Policy.new( :verify_data => true, :verify_signer => false, :verify_chain => false, :verify_root => false, :only_trusted => false, :only_signed => false )
- LowSecurity =
Low security policy: only verify that the signing certificate is actually the gem signer, and that the signing certificate is valid.
This policy is better than nothing, but can still be easily spoofed, and is not recommended.
Policy.new( :verify_data => true, :verify_signer => true, :verify_chain => false, :verify_root => false, :only_trusted => false, :only_signed => false )
- MediumSecurity =
Medium security policy: verify the signing certificate, verify the signing certificate chain all the way to the root certificate, and only trust root certificates that we have explicitly allowed trust for.
This security policy is reasonable, but it allows unsigned packages, so a malicious person could simply delete the package signature and pass the gem off as unsigned.
Policy.new( :verify_data => true, :verify_signer => true, :verify_chain => true, :verify_root => true, :only_trusted => true, :only_signed => false )
- HighSecurity =
High security policy: only allow signed gems to be installed, verify the signing certificate, verify the signing certificate chain all the way to the root certificate, and only trust root certificates that we have explicitly allowed trust for.
This security policy is significantly more difficult to bypass, and offers a reasonable guarantee that the contents of the gem have not been altered.
Policy.new( :verify_data => true, :verify_signer => true, :verify_chain => true, :verify_root => true, :only_trusted => true, :only_signed => true )
- Policies =
Hash of configured security policies
{ 'NoSecurity' => NoSecurity, 'AlmostNoSecurity' => AlmostNoSecurity, 'LowSecurity' => LowSecurity, 'MediumSecurity' => MediumSecurity, 'HighSecurity' => HighSecurity, }
Class Method Summary collapse
-
.add_trusted_cert(cert, opt = {}) ⇒ Object
Add certificate to trusted cert list.
-
.build_cert(name, key, opt = {}) ⇒ Object
Build a certificate from the given DN and private key.
-
.build_self_signed_cert(email_addr, opt = {}) ⇒ Object
Build a self-signed certificate for the given email address.
-
.email_to_name(email_address, munge_re) ⇒ Object
Turns
email_address
into an OpenSSL::X509::Name. -
.sign_cert(cert, signing_key, signing_cert, opt = {}) ⇒ Object
Sign the cert cert with @signing_key and @signing_cert, using the digest algorithm opt.
-
.verify_trust_dir(path, perms) ⇒ Object
Make sure the trust directory exists.
Class Method Details
.add_trusted_cert(cert, opt = {}) ⇒ Object
Add certificate to trusted cert list.
Note: At the moment these are stored in OPT, although that directory may change in the future.
764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 |
# File 'lib/rubygems/security.rb', line 764 def self.add_trusted_cert(cert, opt = {}) opt = OPT.merge(opt) # 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[:trust_dir], opt[:perms][:trust_dir]) # write cert to output file File.open(path, 'wb') do |file| file.chmod(opt[:perms][:trusted_cert]) file.write(cert.to_pem) end # return nil nil end |
.build_cert(name, key, opt = {}) ⇒ Object
Build a certificate from the given DN and private key.
674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 |
# File 'lib/rubygems/security.rb', line 674 def self.build_cert(name, key, opt = {}) Gem.ensure_ssl_available opt = OPT.merge opt cert = OpenSSL::X509::Certificate.new cert.not_after = Time.now + opt[:cert_age] cert.not_before = Time.now cert.public_key = key.public_key cert.serial = 0 cert.subject = name cert.version = 2 ef = OpenSSL::X509::ExtensionFactory.new nil, cert cert.extensions = opt[:cert_exts].map do |ext_name, value| ef.create_extension ext_name, value end i_key = opt[:issuer_key] || key i_cert = opt[:issuer_cert] || cert cert = sign_cert cert, i_key, i_cert, opt cert end |
.build_self_signed_cert(email_addr, opt = {}) ⇒ Object
Build a self-signed certificate for the given email address.
704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 |
# File 'lib/rubygems/security.rb', line 704 def self.build_self_signed_cert(email_addr, opt = {}) Gem.ensure_ssl_available opt = OPT.merge(opt) path = { :key => nil, :cert => nil } name = email_to_name email_addr, opt[:munge_re] key = opt[:key_algo].new opt[:key_size] verify_trust_dir opt[:trust_dir], opt[:perms][:trust_dir] if opt[:save_key] then path[:key] = opt[:save_key_path] || (opt[:output_fmt] % 'private_key') open path[:key], 'wb' do |io| io.chmod opt[:perms][:signing_key] io.write key.to_pem end end cert = build_cert name, key, opt if opt[:save_cert] then path[:cert] = opt[:save_cert_path] || (opt[:output_fmt] % 'public_cert') open path[:cert], 'wb' do |file| file.chmod opt[:perms][:signing_cert] file.write cert.to_pem end end { :key => key, :cert => cert, :key_path => path[:key], :cert_path => path[:cert] } end |
.email_to_name(email_address, munge_re) ⇒ Object
Turns email_address
into an OpenSSL::X509::Name
742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 |
# File 'lib/rubygems/security.rb', line 742 def self.email_to_name email_address, munge_re cn, dcs = email_address.split '@' dcs = dcs.split '.' cn = cn.gsub munge_re, '_' dcs = dcs.map do |dc| dc.gsub munge_re, '_' end name = "CN=#{cn}/" << dcs.map { |dc| "DC=#{dc}" }.join('/') OpenSSL::X509::Name.parse name end |
.sign_cert(cert, signing_key, signing_cert, opt = {}) ⇒ Object
Sign the cert cert with @signing_key and @signing_cert, using the digest algorithm opt. Returns the newly signed certificate.
641 642 643 644 645 646 647 648 |
# File 'lib/rubygems/security.rb', line 641 def self.sign_cert(cert, signing_key, signing_cert, opt = {}) opt = OPT.merge(opt) cert.issuer = signing_cert.subject cert.sign signing_key, opt[:dgst_algo].new cert end |
.verify_trust_dir(path, perms) ⇒ Object
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.
655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 |
# File 'lib/rubygems/security.rb', line 655 def self.verify_trust_dir(path, perms) # 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.exist?(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(perms, path) end end |