package x509

  1. Overview
  2. Docs

X.509 Certificate Chain Validation.

A chain of pairwise signed X.509 certificates is sent to the endpoint, which use these to authenticate the other endpoint. Usually a set of trust anchors is configured on the endpoint, and the chain needs to be rooted in one of the trust anchors. In reality, chains may be incomplete or reversed, and there can be multiple paths from the leaf certificate to a trust anchor.

RFC 5280 specifies a path validation algorithm for authenticating chains, but this does not handle multiple possible paths. RFC 4158 describes possible path building strategies.

This module provides path building, chain of trust verification, trust anchor (certificate authority) validation, and validation via a fingerprint list (for a trust on first use implementation).

Certificate Authorities

type ca_error = [
  1. | `CAIssuerSubjectMismatch of t
  2. | `CAInvalidVersion of t
  3. | `CAInvalidSelfSignature of t
  4. | `CACertificateExpired of t * Ptime.t option
  5. | `CAInvalidExtensions of t
]

The polymorphic variant of possible certificate authorities failures.

val ca_error_of_sexp : Sexplib.Sexp.t -> ca_error

ca_error_of_sexp sexp is ca_error, the unmarshalled sexp.

val sexp_of_ca_error : ca_error -> Sexplib.Sexp.t

sexp_of_ca_error ca_error is sexp, the marshalled ca_error.

val ca_error_to_string : ca_error -> string

ca_error_to_string validation_error is string, the string representation of the ca_error.

val valid_ca : ?time:Ptime.t -> t -> [ `Ok | `Error of ca_error ]

valid_ca ~time certificate is result, which is `Ok if the given certificate is self-signed, it is valid at time, its extensions are not present (if X.509 version 1 certificate), or are appropriate for a CA (BasicConstraints is present and true, KeyUsage extension contains keyCertSign).

val valid_cas : ?time:Ptime.t -> t list -> t list

valid_cas ~time certificates is valid_certificates, only those certificates which pass the valid_ca check.

Chain of trust verification

type leaf_validation_error = [
  1. | `LeafCertificateExpired of t * Ptime.t option
  2. | `LeafInvalidName of t * host option
  3. | `LeafInvalidVersion of t
  4. | `LeafInvalidExtensions of t
]

The polymorphic variant of a leaf certificate validation error.

type chain_validation_error = [
  1. | `IntermediateInvalidExtensions of t
  2. | `IntermediateCertificateExpired of t * Ptime.t option
  3. | `IntermediateInvalidVersion of t
  4. | `ChainIssuerSubjectMismatch of t * t
  5. | `ChainAuthorityKeyIdSubjectKeyIdMismatch of t * t
  6. | `ChainInvalidSignature of t * t
  7. | `ChainInvalidPathlen of t * int
  8. | `EmptyCertificateChain
  9. | `NoTrustAnchor of t
  10. | `Revoked of t
]

The polymorphic variant of a chain validation error.

val build_paths : t -> t list -> t list list

build_paths server rest is paths, which are all possible certificate paths starting with server. These chains (C1..Cn) fulfill the predicate that each certificate Cn is issued by the next one in the chain (C(n+1)): the issuer of Cn matches the subject of C(n+1). This is as described in RFC 4158.

type chain_error = [
  1. | `Leaf of leaf_validation_error
  2. | `Chain of chain_validation_error
]

The polymorphic variant of a chain validation error: either the leaf certificate is problematic, or the chain itself.

val chain_error_of_sexp : Sexplib.Sexp.t -> chain_error

chain_error_of_sexp sexp is chain_error, the unmarshalled sexp.

val sexp_of_chain_error : chain_error -> Sexplib.Sexp.t

sexp_of_chain_error chain_error is sexp, the marshalled chain_error.

val chain_error_to_string : chain_error -> string

chain_error_to_string validation_error is string, the string representation of the chain_error.

val verify_chain : ?host:host -> ?time:Ptime.t -> ?revoked:(issuer:t -> cert:t -> bool) -> anchors:t list -> t list -> [ `Ok of t | `Fail of chain_error ]

verify_chain ~host ~time ~revoked ~anchors chain is result, either Ok and the trust anchor used to verify the chain, or Fail and the chain error. RFC 5280 describes the implemented path validation algorithm: The validity period of the given certificates is checked against the time. The X509v3 extensions of the chain are checked, then a chain of trust from anchors to the server certificate is validated. The path length constraints are checked. The server certificate is checked to contain the given host, using hostnames. The returned certificate is the root of the chain, a member of the given list of anchors.

type fingerprint_validation_error = [
  1. | `ServerNameNotPresent of t * string
  2. | `NameNotInList of t
  3. | `InvalidFingerprint of t * Cstruct.t * Cstruct.t
]

The polymorphic variant of a fingerprint validation error.

type validation_error = [
  1. | `EmptyCertificateChain
  2. | `InvalidChain
  3. | `Leaf of leaf_validation_error
  4. | `Fingerprint of fingerprint_validation_error
]

The polymorphic variant of validation errors.

val validation_error_of_sexp : Sexplib.Sexp.t -> validation_error

validation_error_of_sexp sexp is validation_error, the unmarshalled sexp.

val sexp_of_validation_error : validation_error -> Sexplib.Sexp.t

sexp_of_validation_error validation_error is sexp, the marshalled validation_error.

val validation_error_to_string : validation_error -> string

validation_error_to_string validation_error is string, the string representation of the validation_error.

type result = [
  1. | `Ok of (t list * t) option
  2. | `Fail of validation_error
]

The result of a validation: either success (optionally returning the used trust anchor), or failure

val verify_chain_of_trust : ?host:host -> ?time:Ptime.t -> ?revoked:(issuer:t -> cert:t -> bool) -> anchors:t list -> t list -> result

verify_chain_of_trust ~host ~time ~revoked ~anchors certificates is result. First, all possible paths are constructed using the build_paths function, the first certificate of the chain is verified to be a valid leaf certificate (no BasicConstraints extension) and contains the given host (using hostnames); if some path is valid, using verify_chain, the result will be Ok and contain the actual certificate chain and the trust anchor.

Fingerprint verification

val trust_key_fingerprint : ?host:host -> ?time:Ptime.t -> hash:Nocrypto.Hash.hash -> fingerprints:(string * Cstruct.t) list -> t list -> result

trust_key_fingerprint ~time ~hash ~fingerprints certificates is result, the first element of certificates is verified against the given fingerprints map (hostname to public key fingerprint) using key_fingerprint. The certificate has to be valid in the given time. If a host is provided, the certificate is checked for this name. The `Wildcard hostname of the fingerprint list must match the name in the certificate, using hostnames.

val trust_cert_fingerprint : ?host:host -> ?time:Ptime.t -> hash:Nocrypto.Hash.hash -> fingerprints:(string * Cstruct.t) list -> t list -> result

trust_cert_fingerprint ~time ~hash ~fingerprints certificates is result, the first element of certificates is verified to match the given fingerprints map (hostname to fingerprint) using fingerprint. The certificate has to be valid in the given time. If a host is provided, the certificate is checked for this name. The `Wildcard hostname of the fingerprint list must match the name in the certificate, using hostnames.