Module: CsrPeek::Inspectable

Included in:
Certificate, Csr
Defined in:
lib/csr_peek/inspectable.rb

Overview

The reading surface shared by the Csr and Certificate value objects.

Both are immutable Data structs built from the same precomputed members (subject, subject_alt_names, key_type, key_bits, ec_curve, public_key, openssl). This module turns those flat members into the friendly questions callers ask. Because the members are already resolved and frozen, nothing here re-touches the raise-prone key-loading path.

It is prepended (not included) into each Data class so that its value semantics - #==, #hash, #inspect keyed on the canonical DER - override the defaults Data generates, which would otherwise compare the live OpenSSL handles and dump their bytes.

Constant Summary collapse

MIN_RSA_BITS =

Cryptographic strength floors (independent of any issuance policy).

2048
MIN_EC_BITS =
256
MIN_DSA_BITS =
2048
STRONG_UNSIZED_TYPES =

Edwards signature schemes: strong regardless of RSA-style bit size.

%w[ED25519 ED448].freeze

Instance Method Summary collapse

Instance Method Details

#==(other) ⇒ Object Also known as: eql?

Value semantics keyed on the canonical DER, not the live OpenSSL handle, so two parses of the same bytes are equal and usable as hash keys.



98
99
100
# File 'lib/csr_peek/inspectable.rb', line 98

def ==(other)
  other.is_a?(self.class) && der_identity == other.send(:der_identity)
end

#acceptable_key?(policy = Policy::BASELINE) ⇒ Boolean

True when the key satisfies the issuance policy (Baseline Requirements by default). See CsrPeek::Policy.

Returns:

  • (Boolean)


61
62
63
# File 'lib/csr_peek/inspectable.rb', line 61

def acceptable_key?(policy = Policy::BASELINE)
  key_policy_violations(policy).empty?
end

#all_namesObject

DNS SANs when present, else the Common Name. De-duplicated, stable order.



41
42
43
44
45
# File 'lib/csr_peek/inspectable.rb', line 41

def all_names
  return dns_names.uniq unless dns_names.empty?

  common_name ? [common_name] : []
end

#common_nameObject



28
29
30
# File 'lib/csr_peek/inspectable.rb', line 28

def common_name
  subject["CN"]
end

#dns_namesObject



32
33
34
# File 'lib/csr_peek/inspectable.rb', line 32

def dns_names
  subject_alt_names[:dns]
end

#fingerprint(algo = :sha256) ⇒ Object

Hex fingerprint of the whole object (DER). nil if it cannot be encoded.



88
89
90
91
92
93
94
# File 'lib/csr_peek/inspectable.rb', line 88

def fingerprint(algo = :sha256)
  OpenSSL::Digest.hexdigest(digest_name(algo), openssl.to_der)
rescue OpenSSL::Digest::DigestError,
  OpenSSL::X509::RequestError,
  OpenSSL::X509::CertificateError
  nil
end

#hashObject



103
104
105
# File 'lib/csr_peek/inspectable.rb', line 103

def hash
  der_identity.hash
end

#inspectObject



107
108
109
# File 'lib/csr_peek/inspectable.rb', line 107

def inspect
  "#<#{self.class.name} cn=#{common_name.inspect} #{key_type} #{key_bits || "?"}-bit>"
end

#ip_addressesObject



36
37
38
# File 'lib/csr_peek/inspectable.rb', line 36

def ip_addresses
  subject_alt_names[:ip]
end

#key_policy_violations(policy = Policy::BASELINE) ⇒ Object

The policy reasons the key is unacceptable, as symbols (empty if fine).



66
67
68
69
70
71
72
73
# File 'lib/csr_peek/inspectable.rb', line 66

def key_policy_violations(policy = Policy::BASELINE)
  policy.key_violations(
    type: key_type,
    bits: key_bits,
    curve: ec_curve,
    spki_fingerprint: spki_fingerprint(:sha256)
  )
end

#spki_fingerprint(algo = :sha256) ⇒ Object

Hex fingerprint of the SubjectPublicKeyInfo DER - the stable identity of the key across every CSR and certificate that carries it. nil when the key could not be loaded.



78
79
80
81
82
83
84
85
# File 'lib/csr_peek/inspectable.rb', line 78

def spki_fingerprint(algo = :sha256)
  key = public_key
  return nil if key.nil?

  OpenSSL::Digest.hexdigest(digest_name(algo), key.public_to_der)
rescue OpenSSL::PKey::PKeyError, OpenSSL::Digest::DigestError
  nil
end

#weak_key?Boolean

Cryptographic strength only - see #acceptable_key? for policy. A key that failed to load ("unknown") is treated as weak: "cannot verify" is not safe.

Returns:

  • (Boolean)


49
50
51
52
53
54
55
56
57
# File 'lib/csr_peek/inspectable.rb', line 49

def weak_key?
  case key_type
  when "RSA" then key_bits.nil? || key_bits < MIN_RSA_BITS
  when "EC" then key_bits.nil? || key_bits < MIN_EC_BITS
  when "DSA" then key_bits.nil? || key_bits < MIN_DSA_BITS
  when *STRONG_UNSIZED_TYPES then false
  else true
  end
end