Module: Chef::Mixin::OpenSSLHelper
- Included in:
- Resource::OpensslDhparam, Resource::OpensslEcPrivateKey, Resource::OpensslEcPublicKey, Resource::OpensslRsaPrivateKey, Resource::OpensslRsaPublicKey, Resource::OpensslX509Certificate, Resource::OpensslX509Crl, Resource::OpensslX509Request
- Defined in:
- lib/chef/mixin/openssl_helper.rb
Overview
various helpers for use with openssl. Currently used by the openssl_* resources
Class Method Summary collapse
Instance Method Summary collapse
-
#crl_file_valid?(crl_file) ⇒ Boolean
given a crl file path see if it’s actually a crl.
-
#dhparam_pem_valid?(dhparam_pem_path) ⇒ Boolean
validate a dhparam file from path.
-
#encrypt_ec_key(ec_key, key_password, key_cipher) ⇒ String
generate a pem file given a cipher, key, an optional key_password.
-
#encrypt_rsa_key(rsa_key, key_password, key_cipher) ⇒ String
generate a pem file given a cipher, key, an optional key_password.
-
#gen_dhparam(key_length, generator) ⇒ OpenSSL::PKey::DH
generate a dhparam file.
-
#gen_ec_priv_key(curve) ⇒ OpenSSL::PKey::DH
generate an ec private key given curve type.
-
#gen_ec_pub_key(priv_key, priv_key_password = nil) ⇒ String
generate pem format of the public key given a private key.
-
#gen_rsa_priv_key(key_length) ⇒ OpenSSL::PKey::DH
generate an RSA private key given key length.
-
#gen_rsa_pub_key(priv_key, priv_key_password = nil) ⇒ String
generate pem format of the public key given a private key.
-
#gen_serial ⇒ Integer
generate a random Serial.
-
#gen_x509_cert(request, extension, info, key) ⇒ OpenSSL::X509::Certificate
generate a Certificate given a X509 request.
-
#gen_x509_crl(ca_private_key, info) ⇒ OpenSSL::X509::CRL
generate a X509 CRL given a CA.
-
#gen_x509_extensions(extensions) ⇒ Array
generate an array of X509 Extensions given a hash of extensions.
-
#gen_x509_request(subject, key) ⇒ OpenSSL::X509::Request
generate a csr pem file given a subject and a private key.
-
#get_key_filename(cert_filename) ⇒ String
determine the key filename from the cert filename.
-
#get_next_crl_number(crl) ⇒ Integer
generate the next CRL number available for a X509 CRL given.
-
#key_length_valid?(number) ⇒ Boolean
is the key length a valid key length.
-
#priv_key_file_valid?(key_file, key_password = nil) ⇒ Boolean
given either a key file path or key file content see if it’s actually a private key.
-
#renew_x509_crl(crl, ca_private_key, info) ⇒ OpenSSL::X509::CRL
renew a X509 crl given.
-
#revoke_x509_crl(revoke_info, crl, ca_private_key, info) ⇒ OpenSSL::X509::CRL
add a serial given in the crl given.
-
#serial_revoked?(crl, serial) ⇒ true, false
check is a serial given is revoked in a crl given.
Class Method Details
.included(_base) ⇒ Object
22 23 24 |
# File 'lib/chef/mixin/openssl_helper.rb', line 22 def self.included(_base) require "openssl" unless defined?(::OpenSSL) end |
Instance Method Details
#crl_file_valid?(crl_file) ⇒ Boolean
given a crl file path see if it’s actually a crl
80 81 82 83 84 85 86 87 |
# File 'lib/chef/mixin/openssl_helper.rb', line 80 def crl_file_valid?(crl_file) begin ::OpenSSL::X509::CRL.new ::File.read(crl_file) rescue ::OpenSSL::X509::CRLError, Errno::ENOENT return false end true end |
#dhparam_pem_valid?(dhparam_pem_path) ⇒ Boolean
validate a dhparam file from path
45 46 47 48 49 50 51 52 |
# File 'lib/chef/mixin/openssl_helper.rb', line 45 def dhparam_pem_valid?(dhparam_pem_path) # Check if the dhparam.pem file exists # Verify the dhparam.pem file contains a key return false unless ::File.exist?(dhparam_pem_path) dhparam = ::OpenSSL::PKey::DH.new File.read(dhparam_pem_path) dhparam.params_ok? end |
#encrypt_ec_key(ec_key, key_password, key_cipher) ⇒ String
generate a pem file given a cipher, key, an optional key_password
195 196 197 198 199 200 201 202 203 |
# File 'lib/chef/mixin/openssl_helper.rb', line 195 def encrypt_ec_key(ec_key, key_password, key_cipher) raise TypeError, "ec_key must be a Ruby OpenSSL::PKey::EC object" unless ec_key.is_a?(::OpenSSL::PKey::EC) raise TypeError, "key_password must be a string" unless key_password.is_a?(String) raise TypeError, "key_cipher must be a string" unless key_cipher.is_a?(String) raise ArgumentError, "Specified key_cipher is not available on this system" unless ::OpenSSL::Cipher.ciphers.include?(key_cipher) cipher = ::OpenSSL::Cipher.new(key_cipher) ec_key.to_pem(cipher, key_password) end |
#encrypt_rsa_key(rsa_key, key_password, key_cipher) ⇒ String
generate a pem file given a cipher, key, an optional key_password
146 147 148 149 150 151 152 153 154 |
# File 'lib/chef/mixin/openssl_helper.rb', line 146 def encrypt_rsa_key(rsa_key, key_password, key_cipher) raise TypeError, "rsa_key must be a Ruby OpenSSL::PKey::RSA object" unless rsa_key.is_a?(::OpenSSL::PKey::RSA) raise TypeError, "key_password must be a string" unless key_password.is_a?(String) raise TypeError, "key_cipher must be a string" unless key_cipher.is_a?(String) raise ArgumentError, "Specified key_cipher is not available on this system" unless ::OpenSSL::Cipher.ciphers.include?(key_cipher) cipher = ::OpenSSL::Cipher.new(key_cipher) rsa_key.to_pem(cipher, key_password) end |
#gen_dhparam(key_length, generator) ⇒ OpenSSL::PKey::DH
generate a dhparam file
113 114 115 116 117 118 |
# File 'lib/chef/mixin/openssl_helper.rb', line 113 def gen_dhparam(key_length, generator) raise ArgumentError, "Key length must be a power of 2 greater than or equal to 1024" unless key_length_valid?(key_length) raise TypeError, "Generator must be an integer" unless generator.is_a?(Integer) ::OpenSSL::PKey::DH.new(key_length, generator) end |
#gen_ec_priv_key(curve) ⇒ OpenSSL::PKey::DH
generate an ec private key given curve type
159 160 161 162 163 164 |
# File 'lib/chef/mixin/openssl_helper.rb', line 159 def gen_ec_priv_key(curve) raise TypeError, "curve must be a string" unless curve.is_a?(String) raise ArgumentError, "Specified curve is not available on this system" unless curve == "prime256v1" || curve == "secp384r1" || curve == "secp521r1" ::OpenSSL::PKey::EC.new(curve).generate_key end |
#gen_ec_pub_key(priv_key, priv_key_password = nil) ⇒ String
generate pem format of the public key given a private key
170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 |
# File 'lib/chef/mixin/openssl_helper.rb', line 170 def gen_ec_pub_key(priv_key, priv_key_password = nil) # if the file exists try to read the content # if not assume we were passed the key and set the string to the content key_content = ::File.exist?(priv_key) ? File.read(priv_key) : priv_key key = ::OpenSSL::PKey::EC.new key_content, priv_key_password # Get curve type (prime256v1...) group = ::OpenSSL::PKey::EC::Group.new(key.group.curve_name) # Get Generator point & public point (priv * generator) generator = group.generator pub_point = generator.mul(key.private_key) key.public_key = pub_point # Public Key in pem public_key = ::OpenSSL::PKey::EC.new public_key.group = group public_key.public_key = pub_point public_key.to_pem end |
#gen_rsa_priv_key(key_length) ⇒ OpenSSL::PKey::DH
generate an RSA private key given key length
123 124 125 126 127 |
# File 'lib/chef/mixin/openssl_helper.rb', line 123 def gen_rsa_priv_key(key_length) raise ArgumentError, "Key length must be a power of 2 greater than or equal to 1024" unless key_length_valid?(key_length) ::OpenSSL::PKey::RSA.new(key_length) end |
#gen_rsa_pub_key(priv_key, priv_key_password = nil) ⇒ String
generate pem format of the public key given a private key
133 134 135 136 137 138 139 |
# File 'lib/chef/mixin/openssl_helper.rb', line 133 def gen_rsa_pub_key(priv_key, priv_key_password = nil) # if the file exists try to read the content # if not assume we were passed the key and set the string to the content key_content = ::File.exist?(priv_key) ? File.read(priv_key) : priv_key key = ::OpenSSL::PKey::RSA.new key_content, priv_key_password key.public_key.to_pem end |
#gen_serial ⇒ Integer
generate a random Serial
245 246 247 |
# File 'lib/chef/mixin/openssl_helper.rb', line 245 def gen_serial ::OpenSSL::BN.generate_prime(160) end |
#gen_x509_cert(request, extension, info, key) ⇒ OpenSSL::X509::Certificate
generate a Certificate given a X509 request
255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 |
# File 'lib/chef/mixin/openssl_helper.rb', line 255 def gen_x509_cert(request, extension, info, key) raise TypeError, "request must be a Ruby OpenSSL::X509::Request" unless request.is_a?(::OpenSSL::X509::Request) raise TypeError, "extension must be a Ruby Array" unless extension.is_a?(Array) raise TypeError, "info must be a Ruby Hash" unless info.is_a?(Hash) raise TypeError, "key must be a Ruby OpenSSL::PKey::EC object or a Ruby OpenSSL::PKey::RSA object" unless key.is_a?(::OpenSSL::PKey::EC) || key.is_a?(::OpenSSL::PKey::RSA) raise ArgumentError, "info must contain a validity" unless info.key?("validity") raise TypeError, "info['validity'] must be a Ruby Integer object" unless info["validity"].is_a?(Integer) cert = ::OpenSSL::X509::Certificate.new ef = ::OpenSSL::X509::ExtensionFactory.new cert.serial = gen_serial cert.version = 2 cert.subject = request.subject cert.public_key = request.public_key cert.not_before = Time.now cert.not_after = cert.not_before + info["validity"] * 24 * 60 * 60 if info["issuer"].nil? cert.issuer = request.subject ef.issuer_certificate = cert extension << ef.create_extension("basicConstraints", "CA:TRUE", true) else raise TypeError, "info['issuer'] must be a Ruby OpenSSL::X509::Certificate object" unless info["issuer"].is_a?(::OpenSSL::X509::Certificate) cert.issuer = info["issuer"].subject ef.issuer_certificate = info["issuer"] end ef.subject_certificate = cert ef.config = ::OpenSSL::Config.load(::OpenSSL::Config::DEFAULT_CONFIG_FILE) cert.extensions = extension cert.add_extension ef.create_extension("subjectKeyIdentifier", "hash") cert.add_extension ef.create_extension("authorityKeyIdentifier", "keyid:always,issuer:always") cert.sign(key, ::OpenSSL::Digest::SHA256.new) cert end |
#gen_x509_crl(ca_private_key, info) ⇒ OpenSSL::X509::CRL
generate a X509 CRL given a CA
300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 |
# File 'lib/chef/mixin/openssl_helper.rb', line 300 def gen_x509_crl(ca_private_key, info) raise TypeError, "ca_private_key must be a Ruby OpenSSL::PKey::EC object or a Ruby OpenSSL::PKey::RSA object" unless ca_private_key.is_a?(::OpenSSL::PKey::EC) || ca_private_key.is_a?(::OpenSSL::PKey::RSA) raise TypeError, "info must be a Ruby Hash" unless info.is_a?(Hash) raise ArgumentError, "info must contain a issuer and a validity" unless info.key?("issuer") && info.key?("validity") raise TypeError, "info['issuer'] must be a Ruby OpenSSL::X509::Certificate object" unless info["issuer"].is_a?(::OpenSSL::X509::Certificate) raise TypeError, "info['validity'] must be a Ruby Integer object" unless info["validity"].is_a?(Integer) crl = ::OpenSSL::X509::CRL.new ef = ::OpenSSL::X509::ExtensionFactory.new crl.version = 1 crl.issuer = info["issuer"].subject crl.last_update = Time.now crl.next_update = Time.now + 3600 * 24 * info["validity"] ef.config = ::OpenSSL::Config.load(::OpenSSL::Config::DEFAULT_CONFIG_FILE) ef.issuer_certificate = info["issuer"] crl.add_extension ::OpenSSL::X509::Extension.new("crlNumber", ::OpenSSL::ASN1::Integer(1)) crl.add_extension ef.create_extension("authorityKeyIdentifier", "keyid:always,issuer:always") crl.sign(ca_private_key, ::OpenSSL::Digest::SHA256.new) crl end |
#gen_x509_extensions(extensions) ⇒ Array
generate an array of X509 Extensions given a hash of extensions
228 229 230 231 232 233 234 235 236 237 238 239 240 241 |
# File 'lib/chef/mixin/openssl_helper.rb', line 228 def gen_x509_extensions(extensions) raise TypeError, "extensions must be a Ruby Hash object" unless extensions.is_a?(Hash) exts = [] extensions.each do |ext_name, ext_prop| raise TypeError, "#{ext_name} must contain a Ruby Hash" unless ext_prop.is_a?(Hash) raise ArgumentError, "keys in #{ext_name} must be 'values' and 'critical'" unless ext_prop.key?("values") && ext_prop.key?("critical") raise TypeError, "the key 'values' must contain a Ruby Arrays" unless ext_prop["values"].is_a?(Array) raise TypeError, "the key 'critical' must be a Ruby Boolean true/false" unless ext_prop["critical"].is_a?(TrueClass) || ext_prop["critical"].is_a?(FalseClass) exts << ::OpenSSL::X509::ExtensionFactory.new.create_extension(ext_name, ext_prop["values"].join(","), ext_prop["critical"]) end exts end |
#gen_x509_request(subject, key) ⇒ OpenSSL::X509::Request
generate a csr pem file given a subject and a private key
209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 |
# File 'lib/chef/mixin/openssl_helper.rb', line 209 def gen_x509_request(subject, key) raise TypeError, "subject must be a Ruby OpenSSL::X509::Name object" unless subject.is_a?(::OpenSSL::X509::Name) raise TypeError, "key must be a Ruby OpenSSL::PKey::EC or a Ruby OpenSSL::PKey::RSA object" unless key.is_a?(::OpenSSL::PKey::EC) || key.is_a?(::OpenSSL::PKey::RSA) request = ::OpenSSL::X509::Request.new request.version = 0 request.subject = subject request.public_key = key # Chef 12 backward compatibility ::OpenSSL::PKey::EC.send(:alias_method, :private?, :private_key?) request.sign(key, ::OpenSSL::Digest::SHA256.new) request end |
#get_key_filename(cert_filename) ⇒ String
determine the key filename from the cert filename
29 30 31 32 33 |
# File 'lib/chef/mixin/openssl_helper.rb', line 29 def get_key_filename(cert_filename) cert_file_path, cert_filename = ::File.split(cert_filename) cert_filename = ::File.basename(cert_filename, ::File.extname(cert_filename)) cert_file_path + ::File::SEPARATOR + cert_filename + ".key" end |
#get_next_crl_number(crl) ⇒ Integer
generate the next CRL number available for a X509 CRL given
329 330 331 332 333 334 335 336 337 |
# File 'lib/chef/mixin/openssl_helper.rb', line 329 def get_next_crl_number(crl) raise TypeError, "crl must be a Ruby OpenSSL::X509::CRL object" unless crl.is_a?(::OpenSSL::X509::CRL) crlnum = 1 crl.extensions.each do |e| crlnum = e.value if e.oid == "crlNumber" end crlnum.to_i + 1 end |
#key_length_valid?(number) ⇒ Boolean
is the key length a valid key length
38 39 40 |
# File 'lib/chef/mixin/openssl_helper.rb', line 38 def key_length_valid?(number) number >= 1024 && ( number & (number - 1) == 0 ) end |
#priv_key_file_valid?(key_file, key_password = nil) ⇒ Boolean
given either a key file path or key file content see if it’s actually a private key
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
# File 'lib/chef/mixin/openssl_helper.rb', line 59 def priv_key_file_valid?(key_file, key_password = nil) # if the file exists try to read the content # if not assume we were passed the key and set the string to the content key_content = ::File.exist?(key_file) ? File.read(key_file) : key_file begin key = ::OpenSSL::PKey.read key_content, key_password rescue ::OpenSSL::PKey::PKeyError, ArgumentError return false end if key.is_a?(::OpenSSL::PKey::EC) key.private_key? else key.private? end end |
#renew_x509_crl(crl, ca_private_key, info) ⇒ OpenSSL::X509::CRL
renew a X509 crl given
381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 |
# File 'lib/chef/mixin/openssl_helper.rb', line 381 def renew_x509_crl(crl, ca_private_key, info) raise TypeError, "crl must be a Ruby OpenSSL::X509::CRL object" unless crl.is_a?(::OpenSSL::X509::CRL) raise TypeError, "ca_private_key must be a Ruby OpenSSL::PKey::EC object or a Ruby OpenSSL::PKey::RSA object" unless ca_private_key.is_a?(::OpenSSL::PKey::EC) || ca_private_key.is_a?(::OpenSSL::PKey::RSA) raise TypeError, "info must be a Ruby Hash" unless info.is_a?(Hash) raise ArgumentError, "info must contain a issuer and a validity" unless info.key?("issuer") && info.key?("validity") raise TypeError, "info['issuer'] must be a Ruby OpenSSL::X509::Certificate object" unless info["issuer"].is_a?(::OpenSSL::X509::Certificate) raise TypeError, "info['validity'] must be a Ruby Integer object" unless info["validity"].is_a?(Integer) crl.last_update = Time.now crl.next_update = crl.last_update + 3600 * 24 * info["validity"] ef = ::OpenSSL::X509::ExtensionFactory.new ef.config = ::OpenSSL::Config.load(::OpenSSL::Config::DEFAULT_CONFIG_FILE) ef.issuer_certificate = info["issuer"] crl.extensions = [ ::OpenSSL::X509::Extension.new("crlNumber", ::OpenSSL::ASN1::Integer(get_next_crl_number(crl)))] crl.add_extension ef.create_extension("authorityKeyIdentifier", "keyid:always,issuer:always") crl.sign(ca_private_key, ::OpenSSL::Digest::SHA256.new) crl end |
#revoke_x509_crl(revoke_info, crl, ca_private_key, info) ⇒ OpenSSL::X509::CRL
add a serial given in the crl given
345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 |
# File 'lib/chef/mixin/openssl_helper.rb', line 345 def revoke_x509_crl(revoke_info, crl, ca_private_key, info) raise TypeError, "revoke_info must be a Ruby Hash oject" unless revoke_info.is_a?(Hash) raise TypeError, "crl must be a Ruby OpenSSL::X509::CRL object" unless crl.is_a?(::OpenSSL::X509::CRL) raise TypeError, "ca_private_key must be a Ruby OpenSSL::PKey::EC object or a Ruby OpenSSL::PKey::RSA object" unless ca_private_key.is_a?(::OpenSSL::PKey::EC) || ca_private_key.is_a?(::OpenSSL::PKey::RSA) raise TypeError, "info must be a Ruby Hash" unless info.is_a?(Hash) raise ArgumentError, "revoke_info must contain a serial and a reason" unless revoke_info.key?("serial") && revoke_info.key?("reason") raise TypeError, "revoke_info['serial'] must be a Ruby String or Integer object" unless revoke_info["serial"].is_a?(String) || revoke_info["serial"].is_a?(Integer) raise TypeError, "revoke_info['reason'] must be a Ruby Integer object" unless revoke_info["reason"].is_a?(Integer) raise ArgumentError, "info must contain a issuer and a validity" unless info.key?("issuer") && info.key?("validity") raise TypeError, "info['issuer'] must be a Ruby OpenSSL::X509::Certificate object" unless info["issuer"].is_a?(::OpenSSL::X509::Certificate) raise TypeError, "info['validity'] must be a Ruby Integer object" unless info["validity"].is_a?(Integer) revoked = ::OpenSSL::X509::Revoked.new revoked.serial = if revoke_info["serial"].is_a?(String) revoke_info["serial"].to_i(16) else revoke_info["serial"] end revoked.time = Time.now ext = ::OpenSSL::X509::Extension.new("CRLReason", ::OpenSSL::ASN1::Enumerated(revoke_info["reason"])) revoked.add_extension(ext) crl.add_revoked(revoked) crl = renew_x509_crl(crl, ca_private_key, info) crl end |
#serial_revoked?(crl, serial) ⇒ true, false
check is a serial given is revoked in a crl given
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
# File 'lib/chef/mixin/openssl_helper.rb', line 93 def serial_revoked?(crl, serial) raise TypeError, "crl must be a Ruby OpenSSL::X509::CRL object" unless crl.is_a?(::OpenSSL::X509::CRL) raise TypeError, "serial must be a Ruby String or Integer object" unless serial.is_a?(String) || serial.is_a?(Integer) serial_to_verify = if serial.is_a?(String) serial.to_i(16) else serial end status = false crl.revoked.each do |revoked| status = true if revoked.serial == serial_to_verify end status end |