# `Tspex.Error`
[🔗](https://github.com/openspb/tspex/blob/v0.1.0/lib/tspex/error.ex#L1)

Why a time-stamp request, response or token could not be built, read or
verified.

The functions of `Tspex` return it as `{:error, %Tspex.Error{}}`, and their
bang variants raise it. Match on `:reason`, a stable atom; `:detail` adds
what went wrong where that helps, and never holds the bytes of the data
that was time-stamped; `:cause` is the `Cmsex.Error` when the error came
from the CMS layer.

The message says what happened without showing the data:

    iex> error = %Tspex.Error{reason: :imprint_mismatch, detail: :digest}
    iex> Exception.message(error)
    "the message imprint does not match (:digest)"

Reading:

  * `:malformed` - not valid BER or DER, or not the structure that was
    expected, or a field out of range (an integer that is too large, an
    invalid `genTime` or `accuracy`).
  * `:limit_exceeded` - the input goes beyond a limit; `detail` is the
    option (`:max_size`, `:max_depth` or `:max_nodes`).
  * `:unsupported_version` - a version other than 1.
  * `:unknown_status` - a `PKIStatus` outside 0 to 5.
  * `:unknown_fail_info` - a granted response with a bit of `failInfo`
    that RFC 3161 does not define.

Responses:

  * `:rejection` - status 2; `detail` is `%{fail_info: [...], text: [...]}`.
  * `:waiting`, `:revocation_warning`, `:revocation_notification` - status
    3, 4 and 5.
  * `:granted_with_mods` - status 1 with `granted_with_mods: :reject`.
  * `:token_missing` - status 0 or 1 without a token.
  * `:unexpected_token` - a token with a status greater than 1.

Tokens:

  * `:not_a_time_stamp_token` - not a SignedData, or the content type is
    not `id-ct-TSTInfo`.
  * `:signer_count` - no signer, or more than one.
  * `:token_invalid` - the CMS layer refused the token; `detail` and
    `cause` say why (signature, attributes, certificate). A signature made
    with SHA-1 or MD5 is `:weak_algorithm`, not this.
  * `:signing_certificate_missing` - neither ESSCertID nor ESSCertIDv2.
  * `:bad_tsa_certificate` - the certificate is not one a TSA may use;
    `detail` is `:eku_missing`, `:eku_not_critical`, `:eku_extra_purposes`,
    `:eku_repeated`, `:key_usage` or `:not_valid_at_time`.
  * `:untrusted` - the certificate path did not validate; `detail` is the
    reason, such as `:not_valid_at_time`, `:eku_excludes_time_stamping`,
    `:key_usage_mismatch` or `{:revocation, reason}`.
  * `:imprint_mismatch` - `detail` is `:hash_algorithm`, `:digest` or
    `:length`.
  * `:nonce_missing`, `:nonce_mismatch` - the request had a nonce and the
    token has none, or another one.
  * `:policy_mismatch` - the policy is not the one requested, or is not in
    `:policies`.
  * `:tsa_name_mismatch` - the `tsa` field names none of the names of the
    certificate.
  * `:critical_extension` - an extension of the `TSTInfo` that is critical
    and unknown.
  * `:gen_time_skew` - `:max_skew` exceeded.
  * `:weak_algorithm` - MD5, or SHA-1 without `allow_sha1: true`, in the
    imprint or in the signature of the token (some TSAs sign with SHA-1:
    `detail` is `:sha1`, and `cause` is the error of the CMS layer).

Signature and content time-stamps:

  * `:cms_invalid` - the CMS message that carries the signature could not
    be read, or its signature did not verify; `detail` and `cause` (a
    `Cmsex.Error`) say why.
  * `:signer_not_found` - no signer, or no countersignature, at the
    position; `detail` is the position.
  * `:no_time_stamp` - the signer has no time-stamp.
  * `:unsupported_evidence` - a `TimeStampedData` with `ersEvidence` or
    `otherEvidence`.
  * `:content_missing`, `:unexpected_content` - a `TimeStampedData` that
    does not carry its content and none was given, or that carries it and
    one was given.
  * `:time_order` - a `TimeStampedData` with a token whose `genTime` is
    earlier than the one before it by more than `:max_time_back`; `detail`
    is the position of that token in the chain (the first is 0).

Transport:

  * `:transport` - `detail` is `{:http_status, n}`, `:timeout`,
    `:too_large`, `{:connect, reason}`, `{:tls, reason}` or `{:other,
    reason}`.

# `reason`

```elixir
@type reason() ::
  :malformed
  | :limit_exceeded
  | :unsupported_version
  | :unknown_status
  | :unknown_fail_info
  | :rejection
  | :waiting
  | :revocation_warning
  | :revocation_notification
  | :granted_with_mods
  | :token_missing
  | :unexpected_token
  | :not_a_time_stamp_token
  | :signer_count
  | :token_invalid
  | :signing_certificate_missing
  | :bad_tsa_certificate
  | :untrusted
  | :imprint_mismatch
  | :nonce_missing
  | :nonce_mismatch
  | :policy_mismatch
  | :tsa_name_mismatch
  | :critical_extension
  | :gen_time_skew
  | :weak_algorithm
  | :cms_invalid
  | :signer_not_found
  | :no_time_stamp
  | :unsupported_evidence
  | :content_missing
  | :unexpected_content
  | :time_order
  | :transport
```

Why an operation failed; each reason is described above.

# `t`

```elixir
@type t() :: %Tspex.Error{
  __exception__: true,
  cause: Exception.t() | nil,
  detail: term(),
  reason: reason()
}
```

The error: the `reason`, a `detail` that depends on it (or `nil`) and the
`cause`, the error of the layer below when there is one.

---

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