Class: Acmesmith::Certificate
- Inherits:
-
Object
- Object
- Acmesmith::Certificate
- Defined in:
- lib/acmesmith/certificate.rb
Defined Under Namespace
Classes: CertificateExport, PassphraseRequired, PrivateKeyDecrypted
Instance Attribute Summary collapse
- #certificate ⇒ OpenSSL::X509::Certificate readonly
- #chain ⇒ Array<OpenSSL::X509::Certificate> readonly
- #csr ⇒ OpenSSL::X509::Request readonly
Class Method Summary collapse
-
.by_issuance(pem_chain, csr) ⇒ Acmesmith::Certificate
Return Acmesmith::Certificate by an issued certificate.
-
.split_pems(pems) ⇒ Array<String>
Split string containing multiple PEMs into Array of PEM strings.
Instance Method Summary collapse
-
#common_name ⇒ String
Common name.
- #export(passphrase, cipher: OpenSSL::Cipher.new('aes-256-cbc')) ⇒ CertificateExport
-
#fullchain ⇒ String
Leaf certificate + full certificate chain.
-
#initialize(certificate, chain, private_key, key_passphrase = nil, csr = nil) ⇒ Certificate
constructor
A new instance of Certificate.
-
#issuer_pems ⇒ String
Issuer certificate chain.
-
#key_passphrase=(pw) ⇒ Object
Try to decrypt private_key if encrypted.
- #pkcs12(passphrase) ⇒ OpenSSL::PKCS12
- #private_key ⇒ OpenSSL::PKey::PKey
- #public_key ⇒ OpenSSL::PKey::PKey
-
#sans ⇒ Array<String>
Subject Alternative Names (dNSname).
-
#version ⇒ String
Version string (consists of NotBefore time & certificate serial).
Constructor Details
#initialize(certificate, chain, private_key, key_passphrase = nil, csr = nil) ⇒ Certificate
Returns a new instance of Certificate.
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
# File 'lib/acmesmith/certificate.rb', line 31 def initialize(certificate, chain, private_key, key_passphrase = nil, csr = nil) @certificate = case certificate when OpenSSL::X509::Certificate certificate when String OpenSSL::X509::Certificate.new(certificate) else raise TypeError, 'certificate is expected to be a String or OpenSSL::X509::Certificate' end chain = case chain when String self.class.split_pems(chain) when Array chain when nil [] else raise TypeError, 'chain is expected to be an Array<String or OpenSSL::X509::Certificate> or nil' end @chain = chain.map { |cert| case cert when OpenSSL::X509::Certificate cert when String OpenSSL::X509::Certificate.new(cert) else raise TypeError, 'chain is expected to be an Array<String or OpenSSL::X509::Certificate> or nil' end } case private_key when String @raw_private_key = private_key if key_passphrase self.key_passphrase = key_passphrase else begin @private_key = OpenSSL::PKey.read(@raw_private_key) { nil } rescue OpenSSL::PKey::PKeyError # may be encrypted end end when OpenSSL::PKey::PKey @private_key = private_key else raise TypeError, 'private_key is expected to be a String or OpenSSL::PKey::PKey' end @csr = case csr when nil nil when String OpenSSL::X509::Request.new(csr) when OpenSSL::X509::Request csr end end |
Instance Attribute Details
#certificate ⇒ OpenSSL::X509::Certificate (readonly)
91 92 93 |
# File 'lib/acmesmith/certificate.rb', line 91 def certificate @certificate end |
#chain ⇒ Array<OpenSSL::X509::Certificate> (readonly)
93 94 95 |
# File 'lib/acmesmith/certificate.rb', line 93 def chain @chain end |
#csr ⇒ OpenSSL::X509::Request (readonly)
95 96 97 |
# File 'lib/acmesmith/certificate.rb', line 95 def csr @csr end |
Class Method Details
.by_issuance(pem_chain, csr) ⇒ Acmesmith::Certificate
Return Acmesmith::Certificate by an issued certificate
21 22 23 24 |
# File 'lib/acmesmith/certificate.rb', line 21 def self.by_issuance(pem_chain, csr) pems = split_pems(pem_chain) new(pems[0], pems[1..-1], csr.private_key, nil, csr) end |
.split_pems(pems) ⇒ Array<String>
Split string containing multiple PEMs into Array of PEM strings.
13 14 15 |
# File 'lib/acmesmith/certificate.rb', line 13 def self.split_pems(pems) pems.each_line.slice_before(/^-----BEGIN CERTIFICATE-----$/).map(&:join) end |
Instance Method Details
#common_name ⇒ String
Returns common name.
132 133 134 |
# File 'lib/acmesmith/certificate.rb', line 132 def common_name certificate.subject.to_a.assoc('CN')[1] end |
#export(passphrase, cipher: OpenSSL::Cipher.new('aes-256-cbc')) ⇒ CertificateExport
154 155 156 157 158 159 160 161 162 163 164 165 |
# File 'lib/acmesmith/certificate.rb', line 154 def export(passphrase, cipher: OpenSSL::Cipher.new('aes-256-cbc')) CertificateExport.new.tap do |h| h.certificate = certificate.to_pem h.chain = issuer_pems h.fullchain = fullchain h.private_key = if passphrase private_key.export(cipher, passphrase) else private_key.export end end end |
#fullchain ⇒ String
Returns leaf certificate + full certificate chain.
122 123 124 |
# File 'lib/acmesmith/certificate.rb', line 122 def fullchain "#{certificate.to_pem}\n#{issuer_pems}".gsub(/\n+/,?\n) end |
#issuer_pems ⇒ String
Returns issuer certificate chain.
127 128 129 |
# File 'lib/acmesmith/certificate.rb', line 127 def issuer_pems chain.map(&:to_pem).join("\n") end |
#key_passphrase=(pw) ⇒ Object
Try to decrypt private_key if encrypted.
100 101 102 103 104 105 106 107 |
# File 'lib/acmesmith/certificate.rb', line 100 def key_passphrase=(pw) raise PrivateKeyDecrypted, 'private_key already given' if @private_key @private_key = OpenSSL::PKey.read(@raw_private_key, pw) @raw_private_key = nil nil end |
#pkcs12(passphrase) ⇒ OpenSSL::PKCS12
149 150 151 |
# File 'lib/acmesmith/certificate.rb', line 149 def pkcs12(passphrase) OpenSSL::PKCS12.create(passphrase, common_name, private_key, certificate, chain) end |
#private_key ⇒ OpenSSL::PKey::PKey
111 112 113 114 |
# File 'lib/acmesmith/certificate.rb', line 111 def private_key return @private_key if @private_key raise PassphraseRequired, 'key_passphrase required' end |
#public_key ⇒ OpenSSL::PKey::PKey
117 118 119 |
# File 'lib/acmesmith/certificate.rb', line 117 def public_key @certificate.public_key end |
#sans ⇒ Array<String>
Returns Subject Alternative Names (dNSname).
137 138 139 140 141 |
# File 'lib/acmesmith/certificate.rb', line 137 def sans certificate.extensions.select { |_| _.oid == 'subjectAltName' }.flat_map do |ext| ext.value.split(/,\s*/).select { |_| _.start_with?('DNS:') }.map { |_| _[4..-1] } end end |
#version ⇒ String
Returns Version string (consists of NotBefore time & certificate serial).
144 145 146 |
# File 'lib/acmesmith/certificate.rb', line 144 def version "#{certificate.not_before.utc.strftime('%Y%m%d-%H%M%S')}_#{certificate.serial.to_i.to_s(16)}" end |