# `PdfElixide.Signature.Timestamp`
[🔗](https://github.com/r8/pdf_elixide/blob/v0.16.0/lib/pdf_elixide/signature/timestamp.ex#L1)

An RFC 3161 timestamp token: a time-stamping authority's assertion that some
bytes existed when it saw them.

`PdfElixide.Signature.timestamp/1` reaches the one a signature carries, and
`parse/1` takes a token from anywhere else. A signature's own `:signing_time`
is the signer's unverifiable claim; a timestamp is a third party's, and
`verify/1` is what checks the authority actually made it — while
`PdfElixide.Signature.verify_timestamp/2` checks that it was made over the
signature carrying it, which is a separate question with a separate answer:

    {:ok, [signature]} = PdfElixide.Signature.list(doc)
    {:ok, timestamp} = PdfElixide.Signature.timestamp(signature)
    PdfElixide.Signature.Timestamp.verify(timestamp)
    #=> {:ok, :valid}

The "Timestamps ask three separate questions" section of the
[Signatures](guides/signatures.md) guide sets out which call answers which.

## What a verdict proves

`verify/1` checks one thing: that the token carries an authentic signature
from the certificate embedded in it, over the time and imprint it states. Four
things it does not establish:

  * **That the timestamp covers anything in particular.** `:message_imprint`
    is a digest of whatever was timestamped, and it is compared here to
    nothing at all: until it is matched against something, a `:valid` timestamp
    is a valid timestamp over unknown bytes.
    `PdfElixide.Signature.verify_timestamp/2` performs that match for a token
    reached from a signature.
  * **That the authority is who the token says.** No certificate is chained to
    a root, checked against a revocation list, or compared to any list of
    trusted authorities. `:tsa_name` is the token's own claim and is not
    checked against the certificate that signed it.
  * **That the stated time is right.** A timestamp authority that signs a time
    of its choosing produces a token that verifies.
  * **That the certificate was valid then.** Its validity window is compared to
    nothing, so an expired or not-yet-valid certificate verifies exactly like a
    current one.

## Tokens that cannot be verified

A token comes in two shapes, and `parse/1` reads both: a full CMS-wrapped
`TimeStampToken`, and a bare `TSTInfo`. Only the first carries an authority's
signature, so `verify/1` reports `%PdfElixide.Error{reason: :invalid_pdf}` for
a bare one rather than a verdict — there is nothing there to check. The same
reason covers a token whose authority signed with an algorithm this library
cannot verify, which is why the answer is `:valid` or `:invalid` and never the
third state `PdfElixide.Signature.verify/2` reports.

A timestamp is a plain value with no handle behind it, so it survives
`PdfElixide.Document.close/1` and can be passed between processes freely.

# `hash_algorithm`

```elixir
@type hash_algorithm() :: :sha1 | :sha256 | :sha384 | :sha512 | :unknown
```

The digest algorithm the timestamped imprint was made with.

`:unknown` is an algorithm identifier this library does not recognize, which
leaves `:message_imprint` uninterpretable rather than wrong.

# `t`

```elixir
@type t() :: %PdfElixide.Signature.Timestamp{
  hash_algorithm: hash_algorithm(),
  message_imprint: binary(),
  policy_oid: String.t(),
  serial: String.t(),
  time: DateTime.t(),
  token: binary(),
  tsa_name: String.t() | nil
}
```

One parsed timestamp token.

  * `:token` — the DER the timestamp was parsed from, with any trailing
    padding removed. `verify/1` reads it, and it is what to hand to another
    decoder or to whatever embeds it; nothing here writes one back into a
    document.
  * `:time` — the time the authority says it issued the token. Unlike
    `PdfElixide.Signature`'s `:signing_time`, which is a raw PDF date string,
    this is a `DateTime` in UTC: a timestamp's generation time is a parsed
    value where a signature's `/M` is a string the document supplied.
    Resolution is one second.
  * `:serial` — the authority's serial number for this token, as uppercase
    hexadecimal with no `0x` prefix and no fixed width.
  * `:policy_oid` — the timestamping policy the token was issued under, in
    dotted-decimal form.
  * `:tsa_name` — the name the authority gave itself in the token. A
    distinguished name for the usual directory-name form, otherwise the raw
    URI, DNS or email value. `nil` covers two cases that cannot be told apart
    here: a token naming no authority at all, and one naming it in a form this
    library does not render — an `otherName`, an `ediPartyName`, an IP address
    or a registered identifier. Reaching the certificate that actually signed
    the token is possible only for a document timestamp, whose blob *is* the
    token: `PdfElixide.Signature.certificate/1` returns it for an `:rfc3161`
    signature, and for one carried in a signature's unsigned attributes
    returns that signature's signer instead.
  * `:hash_algorithm`, `:message_imprint` — the digest that was timestamped and
    the algorithm that produced it. `verify/1` does not compare it to content;
    see "What a verdict proves".

# `verdict`

```elixir
@type verdict() :: :valid | :invalid
```

What a `verify/1` call concluded. "What a verdict proves" in the module
documentation says what `:valid` does and does not establish.

# `parse`

```elixir
@spec parse(binary()) :: {:ok, t()} | {:error, PdfElixide.Error.t()}
```

Parses a DER-encoded RFC 3161 timestamp token.

Reads both a full CMS-wrapped `TimeStampToken` and a bare `TSTInfo`, and
tolerates the zero padding a token stored in a PDF carries — so the
`:contents` of an `:rfc3161` signature can be passed straight in, though
`PdfElixide.Signature.timestamp/1` is the shorter way to the same place.

    {:ok, timestamp} = PdfElixide.Signature.Timestamp.parse(der)
    timestamp.time
    #=> ~U[2026-08-23 07:50:03Z]

Reports `%PdfElixide.Error{reason: :invalid_pdf}` when the bytes are neither
shape, carry trailing bytes other than zero padding, or state a generation
time no date can represent.

# `parse!`

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

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

# `verify`

```elixir
@spec verify(t()) :: {:ok, verdict()} | {:error, PdfElixide.Error.t()}
```

Verifies the timestamp authority's signature over the token.

`{:ok, :valid}` means the token is authentically the authority's and has not
been altered since. It says nothing about *what* was timestamped: see "What a
verdict proves" in the module documentation, which is also where the trust,
time and certificate-validity limits are.

    PdfElixide.Signature.Timestamp.verify(timestamp)
    #=> {:ok, :valid}

Reports `%PdfElixide.Error{reason: :invalid_pdf}` rather than a verdict when
the token is a bare `TSTInfo` and so carries no signature to check, and when
the authority signed it with an algorithm this library cannot verify.

# `verify!`

```elixir
@spec verify!(t()) :: verdict()
```

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

---

*Consult [api-reference.md](api-reference.md) for complete listing*
