summaryrefslogtreecommitdiff
path: root/vendor/gems/certificate_authority/lib
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/gems/certificate_authority/lib')
-rw-r--r--vendor/gems/certificate_authority/lib/certificate_authority.rb21
-rw-r--r--vendor/gems/certificate_authority/lib/certificate_authority/certificate.rb258
-rw-r--r--vendor/gems/certificate_authority/lib/certificate_authority/certificate_revocation_list.rb79
-rw-r--r--vendor/gems/certificate_authority/lib/certificate_authority/distinguished_name.rb102
-rw-r--r--vendor/gems/certificate_authority/lib/certificate_authority/extensions.rb631
-rw-r--r--vendor/gems/certificate_authority/lib/certificate_authority/key_material.rb114
-rw-r--r--vendor/gems/certificate_authority/lib/certificate_authority/ocsp_handler.rb144
-rw-r--r--vendor/gems/certificate_authority/lib/certificate_authority/pkcs11_key_material.rb65
-rw-r--r--vendor/gems/certificate_authority/lib/certificate_authority/revocable.rb14
-rw-r--r--vendor/gems/certificate_authority/lib/certificate_authority/serial_number.rb14
-rw-r--r--vendor/gems/certificate_authority/lib/certificate_authority/signing_entity.rb16
-rw-r--r--vendor/gems/certificate_authority/lib/certificate_authority/signing_request.rb91
-rw-r--r--vendor/gems/certificate_authority/lib/tasks/certificate_authority.rake23
13 files changed, 1572 insertions, 0 deletions
diff --git a/vendor/gems/certificate_authority/lib/certificate_authority.rb b/vendor/gems/certificate_authority/lib/certificate_authority.rb
new file mode 100644
index 0000000..a697c1b
--- /dev/null
+++ b/vendor/gems/certificate_authority/lib/certificate_authority.rb
@@ -0,0 +1,21 @@
+$:.unshift(File.dirname(__FILE__)) unless $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
+
+#Exterior requirements
+require 'openssl'
+require 'active_model'
+
+#Internal modules
+require 'certificate_authority/signing_entity'
+require 'certificate_authority/revocable'
+require 'certificate_authority/distinguished_name'
+require 'certificate_authority/serial_number'
+require 'certificate_authority/key_material'
+require 'certificate_authority/pkcs11_key_material'
+require 'certificate_authority/extensions'
+require 'certificate_authority/certificate'
+require 'certificate_authority/certificate_revocation_list'
+require 'certificate_authority/ocsp_handler'
+require 'certificate_authority/signing_request'
+
+module CertificateAuthority
+end
diff --git a/vendor/gems/certificate_authority/lib/certificate_authority/certificate.rb b/vendor/gems/certificate_authority/lib/certificate_authority/certificate.rb
new file mode 100644
index 0000000..0bddb86
--- /dev/null
+++ b/vendor/gems/certificate_authority/lib/certificate_authority/certificate.rb
@@ -0,0 +1,258 @@
+require 'active_support/all'
+
+module CertificateAuthority
+ class Certificate
+ include ActiveModel::Validations
+ include Revocable
+
+ attr_accessor :distinguished_name
+ attr_accessor :serial_number
+ attr_accessor :key_material
+ attr_accessor :not_before
+ attr_accessor :not_after
+ attr_accessor :extensions
+ attr_accessor :openssl_body
+
+ alias :subject :distinguished_name #Same thing as the DN
+
+ attr_accessor :parent
+
+ validate do |certificate|
+ errors.add :base, "Distinguished name must be valid" unless distinguished_name.valid?
+ errors.add :base, "Key material must be valid" unless key_material.valid?
+ errors.add :base, "Serial number must be valid" unless serial_number.valid?
+ errors.add :base, "Extensions must be valid" unless extensions.each do |item|
+ unless item.respond_to?(:valid?)
+ true
+ else
+ item.valid?
+ end
+ end
+ end
+
+ def initialize
+ self.distinguished_name = DistinguishedName.new
+ self.serial_number = SerialNumber.new
+ self.key_material = MemoryKeyMaterial.new
+ self.not_before = Time.now.change(:min => 0).utc
+ self.not_after = Time.now.change(:min => 0).utc + 1.year
+ self.parent = self
+ self.extensions = load_extensions()
+
+ self.signing_entity = false
+
+ end
+
+=begin
+ def self.from_openssl openssl_cert
+ unless openssl_cert.is_a? OpenSSL::X509::Certificate
+ raise "Can only construct from an OpenSSL::X509::Certificate"
+ end
+
+ certificate = Certificate.new
+ # Only subject, key_material, and body are used for signing
+ certificate.distinguished_name = DistinguishedName.from_openssl openssl_cert.subject
+ certificate.key_material.public_key = openssl_cert.public_key
+ certificate.openssl_body = openssl_cert
+ certificate.serial_number.number = openssl_cert.serial.to_i
+ certificate.not_before = openssl_cert.not_before
+ certificate.not_after = openssl_cert.not_after
+ # TODO extensions
+ certificate
+ end
+=end
+
+ def sign!(signing_profile={})
+ raise "Invalid certificate #{self.errors.full_messages}" unless valid?
+ merge_profile_with_extensions(signing_profile)
+
+ openssl_cert = OpenSSL::X509::Certificate.new
+ openssl_cert.version = 2
+ openssl_cert.not_before = self.not_before
+ openssl_cert.not_after = self.not_after
+ openssl_cert.public_key = self.key_material.public_key
+
+ openssl_cert.serial = self.serial_number.number
+
+ openssl_cert.subject = self.distinguished_name.to_x509_name
+ openssl_cert.issuer = parent.distinguished_name.to_x509_name
+
+ require 'tempfile'
+ t = Tempfile.new("bullshit_conf")
+ ## The config requires a file even though we won't use it
+ openssl_config = OpenSSL::Config.new(t.path)
+
+ factory = OpenSSL::X509::ExtensionFactory.new
+ factory.subject_certificate = openssl_cert
+
+ #NB: If the parent doesn't have an SSL body we're making this a self-signed cert
+ if parent.openssl_body.nil?
+ factory.issuer_certificate = openssl_cert
+ else
+ factory.issuer_certificate = parent.openssl_body
+ end
+
+ self.extensions.keys.each do |k|
+ config_extensions = extensions[k].config_extensions
+ openssl_config = merge_options(openssl_config,config_extensions)
+ end
+
+ # p openssl_config.sections
+
+ factory.config = openssl_config
+
+ # Order matters: e.g. for self-signed, subjectKeyIdentifier must come before authorityKeyIdentifier
+ self.extensions.keys.sort{|a,b| b<=>a}.each do |k|
+ e = extensions[k]
+ next if e.to_s.nil? or e.to_s == "" ## If the extension returns an empty string we won't include it
+ ext = factory.create_ext(e.openssl_identifier, e.to_s, e.critical)
+ openssl_cert.add_extension(ext)
+ end
+
+ if signing_profile["digest"].nil?
+ digest = OpenSSL::Digest.new("SHA512")
+ else
+ digest = OpenSSL::Digest.new(signing_profile["digest"])
+ end
+
+ self.openssl_body = openssl_cert.sign(parent.key_material.private_key, digest)
+ ensure
+ t.close! if t # We can get rid of the ridiculous temp file
+ end
+
+ def is_signing_entity?
+ self.extensions["basicConstraints"].ca
+ end
+
+ def signing_entity=(signing)
+ self.extensions["basicConstraints"].ca = signing
+ end
+
+ def revoked?
+ !self.revoked_at.nil?
+ end
+
+ def to_pem
+ raise "Certificate has no signed body" if self.openssl_body.nil?
+ self.openssl_body.to_pem
+ end
+
+ def to_csr
+ csr = SigningRequest.new
+ csr.distinguished_name = self.distinguished_name
+ csr.key_material = self.key_material
+ factory = OpenSSL::X509::ExtensionFactory.new
+ exts = []
+ self.extensions.keys.each do |k|
+ ## Don't copy over key identifiers for CSRs
+ next if k == "subjectKeyIdentifier" || k == "authorityKeyIdentifier"
+ e = extensions[k]
+ ## If the extension returns an empty string we won't include it
+ next if e.to_s.nil? or e.to_s == ""
+ exts << factory.create_ext(e.openssl_identifier, e.to_s, e.critical)
+ end
+ attrval = OpenSSL::ASN1::Set([OpenSSL::ASN1::Sequence(exts)])
+ attrs = [
+ OpenSSL::X509::Attribute.new("extReq", attrval),
+ OpenSSL::X509::Attribute.new("msExtReq", attrval)
+ ]
+ csr.attributes = attrs
+ csr
+ end
+
+ def self.from_x509_cert(raw_cert)
+ openssl_cert = OpenSSL::X509::Certificate.new(raw_cert)
+ Certificate.from_openssl(openssl_cert)
+ end
+
+ def is_root_entity?
+ self.parent == self && is_signing_entity?
+ end
+
+ def is_intermediate_entity?
+ (self.parent != self) && is_signing_entity?
+ end
+
+ private
+
+ def merge_profile_with_extensions(signing_profile={})
+ return self.extensions if signing_profile["extensions"].nil?
+ signing_config = signing_profile["extensions"]
+ signing_config.keys.each do |k|
+ extension = self.extensions[k]
+ items = signing_config[k]
+ items.keys.each do |profile_item_key|
+ if extension.respond_to?("#{profile_item_key}=".to_sym)
+ if k == 'subjectAltName' && profile_item_key == 'emails'
+ items[profile_item_key].map do |email|
+ if email == 'email:copy'
+ fail "no email address provided for subject: #{subject.to_x509_name}" unless subject.email_address
+ "email:#{subject.email_address}"
+ else
+ email
+ end
+ end
+ end
+ extension.send("#{profile_item_key}=".to_sym, items[profile_item_key] )
+ else
+ p "Tried applying '#{profile_item_key}' to #{extension.class} but it doesn't respond!"
+ end
+ end
+ end
+ end
+
+ # Enumeration of the extensions. Not the worst option since
+ # the likelihood of these needing to be updated is low at best.
+ EXTENSIONS = [
+ CertificateAuthority::Extensions::BasicConstraints,
+ CertificateAuthority::Extensions::CrlDistributionPoints,
+ CertificateAuthority::Extensions::SubjectKeyIdentifier,
+ CertificateAuthority::Extensions::AuthorityKeyIdentifier,
+ CertificateAuthority::Extensions::AuthorityInfoAccess,
+ CertificateAuthority::Extensions::KeyUsage,
+ CertificateAuthority::Extensions::ExtendedKeyUsage,
+ CertificateAuthority::Extensions::SubjectAlternativeName,
+ CertificateAuthority::Extensions::CertificatePolicies
+ ]
+
+ def load_extensions
+ extension_hash = {}
+
+ EXTENSIONS.each do |klass|
+ extension = klass.new
+ extension_hash[extension.openssl_identifier] = extension
+ end
+
+ extension_hash
+ end
+
+ def merge_options(config,hash)
+ hash.keys.each do |k|
+ config[k] = hash[k]
+ end
+ config
+ end
+
+ def self.from_openssl openssl_cert
+ unless openssl_cert.is_a? OpenSSL::X509::Certificate
+ raise "Can only construct from an OpenSSL::X509::Certificate"
+ end
+
+ certificate = Certificate.new
+ # Only subject, key_material, and body are used for signing
+ certificate.distinguished_name = DistinguishedName.from_openssl openssl_cert.subject
+ certificate.key_material.public_key = openssl_cert.public_key
+ certificate.openssl_body = openssl_cert
+ certificate.serial_number.number = openssl_cert.serial.to_i
+ certificate.not_before = openssl_cert.not_before
+ certificate.not_after = openssl_cert.not_after
+ EXTENSIONS.each do |klass|
+ _,v,c = (openssl_cert.extensions.detect { |e| e.to_a.first == klass::OPENSSL_IDENTIFIER } || []).to_a
+ certificate.extensions[klass::OPENSSL_IDENTIFIER] = klass.parse(v, c) if v
+ end
+
+ certificate
+ end
+
+ end
+end
diff --git a/vendor/gems/certificate_authority/lib/certificate_authority/certificate_revocation_list.rb b/vendor/gems/certificate_authority/lib/certificate_authority/certificate_revocation_list.rb
new file mode 100644
index 0000000..1c68d09
--- /dev/null
+++ b/vendor/gems/certificate_authority/lib/certificate_authority/certificate_revocation_list.rb
@@ -0,0 +1,79 @@
+module CertificateAuthority
+ class CertificateRevocationList
+ include ActiveModel::Validations
+
+ attr_accessor :certificates
+ attr_accessor :parent
+ attr_accessor :crl_body
+ attr_accessor :next_update
+ attr_accessor :last_update_skew_seconds
+
+ validate do |crl|
+ errors.add :next_update, "Next update must be a positive value" if crl.next_update < 0
+ errors.add :parent, "A parent entity must be set" if crl.parent.nil?
+ end
+
+ def initialize
+ self.certificates = []
+ self.next_update = 60 * 60 * 4 # 4 hour default
+ self.last_update_skew_seconds = 0
+ end
+
+ def <<(revocable)
+ case revocable
+ when Revocable
+ raise "Only revoked entities can be added to a CRL" unless revocable.revoked?
+ self.certificates << revocable
+ when OpenSSL::X509::Certificate
+ raise "Not implemented yet"
+ else
+ raise "#{revocable.class} cannot be included in a CRL"
+ end
+ end
+
+ def sign!(signing_profile={})
+ raise "No parent entity has been set!" if self.parent.nil?
+ raise "Invalid CRL" unless self.valid?
+
+ revocations = self.certificates.collect do |revocable|
+ revocation = OpenSSL::X509::Revoked.new
+
+ ## We really just need a serial number, now we have to dig it out
+ case revocable
+ when Certificate
+ x509_cert = OpenSSL::X509::Certificate.new(revocable.to_pem)
+ revocation.serial = x509_cert.serial
+ when SerialNumber
+ revocation.serial = revocable.number
+ end
+ revocation.time = revocable.revoked_at
+ revocation
+ end
+
+ crl = OpenSSL::X509::CRL.new
+ revocations.each do |revocation|
+ crl.add_revoked(revocation)
+ end
+
+ crl.version = 1
+ crl.last_update = Time.now - self.last_update_skew_seconds
+ crl.next_update = Time.now + self.next_update
+
+ signing_cert = OpenSSL::X509::Certificate.new(self.parent.to_pem)
+ if signing_profile["digest"].nil?
+ digest = OpenSSL::Digest.new("SHA512")
+ else
+ digest = OpenSSL::Digest.new(signing_profile["digest"])
+ end
+ crl.issuer = signing_cert.subject
+ self.crl_body = crl.sign(self.parent.key_material.private_key, digest)
+
+ self.crl_body
+ end
+
+ def to_pem
+ raise "No signed CRL body" if self.crl_body.nil?
+ self.crl_body.to_pem
+ end
+ end#CertificateRevocationList
+end
diff --git a/vendor/gems/certificate_authority/lib/certificate_authority/distinguished_name.rb b/vendor/gems/certificate_authority/lib/certificate_authority/distinguished_name.rb
new file mode 100644
index 0000000..32d9c1e
--- /dev/null
+++ b/vendor/gems/certificate_authority/lib/certificate_authority/distinguished_name.rb
@@ -0,0 +1,102 @@
+module CertificateAuthority
+ class DistinguishedName
+ include ActiveModel::Validations
+
+ validates_presence_of :common_name
+
+ attr_accessor :common_name
+ alias :cn :common_name
+ alias :cn= :common_name=
+
+ attr_accessor :locality
+ alias :l :locality
+ alias :l= :locality=
+
+ attr_accessor :state
+ alias :s :state
+ alias :st= :state=
+
+ attr_accessor :country
+ alias :c :country
+ alias :c= :country=
+
+ attr_accessor :organization
+ alias :o :organization
+ alias :o= :organization=
+
+ attr_accessor :organizational_unit
+ alias :ou :organizational_unit
+ alias :ou= :organizational_unit=
+
+ attr_accessor :email_address
+ alias :emailAddress :email_address
+ alias :emailAddress= :email_address=
+
+ attr_accessor :serial_number
+ alias :serialNumber :serial_number
+ alias :serialNumber= :serial_number=
+
+ def to_x509_name
+ raise "Invalid Distinguished Name" unless valid?
+
+ # NB: the capitalization in the strings counts
+ name = OpenSSL::X509::Name.new
+ name.add_entry("serialNumber", serial_number) unless serial_number.blank?
+ name.add_entry("C", country) unless country.blank?
+ name.add_entry("ST", state) unless state.blank?
+ name.add_entry("L", locality) unless locality.blank?
+ name.add_entry("O", organization) unless organization.blank?
+ name.add_entry("OU", organizational_unit) unless organizational_unit.blank?
+ name.add_entry("CN", common_name)
+ name.add_entry("emailAddress", email_address) unless email_address.blank?
+ name
+ end
+
+ def ==(other)
+ # Use the established OpenSSL comparison
+ self.to_x509_name() == other.to_x509_name()
+ end
+
+ def self.from_openssl openssl_name
+ unless openssl_name.is_a? OpenSSL::X509::Name
+ raise "Argument must be a OpenSSL::X509::Name"
+ end
+
+ WrappedDistinguishedName.new(openssl_name)
+ end
+ end
+
+ ## This is a significantly more complicated case. It's possible that
+ ## generically handled certificates will include custom OIDs in the
+ ## subject.
+ class WrappedDistinguishedName < DistinguishedName
+ attr_accessor :x509_name
+
+ def initialize(x509_name)
+ @x509_name = x509_name
+
+ subject = @x509_name.to_a
+ subject.each do |element|
+ field = element[0].downcase
+ value = element[1]
+ #type = element[2] ## -not used
+ method_sym = "#{field}=".to_sym
+ if self.respond_to?(method_sym)
+ self.send("#{field}=",value)
+ else
+ ## Custom OID
+ @custom_oids = true
+ end
+ end
+
+ end
+
+ def to_x509_name
+ @x509_name
+ end
+
+ def custom_oids?
+ @custom_oids
+ end
+ end
+end
diff --git a/vendor/gems/certificate_authority/lib/certificate_authority/extensions.rb b/vendor/gems/certificate_authority/lib/certificate_authority/extensions.rb
new file mode 100644
index 0000000..89de032
--- /dev/null
+++ b/vendor/gems/certificate_authority/lib/certificate_authority/extensions.rb
@@ -0,0 +1,631 @@
+module CertificateAuthority
+ module Extensions
+ module ExtensionAPI
+ def to_s
+ raise "Implementation required"
+ end
+
+ def self.parse(value, critical)
+ raise "Implementation required"
+ end
+
+ def config_extensions
+ {}
+ end
+
+ def openssl_identifier
+ raise "Implementation required"
+ end
+
+ def ==(value)
+ raise "Implementation required"
+ end
+ end
+
+ # Specifies whether an X.509v3 certificate can act as a CA, signing other
+ # certificates to be verified. If set, a path length constraint can also be
+ # specified.
+ # Reference: Section 4.2.1.10 of RFC3280
+ # http://tools.ietf.org/html/rfc3280#section-4.2.1.10
+ class BasicConstraints
+ OPENSSL_IDENTIFIER = "basicConstraints"
+
+ include ExtensionAPI
+ include ActiveModel::Validations
+
+ attr_accessor :critical
+ attr_accessor :ca
+ attr_accessor :path_len
+ validates :critical, :inclusion => [true,false]
+ validates :ca, :inclusion => [true,false]
+
+ def initialize
+ @critical = false
+ @ca = false
+ end
+
+ def openssl_identifier
+ OPENSSL_IDENTIFIER
+ end
+
+ def is_ca?
+ @ca
+ end
+
+ def path_len=(value)
+ raise "path_len must be a non-negative integer" if value < 0 or !value.is_a?(Fixnum)
+ @path_len = value
+ end
+
+ def to_s
+ res = []
+ res << "CA:#{@ca}"
+ res << "pathlen:#{@path_len}" unless @path_len.nil?
+ res.join(',')
+ end
+
+ def ==(o)
+ o.class == self.class && o.state == state
+ end
+
+ def self.parse(value, critical)
+ obj = self.new
+ return obj if value.nil?
+ obj.critical = critical
+ value.split(/,\s*/).each do |v|
+ c = v.split(':', 2)
+ obj.ca = (c.last.upcase == "TRUE") if c.first == "CA"
+ obj.path_len = c.last.to_i if c.first == "pathlen"
+ end
+ obj
+ end
+
+ protected
+ def state
+ [@critical,@ca,@path_len]
+ end
+ end
+
+ # Specifies where CRL information be be retrieved. This extension isn't
+ # critical, but is recommended for proper CAs.
+ # Reference: Section 4.2.1.14 of RFC3280
+ # http://tools.ietf.org/html/rfc3280#section-4.2.1.14
+ class CrlDistributionPoints
+ OPENSSL_IDENTIFIER = "crlDistributionPoints"
+
+ include ExtensionAPI
+
+ attr_accessor :critical
+ attr_accessor :uris
+
+ def initialize
+ @critical = false
+ @uris = []
+ end
+
+ def openssl_identifier
+ OPENSSL_IDENTIFIER
+ end
+
+ ## NB: At this time it seems OpenSSL's extension handlers don't support
+ ## any of the config options the docs claim to support... everything comes back
+ ## "missing value" on GENERAL NAME. Even if copied verbatim
+ def config_extensions
+ {
+ # "custom_crl_fields" => {"fullname" => "URI:#{fullname}"},
+ # "issuer_sect" => {"CN" => "crlissuer.com", "C" => "US", "O" => "shudder"}
+ }
+ end
+
+ # This is for legacy support. Technically it can (and probably should)
+ # be an array. But if someone is calling the old accessor we shouldn't
+ # necessarily break it.
+ def uri=(value)
+ @uris << value
+ end
+
+ def to_s
+ res = []
+ @uris.each do |uri|
+ res << "URI:#{uri}"
+ end
+ res.join(',')
+ end
+
+ def ==(o)
+ o.class == self.class && o.state == state
+ end
+
+ def self.parse(value, critical)
+ obj = self.new
+ return obj if value.nil?
+ obj.critical = critical
+ value.split(/,\s*/).each do |v|
+ c = v.split(':', 2)
+ obj.uris << c.last if c.first == "URI"
+ end
+ obj
+ end
+
+ protected
+ def state
+ [@critical,@uri]
+ end
+ end
+
+ # Identifies the public key associated with a given certificate.
+ # Should be required for "CA" certificates.
+ # Reference: Section 4.2.1.2 of RFC3280
+ # http://tools.ietf.org/html/rfc3280#section-4.2.1.2
+ class SubjectKeyIdentifier
+ OPENSSL_IDENTIFIER = "subjectKeyIdentifier"
+
+ include ExtensionAPI
+
+ attr_accessor :critical
+ attr_accessor :identifier
+
+ def initialize
+ @critical = false
+ @identifier = "hash"
+ end
+
+ def openssl_identifier
+ OPENSSL_IDENTIFIER
+ end
+
+ def to_s
+ res = []
+ res << @identifier
+ res.join(',')
+ end
+
+ def ==(o)
+ o.class == self.class && o.state == state
+ end
+
+ def self.parse(value, critical)
+ obj = self.new
+ return obj if value.nil?
+ obj.critical = critical
+ obj.identifier = value
+ obj
+ end
+
+ protected
+ def state
+ [@critical,@identifier]
+ end
+ end
+
+ # Identifies the public key associated with a given private key.
+ # Reference: Section 4.2.1.1 of RFC3280
+ # http://tools.ietf.org/html/rfc3280#section-4.2.1.1
+ class AuthorityKeyIdentifier
+ OPENSSL_IDENTIFIER = "authorityKeyIdentifier"
+
+ include ExtensionAPI
+
+ attr_accessor :critical
+ attr_accessor :identifier
+
+ def initialize
+ @critical = false
+ @identifier = ["keyid", "issuer"]
+ end
+
+ def openssl_identifier
+ OPENSSL_IDENTIFIER
+ end
+
+ def to_s
+ res = []
+ res += @identifier
+ res.join(',')
+ end
+
+ def ==(o)
+ o.class == self.class && o.state == state
+ end
+
+ def self.parse(value, critical)
+ obj = self.new
+ return obj if value.nil?
+ obj.critical = critical
+ obj.identifier = value.split(/,\s*/).last.chomp
+ obj
+ end
+
+ protected
+ def state
+ [@critical,@identifier]
+ end
+ end
+
+ # Specifies how to access CA information and services for the CA that
+ # issued this certificate.
+ # Generally used to specify OCSP servers.
+ # Reference: Section 4.2.2.1 of RFC3280
+ # http://tools.ietf.org/html/rfc3280#section-4.2.2.1
+ class AuthorityInfoAccess
+ OPENSSL_IDENTIFIER = "authorityInfoAccess"
+
+ include ExtensionAPI
+
+ attr_accessor :critical
+ attr_accessor :ocsp
+ attr_accessor :ca_issuers
+
+ def initialize
+ @critical = false
+ @ocsp = []
+ @ca_issuers = []
+ end
+
+ def openssl_identifier
+ OPENSSL_IDENTIFIER
+ end
+
+ def to_s
+ res = []
+ res += @ocsp.map {|o| "OCSP;URI:#{o}" }
+ res += @ca_issuers.map {|c| "caIssuers;URI:#{c}" }
+ res.join(',')
+ end
+
+ def ==(o)
+ o.class == self.class && o.state == state
+ end
+
+ def self.parse(value, critical)
+ obj = self.new
+ return obj if value.nil?
+ obj.critical = critical
+ value.split("\n").each do |v|
+ if v.starts_with?("OCSP")
+ obj.ocsp << v.split.last
+ end
+
+ if v.starts_with?("CA Issuers")
+ obj.ca_issuers << v.split.last
+ end
+ end
+ obj
+ end
+
+ protected
+ def state
+ [@critical,@ocsp,@ca_issuers]
+ end
+ end
+
+ # Specifies the allowed usage purposes of the keypair specified in this certificate.
+ # Reference: Section 4.2.1.3 of RFC3280
+ # http://tools.ietf.org/html/rfc3280#section-4.2.1.3
+ #
+ # Note: OpenSSL when parsing an extension will return results in the form
+ # 'Digital Signature', but on signing you have to set it to 'digitalSignature'.
+ # So copying an extension from an imported cert isn't going to work yet.
+ class KeyUsage
+ OPENSSL_IDENTIFIER = "keyUsage"
+
+ include ExtensionAPI
+
+ attr_accessor :critical
+ attr_accessor :usage
+
+ def initialize
+ @critical = false
+ @usage = ["digitalSignature", "nonRepudiation"]
+ end
+
+ def openssl_identifier
+ OPENSSL_IDENTIFIER
+ end
+
+ def to_s
+ res = []
+ res += @usage
+ res.join(',')
+ end
+
+ def ==(o)
+ o.class == self.class && o.state == state
+ end
+
+ def self.parse(value, critical)
+ obj = self.new
+ return obj if value.nil?
+ obj.critical = critical
+ obj.usage = value.split(/,\s*/)
+ obj
+ end
+
+ protected
+ def state
+ [@critical,@usage]
+ end
+ end
+
+ # Specifies even more allowed usages in addition to what is specified in
+ # the Key Usage extension.
+ # Reference: Section 4.2.1.13 of RFC3280
+ # http://tools.ietf.org/html/rfc3280#section-4.2.1.13
+ class ExtendedKeyUsage
+ OPENSSL_IDENTIFIER = "extendedKeyUsage"
+
+ include ExtensionAPI
+
+ attr_accessor :critical
+ attr_accessor :usage
+
+ def initialize
+ @critical = false
+ @usage = ["serverAuth"]
+ end
+
+ def openssl_identifier
+ OPENSSL_IDENTIFIER
+ end
+
+ def to_s
+ res = []
+ res += @usage
+ res.join(',')
+ end
+
+ def ==(o)
+ o.class == self.class && o.state == state
+ end
+
+ def self.parse(value, critical)
+ obj = self.new
+ return obj if value.nil?
+ obj.critical = critical
+ obj.usage = value.split(/,\s*/)
+ obj
+ end
+
+ protected
+ def state
+ [@critical,@usage]
+ end
+ end
+
+ # Specifies additional "names" for which this certificate is valid.
+ # Reference: Section 4.2.1.7 of RFC3280
+ # http://tools.ietf.org/html/rfc3280#section-4.2.1.7
+ class SubjectAlternativeName
+ OPENSSL_IDENTIFIER = "subjectAltName"
+
+ include ExtensionAPI
+
+ attr_accessor :critical
+ attr_accessor :uris, :dns_names, :ips, :emails
+
+ def initialize
+ @critical = false
+ @uris = []
+ @dns_names = []
+ @ips = []
+ @emails = []
+ end
+
+ def openssl_identifier
+ OPENSSL_IDENTIFIER
+ end
+
+ def uris=(value)
+ raise "URIs must be an array" unless value.is_a?(Array)
+ @uris = value
+ end
+
+ def dns_names=(value)
+ raise "DNS names must be an array" unless value.is_a?(Array)
+ @dns_names = value
+ end
+
+ def ips=(value)
+ raise "IPs must be an array" unless value.is_a?(Array)
+ @ips = value
+ end
+
+ def emails=(value)
+ raise "Emails must be an array" unless value.is_a?(Array)
+ @emails = value
+ end
+
+ def to_s
+ res = []
+ res += @uris.map {|u| "URI:#{u}" }
+ res += @dns_names.map {|d| "DNS:#{d}" }
+ res += @ips.map {|i| "IP:#{i}" }
+ res += @emails.map {|i| "email:#{i}" }
+ res.join(',')
+ end
+
+ def ==(o)
+ o.class == self.class && o.state == state
+ end
+
+ def self.parse(value, critical)
+ obj = self.new
+ return obj if value.nil?
+ obj.critical = critical
+ value.split(/,\s*/).each do |v|
+ c = v.split(':', 2)
+ obj.uris << c.last if c.first == "URI"
+ obj.dns_names << c.last if c.first == "DNS"
+ obj.ips << c.last if c.first == "IP"
+ obj.emails << c.last if c.first == "EMAIL"
+ end
+ obj
+ end
+
+ protected
+ def state
+ [@critical,@uris,@dns_names,@ips,@emails]
+ end
+ end
+
+ class CertificatePolicies
+ OPENSSL_IDENTIFIER = "certificatePolicies"
+
+ include ExtensionAPI
+
+ attr_accessor :critical
+ attr_accessor :policy_identifier
+ attr_accessor :cps_uris
+ ##User notice
+ attr_accessor :explicit_text
+ attr_accessor :organization
+ attr_accessor :notice_numbers
+
+ def initialize
+ self.critical = false
+ @contains_data = false
+ end
+
+ def openssl_identifier
+ OPENSSL_IDENTIFIER
+ end
+
+ def user_notice=(value={})
+ value.keys.each do |key|
+ self.send("#{key}=".to_sym, value[key])
+ end
+ end
+
+ def config_extensions
+ config_extension = {}
+ custom_policies = {}
+ notice = {}
+ unless self.policy_identifier.nil?
+ custom_policies["policyIdentifier"] = self.policy_identifier
+ end
+
+ if !self.cps_uris.nil? and self.cps_uris.is_a?(Array)
+ self.cps_uris.each_with_index do |cps_uri,i|
+ custom_policies["CPS.#{i}"] = cps_uri
+ end
+ end
+
+ unless self.explicit_text.nil?
+ notice["explicitText"] = self.explicit_text
+ end
+
+ unless self.organization.nil?
+ notice["organization"] = self.organization
+ end
+
+ unless self.notice_numbers.nil?
+ notice["noticeNumbers"] = self.notice_numbers
+ end
+
+ if notice.keys.size > 0
+ custom_policies["userNotice.1"] = "@notice"
+ config_extension["notice"] = notice
+ end
+
+ if custom_policies.keys.size > 0
+ config_extension["custom_policies"] = custom_policies
+ @contains_data = true
+ end
+
+ config_extension
+ end
+
+ def to_s
+ return "" unless @contains_data
+ res = []
+ res << "ia5org"
+ res += @config_extensions["custom_policies"] unless @config_extensions.nil?
+ res.join(',')
+ end
+
+ def self.parse(value, critical)
+ obj = self.new
+ return obj if value.nil?
+ obj.critical = critical
+ value.split(/,\s*/).each do |v|
+ c = v.split(':', 2)
+ obj.policy_identifier = c.last if c.first == "policyIdentifier"
+ obj.cps_uris << c.last if c.first =~ %r{CPS.\d+}
+ # TODO: explicit_text, organization, notice_numbers
+ end
+ obj
+ end
+ end
+
+ # DEPRECATED
+ # Specifics the purposes for which a certificate can be used.
+ # The basicConstraints, keyUsage, and extendedKeyUsage extensions are now used instead.
+ # https://www.openssl.org/docs/apps/x509v3_config.html#Netscape_Certificate_Type
+ class NetscapeCertificateType
+ OPENSSL_IDENTIFIER = "nsCertType"
+
+ include ExtensionAPI
+
+ attr_accessor :critical
+ attr_accessor :flags
+
+ def initialize
+ self.critical = false
+ self.flags = []
+ end
+
+ def openssl_identifier
+ OPENSSL_IDENTIFIER
+ end
+
+ def to_s
+ res = []
+ res += self.flags
+ res.join(',')
+ end
+
+ def self.parse(value, critical)
+ obj = self.new
+ return obj if value.nil?
+ obj.critical = critical
+ obj.flags = value.split(/,\s*/)
+ obj
+ end
+ end
+
+ # DEPRECATED
+ # Contains a comment which will be displayed when the certificate is viewed in some browsers.
+ # https://www.openssl.org/docs/apps/x509v3_config.html#Netscape_String_extensions_
+ class NetscapeComment
+ OPENSSL_IDENTIFIER = "nsComment"
+
+ include ExtensionAPI
+
+ attr_accessor :critical
+ attr_accessor :comment
+
+ def initialize
+ self.critical = false
+ end
+
+ def openssl_identifier
+ OPENSSL_IDENTIFIER
+ end
+
+ def to_s
+ res = []
+ res << self.comment if self.comment
+ res.join(',')
+ end
+
+ def self.parse(value, critical)
+ obj = self.new
+ return obj if value.nil?
+ obj.critical = critical
+ obj.comment = value
+ obj
+ end
+ end
+
+ end
+end
diff --git a/vendor/gems/certificate_authority/lib/certificate_authority/key_material.rb b/vendor/gems/certificate_authority/lib/certificate_authority/key_material.rb
new file mode 100644
index 0000000..1fd4dd9
--- /dev/null
+++ b/vendor/gems/certificate_authority/lib/certificate_authority/key_material.rb
@@ -0,0 +1,114 @@
+module CertificateAuthority
+ module KeyMaterial
+ def public_key
+ raise "Required implementation"
+ end
+
+ def private_key
+ raise "Required implementation"
+ end
+
+ def is_in_hardware?
+ raise "Required implementation"
+ end
+
+ def is_in_memory?
+ raise "Required implementation"
+ end
+
+ def self.from_x509_key_pair(pair,password=nil)
+ if password.nil?
+ key = OpenSSL::PKey::RSA.new(pair)
+ else
+ key = OpenSSL::PKey::RSA.new(pair,password)
+ end
+ mem_key = MemoryKeyMaterial.new
+ mem_key.public_key = key.public_key
+ mem_key.private_key = key
+ mem_key
+ end
+
+ def self.from_x509_public_key(public_key_pem)
+ key = OpenSSL::PKey::RSA.new(public_key_pem)
+ signing_request_key = SigningRequestKeyMaterial.new
+ signing_request_key.public_key = key.public_key
+ signing_request_key
+ end
+ end
+
+ class MemoryKeyMaterial
+ include KeyMaterial
+ include ActiveModel::Validations
+
+ attr_accessor :keypair
+ attr_accessor :private_key
+ attr_accessor :public_key
+
+ def initialize
+ end
+
+ validates_each :private_key do |record, attr, value|
+ record.errors.add :private_key, "cannot be blank" if record.private_key.nil?
+ end
+ validates_each :public_key do |record, attr, value|
+ record.errors.add :public_key, "cannot be blank" if record.public_key.nil?
+ end
+
+ def is_in_hardware?
+ false
+ end
+
+ def is_in_memory?
+ true
+ end
+
+ def generate_key(modulus_bits=2048)
+ self.keypair = OpenSSL::PKey::RSA.new(modulus_bits)
+ self.private_key = keypair
+ self.public_key = keypair.public_key
+ self.keypair
+ end
+
+ def private_key
+ @private_key
+ end
+
+ def public_key
+ @public_key
+ end
+ end
+
+ class SigningRequestKeyMaterial
+ include KeyMaterial
+ include ActiveModel::Validations
+
+ validates_each :public_key do |record, attr, value|
+ record.errors.add :public_key, "cannot be blank" if record.public_key.nil?
+ end
+
+ attr_accessor :public_key
+
+ def initialize(request=nil)
+ if request.is_a? OpenSSL::X509::Request
+ raise "Invalid certificate signing request" unless request.verify request.public_key
+ self.public_key = request.public_key
+ end
+ end
+
+ def is_in_hardware?
+ false
+ end
+
+ def is_in_memory?
+ true
+ end
+
+ def private_key
+ nil
+ end
+
+ def public_key
+ @public_key
+ end
+ end
+end
diff --git a/vendor/gems/certificate_authority/lib/certificate_authority/ocsp_handler.rb b/vendor/gems/certificate_authority/lib/certificate_authority/ocsp_handler.rb
new file mode 100644
index 0000000..e101f98
--- /dev/null
+++ b/vendor/gems/certificate_authority/lib/certificate_authority/ocsp_handler.rb
@@ -0,0 +1,144 @@
+module CertificateAuthority
+ class OCSPResponseBuilder
+ attr_accessor :ocsp_response
+ attr_accessor :verification_mechanism
+ attr_accessor :ocsp_request_reader
+ attr_accessor :parent
+ attr_accessor :next_update
+
+ GOOD = OpenSSL::OCSP::V_CERTSTATUS_GOOD
+ REVOKED = OpenSSL::OCSP::V_CERTSTATUS_REVOKED
+
+ NO_REASON=0
+ KEY_COMPROMISED=OpenSSL::OCSP::REVOKED_STATUS_KEYCOMPROMISE
+ UNSPECIFIED=OpenSSL::OCSP::REVOKED_STATUS_UNSPECIFIED
+
+ def build_response()
+ raise "Requires a parent for signing" if @parent.nil?
+ if @verification_mechanism.nil?
+ ## If no verification callback is provided we're marking it GOOD
+ @verification_mechanism = lambda {|cert_id| [GOOD,NO_REASON] }
+ end
+
+ @ocsp_request_reader.ocsp_request.certid.each do |cert_id|
+ result,reason = verification_mechanism.call(cert_id.serial)
+
+ ## cert_id, status, reason, rev_time, this update, next update, ext
+ ## - unit of time is seconds
+ ## - rev_time is currently set to "now"
+ @ocsp_response.add_status(cert_id,
+ result, reason,
+ 0, 0, @next_update, nil)
+ end
+
+ @ocsp_response.sign(OpenSSL::X509::Certificate.new(@parent.to_pem), @parent.key_material.private_key, nil, nil)
+ OpenSSL::OCSP::Response.create(OpenSSL::OCSP::RESPONSE_STATUS_SUCCESSFUL, @ocsp_response)
+ end
+
+ def self.from_request_reader(request_reader,verification_mechanism=nil)
+ response_builder = OCSPResponseBuilder.new
+ response_builder.ocsp_request_reader = request_reader
+
+ ocsp_response = OpenSSL::OCSP::BasicResponse.new
+ ocsp_response.copy_nonce(request_reader.ocsp_request)
+ response_builder.ocsp_response = ocsp_response
+ response_builder.next_update = 60*15 #Default of 15 minutes
+ response_builder
+ end
+ end
+
+ class OCSPRequestReader
+ attr_accessor :raw_ocsp_request
+ attr_accessor :ocsp_request
+
+ def serial_numbers
+ @ocsp_request.certid.collect do |cert_id|
+ cert_id.serial
+ end
+ end
+
+ def self.from_der(request_body)
+ reader = OCSPRequestReader.new
+ reader.raw_ocsp_request = request_body
+ reader.ocsp_request = OpenSSL::OCSP::Request.new(request_body)
+
+ reader
+ end
+ end
+
+ ## DEPRECATED
+ class OCSPHandler
+ include ActiveModel::Validations
+
+ attr_accessor :ocsp_request
+ attr_accessor :certificate_ids
+
+ attr_accessor :certificates
+ attr_accessor :parent
+
+ attr_accessor :ocsp_response_body
+
+ validate do |crl|
+ errors.add :parent, "A parent entity must be set" if parent.nil?
+ end
+ validate :all_certificates_available
+
+ def initialize
+ self.certificates = {}
+ end
+
+ def <<(cert)
+ self.certificates[cert.serial_number.number.to_s] = cert
+ end
+
+ def extract_certificate_serials
+ openssl_request = OpenSSL::OCSP::Request.new(@ocsp_request)
+
+ self.certificate_ids = openssl_request.certid.collect do |cert_id|
+ cert_id.serial
+ end
+
+ self.certificate_ids
+ end
+
+
+ def response
+ raise "Invalid response" unless valid?
+
+ openssl_ocsp_response = OpenSSL::OCSP::BasicResponse.new
+ openssl_ocsp_request = OpenSSL::OCSP::Request.new(self.ocsp_request)
+ openssl_ocsp_response.copy_nonce(openssl_ocsp_request)
+
+ openssl_ocsp_request.certid.each do |cert_id|
+ certificate = self.certificates[cert_id.serial.to_s]
+
+ openssl_ocsp_response.add_status(cert_id,
+ OpenSSL::OCSP::V_CERTSTATUS_GOOD, 0,
+ 0, 0, 30, nil)
+ end
+
+
+ openssl_ocsp_response.sign(OpenSSL::X509::Certificate.new(self.parent.to_pem), self.parent.key_material.private_key, nil, nil)
+ final_response = OpenSSL::OCSP::Response.create(OpenSSL::OCSP::RESPONSE_STATUS_SUCCESSFUL, openssl_ocsp_response)
+ self.ocsp_response_body = final_response
+ self.ocsp_response_body
+ end
+
+ def to_der
+ raise "No signed OCSP response body available" if self.ocsp_response_body.nil?
+ self.ocsp_response_body.to_der
+ end
+
+ private
+
+ def all_certificates_available
+ openssl_ocsp_request = OpenSSL::OCSP::Request.new(self.ocsp_request)
+
+ openssl_ocsp_request.certid.each do |cert_id|
+ certificate = self.certificates[cert_id.serial.to_s]
+ errors.add(:base, "Certificate #{cert_id.serial} has not been added yet") if certificate.nil?
+ end
+ end
+
+ end
+end
diff --git a/vendor/gems/certificate_authority/lib/certificate_authority/pkcs11_key_material.rb b/vendor/gems/certificate_authority/lib/certificate_authority/pkcs11_key_material.rb
new file mode 100644
index 0000000..d4ebc47
--- /dev/null
+++ b/vendor/gems/certificate_authority/lib/certificate_authority/pkcs11_key_material.rb
@@ -0,0 +1,65 @@
+module CertificateAuthority
+ class Pkcs11KeyMaterial
+ include KeyMaterial
+ include ActiveModel::Validations
+ include ActiveModel::Serialization
+
+ attr_accessor :engine
+ attr_accessor :token_id
+ attr_accessor :pkcs11_lib
+ attr_accessor :openssl_pkcs11_engine_lib
+ attr_accessor :pin
+
+ def initialize(attributes = {})
+ @attributes = attributes
+ initialize_engine
+ end
+
+ def is_in_hardware?
+ true
+ end
+
+ def is_in_memory?
+ false
+ end
+
+ def generate_key(modulus_bits=1024)
+ puts "Key generation is not currently supported in hardware"
+ nil
+ end
+
+ def private_key
+ initialize_engine
+ self.engine.load_private_key(self.token_id)
+ end
+
+ def public_key
+ initialize_engine
+ self.engine.load_public_key(self.token_id)
+ end
+
+ private
+
+ def initialize_engine
+ ## We're going to return early and try again later if params weren't passed in
+ ## at initialization. Any attempt at getting a public/private key will try
+ ## again.
+ return false if self.openssl_pkcs11_engine_lib.nil? or self.pkcs11_lib.nil?
+ return self.engine unless self.engine.nil?
+ OpenSSL::Engine.load
+
+ pkcs11 = OpenSSL::Engine.by_id("dynamic") do |e|
+ e.ctrl_cmd("SO_PATH",self.openssl_pkcs11_engine_lib)
+ e.ctrl_cmd("ID","pkcs11")
+ e.ctrl_cmd("LIST_ADD","1")
+ e.ctrl_cmd("LOAD")
+ e.ctrl_cmd("PIN",self.pin) unless self.pin.nil? or self.pin == ""
+ e.ctrl_cmd("MODULE_PATH",self.pkcs11_lib)
+ end
+
+ self.engine = pkcs11
+ pkcs11
+ end
+
+ end
+end
diff --git a/vendor/gems/certificate_authority/lib/certificate_authority/revocable.rb b/vendor/gems/certificate_authority/lib/certificate_authority/revocable.rb
new file mode 100644
index 0000000..eba5d98
--- /dev/null
+++ b/vendor/gems/certificate_authority/lib/certificate_authority/revocable.rb
@@ -0,0 +1,14 @@
+module CertificateAuthority
+ module Revocable
+ attr_accessor :revoked_at
+
+ def revoke!(time=Time.now)
+ @revoked_at = time
+ end
+
+ def revoked?
+ # If we have a time, then we're revoked
+ !@revoked_at.nil?
+ end
+ end
+end
diff --git a/vendor/gems/certificate_authority/lib/certificate_authority/serial_number.rb b/vendor/gems/certificate_authority/lib/certificate_authority/serial_number.rb
new file mode 100644
index 0000000..143c144
--- /dev/null
+++ b/vendor/gems/certificate_authority/lib/certificate_authority/serial_number.rb
@@ -0,0 +1,14 @@
+module CertificateAuthority
+ class SerialNumber
+ include ActiveModel::Validations
+ include Revocable
+
+ attr_accessor :number
+
+ validates :number, :presence => true, :numericality => {:greater_than => 0}
+
+ def initialize
+ self.number = SecureRandom.random_number(2**128-1)
+ end
+ end
+end
diff --git a/vendor/gems/certificate_authority/lib/certificate_authority/signing_entity.rb b/vendor/gems/certificate_authority/lib/certificate_authority/signing_entity.rb
new file mode 100644
index 0000000..748350b
--- /dev/null
+++ b/vendor/gems/certificate_authority/lib/certificate_authority/signing_entity.rb
@@ -0,0 +1,16 @@
+module CertificateAuthority
+ module SigningEntity
+
+ def self.included(mod)
+ mod.class_eval do
+ attr_accessor :signing_entity
+ end
+ end
+
+ def signing_entity=(val)
+ raise "invalid param" unless [true,false].include?(val)
+ @signing_entity = val
+ end
+
+ end
+end
diff --git a/vendor/gems/certificate_authority/lib/certificate_authority/signing_request.rb b/vendor/gems/certificate_authority/lib/certificate_authority/signing_request.rb
new file mode 100644
index 0000000..3584dac
--- /dev/null
+++ b/vendor/gems/certificate_authority/lib/certificate_authority/signing_request.rb
@@ -0,0 +1,91 @@
+module CertificateAuthority
+ class SigningRequest
+ attr_accessor :distinguished_name
+ attr_accessor :key_material
+ attr_accessor :raw_body
+ attr_accessor :openssl_csr
+ attr_accessor :digest
+ attr_accessor :attributes
+
+ def initialize()
+ @attributes = []
+ end
+
+ # Fake attribute for convenience because adding
+ # alternative names on a CSR is remarkably non-trivial.
+ def subject_alternative_names=(alt_names)
+ raise "alt_names must be an Array" unless alt_names.is_a?(Array)
+
+ factory = OpenSSL::X509::ExtensionFactory.new
+ name_list = alt_names.map{|m| "DNS:#{m}"}.join(",")
+ ext = factory.create_ext("subjectAltName",name_list,false)
+ ext_set = OpenSSL::ASN1::Set([OpenSSL::ASN1::Sequence([ext])])
+ attr = OpenSSL::X509::Attribute.new("extReq", ext_set)
+ @attributes << attr
+ end
+
+ def read_attributes_by_oid(*oids)
+ attributes.detect { |a| oids.include?(a.oid) }
+ end
+ protected :read_attributes_by_oid
+
+ def to_cert
+ cert = Certificate.new
+ if !@distinguished_name.nil?
+ cert.distinguished_name = @distinguished_name
+ end
+ cert.key_material = @key_material
+ if attribute = read_attributes_by_oid('extReq', 'msExtReq')
+ set = OpenSSL::ASN1.decode(attribute.value)
+ seq = set.value.first
+ seq.value.collect { |asn1ext| OpenSSL::X509::Extension.new(asn1ext).to_a }.each do |o, v, c|
+ Certificate::EXTENSIONS.each do |klass|
+ cert.extensions[klass::OPENSSL_IDENTIFIER] = klass.parse(v, c) if v && klass::OPENSSL_IDENTIFIER == o
+ end
+ end
+ end
+ cert
+ end
+
+ def to_pem
+ to_x509_csr.to_pem
+ end
+
+ def to_x509_csr
+ raise "Must specify a DN/subject on csr" if @distinguished_name.nil?
+ raise "Invalid DN in request" unless @distinguished_name.valid?
+ raise "CSR must have key material" if @key_material.nil?
+ raise "CSR must include a public key on key material" if @key_material.public_key.nil?
+ raise "Need a private key on key material for CSR generation" if @key_material.private_key.nil?
+
+ opensslcsr = OpenSSL::X509::Request.new
+ opensslcsr.subject = @distinguished_name.to_x509_name
+ opensslcsr.public_key = @key_material.public_key
+ opensslcsr.attributes = @attributes unless @attributes.nil?
+ opensslcsr.sign @key_material.private_key, OpenSSL::Digest.new(@digest || "SHA512")
+ opensslcsr
+ end
+
+ def self.from_x509_csr(raw_csr)
+ csr = SigningRequest.new
+ openssl_csr = OpenSSL::X509::Request.new(raw_csr)
+ csr.distinguished_name = DistinguishedName.from_openssl openssl_csr.subject
+ csr.raw_body = raw_csr
+ csr.openssl_csr = openssl_csr
+ csr.attributes = openssl_csr.attributes
+ key_material = SigningRequestKeyMaterial.new
+ key_material.public_key = openssl_csr.public_key
+ csr.key_material = key_material
+ csr
+ end
+
+ def self.from_netscape_spkac(raw_spkac)
+ openssl_spkac = OpenSSL::Netscape::SPKI.new raw_spkac
+ csr = SigningRequest.new
+ csr.raw_body = raw_spkac
+ key_material = SigningRequestKeyMaterial.new
+ key_material.public_key = openssl_spkac.public_key
+ csr
+ end
+ end
+end
diff --git a/vendor/gems/certificate_authority/lib/tasks/certificate_authority.rake b/vendor/gems/certificate_authority/lib/tasks/certificate_authority.rake
new file mode 100644
index 0000000..e7d5bf9
--- /dev/null
+++ b/vendor/gems/certificate_authority/lib/tasks/certificate_authority.rake
@@ -0,0 +1,23 @@
+require 'certificate_authority'
+
+namespace :certificate_authority do
+ desc "Generate a quick self-signed cert"
+ task :self_signed do
+
+ cn = "http://localhost"
+ cn = ENV['DOMAIN'] unless ENV['DOMAIN'].nil?
+
+ root = CertificateAuthority::Certificate.new
+ root.subject.common_name= cn
+ root.key_material.generate_key
+ root.signing_entity = true
+ root.valid?
+ root.sign!
+
+ print "Your cert for #{cn}\n"
+ print root.to_pem
+
+ print "Your private key\n"
+ print root.key_material.private_key.to_pem
+ end
+end