Added macro that indicates presence of the time callback feature. Also added C++...
[BearSSL] / inc / bearssl_x509.h
index 84e73dc..7668e1d 100644 (file)
 #include "bearssl_hash.h"
 #include "bearssl_rsa.h"
 
 #include "bearssl_hash.h"
 #include "bearssl_rsa.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 /** \file bearssl_x509.h
  *
  * # X.509 Certificate Chain Processing
 /** \file bearssl_x509.h
  *
  * # X.509 Certificate Chain Processing
  *     include some limited processing for case-insensitive matching and
  *     whitespace normalisation).
  *
  *     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).
+ *   - Successful validation produces a public key type but also a set
+ *     of allowed usages (`BR_KEYTYPE_KEYX` and/or `BR_KEYTYPE_SIGN`).
+ *     The caller is responsible for checking that the key type and
+ *     usages are compatible with the expected values (e.g. with the
+ *     selected cipher suite, when the client validates the server's
+ *     certificate).
  *
  * **Important caveats:**
  *
  *
  * **Important caveats:**
  *
@@ -233,14 +237,24 @@ typedef struct {
        } key;
 } br_x509_pkey;
 
        } key;
 } br_x509_pkey;
 
+/**
+ * \brief Distinguished Name (X.500) structure.
+ *
+ * The DN is DER-encoded.
+ */
+typedef struct {
+       /** \brief Encoded DN data. */
+       unsigned char *data;
+       /** \brief Encoded DN length (in bytes). */
+       size_t len;
+} br_x500_name;
+
 /**
  * \brief Trust anchor structure.
  */
 typedef struct {
        /** \brief Encoded DN (X.500 name). */
 /**
  * \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;
+       br_x500_name dn;
        /** \brief Anchor flags (e.g. `BR_X509_TA_CA`). */
        unsigned flags;
        /** \brief Anchor public key. */
        /** \brief Anchor flags (e.g. `BR_X509_TA_CA`). */
        unsigned flags;
        /** \brief Anchor public key. */
@@ -346,7 +360,7 @@ typedef struct {
  *   - `end_chain()` is called when the last certificate in the chain
  *     was processed.
  *   - `get_pkey()` is called after chain processing, if the chain
  *   - `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.
+ *     validation was successful.
  *
  * A context structure may be reused; the `start_chain()` method shall
  * ensure (re)initialisation.
  *
  * A context structure may be reused; the `start_chain()` method shall
  * ensure (re)initialisation.
@@ -364,22 +378,16 @@ struct br_x509_class_ {
         * This method shall set the vtable (first field) of the context
         * structure.
         *
         * 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.
         *
         * 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`).
+        * \param ctx           validation context.
+        * \param server_name   server name to match (or `NULL`).
         */
        void (*start_chain)(const br_x509_class **ctx,
         */
        void (*start_chain)(const br_x509_class **ctx,
-               unsigned expected_key_type,
                const char *server_name);
 
        /**
                const char *server_name);
 
        /**
@@ -446,10 +454,17 @@ struct br_x509_class_ {
         * a decoded public key even if the chain did not end on a
         * trusted anchor.
         *
         * a decoded public key even if the chain did not end on a
         * trusted anchor.
         *
+        * If validation succeeded and `usage` is not `NULL`, then
+        * `*usage` is filled with a combination of `BR_KEYTYPE_SIGN`
+        * and/or `BR_KEYTYPE_KEYX` that specifies the validated key
+        * usage types. It is the caller's responsibility to check
+        * that value against the intended use of the public key.
+        *
         * \param ctx   validation context.
         * \return  the end-entity public key, or `NULL`.
         */
         * \param ctx   validation context.
         * \return  the end-entity public key, or `NULL`.
         */
-       const br_x509_pkey *(*get_pkey)(const br_x509_class *const *ctx);
+       const br_x509_pkey *(*get_pkey)(
+               const br_x509_class *const *ctx, unsigned *usages);
 };
 
 /**
 };
 
 /**
@@ -466,6 +481,7 @@ typedef struct {
        const br_x509_class *vtable;
 #ifndef BR_DOXYGEN_IGNORE
        br_x509_pkey pkey;
        const br_x509_class *vtable;
 #ifndef BR_DOXYGEN_IGNORE
        br_x509_pkey pkey;
+       unsigned usages;
 #endif
 } br_x509_knownkey_context;
 
 #endif
 } br_x509_knownkey_context;
 
@@ -477,26 +493,34 @@ extern const br_x509_class br_x509_knownkey_vtable;
 /**
  * \brief Initialize a "known key" X.509 engine with a known RSA public key.
  *
 /**
  * \brief Initialize a "known key" X.509 engine with a known RSA public key.
  *
+ * The `usages` parameter indicates the allowed key usages for that key
+ * (`BR_KEYTYPE_KEYX` and/or `BR_KEYTYPE_SIGN`).
+ *
  * The provided pointers are linked in, not copied, so they must remain
  * valid while the public key may be in usage.
  *
  * 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.
+ * \param ctx      context to initialise.
+ * \param pk       known public key.
+ * \param usages   allowed key usages.
  */
 void br_x509_knownkey_init_rsa(br_x509_knownkey_context *ctx,
  */
 void br_x509_knownkey_init_rsa(br_x509_knownkey_context *ctx,
-       const br_rsa_public_key *pk);
+       const br_rsa_public_key *pk, unsigned usages);
 
 /**
  * \brief Initialize a "known key" X.509 engine with a known EC public key.
  *
 
 /**
  * \brief Initialize a "known key" X.509 engine with a known EC public key.
  *
+ * The `usages` parameter indicates the allowed key usages for that key
+ * (`BR_KEYTYPE_KEYX` and/or `BR_KEYTYPE_SIGN`).
+ *
  * The provided pointers are linked in, not copied, so they must remain
  * valid while the public key may be in usage.
  *
  * 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.
+ * \param ctx      context to initialise.
+ * \param pk       known public key.
+ * \param usages   allowed key usages.
  */
 void br_x509_knownkey_init_ec(br_x509_knownkey_context *ctx,
  */
 void br_x509_knownkey_init_ec(br_x509_knownkey_context *ctx,
-       const br_ec_public_key *pk);
+       const br_ec_public_key *pk, unsigned usages);
 
 #ifndef BR_DOXYGEN_IGNORE
 /*
 
 #ifndef BR_DOXYGEN_IGNORE
 /*
@@ -531,6 +555,122 @@ void br_x509_knownkey_init_ec(br_x509_knownkey_context *ctx,
 #define BR_X509_BUFSIZE_SIG   512
 #endif
 
 #define BR_X509_BUFSIZE_SIG   512
 #endif
 
+/**
+ * \brief Type for receiving a name element.
+ *
+ * An array of such structures can be provided to the X.509 decoding
+ * engines. If the specified elements are found in the certificate
+ * subject DN or the SAN extension, then the name contents are copied
+ * as zero-terminated strings into the buffer.
+ *
+ * The decoder converts TeletexString and BMPString to UTF8String, and
+ * ensures that the resulting string is zero-terminated. If the string
+ * does not fit in the provided buffer, then the copy is aborted and an
+ * error is reported.
+ */
+typedef struct {
+       /**
+        * \brief Element OID.
+        *
+        * For X.500 name elements (to be extracted from the subject DN),
+        * this is the encoded OID for the requested name element; the
+        * first byte shall contain the length of the DER-encoded OID
+        * value, followed by the OID value (for instance, OID 2.5.4.3,
+        * for id-at-commonName, will be `03 55 04 03`). This is
+        * equivalent to full DER encoding with the length but without
+        * the tag.
+        *
+        * For SAN name elements, the first byte (`oid[0]`) has value 0,
+        * followed by another byte that matches the expected GeneralName
+        * tag. Allowed second byte values are then:
+        *
+        *   - 1: `rfc822Name`
+        *
+        *   - 2: `dNSName`
+        *
+        *   - 6: `uniformResourceIdentifier`
+        *
+        *   - 0: `otherName`
+        *
+        * If first and second byte are 0, then this is a SAN element of
+        * type `otherName`; the `oid[]` array should then contain, right
+        * after the two bytes of value 0, an encoded OID (with the same
+        * conventions as for X.500 name elements). If a match is found
+        * for that OID, then the corresponding name element will be
+        * extracted, as long as it is a supported string type.
+        */
+       const unsigned char *oid;
+
+       /**
+        * \brief Destination buffer.
+        */
+       char *buf;
+
+       /**
+        * \brief Length (in bytes) of the destination buffer.
+        *
+        * The buffer MUST NOT be smaller than 1 byte.
+        */
+       size_t len;
+
+       /**
+        * \brief Decoding status.
+        *
+        * Status is 0 if the name element was not found, 1 if it was
+        * found and decoded, or -1 on error. Error conditions include
+        * an unrecognised encoding, an invalid encoding, or a string
+        * too large for the destination buffer.
+        */
+       int status;
+
+} br_name_element;
+
+/**
+ * \brief Callback for validity date checks.
+ *
+ * The function receives as parameter an arbitrary user-provided context,
+ * and the notBefore and notAfter dates specified in an X.509 certificate,
+ * both expressed as a number of days and a number of seconds:
+ *
+ *   - 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).
+ *
+ * Each date and time is understood in the UTC time zone. The "Unix
+ * Epoch" (January 1st, 1970, 00:00 UTC) corresponds to days=719528 and
+ * seconds=0; the "Windows Epoch" (January 1st, 1601, 00:00 UTC) is
+ * days=584754, seconds=0.
+ *
+ * This function must return -1 if the current date is strictly before
+ * the "notBefore" time, or +1 if the current date is strictly after the
+ * "notAfter" time. If neither condition holds, then the function returns
+ * 0, which means that the current date falls within the validity range of
+ * the certificate. If the function returns a value distinct from -1, 0
+ * and +1, then this is interpreted as an unavailability of the current
+ * time, which normally ends the validation process with a
+ * `BR_ERR_X509_TIME_UNKNOWN` error.
+ *
+ * During path validation, this callback will be invoked for each
+ * considered X.509 certificate. Validation fails if any of the calls
+ * returns a non-zero value.
+ *
+ * The context value is an abritrary pointer set by the caller when
+ * configuring this callback.
+ *
+ * \param tctx                 context pointer.
+ * \param not_before_days      notBefore date (days since Jan 1st, 0 AD).
+ * \param not_before_seconds   notBefore time (seconds, at most 86400).
+ * \param not_after_days       notAfter date (days since Jan 1st, 0 AD).
+ * \param not_after_seconds    notAfter time (seconds, at most 86400).
+ * \return  -1, 0 or +1.
+ */
+typedef int (*br_x509_time_check)(void *tctx,
+       uint32_t not_before_days, uint32_t not_before_seconds,
+       uint32_t not_after_days, uint32_t not_after_seconds);
+
 /**
  * \brief The "minimal" X.509 engine structure.
  *
 /**
  * \brief The "minimal" X.509 engine structure.
  *
@@ -553,15 +693,15 @@ typedef struct {
                uint32_t *rp;
                const unsigned char *ip;
        } cpu;
                uint32_t *rp;
                const unsigned char *ip;
        } cpu;
-       uint32_t dp_stack[32];
-       uint32_t rp_stack[32];
+       uint32_t dp_stack[31];
+       uint32_t rp_stack[31];
        int err;
 
        /* Server name to match with the SAN / CN of the EE certificate. */
        const char *server_name;
 
        int err;
 
        /* Server name to match with the SAN / CN of the EE certificate. */
        const char *server_name;
 
-       /* Expected EE key type and usage. */
-       unsigned char expected_key_type;
+       /* Validated key usages. */
+       unsigned char key_usages;
 
        /* Explicitly set date and time. */
        uint32_t days, seconds;
 
        /* Explicitly set date and time. */
        uint32_t days, seconds;
@@ -623,6 +763,18 @@ typedef struct {
        unsigned char next_dn_hash[64];
        unsigned char saved_dn_hash[64];
 
        unsigned char next_dn_hash[64];
        unsigned char saved_dn_hash[64];
 
+       /*
+        * Name elements to gather.
+        */
+       br_name_element *name_elts;
+       size_t num_name_elts;
+
+       /*
+        * Callback function (and context) to get the current date.
+        */
+       void *itime_ctx;
+       br_x509_time_check itime;
+
        /*
         * Public key cryptography implementations (signature verification).
         */
        /*
         * Public key cryptography implementations (signature verification).
         */
@@ -726,6 +878,20 @@ br_x509_minimal_set_ecdsa(br_x509_minimal_context *ctx,
        ctx->iec = iec;
 }
 
        ctx->iec = iec;
 }
 
+/**
+ * \brief Initialise a "minimal" X.509 engine with default algorithms.
+ *
+ * This function performs the same job as `br_x509_minimal_init()`, but
+ * also sets implementations for RSA, ECDSA, and the standard hash
+ * functions.
+ *
+ * \param ctx                 context to initialise.
+ * \param trust_anchors       trust anchors.
+ * \param trust_anchors_num   number of trust anchors.
+ */
+void br_x509_minimal_init_full(br_x509_minimal_context *ctx,
+       const br_x509_trust_anchor *trust_anchors, size_t trust_anchors_num);
+
 /**
  * \brief Set the validation time for the X.509 "minimal" engine.
  *
 /**
  * \brief Set the validation time for the X.509 "minimal" engine.
  *
@@ -739,7 +905,10 @@ br_x509_minimal_set_ecdsa(br_x509_minimal_context *ctx,
  *   - 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.
+ * The validation date and time is understood in the UTC time zone. The
+ * "Unix Epoch" (January 1st, 1970, 00:00 UTC) corresponds to days=719528
+ * and seconds=0; the "Windows Epoch" (January 1st, 1601, 00:00 UTC) is
+ * days=584754, seconds=0.
  *
  * If the validation date and time are not explicitly set, but BearSSL
  * was compiled with support for the system clock on the underlying
  *
  * If the validation date and time are not explicitly set, but BearSSL
  * was compiled with support for the system clock on the underlying
@@ -757,6 +926,28 @@ br_x509_minimal_set_time(br_x509_minimal_context *ctx,
 {
        ctx->days = days;
        ctx->seconds = seconds;
 {
        ctx->days = days;
        ctx->seconds = seconds;
+       ctx->itime = 0;
+}
+
+/**
+ * \brief Set the validity range callback function for the X.509
+ * "minimal" engine.
+ *
+ * The provided function will be invoked to check whether the validation
+ * date is within the validity range for a given X.509 certificate; a
+ * call will be issued for each considered certificate. The provided
+ * context pointer (itime_ctx) will be passed as first parameter to the
+ * callback.
+ *
+ * \param tctx   context for callback invocation.
+ * \param cb     callback function.
+ */
+static inline void
+br_x509_minimal_set_time_callback(br_x509_minimal_context *ctx,
+       void *itime_ctx, br_x509_time_check itime)
+{
+       ctx->itime_ctx = itime_ctx;
+       ctx->itime = itime;
 }
 
 /**
 }
 
 /**
@@ -778,6 +969,26 @@ br_x509_minimal_set_minrsa(br_x509_minimal_context *ctx, int byte_length)
        ctx->min_rsa_size = (int16_t)(byte_length - 128);
 }
 
        ctx->min_rsa_size = (int16_t)(byte_length - 128);
 }
 
+/**
+ * \brief Set the name elements to gather.
+ *
+ * The provided array is linked in the context. The elements are
+ * gathered from the EE certificate. If the same element type is
+ * requested several times, then the relevant structures will be filled
+ * in the order the matching values are encountered in the certificate.
+ *
+ * \param ctx        validation context.
+ * \param elts       array of name element structures to fill.
+ * \param num_elts   number of name element structures to fill.
+ */
+static inline void
+br_x509_minimal_set_name_elements(br_x509_minimal_context *ctx,
+       br_name_element *elts, size_t num_elts)
+{
+       ctx->name_elts = elts;
+       ctx->num_name_elts = num_elts;
+}
+
 /**
  * \brief X.509 decoder context.
  *
 /**
  * \brief X.509 decoder context.
  *
@@ -1115,4 +1326,149 @@ br_skey_decoder_get_ec(const br_skey_decoder_context *ctx)
        }
 }
 
        }
 }
 
+/**
+ * \brief Encode an RSA private key (raw DER format).
+ *
+ * This function encodes the provided key into the "raw" format specified
+ * in PKCS#1 (RFC 8017, Appendix C, type `RSAPrivateKey`), with DER
+ * encoding rules.
+ *
+ * The key elements are:
+ *
+ *  - `sk`: the private key (`p`, `q`, `dp`, `dq` and `iq`)
+ *
+ *  - `pk`: the public key (`n` and `e`)
+ *
+ *  - `d` (size: `dlen` bytes): the private exponent
+ *
+ * The public key elements, and the private exponent `d`, can be
+ * recomputed from the private key (see `br_rsa_compute_modulus()`,
+ * `br_rsa_compute_pubexp()` and `br_rsa_compute_privexp()`).
+ *
+ * If `dest` is not `NULL`, then the encoded key is written at that
+ * address, and the encoded length (in bytes) is returned. If `dest` is
+ * `NULL`, then nothing is written, but the encoded length is still
+ * computed and returned.
+ *
+ * \param dest   the destination buffer (or `NULL`).
+ * \param sk     the RSA private key.
+ * \param pk     the RSA public key.
+ * \param d      the RSA private exponent.
+ * \param dlen   the RSA private exponent length (in bytes).
+ * \return  the encoded key length (in bytes).
+ */
+size_t br_encode_rsa_raw_der(void *dest, const br_rsa_private_key *sk,
+       const br_rsa_public_key *pk, const void *d, size_t dlen);
+
+/**
+ * \brief Encode an RSA private key (PKCS#8 DER format).
+ *
+ * This function encodes the provided key into the PKCS#8 format
+ * (RFC 5958, type `OneAsymmetricKey`). It wraps around the "raw DER"
+ * format for the RSA key, as implemented by `br_encode_rsa_raw_der()`.
+ *
+ * The key elements are:
+ *
+ *  - `sk`: the private key (`p`, `q`, `dp`, `dq` and `iq`)
+ *
+ *  - `pk`: the public key (`n` and `e`)
+ *
+ *  - `d` (size: `dlen` bytes): the private exponent
+ *
+ * The public key elements, and the private exponent `d`, can be
+ * recomputed from the private key (see `br_rsa_compute_modulus()`,
+ * `br_rsa_compute_pubexp()` and `br_rsa_compute_privexp()`).
+ *
+ * If `dest` is not `NULL`, then the encoded key is written at that
+ * address, and the encoded length (in bytes) is returned. If `dest` is
+ * `NULL`, then nothing is written, but the encoded length is still
+ * computed and returned.
+ *
+ * \param dest   the destination buffer (or `NULL`).
+ * \param sk     the RSA private key.
+ * \param pk     the RSA public key.
+ * \param d      the RSA private exponent.
+ * \param dlen   the RSA private exponent length (in bytes).
+ * \return  the encoded key length (in bytes).
+ */
+size_t br_encode_rsa_pkcs8_der(void *dest, const br_rsa_private_key *sk,
+       const br_rsa_public_key *pk, const void *d, size_t dlen);
+
+/**
+ * \brief Encode an EC private key (raw DER format).
+ *
+ * This function encodes the provided key into the "raw" format specified
+ * in RFC 5915 (type `ECPrivateKey`), with DER encoding rules.
+ *
+ * The private key is provided in `sk`, the public key being `pk`. If
+ * `pk` is `NULL`, then the encoded key will not include the public key
+ * in its `publicKey` field (which is nominally optional).
+ *
+ * If `dest` is not `NULL`, then the encoded key is written at that
+ * address, and the encoded length (in bytes) is returned. If `dest` is
+ * `NULL`, then nothing is written, but the encoded length is still
+ * computed and returned.
+ *
+ * If the key cannot be encoded (e.g. because there is no known OBJECT
+ * IDENTIFIER for the used curve), then 0 is returned.
+ *
+ * \param dest   the destination buffer (or `NULL`).
+ * \param sk     the EC private key.
+ * \param pk     the EC public key (or `NULL`).
+ * \return  the encoded key length (in bytes), or 0.
+ */
+size_t br_encode_ec_raw_der(void *dest,
+       const br_ec_private_key *sk, const br_ec_public_key *pk);
+
+/**
+ * \brief Encode an EC private key (PKCS#8 DER format).
+ *
+ * This function encodes the provided key into the PKCS#8 format
+ * (RFC 5958, type `OneAsymmetricKey`). The curve is identified
+ * by an OID provided as parameters to the `privateKeyAlgorithm`
+ * field. The private key value (contents of the `privateKey` field)
+ * contains the DER encoding of the `ECPrivateKey` type defined in
+ * RFC 5915, without the `parameters` field (since they would be
+ * redundant with the information in `privateKeyAlgorithm`).
+ *
+ * The private key is provided in `sk`, the public key being `pk`. If
+ * `pk` is not `NULL`, then the encoded public key is included in the
+ * `publicKey` field of the private key value (but not in the `publicKey`
+ * field of the PKCS#8 `OneAsymmetricKey` wrapper).
+ *
+ * If `dest` is not `NULL`, then the encoded key is written at that
+ * address, and the encoded length (in bytes) is returned. If `dest` is
+ * `NULL`, then nothing is written, but the encoded length is still
+ * computed and returned.
+ *
+ * If the key cannot be encoded (e.g. because there is no known OBJECT
+ * IDENTIFIER for the used curve), then 0 is returned.
+ *
+ * \param dest   the destination buffer (or `NULL`).
+ * \param sk     the EC private key.
+ * \param pk     the EC public key (or `NULL`).
+ * \return  the encoded key length (in bytes), or 0.
+ */
+size_t br_encode_ec_pkcs8_der(void *dest,
+       const br_ec_private_key *sk, const br_ec_public_key *pk);
+
+/**
+ * \brief PEM banner for RSA private key (raw).
+ */
+#define BR_ENCODE_PEM_RSA_RAW      "RSA PRIVATE KEY"
+
+/**
+ * \brief PEM banner for EC private key (raw).
+ */
+#define BR_ENCODE_PEM_EC_RAW       "EC PRIVATE KEY"
+
+/**
+ * \brief PEM banner for an RSA or EC private key in PKCS#8 format.
+ */
+#define BR_ENCODE_PEM_PKCS8        "PRIVATE KEY"
+
+#ifdef __cplusplus
+}
+#endif
+
 #endif
 #endif