An X.509 certificate: who a signature names as its signer, and the window the issuer vouched for that name.
PdfElixide.Signature.certificate/1 reads the one a signature carries.
parse/1, parse_pem/1 and parse_pkcs12/2 read certificates you hold
yourself, from DER, PEM or a .p12 / .pfx file:
{:ok, [signature]} = PdfElixide.Signature.list(doc)
{:ok, certificate} = PdfElixide.Signature.certificate(signature)
certificate.subject_common_name
#=> "pdf_elixide test signer"The "The signer's certificate" section of the Signatures guide puts this in sequence with the rest of a signature check.
Nothing here is a trust decision
The fields are claims read from the certificate. They are not checked against
a trusted root, a revocation source or a list of accepted signers. Use :der
with :public_key or another library to make those decisions.
Names
:subject and :issuer use RFC
4514 form, with the most
specific attribute first. Values that cannot be rendered as text appear as
oid=#hex rather than being dropped.
:subject_common_name is the unescaped common name nearest the leaf. It is
nil when the subject has no textual common name and may contain text that
the full :subject renders as hexadecimal.
A certificate is a plain value with no handle behind it, so it survives
PdfElixide.Document.close/1 and can be passed between processes freely.
Summary
Functions
Parses a DER-encoded X.509 certificate.
Same as parse/1, but raises PdfElixide.Error on failure.
Parses every certificate in PEM text, in file order.
Same as parse_pem/1, but raises PdfElixide.Error on failure.
Reads the certificates out of a PKCS#12 (.p12 / .pfx) file.
Same as parse_pkcs12/2, but raises PdfElixide.Error on failure.
Whether the certificate's validity window covers instant.
Types
@type t() :: %PdfElixide.Signature.Certificate{ der: binary(), issuer: String.t() | nil, not_after: DateTime.t(), not_before: DateTime.t(), serial: String.t(), subject: String.t() | nil, subject_common_name: String.t() | nil }
One parsed X.509 certificate.
:der— the certificate's DER without trailing padding, suitable for OTP's:public_keyor another certificate library.:subject— who the certificate is about, in RFC 4514 form.nilfor a certificate that names no subject at all, which is legal for one identified only by an extension.:subject_common_name— the common name nearest the leaf of:subject, unescaped. See "Names" in the module documentation for when it isnil.:issuer— who issued it, in RFC 4514 form.nilonly for a certificate that names no issuer, which is not a conforming one.:serial— the issuer's serial number as uppercase hexadecimal DER content bytes, without a0xprefix or fixed width. Any sign octet is preserved. This matchesPdfElixide.Signature.Timestamp's:serial.:not_before,:not_after— the window the issuer vouched for, asDateTimes in UTC with one-second resolution.valid_at?/2compares an instant against them.
Functions
@spec parse(binary()) :: {:ok, t()} | {:error, PdfElixide.Error.t()}
Parses a DER-encoded X.509 certificate.
Tolerates trailing zero padding, so a PdfElixide.Signature.DSS entry can be
passed straight in:
{:ok, dss} = PdfElixide.Signature.dss(doc)
[der | _] = dss.certificates
{:ok, certificate} = PdfElixide.Signature.Certificate.parse(der)
certificate.issuer
#=> "CN=pdf_elixide test signer,O=pdf_elixide,C=UA"Reports %PdfElixide.Error{reason: :invalid_pdf} for a malformed or
unsupported certificate, an unrepresentable validity date, or trailing bytes
other than zero padding. A second concatenated certificate is a trailing
value, not a chain, and is rejected.
Same as parse/1, but raises PdfElixide.Error on failure.
@spec parse_pem(binary()) :: {:ok, [t(), ...]} | {:error, PdfElixide.Error.t()}
Parses every certificate in PEM text, in file order.
Reads CERTIFICATE blocks, including the legacy X509 CERTIFICATE label.
Surrounding text and other blocks, including private keys, are ignored rather
than decoded.
{:ok, certificates} =
"fullchain.pem" |> File.read!() |> PdfElixide.Signature.Certificate.parse_pem()Reports %PdfElixide.Error{reason: :not_found} when the input holds no
certificate block, and :invalid_pdf when a block is malformed or does not
hold exactly one X.509 certificate. One bad block fails the whole call.
Same as parse_pem/1, but raises PdfElixide.Error on failure.
@spec parse_pkcs12(binary(), String.t()) :: {:ok, [t(), ...]} | {:error, PdfElixide.Error.t()}
Reads the certificates out of a PKCS#12 (.p12 / .pfx) file.
Returns every certificate in the file. When the file records which one belongs to its private key, that certificate and its available issuer chain come first; the rest keep their stored order. This ordering verifies nothing. The private key is neither decrypted nor returned.
{:ok, mine} =
"signer.p12"
|> File.read!()
|> PdfElixide.Signature.Certificate.parse_pkcs12("passphrase")password is text, as PKCS#12 defines it, so it must be valid UTF-8. Pass
"" for a file protected by an empty password.
Reports %PdfElixide.Error{reason: :wrong_password} when an integrity check
rejects the password. A file without one cannot reject a password; unreadable
encrypted certificate data instead reports :invalid_pdf. Malformed input
also reports :invalid_pdf, a file without certificates reports :not_found,
and an unsupported protection scheme reports :unsupported.
Same as parse_pkcs12/2, but raises PdfElixide.Error on failure.
@spec valid_at?(t(), DateTime.t()) :: boolean()
Whether the certificate's validity window covers instant.
Both ends are inclusive.
PdfElixide.Signature.Certificate.valid_at?(certificate, DateTime.utc_now())
#=> trueFor a signature, compare against its claimed signing time from
PdfElixide.Signature.signing_time_utc/1, or against the :time of a
PdfElixide.Signature.Timestamp whose attachment was confirmed by
PdfElixide.Signature.verify_timestamp/2 and whose authenticity was checked
by PdfElixide.Signature.Timestamp.verify/1. Only the latter is evidence
rather than the signer's claim, and it is still only as trustworthy as the
timestamp authority. A true result does not establish trust or rule out
revocation.