Plasma GitLab Archive
Projects Blog Knowledge

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

This web site is published by Informatikbüro Gerd Stolpmann
Powered by Caml