# `Cmsex.SignerInfo`
[🔗](https://github.com/openspb/cmsex/blob/v0.1.0/lib/cmsex/signer_info.ex#L1)

One signer of a SignedData message, as `Cmsex.decode/2` reads it
(RFC 5652, 5.3). Reading checks the structure only; `Cmsex.verify/2`
checks the signature.

Fields:

  * `:version` - 1 with an issuer and serial number, 3 with a subject key
    identifier.
  * `:sid` - which certificate signed: `{:issuer_and_serial, issuer,
    serial}`, with the issuer as the DER of its Name as received, or
    `{:subject_key_identifier, ski}`.
  * `:digest_algorithm` - the name of the digest algorithm in
    `Cmsex.OID`, such as `:sha256`, or its OID.
  * `:signature_algorithm` - the name of the signature algorithm, such as
    `:rsa_encryption`, `:sha256_with_rsa_encryption`, `:rsassa_pss`,
    `:ecdsa_with_sha256` or `:ed25519`, or its OID.
  * `:signature_parameters` - for `:rsassa_pss`, a map with `:hash`,
    `:mgf_hash`, `:salt_length` and `:trailer_field`, the defaults filled
    in; `nil` otherwise.
  * `:signed_attributes` - a list of `Cmsex.Attribute`, in the order of
    the message, or `nil` when the signer has none.
  * `:unsigned_attributes` - a list of `Cmsex.Attribute`, empty when there
    are none. These are not covered by the signature: anyone can add,
    remove or change them.
  * `:signature` - the signature value. It is also what a signature
    time-stamp (RFC 3161, appendix A) and a countersignature cover.
  * `:deviations` - what the library tolerated when reading, against
    RFC 5652:
    * `:signer_info_version` - the version does not match the signer
      identifier;
    * `:signed_attributes_not_der` - the signed attributes are not in
      DER; the signature is checked over the bytes as received;
    * `:signing_time_encoding` - a signing time from 1950 to 2049 written
      as GeneralizedTime.

# `pss_parameters`

```elixir
@type pss_parameters() :: %{
  hash: atom(),
  mgf_hash: atom(),
  salt_length: non_neg_integer(),
  trailer_field: pos_integer()
}
```

The parameters of RSASSA-PSS (RFC 4055, 3.1), with the defaults filled in.

# `sid`

```elixir
@type sid() ::
  {:issuer_and_serial, binary(), integer()}
  | {:subject_key_identifier, binary()}
```

# `t`

```elixir
@type t() :: %Cmsex.SignerInfo{
  deviations: [atom()],
  digest_algorithm: atom() | tuple(),
  raw: map() | nil,
  sid: sid(),
  signature: binary(),
  signature_algorithm: atom() | tuple(),
  signature_parameters: pss_parameters() | nil,
  signed_attributes: [Cmsex.Attribute.t()] | nil,
  unsigned_attributes: [Cmsex.Attribute.t()],
  version: integer()
}
```

# `attribute`

```elixir
@spec attribute(t(), atom() | tuple()) :: Cmsex.Attribute.t() | nil
```

The first signed attribute of a type, a name of `Cmsex.OID` or an OID, or
`nil`.

# `content_type`

```elixir
@spec content_type(t()) :: {:ok, atom() | tuple()} | :error
```

The content-type attribute: the type of the signed content, as a name of
`Cmsex.OID` or an OID. `:error` when it is missing, repeated, or not a
single OID.

# `countersignatures`

```elixir
@spec countersignatures(t(), keyword()) :: {:ok, [t()]} | {:error, Cmsex.Error.t()}
```

The countersignatures of this signer (RFC 5652, 11.4): each a SignerInfo
over the signature of this one. They are read, not verified; see the
`:countersignatures` option of `Cmsex.verify/2`. Takes the limits of
`Cmsex.decode/2`.

# `message_digest`

```elixir
@spec message_digest(t()) :: {:ok, binary()} | :error
```

The message-digest attribute: the digest of the content. `:error` when it
is missing, repeated, or not a single OCTET STRING.

# `signature`

```elixir
@spec signature(t()) :: binary()
```

The signature value of the signer. It is what a signature time-stamp
covers (RFC 3161, appendix A): the time-stamp request hashes these
bytes, and the token goes back in an unsigned attribute with
`Cmsex.add_unsigned_attribute/4`. A countersignature covers it too
(RFC 5652, 11.4).

# `signing_time`

```elixir
@spec signing_time(t()) :: {:ok, DateTime.t()} | :error
```

The signing-time attribute. It is what the signer claims, not a fact
anyone checked. `:error` when it is missing, repeated or malformed.

# `unsigned_attribute`

```elixir
@spec unsigned_attribute(t(), atom() | tuple()) :: Cmsex.Attribute.t() | nil
```

The first unsigned attribute of a type, such as `:time_stamp_token`, or
`nil`. Unsigned attributes are not covered by the signature.

---

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