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