Class: Gem::Security::Signer
| Relationships & Source Files | |
| Super Chains via Extension / Inclusion / Inheritance | |
| Instance Chain: | |
| Inherits: | Object | 
| Defined in: | lib/rubygems/security/signer.rb | 
Constant Summary
- 
    DEFAULT_OPTIONS =
    
 # File 'lib/rubygems/security/signer.rb', line 37{ expiration_length_days: 365 }.freeze
Class Method Summary
- 
    
      .new(key, cert_chain, passphrase = nil, options = {})  ⇒ Signer 
    
    constructor
    Creates a new signer with an RSA #key or path to a key, and a certificate chaincontaining X509 certificates, encoding certificates or paths to certificates.
- 
    
      .re_sign_cert(expired_cert, expired_cert_path, private_key) {|expired_cert_path, new_expired_cert_path| ... } 
    
    Attemps to re-sign an expired cert with a given private key. 
Instance Attribute Summary
- 
    
      #cert_chain  
    
    rw
    The chain of certificates for signing including the signing certificate. 
- 
    
      #digest_algorithm  
    
    readonly
    The digest algorithm used to create the signature. 
- 
    
      #key  
    
    rw
    The private key for the signing certificate. 
- 
    
      #options  
    
    readonly
    Signeroptions.
- 
    
      #digest_name  
    
    readonly
    Internal use only
    The name of the digest algorithm, used to pull digests out of the hash by name. 
::Gem::DefaultUserInteraction - Included
Instance Method Summary
- 
    
      #sign(data)  
    
    Sign data with given digest algorithm. 
- 
    
      #extract_name(cert)  
    
    Internal use only
    Extracts the full name of cert.
- 
    
      #load_cert_chain  
    
    Internal use only
    Loads any missing issuers in the cert chain from the trusted certificates. 
- 
    
      #re_sign_key(expiration_length: Gem::Security::ONE_YEAR)  
    
    Internal use only
    Attempts to re-sign the private key if the signing certificate is expired. 
::Gem::UserInteraction - Included
| #alert | Displays an alert  | 
| #alert_error | Displays an error  | 
| #alert_warning | Displays a warning  | 
| #ask | Asks a  | 
| #ask_for_password | Asks for a password with a  | 
| #ask_yes_no | Asks a yes or no  | 
| #choose_from_list | Asks the user to answer  | 
| #say | Displays the given  | 
| #terminate_interaction | Terminates the RubyGems process with the given  | 
| #verbose | Calls  | 
::Gem::DefaultUserInteraction - Included
::Gem::Text - Included
| #clean_text | Remove any non-printable characters and make the text suitable for printing. | 
| #format_text | Wraps  | 
| #levenshtein_distance | This code is based directly on the  | 
| #truncate_text, #min3 | |
Constructor Details
    .new(key, cert_chain, passphrase = nil, options = {})  ⇒ Signer 
  
