Class: SSLTool::Certificate
- Inherits:
-
OpenSSL::X509::Certificate
- Object
- OpenSSL::X509::Certificate
- SSLTool::Certificate
- Defined in:
- lib/ssltool/certificate.rb
Defined Under Namespace
Modules: Extensions
Constant Summary collapse
- RX_DOMAIN_NAME =
/^(\*\.)?([a-zA-Z0-9-]+\.)+[a-zA-Z0-9]+$/- @@certificate_cache =
The certificate_cache stuff ensures we always get the same object every time we instantiate the same certificate. This is regardless of differences in the string used to instantiate the object. The weakrefs ensure we don’t hold on to certs that are not being used outside of the cache.
{}
Class Method Summary collapse
- .new(s) ⇒ Object
-
.scan(s) ⇒ Object
returns an array of Certificate objects created from cert strings found in s.
Instance Method Summary collapse
- #acceptable? ⇒ Boolean
- #authority_key_identifier ⇒ Object
- #certificate_authority? ⇒ Boolean
- #certificate_sign? ⇒ Boolean
-
#chain_from(certs) ⇒ Object
chain.
- #common_names ⇒ Object
- #domain_names ⇒ Object
- #domain_names_from_common_names ⇒ Object
- #domain_names_from_subject_alt_names ⇒ Object
- #extensions ⇒ Object
-
#fingerprint ⇒ Object
properties.
- #for_domain_name? ⇒ Boolean
- #key_size ⇒ Object
- #key_size_secure? ⇒ Boolean
- #map_extension_value(extension_name, default = nil) ⇒ Object
- #parent?(other_cert) ⇒ Boolean
- #self_issued? ⇒ Boolean
- #self_signed? ⇒ Boolean
-
#signed_by?(other_cert) ⇒ Boolean
signing.
- #signs?(other_cert) ⇒ Boolean
- #subject_key_identifier ⇒ Object
- #valid? ⇒ Boolean
Class Method Details
.new(s) ⇒ Object
16 17 18 19 20 21 |
# File 'lib/ssltool/certificate.rb', line 16 def self.new(s) cert = super(s) k = cert.fingerprint @@certificate_cache.delete(k) if v = @@certificate_cache[k] and v.respond_to?(:weakref_alive?) && !v.weakref_alive? (@@certificate_cache[k] ||= WeakRef.new(cert)).__getobj__ end |
.scan(s) ⇒ Object
returns an array of Certificate objects created from cert strings found in s
24 25 26 |
# File 'lib/ssltool/certificate.rb', line 24 def self.scan(s) PEMScanner.certs_from(s).uniq end |
Instance Method Details
#acceptable? ⇒ Boolean
122 123 124 |
# File 'lib/ssltool/certificate.rb', line 122 def acceptable? valid? && (!key_size || key_size_secure?) end |
#authority_key_identifier ⇒ Object
97 98 99 |
# File 'lib/ssltool/certificate.rb', line 97 def map_extension_value('authorityKeyIdentifier') { |s| s.sub(/^keyid:/, '').chomp } end |
#certificate_authority? ⇒ Boolean
85 86 87 |
# File 'lib/ssltool/certificate.rb', line 85 def map_extension_value('basicConstraints') { |s| s.split(", ").include?('CA:TRUE') } end |
#certificate_sign? ⇒ Boolean
89 90 91 |
# File 'lib/ssltool/certificate.rb', line 89 def certificate_sign? map_extension_value('keyUsage') { |s| s.split(", ").include?('Certificate Sign') } end |
#chain_from(certs) ⇒ Object
chain
147 148 149 150 151 152 |
# File 'lib/ssltool/certificate.rb', line 147 def chain_from(certs) chain = [self] parent = (certs - chain).find { |cert| cert.parent?(self) } chain.concat(parent.chain_from(certs - chain)) if parent chain end |
#common_names ⇒ Object
63 64 65 |
# File 'lib/ssltool/certificate.rb', line 63 def common_names subject.to_a.select { |k, _, _| k == "CN" }.map { |_, v, _| v } end |
#domain_names ⇒ Object
75 76 77 78 79 |
# File 'lib/ssltool/certificate.rb', line 75 def domain_names [ domain_names_from_common_names, domain_names_from_subject_alt_names, ].flatten.compact.sort.uniq end |
#domain_names_from_common_names ⇒ Object
67 68 69 |
# File 'lib/ssltool/certificate.rb', line 67 def domain_names_from_common_names common_names.select { |cn| cn =~ RX_DOMAIN_NAME } end |
#domain_names_from_subject_alt_names ⇒ Object
71 72 73 |
# File 'lib/ssltool/certificate.rb', line 71 def domain_names_from_subject_alt_names map_extension_value('subjectAltName') { |s| s.scan(/\bDNS:([^\s,]+)/) } end |
#extensions ⇒ Object
135 136 137 |
# File 'lib/ssltool/certificate.rb', line 135 def extensions super.tap { |a| class << a; include Extensions; end } end |
#fingerprint ⇒ Object
properties
59 60 61 |
# File 'lib/ssltool/certificate.rb', line 59 def fingerprint @fingerprint ||= Digest::SHA1.hexdigest(to_der) end |
#for_domain_name? ⇒ Boolean
81 82 83 |
# File 'lib/ssltool/certificate.rb', line 81 def for_domain_name? !domain_names.empty? end |
#key_size ⇒ Object
101 102 103 104 105 106 107 |
# File 'lib/ssltool/certificate.rb', line 101 def key_size case public_key when OpenSSL::PKey::RSA ; public_key.n.num_bits when OpenSSL::PKey::EC ; public_key.group.order.num_bits else ; nil end end |
#key_size_secure? ⇒ Boolean
109 110 111 112 113 114 115 |
# File 'lib/ssltool/certificate.rb', line 109 def key_size_secure? case public_key when OpenSSL::PKey::RSA ; key_size >= 2048 when OpenSSL::PKey::EC ; key_size >= 224 else ; nil end end |
#map_extension_value(extension_name, default = nil) ⇒ Object
139 140 141 142 143 |
# File 'lib/ssltool/certificate.rb', line 139 def map_extension_value(extension_name, default = nil) e = extensions[extension_name] return default if e.nil? block_given? ? yield(e.value) : e.value end |
#parent?(other_cert) ⇒ Boolean
51 52 53 54 55 |
# File 'lib/ssltool/certificate.rb', line 51 def parent?(other_cert) signs?(other_cert) \ && subject == other_cert.issuer \ && subject_key_identifier == other_cert. end |
#self_issued? ⇒ Boolean
47 48 49 |
# File 'lib/ssltool/certificate.rb', line 47 def self_issued? subject.eql?(issuer) end |
#self_signed? ⇒ Boolean
43 44 45 |
# File 'lib/ssltool/certificate.rb', line 43 def self_signed? signs?(self) end |
#signed_by?(other_cert) ⇒ Boolean
signing
30 31 32 33 34 35 36 37 |
# File 'lib/ssltool/certificate.rb', line 30 def signed_by?(other_cert) verify(other_cert.public_key) rescue OpenSSL::X509::CertificateError => e OpenSSL.errors # clear error queue to prevent pg errors return false if e. == "wrong public key type" # self.signature_algorithm is incompatible with type of other_cert.public_key; verify is definitely false return nil if e. == "unknown message digest algorithm" && signature_algorithm =~ /^md2/ # md2 is not present in later versions of openssl; can't tell signature verifies, so returning nil raise e end |
#signs?(other_cert) ⇒ Boolean
39 40 41 |
# File 'lib/ssltool/certificate.rb', line 39 def signs?(other_cert) other_cert.signed_by?(self) end |
#subject_key_identifier ⇒ Object
93 94 95 |
# File 'lib/ssltool/certificate.rb', line 93 def subject_key_identifier map_extension_value('subjectKeyIdentifier') { |s| s.chomp } end |
#valid? ⇒ Boolean
117 118 119 120 |
# File 'lib/ssltool/certificate.rb', line 117 def valid? now = Time.now.utc now <= not_after && now >= not_before end |