module Gem::Security
def self.alt_name_or_x509_entry(certificate, x509_entry)
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
def self.create_cert(subject, key, age = ONE_YEAR, extensions = EXTENSIONS,
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
def self.create_cert_email(email, key, age = ONE_YEAR, extensions = EXTENSIONS)
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
def self.create_cert_self_signed(subject, key, age = ONE_YEAR,
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
def self.create_digest(algorithm = DIGEST_NAME)
def self.create_digest(algorithm = DIGEST_NAME) OpenSSL::Digest.new(algorithm) end
def self.create_digest(algorithm = DIGEST_NAME)
def self.create_digest(algorithm = DIGEST_NAME) Digest.const_get(algorithm).new end
def self.create_key(length = KEY_LENGTH, algorithm = KEY_ALGORITHM)
def self.create_key(length = KEY_LENGTH, algorithm = KEY_ALGORITHM) algorithm.new length end
def self.email_to_name(email_address)
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
def self.re_sign(expired_certificate, private_key, age = ONE_YEAR,
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 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
def self.reset
def self.reset @trust_dir = nil end
def self.sign(certificate, signing_key, signing_cert,
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_NAME end
def self.trust_dir
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
def self.trusted_certificates(&block)
def self.trusted_certificates(&block) trust_dir.each_certificate(&block) end
def self.write(pemmable, path, permissions = 0600, passphrase = nil, cipher = KEY_CIPHER)
def self.write(pemmable, path, permissions = 0600, passphrase = nil, cipher = KEY_CIPHER) path = File.expand_path path File.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