module

Krikri::X509CertInfo

Shared X.509 certificate parsing for the community.crypto info modules (x509_certificate_info, get_certificate). Both plugins need the same field set - subject/issuer dicts, validity, extensions, fingerprints, public key data - so it lives here once, driven by the openssl CLI (the same backend choice every other crypto plugin in this tree makes; there is no Python cryptography library to lean on on the target host).

Field vocabularies were matched against the real module (community.crypto 3.1.1, ansible-core 2.19.4), whose own output comes from Python's cryptography library mapped through OpenSSL's objects.txt long names - which is exactly the vocabulary openssl x509 -text itself prints, so most fields read straight off that output. The module sorts every list-valued extension it returns (key usage, extended key usage, basic constraints), which openssl does not do, so parsed entries are sorted here.

Deliberately not implemented (nothing in the role corpus reads them): extensions_by_oid (the DER-encoded value of every extension - needs an ASN.1 decoder this tree does not carry). The field is omitted from the result rather than emitted empty, and noted in KNOWN_MISSING.md.

Constants

FINGERPRINT_ALGORITHMS = {"md5" => "md5", "sha1" => "sha1", "sha224" => "sha224", "sha256" => "sha256", "sha384" => "sha384", "sha512" => "sha512", "sha3_224" => "sha3-224", "sha3_256" => "sha3-256", "sha3_384" => "sha3-384", "sha3_512" => "sha3-512", "blake2b" => "blake2b512", "blake2s" => "blake2s256"}

hashlib.algorithms_guaranteed minus the two SHAKE XOFs, which OpenSSL exposes only with a caller-chosen output length and Crystal's Digest does not surface - everything else is emitted under the real module's Python algorithm names.

Class methods

big_hex_to_decimal(hex : String) : String

Hex string -> decimal string, for values far wider than Int64 (an RSA modulus is 2048+ bits). Base-10 school multiplication over the hex nibbles - no BigInt shard in this tree.

Source
classify_public_key(text : String) : Tuple(String, Hash(String, JSON::Any))

Reads the same openssl -text shapes the real module's Python backend reads from cryptography objects: RSA gives size/modulus/ exponent, ECC gives curve/x/y/exponent_size, Ed25519/X25519 etc. give an empty public_data dict.

Source
der_bytes(args : Array(String)) : Bytes | Nil
Source
fingerprints(data : Bytes) : Hash(String, JSON::Any)
Source
fingerprints_any(data : Bytes) : JSON::Any
Source
json_int(decimal : String) : JSON::Any

A value that fits Int64 stays a JSON number (matching the real module's Python ints); anything wider - RSA moduli, ECC coordinates, big serial numbers - goes out as its decimal string, because this engine's result world is JSON::Any (Int64 at widest) and truncating digits would be worse than a string.

Source
labeled_hex_value(text : String, header : String) : JSON::Any | Nil

Public wrapper for the private-key modules: the decimal value of a labeled hex block ("prime1:", "priv:", ...) as a JSON int-or-string.

Source
parse(cert_pem : String, now : Time = Time.utc) : Hash(String, JSON::Any) | Nil

The main entry point: cert_pem is the PEM text of one certificate. Returns the module's result fields as a hash, or nil if openssl cannot parse it at all.

Source
parse_csr(csr_pem : String) : Hash(String, JSON::Any) | Nil

The openssl_csr_info half of the family: parses a PKCS#10 certificate request and returns the fields the real module (community.crypto 3.1.1, csr_info.py's get_info) returns that this openssl-CLI backend can produce: subject, subject_ordered, key_usage/extended_key_usage/basic_constraints/ocsp_must_staple/ subject_alt_name (each with its _critical flag, absent exactly when the extension is absent - matching the real backend's None), public_key, public_key_type, public_key_data, public_key_fingerprints, and signature_valid (openssl's own req -verify - the real module asks cryptography's is_signature_valid).

Same deliberate divergence as the certificate half above: extensions_by_oid, subject_key_identifier, authority_key_identifier and the name_constraints_* fields are not returned (they need an ASN.1 decoder this tree does not carry).

Source
run_openssl(args : Array(String)) : String | Nil
Source