Added support for client certificates (both client-side and server-side, but still missing an API for extracting the client identity from the certificate).

This commit is contained in:
Thomas Pornin 2016-12-10 17:35:06 +01:00
parent e9ce2f4e8c
commit e61ad42191
27 changed files with 4441 additions and 1482 deletions

View file

@ -54,7 +54,7 @@ OBJINT32 = $(BUILD)/i32_add.o $(BUILD)/i32_bitlen.o $(BUILD)/i32_decmod.o $(BUIL
OBJMAC = $(BUILD)/hmac.o $(BUILD)/hmac_ct.o
OBJRAND = $(BUILD)/hmac_drbg.o
OBJRSA = $(BUILD)/rsa_i31_pkcs1_sign.o $(BUILD)/rsa_i31_pkcs1_vrfy.o $(BUILD)/rsa_i31_priv.o $(BUILD)/rsa_i31_pub.o $(BUILD)/rsa_i32_pkcs1_sign.o $(BUILD)/rsa_i32_pkcs1_vrfy.o $(BUILD)/rsa_i32_priv.o $(BUILD)/rsa_i32_pub.o $(BUILD)/rsa_ssl_decrypt.o
OBJSSL = $(BUILD)/prf.o $(BUILD)/prf_md5sha1.o $(BUILD)/prf_sha256.o $(BUILD)/prf_sha384.o $(BUILD)/ssl_client.o $(BUILD)/ssl_client_full.o $(BUILD)/ssl_engine.o $(BUILD)/ssl_hashes.o $(BUILD)/ssl_hs_client.o $(BUILD)/ssl_hs_server.o $(BUILD)/ssl_io.o $(BUILD)/ssl_lru.o $(BUILD)/ssl_rec_cbc.o $(BUILD)/ssl_rec_gcm.o $(BUILD)/ssl_server.o $(BUILD)/ssl_server_mine2g.o $(BUILD)/ssl_server_minf2g.o $(BUILD)/ssl_server_minr2g.o $(BUILD)/ssl_server_minu2g.o $(BUILD)/ssl_server_minv2g.o $(BUILD)/ssl_server_full_ec.o $(BUILD)/ssl_server_full_rsa.o $(BUILD)/ssl_single_ec.o $(BUILD)/ssl_single_rsa.o
OBJSSL = $(BUILD)/prf.o $(BUILD)/prf_md5sha1.o $(BUILD)/prf_sha256.o $(BUILD)/prf_sha384.o $(BUILD)/ssl_ccert_single_ec.o $(BUILD)/ssl_ccert_single_rsa.o $(BUILD)/ssl_client.o $(BUILD)/ssl_client_full.o $(BUILD)/ssl_engine.o $(BUILD)/ssl_hashes.o $(BUILD)/ssl_hs_client.o $(BUILD)/ssl_hs_server.o $(BUILD)/ssl_io.o $(BUILD)/ssl_lru.o $(BUILD)/ssl_rec_cbc.o $(BUILD)/ssl_rec_gcm.o $(BUILD)/ssl_server.o $(BUILD)/ssl_server_mine2g.o $(BUILD)/ssl_server_minf2g.o $(BUILD)/ssl_server_minr2g.o $(BUILD)/ssl_server_minu2g.o $(BUILD)/ssl_server_minv2g.o $(BUILD)/ssl_server_full_ec.o $(BUILD)/ssl_server_full_rsa.o $(BUILD)/ssl_scert_single_ec.o $(BUILD)/ssl_scert_single_rsa.o
OBJSYMCIPHER = $(BUILD)/aes_big_cbcdec.o $(BUILD)/aes_big_cbcenc.o $(BUILD)/aes_big_ctr.o $(BUILD)/aes_big_dec.o $(BUILD)/aes_big_enc.o $(BUILD)/aes_common.o $(BUILD)/aes_ct.o $(BUILD)/aes_ct64.o $(BUILD)/aes_ct64_cbcdec.o $(BUILD)/aes_ct64_cbcenc.o $(BUILD)/aes_ct64_ctr.o $(BUILD)/aes_ct64_dec.o $(BUILD)/aes_ct64_enc.o $(BUILD)/aes_ct_cbcdec.o $(BUILD)/aes_ct_cbcenc.o $(BUILD)/aes_ct_ctr.o $(BUILD)/aes_ct_dec.o $(BUILD)/aes_ct_enc.o $(BUILD)/aes_small_cbcdec.o $(BUILD)/aes_small_cbcenc.o $(BUILD)/aes_small_ctr.o $(BUILD)/aes_small_dec.o $(BUILD)/aes_small_enc.o $(BUILD)/des_ct.o $(BUILD)/des_ct_cbcdec.o $(BUILD)/des_ct_cbcenc.o $(BUILD)/des_support.o $(BUILD)/des_tab.o $(BUILD)/des_tab_cbcdec.o $(BUILD)/des_tab_cbcenc.o
OBJX509 = $(BUILD)/skey_decoder.o $(BUILD)/x509_decoder.o $(BUILD)/x509_knownkey.o $(BUILD)/x509_minimal.o
OBJ = $(OBJCODEC) $(OBJEC) $(OBJHASH) $(OBJINT31) $(OBJINT32) $(OBJMAC) $(OBJRAND) $(OBJRSA) $(OBJSSL) $(OBJSYMCIPHER) $(OBJX509)
@ -386,6 +386,12 @@ $(BUILD)/prf_sha256.o: src/ssl/prf_sha256.c $(HEADERS)
$(BUILD)/prf_sha384.o: src/ssl/prf_sha384.c $(HEADERS)
$(CC) $(CFLAGS) -c -o $(BUILD)/prf_sha384.o src/ssl/prf_sha384.c
$(BUILD)/ssl_ccert_single_ec.o: src/ssl/ssl_ccert_single_ec.c $(HEADERS)
$(CC) $(CFLAGS) -c -o $(BUILD)/ssl_ccert_single_ec.o src/ssl/ssl_ccert_single_ec.c
$(BUILD)/ssl_ccert_single_rsa.o: src/ssl/ssl_ccert_single_rsa.c $(HEADERS)
$(CC) $(CFLAGS) -c -o $(BUILD)/ssl_ccert_single_rsa.o src/ssl/ssl_ccert_single_rsa.c
$(BUILD)/ssl_client.o: src/ssl/ssl_client.c $(HEADERS)
$(CC) $(CFLAGS) -c -o $(BUILD)/ssl_client.o src/ssl/ssl_client.c
@ -440,11 +446,11 @@ $(BUILD)/ssl_server_full_ec.o: src/ssl/ssl_server_full_ec.c $(HEADERS)
$(BUILD)/ssl_server_full_rsa.o: src/ssl/ssl_server_full_rsa.c $(HEADERS)
$(CC) $(CFLAGS) -c -o $(BUILD)/ssl_server_full_rsa.o src/ssl/ssl_server_full_rsa.c
$(BUILD)/ssl_single_ec.o: src/ssl/ssl_single_ec.c $(HEADERS)
$(CC) $(CFLAGS) -c -o $(BUILD)/ssl_single_ec.o src/ssl/ssl_single_ec.c
$(BUILD)/ssl_scert_single_ec.o: src/ssl/ssl_scert_single_ec.c $(HEADERS)
$(CC) $(CFLAGS) -c -o $(BUILD)/ssl_scert_single_ec.o src/ssl/ssl_scert_single_ec.c
$(BUILD)/ssl_single_rsa.o: src/ssl/ssl_single_rsa.c $(HEADERS)
$(CC) $(CFLAGS) -c -o $(BUILD)/ssl_single_rsa.o src/ssl/ssl_single_rsa.c
$(BUILD)/ssl_scert_single_rsa.o: src/ssl/ssl_scert_single_rsa.c $(HEADERS)
$(CC) $(CFLAGS) -c -o $(BUILD)/ssl_scert_single_rsa.o src/ssl/ssl_scert_single_rsa.c
$(BUILD)/aes_big_cbcdec.o: src/symcipher/aes_big_cbcdec.c $(HEADERS)
$(CC) $(CFLAGS) -c -o $(BUILD)/aes_big_cbcdec.o src/symcipher/aes_big_cbcdec.c

View file

@ -191,9 +191,18 @@
signature algorithm, hash function). */
#define BR_ERR_INVALID_ALGORITHM 26
/** \brief SSL status: invalid signature on ServerKeyExchange message. */
/** \brief SSL status: invalid signature (on ServerKeyExchange from
server, or in CertificateVerify from client). */
#define BR_ERR_BAD_SIGNATURE 27
/** \brief SSL status: peer's public key does not have the proper type
or is not allowed for requested operation. */
#define BR_ERR_WRONG_KEY_USAGE 28
/** \brief SSL status: client did not send a certificate upon request,
or the client certificate could not be validated. */
#define BR_ERR_NO_CLIENT_AUTH 29
/** \brief SSL status: I/O error or premature close on underlying
transport stream. This error code is set only by the simplified
I/O API ("br_sslio_*"). */
@ -769,12 +778,11 @@ typedef struct {
uint32_t flags;
/*
* Context variables for the handshake processor.
* The 'pad' must be large enough to accommodate an
* RSA-encrypted pre-master secret, or a RSA signature on
* key exchange parameters; since we want to support up to
* RSA-4096, this means at least 512 bytes.
* (Other pad usages require its length to be at least 256.)
* Context variables for the handshake processor. The 'pad' must
* be large enough to accommodate an RSA-encrypted pre-master
* secret, or an RSA signature; since we want to support up to
* RSA-4096, this means at least 512 bytes. (Other pad usages
* require its length to be at least 256.)
*/
struct {
uint32_t *dp;
@ -825,6 +833,16 @@ typedef struct {
*/
const br_x509_class **x509ctx;
/*
* Certificate chain to send. This is used by both client and
* server, when they send their respective Certificate messages.
* If chain_len is 0, then chain may be NULL.
*/
const br_x509_certificate *chain;
size_t chain_len;
const unsigned char *cert_cur;
size_t cert_len;
/*
* Pointers to implementations; left to NULL for unsupported
* functions. For the raw hash functions, implementations are
@ -844,6 +862,8 @@ typedef struct {
const br_sslrec_in_gcm_class *igcm_in;
const br_sslrec_out_gcm_class *igcm_out;
const br_ec_impl *iec;
br_rsa_pkcs1_vrfy irsavrfy;
br_ecdsa_vrfy iecdsa;
#endif
} br_ssl_engine_context;
@ -909,7 +929,7 @@ br_ssl_engine_remove_flags(br_ssl_engine_context *cc, uint32_t flags)
*/
#define BR_OPT_ENFORCE_SERVER_PREFERENCES ((uint32_t)1 << 0)
/*
/**
* \brief Behavioural flag: disable renegotiation.
*
* If this flag is set, then renegotiations are rejected unconditionally:
@ -918,6 +938,26 @@ br_ssl_engine_remove_flags(br_ssl_engine_context *cc, uint32_t flags)
*/
#define BR_OPT_NO_RENEGOTIATION ((uint32_t)1 << 1)
/**
* \brief Behavioural flag: tolerate lack of client authentication.
*
* If this flag is set in a server and the server requests a client
* certificate, but the authentication fails (the client does not send
* a certificate, or the client's certificate chain cannot be validated),
* then the connection keeps on. Without this flag, a failed client
* authentication terminates the connection.
*
* Notes:
*
* - If the client's certificate can be validated and its public key is
* supported, then a wrong signature value terminates the connection
* regardless of that flag.
*
* - If using full-static ECDH, then a failure to validate the client's
* certificate prevents the handshake from succeeding.
*/
#define BR_OPT_TOLERATE_NO_CLIENT_AUTH ((uint32_t)1 << 2)
/**
* \brief Set the minimum and maximum supported protocol versions.
*
@ -1157,6 +1197,44 @@ br_ssl_engine_set_ec(br_ssl_engine_context *cc, const br_ec_impl *iec)
cc->iec = iec;
}
/**
* \brief Set the RSA signature verification implementation.
*
* On the client, this is used to verify the server's signature on its
* ServerKeyExchange message (for ECDHE_RSA cipher suites). On the server,
* this is used to verify the client's CertificateVerify message (if a
* client certificate is requested, and that certificate contains a RSA key).
*
* \param cc SSL engine context.
* \param irsavrfy RSA signature verification implementation.
*/
static inline void
br_ssl_engine_set_rsavrfy(br_ssl_engine_context *cc, br_rsa_pkcs1_vrfy irsavrfy)
{
cc->irsavrfy = irsavrfy;
}
/*
* \brief Set the ECDSA implementation (signature verification).
*
* On the client, this is used to verify the server's signature on its
* ServerKeyExchange message (for ECDHE_ECDSA cipher suites). On the server,
* this is used to verify the client's CertificateVerify message (if a
* client certificate is requested, that certificate contains an EC key,
* and full-static ECDH is not used).
*
* The ECDSA implementation will use the EC core implementation configured
* in the engine context.
*
* \param cc client context.
* \param iecdsa ECDSA verification implementation.
*/
static inline void
br_ssl_engine_set_ecdsa(br_ssl_engine_context *cc, br_ecdsa_vrfy iecdsa)
{
cc->iecdsa = iecdsa;
}
/**
* \brief Set the I/O buffer for the SSL engine.
*
@ -1597,6 +1675,326 @@ void br_ssl_engine_close(br_ssl_engine_context *cc);
*/
int br_ssl_engine_renegotiate(br_ssl_engine_context *cc);
/*
* Pre-declaration for the SSL client context.
*/
typedef struct br_ssl_client_context_ br_ssl_client_context;
/**
* \brief Type for the client certificate, if requested by the server.
*/
typedef struct {
/**
* \brief Authentication type.
*
* This is either `BR_AUTH_RSA` (RSA signature), `BR_AUTH_ECDSA`
* (ECDSA signature), or `BR_AUTH_ECDH` (static ECDH key exchange).
*/
int auth_type;
/**
* \brief Hash function for computing the CertificateVerify.
*
* This is the symbolic identifier for the hash function that
* will be used to produce the hash of handshake messages, to
* be signed into the CertificateVerify. For full static ECDH
* (client and server certificates are both EC in the same
* curve, and static ECDH is used), this value is set to -1.
*
* Take care that with TLS 1.0 and 1.1, that value MUST match
* the protocol requirements: value must be 0 (MD5+SHA-1) for
* a RSA signature, or 2 (SHA-1) for an ECDSA signature. Only
* TLS 1.2 allows for other hash functions.
*/
int hash_id;
/**
* \brief Certificate chain to send to the server.
*
* This is an array of `br_x509_certificate` objects, each
* normally containing a DER-encoded certificate. The client
* code does not try to decode these elements. If there is no
* chain to send to the server, then this pointer shall be
* set to `NULL`.
*/
const br_x509_certificate *chain;
/**
* \brief Certificate chain length (number of certificates).
*
* If there is no chain to send to the server, then this value
* shall be set to 0.
*/
size_t chain_len;
} br_ssl_client_certificate;
/*
* Note: the constants below for signatures match the TLS constants.
*/
/** \brief Client authentication type: static ECDH. */
#define BR_AUTH_ECDH 0
/** \brief Client authentication type: RSA signature. */
#define BR_AUTH_RSA 1
/** \brief Client authentication type: ECDSA signature. */
#define BR_AUTH_ECDSA 3
/**
* \brief Class type for a certificate handler (client side).
*
* A certificate handler selects a client certificate chain to send to
* the server, upon explicit request from that server. It receives
* the list of trust anchor DN from the server, and supported types
* of certificates and signatures, and returns the chain to use. It
* is also invoked to perform the corresponding private key operation
* (a signature, or an ECDH computation).
*
* The SSL client engine will first push the trust anchor DN with
* `start_name_list()`, `start_name()`, `append_name()`, `end_name()`
* and `end_name_list()`. Then it will call `choose()`, to select the
* actual chain (and signature/hash algorithms). Finally, it will call
* either `do_sign()` or `do_keyx()`, depending on the algorithm choices.
*/
typedef struct br_ssl_client_certificate_class_ br_ssl_client_certificate_class;
struct br_ssl_client_certificate_class_ {
/**
* \brief Context size (in bytes).
*/
size_t context_size;
/**
* \brief Begin reception of a list of trust anchor names. This
* is called while parsing the incoming CertificateRequest.
*
* \param pctx certificate handler context.
*/
void (*start_name_list)(const br_ssl_client_certificate_class **pctx);
/**
* \brief Begin reception of a new trust anchor name.
*
* The total encoded name length is provided; it is less than
* 65535 bytes.
*
* \param pctx certificate handler context.
* \param len encoded name length (in bytes).
*/
void (*start_name)(const br_ssl_client_certificate_class **pctx,
size_t len);
/**
* \brief Receive some more bytes for the current trust anchor name.
*
* The provided reference (`data`) points to a transient buffer
* they may be reused as soon as this function returns. The chunk
* length (`len`) is never zero.
*
* \param pctx certificate handler context.
* \param data anchor name chunk.
* \param len anchor name chunk length (in bytes).
*/
void (*append_name)(const br_ssl_client_certificate_class **pctx,
const unsigned char *data, size_t len);
/**
* \brief End current trust anchor name.
*
* This function is called when all the encoded anchor name data
* has been provided.
*
* \param pctx certificate handler context.
*/
void (*end_name)(const br_ssl_client_certificate_class **pctx);
/**
* \brief End list of trust anchor names.
*
* This function is called when all the anchor names in the
* CertificateRequest message have been obtained.
*
* \param pctx certificate handler context.
*/
void (*end_name_list)(const br_ssl_client_certificate_class **pctx);
/**
* \brief Select client certificate and algorithms.
*
* This callback function shall fill the provided `choices`
* structure with the selected algorithms and certificate chain.
* The `hash_id`, `chain` and `chain_len` fields must be set. If
* the client cannot or does not wish to send a certificate,
* then it shall set `chain` to `NULL` and `chain_len` to 0.
*
* The `auth_types` parameter describes the authentication types,
* signature algorithms and hash functions that are supported by
* both the client context and the server, and compatible with
* the current protocol version. This is a bit field with the
* following contents:
*
* - If RSA signatures with hash function x are supported, then
* bit x is set.
*
* - If ECDSA signatures with hash function x are supported,
* then bit 8+x is set.
*
* - If static ECDH is supported, with a RSA-signed certificate,
* then bit 16 is set.
*
* - If static ECDH is supported, with an ECDSA-signed certificate,
* then bit 17 is set.
*
* Notes:
*
* - When using TLS 1.0 or 1.1, the hash function for RSA
* signatures is always the special MD5+SHA-1 (id 0), and the
* hash function for ECDSA signatures is always SHA-1 (id 2).
*
* - When using TLS 1.2, the list of hash functions is trimmed
* down to include only hash functions that the client context
* can support. The actual server list can be obtained with
* `br_ssl_client_get_server_hashes()`; that list may be used
* to select the certificate chain to send to the server.
*
* \param pctx certificate handler context.
* \param cc SSL client context.
* \param auth_types supported authentication types and algorithms.
* \param choices destination structure for the policy choices.
*/
void (*choose)(const br_ssl_client_certificate_class **pctx,
const br_ssl_client_context *cc, uint32_t auth_types,
br_ssl_client_certificate *choices);
/**
* \brief Perform key exchange (client part).
*
* This callback is invoked in case of a full static ECDH key
* exchange:
*
* - the cipher suite uses `ECDH_RSA` or `ECDH_ECDSA`;
*
* - the server requests a client certificate;
*
* - the client has, and sends, a client certificate that
* uses an EC key in the same curve as the server's key,
* and chooses static ECDH (the `hash_id` field in the choice
* structure was set to -1).
*
* In that situation, this callback is invoked to compute the
* client-side ECDH: the provided `data` (of length `len` bytes)
* is the server's public key point (as decoded from its
* certificate), and the client shall multiply that point with
* its own private key, and write back the X coordinate of the
* resulting point in the same buffer, starting at offset 1
* (therefore, writing back the complete encoded point works).
*
* The callback must uphold the following:
*
* - If the input array does not have the proper length for
* an encoded curve point, then an error (0) shall be reported.
*
* - If the input array has the proper length, then processing
* MUST be constant-time, even if the data is not a valid
* encoded point.
*
* - This callback MUST check that the input point is valid.
*
* Returned value is 1 on success, 0 on error.
*
* \param pctx certificate handler context.
* \param data server public key point.
* \param len server public key point length (in bytes).
* \return 1 on success, 0 on error.
*/
uint32_t (*do_keyx)(const br_ssl_client_certificate_class **pctx,
unsigned char *data, size_t len);
/**
* \brief Perform a signature (client authentication).
*
* This callback is invoked when a client certificate was sent,
* and static ECDH is not used. It shall compute a signature,
* using the client's private key, over the provided hash value
* (which is the hash of all previous handshake messages).
*
* On input, the hash value to sign is in `data`, of size
* `hv_len`; the involved hash function is identified by
* `hash_id`. The signature shall be computed and written
* back into `data`; the total size of that buffer is `len`
* bytes.
*
* This callback shall verify that the signature length does not
* exceed `len` bytes, and abstain from writing the signature if
* it does not fit.
*
* For RSA signatures, the `hash_id` may be 0, in which case
* this is the special header-less signature specified in TLS 1.0
* and 1.1, with a 36-byte hash value. Otherwise, normal PKCS#1
* v1.5 signatures shall be computed.
*
* For ECDSA signatures, the signature value shall use the ASN.1
* based encoding.
*
* Returned value is the signature length (in bytes), or 0 on error.
*
* \param pctx certificate handler context.
* \param hash_id hash function identifier.
* \param hv_len hash value length (in bytes).
* \param data input/output buffer (hash value, then signature).
* \param len total buffer length (in bytes).
* \return signature length (in bytes) on success, or 0 on error.
*/
size_t (*do_sign)(const br_ssl_client_certificate_class **pctx,
int hash_id, size_t hv_len, unsigned char *data, size_t len);
};
/**
* \brief A single-chain RSA client certificate handler.
*
* This handler uses a single certificate chain, with a RSA
* signature. The list of trust anchor DN is ignored.
*
* Apart from the first field (vtable pointer), its contents are
* opaque and shall not be accessed directly.
*/
typedef struct {
/** \brief Pointer to vtable. */
const br_ssl_client_certificate_class *vtable;
#ifndef BR_DOXYGEN_IGNORE
const br_x509_certificate *chain;
size_t chain_len;
const br_rsa_private_key *sk;
br_rsa_pkcs1_sign irsasign;
#endif
} br_ssl_client_certificate_rsa_context;
/**
* \brief A single-chain EC client certificate handler.
*
* This handler uses a single certificate chain, with a RSA
* signature. The list of trust anchor DN is ignored.
*
* This handler may support both static ECDH, and ECDSA signatures
* (either usage may be selectively disabled).
*
* Apart from the first field (vtable pointer), its contents are
* opaque and shall not be accessed directly.
*/
typedef struct {
/** \brief Pointer to vtable. */
const br_ssl_client_certificate_class *vtable;
#ifndef BR_DOXYGEN_IGNORE
const br_x509_certificate *chain;
size_t chain_len;
const br_ec_private_key *sk;
unsigned allowed_usages;
unsigned issuer_key_type;
const br_multihash_context *mhash;
const br_ec_impl *iec;
br_ecdsa_sign iecdsa;
#endif
} br_ssl_client_certificate_ec_context;
/**
* \brief Context structure for a SSL client.
*
@ -1605,7 +2003,7 @@ int br_ssl_engine_renegotiate(br_ssl_engine_context *cc);
* a pointer to that field. The other structure fields are opaque and
* must not be accessed directly.
*/
typedef struct {
struct br_ssl_client_context_ {
/**
* \brief The encapsulated engine context.
*/
@ -1620,14 +2018,82 @@ typedef struct {
*/
uint16_t min_clienthello_len;
/*
* Bit field for algoithms (hash + signature) supported by the
* server when requesting a client certificate.
*/
uint16_t hashes;
/*
* Server's public key curve.
*/
int server_curve;
/*
* Context for certificate handler.
*/
const br_ssl_client_certificate_class **client_auth_vtable;
/*
* Client authentication type.
*/
unsigned char auth_type;
/*
* Hash function to use for the client signature. This is 0xFF
* if static ECDH is used.
*/
unsigned char hash_id;
/*
* For the core certificate handlers, thus avoiding (in most
* cases) the need for an externally provided policy context.
*/
union {
const br_ssl_client_certificate_class *vtable;
br_ssl_client_certificate_rsa_context single_rsa;
br_ssl_client_certificate_ec_context single_ec;
} client_auth;
/*
* Implementations.
*/
br_rsa_public irsapub;
br_rsa_pkcs1_vrfy irsavrfy;
br_ecdsa_vrfy iecdsa;
#endif
} br_ssl_client_context;
};
/**
* \brief Get the hash functions and signature algorithms supported by
* the server.
*
* This is a field of bits: for hash function of ID x, bit x is set if
* the hash function is supported in RSA signatures, 8+x if it is supported
* with ECDSA. This information is conveyed by the server when requesting
* a client certificate.
*
* \param cc client context.
* \return the server-supported hash functions (for signatures).
*/
static inline uint16_t
br_ssl_client_get_server_hashes(const br_ssl_client_context *cc)
{
return cc->hashes;
}
/**
* \brief Get the server key curve.
*
* This function returns the ID for the curve used by the server's public
* key. This is set when the server's certificate chain is processed;
* this value is 0 if the server's key is not an EC key.
*
* \return the server's public key curve ID, or 0.
*/
static inline int
br_ssl_client_get_server_curve(const br_ssl_client_context *cc)
{
return cc->server_curve;
}
/*
* Each br_ssl_client_init_xxx() function sets the list of supported
@ -1667,6 +2133,22 @@ void br_ssl_client_init_full(br_ssl_client_context *cc,
*/
void br_ssl_client_zero(br_ssl_client_context *cc);
/**
* \brief Set an externally provided client certificate handler context.
*
* The handler's methods are invoked when the server requests a client
* certificate.
*
* \param cc client context.
* \param pctx certificate handler context (pointer to its vtable field).
*/
static inline void
br_ssl_client_set_client_certificate(br_ssl_client_context *cc,
const br_ssl_client_certificate_class **pctx)
{
cc->client_auth_vtable = pctx;
}
/**
* \brief Set the RSA public-key operations implementation.
*
@ -1682,36 +2164,6 @@ br_ssl_client_set_rsapub(br_ssl_client_context *cc, br_rsa_public irsapub)
cc->irsapub = irsapub;
}
/**
* \brief Set the RSA signature verification implementation.
*
* This will be used to verify the server's signature on its
* ServerKeyExchange message (ECDHE_RSA cipher suites only).
*
* \param cc client context.
* \param irsavrfy RSA signature verification implementation.
*/
static inline void
br_ssl_client_set_rsavrfy(br_ssl_client_context *cc, br_rsa_pkcs1_vrfy irsavrfy)
{
cc->irsavrfy = irsavrfy;
}
/*
* \brief Set the ECDSA implementation (signature verification).
*
* The ECDSA implementation will use the EC core implementation configured
* in the engine context.
*
* \param cc client context.
* \param iecdsa ECDSA verification implementation.
*/
static inline void
br_ssl_client_set_ecdsa(br_ssl_client_context *cc, br_ecdsa_vrfy iecdsa)
{
cc->iecdsa = iecdsa;
}
/**
* \brief Set the minimum ClientHello length (RFC 7685 padding).
*
@ -1783,6 +2235,73 @@ br_ssl_client_forget_session(br_ssl_client_context *cc)
cc->eng.session.session_id_len = 0;
}
/**
* \brief Set client certificate chain and key (single RSA case).
*
* This function sets a client certificate chain, that the client will
* send to the server whenever a client certificate is requested. This
* certificate uses an RSA public key; the corresponding private key is
* invoked for authentication. Trust anchor names sent by the server are
* ignored.
*
* The provided chain and private key are linked in the client context;
* they must remain valid as long as they may be used, i.e. normally
* for the duration of the connection, since they might be invoked
* again upon renegotiations.
*
* \param cc SSL client context.
* \param chain client certificate chain (SSL order: EE comes first).
* \param chain_len client chain length (number of certificates).
* \param sk client private key.
* \param irsasign RSA signature implementation (PKCS#1 v1.5).
*/
void br_ssl_client_set_single_rsa(br_ssl_client_context *cc,
const br_x509_certificate *chain, size_t chain_len,
const br_rsa_private_key *sk, br_rsa_pkcs1_sign irsasign);
/*
* \brief Set the client certificate chain and key (single EC case).
*
* This function sets a client certificate chain, that the client will
* send to the server whenever a client certificate is requested. This
* certificate uses an EC public key; the corresponding private key is
* invoked for authentication. Trust anchor names sent by the server are
* ignored.
*
* The provided chain and private key are linked in the client context;
* they must remain valid as long as they may be used, i.e. normally
* for the duration of the connection, since they might be invoked
* again upon renegotiations.
*
* The `allowed_usages` is a combination of usages, namely
* `BR_KEYTYPE_KEYX` and/or `BR_KEYTYPE_SIGN`. The `BR_KEYTYPE_KEYX`
* value allows full static ECDH, while the `BR_KEYTYPE_SIGN` value
* allows ECDSA signatures. If ECDSA signatures are used, then an ECDSA
* signature implementation must be provided; otherwise, the `iecdsa`
* parameter may be 0.
*
* The `cert_issuer_key_type` value is either `BR_KEYTYPE_RSA` or
* `BR_KEYTYPE_EC`; it is the type of the public key used the the CA
* that issued (signed) the client certificate. That value is used with
* full static ECDH: support of the certificate by the server depends
* on how the certificate was signed. (Note: when using TLS 1.2, this
* parameter is ignored; but its value matters for TLS 1.0 and 1.1.)
*
* \param cc server context.
* \param chain server certificate chain to send.
* \param chain_len chain length (number of certificates).
* \param sk server private key (EC).
* \param allowed_usages allowed private key usages.
* \param cert_issuer_key_type issuing CA's key type.
* \param iec EC core implementation.
* \param iecdsa ECDSA signature implementation ("asn1" format).
*/
void br_ssl_client_set_single_ec(br_ssl_client_context *cc,
const br_x509_certificate *chain, size_t chain_len,
const br_ec_private_key *sk, unsigned allowed_usages,
unsigned cert_issuer_key_type,
const br_ec_impl *iec, br_ecdsa_sign iecdsa);
/**
* \brief Type for a "translated cipher suite", as an array of two
* 16-bit integers.
@ -1906,6 +2425,7 @@ typedef struct {
* \brief Certificate chain length (number of certificates).
*/
size_t chain_len;
} br_ssl_server_choices;
/**
@ -2244,10 +2764,6 @@ struct br_ssl_server_context_ {
* Context for chain handler.
*/
const br_ssl_server_policy_class **policy_vtable;
const br_x509_certificate *chain;
size_t chain_len;
const unsigned char *cert_cur;
size_t cert_len;
unsigned char sign_hash_id;
/*
@ -2266,6 +2782,25 @@ struct br_ssl_server_context_ {
unsigned char ecdhe_key[70];
size_t ecdhe_key_len;
/*
* Trust anchor names for client authentication. "ta_names" and
* "tas" cannot be both non-NULL.
*/
const br_x500_name *ta_names;
const br_x509_trust_anchor *tas;
size_t num_tas;
size_t cur_dn_index;
const unsigned char *cur_dn;
size_t cur_dn_len;
/*
* Buffer for the hash value computed over all handshake messages
* prior to CertificateVerify, and identifier for the hash function.
*/
unsigned char hash_CV[64];
size_t hash_CV_len;
int hash_CV_id;
/*
* Server-specific implementations.
* (none for now)
@ -2539,7 +3074,7 @@ void br_ssl_server_set_single_rsa(br_ssl_server_context *cc,
const br_rsa_private_key *sk, unsigned allowed_usages,
br_rsa_private irsacore, br_rsa_pkcs1_sign irsasign);
/*
/**
* \brief Set the server certificate chain and key (single EC case).
*
* This function uses a policy context included in the server context.
@ -2569,6 +3104,61 @@ void br_ssl_server_set_single_ec(br_ssl_server_context *cc,
unsigned cert_issuer_key_type,
const br_ec_impl *iec, br_ecdsa_sign iecdsa);
/**
* \brief Activate client certificate authentication.
*
* The trust anchor encoded X.500 names (DN) to send to the client are
* provided. A client certificate will be requested and validated through
* the X.509 validator configured in the SSL engine. If `num` is 0, then
* client certificate authentication is disabled.
*
* If the client does not send a certificate, or on validation failure,
* the handshake aborts. Unauthenticated clients can be tolerated by
* setting the `BR_OPT_TOLERATE_NO_CLIENT_AUTH` flag.
*
* The provided array is linked in, not copied, so that pointer must
* remain valid as long as anchor names may be used.
*
* \param cc server context.
* \param ta_names encoded trust anchor names.
* \param num number of encoded trust anchor names.
*/
static inline void
br_ssl_server_set_trust_anchor_names(br_ssl_server_context *cc,
const br_x500_name *ta_names, size_t num)
{
cc->ta_names = ta_names;
cc->tas = NULL;
cc->num_tas = num;
}
/**
* \brief Activate client certificate authentication.
*
* This is a variant for `br_ssl_server_set_trust_anchor_names()`: the
* trust anchor names are provided not as an array of stand-alone names
* (`br_x500_name` structures), but as an array of trust anchors
* (`br_x509_trust_anchor` structures). The server engine itself will
* only use the `dn` field of each trust anchor. This is meant to allow
* defining a single array of trust anchors, to be used here and in the
* X.509 validation engine itself.
*
* The provided array is linked in, not copied, so that pointer must
* remain valid as long as anchor names may be used.
*
* \param cc server context.
* \param tas trust anchors (only names are used).
* \param num number of trust anchors.
*/
static inline void
br_ssl_server_set_trust_anchor_names_alt(br_ssl_server_context *cc,
const br_x509_trust_anchor *tas, size_t num)
{
cc->ta_names = NULL;
cc->tas = tas;
cc->num_tas = num;
}
/**
* \brief Configure the cache for session parameters.
*

View file

@ -95,12 +95,12 @@
* 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:**
*
@ -233,14 +233,24 @@ typedef struct {
} 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). */
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. */
@ -364,10 +374,6 @@ struct br_x509_class_ {
* 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
@ -375,11 +381,9 @@ struct br_x509_class_ {
* 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);
/**
@ -446,10 +450,17 @@ struct br_x509_class_ {
* 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`.
*/
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 +477,7 @@ typedef struct {
const br_x509_class *vtable;
#ifndef BR_DOXYGEN_IGNORE
br_x509_pkey pkey;
unsigned usages;
#endif
} br_x509_knownkey_context;
@ -477,26 +489,34 @@ extern const br_x509_class br_x509_knownkey_vtable;
/**
* \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.
*
* \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,
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.
*
* 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.
*
* \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,
const br_ec_public_key *pk);
const br_ec_public_key *pk, unsigned usages);
#ifndef BR_DOXYGEN_IGNORE
/*
@ -560,8 +580,8 @@ typedef struct {
/* 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;

View file

@ -0,0 +1,150 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "inner.h"
static void
cc_none0(const br_ssl_client_certificate_class **pctx)
{
(void)pctx;
}
static void
cc_none1(const br_ssl_client_certificate_class **pctx, size_t len)
{
(void)pctx;
(void)len;
}
static void
cc_none2(const br_ssl_client_certificate_class **pctx,
const unsigned char *data, size_t len)
{
(void)pctx;
(void)data;
(void)len;
}
static void
cc_choose(const br_ssl_client_certificate_class **pctx,
const br_ssl_client_context *cc, uint32_t auth_types,
br_ssl_client_certificate *choices)
{
br_ssl_client_certificate_ec_context *zc;
int x;
int scurve;
zc = (br_ssl_client_certificate_ec_context *)pctx;
scurve = br_ssl_client_get_server_curve(cc);
if ((zc->allowed_usages & BR_KEYTYPE_KEYX) != 0
&& scurve == zc->sk->curve)
{
int x;
x = (zc->issuer_key_type == BR_KEYTYPE_RSA) ? 16 : 17;
if (((auth_types >> x) & 1) != 0) {
choices->auth_type = BR_AUTH_ECDH;
choices->hash_id = -1;
choices->chain = zc->chain;
choices->chain_len = zc->chain_len;
}
}
/*
* For ECDSA authentication, we must choose an appropriate
* hash function.
*/
x = br_ssl_choose_hash((unsigned)(auth_types >> 8));
if (x == 0 || (zc->allowed_usages & BR_KEYTYPE_SIGN) == 0) {
memset(choices, 0, sizeof *choices);
return;
}
choices->auth_type = BR_AUTH_ECDSA;
choices->hash_id = x;
choices->chain = zc->chain;
choices->chain_len = zc->chain_len;
}
static uint32_t
cc_do_keyx(const br_ssl_client_certificate_class **pctx,
unsigned char *data, size_t len)
{
br_ssl_client_certificate_ec_context *zc;
zc = (br_ssl_client_certificate_ec_context *)pctx;
return zc->iec->mul(data, len, zc->sk->x, zc->sk->xlen, zc->sk->curve);
}
static size_t
cc_do_sign(const br_ssl_client_certificate_class **pctx,
int hash_id, size_t hv_len, unsigned char *data, size_t len)
{
br_ssl_client_certificate_ec_context *zc;
unsigned char hv[64];
const br_hash_class *hc;
zc = (br_ssl_client_certificate_ec_context *)pctx;
memcpy(hv, data, hv_len);
hc = br_multihash_getimpl(zc->mhash, hash_id);
if (hc == NULL) {
return 0;
}
if (len < 139) {
return 0;
}
return zc->iecdsa(zc->iec, hc, hv, zc->sk, data);
}
static const br_ssl_client_certificate_class ccert_vtable = {
sizeof(br_ssl_client_certificate_ec_context),
cc_none0, /* start_name_list */
cc_none1, /* start_name */
cc_none2, /* append_name */
cc_none0, /* end_name */
cc_none0, /* end_name_list */
cc_choose,
cc_do_keyx,
cc_do_sign
};
/* see bearssl_ssl.h */
void
br_ssl_client_set_single_ec(br_ssl_client_context *cc,
const br_x509_certificate *chain, size_t chain_len,
const br_ec_private_key *sk, unsigned allowed_usages,
unsigned cert_issuer_key_type,
const br_ec_impl *iec, br_ecdsa_sign iecdsa)
{
cc->client_auth.single_ec.vtable = &ccert_vtable;
cc->client_auth.single_ec.chain = chain;
cc->client_auth.single_ec.chain_len = chain_len;
cc->client_auth.single_ec.sk = sk;
cc->client_auth.single_ec.allowed_usages = allowed_usages;
cc->client_auth.single_ec.issuer_key_type = cert_issuer_key_type;
cc->client_auth.single_ec.mhash = &cc->eng.mhash;
cc->client_auth.single_ec.iec = iec;
cc->client_auth.single_ec.iecdsa = iecdsa;
cc->client_auth_vtable = &cc->client_auth.single_ec.vtable;
}

View file

@ -0,0 +1,149 @@
/*
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "inner.h"
static void
cc_none0(const br_ssl_client_certificate_class **pctx)
{
(void)pctx;
}
static void
cc_none1(const br_ssl_client_certificate_class **pctx, size_t len)
{
(void)pctx;
(void)len;
}
static void
cc_none2(const br_ssl_client_certificate_class **pctx,
const unsigned char *data, size_t len)
{
(void)pctx;
(void)data;
(void)len;
}
static void
cc_choose(const br_ssl_client_certificate_class **pctx,
const br_ssl_client_context *cc, uint32_t auth_types,
br_ssl_client_certificate *choices)
{
br_ssl_client_certificate_rsa_context *zc;
int x;
(void)cc;
zc = (br_ssl_client_certificate_rsa_context *)pctx;
x = br_ssl_choose_hash((unsigned)auth_types);
if (x == 0 && (auth_types & 1) == 0) {
memset(choices, 0, sizeof *choices);
}
choices->auth_type = BR_AUTH_RSA;
choices->hash_id = x;
choices->chain = zc->chain;
choices->chain_len = zc->chain_len;
}
/*
* OID for hash functions in RSA signatures.
*/
static const unsigned char HASH_OID_SHA1[] = {
0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A
};
static const unsigned char HASH_OID_SHA224[] = {
0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04
};
static const unsigned char HASH_OID_SHA256[] = {
0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01
};
static const unsigned char HASH_OID_SHA384[] = {
0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02
};
static const unsigned char HASH_OID_SHA512[] = {
0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03
};
static const unsigned char *HASH_OID[] = {
HASH_OID_SHA1,
HASH_OID_SHA224,
HASH_OID_SHA256,
HASH_OID_SHA384,
HASH_OID_SHA512
};
static size_t
cc_do_sign(const br_ssl_client_certificate_class **pctx,
int hash_id, size_t hv_len, unsigned char *data, size_t len)
{
br_ssl_client_certificate_rsa_context *zc;
unsigned char hv[64];
const unsigned char *hash_oid;
size_t sig_len;
zc = (br_ssl_client_certificate_rsa_context *)pctx;
memcpy(hv, data, hv_len);
if (hash_id == 0) {
hash_oid = NULL;
} else if (hash_id >= 2 && hash_id <= 6) {
hash_oid = HASH_OID[hash_id - 2];
} else {
return 0;
}
sig_len = (zc->sk->n_bitlen + 7) >> 3;
if (len < sig_len) {
return 0;
}
return zc->irsasign(hash_oid, hv, hv_len, zc->sk, data) ? sig_len : 0;
}
static const br_ssl_client_certificate_class ccert_vtable = {
sizeof(br_ssl_client_certificate_rsa_context),
cc_none0, /* start_name_list */
cc_none1, /* start_name */
cc_none2, /* append_name */
cc_none0, /* end_name */
cc_none0, /* end_name_list */
cc_choose,
0,
cc_do_sign
};
/* see bearssl_ssl.h */
void
br_ssl_client_set_single_rsa(br_ssl_client_context *cc,
const br_x509_certificate *chain, size_t chain_len,
const br_rsa_private_key *sk, br_rsa_pkcs1_sign irsasign)
{
cc->client_auth.single_rsa.vtable = &ccert_vtable;
cc->client_auth.single_rsa.chain = chain;
cc->client_auth.single_rsa.chain_len = chain_len;
cc->client_auth.single_rsa.sk = sk;
cc->client_auth.single_rsa.irsasign = irsasign;
cc->client_auth_vtable = &cc->client_auth.single_rsa.vtable;
}

View file

@ -123,9 +123,9 @@ br_ssl_client_init_full(br_ssl_client_context *cc,
br_ssl_engine_set_suites(&cc->eng, suites,
(sizeof suites) / (sizeof suites[0]));
br_ssl_client_set_rsapub(cc, &br_rsa_i31_public);
br_ssl_client_set_rsavrfy(cc, &br_rsa_i31_pkcs1_vrfy);
br_ssl_engine_set_rsavrfy(&cc->eng, &br_rsa_i31_pkcs1_vrfy);
br_ssl_engine_set_ec(&cc->eng, &br_ec_prime_i31);
br_ssl_client_set_ecdsa(cc, &br_ecdsa_i31_vrfy_asn1);
br_ssl_engine_set_ecdsa(&cc->eng, &br_ecdsa_i31_vrfy_asn1);
br_x509_minimal_set_rsa(xc, &br_rsa_i31_pkcs1_vrfy);
br_x509_minimal_set_ecdsa(xc,
&br_ec_prime_i31, &br_ecdsa_i31_vrfy_asn1);

File diff suppressed because it is too large Load diff

View file

@ -55,7 +55,7 @@ make_pms_rsa(br_ssl_client_context *ctx, int prf_id)
size_t nlen, u;
xc = ctx->eng.x509ctx;
pk = (*xc)->get_pkey(xc);
pk = (*xc)->get_pkey(xc, NULL);
/*
* Compute actual RSA key length, in case there are leading zeros.
@ -145,9 +145,11 @@ static const unsigned char *HASH_OID[] = {
/*
* Check the RSA signature on the ServerKeyExchange message.
*
* hash hash function ID (2 to 6), or 0 for MD5+SHA-1 (with RSA only)
* use_rsa non-zero for RSA signature, zero for ECDSA
* sig_len signature length (in bytes); signature value is in the pad
*
* Returned value is 0 on success, or an error code.
*/
static int
@ -161,7 +163,7 @@ verify_SKE_sig(br_ssl_client_context *ctx,
size_t hv_len;
xc = ctx->eng.x509ctx;
pk = (*xc)->get_pkey(xc);
pk = (*xc)->get_pkey(xc, NULL);
br_multihash_zero(&mhc);
br_multihash_copyimpl(&mhc, &ctx->eng.mhash);
br_multihash_init(&mhc);
@ -198,14 +200,14 @@ verify_SKE_sig(br_ssl_client_context *ctx,
} else {
hash_oid = NULL;
}
if (!ctx->irsavrfy(ctx->eng.pad, sig_len,
if (!ctx->eng.irsavrfy(ctx->eng.pad, sig_len,
hash_oid, hv_len, &pk->key.rsa, tmp)
|| memcmp(tmp, hv, hv_len) != 0)
{
return BR_ERR_BAD_SIGNATURE;
}
} else {
if (!ctx->iecdsa(ctx->eng.iec, hv, hv_len, &pk->key.ec,
if (!ctx->eng.iecdsa(ctx->eng.iec, hv, hv_len, &pk->key.ec,
ctx->eng.pad, sig_len))
{
return BR_ERR_BAD_SIGNATURE;
@ -215,7 +217,7 @@ verify_SKE_sig(br_ssl_client_context *ctx,
}
/*
* Perform client-size ECDH (or ECDHE). The point that should be sent to
* Perform client-side ECDH (or ECDHE). The point that should be sent to
* the server is written in the pad; returned value is either the point
* length (in bytes), or -x on error, with 'x' being an error code.
*
@ -241,7 +243,7 @@ make_pms_ecdh(br_ssl_client_context *ctx, unsigned ecdhe, int prf_id)
const br_x509_pkey *pk;
xc = ctx->eng.x509ctx;
pk = (*xc)->get_pkey(xc);
pk = (*xc)->get_pkey(xc, NULL);
curve = pk->key.ec.curve;
point_src = pk->key.ec.q;
point_len = pk->key.ec.qlen;
@ -292,6 +294,73 @@ make_pms_ecdh(br_ssl_client_context *ctx, unsigned ecdhe, int prf_id)
return (int)glen;
}
/*
* Perform full static ECDH. This occurs only in the context of client
* authentication with certificates: the server uses an EC public key,
* the cipher suite is of type ECDH (not ECDHE), the server requested a
* client certificate and accepts static ECDH, the client has a
* certificate with an EC public key in the same curve, and accepts
* static ECDH as well.
*
* Returned value is 0 on success, -1 on error.
*/
static int
make_pms_static_ecdh(br_ssl_client_context *ctx, int prf_id)
{
unsigned char point[133];
size_t point_len;
const br_x509_class **xc;
const br_x509_pkey *pk;
xc = ctx->eng.x509ctx;
pk = (*xc)->get_pkey(xc, NULL);
point_len = pk->key.ec.qlen;
if (point_len > sizeof point) {
return -1;
}
memcpy(point, pk->key.ec.q, point_len);
if (!(*ctx->client_auth_vtable)->do_keyx(
ctx->client_auth_vtable, point, point_len))
{
return -1;
}
br_ssl_engine_compute_master(&ctx->eng,
prf_id, point + 1, point_len >> 1);
return 0;
}
/*
* Compute the client-side signature. This is invoked only when a
* signature-based client authentication was selected. The computed
* signature is in the pad; its length (in bytes) is returned. On
* error, 0 is returned.
*/
static size_t
make_client_sign(br_ssl_client_context *ctx)
{
size_t hv_len;
/*
* Compute hash of handshake messages so far. This "cannot" fail
* because the list of supported hash functions provided to the
* client certificate handler was trimmed to include only the
* hash functions that the multi-hasher supports.
*/
if (ctx->hash_id) {
hv_len = br_multihash_out(&ctx->eng.mhash,
ctx->hash_id, ctx->eng.pad);
} else {
br_multihash_out(&ctx->eng.mhash,
br_md5_ID, ctx->eng.pad);
br_multihash_out(&ctx->eng.mhash,
br_sha1_ID, ctx->eng.pad + 16);
hv_len = 36;
}
return (*ctx->client_auth_vtable)->do_sign(
ctx->client_auth_vtable, ctx->hash_id, hv_len,
ctx->eng.pad, sizeof ctx->eng.pad);
}
}
\ =======================================================================
@ -303,6 +372,9 @@ make_pms_ecdh(br_ssl_client_context *ctx, unsigned ecdhe, int prf_id)
postpone literal postpone ; ;
addr-ctx: min_clienthello_len
addr-ctx: hashes
addr-ctx: auth_type
addr-ctx: hash_id
\ Length of the Secure Renegotiation extension. This is 5 for the
\ first handshake, 17 for a renegotiation (if the server supports the
@ -319,16 +391,6 @@ addr-ctx: min_clienthello_len
: ext-frag-length ( -- len )
addr-log_max_frag_len get8 14 = if 0 else 5 then ;
\ Test support for RSA signatures.
cc: supports-rsa-sign? ( -- bool ) {
T0_PUSHi(-(CTX->irsavrfy != 0));
}
\ Test support for ECDSA signatures.
cc: supports-ecdsa? ( -- bool ) {
T0_PUSHi(-(CTX->iecdsa != 0));
}
\ Length of Signatures extension.
: ext-signatures-length ( -- len )
supported-hash-functions { x } drop
@ -709,80 +771,26 @@ cc: DEBUG-BLOB ( addr len -- ) {
resume
;
cc: x509-start-chain ( expected-key-type -- ) {
cc: set-server-curve ( -- ) {
const br_x509_class *xc;
const br_x509_pkey *pk;
xc = *(ENG->x509ctx);
xc->start_chain(ENG->x509ctx, T0_POP(), ENG->server_name);
pk = xc->get_pkey(ENG->x509ctx, NULL);
CTX->server_curve =
(pk->key_type == BR_KEYTYPE_EC) ? pk->key.ec.curve : 0;
}
cc: x509-start-cert ( length -- ) {
const br_x509_class *xc;
xc = *(ENG->x509ctx);
xc->start_cert(ENG->x509ctx, T0_POP());
}
cc: x509-append ( length -- ) {
const br_x509_class *xc;
size_t len;
xc = *(ENG->x509ctx);
len = T0_POP();
xc->append(ENG->x509ctx, ENG->pad, len);
}
cc: x509-end-cert ( -- ) {
const br_x509_class *xc;
xc = *(ENG->x509ctx);
xc->end_cert(ENG->x509ctx);
}
cc: x509-end-chain ( -- err ) {
const br_x509_class *xc;
xc = *(ENG->x509ctx);
T0_PUSH(xc->end_chain(ENG->x509ctx));
}
\ Parse Certificate
: read-Certificate ( -- )
\ Get header, and check message type.
read-handshake-header 11 = ifnot ERR_UNEXPECTED fail then
\ Start processing the chain through the X.509 engine.
\ Read Certificate message from server.
: read-Certificate-from-server ( -- )
addr-cipher_suite get16 expected-key-type
x509-start-chain
-1 read-Certificate
dup 0< if neg fail then
dup ifnot ERR_UNEXPECTED fail then
over and <> if ERR_WRONG_KEY_USAGE fail then
\ Total chain length is a 24-bit integer.
read24 open-elt
begin
dup while
read24 open-elt
dup x509-start-cert
\ We read the certificate by chunks through the pad, so
\ as to use the existing reading function (read-blob)
\ that also ensures proper hashing.
begin
dup while
dup 256 > if 256 else dup then { len }
addr-pad len read-blob
len x509-append
repeat
close-elt
x509-end-cert
repeat
\ We must close the chain AND the handshake message.
close-elt
close-elt
\ Chain processing is finished; get the error code.
x509-end-chain
dup if fail then drop
;
\ Set server curve (used for static ECDH).
set-server-curve ;
\ Verify signature on ECDHE point sent by the server.
\ 'hash' is the hash function to use (1 to 6, or 0 for RSA with MD5+SHA-1)
@ -851,15 +859,166 @@ cc: verify-SKE-sig ( hash use-rsa sig-len -- err ) {
close-elt ;
\ Client certificate: start processing of anchor names.
cc: anchor-dn-start-name-list ( -- ) {
if (CTX->client_auth_vtable != NULL) {
(*CTX->client_auth_vtable)->start_name_list(
CTX->client_auth_vtable);
}
}
\ Client certificate: start a new anchor DN (length is 16-bit).
cc: anchor-dn-start-name ( length -- ) {
size_t len;
len = T0_POP();
if (CTX->client_auth_vtable != NULL) {
(*CTX->client_auth_vtable)->start_name(
CTX->client_auth_vtable, len);
}
}
\ Client certificate: push some data for current anchor DN.
cc: anchor-dn-append-name ( length -- ) {
size_t len;
len = T0_POP();
if (CTX->client_auth_vtable != NULL) {
(*CTX->client_auth_vtable)->append_name(
CTX->client_auth_vtable, ENG->pad, len);
}
}
\ Client certificate: end current anchor DN.
cc: anchor-dn-end-name ( -- ) {
if (CTX->client_auth_vtable != NULL) {
(*CTX->client_auth_vtable)->end_name(
CTX->client_auth_vtable);
}
}
\ Client certificate: end list of anchor DN.
cc: anchor-dn-end-name-list ( -- ) {
if (CTX->client_auth_vtable != NULL) {
(*CTX->client_auth_vtable)->end_name_list(
CTX->client_auth_vtable);
}
}
\ Client certificate: obtain the client certificate chain.
cc: get-client-chain ( auth_types -- ) {
uint32_t auth_types;
auth_types = T0_POP();
if (CTX->client_auth_vtable != NULL) {
br_ssl_client_certificate ux;
(*CTX->client_auth_vtable)->choose(CTX->client_auth_vtable,
CTX, auth_types, &ux);
CTX->auth_type = (unsigned char)ux.auth_type;
CTX->hash_id = (unsigned char)ux.hash_id;
ENG->chain = ux.chain;
ENG->chain_len = ux.chain_len;
} else {
CTX->hash_id = 0;
ENG->chain_len = 0;
}
}
\ Parse CertificateRequest. Header has already been read.
: read-contents-CertificateRequest ( lim -- )
\ TODO: implement client certificates. Right now, we simply
\ drop the complete message.
begin dup while read8 drop repeat drop ;
\ Read supported client authentification types. We keep only
\ RSA, ECDSA, and ECDH.
0 { auth_types }
read8 open-elt
begin dup while
read8 case
1 of 0x0000FF endof
64 of 0x00FF00 endof
65 of 0x010000 endof
66 of 0x020000 endof
0 swap
endcase
auth_types or >auth_types
repeat
close-elt
\ Full static ECDH is allowed only if the cipher suite is ECDH
\ (not ECDHE). It would be theoretically feasible to use static
\ ECDH on the client side with an ephemeral key pair from the
\ server, but RFC 4492 (section 3) forbids it because ECDHE suites
\ are supposed to provide forward secrecy, and static ECDH would
\ negate that property.
addr-cipher_suite get16 use-ecdh? ifnot
auth_types 0xFFFF and >auth_types
then
\ Note: if the cipher suite is ECDH, then the X.509 validation
\ engine was invoked with the BR_KEYTYPE_EC | BR_KEYTYPE_KEYX
\ combination, so the server's public key has already been
\ checked to be fit for a key exchange.
\ With TLS 1.2:
\ - rsa_fixed_ecdh and ecdsa_fixed_ecdh are synoymous.
\ - There is an explicit list of supported sign+hash.
\ With TLS 1.0,
addr-version get16 0x0303 >= if
\ With TLS 1.2:
\ - There is an explicit list of supported sign+hash.
\ - The ECDH flags must be adjusted for RSA/ECDSA
\ support.
read-list-sign-algos dup addr-hashes set16
\ Trim down the list depending on what hash functions
\ we support (since the hashing itself is done by the SSL
\ engine, not by the certificate handler).
supported-hash-functions drop dup 8 << or 0x030000 or and
auth_types and
auth_types 0x030000 and if
dup 0x0000FF and if 0x010000 or then
dup 0x00FF00 and if 0x020000 or then
then
>auth_types
else
\ TLS 1.0 or 1.1. The hash function is fixed for signatures
\ (MD5+SHA-1 for RSA, SHA-1 for ECDSA).
auth_types 0x030401 and >auth_types
then
\ Parse list of anchor DN.
anchor-dn-start-name-list
read16 open-elt
begin dup while
read16 open-elt
dup anchor-dn-start-name
\ We read the DN by chunks through the pad, so
\ as to use the existing reading function (read-blob)
\ that also ensures proper hashing.
begin
dup while
dup 256 > if 256 else dup then { len }
addr-pad len read-blob
len anchor-dn-append-name
repeat
close-elt
anchor-dn-end-name
repeat
close-elt
anchor-dn-end-name-list
\ We should have reached the message end.
close-elt
\ Obtain the client chain.
auth_types get-client-chain
;
\ (obsolete)
\ Write an empty Certificate message.
: write-empty-Certificate ( -- )
11 write8 3 write24 0 write24 ;
\ : write-empty-Certificate ( -- )
\ 11 write8 3 write24 0 write24 ;
cc: do-rsa-encrypt ( prf_id -- nlen ) {
int x;
@ -887,7 +1046,27 @@ cc: do-ecdh ( echde prf_id -- ulen ) {
}
}
\ Write ClientKeyExchange
cc: do-static-ecdh ( prf-id -- ) {
unsigned prf_id = T0_POP();
if (make_pms_static_ecdh(CTX, prf_id) < 0) {
br_ssl_engine_fail(ENG, BR_ERR_INVALID_ALGORITHM);
T0_CO();
}
}
cc: do-client-sign ( -- sig_len ) {
size_t sig_len;
sig_len = make_client_sign(CTX);
if (sig_len == 0) {
br_ssl_engine_fail(ENG, BR_ERR_INVALID_ALGORITHM);
T0_CO();
}
T0_PUSH(sig_len);
}
\ Write ClientKeyExchange.
: write-ClientKeyExchange ( -- )
16 write8
addr-cipher_suite get16
@ -903,6 +1082,20 @@ cc: do-ecdh ( echde prf_id -- ulen ) {
addr-pad swap write-blob
then ;
\ Write CertificateVerify. This is invoked only if a client certificate
\ was requested and sent, and the authentication is not full static ECDH.
: write-CertificateVerify ( -- )
do-client-sign
15 write8 dup
addr-version get16 0x0303 >= if
4 + write24
addr-hash_id get8 write8
addr-auth_type get8 write8
else
2+ write24
then
dup write16 addr-pad swap write-blob ;
\ =======================================================================
\ Perform a handshake.
@ -924,7 +1117,9 @@ cc: do-ecdh ( echde prf_id -- ulen ) {
\ Not a session resumption.
read-Certificate
\ Read certificate; then check key type and usages against
\ cipher suite.
read-Certificate-from-server
\ Depending on cipher suite, we may now expect a
\ ServerKeyExchange.
@ -956,12 +1151,27 @@ cc: do-ecdh ( echde prf_id -- ulen ) {
more-incoming-bytes? if ERR_UNEXPECTED fail then
seen-CR if
\ TODO: client certificate support.
write-empty-Certificate
then
write-ClientKeyExchange
\ If the server requested a client certificate, then
\ we must write a Certificate message (it may be
\ empty).
write-Certificate
\ TODO: CertificateVerify
\ If using static ECDH, then the ClientKeyExchange
\ is empty, and there is no CertificateVerify.
\ Otherwise, there is a ClientKeyExchange; there
\ will then be a CertificateVerify if a client chain
\ was indeed sent.
addr-hash_id get8 0xFF = if
drop
16 write8 0 write24
addr-cipher_suite get16 prf-id do-static-ecdh
else
write-ClientKeyExchange
if write-CertificateVerify then
then
else
write-ClientKeyExchange
then
-1 write-CCS-Finished
-1 read-CCS-Finished

View file

@ -145,12 +145,8 @@ addr-eng: version_max
addr-eng: suites_buf
addr-eng: suites_num
addr-eng: server_name
\ addr-eng: version
\ addr-eng: cipher_suite
addr-eng: client_random
addr-eng: server_random
\ addr-eng: session_id_len
\ addr-eng: session_id
addr-eng: ecdhe_curve
addr-eng: ecdhe_point
addr-eng: ecdhe_point_len
@ -212,6 +208,9 @@ err: ERR_LIMIT_EXCEEDED
err: ERR_BAD_FINISHED
err: ERR_RESUME_MISMATCH
err: ERR_INVALID_ALGORITHM
err: ERR_BAD_SIGNATURE
err: ERR_WRONG_KEY_USAGE
err: ERR_NO_CLIENT_AUTH
\ Get supported curves (bit mask).
cc: supported-curves ( -- x ) {
@ -220,6 +219,7 @@ cc: supported-curves ( -- x ) {
}
\ Get supported hash functions (bit mask and number).
\ Note: this (on purpose) skips MD5.
cc: supported-hash-functions ( -- x num ) {
int i;
unsigned x, num;
@ -236,6 +236,16 @@ cc: supported-hash-functions ( -- x num ) {
T0_PUSH(num);
}
\ Test support for RSA signatures.
cc: supports-rsa-sign? ( -- bool ) {
T0_PUSHi(-(ENG->irsavrfy != 0));
}
\ Test support for ECDSA signatures.
cc: supports-ecdsa? ( -- bool ) {
T0_PUSHi(-(ENG->iecdsa != 0));
}
\ (Re)initialise the multihasher.
cc: multihash-init ( -- ) {
br_multihash_init(&ENG->mhash);
@ -1020,3 +1030,186 @@ cc: compute-Finished-inner ( from_client prf_id -- ) {
22 wait-rectype-out
write-Finished
flush-record ;
\ Read and parse a list of supported signature algorithms (with hash
\ functions). The resulting bit field is returned.
: read-list-sign-algos ( lim -- lim value )
0 { hashes }
read16 open-elt
begin dup while
read8 { hash } read8 { sign }
\ We keep the value if the signature is either 1 (RSA)
\ or 3 (ECDSA), and the hash is one of the SHA-* functions
\ (2 to 6, from SHA-1 to SHA-512); we reject MD5.
hash 2 >= hash 6 <= and
sign 1 = sign 3 = or
and if
hashes 1 sign 1- 2 << hash + << or >hashes
then
repeat
close-elt
hashes ;
\ =======================================================================
\ Compute total chain length. This includes the individual certificate
\ headers, but not the total chain header. This also sets the cert_cur,
\ cert_len and chain_len context fields.
cc: total-chain-length ( -- len ) {
size_t u;
uint32_t total;
total = 0;
for (u = 0; u < ENG->chain_len; u ++) {
total += 3 + (uint32_t)ENG->chain[u].data_len;
}
T0_PUSH(total);
}
\ Get length for current certificate in the chain; if the chain end was
\ reached, then this returns -1.
cc: begin-cert ( -- len ) {
if (ENG->chain_len == 0) {
T0_PUSHi(-1);
} else {
ENG->cert_cur = ENG->chain->data;
ENG->cert_len = ENG->chain->data_len;
ENG->chain ++;
ENG->chain_len --;
T0_PUSH(ENG->cert_len);
}
}
\ Copy a chunk of certificate data into the pad. Returned value is the
\ chunk length, or 0 if the certificate end is reached.
cc: copy-cert-chunk ( -- len ) {
size_t clen;
clen = ENG->cert_len;
if (clen > sizeof ENG->pad) {
clen = sizeof ENG->pad;
}
memcpy(ENG->pad, ENG->cert_cur, clen);
ENG->cert_cur += clen;
ENG->cert_len -= clen;
T0_PUSH(clen);
}
\ Write a Certificate message. Total chain length (excluding the 3-byte
\ header) is returned; it is 0 if the chain is empty.
: write-Certificate ( -- total_chain_len )
11 write8
total-chain-length dup
dup 3 + write24 write24
begin
begin-cert
dup 0< if drop ret then write24
begin copy-cert-chunk dup while
addr-pad swap write-blob
repeat
drop
again ;
cc: x509-start-chain ( by_client -- ) {
const br_x509_class *xc;
uint32_t bc;
bc = T0_POP();
xc = *(ENG->x509ctx);
xc->start_chain(ENG->x509ctx, bc ? ENG->server_name : NULL);
}
cc: x509-start-cert ( length -- ) {
const br_x509_class *xc;
xc = *(ENG->x509ctx);
xc->start_cert(ENG->x509ctx, T0_POP());
}
cc: x509-append ( length -- ) {
const br_x509_class *xc;
size_t len;
xc = *(ENG->x509ctx);
len = T0_POP();
xc->append(ENG->x509ctx, ENG->pad, len);
}
cc: x509-end-cert ( -- ) {
const br_x509_class *xc;
xc = *(ENG->x509ctx);
xc->end_cert(ENG->x509ctx);
}
cc: x509-end-chain ( -- err ) {
const br_x509_class *xc;
xc = *(ENG->x509ctx);
T0_PUSH(xc->end_chain(ENG->x509ctx));
}
cc: get-key-type-usages ( -- key-type-usages ) {
const br_x509_class *xc;
const br_x509_pkey *pk;
unsigned usages;
xc = *(ENG->x509ctx);
pk = xc->get_pkey(ENG->x509ctx, &usages);
if (pk == NULL) {
T0_PUSH(0);
} else {
T0_PUSH(pk->key_type | usages);
}
}
\ Read a Certificate message.
\ Parameter: non-zero if this is a read by the client of a certificate
\ sent by the server; zero otherwise.
\ Returned value:
\ - Empty: 0
\ - Valid: combination of key type and allowed key usages.
\ - Invalid: negative (-x for error code x)
: read-Certificate ( by_client -- key-type-usages )
\ Get header, and check message type.
read-handshake-header 11 = ifnot ERR_UNEXPECTED fail then
\ If the chain is empty, do some special processing.
dup 3 = if
read24 if ERR_BAD_PARAM fail then
swap drop ret
then
\ Start processing the chain through the X.509 engine.
swap x509-start-chain
\ Total chain length is a 24-bit integer.
read24 open-elt
begin
dup while
read24 open-elt
dup x509-start-cert
\ We read the certificate by chunks through the pad, so
\ as to use the existing reading function (read-blob)
\ that also ensures proper hashing.
begin
dup while
dup 256 > if 256 else dup then { len }
addr-pad len read-blob
len x509-append
repeat
close-elt
x509-end-cert
repeat
\ We must close the chain AND the handshake message.
close-elt
close-elt
\ Chain processing is finished; get the error code.
x509-end-chain
dup if neg ret then drop
\ Return key type and usages.
get-key-type-usages ;

File diff suppressed because it is too large Load diff

View file

@ -140,6 +140,35 @@ do_ecdh(br_ssl_server_context *ctx, int prf_id,
ecdh_common(ctx, prf_id, cpoint, cpoint_len, x);
}
/*
* Do the full static ECDH key exchange. When this function is called,
* it has already been verified that the cipher suite uses ECDH (not ECDHE),
* and the client's public key (from its certificate) has type EC and is
* apt for key exchange.
*/
static void
do_static_ecdh(br_ssl_server_context *ctx, int prf_id)
{
unsigned char cpoint[133];
size_t cpoint_len;
const br_x509_class **xc;
const br_x509_pkey *pk;
xc = ctx->eng.x509ctx;
pk = (*xc)->get_pkey(xc, NULL);
cpoint_len = pk->key.ec.qlen;
if (cpoint_len > sizeof cpoint) {
/*
* If the point is larger than our buffer then we need to
* restrict it. Length 2 is not a valid point length, so
* the ECDH will fail.
*/
cpoint_len = 2;
}
memcpy(cpoint, pk->key.ec.q, cpoint_len);
do_ecdh(ctx, prf_id, cpoint, cpoint_len);
}
/*
* Do the ECDHE key exchange (part 1: generation of transient key, and
* computing of the point to send to the client). Returned value is the
@ -258,6 +287,94 @@ do_ecdhe_part2(br_ssl_server_context *ctx, int prf_id,
memset(ctx->ecdhe_key, 0, ctx->ecdhe_key_len);
}
/*
* Offset for hash value within the pad (when obtaining all hash values,
* in preparation for verification of the CertificateVerify message).
* Order is MD5, SHA-1, SHA-224, SHA-256, SHA-384, SHA-512; last value
* is used to get the total length.
*/
static const unsigned char HASH_PAD_OFF[] = { 0, 16, 36, 64, 96, 144, 208 };
/*
* OID for hash functions in RSA signatures.
*/
static const unsigned char HASH_OID_SHA1[] = {
0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A
};
static const unsigned char HASH_OID_SHA224[] = {
0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04
};
static const unsigned char HASH_OID_SHA256[] = {
0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01
};
static const unsigned char HASH_OID_SHA384[] = {
0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02
};
static const unsigned char HASH_OID_SHA512[] = {
0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03
};
static const unsigned char *HASH_OID[] = {
HASH_OID_SHA1,
HASH_OID_SHA224,
HASH_OID_SHA256,
HASH_OID_SHA384,
HASH_OID_SHA512
};
/*
* Verify the signature in CertificateVerify. Returned value is 0 on
* success, or a non-zero error code. Lack of implementation of the
* designated signature algorithm is reported as a "bad signature"
* error (because it means that the peer did not honour our advertised
* set of supported signature algorithms).
*/
static int
verify_CV_sig(br_ssl_server_context *ctx, size_t sig_len)
{
const br_x509_class **xc;
const br_x509_pkey *pk;
int id;
id = ctx->hash_CV_id;
xc = ctx->eng.x509ctx;
pk = (*xc)->get_pkey(xc, NULL);
if (pk->key_type == BR_KEYTYPE_RSA) {
unsigned char tmp[64];
const unsigned char *hash_oid;
if (id == 0) {
hash_oid = NULL;
} else {
hash_oid = HASH_OID[id - 2];
}
if (ctx->eng.irsavrfy == 0) {
return BR_ERR_BAD_SIGNATURE;
}
if (!ctx->eng.irsavrfy(ctx->eng.pad, sig_len,
hash_oid, ctx->hash_CV_len, &pk->key.rsa, tmp)
|| memcmp(tmp, ctx->hash_CV, ctx->hash_CV_len) != 0)
{
return BR_ERR_BAD_SIGNATURE;
}
} else {
if (ctx->eng.iecdsa == 0) {
return BR_ERR_BAD_SIGNATURE;
}
if (!ctx->eng.iecdsa(ctx->eng.iec,
ctx->hash_CV, ctx->hash_CV_len,
&pk->key.ec, ctx->eng.pad, sig_len))
{
return BR_ERR_BAD_SIGNATURE;
}
}
return 0;
}
}
\ =======================================================================
@ -386,26 +503,7 @@ cc: set-max-frag-len ( len -- ) {
\ Open extension value.
read16 open-elt
\ Clear list of supported signature algorithms.
0 addr-hashes set16
\ Get list of algorithms length.
read16 open-elt
begin dup while
read8 { hash } read8 { sign }
\ We keep the value if the signature is either 1 (RSA) or
\ 3 (ECDSA), and the hash is one of the SHA-* functions
\ (2 to 6, from SHA-1 to SHA-512). Note that we reject
\ any use of MD5. Also, we do not keep track of the client
\ preferences.
hash 2 >= hash 6 <= and
sign 1 = sign 3 = or
and if
addr-hashes get16
1 sign 1- 2 << hash + << or addr-hashes set16
then
repeat
close-elt
read-list-sign-algos addr-hashes set16
\ Close extension value.
close-elt ;
@ -440,8 +538,8 @@ cc: call-policy-handler ( -- bool ) {
CTX->policy_vtable, CTX, &choices);
ENG->session.cipher_suite = choices.cipher_suite;
CTX->sign_hash_id = choices.hash_id;
CTX->chain = choices.chain;
CTX->chain_len = choices.chain_len;
ENG->chain = choices.chain;
ENG->chain_len = choices.chain_len;
T0_PUSHi(-(x != 0));
}
@ -667,11 +765,14 @@ cc: save-session ( -- ) {
ok-compression ifnot 40 fail-alert then
\ Filter hash function support by what the server also supports.
\ If no common hash function remains, then ECDHE suites are not
\ possible.
\ If no common hash function remains with RSA and/or ECDSA, then
\ the corresponding ECDHE suites are not possible.
supported-hash-functions drop 257 *
addr-hashes get16 and dup addr-hashes set16
0<> { can-ecdhe }
\ In 'can-ecdhe', bit 12 is set if ECDHE_RSA is possible, bit 13 is
\ set if ECDHE_ECDSA is possible.
dup 0xFF and 0<> neg
swap 8 >> 0<> 2 and or { can-ecdhe }
\ Filter supported curves. If there is no common curve between
\ client and us, then ECDHE suites cannot be used. Note that we
@ -684,6 +785,11 @@ cc: save-session ( -- ) {
resume if -1 ret then
\ We are not resuming, so a new session ID should be generated.
\ We don't check that the new ID is distinct from the one sent
\ by the client because probability of such an event is 2^(-256),
\ i.e. much (much) lower than that of an undetected transmission
\ error or hardware miscomputation, and with similar consequences
\ (handshake simply fails).
addr-session_id 32 mkrand
32 addr-session_id_len set8
@ -692,14 +798,14 @@ cc: save-session ( -- ) {
\ server preference order is enforced, and also in case some
\ suites are filtered out. In particular:
\ -- ECDHE suites are removed if there is no common hash function
\ (for signatures) or no common curve.
\ (for the relevant signature algorithm) or no common curve.
\ -- TLS-1.2-only suites are removed if the negociated version is
\ TLS-1.1 or lower.
addr-client_suites dup >css-off
begin dup css-max < while
dup get16 dup cipher-suite-to-elements
can-ecdhe ifnot
dup 12 >> dup 1 = swap 2 = or if
dup can-ecdhe and ifnot
2drop 0 dup
then
then
@ -791,63 +897,6 @@ cc: save-session ( -- ) {
drop
then ;
\ Compute total chain length. This includes the individual certificate
\ headers, but not the total chain header. This also sets the cert_cur,
\ cert_len and chain_len context fields.
cc: total-chain-length ( -- len ) {
size_t u;
uint32_t total;
total = 0;
for (u = 0; u < CTX->chain_len; u ++) {
total += 3 + (uint32_t)CTX->chain[u].data_len;
}
T0_PUSH(total);
}
\ Get length for current certificate in the chain; if the chain end was
\ reached, then this returns -1.
cc: begin-cert ( -- len ) {
if (CTX->chain_len == 0) {
T0_PUSHi(-1);
} else {
CTX->cert_cur = CTX->chain->data;
CTX->cert_len = CTX->chain->data_len;
CTX->chain ++;
CTX->chain_len --;
T0_PUSH(CTX->cert_len);
}
}
\ Copy a chunk of certificate data into the pad. Returned value is the
\ chunk length, or 0 if the certificate end is reached.
cc: copy-cert-chunk ( -- len ) {
size_t clen;
clen = CTX->cert_len;
if (clen > sizeof ENG->pad) {
clen = sizeof ENG->pad;
}
memcpy(ENG->pad, CTX->cert_cur, clen);
CTX->cert_cur += clen;
CTX->cert_len -= clen;
T0_PUSH(clen);
}
\ Write the server Certificate.
: write-Certificate ( -- )
11 write8
total-chain-length
dup 3 + write24 write24
begin
begin-cert
dup 0< if drop ret then write24
begin copy-cert-chunk dup while
addr-pad swap write-blob
repeat
drop
again ;
\ Do the first part of ECDHE. Returned value is the computed signature
\ length, or a negative error code on error.
cc: do-ecdhe-part1 ( curve -- len ) {
@ -900,6 +949,166 @@ cc: do-ecdhe-part1 ( curve -- len ) {
sig-len write16
addr-pad sig-len write-blob ;
\ Get length of the list of anchor names to send to the client. The length
\ includes the per-name 2-byte header, but _not_ the 2-byte header for
\ the list itself. If no client certificate is requested, then this
\ returns 0.
cc: ta-names-total-length ( -- len ) {
size_t u, len;
len = 0;
if (CTX->ta_names != NULL) {
for (u = 0; u < CTX->num_tas; u ++) {
len += CTX->ta_names[u].len + 2;
}
} else if (CTX->tas != NULL) {
for (u = 0; u < CTX->num_tas; u ++) {
len += CTX->tas[u].dn.len + 2;
}
}
T0_PUSH(len);
}
\ Compute length and optionally write the contents of the list of
\ supported client authentication methods.
: write-list-auth ( do_write -- len )
0
addr-cipher_suite get16 use-ecdh? if
2+ over if 65 write8 66 write8 then
then
supports-rsa-sign? if 1+ over if 1 write8 then then
supports-ecdsa? if 1+ over if 64 write8 then then
swap drop ;
: write-signhash-inner2 ( dow algo hashes len id -- dow algo hashes len )
{ id }
over 1 id << and ifnot ret then
2+
3 pick if id write8 2 pick write8 then ;
: write-signhash-inner1 ( dow algo hashes -- dow len )
0
4 write-signhash-inner2
5 write-signhash-inner2
6 write-signhash-inner2
3 write-signhash-inner2
2 write-signhash-inner2
-rot 2drop ;
\ Compute length and optionally write the contents of the list of
\ supported sign+hash algorithms.
: write-list-signhash ( do_write -- len )
0 { len }
\ If supporting neither RSA nor ECDSA in the engine, then we
\ will do only static ECDH, and thus we claim support for
\ everything (for the X.509 validator).
supports-rsa-sign? supports-ecdsa? or ifnot
1 0x7C write-signhash-inner1 >len
3 0x7C write-signhash-inner1 len +
swap drop ret
then
supports-rsa-sign? if
1 supported-hash-functions drop
write-signhash-inner1 >len
then
supports-ecdsa? if
3 supported-hash-functions drop
write-signhash-inner1 len + >len
then
drop len ;
\ Initialise index for sending the list of anchor DN.
cc: begin-ta-name-list ( -- ) {
CTX->cur_dn_index = 0;
}
\ Switch to next DN in the list. Returned value is the DN length, or -1
\ if the end of the list was reached.
cc: begin-ta-name ( -- len ) {
const br_x500_name *dn;
if (CTX->cur_dn_index >= CTX->num_tas) {
T0_PUSHi(-1);
} else {
if (CTX->ta_names == NULL) {
dn = &CTX->tas[CTX->cur_dn_index].dn;
} else {
dn = &CTX->ta_names[CTX->cur_dn_index];
}
CTX->cur_dn_index ++;
CTX->cur_dn = dn->data;
CTX->cur_dn_len = dn->len;
T0_PUSH(CTX->cur_dn_len);
}
}
\ Copy a chunk of the current DN into the pad. Returned value is the
\ chunk length; this is 0 when the end of the current DN is reached.
cc: copy-dn-chunk ( -- len ) {
size_t clen;
clen = CTX->cur_dn_len;
if (clen > sizeof ENG->pad) {
clen = sizeof ENG->pad;
}
memcpy(ENG->pad, CTX->cur_dn, clen);
CTX->cur_dn += clen;
CTX->cur_dn_len -= clen;
T0_PUSH(clen);
}
\ Write a CertificateRequest message.
: write-CertificateRequest ( -- )
\ The list of client authentication types includes:
\ rsa_sign (1)
\ ecdsa_sign (64)
\ rsa_fixed_ecdh (65)
\ ecdsa_fixed_ecdh (66)
\ rsa_sign and ecdsa_sign require, respectively, RSA and ECDSA
\ support. Static ECDH requires that the cipher suite is ECDH.
\ When we ask for static ECDH, we always send both rsa_fixed_ecdh
\ and ecdsa_fixed_ecdh because what matters there is what the
\ X.509 engine may support, and we do not control that.
\
\ With TLS 1.2, we must also send a list of supported signature
\ and hash algorithms. That list is supposed to qualify both
\ the engine itself, and the X.509 validator, which are separate
\ in BearSSL. There again, we use the engine capabilities in that
\ list, and resort to a generic all-support list if only
\ static ECDH is accepted.
\
\ (In practice, client implementations tend to have at most one
\ or two certificates, and send the chain regardless of what
\ algorithms are used in it.)
0 write-list-auth
addr-version get16 0x0303 >= if
2+ 0 write-list-signhash +
then
ta-names-total-length + 3 +
\ Message header
13 write8 write24
\ List of authentication methods
0 write-list-auth write8 1 write-list-auth drop
\ For TLS 1.2+, list of sign+hash
addr-version get16 0x0303 >= if
0 write-list-signhash write16 1 write-list-signhash drop
then
\ Trust anchor names
ta-names-total-length write16
begin-ta-name-list
begin
begin-ta-name
dup 0< if drop ret then write16
begin copy-dn-chunk dup while
addr-pad swap write-blob
repeat
drop
again ;
\ Write the Server Hello Done message.
: write-ServerHelloDone ( -- )
14 write8 0 write24 ;
@ -927,11 +1136,18 @@ cc: do-ecdhe-part2 ( len prf_id -- ) {
do_ecdhe_part2(CTX, prf_id, ENG->pad, len);
}
\ Read the Client Key Exchange.
: read-ClientKeyExchange ( -- )
\ Get header, and check message type.
read-handshake-header 16 = ifnot ERR_UNEXPECTED fail then
\ Perform static ECDH. The point from the client is the public key
\ extracted from its certificate.
cc: do-static-ecdh ( prf_id -- ) {
do_static_ecdh(CTX, T0_POP());
}
\ Read a ClientKeyExchange header.
: read-ClientKeyExchange-header ( -- len )
read-handshake-header 16 = ifnot ERR_UNEXPECTED fail then ;
\ Read the Client Key Exchange contents (non-empty case).
: read-ClientKeyExchange-contents ( lim -- )
\ What we should get depends on the cipher suite.
addr-cipher_suite get16 use-rsa-keyx? if
\ RSA key exchange: we expect a RSA-encrypted value.
@ -951,6 +1167,116 @@ cc: do-ecdhe-part2 ( len prf_id -- ) {
then
close-elt ;
\ Read the Client Key Exchange (normal case).
: read-ClientKeyExchange ( -- )
read-ClientKeyExchange-header
read-ClientKeyExchange-contents ;
\ Obtain all possible hash values for handshake messages so far. This
\ is done because we need the hash value for the CertificateVerify
\ _before_ knowing which hash function will actually be used, as this
\ information is obtained from decoding the message header itself.
\ All hash values are stored in the pad (208 bytes in total).
cc: compute-hash-CV ( -- ) {
int i;
for (i = 1; i <= 6; i ++) {
br_multihash_out(&ENG->mhash, i,
ENG->pad + HASH_PAD_OFF[i - 1]);
}
}
\ Copy the proper hash value from the pad into the dedicated buffer.
\ Returned value is true (-1) on success, false (0) on error (error
\ being an unimplemented hash function). The id has already been verified
\ to be either 0 (for MD5+SHA-1) or one of the SHA-* functions.
cc: copy-hash-CV ( hash_id -- bool ) {
int id = T0_POP();
size_t off, len;
if (id == 0) {
off = 0;
len = 36;
} else {
if (br_multihash_getimpl(&ENG->mhash, id) == 0) {
T0_PUSH(0);
T0_RET();
}
off = HASH_PAD_OFF[id - 1];
len = HASH_PAD_OFF[id] - off;
}
memcpy(CTX->hash_CV, ENG->pad + off, len);
CTX->hash_CV_len = len;
CTX->hash_CV_id = id;
T0_PUSHi(-1);
}
\ Verify signature in CertificateVerify. Output is 0 on success, or a
\ non-zero error code.
cc: verify-CV-sig ( sig-len -- err ) {
int err;
err = verify_CV_sig(CTX, T0_POP());
T0_PUSHi(err);
}
\ Process static ECDH.
: process-static-ECDH ( ktu -- )
\ Static ECDH is allowed only if the cipher suite uses ECDH, and
\ the client's public key has type EC and allows key exchange.
\ BR_KEYTYPE_KEYX is 0x10, and BR_KEYTYPE_EC is 2.
0x1F and 0x12 = ifnot ERR_WRONG_KEY_USAGE fail then
addr-cipher_suite get16
dup use-ecdh? ifnot ERR_UNEXPECTED fail then
prf-id
do-static-ecdh ;
\ Read CertificateVerify header.
: read-CertificateVerify-header ( -- lim )
compute-hash-CV
read-handshake-header 15 = ifnot ERR_UNEXPECTED fail then ;
\ Read CertificateVerify. The client key type + usage is expected on the
\ stack.
: read-CertificateVerify ( ktu -- )
\ Check that the key allows for signatures.
dup 0x20 and ifnot ERR_WRONG_KEY_USAGE fail then
0x0F and { key-type }
\ Get header.
read-CertificateVerify-header
\ With TLS 1.2+, there is an explicit hash + signature indication,
\ which must be compatible with the key type.
addr-version get16 0x0303 >= if
\ Get hash function, then signature algorithm. The
\ signature algorithm is 1 (RSA) or 3 (ECDSA) while our
\ symbolic constants for key types are 1 (RSA) or 2 (EC).
read16
dup 0xFF and 1+ 1 >> key-type = ifnot
ERR_BAD_SIGNATURE fail
then
8 >>
\ We support only SHA-1, SHA-224, SHA-256, SHA-384
\ and SHA-512. We explicitly reject MD5.
dup 2 < over 6 > or if ERR_INVALID_ALGORITHM fail then
else
\ With TLS 1.0 and 1.1, hash is MD5+SHA-1 (0) for RSA,
\ SHA-1 (2) for ECDSA.
key-type 0x01 = if 0 else 2 then
then
copy-hash-CV ifnot ERR_INVALID_ALGORITHM fail then
\ Read signature.
read16 dup { sig-len }
dup 512 > if ERR_LIMIT_EXCEEDED fail then
addr-pad swap read-blob
sig-len verify-CV-sig
dup if fail then drop
close-elt ;
\ Send a HelloRequest.
: send-HelloRequest ( -- )
flush-record
@ -974,11 +1300,54 @@ cc: do-ecdhe-part2 ( len prf_id -- ) {
else
\ Not a session resumption
write-ServerHello
write-Certificate
write-Certificate drop
write-ServerKeyExchange
ta-names-total-length if
write-CertificateRequest
then
write-ServerHelloDone
flush-record
\ If we sent a CertificateRequest then we expect a
\ Certificate message.
ta-names-total-length if
\ Read client certificate.
0 read-Certificate
choice
dup 0< uf
\ Client certificate validation failed.
2 flag? ifnot neg fail then
drop
read-ClientKeyExchange
read-CertificateVerify-header
dup skip-blob drop
enduf
dup 0= uf
\ Client sent no certificate at all.
drop
2 flag? ifnot
ERR_NO_CLIENT_AUTH fail
then
read-ClientKeyExchange
enduf
\ Client certificate was validated.
read-ClientKeyExchange-header
dup ifnot
\ Empty ClientKeyExchange.
drop
process-static-ECDH
else
read-ClientKeyExchange-contents
read-CertificateVerify
then
endchoice
else
\ No client certificate request, we just expect
\ a non-empty ClientKeyExchange.
read-ClientKeyExchange
then
0 read-CCS-Finished
0 write-CCS-Finished
save-session

View file

@ -36,7 +36,7 @@ se_choose(const br_ssl_server_policy_class **pctx,
pc = (br_ssl_server_policy_ec_context *)pctx;
st = br_ssl_server_get_client_suites(cc, &st_num);
hash_id = br_ssl_choose_hash(br_ssl_server_get_client_hashes(cc));
hash_id = br_ssl_choose_hash(br_ssl_server_get_client_hashes(cc) >> 8);
if (cc->eng.session.version < BR_TLS12) {
hash_id = br_sha1_ID;
}

View file

@ -27,29 +27,29 @@
/* see bearssl_x509.h */
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)
{
ctx->vtable = &br_x509_knownkey_vtable;
ctx->pkey.key_type = BR_KEYTYPE_RSA;
ctx->pkey.key.rsa = *pk;
ctx->usages = usages;
}
/* see bearssl_x509.h */
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)
{
ctx->vtable = &br_x509_knownkey_vtable;
ctx->pkey.key_type = BR_KEYTYPE_EC;
ctx->pkey.key.ec = *pk;
ctx->usages = usages;
}
static void
kk_start_chain(const br_x509_class **ctx,
unsigned expected_key_type, const char *server_name)
kk_start_chain(const br_x509_class **ctx, const char *server_name)
{
(void)ctx;
(void)expected_key_type;
(void)server_name;
}
@ -82,9 +82,15 @@ kk_end_chain(const br_x509_class **ctx)
}
static const br_x509_pkey *
kk_get_pkey(const br_x509_class *const *ctx)
kk_get_pkey(const br_x509_class *const *ctx, unsigned *usages)
{
return &((const br_x509_knownkey_context *)ctx)->pkey;
const br_x509_knownkey_context *xc;
xc = (const br_x509_knownkey_context *)ctx;
if (usages != NULL) {
*usages = xc->usages;
}
return &xc->pkey;
}
/* see bearssl_x509.h */

View file

@ -239,8 +239,7 @@ br_x509_minimal_init(br_x509_minimal_context *ctx,
}
static void
xm_start_chain(const br_x509_class **ctx,
unsigned expected_key_type, const char *server_name)
xm_start_chain(const br_x509_class **ctx, const char *server_name)
{
br_x509_minimal_context *cc;
@ -251,7 +250,6 @@ xm_start_chain(const br_x509_class **ctx,
cc->cpu.dp = cc->dp_stack;
cc->cpu.rp = cc->rp_stack;
br_x509_minimal_init_main(&cc->cpu);
cc->expected_key_type = expected_key_type;
if (server_name == NULL || *server_name == 0) {
cc->server_name = NULL;
} else {
@ -320,7 +318,7 @@ xm_end_chain(const br_x509_class **ctx)
}
static const br_x509_pkey *
xm_get_pkey(const br_x509_class *const *ctx)
xm_get_pkey(const br_x509_class *const *ctx, unsigned *usages)
{
br_x509_minimal_context *cc;
@ -328,6 +326,9 @@ xm_get_pkey(const br_x509_class *const *ctx)
if (cc->err == BR_ERR_X509_OK
|| cc->err == BR_ERR_X509_NOT_TRUSTED)
{
if (usages != NULL) {
*usages = cc->key_usages;
}
return &((br_x509_minimal_context *)ctx)->pkey;
} else {
return NULL;
@ -518,7 +519,6 @@ static const uint8_t t0_codeblock[] = {
T0_INT1(BR_ERR_X509_UNEXPECTED), 0x00, 0x00, 0x01,
T0_INT1(BR_ERR_X509_UNSUPPORTED), 0x00, 0x00, 0x01,
T0_INT1(BR_ERR_X509_WEAK_PUBLIC_KEY), 0x00, 0x00, 0x01,
T0_INT1(BR_ERR_X509_WRONG_KEY_TYPE), 0x00, 0x00, 0x01,
T0_INT1(BR_KEYTYPE_EC), 0x00, 0x00, 0x01, T0_INT1(BR_KEYTYPE_RSA),
0x00, 0x00, 0x01, T0_INT2(offsetof(CONTEXT_NAME, cert_length)), 0x00,
0x00, 0x01, T0_INT2(offsetof(CONTEXT_NAME, cert_sig)), 0x00, 0x00,
@ -527,182 +527,182 @@ static const uint8_t t0_codeblock[] = {
0x01, T0_INT2(offsetof(CONTEXT_NAME, cert_sig_len)), 0x00, 0x00, 0x01,
T0_INT2(offsetof(CONTEXT_NAME, cert_signer_key_type)), 0x00, 0x00,
0x01, T0_INT2(offsetof(CONTEXT_NAME, current_dn_hash)), 0x00, 0x00,
0x01, T0_INT2(offsetof(CONTEXT_NAME, expected_key_type)), 0x00, 0x00,
0x01, T0_INT2(offsetof(br_x509_minimal_context, pkey_data)), 0x01,
0x01, T0_INT2(offsetof(CONTEXT_NAME, key_usages)), 0x00, 0x00, 0x01,
T0_INT2(offsetof(br_x509_minimal_context, pkey_data)), 0x01,
T0_INT2(BR_X509_BUFSIZE_KEY), 0x00, 0x00, 0x01,
T0_INT2(offsetof(CONTEXT_NAME, min_rsa_size)), 0x00, 0x00, 0x01,
T0_INT2(offsetof(CONTEXT_NAME, next_dn_hash)), 0x00, 0x00, 0x01,
T0_INT2(offsetof(CONTEXT_NAME, num_certs)), 0x00, 0x00, 0x01,
T0_INT2(offsetof(CONTEXT_NAME, pad)), 0x00, 0x00, 0x01,
T0_INT2(offsetof(CONTEXT_NAME, saved_dn_hash)), 0x00, 0x00, 0x81, 0x31,
0x6E, 0x00, 0x00, 0x01, 0x80, 0x73, 0x00, 0x00, 0x01, 0x80, 0x7C, 0x00,
T0_INT2(offsetof(CONTEXT_NAME, saved_dn_hash)), 0x00, 0x00, 0x81, 0x2F,
0x6C, 0x00, 0x00, 0x01, 0x80, 0x73, 0x00, 0x00, 0x01, 0x80, 0x7C, 0x00,
0x00, 0x01, 0x81, 0x02, 0x00, 0x00, 0x01, 0x82, 0x08, 0x00, 0x00, 0x01,
0x81, 0x70, 0x00, 0x00, 0x01, 0x81, 0x64, 0x00, 0x04, 0x03, 0x00, 0x03,
0x01, 0x03, 0x02, 0x03, 0x03, 0x02, 0x03, 0x02, 0x01, 0x11, 0x06, 0x07,
0x02, 0x02, 0x02, 0x00, 0x0D, 0x04, 0x05, 0x02, 0x03, 0x02, 0x01, 0x0D,
0x00, 0x02, 0x03, 0x00, 0x03, 0x01, 0x23, 0x02, 0x01, 0x13, 0x39, 0x02,
0x00, 0x0F, 0x15, 0x00, 0x00, 0x05, 0x02, 0x4F, 0x26, 0x00, 0x00, 0x06,
0x02, 0x50, 0x26, 0x00, 0x00, 0x01, 0x10, 0x73, 0x00, 0x00, 0x11, 0x05,
0x02, 0x53, 0x26, 0x70, 0x00, 0x00, 0x11, 0x05, 0x02, 0x53, 0x26, 0x71,
0x00, 0x00, 0x06, 0x02, 0x49, 0x26, 0x00, 0x00, 0x01, 0x82, 0x00, 0x00,
0x00, 0x23, 0x1E, 0x01, 0x08, 0x0E, 0x39, 0x3D, 0x1E, 0x09, 0x00, 0x09,
0x03, 0x00, 0x59, 0x29, 0x81, 0x1D, 0x37, 0x81, 0x1D, 0x81, 0x20, 0x23,
0x01, 0x20, 0x11, 0x06, 0x15, 0x22, 0x70, 0x81, 0x1B, 0x81, 0x20, 0x01,
0x02, 0x74, 0x81, 0x1E, 0x01, 0x02, 0x12, 0x06, 0x02, 0x54, 0x26, 0x75,
0x81, 0x20, 0x01, 0x02, 0x74, 0x81, 0x1C, 0x81, 0x1D, 0x81, 0x2A, 0x81,
0x10, 0x63, 0x5F, 0x1F, 0x16, 0x81, 0x1D, 0x81, 0x15, 0x27, 0x67, 0x06,
0x02, 0x48, 0x26, 0x81, 0x15, 0x27, 0x6E, 0x06, 0x02, 0x48, 0x26, 0x75,
0x81, 0x10, 0x02, 0x00, 0x06, 0x05, 0x2B, 0x03, 0x01, 0x04, 0x08, 0x5F,
0x66, 0x1F, 0x25, 0x05, 0x02, 0x47, 0x26, 0x66, 0x63, 0x1F, 0x16, 0x81,
0x1D, 0x81, 0x1D, 0x81, 0x11, 0x05, 0x02, 0x54, 0x26, 0x81, 0x24, 0x24,
0x06, 0x2C, 0x81, 0x2A, 0x81, 0x12, 0x81, 0x1D, 0x61, 0x81, 0x18, 0x03,
0x03, 0x61, 0x39, 0x02, 0x03, 0x09, 0x39, 0x02, 0x03, 0x0A, 0x81, 0x18,
0x03, 0x04, 0x75, 0x62, 0x28, 0x01, 0x81, 0x00, 0x09, 0x02, 0x03, 0x12,
0x06, 0x02, 0x55, 0x26, 0x75, 0x58, 0x03, 0x02, 0x04, 0x3E, 0x81, 0x01,
0x24, 0x06, 0x37, 0x81, 0x11, 0x05, 0x02, 0x54, 0x26, 0x68, 0x24, 0x06,
0x04, 0x01, 0x17, 0x04, 0x12, 0x69, 0x24, 0x06, 0x04, 0x01, 0x18, 0x04,
0x0A, 0x6A, 0x24, 0x06, 0x04, 0x01, 0x19, 0x04, 0x02, 0x54, 0x26, 0x03,
0x05, 0x75, 0x81, 0x12, 0x23, 0x03, 0x06, 0x23, 0x61, 0x32, 0x0D, 0x06,
0x02, 0x4D, 0x26, 0x81, 0x13, 0x57, 0x03, 0x02, 0x04, 0x02, 0x54, 0x26,
0x75, 0x02, 0x00, 0x06, 0x33, 0x60, 0x2A, 0x01, 0x0F, 0x15, 0x23, 0x06,
0x09, 0x02, 0x02, 0x11, 0x05, 0x02, 0x56, 0x26, 0x04, 0x01, 0x22, 0x02,
0x02, 0x58, 0x2E, 0x11, 0x06, 0x08, 0x22, 0x02, 0x03, 0x02, 0x04, 0x1D,
0x04, 0x10, 0x57, 0x2E, 0x11, 0x06, 0x08, 0x22, 0x02, 0x05, 0x02, 0x06,
0x1C, 0x04, 0x03, 0x54, 0x26, 0x22, 0x04, 0x24, 0x02, 0x02, 0x58, 0x2E,
0x11, 0x06, 0x08, 0x22, 0x02, 0x03, 0x02, 0x04, 0x21, 0x04, 0x10, 0x57,
0x2E, 0x11, 0x06, 0x08, 0x22, 0x02, 0x05, 0x02, 0x06, 0x20, 0x04, 0x03,
0x54, 0x26, 0x22, 0x23, 0x06, 0x01, 0x26, 0x22, 0x01, 0x00, 0x03, 0x07,
0x81, 0x21, 0x01, 0x21, 0x81, 0x07, 0x01, 0x22, 0x81, 0x07, 0x23, 0x01,
0x23, 0x11, 0x06, 0x81, 0x36, 0x22, 0x70, 0x81, 0x1B, 0x81, 0x1D, 0x23,
0x06, 0x81, 0x28, 0x01, 0x00, 0x03, 0x08, 0x81, 0x1D, 0x81, 0x11, 0x22,
0x81, 0x20, 0x23, 0x01, 0x01, 0x11, 0x06, 0x06, 0x81, 0x14, 0x03, 0x08,
0x81, 0x20, 0x01, 0x04, 0x74, 0x81, 0x1B, 0x6D, 0x24, 0x06, 0x11, 0x02,
0x00, 0x06, 0x04, 0x81, 0x2B, 0x04, 0x06, 0x81, 0x0E, 0x01, 0x7F, 0x03,
0x07, 0x04, 0x80, 0x72, 0x81, 0x09, 0x24, 0x06, 0x07, 0x02, 0x00, 0x81,
0x0F, 0x04, 0x80, 0x66, 0x81, 0x2D, 0x24, 0x06, 0x13, 0x02, 0x00, 0x06,
0x0A, 0x01, 0x00, 0x03, 0x01, 0x81, 0x0D, 0x03, 0x01, 0x04, 0x02, 0x81,
0x2B, 0x04, 0x80, 0x4E, 0x6C, 0x24, 0x06, 0x05, 0x81, 0x2B, 0x04, 0x80,
0x45, 0x81, 0x30, 0x24, 0x06, 0x04, 0x81, 0x2B, 0x04, 0x3C, 0x81, 0x08,
0x24, 0x06, 0x04, 0x81, 0x2B, 0x04, 0x33, 0x81, 0x2E, 0x24, 0x06, 0x04,
0x81, 0x2B, 0x04, 0x2A, 0x76, 0x24, 0x06, 0x04, 0x81, 0x2B, 0x04, 0x22,
0x81, 0x00, 0x24, 0x06, 0x04, 0x81, 0x2B, 0x04, 0x19, 0x6B, 0x24, 0x06,
0x04, 0x81, 0x2B, 0x04, 0x11, 0x81, 0x2F, 0x24, 0x06, 0x04, 0x81, 0x2B,
0x04, 0x08, 0x02, 0x08, 0x06, 0x02, 0x46, 0x26, 0x81, 0x2B, 0x75, 0x75,
0x04, 0xFE, 0x54, 0x75, 0x75, 0x04, 0x08, 0x01, 0x7F, 0x11, 0x05, 0x02,
0x53, 0x26, 0x22, 0x75, 0x38, 0x02, 0x00, 0x06, 0x08, 0x02, 0x01, 0x3A,
0x2D, 0x05, 0x02, 0x42, 0x26, 0x02, 0x00, 0x06, 0x01, 0x17, 0x02, 0x00,
0x02, 0x07, 0x2D, 0x05, 0x02, 0x4E, 0x26, 0x81, 0x20, 0x72, 0x81, 0x1B,
0x81, 0x11, 0x06, 0x81, 0x07, 0x81, 0x25, 0x24, 0x06, 0x08, 0x01, 0x02,
0x58, 0x81, 0x02, 0x04, 0x80, 0x6C, 0x81, 0x26, 0x24, 0x06, 0x08, 0x01,
0x03, 0x58, 0x81, 0x03, 0x04, 0x80, 0x5F, 0x81, 0x27, 0x24, 0x06, 0x08,
0x01, 0x04, 0x58, 0x81, 0x04, 0x04, 0x80, 0x52, 0x81, 0x28, 0x24, 0x06,
0x08, 0x01, 0x05, 0x58, 0x81, 0x05, 0x04, 0x80, 0x45, 0x81, 0x29, 0x24,
0x06, 0x07, 0x01, 0x06, 0x58, 0x81, 0x06, 0x04, 0x39, 0x7B, 0x24, 0x06,
0x07, 0x01, 0x02, 0x57, 0x81, 0x02, 0x04, 0x2E, 0x7C, 0x24, 0x06, 0x07,
0x01, 0x03, 0x57, 0x81, 0x03, 0x04, 0x23, 0x7D, 0x24, 0x06, 0x07, 0x01,
0x04, 0x57, 0x81, 0x04, 0x04, 0x18, 0x7E, 0x24, 0x06, 0x07, 0x01, 0x05,
0x57, 0x81, 0x05, 0x04, 0x0D, 0x7F, 0x24, 0x06, 0x07, 0x01, 0x06, 0x57,
0x81, 0x06, 0x04, 0x02, 0x54, 0x26, 0x5C, 0x33, 0x5E, 0x35, 0x1B, 0x23,
0x05, 0x02, 0x54, 0x26, 0x5B, 0x35, 0x04, 0x02, 0x54, 0x26, 0x81, 0x2A,
0x81, 0x12, 0x23, 0x01, T0_INT2(BR_X509_BUFSIZE_SIG), 0x12, 0x06, 0x02,
0x4D, 0x26, 0x23, 0x5D, 0x33, 0x5A, 0x81, 0x13, 0x75, 0x75, 0x01, 0x00,
0x59, 0x34, 0x18, 0x00, 0x00, 0x01, 0x30, 0x0A, 0x23, 0x01, 0x00, 0x01,
0x09, 0x6F, 0x05, 0x02, 0x45, 0x26, 0x00, 0x00, 0x2E, 0x2E, 0x00, 0x00,
0x01, 0x81, 0x08, 0x00, 0x00, 0x01, 0x81, 0x10, 0x00, 0x00, 0x01, 0x81,
0x19, 0x00, 0x00, 0x01, 0x81, 0x22, 0x00, 0x00, 0x01, 0x81, 0x2B, 0x00,
0x00, 0x01, 0x82, 0x04, 0x00, 0x00, 0x01, 0x80, 0x6B, 0x00, 0x00, 0x01,
0x3D, 0x00, 0x00, 0x01, 0x80, 0x43, 0x00, 0x00, 0x01, 0x80, 0x4D, 0x00,
0x00, 0x01, 0x80, 0x57, 0x00, 0x00, 0x01, 0x80, 0x61, 0x00, 0x00, 0x2E,
0x11, 0x06, 0x07, 0x3F, 0x81, 0x1B, 0x81, 0x2A, 0x81, 0x21, 0x00, 0x00,
0x01, 0x81, 0x78, 0x00, 0x00, 0x01, 0x81, 0x68, 0x00, 0x00, 0x01, 0x7F,
0x78, 0x19, 0x01, 0x00, 0x78, 0x19, 0x04, 0x7A, 0x00, 0x01, 0x81, 0x34,
0x00, 0x01, 0x7A, 0x0D, 0x06, 0x02, 0x4C, 0x26, 0x23, 0x03, 0x00, 0x0A,
0x02, 0x00, 0x00, 0x01, 0x01, 0x00, 0x03, 0x00, 0x81, 0x1D, 0x23, 0x06,
0x18, 0x81, 0x20, 0x01, 0x22, 0x11, 0x06, 0x0C, 0x71, 0x81, 0x1F, 0x22,
0x2B, 0x02, 0x00, 0x2D, 0x03, 0x00, 0x04, 0x03, 0x22, 0x81, 0x1C, 0x04,
0x65, 0x75, 0x02, 0x00, 0x00, 0x00, 0x81, 0x1D, 0x81, 0x21, 0x23, 0x01,
0x01, 0x11, 0x06, 0x0A, 0x81, 0x14, 0x05, 0x02, 0x4E, 0x26, 0x81, 0x21,
0x04, 0x02, 0x4E, 0x26, 0x23, 0x01, 0x02, 0x11, 0x06, 0x0E, 0x22, 0x71,
0x81, 0x1E, 0x64, 0x29, 0x3E, 0x0D, 0x06, 0x02, 0x4E, 0x26, 0x81, 0x21,
0x01, 0x7F, 0x10, 0x06, 0x02, 0x53, 0x26, 0x22, 0x75, 0x00, 0x02, 0x06,
0x10, 0x60, 0x2A, 0x01, 0x10, 0x15, 0x06, 0x04, 0x01, 0x30, 0x04, 0x03,
0x01, 0x81, 0x40, 0x04, 0x02, 0x01, 0x04, 0x03, 0x00, 0x81, 0x20, 0x01,
0x03, 0x74, 0x81, 0x1B, 0x81, 0x22, 0x03, 0x01, 0x02, 0x01, 0x01, 0x07,
0x12, 0x06, 0x02, 0x53, 0x26, 0x23, 0x01, 0x00, 0x2E, 0x11, 0x06, 0x05,
0x22, 0x4A, 0x26, 0x04, 0x17, 0x01, 0x01, 0x2E, 0x11, 0x06, 0x0B, 0x22,
0x81, 0x22, 0x02, 0x01, 0x14, 0x02, 0x01, 0x0E, 0x04, 0x06, 0x22, 0x81,
0x22, 0x01, 0x00, 0x22, 0x02, 0x00, 0x15, 0x05, 0x02, 0x4A, 0x26, 0x81,
0x2A, 0x00, 0x02, 0x36, 0x01, 0x00, 0x65, 0x35, 0x81, 0x1D, 0x23, 0x06,
0x80, 0x6F, 0x81, 0x20, 0x01, 0x11, 0x73, 0x81, 0x1B, 0x23, 0x05, 0x02,
0x41, 0x26, 0x23, 0x06, 0x80, 0x5B, 0x81, 0x1D, 0x81, 0x20, 0x01, 0x06,
0x74, 0x81, 0x1B, 0x23, 0x01, 0x03, 0x11, 0x06, 0x1E, 0x81, 0x22, 0x01,
0x10, 0x0E, 0x03, 0x00, 0x81, 0x22, 0x01, 0x08, 0x0E, 0x02, 0x00, 0x09,
0x03, 0x00, 0x81, 0x22, 0x02, 0x00, 0x09, 0x01, 0x82, 0xD4, 0x88, 0x03,
0x11, 0x03, 0x01, 0x81, 0x2A, 0x02, 0x01, 0x06, 0x23, 0x81, 0x20, 0x23,
0x23, 0x01, 0x0C, 0x11, 0x39, 0x01, 0x13, 0x11, 0x2D, 0x39, 0x01, 0x14,
0x11, 0x2D, 0x06, 0x07, 0x71, 0x81, 0x1F, 0x22, 0x75, 0x04, 0x07, 0x22,
0x01, 0x00, 0x65, 0x35, 0x81, 0x2A, 0x04, 0x02, 0x81, 0x2A, 0x04, 0xFF,
0x21, 0x75, 0x04, 0xFF, 0x0D, 0x75, 0x1A, 0x00, 0x00, 0x81, 0x20, 0x01,
0x06, 0x74, 0x81, 0x1F, 0x00, 0x00, 0x81, 0x20, 0x01, 0x03, 0x74, 0x81,
0x1B, 0x81, 0x22, 0x06, 0x02, 0x52, 0x26, 0x00, 0x00, 0x39, 0x23, 0x06,
0x07, 0x2F, 0x23, 0x06, 0x01, 0x19, 0x04, 0x76, 0x3F, 0x00, 0x00, 0x01,
0x01, 0x74, 0x81, 0x1A, 0x01, 0x01, 0x10, 0x06, 0x02, 0x40, 0x26, 0x81,
0x22, 0x3B, 0x00, 0x04, 0x81, 0x20, 0x23, 0x01, 0x17, 0x01, 0x18, 0x6F,
0x05, 0x02, 0x45, 0x26, 0x01, 0x18, 0x11, 0x03, 0x00, 0x71, 0x81, 0x1B,
0x81, 0x16, 0x02, 0x00, 0x06, 0x0D, 0x01, 0x80, 0x64, 0x08, 0x03, 0x01,
0x81, 0x16, 0x02, 0x01, 0x09, 0x04, 0x0E, 0x23, 0x01, 0x32, 0x0D, 0x06,
0x04, 0x01, 0x80, 0x64, 0x09, 0x01, 0x8E, 0x6C, 0x09, 0x03, 0x01, 0x02,
0x01, 0x01, 0x82, 0x6D, 0x08, 0x02, 0x01, 0x01, 0x03, 0x09, 0x01, 0x04,
0x0C, 0x09, 0x02, 0x01, 0x01, 0x80, 0x63, 0x09, 0x01, 0x80, 0x64, 0x0C,
0x0A, 0x02, 0x01, 0x01, 0x83, 0x0F, 0x09, 0x01, 0x83, 0x10, 0x0C, 0x09,
0x03, 0x03, 0x01, 0x01, 0x01, 0x0C, 0x81, 0x17, 0x3E, 0x01, 0x01, 0x0E,
0x02, 0x01, 0x01, 0x04, 0x07, 0x3C, 0x02, 0x01, 0x01, 0x80, 0x64, 0x07,
0x3B, 0x02, 0x01, 0x01, 0x83, 0x10, 0x07, 0x3C, 0x2D, 0x15, 0x06, 0x03,
0x01, 0x18, 0x09, 0x81, 0x0B, 0x09, 0x77, 0x23, 0x01, 0x05, 0x14, 0x02,
0x03, 0x09, 0x03, 0x03, 0x01, 0x1F, 0x15, 0x01, 0x01, 0x39, 0x81, 0x17,
0x02, 0x03, 0x09, 0x3E, 0x03, 0x03, 0x01, 0x00, 0x01, 0x17, 0x81, 0x17,
0x01, 0x9C, 0x10, 0x08, 0x03, 0x02, 0x01, 0x00, 0x01, 0x3B, 0x81, 0x17,
0x01, 0x3C, 0x08, 0x02, 0x02, 0x09, 0x03, 0x02, 0x01, 0x00, 0x01, 0x3C,
0x81, 0x17, 0x02, 0x02, 0x09, 0x03, 0x02, 0x81, 0x22, 0x23, 0x01, 0x2E,
0x11, 0x06, 0x0E, 0x22, 0x81, 0x22, 0x23, 0x01, 0x30, 0x01, 0x39, 0x6F,
0x06, 0x03, 0x22, 0x04, 0x73, 0x01, 0x80, 0x5A, 0x10, 0x06, 0x02, 0x45,
0x26, 0x75, 0x02, 0x03, 0x02, 0x02, 0x00, 0x01, 0x81, 0x22, 0x79, 0x01,
0x0A, 0x08, 0x03, 0x00, 0x81, 0x22, 0x79, 0x02, 0x00, 0x09, 0x00, 0x02,
0x03, 0x00, 0x03, 0x01, 0x81, 0x16, 0x23, 0x02, 0x01, 0x02, 0x00, 0x6F,
0x05, 0x02, 0x45, 0x26, 0x00, 0x00, 0x32, 0x81, 0x20, 0x01, 0x02, 0x74,
0x0B, 0x81, 0x19, 0x00, 0x03, 0x23, 0x03, 0x00, 0x03, 0x01, 0x03, 0x02,
0x81, 0x1B, 0x81, 0x22, 0x23, 0x01, 0x81, 0x00, 0x13, 0x06, 0x02, 0x51,
0x26, 0x23, 0x01, 0x00, 0x11, 0x06, 0x0C, 0x22, 0x23, 0x05, 0x04, 0x22,
0x01, 0x00, 0x00, 0x81, 0x22, 0x04, 0x6E, 0x02, 0x01, 0x23, 0x05, 0x02,
0x4D, 0x26, 0x3E, 0x03, 0x01, 0x02, 0x02, 0x35, 0x02, 0x02, 0x3D, 0x03,
0x02, 0x23, 0x06, 0x04, 0x81, 0x22, 0x04, 0x67, 0x22, 0x02, 0x00, 0x02,
0x01, 0x0A, 0x00, 0x01, 0x81, 0x22, 0x23, 0x01, 0x81, 0x00, 0x0D, 0x06,
0x01, 0x00, 0x01, 0x81, 0x00, 0x0A, 0x23, 0x05, 0x02, 0x4B, 0x26, 0x03,
0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x12, 0x06, 0x1A, 0x02, 0x00,
0x3E, 0x03, 0x00, 0x23, 0x01, 0x87, 0xFF, 0xFF, 0x7F, 0x12, 0x06, 0x02,
0x4C, 0x26, 0x01, 0x08, 0x0E, 0x39, 0x81, 0x22, 0x32, 0x09, 0x04, 0x5F,
0x00, 0x00, 0x81, 0x1A, 0x81, 0x0C, 0x00, 0x00, 0x81, 0x1B, 0x81, 0x2A,
0x00, 0x00, 0x81, 0x20, 0x72, 0x81, 0x1B, 0x00, 0x01, 0x81, 0x1B, 0x23,
0x05, 0x02, 0x51, 0x26, 0x81, 0x22, 0x23, 0x01, 0x81, 0x00, 0x13, 0x06,
0x02, 0x51, 0x26, 0x03, 0x00, 0x23, 0x06, 0x17, 0x81, 0x22, 0x02, 0x00,
0x23, 0x01, 0x87, 0xFF, 0xFF, 0x7F, 0x13, 0x06, 0x02, 0x51, 0x26, 0x01,
0x08, 0x0E, 0x09, 0x03, 0x00, 0x04, 0x66, 0x22, 0x02, 0x00, 0x00, 0x00,
0x81, 0x1B, 0x23, 0x01, 0x81, 0x7F, 0x12, 0x06, 0x09, 0x81, 0x2A, 0x01,
0x00, 0x65, 0x35, 0x01, 0x00, 0x00, 0x23, 0x65, 0x35, 0x65, 0x3D, 0x81,
0x13, 0x01, 0x7F, 0x00, 0x01, 0x81, 0x22, 0x03, 0x00, 0x02, 0x00, 0x01,
0x05, 0x14, 0x01, 0x01, 0x15, 0x2C, 0x02, 0x00, 0x01, 0x06, 0x14, 0x23,
0x01, 0x01, 0x15, 0x06, 0x02, 0x43, 0x26, 0x01, 0x04, 0x0E, 0x02, 0x00,
0x01, 0x1F, 0x15, 0x23, 0x01, 0x1F, 0x11, 0x06, 0x02, 0x44, 0x26, 0x09,
0x00, 0x00, 0x23, 0x05, 0x05, 0x01, 0x00, 0x01, 0x7F, 0x00, 0x81, 0x20,
0x00, 0x00, 0x23, 0x05, 0x02, 0x4C, 0x26, 0x3E, 0x81, 0x23, 0x00, 0x00,
0x30, 0x23, 0x01, 0x00, 0x13, 0x06, 0x01, 0x00, 0x22, 0x19, 0x04, 0x74,
0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x0B, 0x00, 0x00, 0x01, 0x15, 0x00,
0x00, 0x01, 0x1F, 0x00, 0x00, 0x01, 0x29, 0x00, 0x00, 0x01, 0x33, 0x00,
0x00, 0x81, 0x2B, 0x22, 0x00, 0x00, 0x23, 0x06, 0x08, 0x81, 0x2C, 0x23,
0x06, 0x01, 0x19, 0x04, 0x75, 0x00, 0x00, 0x01, 0x00, 0x2E, 0x2F, 0x0B,
0x3F, 0x00, 0x00, 0x01, 0x81, 0x6C, 0x00, 0x00, 0x01, 0x81, 0x7C, 0x00,
0x00, 0x01, 0x82, 0x11, 0x00, 0x00, 0x01, 0x81, 0x74, 0x00, 0x00, 0x01,
0x03, 0x31, 0x01, 0x03, 0x31, 0x00
0x00, 0x02, 0x03, 0x00, 0x03, 0x01, 0x23, 0x02, 0x01, 0x13, 0x38, 0x02,
0x00, 0x0F, 0x15, 0x00, 0x00, 0x05, 0x02, 0x4E, 0x26, 0x00, 0x00, 0x06,
0x02, 0x4F, 0x26, 0x00, 0x00, 0x01, 0x10, 0x71, 0x00, 0x00, 0x11, 0x05,
0x02, 0x52, 0x26, 0x6E, 0x00, 0x00, 0x11, 0x05, 0x02, 0x52, 0x26, 0x6F,
0x00, 0x00, 0x06, 0x02, 0x48, 0x26, 0x00, 0x00, 0x01, 0x82, 0x00, 0x00,
0x00, 0x23, 0x1E, 0x01, 0x08, 0x0E, 0x38, 0x3C, 0x1E, 0x09, 0x00, 0x09,
0x03, 0x00, 0x57, 0x29, 0x81, 0x1B, 0x36, 0x81, 0x1B, 0x81, 0x1E, 0x23,
0x01, 0x20, 0x11, 0x06, 0x15, 0x22, 0x6E, 0x81, 0x19, 0x81, 0x1E, 0x01,
0x02, 0x72, 0x81, 0x1C, 0x01, 0x02, 0x12, 0x06, 0x02, 0x53, 0x26, 0x73,
0x81, 0x1E, 0x01, 0x02, 0x72, 0x81, 0x1A, 0x81, 0x1B, 0x81, 0x28, 0x81,
0x0E, 0x61, 0x5D, 0x1F, 0x16, 0x81, 0x1B, 0x81, 0x13, 0x27, 0x65, 0x06,
0x02, 0x47, 0x26, 0x81, 0x13, 0x27, 0x6C, 0x06, 0x02, 0x47, 0x26, 0x73,
0x81, 0x0E, 0x02, 0x00, 0x06, 0x05, 0x2A, 0x03, 0x01, 0x04, 0x08, 0x5D,
0x64, 0x1F, 0x25, 0x05, 0x02, 0x46, 0x26, 0x64, 0x61, 0x1F, 0x16, 0x81,
0x1B, 0x81, 0x1B, 0x81, 0x0F, 0x05, 0x02, 0x53, 0x26, 0x81, 0x22, 0x24,
0x06, 0x2C, 0x81, 0x28, 0x81, 0x10, 0x81, 0x1B, 0x5F, 0x81, 0x16, 0x03,
0x03, 0x5F, 0x38, 0x02, 0x03, 0x09, 0x38, 0x02, 0x03, 0x0A, 0x81, 0x16,
0x03, 0x04, 0x73, 0x60, 0x28, 0x01, 0x81, 0x00, 0x09, 0x02, 0x03, 0x12,
0x06, 0x02, 0x54, 0x26, 0x73, 0x56, 0x03, 0x02, 0x04, 0x3D, 0x7F, 0x24,
0x06, 0x37, 0x81, 0x0F, 0x05, 0x02, 0x53, 0x26, 0x66, 0x24, 0x06, 0x04,
0x01, 0x17, 0x04, 0x12, 0x67, 0x24, 0x06, 0x04, 0x01, 0x18, 0x04, 0x0A,
0x68, 0x24, 0x06, 0x04, 0x01, 0x19, 0x04, 0x02, 0x53, 0x26, 0x03, 0x05,
0x73, 0x81, 0x10, 0x23, 0x03, 0x06, 0x23, 0x5F, 0x31, 0x0D, 0x06, 0x02,
0x4C, 0x26, 0x81, 0x11, 0x55, 0x03, 0x02, 0x04, 0x02, 0x53, 0x26, 0x73,
0x02, 0x00, 0x06, 0x21, 0x02, 0x02, 0x56, 0x2D, 0x11, 0x06, 0x08, 0x22,
0x02, 0x03, 0x02, 0x04, 0x1D, 0x04, 0x10, 0x55, 0x2D, 0x11, 0x06, 0x08,
0x22, 0x02, 0x05, 0x02, 0x06, 0x1C, 0x04, 0x03, 0x53, 0x26, 0x22, 0x04,
0x24, 0x02, 0x02, 0x56, 0x2D, 0x11, 0x06, 0x08, 0x22, 0x02, 0x03, 0x02,
0x04, 0x21, 0x04, 0x10, 0x55, 0x2D, 0x11, 0x06, 0x08, 0x22, 0x02, 0x05,
0x02, 0x06, 0x20, 0x04, 0x03, 0x53, 0x26, 0x22, 0x23, 0x06, 0x01, 0x26,
0x22, 0x01, 0x00, 0x03, 0x07, 0x81, 0x1F, 0x01, 0x21, 0x81, 0x05, 0x01,
0x22, 0x81, 0x05, 0x23, 0x01, 0x23, 0x11, 0x06, 0x81, 0x35, 0x22, 0x6E,
0x81, 0x19, 0x81, 0x1B, 0x23, 0x06, 0x81, 0x27, 0x01, 0x00, 0x03, 0x08,
0x81, 0x1B, 0x81, 0x0F, 0x22, 0x81, 0x1E, 0x23, 0x01, 0x01, 0x11, 0x06,
0x06, 0x81, 0x12, 0x03, 0x08, 0x81, 0x1E, 0x01, 0x04, 0x72, 0x81, 0x19,
0x6B, 0x24, 0x06, 0x11, 0x02, 0x00, 0x06, 0x04, 0x81, 0x29, 0x04, 0x06,
0x81, 0x0C, 0x01, 0x7F, 0x03, 0x07, 0x04, 0x80, 0x71, 0x81, 0x07, 0x24,
0x06, 0x07, 0x02, 0x00, 0x81, 0x0D, 0x04, 0x80, 0x65, 0x81, 0x2B, 0x24,
0x06, 0x13, 0x02, 0x00, 0x06, 0x0A, 0x01, 0x00, 0x03, 0x01, 0x81, 0x0B,
0x03, 0x01, 0x04, 0x02, 0x81, 0x29, 0x04, 0x80, 0x4D, 0x6A, 0x24, 0x06,
0x05, 0x81, 0x29, 0x04, 0x80, 0x44, 0x81, 0x2E, 0x24, 0x06, 0x04, 0x81,
0x29, 0x04, 0x3B, 0x81, 0x06, 0x24, 0x06, 0x04, 0x81, 0x29, 0x04, 0x32,
0x81, 0x2C, 0x24, 0x06, 0x04, 0x81, 0x29, 0x04, 0x29, 0x74, 0x24, 0x06,
0x04, 0x81, 0x29, 0x04, 0x21, 0x7E, 0x24, 0x06, 0x04, 0x81, 0x29, 0x04,
0x19, 0x69, 0x24, 0x06, 0x04, 0x81, 0x29, 0x04, 0x11, 0x81, 0x2D, 0x24,
0x06, 0x04, 0x81, 0x29, 0x04, 0x08, 0x02, 0x08, 0x06, 0x02, 0x45, 0x26,
0x81, 0x29, 0x73, 0x73, 0x04, 0xFE, 0x55, 0x73, 0x73, 0x04, 0x08, 0x01,
0x7F, 0x11, 0x05, 0x02, 0x52, 0x26, 0x22, 0x73, 0x37, 0x02, 0x00, 0x06,
0x08, 0x02, 0x01, 0x39, 0x2C, 0x05, 0x02, 0x41, 0x26, 0x02, 0x00, 0x06,
0x01, 0x17, 0x02, 0x00, 0x02, 0x07, 0x2C, 0x05, 0x02, 0x4D, 0x26, 0x81,
0x1E, 0x70, 0x81, 0x19, 0x81, 0x0F, 0x06, 0x81, 0x07, 0x81, 0x23, 0x24,
0x06, 0x08, 0x01, 0x02, 0x56, 0x81, 0x00, 0x04, 0x80, 0x6C, 0x81, 0x24,
0x24, 0x06, 0x08, 0x01, 0x03, 0x56, 0x81, 0x01, 0x04, 0x80, 0x5F, 0x81,
0x25, 0x24, 0x06, 0x08, 0x01, 0x04, 0x56, 0x81, 0x02, 0x04, 0x80, 0x52,
0x81, 0x26, 0x24, 0x06, 0x08, 0x01, 0x05, 0x56, 0x81, 0x03, 0x04, 0x80,
0x45, 0x81, 0x27, 0x24, 0x06, 0x07, 0x01, 0x06, 0x56, 0x81, 0x04, 0x04,
0x39, 0x79, 0x24, 0x06, 0x07, 0x01, 0x02, 0x55, 0x81, 0x00, 0x04, 0x2E,
0x7A, 0x24, 0x06, 0x07, 0x01, 0x03, 0x55, 0x81, 0x01, 0x04, 0x23, 0x7B,
0x24, 0x06, 0x07, 0x01, 0x04, 0x55, 0x81, 0x02, 0x04, 0x18, 0x7C, 0x24,
0x06, 0x07, 0x01, 0x05, 0x55, 0x81, 0x03, 0x04, 0x0D, 0x7D, 0x24, 0x06,
0x07, 0x01, 0x06, 0x55, 0x81, 0x04, 0x04, 0x02, 0x53, 0x26, 0x5A, 0x32,
0x5C, 0x34, 0x1B, 0x23, 0x05, 0x02, 0x53, 0x26, 0x59, 0x34, 0x04, 0x02,
0x53, 0x26, 0x81, 0x28, 0x81, 0x10, 0x23, 0x01,
T0_INT2(BR_X509_BUFSIZE_SIG), 0x12, 0x06, 0x02, 0x4C, 0x26, 0x23, 0x5B,
0x32, 0x58, 0x81, 0x11, 0x73, 0x73, 0x01, 0x00, 0x57, 0x33, 0x18, 0x00,
0x00, 0x01, 0x30, 0x0A, 0x23, 0x01, 0x00, 0x01, 0x09, 0x6D, 0x05, 0x02,
0x44, 0x26, 0x00, 0x00, 0x2D, 0x2D, 0x00, 0x00, 0x01, 0x81, 0x08, 0x00,
0x00, 0x01, 0x81, 0x10, 0x00, 0x00, 0x01, 0x81, 0x19, 0x00, 0x00, 0x01,
0x81, 0x22, 0x00, 0x00, 0x01, 0x81, 0x2B, 0x00, 0x00, 0x01, 0x82, 0x04,
0x00, 0x00, 0x01, 0x80, 0x6B, 0x00, 0x00, 0x01, 0x3D, 0x00, 0x00, 0x01,
0x80, 0x43, 0x00, 0x00, 0x01, 0x80, 0x4D, 0x00, 0x00, 0x01, 0x80, 0x57,
0x00, 0x00, 0x01, 0x80, 0x61, 0x00, 0x00, 0x2D, 0x11, 0x06, 0x07, 0x3E,
0x81, 0x19, 0x81, 0x28, 0x81, 0x1F, 0x00, 0x00, 0x01, 0x81, 0x78, 0x00,
0x00, 0x01, 0x81, 0x68, 0x00, 0x00, 0x01, 0x30, 0x5E, 0x34, 0x01, 0x7F,
0x76, 0x19, 0x01, 0x00, 0x76, 0x19, 0x04, 0x7A, 0x00, 0x01, 0x81, 0x34,
0x00, 0x01, 0x78, 0x0D, 0x06, 0x02, 0x4B, 0x26, 0x23, 0x03, 0x00, 0x0A,
0x02, 0x00, 0x00, 0x01, 0x01, 0x00, 0x03, 0x00, 0x81, 0x1B, 0x23, 0x06,
0x18, 0x81, 0x1E, 0x01, 0x22, 0x11, 0x06, 0x0C, 0x6F, 0x81, 0x1D, 0x22,
0x2A, 0x02, 0x00, 0x2C, 0x03, 0x00, 0x04, 0x03, 0x22, 0x81, 0x1A, 0x04,
0x65, 0x73, 0x02, 0x00, 0x00, 0x00, 0x81, 0x1B, 0x81, 0x1F, 0x23, 0x01,
0x01, 0x11, 0x06, 0x0A, 0x81, 0x12, 0x05, 0x02, 0x4D, 0x26, 0x81, 0x1F,
0x04, 0x02, 0x4D, 0x26, 0x23, 0x01, 0x02, 0x11, 0x06, 0x0E, 0x22, 0x6F,
0x81, 0x1C, 0x62, 0x29, 0x3D, 0x0D, 0x06, 0x02, 0x4D, 0x26, 0x81, 0x1F,
0x01, 0x7F, 0x10, 0x06, 0x02, 0x52, 0x26, 0x22, 0x73, 0x00, 0x02, 0x03,
0x00, 0x81, 0x1E, 0x01, 0x03, 0x72, 0x81, 0x19, 0x81, 0x20, 0x03, 0x01,
0x02, 0x01, 0x01, 0x07, 0x12, 0x06, 0x02, 0x52, 0x26, 0x23, 0x01, 0x00,
0x2D, 0x11, 0x06, 0x05, 0x22, 0x49, 0x26, 0x04, 0x17, 0x01, 0x01, 0x2D,
0x11, 0x06, 0x0B, 0x22, 0x81, 0x20, 0x02, 0x01, 0x14, 0x02, 0x01, 0x0E,
0x04, 0x06, 0x22, 0x81, 0x20, 0x01, 0x00, 0x22, 0x02, 0x00, 0x06, 0x19,
0x01, 0x00, 0x2D, 0x01, 0x38, 0x15, 0x06, 0x03, 0x01, 0x10, 0x2C, 0x38,
0x01, 0x81, 0x40, 0x15, 0x06, 0x03, 0x01, 0x20, 0x2C, 0x5E, 0x34, 0x04,
0x07, 0x01, 0x04, 0x15, 0x05, 0x02, 0x49, 0x26, 0x81, 0x28, 0x00, 0x02,
0x35, 0x01, 0x00, 0x63, 0x34, 0x81, 0x1B, 0x23, 0x06, 0x80, 0x6F, 0x81,
0x1E, 0x01, 0x11, 0x71, 0x81, 0x19, 0x23, 0x05, 0x02, 0x40, 0x26, 0x23,
0x06, 0x80, 0x5B, 0x81, 0x1B, 0x81, 0x1E, 0x01, 0x06, 0x72, 0x81, 0x19,
0x23, 0x01, 0x03, 0x11, 0x06, 0x1E, 0x81, 0x20, 0x01, 0x10, 0x0E, 0x03,
0x00, 0x81, 0x20, 0x01, 0x08, 0x0E, 0x02, 0x00, 0x09, 0x03, 0x00, 0x81,
0x20, 0x02, 0x00, 0x09, 0x01, 0x82, 0xD4, 0x88, 0x03, 0x11, 0x03, 0x01,
0x81, 0x28, 0x02, 0x01, 0x06, 0x23, 0x81, 0x1E, 0x23, 0x23, 0x01, 0x0C,
0x11, 0x38, 0x01, 0x13, 0x11, 0x2C, 0x38, 0x01, 0x14, 0x11, 0x2C, 0x06,
0x07, 0x6F, 0x81, 0x1D, 0x22, 0x73, 0x04, 0x07, 0x22, 0x01, 0x00, 0x63,
0x34, 0x81, 0x28, 0x04, 0x02, 0x81, 0x28, 0x04, 0xFF, 0x21, 0x73, 0x04,
0xFF, 0x0D, 0x73, 0x1A, 0x00, 0x00, 0x81, 0x1E, 0x01, 0x06, 0x72, 0x81,
0x1D, 0x00, 0x00, 0x81, 0x1E, 0x01, 0x03, 0x72, 0x81, 0x19, 0x81, 0x20,
0x06, 0x02, 0x51, 0x26, 0x00, 0x00, 0x38, 0x23, 0x06, 0x07, 0x2E, 0x23,
0x06, 0x01, 0x19, 0x04, 0x76, 0x3E, 0x00, 0x00, 0x01, 0x01, 0x72, 0x81,
0x18, 0x01, 0x01, 0x10, 0x06, 0x02, 0x3F, 0x26, 0x81, 0x20, 0x3A, 0x00,
0x04, 0x81, 0x1E, 0x23, 0x01, 0x17, 0x01, 0x18, 0x6D, 0x05, 0x02, 0x44,
0x26, 0x01, 0x18, 0x11, 0x03, 0x00, 0x6F, 0x81, 0x19, 0x81, 0x14, 0x02,
0x00, 0x06, 0x0D, 0x01, 0x80, 0x64, 0x08, 0x03, 0x01, 0x81, 0x14, 0x02,
0x01, 0x09, 0x04, 0x0E, 0x23, 0x01, 0x32, 0x0D, 0x06, 0x04, 0x01, 0x80,
0x64, 0x09, 0x01, 0x8E, 0x6C, 0x09, 0x03, 0x01, 0x02, 0x01, 0x01, 0x82,
0x6D, 0x08, 0x02, 0x01, 0x01, 0x03, 0x09, 0x01, 0x04, 0x0C, 0x09, 0x02,
0x01, 0x01, 0x80, 0x63, 0x09, 0x01, 0x80, 0x64, 0x0C, 0x0A, 0x02, 0x01,
0x01, 0x83, 0x0F, 0x09, 0x01, 0x83, 0x10, 0x0C, 0x09, 0x03, 0x03, 0x01,
0x01, 0x01, 0x0C, 0x81, 0x15, 0x3D, 0x01, 0x01, 0x0E, 0x02, 0x01, 0x01,
0x04, 0x07, 0x3B, 0x02, 0x01, 0x01, 0x80, 0x64, 0x07, 0x3A, 0x02, 0x01,
0x01, 0x83, 0x10, 0x07, 0x3B, 0x2C, 0x15, 0x06, 0x03, 0x01, 0x18, 0x09,
0x81, 0x09, 0x09, 0x75, 0x23, 0x01, 0x05, 0x14, 0x02, 0x03, 0x09, 0x03,
0x03, 0x01, 0x1F, 0x15, 0x01, 0x01, 0x38, 0x81, 0x15, 0x02, 0x03, 0x09,
0x3D, 0x03, 0x03, 0x01, 0x00, 0x01, 0x17, 0x81, 0x15, 0x01, 0x9C, 0x10,
0x08, 0x03, 0x02, 0x01, 0x00, 0x01, 0x3B, 0x81, 0x15, 0x01, 0x3C, 0x08,
0x02, 0x02, 0x09, 0x03, 0x02, 0x01, 0x00, 0x01, 0x3C, 0x81, 0x15, 0x02,
0x02, 0x09, 0x03, 0x02, 0x81, 0x20, 0x23, 0x01, 0x2E, 0x11, 0x06, 0x0E,
0x22, 0x81, 0x20, 0x23, 0x01, 0x30, 0x01, 0x39, 0x6D, 0x06, 0x03, 0x22,
0x04, 0x73, 0x01, 0x80, 0x5A, 0x10, 0x06, 0x02, 0x44, 0x26, 0x73, 0x02,
0x03, 0x02, 0x02, 0x00, 0x01, 0x81, 0x20, 0x77, 0x01, 0x0A, 0x08, 0x03,
0x00, 0x81, 0x20, 0x77, 0x02, 0x00, 0x09, 0x00, 0x02, 0x03, 0x00, 0x03,
0x01, 0x81, 0x14, 0x23, 0x02, 0x01, 0x02, 0x00, 0x6D, 0x05, 0x02, 0x44,
0x26, 0x00, 0x00, 0x31, 0x81, 0x1E, 0x01, 0x02, 0x72, 0x0B, 0x81, 0x17,
0x00, 0x03, 0x23, 0x03, 0x00, 0x03, 0x01, 0x03, 0x02, 0x81, 0x19, 0x81,
0x20, 0x23, 0x01, 0x81, 0x00, 0x13, 0x06, 0x02, 0x50, 0x26, 0x23, 0x01,
0x00, 0x11, 0x06, 0x0C, 0x22, 0x23, 0x05, 0x04, 0x22, 0x01, 0x00, 0x00,
0x81, 0x20, 0x04, 0x6E, 0x02, 0x01, 0x23, 0x05, 0x02, 0x4C, 0x26, 0x3D,
0x03, 0x01, 0x02, 0x02, 0x34, 0x02, 0x02, 0x3C, 0x03, 0x02, 0x23, 0x06,
0x04, 0x81, 0x20, 0x04, 0x67, 0x22, 0x02, 0x00, 0x02, 0x01, 0x0A, 0x00,
0x01, 0x81, 0x20, 0x23, 0x01, 0x81, 0x00, 0x0D, 0x06, 0x01, 0x00, 0x01,
0x81, 0x00, 0x0A, 0x23, 0x05, 0x02, 0x4A, 0x26, 0x03, 0x00, 0x01, 0x00,
0x02, 0x00, 0x01, 0x00, 0x12, 0x06, 0x1A, 0x02, 0x00, 0x3D, 0x03, 0x00,
0x23, 0x01, 0x87, 0xFF, 0xFF, 0x7F, 0x12, 0x06, 0x02, 0x4B, 0x26, 0x01,
0x08, 0x0E, 0x38, 0x81, 0x20, 0x31, 0x09, 0x04, 0x5F, 0x00, 0x00, 0x81,
0x18, 0x81, 0x0A, 0x00, 0x00, 0x81, 0x19, 0x81, 0x28, 0x00, 0x00, 0x81,
0x1E, 0x70, 0x81, 0x19, 0x00, 0x01, 0x81, 0x19, 0x23, 0x05, 0x02, 0x50,
0x26, 0x81, 0x20, 0x23, 0x01, 0x81, 0x00, 0x13, 0x06, 0x02, 0x50, 0x26,
0x03, 0x00, 0x23, 0x06, 0x17, 0x81, 0x20, 0x02, 0x00, 0x23, 0x01, 0x87,
0xFF, 0xFF, 0x7F, 0x13, 0x06, 0x02, 0x50, 0x26, 0x01, 0x08, 0x0E, 0x09,
0x03, 0x00, 0x04, 0x66, 0x22, 0x02, 0x00, 0x00, 0x00, 0x81, 0x19, 0x23,
0x01, 0x81, 0x7F, 0x12, 0x06, 0x09, 0x81, 0x28, 0x01, 0x00, 0x63, 0x34,
0x01, 0x00, 0x00, 0x23, 0x63, 0x34, 0x63, 0x3C, 0x81, 0x11, 0x01, 0x7F,
0x00, 0x01, 0x81, 0x20, 0x03, 0x00, 0x02, 0x00, 0x01, 0x05, 0x14, 0x01,
0x01, 0x15, 0x2B, 0x02, 0x00, 0x01, 0x06, 0x14, 0x23, 0x01, 0x01, 0x15,
0x06, 0x02, 0x42, 0x26, 0x01, 0x04, 0x0E, 0x02, 0x00, 0x01, 0x1F, 0x15,
0x23, 0x01, 0x1F, 0x11, 0x06, 0x02, 0x43, 0x26, 0x09, 0x00, 0x00, 0x23,
0x05, 0x05, 0x01, 0x00, 0x01, 0x7F, 0x00, 0x81, 0x1E, 0x00, 0x00, 0x23,
0x05, 0x02, 0x4B, 0x26, 0x3D, 0x81, 0x21, 0x00, 0x00, 0x2F, 0x23, 0x01,
0x00, 0x13, 0x06, 0x01, 0x00, 0x22, 0x19, 0x04, 0x74, 0x00, 0x01, 0x01,
0x00, 0x00, 0x01, 0x0B, 0x00, 0x00, 0x01, 0x15, 0x00, 0x00, 0x01, 0x1F,
0x00, 0x00, 0x01, 0x29, 0x00, 0x00, 0x01, 0x33, 0x00, 0x00, 0x81, 0x29,
0x22, 0x00, 0x00, 0x23, 0x06, 0x08, 0x81, 0x2A, 0x23, 0x06, 0x01, 0x19,
0x04, 0x75, 0x00, 0x00, 0x01, 0x00, 0x2D, 0x2E, 0x0B, 0x3E, 0x00, 0x00,
0x01, 0x81, 0x6C, 0x00, 0x00, 0x01, 0x81, 0x7C, 0x00, 0x00, 0x01, 0x82,
0x11, 0x00, 0x00, 0x01, 0x81, 0x74, 0x00, 0x00, 0x01, 0x03, 0x30, 0x01,
0x03, 0x30, 0x00
};
static const uint16_t t0_caddr[] = {
@ -736,98 +736,97 @@ static const uint16_t t0_caddr[] = {
112,
116,
120,
124,
129,
134,
139,
144,
149,
154,
159,
164,
172,
177,
182,
187,
192,
197,
202,
207,
212,
217,
222,
227,
232,
261,
276,
282,
288,
293,
301,
309,
315,
320,
331,
125,
130,
135,
140,
145,
150,
155,
160,
168,
173,
178,
183,
188,
193,
198,
203,
208,
213,
218,
223,
228,
257,
272,
278,
284,
289,
297,
305,
311,
316,
327,
1029,
1044,
1048,
1053,
1058,
1063,
1068,
1072,
1077,
1082,
1073,
1078,
1083,
1087,
1092,
1097,
1102,
1107,
1111,
1116,
1121,
1126,
1131,
1144,
1149,
1154,
1165,
1170,
1184,
1222,
1275,
1363,
1489,
1498,
1513,
1527,
1544,
1776,
1792,
1120,
1125,
1130,
1145,
1150,
1164,
1202,
1255,
1352,
1478,
1487,
1502,
1516,
1533,
1765,
1781,
1799,
1810,
1821,
1892,
1950,
1956,
1962,
1969,
2020,
2049,
2094,
2106,
2116,
2129,
2133,
2137,
2141,
2145,
2149,
2153,
2158,
2171,
2179,
2184,
2189,
2194,
2199
1881,
1939,
1945,
1951,
1958,
2009,
2038,
2083,
2095,
2105,
2118,
2122,
2126,
2130,
2134,
2138,
2142,
2147,
2160,
2168,
2173,
2178,
2183,
2188
};
#define T0_INTERPRETED 59
#define T0_INTERPRETED 58
#define T0_ENTER(ip, rp, slot) do { \
const unsigned char *t0_newip; \
@ -848,7 +847,7 @@ name(void *ctx) \
T0_ENTER(t0ctx->ip, t0ctx->rp, slot); \
}
T0_DEFENTRY(br_x509_minimal_init_main, 138)
T0_DEFENTRY(br_x509_minimal_init_main, 136)
void
br_x509_minimal_run(void *t0ctx)
@ -1100,7 +1099,7 @@ br_x509_minimal_run(void *t0ctx)
if (ta->flags & BR_X509_TA_CA) {
continue;
}
hash_dn(CTX, ta->dn, ta->dn_len, hashed_DN);
hash_dn(CTX, ta->dn.data, ta->dn.len, hashed_DN);
if (memcmp(hashed_DN, CTX->current_dn_hash, DNHASH_LEN)) {
continue;
}
@ -1161,7 +1160,7 @@ br_x509_minimal_run(void *t0ctx)
if (!(ta->flags & BR_X509_TA_CA)) {
continue;
}
hash_dn(CTX, ta->dn, ta->dn_len, hashed_DN);
hash_dn(CTX, ta->dn.data, ta->dn.len, hashed_DN);
if (memcmp(hashed_DN, CTX->saved_dn_hash, DNHASH_LEN)) {
continue;
}
@ -1360,14 +1359,6 @@ br_x509_minimal_run(void *t0ctx)
}
break;
case 42: {
/* get8 */
uint32_t addr = T0_POP();
T0_PUSH(*((unsigned char *)CTX + addr));
}
break;
case 43: {
/* match-server-name */
size_t n1, n2;
@ -1402,7 +1393,7 @@ br_x509_minimal_run(void *t0ctx)
}
break;
case 44: {
case 43: {
/* neg */
uint32_t a = T0_POP();
@ -1410,7 +1401,7 @@ br_x509_minimal_run(void *t0ctx)
}
break;
case 45: {
case 44: {
/* or */
uint32_t b = T0_POP();
@ -1419,12 +1410,12 @@ br_x509_minimal_run(void *t0ctx)
}
break;
case 46: {
case 45: {
/* over */
T0_PUSH(T0_PEEK(1));
}
break;
case 47: {
case 46: {
/* read-blob-inner */
uint32_t len = T0_POP();
@ -1450,7 +1441,7 @@ br_x509_minimal_run(void *t0ctx)
}
break;
case 48: {
case 47: {
/* read8-low */
if (CTX->hlen == 0) {
@ -1469,17 +1460,17 @@ br_x509_minimal_run(void *t0ctx)
}
break;
case 49: {
case 48: {
/* roll */
T0_ROLL(T0_POP());
}
break;
case 50: {
case 49: {
/* rot */
T0_ROT();
}
break;
case 51: {
case 50: {
/* set16 */
uint32_t addr = T0_POP();
@ -1487,7 +1478,7 @@ br_x509_minimal_run(void *t0ctx)
}
break;
case 52: {
case 51: {
/* set32 */
uint32_t addr = T0_POP();
@ -1495,7 +1486,7 @@ br_x509_minimal_run(void *t0ctx)
}
break;
case 53: {
case 52: {
/* set8 */
uint32_t addr = T0_POP();
@ -1503,7 +1494,7 @@ br_x509_minimal_run(void *t0ctx)
}
break;
case 54: {
case 53: {
/* start-dn-hash */
CTX->dn_hash_impl->init(&CTX->dn_hash.vtable);
@ -1511,7 +1502,7 @@ br_x509_minimal_run(void *t0ctx)
}
break;
case 55: {
case 54: {
/* start-tbs-hash */
br_multihash_init(&CTX->mhash);
@ -1519,19 +1510,19 @@ br_x509_minimal_run(void *t0ctx)
}
break;
case 56: {
case 55: {
/* stop-tbs-hash */
CTX->do_mhash = 0;
}
break;
case 57: {
case 56: {
/* swap */
T0_SWAP();
}
break;
case 58: {
case 57: {
/* zero-server-name */
T0_PUSHi(-(CTX->server_name == NULL));

View file

@ -188,8 +188,7 @@ br_x509_minimal_init(br_x509_minimal_context *ctx,
}
static void
xm_start_chain(const br_x509_class **ctx,
unsigned expected_key_type, const char *server_name)
xm_start_chain(const br_x509_class **ctx, const char *server_name)
{
br_x509_minimal_context *cc;
@ -200,7 +199,6 @@ xm_start_chain(const br_x509_class **ctx,
cc->cpu.dp = cc->dp_stack;
cc->cpu.rp = cc->rp_stack;
br_x509_minimal_init_main(&cc->cpu);
cc->expected_key_type = expected_key_type;
if (server_name == NULL || *server_name == 0) {
cc->server_name = NULL;
} else {
@ -269,7 +267,7 @@ xm_end_chain(const br_x509_class **ctx)
}
static const br_x509_pkey *
xm_get_pkey(const br_x509_class *const *ctx)
xm_get_pkey(const br_x509_class *const *ctx, unsigned *usages)
{
br_x509_minimal_context *cc;
@ -277,6 +275,9 @@ xm_get_pkey(const br_x509_class *const *ctx)
if (cc->err == BR_ERR_X509_OK
|| cc->err == BR_ERR_X509_NOT_TRUSTED)
{
if (usages != NULL) {
*usages = cc->key_usages;
}
return &((br_x509_minimal_context *)ctx)->pkey;
} else {
return NULL;
@ -472,7 +473,7 @@ cc: zero-server-name ( -- bool ) {
T0_PUSHi(-(CTX->server_name == NULL));
}
addr: expected_key_type
addr: key_usages
addr: cert_sig
addr: cert_sig_len
addr: cert_signer_key_type
@ -705,7 +706,7 @@ cc: check-direct-trust ( -- ) {
if (ta->flags & BR_X509_TA_CA) {
continue;
}
hash_dn(CTX, ta->dn, ta->dn_len, hashed_DN);
hash_dn(CTX, ta->dn.data, ta->dn.len, hashed_DN);
if (memcmp(hashed_DN, CTX->current_dn_hash, DNHASH_LEN)) {
continue;
}
@ -765,7 +766,7 @@ cc: check-trust-anchor-CA ( -- ) {
if (!(ta->flags & BR_X509_TA_CA)) {
continue;
}
hash_dn(CTX, ta->dn, ta->dn_len, hashed_DN);
hash_dn(CTX, ta->dn.data, ta->dn.len, hashed_DN);
if (memcmp(hashed_DN, CTX->saved_dn_hash, DNHASH_LEN)) {
continue;
}
@ -892,20 +893,14 @@ OID: subjectInfoAccess 1.3.6.1.5.5.7.1.11
\ Process a Key Usage extension.
\ For the EE certificate:
\ -- if the expected key usage is "key exchange", then the extension
\ must contain either keyEncipherment (2) or dataEncipherment (3);
\ -- if the expected key usage is "signature", then the extension
\ must contain either digitalSignature (0) or nonRepudiation (1).
\ -- if the key usage contains keyEncipherment (2), dataEncipherment (3)
\ or keyAgreement (4), then the "key exchange" usage is allowed;
\ -- if the key usage contains digitalSignature (0) or nonRepudiation (1),
\ then the "signature" usage is allowed.
\ For CA certificates, the extension must contain keyCertSign (5).
: process-keyUsage ( lim ee -- lim )
\ Compute flags, depending on EE status and expected key usage.
\ This is a mask of bits in the first byte.
if
addr-expected_key_type get8 0x10 and if 0x30 else 0xC0 then
else
0x04
then
{ mask }
{ ee }
\ Read tag for the BIT STRING and open it.
read-tag 0x03 check-tag-primitive
read-length-open-elt
@ -919,7 +914,20 @@ OID: subjectInfoAccess 1.3.6.1.5.5.7.1.11
1 of read8 ign >> ign << endof
drop read8 0
endcase
mask and ifnot ERR_X509_FORBIDDEN_KEY_USAGE fail then
\ Check bits.
ee if
\ EE: get usages.
0
over 0x38 and if 0x10 or then
swap 0xC0 and if 0x20 or then
addr-key_usages set8
else
\ Not EE: keyCertSign must be set.
0x04 and ifnot ERR_X509_FORBIDDEN_KEY_USAGE fail then
then
\ We don't care about subsequent bytes.
skip-close-elt ;
\ Process a Subject Alt Name extension. Returned value is a boolean set
@ -1070,15 +1078,8 @@ OID: subjectInfoAccess 1.3.6.1.5.5.7.1.11
\ Process public key.
ee if
\ For the EE certificate, check that the key type
\ matches that which was expected, then copy the
\ data to the relevant buffer.
addr-expected_key_type get8 0x0F and
dup if
pkey-type = ifnot ERR_X509_WRONG_KEY_TYPE fail then
else
drop
then
\ For the EE certificate, copy the key data to the
\ relevant buffer.
pkey-type case
KEYTYPE_RSA of nlen elen copy-ee-rsa-pkey endof
KEYTYPE_EC of curve qlen copy-ee-ec-pkey endof
@ -1286,6 +1287,9 @@ OID: subjectInfoAccess 1.3.6.1.5.5.7.1.11
check-trust-anchor-CA ;
: main
\ Unless restricted by a Key Usage extension, all usages are
\ deemed allowed.
0x30 addr-key_usages set8
-1 decode-certificate
co
begin

View file

@ -1438,6 +1438,7 @@ run_test_case(test_case *tc)
blob *certs;
br_x509_pkey *ee_pkey_ref;
const br_x509_pkey *ee_pkey;
unsigned usages;
unsigned status;
printf("%s: ", tc->name);
@ -1477,8 +1478,8 @@ run_test_case(test_case *tc)
tta->key_name);
exit(EXIT_FAILURE);
}
anchors[u].dn = tta->dn;
anchors[u].dn_len = tta->dn_len;
anchors[u].dn.data = tta->dn;
anchors[u].dn.len = tta->dn_len;
anchors[u].flags = tta->flags;
anchors[u].pkey = *tak;
}
@ -1541,8 +1542,7 @@ run_test_case(test_case *tc)
* Run the engine. We inject certificates by chunks of 100 bytes
* in order to exercise the coroutine API.
*/
ctx.vtable->start_chain(&ctx.vtable,
tc->key_type_usage, tc->servername);
ctx.vtable->start_chain(&ctx.vtable, tc->servername);
for (u = 0; u < num_certs; u ++) {
size_t v;
@ -1561,7 +1561,22 @@ run_test_case(test_case *tc)
ctx.vtable->end_cert(&ctx.vtable);
}
status = ctx.vtable->end_chain(&ctx.vtable);
ee_pkey = ctx.vtable->get_pkey(&ctx.vtable);
ee_pkey = ctx.vtable->get_pkey(&ctx.vtable, &usages);
/*
* Check key type and usage.
*/
if (ee_pkey != NULL) {
unsigned ktu;
ktu = ee_pkey->key_type | usages;
if (tc->key_type_usage != (ktu & tc->key_type_usage)) {
fprintf(stderr, "wrong key type + usage"
" (expected 0x%02X, got 0x%02X)\n",
tc->key_type_usage, ktu);
exit(EXIT_FAILURE);
}
}
/*
* Check results. Note that we may still get a public key if

View file

@ -279,6 +279,11 @@ void list_names(void);
*/
const char *ec_curve_name(int curve);
/*
* Get the symbolic name for a hash function name (by ID).
*/
const char *hash_function_name(int id);
/*
* Read a file completely. The returned block is allocated with xmalloc()
* and must be released by the caller.
@ -342,6 +347,12 @@ pem_object *decode_pem(const void *src, size_t len, size_t *num);
*/
br_x509_certificate *read_certificates(const char *fname, size_t *num);
/*
* Release certificates. This releases all certificate data arrays,
* and the whole array as well.
*/
void free_certificates(br_x509_certificate *certs, size_t num);
/*
* Interpret a certificate as a trust anchor. The trust anchor is
* newly allocated with xmalloc() and the caller must release it.
@ -369,6 +380,12 @@ void free_ta_contents(br_x509_trust_anchor *ta);
*/
size_t read_trust_anchors(anchor_list *dst, const char *fname);
/*
* Get the "signer key type" for the certificate (key type of the
* issuing CA). On error, this prints a message on stderr, and returns 0.
*/
int get_cert_signer_algo(br_x509_certificate *xc);
/*
* Special "no anchor" X.509 validator that wraps around another X.509
* validator and turns "not trusted" error codes into success. This is
@ -408,6 +425,20 @@ private_key *read_private_key(const char *fname);
*/
void free_private_key(private_key *sk);
/*
* Get the encoded OID for a given hash function (to use with PKCS#1
* signatures). If the hash function ID is 0 (for MD5+SHA-1), or if
* the ID is not one of the SHA-* functions (SHA-1, SHA-224, SHA-256,
* SHA-384, SHA-512), then this function returns NULL.
*/
const unsigned char *get_hash_oid(int id);
/*
* Get a hash implementation by ID. This returns NULL if the hash
* implementation is not available.
*/
const br_hash_class *get_hash_impl(int id);
/*
* Find the symbolic name and the description for an error. If 'err' is
* recognised then the error symbolic name is returned; if 'comment' is

View file

@ -53,8 +53,8 @@ certificate_to_trust_anchor_inner(br_x509_trust_anchor *ta,
VEC_CLEAR(vdn);
return -1;
}
ta->dn = VEC_TOARRAY(vdn);
ta->dn_len = VEC_LEN(vdn);
ta->dn.data = VEC_TOARRAY(vdn);
ta->dn.len = VEC_LEN(vdn);
VEC_CLEAR(vdn);
ta->flags = 0;
if (br_x509_decoder_isCA(&dc)) {
@ -76,7 +76,7 @@ certificate_to_trust_anchor_inner(br_x509_trust_anchor *ta,
break;
default:
fprintf(stderr, "ERROR: unsupported public key type in CA\n");
xfree(ta->dn);
xfree(ta->dn.data);
return -1;
}
return 0;
@ -99,7 +99,7 @@ certificate_to_trust_anchor(br_x509_certificate *xc)
void
free_ta_contents(br_x509_trust_anchor *ta)
{
xfree(ta->dn);
xfree(ta->dn.data);
switch (ta->pkey.key_type) {
case BR_KEYTYPE_RSA:
xfree(ta->pkey.key.rsa.n);
@ -137,15 +137,32 @@ read_trust_anchors(anchor_list *dst, const char *fname)
return num;
}
/* see brssl.h */
int
get_cert_signer_algo(br_x509_certificate *xc)
{
br_x509_decoder_context dc;
int err;
br_x509_decoder_init(&dc, 0, 0);
br_x509_decoder_push(&dc, xc->data, xc->data_len);
err = br_x509_decoder_last_error(&dc);
if (err != 0) {
fprintf(stderr,
"ERROR: certificate decoding failed with error %d\n",
-err);
return 0;
}
return br_x509_decoder_get_signer_key_type(&dc);
}
static void
xwc_start_chain(const br_x509_class **ctx,
unsigned expected_key_type, const char *server_name)
xwc_start_chain(const br_x509_class **ctx, const char *server_name)
{
x509_noanchor_context *xwc;
xwc = (x509_noanchor_context *)ctx;
(*xwc->inner)->start_chain(xwc->inner,
expected_key_type, server_name);
(*xwc->inner)->start_chain(xwc->inner, server_name);
}
static void
@ -190,12 +207,12 @@ xwc_end_chain(const br_x509_class **ctx)
}
static const br_x509_pkey *
xwc_get_pkey(const br_x509_class *const *ctx)
xwc_get_pkey(const br_x509_class *const *ctx, unsigned *usages)
{
x509_noanchor_context *xwc;
xwc = (x509_noanchor_context *)ctx;
return (*xwc->inner)->get_pkey(xwc->inner);
return (*xwc->inner)->get_pkey(xwc->inner, usages);
}
/* see brssl.h */

View file

@ -117,6 +117,308 @@ host_connect(const char *host, const char *port, int verbose)
return fd;
}
typedef struct {
const br_ssl_client_certificate_class *vtable;
int verbose;
br_x509_certificate *chain;
size_t chain_len;
private_key *sk;
int issuer_key_type;
} ccert_context;
static void
cc_start_name_list(const br_ssl_client_certificate_class **pctx)
{
ccert_context *zc;
zc = (ccert_context *)pctx;
if (zc->verbose) {
fprintf(stderr, "Server requests a client certificate.\n");
fprintf(stderr, "--- anchor DN list start ---\n");
}
}
static void
cc_start_name(const br_ssl_client_certificate_class **pctx, size_t len)
{
ccert_context *zc;
zc = (ccert_context *)pctx;
if (zc->verbose) {
fprintf(stderr, "new anchor name, length = %u\n",
(unsigned)len);
}
}
static void
cc_append_name(const br_ssl_client_certificate_class **pctx,
const unsigned char *data, size_t len)
{
ccert_context *zc;
zc = (ccert_context *)pctx;
if (zc->verbose) {
size_t u;
for (u = 0; u < len; u ++) {
if (u == 0) {
fprintf(stderr, " ");
} else if (u > 0 && u % 16 == 0) {
fprintf(stderr, "\n ");
}
fprintf(stderr, " %02x", data[u]);
}
if (len > 0) {
fprintf(stderr, "\n");
}
}
}
static void
cc_end_name(const br_ssl_client_certificate_class **pctx)
{
(void)pctx;
}
static void
cc_end_name_list(const br_ssl_client_certificate_class **pctx)
{
ccert_context *zc;
zc = (ccert_context *)pctx;
if (zc->verbose) {
fprintf(stderr, "--- anchor DN list end ---\n");
}
}
static void
print_hashes(unsigned hh, unsigned hh2)
{
int i;
for (i = 0; i < 8; i ++) {
const char *name;
name = hash_function_name(i);
if (((hh >> i) & 1) != 0) {
fprintf(stderr, " %s", name);
} else if (((hh2 >> i) & 1) != 0) {
fprintf(stderr, " (%s)", name);
}
}
}
static int
choose_hash(unsigned hh)
{
static const int f[] = {
br_sha256_ID, br_sha224_ID, br_sha384_ID, br_sha512_ID,
br_sha1_ID, br_md5sha1_ID, -1
};
size_t u;
for (u = 0; f[u] >= 0; u ++) {
if (((hh >> f[u]) & 1) != 0) {
return f[u];
}
}
return -1;
}
static void
cc_choose(const br_ssl_client_certificate_class **pctx,
const br_ssl_client_context *cc, uint32_t auth_types,
br_ssl_client_certificate *choices)
{
ccert_context *zc;
int scurve;
zc = (ccert_context *)pctx;
scurve = br_ssl_client_get_server_curve(cc);
if (zc->verbose) {
unsigned hashes;
hashes = br_ssl_client_get_server_hashes(cc);
if ((auth_types & 0x00FF) != 0) {
fprintf(stderr, "supported: RSA signatures:");
print_hashes(auth_types, hashes);
fprintf(stderr, "\n");
}
if ((auth_types & 0xFF00) != 0) {
fprintf(stderr, "supported: ECDSA signatures:");
print_hashes(auth_types >> 8, hashes >> 8);
fprintf(stderr, "\n");
}
if ((auth_types & 0x010000) != 0) {
fprintf(stderr, "supported:"
" fixed ECDH (cert signed with RSA)\n");
}
if ((auth_types & 0x020000) != 0) {
fprintf(stderr, "supported:"
" fixed ECDH (cert signed with ECDSA)\n");
}
if (scurve) {
fprintf(stderr, "server key curve: %s (%d)\n",
ec_curve_name(scurve), scurve);
} else {
fprintf(stderr, "server key is not EC\n");
}
}
switch (zc->sk->key_type) {
case BR_KEYTYPE_RSA:
if ((choices->hash_id = choose_hash(auth_types)) >= 0) {
if (zc->verbose) {
fprintf(stderr, "using RSA, hash = %d (%s)\n",
choices->hash_id,
hash_function_name(choices->hash_id));
}
choices->auth_type = BR_AUTH_RSA;
choices->chain = zc->chain;
choices->chain_len = zc->chain_len;
return;
}
break;
case BR_KEYTYPE_EC:
if (zc->issuer_key_type != 0
&& scurve == zc->sk->key.ec.curve)
{
int x;
x = (zc->issuer_key_type == BR_KEYTYPE_RSA) ? 16 : 17;
if (((auth_types >> x) & 1) != 0) {
if (zc->verbose) {
fprintf(stderr, "using static ECDH\n");
}
choices->auth_type = BR_AUTH_ECDH;
choices->hash_id = -1;
choices->chain = zc->chain;
choices->chain_len = zc->chain_len;
return;
}
}
if ((choices->hash_id = choose_hash(auth_types >> 8)) >= 0) {
if (zc->verbose) {
fprintf(stderr, "using ECDSA, hash = %d (%s)\n",
choices->hash_id,
hash_function_name(choices->hash_id));
}
choices->auth_type = BR_AUTH_ECDSA;
choices->chain = zc->chain;
choices->chain_len = zc->chain_len;
return;
}
break;
}
if (zc->verbose) {
fprintf(stderr, "no matching client certificate\n");
}
choices->chain = NULL;
choices->chain_len = 0;
}
static uint32_t
cc_do_keyx(const br_ssl_client_certificate_class **pctx,
unsigned char *data, size_t len)
{
ccert_context *zc;
zc = (ccert_context *)pctx;
return br_ec_prime_i31.mul(data, len, zc->sk->key.ec.x,
zc->sk->key.ec.xlen, zc->sk->key.ec.curve);
}
static size_t
cc_do_sign(const br_ssl_client_certificate_class **pctx,
int hash_id, size_t hv_len, unsigned char *data, size_t len)
{
ccert_context *zc;
unsigned char hv[64];
zc = (ccert_context *)pctx;
memcpy(hv, data, hv_len);
switch (zc->sk->key_type) {
const br_hash_class *hc;
const unsigned char *hash_oid;
uint32_t x;
size_t sig_len;
case BR_KEYTYPE_RSA:
hash_oid = get_hash_oid(hash_id);
if (hash_oid == NULL && hash_id != 0) {
if (zc->verbose) {
fprintf(stderr, "ERROR: cannot RSA-sign with"
" unknown hash function: %d\n",
hash_id);
}
return 0;
}
sig_len = (zc->sk->key.rsa.n_bitlen + 7) >> 3;
if (len < sig_len) {
if (zc->verbose) {
fprintf(stderr, "ERROR: cannot RSA-sign,"
" buffer is too small"
" (sig=%lu, buf=%lu)\n",
(unsigned long)sig_len,
(unsigned long)len);
}
return 0;
}
x = br_rsa_i31_pkcs1_sign(hash_oid, hv, hv_len,
&zc->sk->key.rsa, data);
if (!x) {
if (zc->verbose) {
fprintf(stderr, "ERROR: RSA-sign failure\n");
}
return 0;
}
return sig_len;
case BR_KEYTYPE_EC:
hc = get_hash_impl(hash_id);
if (hc == NULL) {
if (zc->verbose) {
fprintf(stderr, "ERROR: cannot ECDSA-sign with"
" unknown hash function: %d\n",
hash_id);
}
return 0;
}
if (len < 139) {
if (zc->verbose) {
fprintf(stderr, "ERROR: cannot ECDSA-sign"
" (output buffer = %lu)\n",
(unsigned long)len);
}
return 0;
}
sig_len = br_ecdsa_i31_sign_asn1(&br_ec_prime_i31,
hc, hv, &zc->sk->key.ec, data);
if (sig_len == 0) {
if (zc->verbose) {
fprintf(stderr, "ERROR: ECDSA-sign failure\n");
}
return 0;
}
return sig_len;
default:
return 0;
}
}
static const br_ssl_client_certificate_class ccert_vtable = {
sizeof(ccert_context),
cc_start_name_list,
cc_start_name,
cc_append_name,
cc_end_name,
cc_end_name_list,
cc_choose,
cc_do_keyx,
cc_do_sign
};
static void
usage_client(void)
{
@ -139,6 +441,12 @@ usage_client(void)
fprintf(stderr,
" -CA file add certificates in 'file' to trust anchors\n");
fprintf(stderr,
" -cert file set client certificate chain\n");
fprintf(stderr,
" -key file set client private key (for certificate authentication)\n");
fprintf(stderr,
" -nostaticecdh prohibit full-static ECDH (client certificate)\n");
fprintf(stderr,
" -list list supported names (protocols, algorithms...)\n");
fprintf(stderr,
" -vmin name set minimum supported version (default: TLS-1.0)\n");
@ -179,6 +487,11 @@ do_client(int argc, char *argv[])
br_x509_minimal_context xc;
x509_noanchor_context xwc;
const br_hash_class *dnhash;
ccert_context zc;
br_x509_certificate *chain;
size_t chain_len;
private_key *sk;
int nostaticecdh;
unsigned char *iobuf;
size_t iobuf_len;
size_t minhello_len;
@ -200,6 +513,10 @@ do_client(int argc, char *argv[])
num_suites = 0;
hfuns = 0;
suite_ids = NULL;
chain = NULL;
chain_len = 0;
sk = NULL;
nostaticecdh = 0;
iobuf = NULL;
iobuf_len = 0;
minhello_len = (size_t)-1;
@ -279,6 +596,44 @@ do_client(int argc, char *argv[])
usage_client();
goto client_exit_error;
}
} else if (eqstr(arg, "-cert")) {
if (++ i >= argc) {
fprintf(stderr,
"ERROR: no argument for '-cert'\n");
usage_client();
goto client_exit_error;
}
if (chain != NULL) {
fprintf(stderr,
"ERROR: duplicate certificate chain\n");
usage_client();
goto client_exit_error;
}
arg = argv[i];
chain = read_certificates(arg, &chain_len);
if (chain == NULL || chain_len == 0) {
goto client_exit_error;
}
} else if (eqstr(arg, "-key")) {
if (++ i >= argc) {
fprintf(stderr,
"ERROR: no argument for '-key'\n");
usage_client();
goto client_exit_error;
}
if (sk != NULL) {
fprintf(stderr,
"ERROR: duplicate private key\n");
usage_client();
goto client_exit_error;
}
arg = argv[i];
sk = read_private_key(arg);
if (sk == NULL) {
goto client_exit_error;
}
} else if (eqstr(arg, "-nostaticecdh")) {
nostaticecdh = 1;
} else if (eqstr(arg, "-list")) {
list_names();
goto client_exit;
@ -412,7 +767,7 @@ do_client(int argc, char *argv[])
}
if (u == 0) {
host = xstrdup(server_name);
port = "443";
port = xstrdup("443");
} else {
port = xstrdup(server_name + u);
host = xmalloc(u);
@ -423,6 +778,19 @@ do_client(int argc, char *argv[])
sni = host;
}
if (chain == NULL && sk != NULL) {
fprintf(stderr, "ERROR: private key specified, but"
" no certificate chain\n");
usage_client();
goto client_exit_error;
}
if (chain != NULL && sk == NULL) {
fprintf(stderr, "ERROR: certificate chain specified, but"
" no private key\n");
usage_client();
goto client_exit_error;
}
if (vmin == 0) {
vmin = BR_TLS10;
}
@ -560,11 +928,13 @@ do_client(int argc, char *argv[])
}
if ((req & REQ_ECDHE_RSA) != 0) {
br_ssl_engine_set_ec(&cc.eng, &br_ec_prime_i31);
br_ssl_client_set_rsavrfy(&cc, &br_rsa_i31_pkcs1_vrfy);
br_ssl_engine_set_rsavrfy(&cc.eng,
&br_rsa_i31_pkcs1_vrfy);
}
if ((req & REQ_ECDHE_ECDSA) != 0) {
br_ssl_engine_set_ec(&cc.eng, &br_ec_prime_i31);
br_ssl_client_set_ecdsa(&cc, &br_ecdsa_i31_vrfy_asn1);
br_ssl_engine_set_ecdsa(&cc.eng,
&br_ecdsa_i31_vrfy_asn1);
}
if ((req & REQ_ECDH) != 0) {
br_ssl_engine_set_ec(&cc.eng, &br_ec_prime_i31);
@ -624,6 +994,23 @@ do_client(int argc, char *argv[])
}
br_ssl_engine_set_all_flags(&cc.eng, flags);
if (chain != NULL) {
zc.vtable = &ccert_vtable;
zc.verbose = verbose;
zc.chain = chain;
zc.chain_len = chain_len;
zc.sk = sk;
if (nostaticecdh || sk->key_type != BR_KEYTYPE_EC) {
zc.issuer_key_type = 0;
} else {
zc.issuer_key_type = get_cert_signer_algo(&chain[0]);
if (zc.issuer_key_type == 0) {
goto client_exit_error;
}
}
br_ssl_client_set_client_certificate(&cc, &zc.vtable);
}
br_ssl_engine_set_buffer(&cc.eng, iobuf, iobuf_len, bidi);
br_ssl_client_reset(&cc, sni, 0);
@ -657,9 +1044,12 @@ do_client(int argc, char *argv[])
*/
client_exit:
xfree(host);
xfree(port);
xfree(suites);
xfree(suite_ids);
VEC_CLEAREXT(anchors, &free_ta_contents);
free_certificates(chain, chain_len);
free_private_key(sk);
xfree(iobuf);
if (fd >= 0) {
close(fd);

View file

@ -157,7 +157,18 @@ static struct {
}, {
BR_ERR_BAD_SIGNATURE,
"BR_ERR_BAD_SIGNATURE",
"Invalid signature on ServerKeyExchange message."
"Invalid signature in ServerKeyExchange or"
" CertificateVerify message."
}, {
BR_ERR_WRONG_KEY_USAGE,
"BR_ERR_WRONG_KEY_USAGE",
"Peer's public key does not have the proper type or is"
" not allowed for the requested operation."
}, {
BR_ERR_NO_CLIENT_AUTH,
"BR_ERR_NO_CLIENT_AUTH",
"Client did not send a certificate upon request, or the"
" client certificate could not be validated."
}, {
BR_ERR_IO,
"BR_ERR_IO",

View file

@ -300,3 +300,15 @@ read_certificates(const char *fname, size_t *num)
VEC_CLEAR(cert_list);
return xcs;
}
/* see brssl.h */
void
free_certificates(br_x509_certificate *certs, size_t num)
{
size_t u;
for (u = 0; u < num; u ++) {
xfree(certs[u].data);
}
xfree(certs);
}

View file

@ -168,3 +168,64 @@ free_private_key(private_key *sk)
}
xfree(sk);
}
/*
* OID for hash functions in RSA signatures.
*/
static const unsigned char HASH_OID_SHA1[] = {
0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A
};
static const unsigned char HASH_OID_SHA224[] = {
0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04
};
static const unsigned char HASH_OID_SHA256[] = {
0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01
};
static const unsigned char HASH_OID_SHA384[] = {
0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02
};
static const unsigned char HASH_OID_SHA512[] = {
0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03
};
static const unsigned char *HASH_OID[] = {
HASH_OID_SHA1,
HASH_OID_SHA224,
HASH_OID_SHA256,
HASH_OID_SHA384,
HASH_OID_SHA512
};
/* see brssl.h */
const unsigned char *
get_hash_oid(int id)
{
if (id >= 2 && id <= 6) {
return HASH_OID[id - 2];
} else {
return NULL;
}
}
/* see brssl.h */
const br_hash_class *
get_hash_impl(int hash_id)
{
size_t u;
for (u = 0; hash_functions[u].name; u ++) {
const br_hash_class *hc;
int id;
hc = hash_functions[u].hclass;
id = (hc->desc >> BR_HASHDESC_ID_OFF) & BR_HASHDESC_ID_MASK;
if (id == hash_id) {
return hc;
}
}
return NULL;
}

View file

@ -651,3 +651,20 @@ ec_curve_name(int curve)
return "unknown";
}
}
/* see brssl.h */
const char *
hash_function_name(int id)
{
switch (id) {
case br_md5sha1_ID: return "MD5+SHA-1";
case br_md5_ID: return "MD5";
case br_sha1_ID: return "SHA-1";
case br_sha224_ID: return "SHA-224";
case br_sha256_ID: return "SHA-256";
case br_sha384_ID: return "SHA-384";
case br_sha512_ID: return "SHA-512";
default:
return "unknown";
}
}

View file

@ -214,6 +214,10 @@ usage_server(void)
fprintf(stderr,
" -key fname read private key from file 'fname'\n");
fprintf(stderr,
" -CA file add trust anchors from 'file' (for client auth)\n");
fprintf(stderr,
" -anon_ok request but do not require a client certificate\n");
fprintf(stderr,
" -list list supported names (protocols, algorithms...)\n");
fprintf(stderr,
" -vmin name set minimum supported version (default: TLS-1.0)\n");
@ -237,20 +241,43 @@ typedef struct {
private_key *sk;
} policy_context;
static int
get_cert_signer_algo(br_x509_certificate *xc)
static void
print_hashes(unsigned chashes)
{
br_x509_decoder_context dc;
int err;
int i;
br_x509_decoder_init(&dc, 0, 0);
br_x509_decoder_push(&dc, xc->data, xc->data_len);
err = br_x509_decoder_last_error(&dc);
if (err != 0) {
return -err;
} else {
return br_x509_decoder_get_signer_key_type(&dc);
for (i = 2; i <= 6; i ++) {
if ((chashes >> i) & 1) {
int z;
switch (i) {
case 3: z = 224; break;
case 4: z = 256; break;
case 5: z = 384; break;
case 6: z = 512; break;
default:
z = 1;
break;
}
fprintf(stderr, " sha%d", z);
}
}
}
static int
choose_hash(unsigned chashes)
{
int hash_id;
for (hash_id = 6; hash_id >= 2; hash_id --) {
if (((chashes >> hash_id) & 1) != 0) {
return hash_id;
}
}
/*
* Normally unreachable.
*/
return 0;
}
static int
@ -262,16 +289,10 @@ sp_choose(const br_ssl_server_policy_class **pctx,
const br_suite_translated *st;
size_t u, st_num;
unsigned chashes;
int hash_id;
pc = (policy_context *)pctx;
st = br_ssl_server_get_client_suites(cc, &st_num);
chashes = br_ssl_server_get_client_hashes(cc);
for (hash_id = 6; hash_id >= 2; hash_id --) {
if ((chashes >> hash_id) & 1) {
break;
}
}
if (pc->verbose) {
fprintf(stderr, "Client parameters:\n");
fprintf(stderr, " Maximum version: ");
@ -301,25 +322,18 @@ sp_choose(const br_ssl_server_policy_class **pctx,
get_suite_name_ext(st[u][0], csn, sizeof csn);
fprintf(stderr, " %s\n", csn);
}
fprintf(stderr, " Common hash functions:");
for (u = 2; u <= 6; u ++) {
if ((chashes >> u) & 1) {
int z;
switch (u) {
case 3: z = 224; break;
case 4: z = 256; break;
case 5: z = 384; break;
case 6: z = 512; break;
default:
z = 1;
break;
}
fprintf(stderr, " sha%d", z);
}
}
fprintf(stderr, " Common sign+hash functions:\n");
if ((chashes & 0xFF) != 0) {
fprintf(stderr, " with RSA:");
print_hashes(chashes);
fprintf(stderr, "\n");
}
if ((chashes >> 8) != 0) {
fprintf(stderr, " with ECDSA:");
print_hashes(chashes >> 8);
fprintf(stderr, "\n");
}
}
for (u = 0; u < st_num; u ++) {
unsigned tt;
@ -337,9 +351,10 @@ sp_choose(const br_ssl_server_policy_class **pctx,
if (br_ssl_engine_get_version(&cc->eng)
< BR_TLS12)
{
hash_id = 0;
choices->hash_id = 0;
} else {
choices->hash_id = choose_hash(chashes);
}
choices->hash_id = hash_id;
goto choose_ok;
}
break;
@ -349,9 +364,11 @@ sp_choose(const br_ssl_server_policy_class **pctx,
if (br_ssl_engine_get_version(&cc->eng)
< BR_TLS12)
{
hash_id = br_sha1_ID;
choices->hash_id = br_sha1_ID;
} else {
choices->hash_id =
choose_hash(chashes >> 8);
}
choices->hash_id = hash_id;
goto choose_ok;
}
break;
@ -409,55 +426,6 @@ sp_do_keyx(const br_ssl_server_policy_class **pctx,
}
}
/*
* OID for hash functions in RSA signatures.
*/
static const unsigned char HASH_OID_SHA1[] = {
0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A
};
static const unsigned char HASH_OID_SHA224[] = {
0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04
};
static const unsigned char HASH_OID_SHA256[] = {
0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01
};
static const unsigned char HASH_OID_SHA384[] = {
0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02
};
static const unsigned char HASH_OID_SHA512[] = {
0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03
};
static const unsigned char *HASH_OID[] = {
HASH_OID_SHA1,
HASH_OID_SHA224,
HASH_OID_SHA256,
HASH_OID_SHA384,
HASH_OID_SHA512
};
static const br_hash_class *
get_hash_impl(int hash_id)
{
size_t u;
for (u = 0; hash_functions[u].name; u ++) {
const br_hash_class *hc;
int id;
hc = hash_functions[u].hclass;
id = (hc->desc >> BR_HASHDESC_ID_OFF) & BR_HASHDESC_ID_MASK;
if (id == hash_id) {
return hc;
}
}
return NULL;
}
static size_t
sp_do_sign(const br_ssl_server_policy_class **pctx,
int hash_id, size_t hv_len, unsigned char *data, size_t len)
@ -474,11 +442,8 @@ sp_do_sign(const br_ssl_server_policy_class **pctx,
const br_hash_class *hc;
case BR_KEYTYPE_RSA:
if (hash_id == 0) {
hash_oid = NULL;
} else if (hash_id >= 2 && hash_id <= 6) {
hash_oid = HASH_OID[hash_id - 2];
} else {
hash_oid = get_hash_oid(hash_id);
if (hash_oid == NULL && hash_id != 0) {
if (pc->verbose) {
fprintf(stderr, "ERROR: cannot RSA-sign with"
" unknown hash function: %d\n",
@ -566,6 +531,9 @@ do_server(int argc, char *argv[])
size_t chain_len;
int cert_signer_algo;
private_key *sk;
anchor_list anchors = VEC_INIT;
br_x509_minimal_context xc;
const br_hash_class *dnhash;
size_t u;
br_ssl_server_context cc;
policy_context pc;
@ -713,6 +681,20 @@ do_server(int argc, char *argv[])
if (sk == NULL) {
goto server_exit_error;
}
} else if (eqstr(arg, "-CA")) {
if (++ i >= argc) {
fprintf(stderr,
"ERROR: no argument for '-CA'\n");
usage_server();
goto server_exit_error;
}
arg = argv[i];
if (read_trust_anchors(&anchors, arg) == 0) {
usage_server();
goto server_exit_error;
}
} else if (eqstr(arg, "-anon_ok")) {
flags |= BR_OPT_TOLERATE_NO_CLIENT_AUTH;
} else if (eqstr(arg, "-list")) {
list_names();
goto server_exit;
@ -872,11 +854,10 @@ do_server(int argc, char *argv[])
break;
}
cert_signer_algo = get_cert_signer_algo(chain);
if (cert_signer_algo < 0) {
fprintf(stderr, "ERROR: server certificate cannot be"
" decoded (err=%d)\n", -cert_signer_algo);
if (cert_signer_algo == 0) {
goto server_exit_error;
} else if (verbose) {
}
if (verbose) {
const char *csas;
switch (cert_signer_algo) {
@ -980,6 +961,7 @@ do_server(int argc, char *argv[])
}
br_ssl_engine_set_suites(&cc.eng, suite_ids, num_suites);
dnhash = NULL;
for (u = 0; hash_functions[u].name; u ++) {
const br_hash_class *hc;
int id;
@ -987,6 +969,7 @@ do_server(int argc, char *argv[])
hc = hash_functions[u].hclass;
id = (hc->desc >> BR_HASHDESC_ID_OFF) & BR_HASHDESC_ID_MASK;
if ((hfuns & ((unsigned)1 << id)) != 0) {
dnhash = hc;
br_ssl_engine_set_hash(&cc.eng, id, hc);
}
}
@ -1007,6 +990,11 @@ do_server(int argc, char *argv[])
br_ssl_session_cache_lru_init(&lru, cache, cache_len);
br_ssl_server_set_cache(&cc, &lru.vtable);
/*
* Set the policy handler (that chooses the actual cipher suite,
* selects the certificate chain, and runs the private key
* operations).
*/
pc.vtable = &policy_vtable;
pc.verbose = verbose;
pc.chain = chain;
@ -1015,6 +1003,36 @@ do_server(int argc, char *argv[])
pc.sk = sk;
br_ssl_server_set_policy(&cc, &pc.vtable);
/*
* If trust anchors have been configured, then set an X.509
* validation engine and activate client certificate
* authentication.
*/
if (VEC_LEN(anchors) != 0) {
br_x509_minimal_init(&xc, dnhash,
&VEC_ELT(anchors, 0), VEC_LEN(anchors));
for (u = 0; hash_functions[u].name; u ++) {
const br_hash_class *hc;
int id;
hc = hash_functions[u].hclass;
id = (hc->desc >> BR_HASHDESC_ID_OFF)
& BR_HASHDESC_ID_MASK;
if ((hfuns & ((unsigned)1 << id)) != 0) {
br_x509_minimal_set_hash(&xc, id, hc);
}
}
br_ssl_engine_set_rsavrfy(&cc.eng, &br_rsa_i31_pkcs1_vrfy);
br_ssl_engine_set_ec(&cc.eng, &br_ec_prime_i31);
br_ssl_engine_set_ecdsa(&cc.eng, &br_ecdsa_i31_vrfy_asn1);
br_x509_minimal_set_rsa(&xc, &br_rsa_i31_pkcs1_vrfy);
br_x509_minimal_set_ecdsa(&xc,
&br_ec_prime_i31, &br_ecdsa_i31_vrfy_asn1);
br_ssl_engine_set_x509(&cc.eng, &xc.vtable);
br_ssl_server_set_trust_anchor_names_alt(&cc,
&VEC_ELT(anchors, 0), VEC_LEN(anchors));
}
br_ssl_engine_set_buffer(&cc.eng, iobuf, iobuf_len, bidi);
/*
@ -1061,13 +1079,9 @@ do_server(int argc, char *argv[])
server_exit:
xfree(suites);
xfree(suite_ids);
if (chain != NULL) {
for (u = 0; u < chain_len; u ++) {
xfree(chain[u].data);
}
xfree(chain);
}
free_certificates(chain, chain_len);
free_private_key(sk);
VEC_CLEAREXT(anchors, &free_ta_contents);
xfree(iobuf);
xfree(cache);
if (fd >= 0) {

View file

@ -93,7 +93,7 @@ print_ta_internals(br_x509_trust_anchor *ta, long ctr)
char tmp[25];
sprintf(tmp, "TA%ld_DN", ctr);
print_blob(tmp, ta->dn, ta->dn_len);
print_blob(tmp, ta->dn.data, ta->dn.len);
switch (ta->pkey.key_type) {
case BR_KEYTYPE_RSA:
sprintf(tmp, "TA%ld_RSA_N", ctr);
@ -119,7 +119,8 @@ print_ta(br_x509_trust_anchor *ta, long ctr)
char tmp[25];
printf("\t{\n");
printf("\t\t(unsigned char *)TA%ld_DN, sizeof TA%ld_DN,\n", ctr, ctr);
printf("\t\t{ (unsigned char *)TA%ld_DN, sizeof TA%ld_DN },\n",
ctr, ctr);
printf("\t\t%s,\n", (ta->flags & BR_X509_TA_CA)
? "BR_X509_TA_CA" : "0");
printf("\t\t{\n");

View file

@ -181,9 +181,11 @@ do_verify(int argc, char *argv[])
cert_list chain = VEC_INIT;
size_t u;
br_x509_minimal_context mc;
int err_keyx, err_sign;
int err;
int print_text, print_C;
br_x509_pkey *pk;
const br_x509_pkey *tpk;
unsigned usages;
retcode = 0;
verbose = 1;
@ -191,8 +193,6 @@ do_verify(int argc, char *argv[])
print_text = 0;
print_C = 0;
pk = NULL;
err_keyx = 0;
err_sign = 0;
for (i = 0; i < argc; i ++) {
const char *arg;
@ -266,12 +266,8 @@ do_verify(int argc, char *argv[])
br_x509_minimal_set_rsa(&mc, &br_rsa_i31_pkcs1_vrfy);
br_x509_minimal_set_ecdsa(&mc,
&br_ec_prime_i31, &br_ecdsa_i31_vrfy_asn1);
for (i = 0; i < 2; i ++) {
const br_x509_pkey *tpk;
int err;
mc.vtable->start_chain(&mc.vtable,
i == 0 ? BR_KEYTYPE_KEYX : BR_KEYTYPE_SIGN, sni);
mc.vtable->start_chain(&mc.vtable, sni);
for (u = 0; u < VEC_LEN(chain); u ++) {
br_x509_certificate *xc;
@ -281,40 +277,33 @@ do_verify(int argc, char *argv[])
mc.vtable->end_cert(&mc.vtable);
}
err = mc.vtable->end_chain(&mc.vtable);
if (i == 0) {
err_keyx = err;
} else {
err_sign = err;
}
tpk = mc.vtable->get_pkey(&mc.vtable);
if (pk == NULL && tpk != NULL) {
tpk = mc.vtable->get_pkey(&mc.vtable, &usages);
if (tpk != NULL) {
pk = xpkeydup(tpk);
}
}
if (err_keyx == 0 || err_sign == 0) {
if (err == 0) {
if (verbose) {
fprintf(stderr, "Validation success");
if (err_keyx == 0 && err_sign == 0) {
fprintf(stderr, " (key exchange, sign)\n");
} else if (err_keyx == 0) {
fprintf(stderr, " (key exchange)\n");
} else if (err_sign == 0) {
fprintf(stderr, " (signature)\n");
int hkx;
fprintf(stderr, "Validation success; usages:");
hkx = 0;
if (usages & BR_KEYTYPE_KEYX) {
fprintf(stderr, " key exchange");
hkx = 1;
}
if (usages & BR_KEYTYPE_SIGN) {
if (hkx) {
fprintf(stderr, ",");
}
fprintf(stderr, " signature");
}
fprintf(stderr, "\n");
}
} else {
if (verbose) {
int err;
const char *errname, *errmsg;
/*
* If the two error codes differ, we want the one
* which is not a "forbidden key usage".
*/
err = err_keyx;
if (err == BR_ERR_X509_FORBIDDEN_KEY_USAGE) {
err = err_sign;
}
fprintf(stderr, "Validation failed, err = %d", err);
errname = find_error_name(err, &errmsg);
if (errname != NULL) {