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_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 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

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_ALGORITHM.new
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
  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