Class: Puppetserver::Ca::X509Loader
- Inherits:
-
Object
- Object
- Puppetserver::Ca::X509Loader
- Defined in:
- lib/puppetserver/ca/x509_loader.rb
Overview
Load, validate, and store x509 objects needed by the Puppet Server CA.
Instance Attribute Summary collapse
-
#certs ⇒ Object
readonly
Returns the value of attribute certs.
-
#crls ⇒ Object
readonly
Returns the value of attribute crls.
-
#errors ⇒ Object
readonly
Returns the value of attribute errors.
-
#key ⇒ Object
readonly
Returns the value of attribute key.
Instance Method Summary collapse
-
#initialize(bundle_path, key_path, chain_path) ⇒ X509Loader
constructor
A new instance of X509Loader.
- #load_certs(bundle_path) ⇒ Object
- #load_crls(chain_path) ⇒ Object
- #load_key(key_path) ⇒ Object
-
#validate(bundle, pkey, chain) ⇒ Object
Only do as much validation as is possible, assume whoever tried to load the objects wrote errors about any invalid ones, but that bundle and chain may be empty arrays and pkey may be nil.
- #validate_cert_and_key(key, cert) ⇒ Object
- #validate_crl_and_cert(crl, cert) ⇒ Object
-
#validate_full_chain(certs, crls) ⇒ Object
By creating an X509::Store and validating the leaf cert with it we: - Ensure a full chain of trust (root to leaf) is within the bundle - If provided, there are CRLs for the CAs - If provided, no CAs within the chain of trust have been revoked However this does allow for: - Additional, ignored, certs and CRLs in the bundle/chain - certs and CRLs in any order (as long as the leaf cert is first).
Constructor Details
#initialize(bundle_path, key_path, chain_path) ⇒ X509Loader
Returns a new instance of X509Loader.
10 11 12 13 14 15 16 17 18 |
# File 'lib/puppetserver/ca/x509_loader.rb', line 10 def initialize(bundle_path, key_path, chain_path) @errors = [] @certs = load_certs(bundle_path) @key = load_key(key_path) @crls = load_crls(chain_path) validate(@certs, @key, @crls) end |
Instance Attribute Details
#certs ⇒ Object (readonly)
Returns the value of attribute certs.
8 9 10 |
# File 'lib/puppetserver/ca/x509_loader.rb', line 8 def certs @certs end |
#crls ⇒ Object (readonly)
Returns the value of attribute crls.
8 9 10 |
# File 'lib/puppetserver/ca/x509_loader.rb', line 8 def crls @crls end |
#errors ⇒ Object (readonly)
Returns the value of attribute errors.
8 9 10 |
# File 'lib/puppetserver/ca/x509_loader.rb', line 8 def errors @errors end |
#key ⇒ Object (readonly)
Returns the value of attribute key.
8 9 10 |
# File 'lib/puppetserver/ca/x509_loader.rb', line 8 def key @key end |
Instance Method Details
#load_certs(bundle_path) ⇒ Object
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
# File 'lib/puppetserver/ca/x509_loader.rb', line 37 def load_certs(bundle_path) certs, errs = [], [] bundle_string = File.read(bundle_path) cert_strings = bundle_string.scan(/-----BEGIN CERTIFICATE-----.*?-----END CERTIFICATE-----/m) cert_strings.each do |cert_string| begin certs << OpenSSL::X509::Certificate.new(cert_string) rescue OpenSSL::X509::CertificateError errs << "Could not parse entry:\n#{cert_string}" end end if certs.empty? errs << "Could not detect any certs within #{bundle_path}" end unless errs.empty? @errors << "Could not parse #{bundle_path}" @errors += errs end return certs end |
#load_crls(chain_path) ⇒ Object
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
# File 'lib/puppetserver/ca/x509_loader.rb', line 72 def load_crls(chain_path) errs, crls = [], [] chain_string = File.read(chain_path) crl_strings = chain_string.scan(/-----BEGIN X509 CRL-----.*?-----END X509 CRL-----/m) crl_strings.map do |crl_string| begin crls << OpenSSL::X509::CRL.new(crl_string) rescue OpenSSL::X509::CRLError errs << "Could not parse entry:\n#{crl_string}" end end if crls.empty? errs << "Could not detect any crls within #{chain_path}" end unless errs.empty? @errors << "Could not parse #{chain_path}" @errors += errs end return crls end |
#load_key(key_path) ⇒ Object
62 63 64 65 66 67 68 69 70 |
# File 'lib/puppetserver/ca/x509_loader.rb', line 62 def load_key(key_path) begin OpenSSL::PKey.read(File.read(key_path)) rescue ArgumentError, OpenSSL::PKey::PKeyError => e @errors << "Could not parse #{key_path}" return nil end end |
#validate(bundle, pkey, chain) ⇒ Object
Only do as much validation as is possible, assume whoever tried to load the objects wrote errors about any invalid ones, but that bundle and chain may be empty arrays and pkey may be nil.
23 24 25 26 27 28 29 30 31 32 33 34 35 |
# File 'lib/puppetserver/ca/x509_loader.rb', line 23 def validate(bundle, pkey, chain) if !chain.empty? && !bundle.empty? validate_crl_and_cert(chain.first, bundle.first) end if pkey && !bundle.empty? validate_cert_and_key(pkey, bundle.first) end unless bundle.empty? validate_full_chain(bundle, chain) end end |
#validate_cert_and_key(key, cert) ⇒ Object
97 98 99 100 101 |
# File 'lib/puppetserver/ca/x509_loader.rb', line 97 def validate_cert_and_key(key, cert) unless cert.check_private_key(key) @errors << 'Private key and certificate do not match' end end |
#validate_crl_and_cert(crl, cert) ⇒ Object
103 104 105 106 107 |
# File 'lib/puppetserver/ca/x509_loader.rb', line 103 def validate_crl_and_cert(crl, cert) unless crl.issuer == cert.subject @errors << 'Leaf CRL was not issued by leaf certificate' end end |
#validate_full_chain(certs, crls) ⇒ Object
By creating an X509::Store and validating the leaf cert with it we:
- Ensure a full chain of trust (root to leaf) is within the bundle
- If provided, there are CRLs for the CAs
- If provided, no CAs within the chain of trust have been revoked
However this does allow for:
- Additional, ignored, certs and CRLs in the bundle/chain
- certs and CRLs in any order (as long as the leaf cert is first)
116 117 118 119 120 121 122 123 124 125 126 127 128 |
# File 'lib/puppetserver/ca/x509_loader.rb', line 116 def validate_full_chain(certs, crls) store = OpenSSL::X509::Store.new certs.each {|cert| store.add_cert(cert) } if !crls.empty? store.flags = OpenSSL::X509::V_FLAG_CRL_CHECK | OpenSSL::X509::V_FLAG_CRL_CHECK_ALL crls.each {|crl| store.add_crl(crl) } end unless store.verify(certs.first) @errors << 'Leaf certificate could not be validated' @errors << "Validating cert store returned: #{store.error} - #{store.error_string}" end end |