X509CERT(3) Library Functions Manual X509CERT(3)

x509cert_encode, x509cert_sign, x509cert_encode_req, x509cert_encode_cert, x509cert_encode_dn
construct and sign X.509 certificates and certificate requests

x509cert_dn_string_rdn_len, x509cert_parse_dn_string

parse RFC 4514 DistinguishedName string representation

#include <x509cert.h>

size_t
x509cert_encode(const struct x509cert_item *, unsigned char *);

size_t
x509cert_sign(const struct x509cert_item *, const struct x509cert_skey *, const br_hash_class *, unsigned char *);

size_t
x509cert_encode_req(const struct x509cert_req *, unsigned char *);

x509cert_encoder x509cert_req_encoder;

size_t
x509cert_encode_cert(const struct x509cert_cert *, unsigned char *);

x509cert_encoder x509cert_cert_encoder;

size_t
x509cert_encode_dn(const struct x509cert_dn *, unsigned char *);

x509cert_encoder x509cert_dn_encoder;

size_t
x509cert_dn_string_rdn_len(const char *);

int
x509cert_parse_dn_string(struct x509cert_rdn *, char *);

Most functions in libx509cert follow a similar pattern. They take a pointer to a buffer in which to encode some ASN.1 structure, and return the encoded length, or 0 if it cannot be encoded. In order to determine an appropriate size for this buffer, the function should first be called with NULL to compute the encoded size, and then again with an allocated buffer of at least this size. This pattern is captured with the x509cert_encoder function typedef.

A general ASN.1 item is represented with struct x509cert_item, which has the following members:

tag
The item tag.
len
The length of the item contents in bytes.
val
The item contents.
enc
An optional custom encoder for the item.

The x509cert_encode() function encodes an ASN.1 item into a buffer. If enc is NULL, the default encoder is used, which encodes tag and len, then copies len bytes from val into the buffer. If tag is 0, val is assumed to be pre-encoded, and no tag-length header is added. Otherwise, the enc function is called with the item as its argument, which encodes the item some other way. In this case, val might point to some structure, with tag and len unused.

The x509cert_sign() function DER-encodes a ASN.1 item along with its signature as an X.509 SIGNED{...} structure into a buffer, returning its length. If the buffer is NULL, no encoding or signing takes place. Instead, the maximum length of the encoded item is returned. The actual length may be several bytes smaller. The signature algorithm used is determined by the type of the private key and the hash algorithm. Supported key types are BR_KEYTYPE_RSA (up to 4096 bit) and BR_KEYTYPE_EC (secp256r1, secp384r1, secp521r1).

A certificate request is described by struct x509cert_req, which has the following members:

subject
The subject of the requested certificate. Must encode as an X.501 DistinguishedName.
pkey
The public key of the requested certificate. This must match the key passed to x509cert_sign().
alts
An array of alternate names to add in a subjectAltName extension.
alts_len
The length of the alts array.

The x509cert_encode_req() function DER-encodes a PKCS#10 CertificateRequestInfo into a buffer. If alts_len is positive, an extension request is added for subjectAltName containing the alternate names given in alts. Each one must have a one of the following tags and correseponding value type:

SEQUENCE { OID, ANY }
IA5String
IA5String
IA5String
OCTET STRING

A certificate is described by struct x509cert_cert, which has the following members:

req
An inner struct x509cert_req is used for its subject, pkey, alts, and alts_len members, which have the same semantics as they do for x509cert_encode_req() except that pkey needn't match the signing key.
serial
The serial number of the certificate, in big-endian format. Must be unique for each certificate issued by a given CA.
key_type
The type of the CA's signing key. This must match the key passed to x509cert_sign().
hash_id
The ID of the hash used for signing the certificate. This must match the hash passed to x509cert_sign().
issuer
The name of the certificate issuer. Must encode as an X.501 DistinguishedName.
notbefore
The Unix time at which the certificate becomes valid.
notafter
The Unix time after which the certificate is no longer valid.
ca
Indicates whether or not the subject is a certificate authority.