Creates a new signer with an RSA #key or path to a key, and a certificate chain containing X509 certificates, encoding certificates or paths to certificates.
# File 'lib/rubygems/security/signer.rb', line 68
def initialize(key, cert_chain, passphrase = nil, = {}) @cert_chain = cert_chain @key = key @passphrase = passphrase @options = DEFAULT_OPTIONS.merge() unless @key default_key = File.join Gem.default_key_path @key = default_key if File.exist? default_key end unless @cert_chain default_cert = File.join Gem.default_cert_path @cert_chain = [default_cert] if File.exist? default_cert end @digest_algorithm = Gem::Security::DIGEST_ALGORITHM @digest_name = Gem::Security::DIGEST_NAME if @key && !@key.is_a?(OpenSSL::PKey::RSA) @key = OpenSSL::PKey::RSA.new(File.read(@key), @passphrase) end if @cert_chain @cert_chain = @cert_chain.compact.map do |cert| next cert if OpenSSL::X509::Certificate === cert cert = File.read cert if File.exist? cert OpenSSL::X509::Certificate.new cert end load_cert_chain end end
Class Method Details
.re_sign_cert(expired_cert, expired_cert_path, private_key) {|expired_cert_path, new_expired_cert_path| ... }
Attemps to re-sign an expired cert with a given private key
# File 'lib/rubygems/security/signer.rb', line 43
def self.re_sign_cert(expired_cert, expired_cert_path, private_key) return unless expired_cert.not_after < Time.now expiry = expired_cert.not_after.strftime('%Y%m%d%H%M%S') expired_cert_file = "#{File.basename(expired_cert_path)}.expired.#{expiry}" new_expired_cert_path = File.join(Gem.user_home, ".gem", expired_cert_file) Gem::Security.write(expired_cert, new_expired_cert_path) re_signed_cert = Gem::Security.re_sign( expired_cert, private_key, (Gem::Security::ONE_DAY * Gem.configuration.cert_expiration_length_days) ) Gem::Security.write(re_signed_cert, expired_cert_path) yield(expired_cert_path, new_expired_cert_path) if block_given? end
Instance Attribute Details
#cert_chain (rw)
The chain of certificates for signing including the signing certificate
# File 'lib/rubygems/security/signer.rb', line 14
attr_accessor :cert_chain
#digest_algorithm (readonly)
The digest algorithm used to create the signature
# File 'lib/rubygems/security/signer.rb', line 24
attr_reader :digest_algorithm
#digest_name (readonly)
The name of the digest algorithm, used to pull digests out of the hash by name.
# File 'lib/rubygems/security/signer.rb', line 30
attr_reader :digest_name # :nodoc:
#key (rw)
The private key for the signing certificate
# File 'lib/rubygems/security/signer.rb', line 19
attr_accessor :key
#options (readonly)
Signer options
# File 'lib/rubygems/security/signer.rb', line 35
attr_reader :
Instance Method Details
#extract_name(cert)
Extracts the full name of cert.  If the certificate has a subjectAltName this value is preferred, otherwise the subject is used.
# File 'lib/rubygems/security/signer.rb', line 108
def extract_name(cert) # :nodoc: subject_alt_name = cert.extensions.find { |e| 'subjectAltName' == e.oid } if subject_alt_name /\Aemail:/ =~ subject_alt_name.value $' || subject_alt_name.value else cert.subject end end
#load_cert_chain
Loads any missing issuers in the cert chain from the trusted certificates.
If the issuer does not exist it is ignored as it will be checked later.
# File 'lib/rubygems/security/signer.rb', line 125
def load_cert_chain # :nodoc: return if @cert_chain.empty? while @cert_chain.first.issuer.to_s != @cert_chain.first.subject.to_s do issuer = Gem::Security.trust_dir.issuer_of @cert_chain.first break unless issuer # cert chain is verified later @cert_chain.unshift issuer end end
#re_sign_key(expiration_length: Gem::Security::ONE_YEAR)
Attempts to re-sign the private key if the signing certificate is expired.
The key will be re-signed if:
- 
The expired certificate is self-signed 
- 
The expired certificate is saved at ~/.gem/gem-public_cert.pem and the private key is saved at ~/.gem/gem-private_key.pem 
- 
There is no file matching the expiry date at ~/.gem/gem-public_cert.pem.expired.%Y%m%d%H%M%S 
If the signing certificate can be re-signed the expired certificate will be saved as ~/.gem/gem-public_cert.pem.expired.%Y%m%d%H%M%S where the expiry time (not after) is used for the timestamp.
# File 'lib/rubygems/security/signer.rb', line 174
def re_sign_key(expiration_length: Gem::Security::ONE_YEAR) # :nodoc: old_cert = @cert_chain.last disk_cert_path = File.join(Gem.default_cert_path) disk_cert = File.read(disk_cert_path) rescue nil disk_key_path = File.join(Gem.default_key_path) disk_key = OpenSSL::PKey::RSA.new(File.read(disk_key_path), @passphrase) rescue nil return unless disk_key if disk_key.to_pem == @key.to_pem && disk_cert == old_cert.to_pem expiry = old_cert.not_after.strftime('%Y%m%d%H%M%S') old_cert_file = "gem-public_cert.pem.expired.#{expiry}" old_cert_path = File.join(Gem.user_home, ".gem", old_cert_file) unless File.exist?(old_cert_path) Gem::Security.write(old_cert, old_cert_path) cert = Gem::Security.re_sign(old_cert, @key, expiration_length) Gem::Security.write(cert, disk_cert_path) alert("Your cert: #{disk_cert_path} has been auto re-signed with the key: #{disk_key_path}") alert("Your expired cert will be located at: #{old_cert_path}") @cert_chain = [cert] end end end
#sign(data)
Sign data with given digest algorithm
# File 'lib/rubygems/security/signer.rb', line 140
def sign(data) return unless @key raise Gem::Security::Exception, 'no certs provided' if @cert_chain.empty? if @cert_chain.length == 1 and @cert_chain.last.not_after < Time.now alert("Your certificate has expired, trying to re-sign it...") re_sign_key( expiration_length: (Gem::Security::ONE_DAY * [:expiration_length_days]) ) end full_name = extract_name @cert_chain.last Gem::Security::SigningPolicy.verify @cert_chain, @key, {}, {}, full_name @key.sign @digest_algorithm.new, data end