# Module Netx509

    module Netx509: sig .. end

X.509 certificates

This module defines a parser for X.509 certificates in Internet context (RFC 5280). The basic structure is implemented, and there are also parsers for the most needed extensions.

There are several involved formats:

- `ASN.1` is the language in which the certificate format is described. When we refer here to ASN.1 we mean tagged values as defined by `Netasn1.Value.value`.
- `DER` is the common binary encoding for ASN.1 values in this context. `DER` is a subset of `BER` (which is implemented by `Netasn1.decode_ber`). The encoding of ASN.1 values in `BER` is ambiguous, and `DER` specifies the variant to use in order to get a "distinguished" encoding (that's what the "D" stands for), which is needed to get unique digital signatures.
- `PEM` is a set of standards for "privacy enhanced mail". The "PEM encoding" of certificates is simply BASE-64 of `DER`.

    type oid = Netoid.t

OIDs are just integer sequences

    class type directory_name = object .. end

Directory names are also known as distinguished names.

    class type x509_certificate = object .. end

An X.509 certificate in decoded form.

### OIDs for DN attribute types

    module DN_attributes: sig .. end

### Distinguished names

    module X509_DN_string: Netdn.DN_string

Parser/printer for distnguished names as they may occur in X.509 certificates

    val lookup_dn_ava : directory_name -> oid -> Netasn1.Value.value

Find the first relative DN setting this OID (or `Not_found`)

    val lookup_dn_ava_utf8 : directory_name -> oid -> string

Same as `lookup_dn_ava`, but additionally converts the value to UTF-8

### Parsers

    class x509_dn_from_ASN1 : Netasn1.Value.value -> directory_name

Returns the DN object for a `Name` entity

    class x509_dn_from_string : string -> directory_name

Returns the DN object for an RFC 4514-encoded string

    class x509_certificate_from_ASN1 : Netasn1.Value.value -> x509_certificate

Parses the passed ASN.1 value and returns the certificate object

    class x509_certificate_from_DER : string -> x509_certificate

Parses the passed DER string and returns the certificate object

### Extensions

Extensions are identified by an OID (found in the following `CE` module), and the value is a DER-encoded ASN.1 value. The parse_* functions take this DER-encoded value and decode them. E.g. get the "authority key identifier":

      let _, aki_der, _ =
        List.find
          (fun (oid,_,_) -> oid = CE.ce_authority_key_identifier)
          cert#extensions in
      let aki =
        parse_authority_key_identifier aki_der

Or use `find_extension`, as defined below.

Note that we don't have parsers for all extensions.

    module CE: sig .. end

    exception Extension_not_found of oid

    val find_extension : oid -> (oid * string * bool) list -> string * bool

`find_extension` is designed to be applied to the result of the `extensions` method of `Netx509.x509_certificate`:

      let (data, critical) =
        find_extension CE.ce:authority_key_identifier cert#extensions

It returns the undecoded data string, and the critical flag.

Raises `Extension_not_found` if there is no such extension.

    val check_critical_exts : oid list -> (oid * string * bool) list -> bool

`check_critical_exts list exts`: When an extension is flagged as critical, it must be processed by the communication endpoint. If there is a critical extension that cannot be processed, this is an error. This function checks whether there are any critical extensions in `exts` beyond those in `list`, and returns `true` in this case.

Use this in software as:

      let unprocessed_critical =
        check_critical_exts
           [ CE.ce_basic_constraints ]
           cert#extensions

and pass the list of all extension OIDs you actually process. You should raise an error if `unprocessed_critical` is true.

    type general_name = [ `DNS_name of string
           | `Directory_name of directory_name
           | `Edi_party_name of string option * string
           | `IP_address of Unix.socket_domain * Unix.inet_addr * Unix.inet_addr
           | `Other_name of oid * Netasn1.Value.value
           | `Registered_ID of oid
           | `Rfc822_name of string
           | `Uniform_resource_identifier of string
           | `X400_address of Netasn1.Value.value ]

General names:

- ``Other_name(oid, value)`: the `oid` determines the extension name format
- ``Rfc822_name n`: an email address `n` (ASCII encoded)
- ``DNS_name n`: an Internet domain `n` (ASCII encoded - no internationalization)
- ``X400_address v`: an X.400 address, which is not decoded here and just given as unparsed ASN.1 value `v`
- ``Directory_name n`: a directory name `n` (i.e. a name using the syntax of distinguished names)
- ``Edi_party_name(assigner,party)`, both names as UTF-8
- ``Uniform_resource_identifier uri`: this `uri` (ASCII-encoded, no internationalization)
- ``IP_address(dom,addr,mask)`: the address with mask
- ``Registered oid`: a symbolical pre-registered name known under `oid`

    type authority_key_identifier = {

`` | `aki_key_identifier : `string option`;`
`` | `aki_authority_cert_issuer : `general_name list`;`
`` | `aki_authority_cert_serial_number : `string option`;`

}

    val parse_authority_key_identifier : string -> authority_key_identifier

    val parse_subject_key_identifier : string -> string

Returns the key identifier directly

    type key_usage_flag = [ `Crl_sign
           | `Data_encipherment
           | `Decipher_only
           | `Digital_signature
           | `Encipher_only
           | `Key_agreement
           | `Key_cert_sign
           | `Key_encipherment
           | `Non_repudiation ]

    val parse_key_usage : string -> key_usage_flag list

    val parse_subject_alt_name : string -> general_name list

    val parse_issuer_alt_name : string -> general_name list

    val parse_subject_directory_attributes : string -> (oid * Netasn1.Value.value list) list

    val parse_basic_constraints : string -> bool * int option

    type ext_key_usage_flag = [ `Client_auth
           | `Code_signing
           | `Email_protection
           | `OCSP_signing
           | `Server_auth
           | `Time_stamping
           | `Unknown ]

    val parse_ext_key_usage : string -> (oid * ext_key_usage_flag) list

Returns the OID as array, and as decoded flag

    module KP: sig .. end

Key purpose IDs as returned by `parse_ext_key_usage`

    type authority_access_description_flag = [ `CA_issuers | `OCSP | `Unknown ]

    type subject_access_description_flag = [ `CA_repository | `Time_stamping | `Unknown ]

    type access_description_flag = [ `CA_issuers | `CA_repository | `OCSP | `Time_stamping | `Unknown ]

    val parse_authority_info_access : string ->
           (oid * authority_access_description_flag *
            general_name)
           list

    val parse_subject_info_access : string ->
           (oid * subject_access_description_flag * general_name)
           list

    module AD: sig .. end

Generic parsers

    val general_name_from_ASN1 : Netasn1.Value.value -> general_name

Parses the general_name structure

    val general_names_from_ASN1 : Netasn1.Value.value -> general_name list

Parse a sequence of general names

    val directory_string_from_ASN1 : Netasn1.Value.value -> string

Returns the directory_string as UTF-8

    val attribute_from_ASN1 : Netasn1.Value.value -> oid * Netasn1.Value.value list

Parses an attribute

    val attributes_from_ASN1 : Netasn1.Value.value -> (oid * Netasn1.Value.value list) list

Parses a sequence of attributes