PdfElixide.Signature.Certificate (pdf_elixide v0.15.0)

Copy Markdown View Source

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 reads DER from another source:

{: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

Types

t()

One parsed X.509 certificate.

Functions

Parses a DER-encoded X.509 certificate.

Same as parse/1, but raises PdfElixide.Error on failure.

Whether the certificate's validity window covers instant.

Types

t()

@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_key or another certificate library.
  • :subject — who the certificate is about, in RFC 4514 form. nil for 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 is nil.
  • :issuer — who issued it, in RFC 4514 form. nil only 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 a 0x prefix or fixed width. Any sign octet is preserved. This matches PdfElixide.Signature.Timestamp's :serial.
  • :not_before, :not_after — the window the issuer vouched for, as DateTimes in UTC with one-second resolution. valid_at?/2 compares an instant against them.

Functions

parse(der)

@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.

parse!(der)

@spec parse!(binary()) :: t()

Same as parse/1, but raises PdfElixide.Error on failure.

valid_at?(certificate, instant)

@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())
#=> true

For 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.