The x509cert_encode_cert() function DER-encodes an X.509 TBSCertificate into a buffer. If ca is non-zero, a basicConstraints extension is added with the cA field set to TRUE, indicating that the subject is a certificate authority.

A distinguished name is represented with struct x509cert_dn, which has the following members:

rdn
An array of relative distinguished names, starting with the most significant.
rdn_len
The length of the rdn array.

Each RDN has type struct x509cert_rdn, which has the following members:

oid
A pre-encoded OID indicating the attribute type.
val
The attribute value, which must be a PrintableString or UTF8String.

The x509cert_encode_dn() function DER-encodes an X.501 DistinguishedName into a buffer. RDNs with multiple attributes are not supported.

The x509cert_dn_string_rdn_len() function determines the number of RDNs represented in a RFC 4514 DN string.

The x509cert_parse_dn_string() function parses the RFC 4514 DN string representation (for example, C=US,CN=example.com) into an array of RDNs. Multi-valued RDNs are not supported. The array must be large enough for all RDNs, the number of which can be determined with x509cert_dn_string_rdn_len(). The string buffer is rewritten in-place with RDN values and encoded OIDs.

The following attribute names are supported:

CN
commonName (OID 2.5.4.3)
L
localityName (OID 2.5.4.7)
ST
stateOrProvinceName (OID 2.5.4.8)
O
organizationName (OID 2.5.4.10)
OU
organizationalUnitName (OID 2.5.4.11)
C
countryName (OID 2.5.4.6)
STREET
streetAddress (OID 2.5.4.9)
DC
domainComponent (OID 0.9.2342.19200300.100.1.25)
UID
userId (OID 0.9.2342.19200300.100.1.1)

The OIDs for these attributes are also available for explicit struct x509cert_dn construction as x509cert_oid_*.

The x509cert_encode(), x509cert_encode_req(), x509cert_encode_cert(), and x509cert_encode_dn() functions return the encoded length of the ASN.1 item, or 0 if the item cannot be encoded.

The x509cert_sign() function returns the maximum encoded length of the ASN.1 SIGNED{...} structure if the buffer is NULL, and the actual encoded length otherwise. If the item cannot be encoded, or there is an error computing the signature, 0 is returned.

The x509cert_dn_string_rdn_len() function returns the number of RDNs described in the string.

The x509cert_parse_dn_string() function returns 1 on success, or 0 if the string is invalid or the buffer is not large enough.

Creating a self-signed certificate for example.com:
#include <stdlib.h>
#include <x509cert.h>

br_x509_certificate
selfsigned(const struct x509cert_skey *skey, const br_x509_pkey *pkey)
{
	struct x509cert_dn dn = {
		.rdn = &(struct x509cert_rdn){
			.oid = x509cert_oid_CN,
			.val.tag = X509CERT_ASN1_UTF8STRING,
			.val.len = 11,
			.val.val = "example.com",
		},
		.rdn_len = 1,
	};
	struct x509cert_cert cert = {
		.req = &(struct x509cert_req){
			.subject = {.enc = x509cert_dn_encoder, .val = &dn},
			.pkey = *pkey,
		},
		.key_type = skey->type,
		.hash_id = br_sha256_ID,
		.issuer = {.enc = x509cert_dn_encoder, .val = &dn}
	};
	struct x509cert_item cert_item = {
		.enc = x509cert_cert_encoder,
		.val = &cert,
	};
	size_t len;
	unsigned char *buf;

	cert.notbefore = time(NULL);
	cert.notafter = cert.notbefore + 2592000;

	/* calculate maximum length */
	len = x509cert_sign(&cert_item, skey, &br_sha256_vtable, NULL);
	if (len == 0 || !(buf = malloc(len)))
		return (br_x509_certificate){0};
	len = x509cert_sign(&cert_item, skey, &br_sha256_vtable, buf);
	if (len == 0) {
		free(buf);
		return (br_x509_certificate){0};
	}

	return (br_x509_certificate){.data = buf, .data_len = len};
}

x509cert(1)
May 6, 2021 Linux 5.11.4+