From: Thomas Pornin Date: Tue, 22 Nov 2016 01:41:34 +0000 (+0100) Subject: Some more Doxygen API documentation (X.509 processing). X-Git-Tag: v0.4~43 X-Git-Url: https://bearssl.org/gitweb//home/git/?a=commitdiff_plain;h=2e2b17186bf66b19831c0003cacc7afe2dd3dcdf;p=BearSSL Some more Doxygen API documentation (X.509 processing). --- diff --git a/Doxyfile b/Doxyfile index 131d48e..dd0a60f 100644 --- a/Doxyfile +++ b/Doxyfile @@ -771,7 +771,7 @@ WARN_LOGFILE = # spaces. See also FILE_PATTERNS and EXTENSION_MAPPING # Note: If this tag is empty the current directory is searched. -INPUT = inc/bearssl.h inc/bearssl_block.h inc/bearssl_ec.h inc/bearssl_hash.h inc/bearssl_hmac.h inc/bearssl_pem.h inc/bearssl_prf.h inc/bearssl_rand.h inc/bearssl_rsa.h +INPUT = inc/bearssl.h inc/bearssl_block.h inc/bearssl_ec.h inc/bearssl_hash.h inc/bearssl_hmac.h inc/bearssl_pem.h inc/bearssl_prf.h inc/bearssl_rand.h inc/bearssl_rsa.h inc/bearssl_x509.h # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses diff --git a/inc/bearssl.h b/inc/bearssl.h index 6258e92..a9f1db7 100644 --- a/inc/bearssl.h +++ b/inc/bearssl.h @@ -75,6 +75,16 @@ * total code footprint ligther. * * + * ## `NULL` values + * + * Function parameters with a pointer type shall not be `NULL` unless + * explicitly authorised by the documentation. As an exception, then + * the pointer aims at a sequence of bytes and is accompanied with + * a length parameter, and the length is zero (meaning that there is + * no byte at all to retrieve), then the pointer may be `NULL` even if + * not explicitly allowed. + * + * * ## Memory Allocation * * BearSSL does not perform dynamic memory allocation. This implies that diff --git a/inc/bearssl_x509.h b/inc/bearssl_x509.h index b35eddd..84e73dc 100644 --- a/inc/bearssl_x509.h +++ b/inc/bearssl_x509.h @@ -32,9 +32,9 @@ #include "bearssl_hash.h" #include "bearssl_rsa.h" -/* - * X.509 Certificate Chain Processing - * ---------------------------------- +/** \file bearssl_x509.h + * + * # X.509 Certificate Chain Processing * * An X.509 processing engine receives an X.509 chain, chunk by chunk, * as received from a SSL/TLS client or server (the client receives the @@ -45,130 +45,215 @@ * The engine's job is to return the public key to use for SSL/TLS. * How exactly that key is obtained and verified is entirely up to the * engine. + * + * **The "known key" engine** returns a public key which is already known + * from out-of-band information (e.g. the client _remembers_ the key from + * a previous connection, as in the usual SSH model). This is the simplest + * engine since it simply ignores the chain, thereby avoiding the need + * for any decoding logic. + * + * **The "minimal" engine** implements minimal X.509 decoding and chain + * validation: + * + * - The provided chain should validate "as is". There is no attempt + * at reordering, skipping or downloading extra certificates. + * + * - X.509 v1, v2 and v3 certificates are supported. + * + * - Trust anchors are a DN and a public key. Each anchor is either a + * "CA" anchor, or a non-CA. + * + * - If the end-entity certificate matches a non-CA anchor (subject DN + * is equal to the non-CA name, and public key is also identical to + * the anchor key), then this is a _direct trust_ case and the + * remaining certificates are ignored. + * + * - Unless direct trust is applied, the chain must be verifiable up to + * a certificate whose issuer DN matches the DN from a "CA" trust anchor, + * and whose signature is verifiable against that anchor's public key. + * Subsequent certificates in the chain are ignored. + * + * - The engine verifies subject/issuer DN matching, and enforces + * processing of Basic Constraints and Key Usage extensions. The + * Authority Key Identifier, Subject Key Identifier, Issuer Alt Name, + * Subject Directory Attribute, CRL Distribution Points, Freshest CRL, + * Authority Info Access and Subject Info Access extensions are + * ignored. The Subject Alt Name is decoded for the end-entity + * certificate under some conditions (see below). Other extensions + * are ignored if non-critical, or imply chain rejection if critical. + * + * - The Subject Alt Name extension is parsed for names of type `dNSName` + * when decoding the end-entity certificate, and only if there is a + * server name to match. If there is no SAN extension, then the + * Common Name from the subjectDN is used. That name matching is + * case-insensitive and honours a single starting wildcard (i.e. if + * the name in the certificate starts with "`*.`" then this matches + * any word as first element). Note: this name matching is performed + * also in the "direct trust" model. + * + * - DN matching is byte-to-byte equality (a future version might + * include some limited processing for case-insensitive matching and + * whitespace normalisation). + * + * - When doing validation, a target public key type is provided. That + * type is the combination of a key algorithm (RSA or EC) and an + * intended key usage (key exchange or signature); in the context + * of a SSL/TLS client validating a server's certificate, the algorithm + * and usage are obtained from the cipher suite (e.g. ECDHE_RSA means + * that an RSA key for signatures is expected). + * + * **Important caveats:** + * + * - The "minimal" engine does not check revocation status. The relevant + * extensions are ignored, and CRL or OCSP responses are not gathered + * or checked. + * + * - The "minimal" engine does not currently support Name Constraints + * (some basic functionality to handle sub-domains may be added in a + * later version). + * + * - The decoder is not "validating" in the sense that it won't reject + * some certificates with invalid field values when these fields are + * not actually processed. */ /* * X.509 error codes are in the 32..63 range. */ -/* Validation was successful; this is not actually an error. */ +/** \brief X.509 status: validation was successful; this is not actually + an error. */ #define BR_ERR_X509_OK 32 -/* Invalid value in an ASN.1 structure. */ +/** \brief X.509 status: invalid value in an ASN.1 structure. */ #define BR_ERR_X509_INVALID_VALUE 33 -/* Truncated certificate. */ +/** \brief X.509 status: truncated certificate. */ #define BR_ERR_X509_TRUNCATED 34 -/* Empty certificate chain (no certificate at all). */ +/** \brief X.509 status: empty certificate chain (no certificate at all). */ #define BR_ERR_X509_EMPTY_CHAIN 35 -/* Decoding error: inner element extends beyond outer element size. */ +/** \brief X.509 status: decoding error: inner element extends beyond + outer element size. */ #define BR_ERR_X509_INNER_TRUNC 36 -/* Decoding error: unsupported tag class (application or private). */ +/** \brief X.509 status: decoding error: unsupported tag class (application + or private). */ #define BR_ERR_X509_BAD_TAG_CLASS 37 -/* Decoding error: unsupported tag value. */ +/** \brief X.509 status: decoding error: unsupported tag value. */ #define BR_ERR_X509_BAD_TAG_VALUE 38 -/* Decoding error: indefinite length. */ +/** \brief X.509 status: decoding error: indefinite length. */ #define BR_ERR_X509_INDEFINITE_LENGTH 39 -/* Decoding error: extraneous element. */ +/** \brief X.509 status: decoding error: extraneous element. */ #define BR_ERR_X509_EXTRA_ELEMENT 40 -/* Decoding error: unexpected element. */ +/** \brief X.509 status: decoding error: unexpected element. */ #define BR_ERR_X509_UNEXPECTED 41 -/* Decoding error: expected constructed element, but is primitive. */ +/** \brief X.509 status: decoding error: expected constructed element, but + is primitive. */ #define BR_ERR_X509_NOT_CONSTRUCTED 42 -/* Decoding error: expected primitive element, but is constructed. */ +/** \brief X.509 status: decoding error: expected primitive element, but + is constructed. */ #define BR_ERR_X509_NOT_PRIMITIVE 43 -/* Decoding error: BIT STRING length is not multiple of 8. */ +/** \brief X.509 status: decoding error: BIT STRING length is not multiple + of 8. */ #define BR_ERR_X509_PARTIAL_BYTE 44 -/* Decoding error: BOOLEAN value has invalid length. */ +/** \brief X.509 status: decoding error: BOOLEAN value has invalid length. */ #define BR_ERR_X509_BAD_BOOLEAN 45 -/* Decoding error: value is off-limits. */ +/** \brief X.509 status: decoding error: value is off-limits. */ #define BR_ERR_X509_OVERFLOW 46 -/* Invalid distinguished name. */ +/** \brief X.509 status: invalid distinguished name. */ #define BR_ERR_X509_BAD_DN 47 -/* Invalid date/time representation. */ +/** \brief X.509 status: invalid date/time representation. */ #define BR_ERR_X509_BAD_TIME 48 -/* Certificate contains unsupported features that cannot be ignored. */ +/** \brief X.509 status: certificate contains unsupported features that + cannot be ignored. */ #define BR_ERR_X509_UNSUPPORTED 49 -/* Key or signature size exceeds internal limits. */ +/** \brief X.509 status: key or signature size exceeds internal limits. */ #define BR_ERR_X509_LIMIT_EXCEEDED 50 -/* Key type does not match that which was expected. */ +/** \brief X.509 status: key type does not match that which was expected. */ #define BR_ERR_X509_WRONG_KEY_TYPE 51 -/* Signature is invalid. */ +/** \brief X.509 status: signature is invalid. */ #define BR_ERR_X509_BAD_SIGNATURE 52 -/* Validation time is unknown. */ +/** \brief X.509 status: validation time is unknown. */ #define BR_ERR_X509_TIME_UNKNOWN 53 -/* Certificate is expired or not yet valid. */ +/** \brief X.509 status: certificate is expired or not yet valid. */ #define BR_ERR_X509_EXPIRED 54 -/* Issuer/Subject DN mismatch in the chain. */ +/** \brief X.509 status: issuer/subject DN mismatch in the chain. */ #define BR_ERR_X509_DN_MISMATCH 55 -/* Expected server name was not found in the chain. */ +/** \brief X.509 status: expected server name was not found in the chain. */ #define BR_ERR_X509_BAD_SERVER_NAME 56 -/* Unknown critical extension in certificate. */ +/** \brief X.509 status: unknown critical extension in certificate. */ #define BR_ERR_X509_CRITICAL_EXTENSION 57 -/* Not a CA, or path length constraint violation */ +/** \brief X.509 status: not a CA, or path length constraint violation */ #define BR_ERR_X509_NOT_CA 58 -/* Key Usage extension prohibits intended usage. */ +/** \brief X.509 status: Key Usage extension prohibits intended usage. */ #define BR_ERR_X509_FORBIDDEN_KEY_USAGE 59 -/* Public key found in certificate is too small. */ +/** \brief X.509 status: public key found in certificate is too small. */ #define BR_ERR_X509_WEAK_PUBLIC_KEY 60 -/* Chain could not be linked to a trust anchor. */ +/** \brief X.509 status: chain could not be linked to a trust anchor. */ #define BR_ERR_X509_NOT_TRUSTED 62 -/* - * A structure to encode public keys. +/** + * \brief Aggregate structure for public keys. */ typedef struct { + /** \brief Key type: `BR_KEYTYPE_RSA` or `BR_KEYTYPE_EC` */ unsigned char key_type; + /** \brief Actual public key. */ union { + /** \brief RSA public key. */ br_rsa_public_key rsa; + /** \brief EC public key. */ br_ec_public_key ec; } key; } br_x509_pkey; -/* - * A trust anchor consists in: - * -- an encoded DN - * -- a public key - * -- flags +/** + * \brief Trust anchor structure. */ typedef struct { + /** \brief Encoded DN (X.500 name). */ unsigned char *dn; + /** \brief Encoded DN length (in bytes). */ size_t dn_len; - /* unsigned char hashed_DN[64]; */ + /** \brief Anchor flags (e.g. `BR_X509_TA_CA`). */ unsigned flags; + /** \brief Anchor public key. */ br_x509_pkey pkey; } br_x509_trust_anchor; -/* Trust anchor flag: trust anchor is a CA and thus acceptable for - signing other certificates. Without this flag, the trust anchor - is only for direct trust (name and key match EE certificate). */ +/** + * \brief Trust anchor flag: CA. + * + * A "CA" anchor is deemed fit to verify signatures on certificates. + * A "non-CA" anchor is accepted only for direct trust (server's + * certificate name and key match the anchor). + */ #define BR_X509_TA_CA 0x0001 /* @@ -181,11 +266,31 @@ typedef struct { * for the key; the basic key type may be set to 0 to indicate that any * key type compatible with the indicated purpose is acceptable. */ +/** \brief Key type: algorithm is RSA. */ #define BR_KEYTYPE_RSA 1 +/** \brief Key type: algorithm is EC. */ #define BR_KEYTYPE_EC 2 -#define BR_KEYTYPE_KEYX 0x10 /* key is for key exchange or encryption */ -#define BR_KEYTYPE_SIGN 0x20 /* key is for verifying signatures */ +/** + * \brief Key type: usage is "key exchange". + * + * This value is combined (with bitwise OR) with the algorithm + * (`BR_KEYTYPE_RSA` or `BR_KEYTYPE_EC`) when informing the X.509 + * validation engine that it should find a public key of that type, + * fit for key exchanges (e.g. `TLS_RSA_*` and `TLS_ECDH_*` cipher + * suites). + */ +#define BR_KEYTYPE_KEYX 0x10 + +/** + * \brief Key type: usage is "signature". + * + * This value is combined (with bitwise OR) with the algorithm + * (`BR_KEYTYPE_RSA` or `BR_KEYTYPE_EC`) when informing the X.509 + * validation engine that it should find a public key of that type, + * fit for signatures (e.g. `TLS_ECDHE_*` cipher suites). + */ +#define BR_KEYTYPE_SIGN 0x20 /* * start_chain Called when a new chain is started. If 'server_name' @@ -220,51 +325,180 @@ typedef struct { * pointer to a public key even in some cases of validation failure, * depending on the validation engine. */ + +/** + * \brief Class type for an X.509 engine. + * + * A certificate chain validation uses a caller-allocated context, which + * contains the running state for that validation. Methods are called + * in due order: + * + * - `start_chain()` is called at the start of the validation. + * - Certificates are processed one by one, in SSL order (end-entity + * comes first). For each certificate, the following methods are + * called: + * + * - `start_cert()` at the beginning of the certificate. + * - `append()` is called zero, one or more times, to provide + * the certificate (possibly in chunks). + * - `end_cert()` at the end of the certificate. + * + * - `end_chain()` is called when the last certificate in the chain + * was processed. + * - `get_pkey()` is called after chain processing, if the chain + * validation was succesfull. + * + * A context structure may be reused; the `start_chain()` method shall + * ensure (re)initialisation. + */ typedef struct br_x509_class_ br_x509_class; struct br_x509_class_ { + /** + * \brief X.509 context size, in bytes. + */ size_t context_size; + + /** + * \brief Start a new chain. + * + * This method shall set the vtable (first field) of the context + * structure. + * + * The `expected_key_type` is a combination of the algorithm type + * (`BR_KEYTYPE_RSA` or `BR_KEYTYPE_EC`) and the key usage + * (`BR_KEYTYPE_KEYX` or `BR_KEYTYPE_SIGN`). + * + * The `server_name`, if not `NULL`, will be considered as a + * fully qualified domain name, to be matched against the `dNSName` + * elements of the end-entity certificate's SAN extension (if there + * is no SAN, then the Common Name from the subjectDN will be used). + * If `server_name` is `NULL` then no such matching is performed. + * + * \param ctx validation context. + * \param expected_key_type expected key type (algorithm and usage). + * \param server_name server name to match (or `NULL`). + */ void (*start_chain)(const br_x509_class **ctx, unsigned expected_key_type, const char *server_name); + + /** + * \brief Start a new certificate. + * + * \param ctx validation context. + * \param length new certificate length (in bytes). + */ void (*start_cert)(const br_x509_class **ctx, uint32_t length); + + /** + * \brief Receive some bytes for the current certificate. + * + * This function may be called several times in succession for + * a given certificate. The caller guarantees that for each + * call, `len` is not zero, and the sum of all chunk lengths + * for a certificate matches the total certificate length which + * was provided in the previous `start_cert()` call. + * + * If the new certificate is empty (no byte at all) then this + * function won't be called at all. + * + * \param ctx validation context. + * \param buf certificate data chunk. + * \param len certificate data chunk length (in bytes). + */ void (*append)(const br_x509_class **ctx, const unsigned char *buf, size_t len); + + /** + * \brief Finish the current certificate. + * + * This function is called when the end of the current certificate + * is reached. + * + * \param ctx validation context. + */ void (*end_cert)(const br_x509_class **ctx); + + /** + * \brief Finish the chain. + * + * This function is called at the end of the chain. It shall + * return either 0 if the validation was successful, or a + * non-zero error code. The `BR_ERR_X509_*` constants are + * error codes, though other values may be possible. + * + * \param ctx validation context. + * \return 0 on success, or a non-zero error code. + */ unsigned (*end_chain)(const br_x509_class **ctx); + + /** + * \brief Get the resulting end-entity public key. + * + * The decoded public key is returned. The returned pointer + * may be valid only as long as the context structure is + * unmodified, i.e. it may cease to be valid if the context + * is released or reused. + * + * This function _may_ return `NULL` if the validation failed. + * However, returning a public key does not mean that the + * validation was wholly successful; some engines may return + * a decoded public key even if the chain did not end on a + * trusted anchor. + * + * \param ctx validation context. + * \return the end-entity public key, or `NULL`. + */ const br_x509_pkey *(*get_pkey)(const br_x509_class *const *ctx); }; -/* - * The "known key" X.509 engine is a trivial engine that completely - * ignores the certificates, and instead reports an externally - * configured public key. +/** + * \brief The "known key" X.509 engine structure. + * + * The structure contents are opaque (they shall not be accessed directly), + * except for the first field (the vtable). + * + * The "known key" engine returns an externally configured public key, + * and totally ignores the certificate contents. */ typedef struct { + /** \brief Reference to the context vtable. */ const br_x509_class *vtable; +#ifndef BR_DOXYGEN_IGNORE br_x509_pkey pkey; +#endif } br_x509_knownkey_context; + +/** + * \brief Class instance for the "known key" X.509 engine. + */ extern const br_x509_class br_x509_knownkey_vtable; -/* - * Initialize a "known key" X.509 engine with a known RSA public key. - * The provided pointers are linked in, not copied, so they must - * remain valid while the public key may be in usage (i.e. at least up - * to the end of the handshake -- and since there may be renegotiations, - * these buffers should stay until the connection is finished). +/** + * \brief Initialize a "known key" X.509 engine with a known RSA public key. + * + * The provided pointers are linked in, not copied, so they must remain + * valid while the public key may be in usage. + * + * \param ctx context to initialise. + * \param pk known public key. */ void br_x509_knownkey_init_rsa(br_x509_knownkey_context *ctx, const br_rsa_public_key *pk); -/* - * Initialize a "known key" X.509 engine with a known EC public key. - * The provided pointers are linked in, not copied, so they must - * remain valid while the public key may be in usage (i.e. at least up - * to the end of the handshake -- and since there may be renegotiations, - * these buffers should stay until the connection is finished). +/** + * \brief Initialize a "known key" X.509 engine with a known EC public key. + * + * The provided pointers are linked in, not copied, so they must remain + * valid while the public key may be in usage. + * + * \param ctx context to initialise. + * \param pk known public key. */ void br_x509_knownkey_init_ec(br_x509_knownkey_context *ctx, const br_ec_public_key *pk); +#ifndef BR_DOXYGEN_IGNORE /* * The minimal X.509 engine has some state buffers which must be large * enough to simultaneously accommodate: @@ -282,10 +516,12 @@ void br_x509_knownkey_init_ec(br_x509_knownkey_context *ctx, * Though RSA public exponents can formally be as large as the modulus * (mathematically, even larger exponents would work, but PKCS#1 forbids * them), exponents that do not fit on 32 bits are extremely rare, - * notably because some widespread implementation (e.g. Microsoft's + * notably because some widespread implementations (e.g. Microsoft's * CryptoAPI) don't support them. Moreover, large public exponent do not * seem to imply any tangible security benefit, and they increase the - * cost of public key operations. + * cost of public key operations. The X.509 "minimal" engine will tolerate + * public exponents of arbitrary size as long as the modulus and the + * exponent can fit together in the dedicated buffer. * * EC public keys are shorter than RSA public keys; even with curve * NIST P-521 (the largest curve we care to support), a public key is @@ -293,19 +529,21 @@ void br_x509_knownkey_init_ec(br_x509_knownkey_context *ctx, */ #define BR_X509_BUFSIZE_KEY 520 #define BR_X509_BUFSIZE_SIG 512 +#endif -/* - * The "minimal" X.509 engine performs basic decoding of certificates and - * some validations: - * -- DN matching - * -- signatures - * -- validity dates - * -- Basic Constraints extension - * -- Server name check against SAN extension +/** + * \brief The "minimal" X.509 engine structure. + * + * The structure contents are opaque (they shall not be accessed directly), + * except for the first field (the vtable). + * + * The "minimal" engine performs a rudimentary but serviceable X.509 path + * validation. */ typedef struct { const br_x509_class *vtable; +#ifndef BR_DOXYGEN_IGNORE /* Structure for returning the EE public key. */ br_x509_pkey pkey; @@ -391,27 +629,51 @@ typedef struct { br_rsa_pkcs1_vrfy irsa; br_ecdsa_vrfy iecdsa; const br_ec_impl *iec; +#endif } br_x509_minimal_context; + +/** + * \brief Class instance for the "minimal" X.509 engine. + */ extern const br_x509_class br_x509_minimal_vtable; -/* - * Initialize a "minimal" X.509 engine. Parameters are: - * -- context to initialize - * -- hash function to use for hashing normalized DN - * -- list of trust anchors +/** + * \brief Initialise a "minimal" X.509 engine. + * + * The `dn_hash_impl` parameter shall be a hash function internally used + * to match X.500 names (subject/issuer DN, and anchor names). Any standard + * hash function may be used, but a collision-resistant hash function is + * advised. + * + * After initialization, some implementations for signature verification + * (hash functions and signature algorithms) MUST be added. * - * After initialization, some hash function implementations for signature - * verification MUST be added. + * \param ctx context to initialise. + * \param dn_hash_impl hash function for DN comparisons. + * \param trust_anchors trust anchors. + * \param trust_anchors_num number of trust anchors. */ void br_x509_minimal_init(br_x509_minimal_context *ctx, const br_hash_class *dn_hash_impl, const br_x509_trust_anchor *trust_anchors, size_t trust_anchors_num); -/* - * Set a hash function implementation, identified by ID, for purposes of - * verifying signatures on certificates. This must be called after - * br_x509_minimal_init(). +/** + * \brief Set a supported hash function in an X.509 "minimal" engine. + * + * Hash functions are used with signature verification algorithms. + * Once initialised (with `br_x509_minimal_init()`), the context must + * be configured with the hash functions it shall support for that + * purpose. The hash function identifier MUST be one of the standard + * hash function identifiers (1 to 6, for MD5, SHA-1, SHA-224, SHA-256, + * SHA-384 and SHA-512). + * + * If `impl` is `NULL`, this _removes_ support for the designated + * hash function. + * + * \param ctx validation context. + * \param id hash function identifier (from 1 to 6). + * \param impl hash function implementation (or `NULL`). */ static inline void br_x509_minimal_set_hash(br_x509_minimal_context *ctx, @@ -420,9 +682,17 @@ br_x509_minimal_set_hash(br_x509_minimal_context *ctx, br_multihash_setimpl(&ctx->mhash, id, impl); } -/* - * Set a RSA implementation, for purposes of verifying signatures on - * certificates. This must be called after br_x509_minimal_init(). +/** + * \brief Set a RSA signature verification implementation in the X.509 + * "minimal" engine. + * + * Once initialised (with `br_x509_minimal_init()`), the context must + * be configured with the signature verification implementations that + * it is supposed to support. If `irsa` is `0`, then the RSA support + * is disabled. + * + * \param ctx validation context. + * \param irsa RSA signature verification implementation (or `0`). */ static inline void br_x509_minimal_set_rsa(br_x509_minimal_context *ctx, @@ -431,9 +701,22 @@ br_x509_minimal_set_rsa(br_x509_minimal_context *ctx, ctx->irsa = irsa; } -/* - * Set an ECDSA implementation, for purposes of verifying signatures on - * certificates. This must be called after br_x509_minimal_init(). +/** + * \brief Set a ECDSA signature verification implementation in the X.509 + * "minimal" engine. + * + * Once initialised (with `br_x509_minimal_init()`), the context must + * be configured with the signature verification implementations that + * it is supposed to support. + * + * If `iecdsa` is `0`, then this call disables ECDSA support; in that + * case, `iec` may be `NULL`. Otherwise, `iecdsa` MUST point to a function + * that verifies ECDSA signatures with format "asn1", and it will use + * `iec` as underlying elliptic curve support. + * + * \param ctx validation context. + * \param iec elliptic curve implementation (or `NULL`). + * \param iecdsa ECDSA implementation (or `0`). */ static inline void br_x509_minimal_set_ecdsa(br_x509_minimal_context *ctx, @@ -443,21 +726,30 @@ br_x509_minimal_set_ecdsa(br_x509_minimal_context *ctx, ctx->iec = iec; } -/* - * Set the validation time, normally to the current date and time. - * This consists in two 32-bit counts: +/** + * \brief Set the validation time for the X.509 "minimal" engine. + * + * The validation time is set as two 32-bit integers, for days and + * seconds since a fixed epoch: * - * -- Days are counted in a proleptic Gregorian calendar since - * January 1st, 0 AD. Year "0 AD" is the one that preceded "1 AD"; - * it is also traditionally known as "1 BC". + * - Days are counted in a proleptic Gregorian calendar since + * January 1st, 0 AD. Year "0 AD" is the one that preceded "1 AD"; + * it is also traditionally known as "1 BC". * - * -- Seconds are counted since midnight, from 0 to 86400 (a count of - * 86400 is possible only if a leap second happened). + * - Seconds are counted since midnight, from 0 to 86400 (a count of + * 86400 is possible only if a leap second happened). + * + * The validation date and time is understood in the UTC time zone. * * If the validation date and time are not explicitly set, but BearSSL * was compiled with support for the system clock on the underlying * platform, then the current time will automatically be used. Otherwise, - * validation will fail (except in case of direct trust of the EE key). + * not setting the validation date and time implies a validation + * failure (except in case of direct trust of the EE key). + * + * \param ctx validation context. + * \param days days since January 1st, 0 AD (Gregorian calendar). + * \param seconds seconds since midnight (0 to 86400). */ static inline void br_x509_minimal_set_time(br_x509_minimal_context *ctx, @@ -467,11 +759,18 @@ br_x509_minimal_set_time(br_x509_minimal_context *ctx, ctx->seconds = seconds; } -/* - * Set the minimal acceptable length for RSA keys, in bytes. Default - * is 128 bytes, which means RSA keys of 1017 bits or more. This setting - * applies to keys extracted from certificates (EE and intermediate CA). - * It does _not_ apply to "CA" trust anchors. +/** + * \brief Set the minimal acceptable length for RSA keys (X.509 "minimal" + * engine). + * + * The RSA key length is expressed in bytes. The default minimum key + * length is 128 bytes, corresponding to 1017 bits. RSA keys shorter + * than the configured length will be rejected, implying validation + * failure. This setting applies to keys extracted from certificates + * (both end-entity, and intermediate CA) but not to "CA" trust anchors. + * + * \param ctx validation context. + * \param byte_length minimum RSA key length, **in bytes** (not bits). */ static inline void br_x509_minimal_set_minrsa(br_x509_minimal_context *ctx, int byte_length) @@ -479,13 +778,18 @@ br_x509_minimal_set_minrsa(br_x509_minimal_context *ctx, int byte_length) ctx->min_rsa_size = (int16_t)(byte_length - 128); } -/* - * An X.509 decoder context. This is not for X.509 validation, but for - * using certificates as trust anchors (e.g. self-signed certificates - * read from files). +/** + * \brief X.509 decoder context. + * + * This structure is _not_ for X.509 validation, but for extracting + * names and public keys from encoded certificates. Intended usage is + * to use (self-signed) certificates as trust anchors. + * + * Contents are opaque and shall not be accessed directly. */ typedef struct { +#ifndef BR_DOXYGEN_IGNORE /* Structure for returning the public key. */ br_x509_pkey pkey; @@ -529,28 +833,51 @@ typedef struct { /* Type of key and hash function used in the certificate signature. */ unsigned char signer_key_type; unsigned char signer_hash_id; +#endif } br_x509_decoder_context; -/* - * Initialise an X.509 decoder context for processing a new certificate. +/** + * \brief Initialise an X.509 decoder context for processing a new + * certificate. + * + * The `append_dn()` callback (with opaque context `append_dn_ctx`) + * will be invoked to receive, chunk by chunk, the certificate's + * subject DN. If `append_dn` is `0` then the subject DN will be + * ignored. + * + * \param ctx X.509 decoder context to initialise. + * \param append_dn DN receiver callback (or `0`). + * \param append_dn_ctx context for the DN receiver callback. */ void br_x509_decoder_init(br_x509_decoder_context *ctx, void (*append_dn)(void *ctx, const void *buf, size_t len), void *append_dn_ctx); -/* - * Push some certificate bytes into a decoder context. +/** + * \brief Push some certificate bytes into a decoder context. + * + * If `len` is non-zero, then that many bytes are pushed, from address + * `data`, into the provided decoder context. + * + * \param ctx X.509 decoder context. + * \param data certificate data chunk. + * \param len certificate data chunk length (in bytes). */ void br_x509_decoder_push(br_x509_decoder_context *ctx, const void *data, size_t len); -/* - * Obtain the decoded public key. Returned value is a pointer to a - * structure internal to the decoder context; releasing or reusing the - * decoder context invalidates that structure. +/** + * \brief Obtain the decoded public key. + * + * Returned value is a pointer to a structure internal to the decoder + * context; releasing or reusing the decoder context invalidates that + * structure. * - * If decoding was not finished, or failed, then NULL is returned. + * If decoding was not finished, or failed, then `NULL` is returned. + * + * \param ctx X.509 decoder context. + * \return the public key, or `NULL` on unfinished/error. */ static inline br_x509_pkey * br_x509_decoder_get_pkey(br_x509_decoder_context *ctx) @@ -562,10 +889,15 @@ br_x509_decoder_get_pkey(br_x509_decoder_context *ctx) } } -/* - * Get decoder error. If no error was reported yet but the certificate - * decoding is not finished, then the error code is BR_ERR_X509_TRUNCATED. - * If decoding was successful, then 0 is returned. +/** + * \brief Get decoder error status. + * + * If no error was reported yet but the certificate decoding is not + * finished, then the error code is `BR_ERR_X509_TRUNCATED`. If decoding + * was successful, then 0 is returned. + * + * \param ctx X.509 decoder context. + * \return 0 on successful decoding, or a non-zero error code. */ static inline int br_x509_decoder_last_error(br_x509_decoder_context *ctx) @@ -579,10 +911,15 @@ br_x509_decoder_last_error(br_x509_decoder_context *ctx) return 0; } -/* - * Get the "isCA" flag from an X.509 decoder context. This flag is set - * if the decoded certificate claims to be a CA through a Basic - * Constraints extension. +/** + * \brief Get the "isCA" flag from an X.509 decoder context. + * + * This flag is set if the decoded certificate claims to be a CA through + * a Basic Constraints extension. This flag should not be read before + * decoding completed successfully. + * + * \param ctx X.509 decoder context. + * \return the "isCA" flag. */ static inline int br_x509_decoder_isCA(br_x509_decoder_context *ctx) @@ -590,10 +927,15 @@ br_x509_decoder_isCA(br_x509_decoder_context *ctx) return ctx->isCA; } -/* - * Get the issuing CA key type (type of key used to sign the decoded - * certificate). This is BR_KEYTYPE_RSA or BR_KEYTYPE_EC. The value 0 - * is returned if the signature type was not recognised. +/** + * \brief Get the issuing CA key type (type of algorithm used to sign the + * decoded certificate). + * + * This is `BR_KEYTYPE_RSA` or `BR_KEYTYPE_EC`. The value 0 is returned + * if the signature type was not recognised. + * + * \param ctx X.509 decoder context. + * \return the issuing CA key type. */ static inline int br_x509_decoder_get_signer_key_type(br_x509_decoder_context *ctx) @@ -601,9 +943,14 @@ br_x509_decoder_get_signer_key_type(br_x509_decoder_context *ctx) return ctx->signer_key_type; } -/* - * Get the identifier for the hash function used to sign the decoded - * certificate. This is 0 if the hash function was not recognised. +/** + * \brief Get the identifier for the hash function used to sign the decoded + * certificate. + * + * This is 0 if the hash function was not recognised. + * + * \param ctx X.509 decoder context. + * \return the signature hash function identifier. */ static inline int br_x509_decoder_get_signer_hash_id(br_x509_decoder_context *ctx) @@ -611,19 +958,27 @@ br_x509_decoder_get_signer_hash_id(br_x509_decoder_context *ctx) return ctx->signer_hash_id; } -/* - * Type for an X.509 certificate (DER-encoded). +/** + * \brief Type for an X.509 certificate (DER-encoded). */ typedef struct { + /** \brief The DER-encoded certificate data. */ unsigned char *data; + /** \brief The DER-encoded certificate length (in bytes). */ size_t data_len; } br_x509_certificate; -/* - * Private key decoder context. +/** + * \brief Private key decoder context. + * + * The private key decoder recognises RSA and EC private keys, either in + * their raw, DER-encoded format, or wrapped in an unencrypted PKCS#8 + * archive (again DER-encoded). + * + * Structure contents are opaque and shall not be accessed directly. */ typedef struct { - +#ifndef BR_DOXYGEN_IGNORE /* Structure for returning the private key. */ union { br_rsa_private_key rsa; @@ -654,23 +1009,38 @@ typedef struct { to accommodate all elements for a RSA-4096 private key (roughly five 2048-bit integers, possibly a bit more). */ unsigned char key_data[3 * BR_X509_BUFSIZE_SIG]; - +#endif } br_skey_decoder_context; -/* - * Initialise a private key decoder context. +/** + * \brief Initialise a private key decoder context. + * + * \param ctx key decoder context to initialise. */ void br_skey_decoder_init(br_skey_decoder_context *ctx); -/* - * Push some data bytes into a private key decoder context. +/** + * \brief Push some data bytes into a private key decoder context. + * + * If `len` is non-zero, then that many data bytes, starting at address + * `data`, are pushed into the decoder. + * + * \param ctx key decoder context. + * \param data private key data chunk. + * \param len private key data chunk length (in bytes). */ void br_skey_decoder_push(br_skey_decoder_context *ctx, const void *data, size_t len); -/* - * Get the decoding status for a private key. This is either 0 on success, - * or a non-zero error code. +/** + * \brief Get the decoding status for a private key. + * + * Decoding status is 0 on success, or a non-zero error code. If the + * decoding is unfinished when this function is called, then the + * status code `BR_ERR_X509_TRUNCATED` is returned. + * + * \param ctx key decoder context. + * \return 0 on successful decoding, or a non-zero error code. */ static inline int br_skey_decoder_last_error(const br_skey_decoder_context *ctx) @@ -684,9 +1054,14 @@ br_skey_decoder_last_error(const br_skey_decoder_context *ctx) return 0; } -/* - * Get the decoded private key type. This is 0 if decoding is not finished - * or failed. +/** + * \brief Get the decoded private key type. + * + * Private key type is `BR_KEYTYPE_RSA` or `BR_KEYTYPE_EC`. If decoding is + * not finished or failed, then 0 is returned. + * + * \param ctx key decoder context. + * \return decoded private key type, or 0. */ static inline int br_skey_decoder_key_type(const br_skey_decoder_context *ctx) @@ -698,11 +1073,16 @@ br_skey_decoder_key_type(const br_skey_decoder_context *ctx) } } -/* - * Get the decoded RSA private key. This function returns NULL if the - * decoding failed, or is not finished, or the key is not RSA. The returned - * pointer references structures within the context that can become - * invalid if the context is reused or released. +/** + * \brief Get the decoded RSA private key. + * + * This function returns `NULL` if the decoding failed, or is not + * finished, or the key is not RSA. The returned pointer references + * structures within the context that can become invalid if the context + * is reused or released. + * + * \param ctx key decoder context. + * \return decoded RSA private key, or `NULL`. */ static inline const br_rsa_private_key * br_skey_decoder_get_rsa(const br_skey_decoder_context *ctx) @@ -714,11 +1094,16 @@ br_skey_decoder_get_rsa(const br_skey_decoder_context *ctx) } } -/* - * Get the decoded EC private key. This function returns NULL if the - * decoding failed, or is not finished, or the key is not EC. The returned - * pointer references structures within the context that can become - * invalid if the context is reused or released. +/** + * \brief Get the decoded EC private key. + * + * This function returns `NULL` if the decoding failed, or is not + * finished, or the key is not EC. The returned pointer references + * structures within the context that can become invalid if the context + * is reused or released. + * + * \param ctx key decoder context. + * \return decoded EC private key, or `NULL`. */ static inline const br_ec_private_key * br_skey_decoder_get_ec(const br_skey_decoder_context *ctx)