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
- #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) {|e.value| ... } ⇒ Object
- #self_issued? ⇒ Boolean
- #self_signed? ⇒ Boolean
-
#signed_by?(other_cert) ⇒ Boolean
signing.
- #signs?(other_cert) ⇒ Boolean
- #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
107 108 109 |
# File 'lib/ssltool/certificate.rb', line 107 def acceptable? valid? && (!key_size || key_size_secure?) end |
#certificate_authority? ⇒ Boolean
78 79 80 |
# File 'lib/ssltool/certificate.rb', line 78 def map_extension_value('basicConstraints') { |s| s.split(", ").include?('CA:TRUE') } end |
#certificate_sign? ⇒ Boolean
82 83 84 |
# File 'lib/ssltool/certificate.rb', line 82 def certificate_sign? map_extension_value('keyUsage') { |s| s.split(", ").include?('Certificate Sign') } end |
#chain_from(certs) ⇒ Object
chain
132 133 134 135 136 137 |
# File 'lib/ssltool/certificate.rb', line 132 def chain_from(certs) chain = [self] parent = (certs - chain).find { |cert| cert.signs?(self) } chain.concat(parent.chain_from(certs - chain)) if parent chain end |
#common_names ⇒ Object
56 57 58 |
# File 'lib/ssltool/certificate.rb', line 56 def common_names subject.to_a.select { |k, _, _| k == "CN" }.map { |_, v, _| v } end |
#domain_names ⇒ Object
68 69 70 71 72 |
# File 'lib/ssltool/certificate.rb', line 68 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
60 61 62 |
# File 'lib/ssltool/certificate.rb', line 60 def domain_names_from_common_names common_names.select { |cn| cn =~ RX_DOMAIN_NAME } end |
#domain_names_from_subject_alt_names ⇒ Object
64 65 66 |
# File 'lib/ssltool/certificate.rb', line 64 def domain_names_from_subject_alt_names map_extension_value('subjectAltName') { |s| s.scan(/\bDNS:([^\s,]+)/) } end |
#extensions ⇒ Object
120 121 122 |
# File 'lib/ssltool/certificate.rb', line 120 def extensions super.tap { |a| class << a; include Extensions; end } end |
#fingerprint ⇒ Object
properties
52 53 54 |
# File 'lib/ssltool/certificate.rb', line 52 def fingerprint @fingerprint ||= Digest::SHA1.hexdigest(to_der) end |
#for_domain_name? ⇒ Boolean
74 75 76 |
# File 'lib/ssltool/certificate.rb', line 74 def for_domain_name? !domain_names.empty? end |
#key_size ⇒ Object
86 87 88 89 90 91 92 |
# File 'lib/ssltool/certificate.rb', line 86 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
94 95 96 97 98 99 100 |
# File 'lib/ssltool/certificate.rb', line 94 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) {|e.value| ... } ⇒ Object
124 125 126 127 128 |
# File 'lib/ssltool/certificate.rb', line 124 def map_extension_value(extension_name, default = nil) e = extensions[extension_name] return default if e.nil? yield(e.value) end |
#self_issued? ⇒ Boolean
46 47 48 |
# File 'lib/ssltool/certificate.rb', line 46 def self_issued? subject.eql?(issuer) end |
#self_signed? ⇒ Boolean
42 43 44 |
# File 'lib/ssltool/certificate.rb', line 42 def self_signed? signs?(self) end |
#signed_by?(other_cert) ⇒ Boolean
signing
30 31 32 33 34 35 36 |
# File 'lib/ssltool/certificate.rb', line 30 def signed_by?(other_cert) verify(other_cert.public_key) rescue OpenSSL::X509::CertificateError => e 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
38 39 40 |
# File 'lib/ssltool/certificate.rb', line 38 def signs?(other_cert) other_cert.signed_by?(self) end |
#valid? ⇒ Boolean
102 103 104 105 |
# File 'lib/ssltool/certificate.rb', line 102 def valid? now = Time.now.utc now <= not_after && now >= not_before end |