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:
parent
e9ce2f4e8c
commit
e61ad42191
27 changed files with 4441 additions and 1482 deletions
16
Makefile
16
Makefile
|
|
@ -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
|
OBJMAC = $(BUILD)/hmac.o $(BUILD)/hmac_ct.o
|
||||||
OBJRAND = $(BUILD)/hmac_drbg.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
|
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
|
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
|
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)
|
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)
|
$(BUILD)/prf_sha384.o: src/ssl/prf_sha384.c $(HEADERS)
|
||||||
$(CC) $(CFLAGS) -c -o $(BUILD)/prf_sha384.o src/ssl/prf_sha384.c
|
$(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)
|
$(BUILD)/ssl_client.o: src/ssl/ssl_client.c $(HEADERS)
|
||||||
$(CC) $(CFLAGS) -c -o $(BUILD)/ssl_client.o src/ssl/ssl_client.c
|
$(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)
|
$(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
|
$(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)
|
$(BUILD)/ssl_scert_single_ec.o: src/ssl/ssl_scert_single_ec.c $(HEADERS)
|
||||||
$(CC) $(CFLAGS) -c -o $(BUILD)/ssl_single_ec.o src/ssl/ssl_single_ec.c
|
$(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)
|
$(BUILD)/ssl_scert_single_rsa.o: src/ssl/ssl_scert_single_rsa.c $(HEADERS)
|
||||||
$(CC) $(CFLAGS) -c -o $(BUILD)/ssl_single_rsa.o src/ssl/ssl_single_rsa.c
|
$(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)
|
$(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
|
$(CC) $(CFLAGS) -c -o $(BUILD)/aes_big_cbcdec.o src/symcipher/aes_big_cbcdec.c
|
||||||
|
|
|
||||||
|
|
@ -191,9 +191,18 @@
|
||||||
signature algorithm, hash function). */
|
signature algorithm, hash function). */
|
||||||
#define BR_ERR_INVALID_ALGORITHM 26
|
#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
|
#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
|
/** \brief SSL status: I/O error or premature close on underlying
|
||||||
transport stream. This error code is set only by the simplified
|
transport stream. This error code is set only by the simplified
|
||||||
I/O API ("br_sslio_*"). */
|
I/O API ("br_sslio_*"). */
|
||||||
|
|
@ -769,12 +778,11 @@ typedef struct {
|
||||||
uint32_t flags;
|
uint32_t flags;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Context variables for the handshake processor.
|
* Context variables for the handshake processor. The 'pad' must
|
||||||
* The 'pad' must be large enough to accommodate an
|
* be large enough to accommodate an RSA-encrypted pre-master
|
||||||
* RSA-encrypted pre-master secret, or a RSA signature on
|
* secret, or an RSA signature; since we want to support up to
|
||||||
* key exchange parameters; since we want to support up to
|
* RSA-4096, this means at least 512 bytes. (Other pad usages
|
||||||
* RSA-4096, this means at least 512 bytes.
|
* require its length to be at least 256.)
|
||||||
* (Other pad usages require its length to be at least 256.)
|
|
||||||
*/
|
*/
|
||||||
struct {
|
struct {
|
||||||
uint32_t *dp;
|
uint32_t *dp;
|
||||||
|
|
@ -825,6 +833,16 @@ typedef struct {
|
||||||
*/
|
*/
|
||||||
const br_x509_class **x509ctx;
|
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
|
* Pointers to implementations; left to NULL for unsupported
|
||||||
* functions. For the raw hash functions, implementations are
|
* 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_in_gcm_class *igcm_in;
|
||||||
const br_sslrec_out_gcm_class *igcm_out;
|
const br_sslrec_out_gcm_class *igcm_out;
|
||||||
const br_ec_impl *iec;
|
const br_ec_impl *iec;
|
||||||
|
br_rsa_pkcs1_vrfy irsavrfy;
|
||||||
|
br_ecdsa_vrfy iecdsa;
|
||||||
#endif
|
#endif
|
||||||
} br_ssl_engine_context;
|
} 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)
|
#define BR_OPT_ENFORCE_SERVER_PREFERENCES ((uint32_t)1 << 0)
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* \brief Behavioural flag: disable renegotiation.
|
* \brief Behavioural flag: disable renegotiation.
|
||||||
*
|
*
|
||||||
* If this flag is set, then renegotiations are rejected unconditionally:
|
* 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)
|
#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.
|
* \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;
|
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.
|
* \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);
|
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.
|
* \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
|
* a pointer to that field. The other structure fields are opaque and
|
||||||
* must not be accessed directly.
|
* must not be accessed directly.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
struct br_ssl_client_context_ {
|
||||||
/**
|
/**
|
||||||
* \brief The encapsulated engine context.
|
* \brief The encapsulated engine context.
|
||||||
*/
|
*/
|
||||||
|
|
@ -1620,14 +2018,82 @@ typedef struct {
|
||||||
*/
|
*/
|
||||||
uint16_t min_clienthello_len;
|
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.
|
* Implementations.
|
||||||
*/
|
*/
|
||||||
br_rsa_public irsapub;
|
br_rsa_public irsapub;
|
||||||
br_rsa_pkcs1_vrfy irsavrfy;
|
|
||||||
br_ecdsa_vrfy iecdsa;
|
|
||||||
#endif
|
#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
|
* 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);
|
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.
|
* \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;
|
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).
|
* \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;
|
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
|
* \brief Type for a "translated cipher suite", as an array of two
|
||||||
* 16-bit integers.
|
* 16-bit integers.
|
||||||
|
|
@ -1906,6 +2425,7 @@ typedef struct {
|
||||||
* \brief Certificate chain length (number of certificates).
|
* \brief Certificate chain length (number of certificates).
|
||||||
*/
|
*/
|
||||||
size_t chain_len;
|
size_t chain_len;
|
||||||
|
|
||||||
} br_ssl_server_choices;
|
} br_ssl_server_choices;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -2244,10 +2764,6 @@ struct br_ssl_server_context_ {
|
||||||
* Context for chain handler.
|
* Context for chain handler.
|
||||||
*/
|
*/
|
||||||
const br_ssl_server_policy_class **policy_vtable;
|
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;
|
unsigned char sign_hash_id;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -2266,6 +2782,25 @@ struct br_ssl_server_context_ {
|
||||||
unsigned char ecdhe_key[70];
|
unsigned char ecdhe_key[70];
|
||||||
size_t ecdhe_key_len;
|
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.
|
* Server-specific implementations.
|
||||||
* (none for now)
|
* (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,
|
const br_rsa_private_key *sk, unsigned allowed_usages,
|
||||||
br_rsa_private irsacore, br_rsa_pkcs1_sign irsasign);
|
br_rsa_private irsacore, br_rsa_pkcs1_sign irsasign);
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* \brief Set the server certificate chain and key (single EC case).
|
* \brief Set the server certificate chain and key (single EC case).
|
||||||
*
|
*
|
||||||
* This function uses a policy context included in the server context.
|
* 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,
|
unsigned cert_issuer_key_type,
|
||||||
const br_ec_impl *iec, br_ecdsa_sign iecdsa);
|
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.
|
* \brief Configure the cache for session parameters.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -95,12 +95,12 @@
|
||||||
* include some limited processing for case-insensitive matching and
|
* include some limited processing for case-insensitive matching and
|
||||||
* whitespace normalisation).
|
* whitespace normalisation).
|
||||||
*
|
*
|
||||||
* - When doing validation, a target public key type is provided. That
|
* - Successful validation produces a public key type but also a set
|
||||||
* type is the combination of a key algorithm (RSA or EC) and an
|
* of allowed usages (`BR_KEYTYPE_KEYX` and/or `BR_KEYTYPE_SIGN`).
|
||||||
* intended key usage (key exchange or signature); in the context
|
* The caller is responsible for checking that the key type and
|
||||||
* of a SSL/TLS client validating a server's certificate, the algorithm
|
* usages are compatible with the expected values (e.g. with the
|
||||||
* and usage are obtained from the cipher suite (e.g. ECDHE_RSA means
|
* selected cipher suite, when the client validates the server's
|
||||||
* that an RSA key for signatures is expected).
|
* certificate).
|
||||||
*
|
*
|
||||||
* **Important caveats:**
|
* **Important caveats:**
|
||||||
*
|
*
|
||||||
|
|
@ -233,14 +233,24 @@ typedef struct {
|
||||||
} key;
|
} key;
|
||||||
} br_x509_pkey;
|
} 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.
|
* \brief Trust anchor structure.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
/** \brief Encoded DN (X.500 name). */
|
/** \brief Encoded DN (X.500 name). */
|
||||||
unsigned char *dn;
|
br_x500_name dn;
|
||||||
/** \brief Encoded DN length (in bytes). */
|
|
||||||
size_t dn_len;
|
|
||||||
/** \brief Anchor flags (e.g. `BR_X509_TA_CA`). */
|
/** \brief Anchor flags (e.g. `BR_X509_TA_CA`). */
|
||||||
unsigned flags;
|
unsigned flags;
|
||||||
/** \brief Anchor public key. */
|
/** \brief Anchor public key. */
|
||||||
|
|
@ -364,10 +374,6 @@ struct br_x509_class_ {
|
||||||
* This method shall set the vtable (first field) of the context
|
* This method shall set the vtable (first field) of the context
|
||||||
* structure.
|
* 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
|
* The `server_name`, if not `NULL`, will be considered as a
|
||||||
* fully qualified domain name, to be matched against the `dNSName`
|
* fully qualified domain name, to be matched against the `dNSName`
|
||||||
* elements of the end-entity certificate's SAN extension (if there
|
* 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.
|
* If `server_name` is `NULL` then no such matching is performed.
|
||||||
*
|
*
|
||||||
* \param ctx validation context.
|
* \param ctx validation context.
|
||||||
* \param expected_key_type expected key type (algorithm and usage).
|
|
||||||
* \param server_name server name to match (or `NULL`).
|
* \param server_name server name to match (or `NULL`).
|
||||||
*/
|
*/
|
||||||
void (*start_chain)(const br_x509_class **ctx,
|
void (*start_chain)(const br_x509_class **ctx,
|
||||||
unsigned expected_key_type,
|
|
||||||
const char *server_name);
|
const char *server_name);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -446,10 +450,17 @@ struct br_x509_class_ {
|
||||||
* a decoded public key even if the chain did not end on a
|
* a decoded public key even if the chain did not end on a
|
||||||
* trusted anchor.
|
* 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.
|
* \param ctx validation context.
|
||||||
* \return the end-entity public key, or `NULL`.
|
* \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;
|
const br_x509_class *vtable;
|
||||||
#ifndef BR_DOXYGEN_IGNORE
|
#ifndef BR_DOXYGEN_IGNORE
|
||||||
br_x509_pkey pkey;
|
br_x509_pkey pkey;
|
||||||
|
unsigned usages;
|
||||||
#endif
|
#endif
|
||||||
} br_x509_knownkey_context;
|
} 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.
|
* \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
|
* The provided pointers are linked in, not copied, so they must remain
|
||||||
* valid while the public key may be in usage.
|
* valid while the public key may be in usage.
|
||||||
*
|
*
|
||||||
* \param ctx context to initialise.
|
* \param ctx context to initialise.
|
||||||
* \param pk known public key.
|
* \param pk known public key.
|
||||||
|
* \param usages allowed key usages.
|
||||||
*/
|
*/
|
||||||
void br_x509_knownkey_init_rsa(br_x509_knownkey_context *ctx,
|
void br_x509_knownkey_init_rsa(br_x509_knownkey_context *ctx,
|
||||||
const br_rsa_public_key *pk);
|
const br_rsa_public_key *pk, unsigned usages);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Initialize a "known key" X.509 engine with a known EC public key.
|
* \brief Initialize a "known key" X.509 engine with a known EC public key.
|
||||||
*
|
*
|
||||||
|
* The `usages` parameter indicates the allowed key usages for that key
|
||||||
|
* (`BR_KEYTYPE_KEYX` and/or `BR_KEYTYPE_SIGN`).
|
||||||
|
*
|
||||||
* The provided pointers are linked in, not copied, so they must remain
|
* The provided pointers are linked in, not copied, so they must remain
|
||||||
* valid while the public key may be in usage.
|
* valid while the public key may be in usage.
|
||||||
*
|
*
|
||||||
* \param ctx context to initialise.
|
* \param ctx context to initialise.
|
||||||
* \param pk known public key.
|
* \param pk known public key.
|
||||||
|
* \param usages allowed key usages.
|
||||||
*/
|
*/
|
||||||
void br_x509_knownkey_init_ec(br_x509_knownkey_context *ctx,
|
void br_x509_knownkey_init_ec(br_x509_knownkey_context *ctx,
|
||||||
const br_ec_public_key *pk);
|
const br_ec_public_key *pk, unsigned usages);
|
||||||
|
|
||||||
#ifndef BR_DOXYGEN_IGNORE
|
#ifndef BR_DOXYGEN_IGNORE
|
||||||
/*
|
/*
|
||||||
|
|
@ -560,8 +580,8 @@ typedef struct {
|
||||||
/* Server name to match with the SAN / CN of the EE certificate. */
|
/* Server name to match with the SAN / CN of the EE certificate. */
|
||||||
const char *server_name;
|
const char *server_name;
|
||||||
|
|
||||||
/* Expected EE key type and usage. */
|
/* Validated key usages. */
|
||||||
unsigned char expected_key_type;
|
unsigned char key_usages;
|
||||||
|
|
||||||
/* Explicitly set date and time. */
|
/* Explicitly set date and time. */
|
||||||
uint32_t days, seconds;
|
uint32_t days, seconds;
|
||||||
|
|
|
||||||
150
src/ssl/ssl_ccert_single_ec.c
Normal file
150
src/ssl/ssl_ccert_single_ec.c
Normal 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;
|
||||||
|
}
|
||||||
149
src/ssl/ssl_ccert_single_rsa.c
Normal file
149
src/ssl/ssl_ccert_single_rsa.c
Normal 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;
|
||||||
|
}
|
||||||
|
|
@ -123,9 +123,9 @@ br_ssl_client_init_full(br_ssl_client_context *cc,
|
||||||
br_ssl_engine_set_suites(&cc->eng, suites,
|
br_ssl_engine_set_suites(&cc->eng, suites,
|
||||||
(sizeof suites) / (sizeof suites[0]));
|
(sizeof suites) / (sizeof suites[0]));
|
||||||
br_ssl_client_set_rsapub(cc, &br_rsa_i31_public);
|
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_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_rsa(xc, &br_rsa_i31_pkcs1_vrfy);
|
||||||
br_x509_minimal_set_ecdsa(xc,
|
br_x509_minimal_set_ecdsa(xc,
|
||||||
&br_ec_prime_i31, &br_ecdsa_i31_vrfy_asn1);
|
&br_ec_prime_i31, &br_ecdsa_i31_vrfy_asn1);
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -55,7 +55,7 @@ make_pms_rsa(br_ssl_client_context *ctx, int prf_id)
|
||||||
size_t nlen, u;
|
size_t nlen, u;
|
||||||
|
|
||||||
xc = ctx->eng.x509ctx;
|
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.
|
* 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.
|
* Check the RSA signature on the ServerKeyExchange message.
|
||||||
|
*
|
||||||
* hash hash function ID (2 to 6), or 0 for MD5+SHA-1 (with RSA only)
|
* 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
|
* use_rsa non-zero for RSA signature, zero for ECDSA
|
||||||
* sig_len signature length (in bytes); signature value is in the pad
|
* sig_len signature length (in bytes); signature value is in the pad
|
||||||
|
*
|
||||||
* Returned value is 0 on success, or an error code.
|
* Returned value is 0 on success, or an error code.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
|
|
@ -161,7 +163,7 @@ verify_SKE_sig(br_ssl_client_context *ctx,
|
||||||
size_t hv_len;
|
size_t hv_len;
|
||||||
|
|
||||||
xc = ctx->eng.x509ctx;
|
xc = ctx->eng.x509ctx;
|
||||||
pk = (*xc)->get_pkey(xc);
|
pk = (*xc)->get_pkey(xc, NULL);
|
||||||
br_multihash_zero(&mhc);
|
br_multihash_zero(&mhc);
|
||||||
br_multihash_copyimpl(&mhc, &ctx->eng.mhash);
|
br_multihash_copyimpl(&mhc, &ctx->eng.mhash);
|
||||||
br_multihash_init(&mhc);
|
br_multihash_init(&mhc);
|
||||||
|
|
@ -198,14 +200,14 @@ verify_SKE_sig(br_ssl_client_context *ctx,
|
||||||
} else {
|
} else {
|
||||||
hash_oid = NULL;
|
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)
|
hash_oid, hv_len, &pk->key.rsa, tmp)
|
||||||
|| memcmp(tmp, hv, hv_len) != 0)
|
|| memcmp(tmp, hv, hv_len) != 0)
|
||||||
{
|
{
|
||||||
return BR_ERR_BAD_SIGNATURE;
|
return BR_ERR_BAD_SIGNATURE;
|
||||||
}
|
}
|
||||||
} else {
|
} 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))
|
ctx->eng.pad, sig_len))
|
||||||
{
|
{
|
||||||
return BR_ERR_BAD_SIGNATURE;
|
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
|
* 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.
|
* 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;
|
const br_x509_pkey *pk;
|
||||||
|
|
||||||
xc = ctx->eng.x509ctx;
|
xc = ctx->eng.x509ctx;
|
||||||
pk = (*xc)->get_pkey(xc);
|
pk = (*xc)->get_pkey(xc, NULL);
|
||||||
curve = pk->key.ec.curve;
|
curve = pk->key.ec.curve;
|
||||||
point_src = pk->key.ec.q;
|
point_src = pk->key.ec.q;
|
||||||
point_len = pk->key.ec.qlen;
|
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;
|
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 ; ;
|
postpone literal postpone ; ;
|
||||||
|
|
||||||
addr-ctx: min_clienthello_len
|
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
|
\ Length of the Secure Renegotiation extension. This is 5 for the
|
||||||
\ first handshake, 17 for a renegotiation (if the server supports 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 )
|
: ext-frag-length ( -- len )
|
||||||
addr-log_max_frag_len get8 14 = if 0 else 5 then ;
|
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.
|
\ Length of Signatures extension.
|
||||||
: ext-signatures-length ( -- len )
|
: ext-signatures-length ( -- len )
|
||||||
supported-hash-functions { x } drop
|
supported-hash-functions { x } drop
|
||||||
|
|
@ -709,80 +771,26 @@ cc: DEBUG-BLOB ( addr len -- ) {
|
||||||
resume
|
resume
|
||||||
;
|
;
|
||||||
|
|
||||||
cc: x509-start-chain ( expected-key-type -- ) {
|
cc: set-server-curve ( -- ) {
|
||||||
const br_x509_class *xc;
|
const br_x509_class *xc;
|
||||||
|
const br_x509_pkey *pk;
|
||||||
|
|
||||||
xc = *(ENG->x509ctx);
|
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 -- ) {
|
\ Read Certificate message from server.
|
||||||
const br_x509_class *xc;
|
: read-Certificate-from-server ( -- )
|
||||||
|
|
||||||
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.
|
|
||||||
addr-cipher_suite get16 expected-key-type
|
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.
|
\ Set server curve (used for static ECDH).
|
||||||
read24 open-elt
|
set-server-curve ;
|
||||||
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
|
|
||||||
;
|
|
||||||
|
|
||||||
\ Verify signature on ECDHE point sent by the server.
|
\ 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)
|
\ '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 ;
|
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.
|
\ Parse CertificateRequest. Header has already been read.
|
||||||
: read-contents-CertificateRequest ( lim -- )
|
: read-contents-CertificateRequest ( lim -- )
|
||||||
\ TODO: implement client certificates. Right now, we simply
|
\ Read supported client authentification types. We keep only
|
||||||
\ drop the complete message.
|
\ RSA, ECDSA, and ECDH.
|
||||||
begin dup while read8 drop repeat drop ;
|
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 an empty Certificate message.
|
||||||
: write-empty-Certificate ( -- )
|
\ : write-empty-Certificate ( -- )
|
||||||
11 write8 3 write24 0 write24 ;
|
\ 11 write8 3 write24 0 write24 ;
|
||||||
|
|
||||||
cc: do-rsa-encrypt ( prf_id -- nlen ) {
|
cc: do-rsa-encrypt ( prf_id -- nlen ) {
|
||||||
int x;
|
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 ( -- )
|
: write-ClientKeyExchange ( -- )
|
||||||
16 write8
|
16 write8
|
||||||
addr-cipher_suite get16
|
addr-cipher_suite get16
|
||||||
|
|
@ -903,6 +1082,20 @@ cc: do-ecdh ( echde prf_id -- ulen ) {
|
||||||
addr-pad swap write-blob
|
addr-pad swap write-blob
|
||||||
then ;
|
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.
|
\ Perform a handshake.
|
||||||
|
|
@ -924,7 +1117,9 @@ cc: do-ecdh ( echde prf_id -- ulen ) {
|
||||||
|
|
||||||
\ Not a session resumption.
|
\ 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
|
\ Depending on cipher suite, we may now expect a
|
||||||
\ ServerKeyExchange.
|
\ ServerKeyExchange.
|
||||||
|
|
@ -956,12 +1151,27 @@ cc: do-ecdh ( echde prf_id -- ulen ) {
|
||||||
more-incoming-bytes? if ERR_UNEXPECTED fail then
|
more-incoming-bytes? if ERR_UNEXPECTED fail then
|
||||||
|
|
||||||
seen-CR if
|
seen-CR if
|
||||||
\ TODO: client certificate support.
|
\ If the server requested a client certificate, then
|
||||||
write-empty-Certificate
|
\ we must write a Certificate message (it may be
|
||||||
then
|
\ empty).
|
||||||
write-ClientKeyExchange
|
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 write-CCS-Finished
|
||||||
-1 read-CCS-Finished
|
-1 read-CCS-Finished
|
||||||
|
|
|
||||||
|
|
@ -145,12 +145,8 @@ addr-eng: version_max
|
||||||
addr-eng: suites_buf
|
addr-eng: suites_buf
|
||||||
addr-eng: suites_num
|
addr-eng: suites_num
|
||||||
addr-eng: server_name
|
addr-eng: server_name
|
||||||
\ addr-eng: version
|
|
||||||
\ addr-eng: cipher_suite
|
|
||||||
addr-eng: client_random
|
addr-eng: client_random
|
||||||
addr-eng: server_random
|
addr-eng: server_random
|
||||||
\ addr-eng: session_id_len
|
|
||||||
\ addr-eng: session_id
|
|
||||||
addr-eng: ecdhe_curve
|
addr-eng: ecdhe_curve
|
||||||
addr-eng: ecdhe_point
|
addr-eng: ecdhe_point
|
||||||
addr-eng: ecdhe_point_len
|
addr-eng: ecdhe_point_len
|
||||||
|
|
@ -212,6 +208,9 @@ err: ERR_LIMIT_EXCEEDED
|
||||||
err: ERR_BAD_FINISHED
|
err: ERR_BAD_FINISHED
|
||||||
err: ERR_RESUME_MISMATCH
|
err: ERR_RESUME_MISMATCH
|
||||||
err: ERR_INVALID_ALGORITHM
|
err: ERR_INVALID_ALGORITHM
|
||||||
|
err: ERR_BAD_SIGNATURE
|
||||||
|
err: ERR_WRONG_KEY_USAGE
|
||||||
|
err: ERR_NO_CLIENT_AUTH
|
||||||
|
|
||||||
\ Get supported curves (bit mask).
|
\ Get supported curves (bit mask).
|
||||||
cc: supported-curves ( -- x ) {
|
cc: supported-curves ( -- x ) {
|
||||||
|
|
@ -220,6 +219,7 @@ cc: supported-curves ( -- x ) {
|
||||||
}
|
}
|
||||||
|
|
||||||
\ Get supported hash functions (bit mask and number).
|
\ Get supported hash functions (bit mask and number).
|
||||||
|
\ Note: this (on purpose) skips MD5.
|
||||||
cc: supported-hash-functions ( -- x num ) {
|
cc: supported-hash-functions ( -- x num ) {
|
||||||
int i;
|
int i;
|
||||||
unsigned x, num;
|
unsigned x, num;
|
||||||
|
|
@ -236,6 +236,16 @@ cc: supported-hash-functions ( -- x num ) {
|
||||||
T0_PUSH(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.
|
\ (Re)initialise the multihasher.
|
||||||
cc: multihash-init ( -- ) {
|
cc: multihash-init ( -- ) {
|
||||||
br_multihash_init(&ENG->mhash);
|
br_multihash_init(&ENG->mhash);
|
||||||
|
|
@ -1020,3 +1030,186 @@ cc: compute-Finished-inner ( from_client prf_id -- ) {
|
||||||
22 wait-rectype-out
|
22 wait-rectype-out
|
||||||
write-Finished
|
write-Finished
|
||||||
flush-record ;
|
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
|
|
@ -140,6 +140,35 @@ do_ecdh(br_ssl_server_context *ctx, int prf_id,
|
||||||
ecdh_common(ctx, prf_id, cpoint, cpoint_len, x);
|
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
|
* 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
|
* 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);
|
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.
|
\ Open extension value.
|
||||||
read16 open-elt
|
read16 open-elt
|
||||||
|
|
||||||
\ Clear list of supported signature algorithms.
|
read-list-sign-algos addr-hashes set16
|
||||||
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
|
|
||||||
|
|
||||||
\ Close extension value.
|
\ Close extension value.
|
||||||
close-elt ;
|
close-elt ;
|
||||||
|
|
@ -440,8 +538,8 @@ cc: call-policy-handler ( -- bool ) {
|
||||||
CTX->policy_vtable, CTX, &choices);
|
CTX->policy_vtable, CTX, &choices);
|
||||||
ENG->session.cipher_suite = choices.cipher_suite;
|
ENG->session.cipher_suite = choices.cipher_suite;
|
||||||
CTX->sign_hash_id = choices.hash_id;
|
CTX->sign_hash_id = choices.hash_id;
|
||||||
CTX->chain = choices.chain;
|
ENG->chain = choices.chain;
|
||||||
CTX->chain_len = choices.chain_len;
|
ENG->chain_len = choices.chain_len;
|
||||||
T0_PUSHi(-(x != 0));
|
T0_PUSHi(-(x != 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -667,11 +765,14 @@ cc: save-session ( -- ) {
|
||||||
ok-compression ifnot 40 fail-alert then
|
ok-compression ifnot 40 fail-alert then
|
||||||
|
|
||||||
\ Filter hash function support by what the server also supports.
|
\ Filter hash function support by what the server also supports.
|
||||||
\ If no common hash function remains, then ECDHE suites are not
|
\ If no common hash function remains with RSA and/or ECDSA, then
|
||||||
\ possible.
|
\ the corresponding ECDHE suites are not possible.
|
||||||
supported-hash-functions drop 257 *
|
supported-hash-functions drop 257 *
|
||||||
addr-hashes get16 and dup addr-hashes set16
|
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
|
\ Filter supported curves. If there is no common curve between
|
||||||
\ client and us, then ECDHE suites cannot be used. Note that we
|
\ client and us, then ECDHE suites cannot be used. Note that we
|
||||||
|
|
@ -684,6 +785,11 @@ cc: save-session ( -- ) {
|
||||||
resume if -1 ret then
|
resume if -1 ret then
|
||||||
|
|
||||||
\ We are not resuming, so a new session ID should be generated.
|
\ 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
|
addr-session_id 32 mkrand
|
||||||
32 addr-session_id_len set8
|
32 addr-session_id_len set8
|
||||||
|
|
||||||
|
|
@ -692,14 +798,14 @@ cc: save-session ( -- ) {
|
||||||
\ server preference order is enforced, and also in case some
|
\ server preference order is enforced, and also in case some
|
||||||
\ suites are filtered out. In particular:
|
\ suites are filtered out. In particular:
|
||||||
\ -- ECDHE suites are removed if there is no common hash function
|
\ -- 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.2-only suites are removed if the negociated version is
|
||||||
\ TLS-1.1 or lower.
|
\ TLS-1.1 or lower.
|
||||||
addr-client_suites dup >css-off
|
addr-client_suites dup >css-off
|
||||||
begin dup css-max < while
|
begin dup css-max < while
|
||||||
dup get16 dup cipher-suite-to-elements
|
dup get16 dup cipher-suite-to-elements
|
||||||
can-ecdhe ifnot
|
|
||||||
dup 12 >> dup 1 = swap 2 = or if
|
dup 12 >> dup 1 = swap 2 = or if
|
||||||
|
dup can-ecdhe and ifnot
|
||||||
2drop 0 dup
|
2drop 0 dup
|
||||||
then
|
then
|
||||||
then
|
then
|
||||||
|
|
@ -791,63 +897,6 @@ cc: save-session ( -- ) {
|
||||||
drop
|
drop
|
||||||
then ;
|
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
|
\ Do the first part of ECDHE. Returned value is the computed signature
|
||||||
\ length, or a negative error code on error.
|
\ length, or a negative error code on error.
|
||||||
cc: do-ecdhe-part1 ( curve -- len ) {
|
cc: do-ecdhe-part1 ( curve -- len ) {
|
||||||
|
|
@ -900,6 +949,166 @@ cc: do-ecdhe-part1 ( curve -- len ) {
|
||||||
sig-len write16
|
sig-len write16
|
||||||
addr-pad sig-len write-blob ;
|
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 the Server Hello Done message.
|
||||||
: write-ServerHelloDone ( -- )
|
: write-ServerHelloDone ( -- )
|
||||||
14 write8 0 write24 ;
|
14 write8 0 write24 ;
|
||||||
|
|
@ -927,11 +1136,18 @@ cc: do-ecdhe-part2 ( len prf_id -- ) {
|
||||||
do_ecdhe_part2(CTX, prf_id, ENG->pad, len);
|
do_ecdhe_part2(CTX, prf_id, ENG->pad, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
\ Read the Client Key Exchange.
|
\ Perform static ECDH. The point from the client is the public key
|
||||||
: read-ClientKeyExchange ( -- )
|
\ extracted from its certificate.
|
||||||
\ Get header, and check message type.
|
cc: do-static-ecdh ( prf_id -- ) {
|
||||||
read-handshake-header 16 = ifnot ERR_UNEXPECTED fail then
|
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.
|
\ What we should get depends on the cipher suite.
|
||||||
addr-cipher_suite get16 use-rsa-keyx? if
|
addr-cipher_suite get16 use-rsa-keyx? if
|
||||||
\ RSA key exchange: we expect a RSA-encrypted value.
|
\ RSA key exchange: we expect a RSA-encrypted value.
|
||||||
|
|
@ -951,6 +1167,116 @@ cc: do-ecdhe-part2 ( len prf_id -- ) {
|
||||||
then
|
then
|
||||||
close-elt ;
|
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 a HelloRequest.
|
||||||
: send-HelloRequest ( -- )
|
: send-HelloRequest ( -- )
|
||||||
flush-record
|
flush-record
|
||||||
|
|
@ -974,11 +1300,54 @@ cc: do-ecdhe-part2 ( len prf_id -- ) {
|
||||||
else
|
else
|
||||||
\ Not a session resumption
|
\ Not a session resumption
|
||||||
write-ServerHello
|
write-ServerHello
|
||||||
write-Certificate
|
write-Certificate drop
|
||||||
write-ServerKeyExchange
|
write-ServerKeyExchange
|
||||||
|
ta-names-total-length if
|
||||||
|
write-CertificateRequest
|
||||||
|
then
|
||||||
write-ServerHelloDone
|
write-ServerHelloDone
|
||||||
flush-record
|
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-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 read-CCS-Finished
|
||||||
0 write-CCS-Finished
|
0 write-CCS-Finished
|
||||||
save-session
|
save-session
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ se_choose(const br_ssl_server_policy_class **pctx,
|
||||||
|
|
||||||
pc = (br_ssl_server_policy_ec_context *)pctx;
|
pc = (br_ssl_server_policy_ec_context *)pctx;
|
||||||
st = br_ssl_server_get_client_suites(cc, &st_num);
|
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) {
|
if (cc->eng.session.version < BR_TLS12) {
|
||||||
hash_id = br_sha1_ID;
|
hash_id = br_sha1_ID;
|
||||||
}
|
}
|
||||||
|
|
@ -27,29 +27,29 @@
|
||||||
/* see bearssl_x509.h */
|
/* see bearssl_x509.h */
|
||||||
void
|
void
|
||||||
br_x509_knownkey_init_rsa(br_x509_knownkey_context *ctx,
|
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->vtable = &br_x509_knownkey_vtable;
|
||||||
ctx->pkey.key_type = BR_KEYTYPE_RSA;
|
ctx->pkey.key_type = BR_KEYTYPE_RSA;
|
||||||
ctx->pkey.key.rsa = *pk;
|
ctx->pkey.key.rsa = *pk;
|
||||||
|
ctx->usages = usages;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* see bearssl_x509.h */
|
/* see bearssl_x509.h */
|
||||||
void
|
void
|
||||||
br_x509_knownkey_init_ec(br_x509_knownkey_context *ctx,
|
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->vtable = &br_x509_knownkey_vtable;
|
||||||
ctx->pkey.key_type = BR_KEYTYPE_EC;
|
ctx->pkey.key_type = BR_KEYTYPE_EC;
|
||||||
ctx->pkey.key.ec = *pk;
|
ctx->pkey.key.ec = *pk;
|
||||||
|
ctx->usages = usages;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
kk_start_chain(const br_x509_class **ctx,
|
kk_start_chain(const br_x509_class **ctx, const char *server_name)
|
||||||
unsigned expected_key_type, const char *server_name)
|
|
||||||
{
|
{
|
||||||
(void)ctx;
|
(void)ctx;
|
||||||
(void)expected_key_type;
|
|
||||||
(void)server_name;
|
(void)server_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -82,9 +82,15 @@ kk_end_chain(const br_x509_class **ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
static const br_x509_pkey *
|
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 */
|
/* see bearssl_x509.h */
|
||||||
|
|
|
||||||
|
|
@ -239,8 +239,7 @@ br_x509_minimal_init(br_x509_minimal_context *ctx,
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
xm_start_chain(const br_x509_class **ctx,
|
xm_start_chain(const br_x509_class **ctx, const char *server_name)
|
||||||
unsigned expected_key_type, const char *server_name)
|
|
||||||
{
|
{
|
||||||
br_x509_minimal_context *cc;
|
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.dp = cc->dp_stack;
|
||||||
cc->cpu.rp = cc->rp_stack;
|
cc->cpu.rp = cc->rp_stack;
|
||||||
br_x509_minimal_init_main(&cc->cpu);
|
br_x509_minimal_init_main(&cc->cpu);
|
||||||
cc->expected_key_type = expected_key_type;
|
|
||||||
if (server_name == NULL || *server_name == 0) {
|
if (server_name == NULL || *server_name == 0) {
|
||||||
cc->server_name = NULL;
|
cc->server_name = NULL;
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -320,7 +318,7 @@ xm_end_chain(const br_x509_class **ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
static const br_x509_pkey *
|
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;
|
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
|
if (cc->err == BR_ERR_X509_OK
|
||||||
|| cc->err == BR_ERR_X509_NOT_TRUSTED)
|
|| cc->err == BR_ERR_X509_NOT_TRUSTED)
|
||||||
{
|
{
|
||||||
|
if (usages != NULL) {
|
||||||
|
*usages = cc->key_usages;
|
||||||
|
}
|
||||||
return &((br_x509_minimal_context *)ctx)->pkey;
|
return &((br_x509_minimal_context *)ctx)->pkey;
|
||||||
} else {
|
} else {
|
||||||
return NULL;
|
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_UNEXPECTED), 0x00, 0x00, 0x01,
|
||||||
T0_INT1(BR_ERR_X509_UNSUPPORTED), 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_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),
|
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, 0x00, 0x01, T0_INT2(offsetof(CONTEXT_NAME, cert_length)), 0x00,
|
||||||
0x00, 0x01, T0_INT2(offsetof(CONTEXT_NAME, cert_sig)), 0x00, 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,
|
0x01, T0_INT2(offsetof(CONTEXT_NAME, cert_sig_len)), 0x00, 0x00, 0x01,
|
||||||
T0_INT2(offsetof(CONTEXT_NAME, cert_signer_key_type)), 0x00, 0x00,
|
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, current_dn_hash)), 0x00, 0x00,
|
||||||
0x01, T0_INT2(offsetof(CONTEXT_NAME, expected_key_type)), 0x00, 0x00,
|
0x01, T0_INT2(offsetof(CONTEXT_NAME, key_usages)), 0x00, 0x00, 0x01,
|
||||||
0x01, T0_INT2(offsetof(br_x509_minimal_context, pkey_data)), 0x01,
|
T0_INT2(offsetof(br_x509_minimal_context, pkey_data)), 0x01,
|
||||||
T0_INT2(BR_X509_BUFSIZE_KEY), 0x00, 0x00, 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, min_rsa_size)), 0x00, 0x00, 0x01,
|
||||||
T0_INT2(offsetof(CONTEXT_NAME, next_dn_hash)), 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, num_certs)), 0x00, 0x00, 0x01,
|
||||||
T0_INT2(offsetof(CONTEXT_NAME, pad)), 0x00, 0x00, 0x01,
|
T0_INT2(offsetof(CONTEXT_NAME, pad)), 0x00, 0x00, 0x01,
|
||||||
T0_INT2(offsetof(CONTEXT_NAME, saved_dn_hash)), 0x00, 0x00, 0x81, 0x31,
|
T0_INT2(offsetof(CONTEXT_NAME, saved_dn_hash)), 0x00, 0x00, 0x81, 0x2F,
|
||||||
0x6E, 0x00, 0x00, 0x01, 0x80, 0x73, 0x00, 0x00, 0x01, 0x80, 0x7C, 0x00,
|
0x6C, 0x00, 0x00, 0x01, 0x80, 0x73, 0x00, 0x00, 0x01, 0x80, 0x7C, 0x00,
|
||||||
0x00, 0x01, 0x81, 0x02, 0x00, 0x00, 0x01, 0x82, 0x08, 0x00, 0x00, 0x01,
|
0x00, 0x01, 0x81, 0x02, 0x00, 0x00, 0x01, 0x82, 0x08, 0x00, 0x00, 0x01,
|
||||||
0x81, 0x70, 0x00, 0x00, 0x01, 0x81, 0x64, 0x00, 0x04, 0x03, 0x00, 0x03,
|
0x81, 0x70, 0x00, 0x00, 0x01, 0x81, 0x64, 0x00, 0x04, 0x03, 0x00, 0x03,
|
||||||
0x01, 0x03, 0x02, 0x03, 0x03, 0x02, 0x03, 0x02, 0x01, 0x11, 0x06, 0x07,
|
0x01, 0x03, 0x02, 0x03, 0x03, 0x02, 0x03, 0x02, 0x01, 0x11, 0x06, 0x07,
|
||||||
0x02, 0x02, 0x02, 0x00, 0x0D, 0x04, 0x05, 0x02, 0x03, 0x02, 0x01, 0x0D,
|
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, 0x02, 0x03, 0x00, 0x03, 0x01, 0x23, 0x02, 0x01, 0x13, 0x38, 0x02,
|
||||||
0x00, 0x0F, 0x15, 0x00, 0x00, 0x05, 0x02, 0x4F, 0x26, 0x00, 0x00, 0x06,
|
0x00, 0x0F, 0x15, 0x00, 0x00, 0x05, 0x02, 0x4E, 0x26, 0x00, 0x00, 0x06,
|
||||||
0x02, 0x50, 0x26, 0x00, 0x00, 0x01, 0x10, 0x73, 0x00, 0x00, 0x11, 0x05,
|
0x02, 0x4F, 0x26, 0x00, 0x00, 0x01, 0x10, 0x71, 0x00, 0x00, 0x11, 0x05,
|
||||||
0x02, 0x53, 0x26, 0x70, 0x00, 0x00, 0x11, 0x05, 0x02, 0x53, 0x26, 0x71,
|
0x02, 0x52, 0x26, 0x6E, 0x00, 0x00, 0x11, 0x05, 0x02, 0x52, 0x26, 0x6F,
|
||||||
0x00, 0x00, 0x06, 0x02, 0x49, 0x26, 0x00, 0x00, 0x01, 0x82, 0x00, 0x00,
|
0x00, 0x00, 0x06, 0x02, 0x48, 0x26, 0x00, 0x00, 0x01, 0x82, 0x00, 0x00,
|
||||||
0x00, 0x23, 0x1E, 0x01, 0x08, 0x0E, 0x39, 0x3D, 0x1E, 0x09, 0x00, 0x09,
|
0x00, 0x23, 0x1E, 0x01, 0x08, 0x0E, 0x38, 0x3C, 0x1E, 0x09, 0x00, 0x09,
|
||||||
0x03, 0x00, 0x59, 0x29, 0x81, 0x1D, 0x37, 0x81, 0x1D, 0x81, 0x20, 0x23,
|
0x03, 0x00, 0x57, 0x29, 0x81, 0x1B, 0x36, 0x81, 0x1B, 0x81, 0x1E, 0x23,
|
||||||
0x01, 0x20, 0x11, 0x06, 0x15, 0x22, 0x70, 0x81, 0x1B, 0x81, 0x20, 0x01,
|
0x01, 0x20, 0x11, 0x06, 0x15, 0x22, 0x6E, 0x81, 0x19, 0x81, 0x1E, 0x01,
|
||||||
0x02, 0x74, 0x81, 0x1E, 0x01, 0x02, 0x12, 0x06, 0x02, 0x54, 0x26, 0x75,
|
0x02, 0x72, 0x81, 0x1C, 0x01, 0x02, 0x12, 0x06, 0x02, 0x53, 0x26, 0x73,
|
||||||
0x81, 0x20, 0x01, 0x02, 0x74, 0x81, 0x1C, 0x81, 0x1D, 0x81, 0x2A, 0x81,
|
0x81, 0x1E, 0x01, 0x02, 0x72, 0x81, 0x1A, 0x81, 0x1B, 0x81, 0x28, 0x81,
|
||||||
0x10, 0x63, 0x5F, 0x1F, 0x16, 0x81, 0x1D, 0x81, 0x15, 0x27, 0x67, 0x06,
|
0x0E, 0x61, 0x5D, 0x1F, 0x16, 0x81, 0x1B, 0x81, 0x13, 0x27, 0x65, 0x06,
|
||||||
0x02, 0x48, 0x26, 0x81, 0x15, 0x27, 0x6E, 0x06, 0x02, 0x48, 0x26, 0x75,
|
0x02, 0x47, 0x26, 0x81, 0x13, 0x27, 0x6C, 0x06, 0x02, 0x47, 0x26, 0x73,
|
||||||
0x81, 0x10, 0x02, 0x00, 0x06, 0x05, 0x2B, 0x03, 0x01, 0x04, 0x08, 0x5F,
|
0x81, 0x0E, 0x02, 0x00, 0x06, 0x05, 0x2A, 0x03, 0x01, 0x04, 0x08, 0x5D,
|
||||||
0x66, 0x1F, 0x25, 0x05, 0x02, 0x47, 0x26, 0x66, 0x63, 0x1F, 0x16, 0x81,
|
0x64, 0x1F, 0x25, 0x05, 0x02, 0x46, 0x26, 0x64, 0x61, 0x1F, 0x16, 0x81,
|
||||||
0x1D, 0x81, 0x1D, 0x81, 0x11, 0x05, 0x02, 0x54, 0x26, 0x81, 0x24, 0x24,
|
0x1B, 0x81, 0x1B, 0x81, 0x0F, 0x05, 0x02, 0x53, 0x26, 0x81, 0x22, 0x24,
|
||||||
0x06, 0x2C, 0x81, 0x2A, 0x81, 0x12, 0x81, 0x1D, 0x61, 0x81, 0x18, 0x03,
|
0x06, 0x2C, 0x81, 0x28, 0x81, 0x10, 0x81, 0x1B, 0x5F, 0x81, 0x16, 0x03,
|
||||||
0x03, 0x61, 0x39, 0x02, 0x03, 0x09, 0x39, 0x02, 0x03, 0x0A, 0x81, 0x18,
|
0x03, 0x5F, 0x38, 0x02, 0x03, 0x09, 0x38, 0x02, 0x03, 0x0A, 0x81, 0x16,
|
||||||
0x03, 0x04, 0x75, 0x62, 0x28, 0x01, 0x81, 0x00, 0x09, 0x02, 0x03, 0x12,
|
0x03, 0x04, 0x73, 0x60, 0x28, 0x01, 0x81, 0x00, 0x09, 0x02, 0x03, 0x12,
|
||||||
0x06, 0x02, 0x55, 0x26, 0x75, 0x58, 0x03, 0x02, 0x04, 0x3E, 0x81, 0x01,
|
0x06, 0x02, 0x54, 0x26, 0x73, 0x56, 0x03, 0x02, 0x04, 0x3D, 0x7F, 0x24,
|
||||||
0x24, 0x06, 0x37, 0x81, 0x11, 0x05, 0x02, 0x54, 0x26, 0x68, 0x24, 0x06,
|
0x06, 0x37, 0x81, 0x0F, 0x05, 0x02, 0x53, 0x26, 0x66, 0x24, 0x06, 0x04,
|
||||||
0x04, 0x01, 0x17, 0x04, 0x12, 0x69, 0x24, 0x06, 0x04, 0x01, 0x18, 0x04,
|
0x01, 0x17, 0x04, 0x12, 0x67, 0x24, 0x06, 0x04, 0x01, 0x18, 0x04, 0x0A,
|
||||||
0x0A, 0x6A, 0x24, 0x06, 0x04, 0x01, 0x19, 0x04, 0x02, 0x54, 0x26, 0x03,
|
0x68, 0x24, 0x06, 0x04, 0x01, 0x19, 0x04, 0x02, 0x53, 0x26, 0x03, 0x05,
|
||||||
0x05, 0x75, 0x81, 0x12, 0x23, 0x03, 0x06, 0x23, 0x61, 0x32, 0x0D, 0x06,
|
0x73, 0x81, 0x10, 0x23, 0x03, 0x06, 0x23, 0x5F, 0x31, 0x0D, 0x06, 0x02,
|
||||||
0x02, 0x4D, 0x26, 0x81, 0x13, 0x57, 0x03, 0x02, 0x04, 0x02, 0x54, 0x26,
|
0x4C, 0x26, 0x81, 0x11, 0x55, 0x03, 0x02, 0x04, 0x02, 0x53, 0x26, 0x73,
|
||||||
0x75, 0x02, 0x00, 0x06, 0x33, 0x60, 0x2A, 0x01, 0x0F, 0x15, 0x23, 0x06,
|
0x02, 0x00, 0x06, 0x21, 0x02, 0x02, 0x56, 0x2D, 0x11, 0x06, 0x08, 0x22,
|
||||||
0x09, 0x02, 0x02, 0x11, 0x05, 0x02, 0x56, 0x26, 0x04, 0x01, 0x22, 0x02,
|
0x02, 0x03, 0x02, 0x04, 0x1D, 0x04, 0x10, 0x55, 0x2D, 0x11, 0x06, 0x08,
|
||||||
0x02, 0x58, 0x2E, 0x11, 0x06, 0x08, 0x22, 0x02, 0x03, 0x02, 0x04, 0x1D,
|
0x22, 0x02, 0x05, 0x02, 0x06, 0x1C, 0x04, 0x03, 0x53, 0x26, 0x22, 0x04,
|
||||||
0x04, 0x10, 0x57, 0x2E, 0x11, 0x06, 0x08, 0x22, 0x02, 0x05, 0x02, 0x06,
|
0x24, 0x02, 0x02, 0x56, 0x2D, 0x11, 0x06, 0x08, 0x22, 0x02, 0x03, 0x02,
|
||||||
0x1C, 0x04, 0x03, 0x54, 0x26, 0x22, 0x04, 0x24, 0x02, 0x02, 0x58, 0x2E,
|
0x04, 0x21, 0x04, 0x10, 0x55, 0x2D, 0x11, 0x06, 0x08, 0x22, 0x02, 0x05,
|
||||||
0x11, 0x06, 0x08, 0x22, 0x02, 0x03, 0x02, 0x04, 0x21, 0x04, 0x10, 0x57,
|
0x02, 0x06, 0x20, 0x04, 0x03, 0x53, 0x26, 0x22, 0x23, 0x06, 0x01, 0x26,
|
||||||
0x2E, 0x11, 0x06, 0x08, 0x22, 0x02, 0x05, 0x02, 0x06, 0x20, 0x04, 0x03,
|
0x22, 0x01, 0x00, 0x03, 0x07, 0x81, 0x1F, 0x01, 0x21, 0x81, 0x05, 0x01,
|
||||||
0x54, 0x26, 0x22, 0x23, 0x06, 0x01, 0x26, 0x22, 0x01, 0x00, 0x03, 0x07,
|
0x22, 0x81, 0x05, 0x23, 0x01, 0x23, 0x11, 0x06, 0x81, 0x35, 0x22, 0x6E,
|
||||||
0x81, 0x21, 0x01, 0x21, 0x81, 0x07, 0x01, 0x22, 0x81, 0x07, 0x23, 0x01,
|
0x81, 0x19, 0x81, 0x1B, 0x23, 0x06, 0x81, 0x27, 0x01, 0x00, 0x03, 0x08,
|
||||||
0x23, 0x11, 0x06, 0x81, 0x36, 0x22, 0x70, 0x81, 0x1B, 0x81, 0x1D, 0x23,
|
0x81, 0x1B, 0x81, 0x0F, 0x22, 0x81, 0x1E, 0x23, 0x01, 0x01, 0x11, 0x06,
|
||||||
0x06, 0x81, 0x28, 0x01, 0x00, 0x03, 0x08, 0x81, 0x1D, 0x81, 0x11, 0x22,
|
0x06, 0x81, 0x12, 0x03, 0x08, 0x81, 0x1E, 0x01, 0x04, 0x72, 0x81, 0x19,
|
||||||
0x81, 0x20, 0x23, 0x01, 0x01, 0x11, 0x06, 0x06, 0x81, 0x14, 0x03, 0x08,
|
0x6B, 0x24, 0x06, 0x11, 0x02, 0x00, 0x06, 0x04, 0x81, 0x29, 0x04, 0x06,
|
||||||
0x81, 0x20, 0x01, 0x04, 0x74, 0x81, 0x1B, 0x6D, 0x24, 0x06, 0x11, 0x02,
|
0x81, 0x0C, 0x01, 0x7F, 0x03, 0x07, 0x04, 0x80, 0x71, 0x81, 0x07, 0x24,
|
||||||
0x00, 0x06, 0x04, 0x81, 0x2B, 0x04, 0x06, 0x81, 0x0E, 0x01, 0x7F, 0x03,
|
0x06, 0x07, 0x02, 0x00, 0x81, 0x0D, 0x04, 0x80, 0x65, 0x81, 0x2B, 0x24,
|
||||||
0x07, 0x04, 0x80, 0x72, 0x81, 0x09, 0x24, 0x06, 0x07, 0x02, 0x00, 0x81,
|
0x06, 0x13, 0x02, 0x00, 0x06, 0x0A, 0x01, 0x00, 0x03, 0x01, 0x81, 0x0B,
|
||||||
0x0F, 0x04, 0x80, 0x66, 0x81, 0x2D, 0x24, 0x06, 0x13, 0x02, 0x00, 0x06,
|
0x03, 0x01, 0x04, 0x02, 0x81, 0x29, 0x04, 0x80, 0x4D, 0x6A, 0x24, 0x06,
|
||||||
0x0A, 0x01, 0x00, 0x03, 0x01, 0x81, 0x0D, 0x03, 0x01, 0x04, 0x02, 0x81,
|
0x05, 0x81, 0x29, 0x04, 0x80, 0x44, 0x81, 0x2E, 0x24, 0x06, 0x04, 0x81,
|
||||||
0x2B, 0x04, 0x80, 0x4E, 0x6C, 0x24, 0x06, 0x05, 0x81, 0x2B, 0x04, 0x80,
|
0x29, 0x04, 0x3B, 0x81, 0x06, 0x24, 0x06, 0x04, 0x81, 0x29, 0x04, 0x32,
|
||||||
0x45, 0x81, 0x30, 0x24, 0x06, 0x04, 0x81, 0x2B, 0x04, 0x3C, 0x81, 0x08,
|
0x81, 0x2C, 0x24, 0x06, 0x04, 0x81, 0x29, 0x04, 0x29, 0x74, 0x24, 0x06,
|
||||||
0x24, 0x06, 0x04, 0x81, 0x2B, 0x04, 0x33, 0x81, 0x2E, 0x24, 0x06, 0x04,
|
0x04, 0x81, 0x29, 0x04, 0x21, 0x7E, 0x24, 0x06, 0x04, 0x81, 0x29, 0x04,
|
||||||
0x81, 0x2B, 0x04, 0x2A, 0x76, 0x24, 0x06, 0x04, 0x81, 0x2B, 0x04, 0x22,
|
0x19, 0x69, 0x24, 0x06, 0x04, 0x81, 0x29, 0x04, 0x11, 0x81, 0x2D, 0x24,
|
||||||
0x81, 0x00, 0x24, 0x06, 0x04, 0x81, 0x2B, 0x04, 0x19, 0x6B, 0x24, 0x06,
|
0x06, 0x04, 0x81, 0x29, 0x04, 0x08, 0x02, 0x08, 0x06, 0x02, 0x45, 0x26,
|
||||||
0x04, 0x81, 0x2B, 0x04, 0x11, 0x81, 0x2F, 0x24, 0x06, 0x04, 0x81, 0x2B,
|
0x81, 0x29, 0x73, 0x73, 0x04, 0xFE, 0x55, 0x73, 0x73, 0x04, 0x08, 0x01,
|
||||||
0x04, 0x08, 0x02, 0x08, 0x06, 0x02, 0x46, 0x26, 0x81, 0x2B, 0x75, 0x75,
|
0x7F, 0x11, 0x05, 0x02, 0x52, 0x26, 0x22, 0x73, 0x37, 0x02, 0x00, 0x06,
|
||||||
0x04, 0xFE, 0x54, 0x75, 0x75, 0x04, 0x08, 0x01, 0x7F, 0x11, 0x05, 0x02,
|
0x08, 0x02, 0x01, 0x39, 0x2C, 0x05, 0x02, 0x41, 0x26, 0x02, 0x00, 0x06,
|
||||||
0x53, 0x26, 0x22, 0x75, 0x38, 0x02, 0x00, 0x06, 0x08, 0x02, 0x01, 0x3A,
|
0x01, 0x17, 0x02, 0x00, 0x02, 0x07, 0x2C, 0x05, 0x02, 0x4D, 0x26, 0x81,
|
||||||
0x2D, 0x05, 0x02, 0x42, 0x26, 0x02, 0x00, 0x06, 0x01, 0x17, 0x02, 0x00,
|
0x1E, 0x70, 0x81, 0x19, 0x81, 0x0F, 0x06, 0x81, 0x07, 0x81, 0x23, 0x24,
|
||||||
0x02, 0x07, 0x2D, 0x05, 0x02, 0x4E, 0x26, 0x81, 0x20, 0x72, 0x81, 0x1B,
|
0x06, 0x08, 0x01, 0x02, 0x56, 0x81, 0x00, 0x04, 0x80, 0x6C, 0x81, 0x24,
|
||||||
0x81, 0x11, 0x06, 0x81, 0x07, 0x81, 0x25, 0x24, 0x06, 0x08, 0x01, 0x02,
|
0x24, 0x06, 0x08, 0x01, 0x03, 0x56, 0x81, 0x01, 0x04, 0x80, 0x5F, 0x81,
|
||||||
0x58, 0x81, 0x02, 0x04, 0x80, 0x6C, 0x81, 0x26, 0x24, 0x06, 0x08, 0x01,
|
0x25, 0x24, 0x06, 0x08, 0x01, 0x04, 0x56, 0x81, 0x02, 0x04, 0x80, 0x52,
|
||||||
0x03, 0x58, 0x81, 0x03, 0x04, 0x80, 0x5F, 0x81, 0x27, 0x24, 0x06, 0x08,
|
0x81, 0x26, 0x24, 0x06, 0x08, 0x01, 0x05, 0x56, 0x81, 0x03, 0x04, 0x80,
|
||||||
0x01, 0x04, 0x58, 0x81, 0x04, 0x04, 0x80, 0x52, 0x81, 0x28, 0x24, 0x06,
|
0x45, 0x81, 0x27, 0x24, 0x06, 0x07, 0x01, 0x06, 0x56, 0x81, 0x04, 0x04,
|
||||||
0x08, 0x01, 0x05, 0x58, 0x81, 0x05, 0x04, 0x80, 0x45, 0x81, 0x29, 0x24,
|
0x39, 0x79, 0x24, 0x06, 0x07, 0x01, 0x02, 0x55, 0x81, 0x00, 0x04, 0x2E,
|
||||||
0x06, 0x07, 0x01, 0x06, 0x58, 0x81, 0x06, 0x04, 0x39, 0x7B, 0x24, 0x06,
|
0x7A, 0x24, 0x06, 0x07, 0x01, 0x03, 0x55, 0x81, 0x01, 0x04, 0x23, 0x7B,
|
||||||
0x07, 0x01, 0x02, 0x57, 0x81, 0x02, 0x04, 0x2E, 0x7C, 0x24, 0x06, 0x07,
|
0x24, 0x06, 0x07, 0x01, 0x04, 0x55, 0x81, 0x02, 0x04, 0x18, 0x7C, 0x24,
|
||||||
0x01, 0x03, 0x57, 0x81, 0x03, 0x04, 0x23, 0x7D, 0x24, 0x06, 0x07, 0x01,
|
0x06, 0x07, 0x01, 0x05, 0x55, 0x81, 0x03, 0x04, 0x0D, 0x7D, 0x24, 0x06,
|
||||||
0x04, 0x57, 0x81, 0x04, 0x04, 0x18, 0x7E, 0x24, 0x06, 0x07, 0x01, 0x05,
|
0x07, 0x01, 0x06, 0x55, 0x81, 0x04, 0x04, 0x02, 0x53, 0x26, 0x5A, 0x32,
|
||||||
0x57, 0x81, 0x05, 0x04, 0x0D, 0x7F, 0x24, 0x06, 0x07, 0x01, 0x06, 0x57,
|
0x5C, 0x34, 0x1B, 0x23, 0x05, 0x02, 0x53, 0x26, 0x59, 0x34, 0x04, 0x02,
|
||||||
0x81, 0x06, 0x04, 0x02, 0x54, 0x26, 0x5C, 0x33, 0x5E, 0x35, 0x1B, 0x23,
|
0x53, 0x26, 0x81, 0x28, 0x81, 0x10, 0x23, 0x01,
|
||||||
0x05, 0x02, 0x54, 0x26, 0x5B, 0x35, 0x04, 0x02, 0x54, 0x26, 0x81, 0x2A,
|
T0_INT2(BR_X509_BUFSIZE_SIG), 0x12, 0x06, 0x02, 0x4C, 0x26, 0x23, 0x5B,
|
||||||
0x81, 0x12, 0x23, 0x01, T0_INT2(BR_X509_BUFSIZE_SIG), 0x12, 0x06, 0x02,
|
0x32, 0x58, 0x81, 0x11, 0x73, 0x73, 0x01, 0x00, 0x57, 0x33, 0x18, 0x00,
|
||||||
0x4D, 0x26, 0x23, 0x5D, 0x33, 0x5A, 0x81, 0x13, 0x75, 0x75, 0x01, 0x00,
|
0x00, 0x01, 0x30, 0x0A, 0x23, 0x01, 0x00, 0x01, 0x09, 0x6D, 0x05, 0x02,
|
||||||
0x59, 0x34, 0x18, 0x00, 0x00, 0x01, 0x30, 0x0A, 0x23, 0x01, 0x00, 0x01,
|
0x44, 0x26, 0x00, 0x00, 0x2D, 0x2D, 0x00, 0x00, 0x01, 0x81, 0x08, 0x00,
|
||||||
0x09, 0x6F, 0x05, 0x02, 0x45, 0x26, 0x00, 0x00, 0x2E, 0x2E, 0x00, 0x00,
|
0x00, 0x01, 0x81, 0x10, 0x00, 0x00, 0x01, 0x81, 0x19, 0x00, 0x00, 0x01,
|
||||||
0x01, 0x81, 0x08, 0x00, 0x00, 0x01, 0x81, 0x10, 0x00, 0x00, 0x01, 0x81,
|
0x81, 0x22, 0x00, 0x00, 0x01, 0x81, 0x2B, 0x00, 0x00, 0x01, 0x82, 0x04,
|
||||||
0x19, 0x00, 0x00, 0x01, 0x81, 0x22, 0x00, 0x00, 0x01, 0x81, 0x2B, 0x00,
|
0x00, 0x00, 0x01, 0x80, 0x6B, 0x00, 0x00, 0x01, 0x3D, 0x00, 0x00, 0x01,
|
||||||
0x00, 0x01, 0x82, 0x04, 0x00, 0x00, 0x01, 0x80, 0x6B, 0x00, 0x00, 0x01,
|
0x80, 0x43, 0x00, 0x00, 0x01, 0x80, 0x4D, 0x00, 0x00, 0x01, 0x80, 0x57,
|
||||||
0x3D, 0x00, 0x00, 0x01, 0x80, 0x43, 0x00, 0x00, 0x01, 0x80, 0x4D, 0x00,
|
0x00, 0x00, 0x01, 0x80, 0x61, 0x00, 0x00, 0x2D, 0x11, 0x06, 0x07, 0x3E,
|
||||||
0x00, 0x01, 0x80, 0x57, 0x00, 0x00, 0x01, 0x80, 0x61, 0x00, 0x00, 0x2E,
|
0x81, 0x19, 0x81, 0x28, 0x81, 0x1F, 0x00, 0x00, 0x01, 0x81, 0x78, 0x00,
|
||||||
0x11, 0x06, 0x07, 0x3F, 0x81, 0x1B, 0x81, 0x2A, 0x81, 0x21, 0x00, 0x00,
|
0x00, 0x01, 0x81, 0x68, 0x00, 0x00, 0x01, 0x30, 0x5E, 0x34, 0x01, 0x7F,
|
||||||
0x01, 0x81, 0x78, 0x00, 0x00, 0x01, 0x81, 0x68, 0x00, 0x00, 0x01, 0x7F,
|
0x76, 0x19, 0x01, 0x00, 0x76, 0x19, 0x04, 0x7A, 0x00, 0x01, 0x81, 0x34,
|
||||||
0x78, 0x19, 0x01, 0x00, 0x78, 0x19, 0x04, 0x7A, 0x00, 0x01, 0x81, 0x34,
|
0x00, 0x01, 0x78, 0x0D, 0x06, 0x02, 0x4B, 0x26, 0x23, 0x03, 0x00, 0x0A,
|
||||||
0x00, 0x01, 0x7A, 0x0D, 0x06, 0x02, 0x4C, 0x26, 0x23, 0x03, 0x00, 0x0A,
|
0x02, 0x00, 0x00, 0x01, 0x01, 0x00, 0x03, 0x00, 0x81, 0x1B, 0x23, 0x06,
|
||||||
0x02, 0x00, 0x00, 0x01, 0x01, 0x00, 0x03, 0x00, 0x81, 0x1D, 0x23, 0x06,
|
0x18, 0x81, 0x1E, 0x01, 0x22, 0x11, 0x06, 0x0C, 0x6F, 0x81, 0x1D, 0x22,
|
||||||
0x18, 0x81, 0x20, 0x01, 0x22, 0x11, 0x06, 0x0C, 0x71, 0x81, 0x1F, 0x22,
|
0x2A, 0x02, 0x00, 0x2C, 0x03, 0x00, 0x04, 0x03, 0x22, 0x81, 0x1A, 0x04,
|
||||||
0x2B, 0x02, 0x00, 0x2D, 0x03, 0x00, 0x04, 0x03, 0x22, 0x81, 0x1C, 0x04,
|
0x65, 0x73, 0x02, 0x00, 0x00, 0x00, 0x81, 0x1B, 0x81, 0x1F, 0x23, 0x01,
|
||||||
0x65, 0x75, 0x02, 0x00, 0x00, 0x00, 0x81, 0x1D, 0x81, 0x21, 0x23, 0x01,
|
0x01, 0x11, 0x06, 0x0A, 0x81, 0x12, 0x05, 0x02, 0x4D, 0x26, 0x81, 0x1F,
|
||||||
0x01, 0x11, 0x06, 0x0A, 0x81, 0x14, 0x05, 0x02, 0x4E, 0x26, 0x81, 0x21,
|
0x04, 0x02, 0x4D, 0x26, 0x23, 0x01, 0x02, 0x11, 0x06, 0x0E, 0x22, 0x6F,
|
||||||
0x04, 0x02, 0x4E, 0x26, 0x23, 0x01, 0x02, 0x11, 0x06, 0x0E, 0x22, 0x71,
|
0x81, 0x1C, 0x62, 0x29, 0x3D, 0x0D, 0x06, 0x02, 0x4D, 0x26, 0x81, 0x1F,
|
||||||
0x81, 0x1E, 0x64, 0x29, 0x3E, 0x0D, 0x06, 0x02, 0x4E, 0x26, 0x81, 0x21,
|
0x01, 0x7F, 0x10, 0x06, 0x02, 0x52, 0x26, 0x22, 0x73, 0x00, 0x02, 0x03,
|
||||||
0x01, 0x7F, 0x10, 0x06, 0x02, 0x53, 0x26, 0x22, 0x75, 0x00, 0x02, 0x06,
|
0x00, 0x81, 0x1E, 0x01, 0x03, 0x72, 0x81, 0x19, 0x81, 0x20, 0x03, 0x01,
|
||||||
0x10, 0x60, 0x2A, 0x01, 0x10, 0x15, 0x06, 0x04, 0x01, 0x30, 0x04, 0x03,
|
0x02, 0x01, 0x01, 0x07, 0x12, 0x06, 0x02, 0x52, 0x26, 0x23, 0x01, 0x00,
|
||||||
0x01, 0x81, 0x40, 0x04, 0x02, 0x01, 0x04, 0x03, 0x00, 0x81, 0x20, 0x01,
|
0x2D, 0x11, 0x06, 0x05, 0x22, 0x49, 0x26, 0x04, 0x17, 0x01, 0x01, 0x2D,
|
||||||
0x03, 0x74, 0x81, 0x1B, 0x81, 0x22, 0x03, 0x01, 0x02, 0x01, 0x01, 0x07,
|
0x11, 0x06, 0x0B, 0x22, 0x81, 0x20, 0x02, 0x01, 0x14, 0x02, 0x01, 0x0E,
|
||||||
0x12, 0x06, 0x02, 0x53, 0x26, 0x23, 0x01, 0x00, 0x2E, 0x11, 0x06, 0x05,
|
0x04, 0x06, 0x22, 0x81, 0x20, 0x01, 0x00, 0x22, 0x02, 0x00, 0x06, 0x19,
|
||||||
0x22, 0x4A, 0x26, 0x04, 0x17, 0x01, 0x01, 0x2E, 0x11, 0x06, 0x0B, 0x22,
|
0x01, 0x00, 0x2D, 0x01, 0x38, 0x15, 0x06, 0x03, 0x01, 0x10, 0x2C, 0x38,
|
||||||
0x81, 0x22, 0x02, 0x01, 0x14, 0x02, 0x01, 0x0E, 0x04, 0x06, 0x22, 0x81,
|
0x01, 0x81, 0x40, 0x15, 0x06, 0x03, 0x01, 0x20, 0x2C, 0x5E, 0x34, 0x04,
|
||||||
0x22, 0x01, 0x00, 0x22, 0x02, 0x00, 0x15, 0x05, 0x02, 0x4A, 0x26, 0x81,
|
0x07, 0x01, 0x04, 0x15, 0x05, 0x02, 0x49, 0x26, 0x81, 0x28, 0x00, 0x02,
|
||||||
0x2A, 0x00, 0x02, 0x36, 0x01, 0x00, 0x65, 0x35, 0x81, 0x1D, 0x23, 0x06,
|
0x35, 0x01, 0x00, 0x63, 0x34, 0x81, 0x1B, 0x23, 0x06, 0x80, 0x6F, 0x81,
|
||||||
0x80, 0x6F, 0x81, 0x20, 0x01, 0x11, 0x73, 0x81, 0x1B, 0x23, 0x05, 0x02,
|
0x1E, 0x01, 0x11, 0x71, 0x81, 0x19, 0x23, 0x05, 0x02, 0x40, 0x26, 0x23,
|
||||||
0x41, 0x26, 0x23, 0x06, 0x80, 0x5B, 0x81, 0x1D, 0x81, 0x20, 0x01, 0x06,
|
0x06, 0x80, 0x5B, 0x81, 0x1B, 0x81, 0x1E, 0x01, 0x06, 0x72, 0x81, 0x19,
|
||||||
0x74, 0x81, 0x1B, 0x23, 0x01, 0x03, 0x11, 0x06, 0x1E, 0x81, 0x22, 0x01,
|
0x23, 0x01, 0x03, 0x11, 0x06, 0x1E, 0x81, 0x20, 0x01, 0x10, 0x0E, 0x03,
|
||||||
0x10, 0x0E, 0x03, 0x00, 0x81, 0x22, 0x01, 0x08, 0x0E, 0x02, 0x00, 0x09,
|
0x00, 0x81, 0x20, 0x01, 0x08, 0x0E, 0x02, 0x00, 0x09, 0x03, 0x00, 0x81,
|
||||||
0x03, 0x00, 0x81, 0x22, 0x02, 0x00, 0x09, 0x01, 0x82, 0xD4, 0x88, 0x03,
|
0x20, 0x02, 0x00, 0x09, 0x01, 0x82, 0xD4, 0x88, 0x03, 0x11, 0x03, 0x01,
|
||||||
0x11, 0x03, 0x01, 0x81, 0x2A, 0x02, 0x01, 0x06, 0x23, 0x81, 0x20, 0x23,
|
0x81, 0x28, 0x02, 0x01, 0x06, 0x23, 0x81, 0x1E, 0x23, 0x23, 0x01, 0x0C,
|
||||||
0x23, 0x01, 0x0C, 0x11, 0x39, 0x01, 0x13, 0x11, 0x2D, 0x39, 0x01, 0x14,
|
0x11, 0x38, 0x01, 0x13, 0x11, 0x2C, 0x38, 0x01, 0x14, 0x11, 0x2C, 0x06,
|
||||||
0x11, 0x2D, 0x06, 0x07, 0x71, 0x81, 0x1F, 0x22, 0x75, 0x04, 0x07, 0x22,
|
0x07, 0x6F, 0x81, 0x1D, 0x22, 0x73, 0x04, 0x07, 0x22, 0x01, 0x00, 0x63,
|
||||||
0x01, 0x00, 0x65, 0x35, 0x81, 0x2A, 0x04, 0x02, 0x81, 0x2A, 0x04, 0xFF,
|
0x34, 0x81, 0x28, 0x04, 0x02, 0x81, 0x28, 0x04, 0xFF, 0x21, 0x73, 0x04,
|
||||||
0x21, 0x75, 0x04, 0xFF, 0x0D, 0x75, 0x1A, 0x00, 0x00, 0x81, 0x20, 0x01,
|
0xFF, 0x0D, 0x73, 0x1A, 0x00, 0x00, 0x81, 0x1E, 0x01, 0x06, 0x72, 0x81,
|
||||||
0x06, 0x74, 0x81, 0x1F, 0x00, 0x00, 0x81, 0x20, 0x01, 0x03, 0x74, 0x81,
|
0x1D, 0x00, 0x00, 0x81, 0x1E, 0x01, 0x03, 0x72, 0x81, 0x19, 0x81, 0x20,
|
||||||
0x1B, 0x81, 0x22, 0x06, 0x02, 0x52, 0x26, 0x00, 0x00, 0x39, 0x23, 0x06,
|
0x06, 0x02, 0x51, 0x26, 0x00, 0x00, 0x38, 0x23, 0x06, 0x07, 0x2E, 0x23,
|
||||||
0x07, 0x2F, 0x23, 0x06, 0x01, 0x19, 0x04, 0x76, 0x3F, 0x00, 0x00, 0x01,
|
0x06, 0x01, 0x19, 0x04, 0x76, 0x3E, 0x00, 0x00, 0x01, 0x01, 0x72, 0x81,
|
||||||
0x01, 0x74, 0x81, 0x1A, 0x01, 0x01, 0x10, 0x06, 0x02, 0x40, 0x26, 0x81,
|
0x18, 0x01, 0x01, 0x10, 0x06, 0x02, 0x3F, 0x26, 0x81, 0x20, 0x3A, 0x00,
|
||||||
0x22, 0x3B, 0x00, 0x04, 0x81, 0x20, 0x23, 0x01, 0x17, 0x01, 0x18, 0x6F,
|
0x04, 0x81, 0x1E, 0x23, 0x01, 0x17, 0x01, 0x18, 0x6D, 0x05, 0x02, 0x44,
|
||||||
0x05, 0x02, 0x45, 0x26, 0x01, 0x18, 0x11, 0x03, 0x00, 0x71, 0x81, 0x1B,
|
0x26, 0x01, 0x18, 0x11, 0x03, 0x00, 0x6F, 0x81, 0x19, 0x81, 0x14, 0x02,
|
||||||
0x81, 0x16, 0x02, 0x00, 0x06, 0x0D, 0x01, 0x80, 0x64, 0x08, 0x03, 0x01,
|
0x00, 0x06, 0x0D, 0x01, 0x80, 0x64, 0x08, 0x03, 0x01, 0x81, 0x14, 0x02,
|
||||||
0x81, 0x16, 0x02, 0x01, 0x09, 0x04, 0x0E, 0x23, 0x01, 0x32, 0x0D, 0x06,
|
0x01, 0x09, 0x04, 0x0E, 0x23, 0x01, 0x32, 0x0D, 0x06, 0x04, 0x01, 0x80,
|
||||||
0x04, 0x01, 0x80, 0x64, 0x09, 0x01, 0x8E, 0x6C, 0x09, 0x03, 0x01, 0x02,
|
0x64, 0x09, 0x01, 0x8E, 0x6C, 0x09, 0x03, 0x01, 0x02, 0x01, 0x01, 0x82,
|
||||||
0x01, 0x01, 0x82, 0x6D, 0x08, 0x02, 0x01, 0x01, 0x03, 0x09, 0x01, 0x04,
|
0x6D, 0x08, 0x02, 0x01, 0x01, 0x03, 0x09, 0x01, 0x04, 0x0C, 0x09, 0x02,
|
||||||
0x0C, 0x09, 0x02, 0x01, 0x01, 0x80, 0x63, 0x09, 0x01, 0x80, 0x64, 0x0C,
|
0x01, 0x01, 0x80, 0x63, 0x09, 0x01, 0x80, 0x64, 0x0C, 0x0A, 0x02, 0x01,
|
||||||
0x0A, 0x02, 0x01, 0x01, 0x83, 0x0F, 0x09, 0x01, 0x83, 0x10, 0x0C, 0x09,
|
0x01, 0x83, 0x0F, 0x09, 0x01, 0x83, 0x10, 0x0C, 0x09, 0x03, 0x03, 0x01,
|
||||||
0x03, 0x03, 0x01, 0x01, 0x01, 0x0C, 0x81, 0x17, 0x3E, 0x01, 0x01, 0x0E,
|
0x01, 0x01, 0x0C, 0x81, 0x15, 0x3D, 0x01, 0x01, 0x0E, 0x02, 0x01, 0x01,
|
||||||
0x02, 0x01, 0x01, 0x04, 0x07, 0x3C, 0x02, 0x01, 0x01, 0x80, 0x64, 0x07,
|
0x04, 0x07, 0x3B, 0x02, 0x01, 0x01, 0x80, 0x64, 0x07, 0x3A, 0x02, 0x01,
|
||||||
0x3B, 0x02, 0x01, 0x01, 0x83, 0x10, 0x07, 0x3C, 0x2D, 0x15, 0x06, 0x03,
|
0x01, 0x83, 0x10, 0x07, 0x3B, 0x2C, 0x15, 0x06, 0x03, 0x01, 0x18, 0x09,
|
||||||
0x01, 0x18, 0x09, 0x81, 0x0B, 0x09, 0x77, 0x23, 0x01, 0x05, 0x14, 0x02,
|
0x81, 0x09, 0x09, 0x75, 0x23, 0x01, 0x05, 0x14, 0x02, 0x03, 0x09, 0x03,
|
||||||
0x03, 0x09, 0x03, 0x03, 0x01, 0x1F, 0x15, 0x01, 0x01, 0x39, 0x81, 0x17,
|
0x03, 0x01, 0x1F, 0x15, 0x01, 0x01, 0x38, 0x81, 0x15, 0x02, 0x03, 0x09,
|
||||||
0x02, 0x03, 0x09, 0x3E, 0x03, 0x03, 0x01, 0x00, 0x01, 0x17, 0x81, 0x17,
|
0x3D, 0x03, 0x03, 0x01, 0x00, 0x01, 0x17, 0x81, 0x15, 0x01, 0x9C, 0x10,
|
||||||
0x01, 0x9C, 0x10, 0x08, 0x03, 0x02, 0x01, 0x00, 0x01, 0x3B, 0x81, 0x17,
|
0x08, 0x03, 0x02, 0x01, 0x00, 0x01, 0x3B, 0x81, 0x15, 0x01, 0x3C, 0x08,
|
||||||
0x01, 0x3C, 0x08, 0x02, 0x02, 0x09, 0x03, 0x02, 0x01, 0x00, 0x01, 0x3C,
|
0x02, 0x02, 0x09, 0x03, 0x02, 0x01, 0x00, 0x01, 0x3C, 0x81, 0x15, 0x02,
|
||||||
0x81, 0x17, 0x02, 0x02, 0x09, 0x03, 0x02, 0x81, 0x22, 0x23, 0x01, 0x2E,
|
0x02, 0x09, 0x03, 0x02, 0x81, 0x20, 0x23, 0x01, 0x2E, 0x11, 0x06, 0x0E,
|
||||||
0x11, 0x06, 0x0E, 0x22, 0x81, 0x22, 0x23, 0x01, 0x30, 0x01, 0x39, 0x6F,
|
0x22, 0x81, 0x20, 0x23, 0x01, 0x30, 0x01, 0x39, 0x6D, 0x06, 0x03, 0x22,
|
||||||
0x06, 0x03, 0x22, 0x04, 0x73, 0x01, 0x80, 0x5A, 0x10, 0x06, 0x02, 0x45,
|
0x04, 0x73, 0x01, 0x80, 0x5A, 0x10, 0x06, 0x02, 0x44, 0x26, 0x73, 0x02,
|
||||||
0x26, 0x75, 0x02, 0x03, 0x02, 0x02, 0x00, 0x01, 0x81, 0x22, 0x79, 0x01,
|
0x03, 0x02, 0x02, 0x00, 0x01, 0x81, 0x20, 0x77, 0x01, 0x0A, 0x08, 0x03,
|
||||||
0x0A, 0x08, 0x03, 0x00, 0x81, 0x22, 0x79, 0x02, 0x00, 0x09, 0x00, 0x02,
|
0x00, 0x81, 0x20, 0x77, 0x02, 0x00, 0x09, 0x00, 0x02, 0x03, 0x00, 0x03,
|
||||||
0x03, 0x00, 0x03, 0x01, 0x81, 0x16, 0x23, 0x02, 0x01, 0x02, 0x00, 0x6F,
|
0x01, 0x81, 0x14, 0x23, 0x02, 0x01, 0x02, 0x00, 0x6D, 0x05, 0x02, 0x44,
|
||||||
0x05, 0x02, 0x45, 0x26, 0x00, 0x00, 0x32, 0x81, 0x20, 0x01, 0x02, 0x74,
|
0x26, 0x00, 0x00, 0x31, 0x81, 0x1E, 0x01, 0x02, 0x72, 0x0B, 0x81, 0x17,
|
||||||
0x0B, 0x81, 0x19, 0x00, 0x03, 0x23, 0x03, 0x00, 0x03, 0x01, 0x03, 0x02,
|
0x00, 0x03, 0x23, 0x03, 0x00, 0x03, 0x01, 0x03, 0x02, 0x81, 0x19, 0x81,
|
||||||
0x81, 0x1B, 0x81, 0x22, 0x23, 0x01, 0x81, 0x00, 0x13, 0x06, 0x02, 0x51,
|
0x20, 0x23, 0x01, 0x81, 0x00, 0x13, 0x06, 0x02, 0x50, 0x26, 0x23, 0x01,
|
||||||
0x26, 0x23, 0x01, 0x00, 0x11, 0x06, 0x0C, 0x22, 0x23, 0x05, 0x04, 0x22,
|
0x00, 0x11, 0x06, 0x0C, 0x22, 0x23, 0x05, 0x04, 0x22, 0x01, 0x00, 0x00,
|
||||||
0x01, 0x00, 0x00, 0x81, 0x22, 0x04, 0x6E, 0x02, 0x01, 0x23, 0x05, 0x02,
|
0x81, 0x20, 0x04, 0x6E, 0x02, 0x01, 0x23, 0x05, 0x02, 0x4C, 0x26, 0x3D,
|
||||||
0x4D, 0x26, 0x3E, 0x03, 0x01, 0x02, 0x02, 0x35, 0x02, 0x02, 0x3D, 0x03,
|
0x03, 0x01, 0x02, 0x02, 0x34, 0x02, 0x02, 0x3C, 0x03, 0x02, 0x23, 0x06,
|
||||||
0x02, 0x23, 0x06, 0x04, 0x81, 0x22, 0x04, 0x67, 0x22, 0x02, 0x00, 0x02,
|
0x04, 0x81, 0x20, 0x04, 0x67, 0x22, 0x02, 0x00, 0x02, 0x01, 0x0A, 0x00,
|
||||||
0x01, 0x0A, 0x00, 0x01, 0x81, 0x22, 0x23, 0x01, 0x81, 0x00, 0x0D, 0x06,
|
0x01, 0x81, 0x20, 0x23, 0x01, 0x81, 0x00, 0x0D, 0x06, 0x01, 0x00, 0x01,
|
||||||
0x01, 0x00, 0x01, 0x81, 0x00, 0x0A, 0x23, 0x05, 0x02, 0x4B, 0x26, 0x03,
|
0x81, 0x00, 0x0A, 0x23, 0x05, 0x02, 0x4A, 0x26, 0x03, 0x00, 0x01, 0x00,
|
||||||
0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x12, 0x06, 0x1A, 0x02, 0x00,
|
0x02, 0x00, 0x01, 0x00, 0x12, 0x06, 0x1A, 0x02, 0x00, 0x3D, 0x03, 0x00,
|
||||||
0x3E, 0x03, 0x00, 0x23, 0x01, 0x87, 0xFF, 0xFF, 0x7F, 0x12, 0x06, 0x02,
|
0x23, 0x01, 0x87, 0xFF, 0xFF, 0x7F, 0x12, 0x06, 0x02, 0x4B, 0x26, 0x01,
|
||||||
0x4C, 0x26, 0x01, 0x08, 0x0E, 0x39, 0x81, 0x22, 0x32, 0x09, 0x04, 0x5F,
|
0x08, 0x0E, 0x38, 0x81, 0x20, 0x31, 0x09, 0x04, 0x5F, 0x00, 0x00, 0x81,
|
||||||
0x00, 0x00, 0x81, 0x1A, 0x81, 0x0C, 0x00, 0x00, 0x81, 0x1B, 0x81, 0x2A,
|
0x18, 0x81, 0x0A, 0x00, 0x00, 0x81, 0x19, 0x81, 0x28, 0x00, 0x00, 0x81,
|
||||||
0x00, 0x00, 0x81, 0x20, 0x72, 0x81, 0x1B, 0x00, 0x01, 0x81, 0x1B, 0x23,
|
0x1E, 0x70, 0x81, 0x19, 0x00, 0x01, 0x81, 0x19, 0x23, 0x05, 0x02, 0x50,
|
||||||
0x05, 0x02, 0x51, 0x26, 0x81, 0x22, 0x23, 0x01, 0x81, 0x00, 0x13, 0x06,
|
0x26, 0x81, 0x20, 0x23, 0x01, 0x81, 0x00, 0x13, 0x06, 0x02, 0x50, 0x26,
|
||||||
0x02, 0x51, 0x26, 0x03, 0x00, 0x23, 0x06, 0x17, 0x81, 0x22, 0x02, 0x00,
|
0x03, 0x00, 0x23, 0x06, 0x17, 0x81, 0x20, 0x02, 0x00, 0x23, 0x01, 0x87,
|
||||||
0x23, 0x01, 0x87, 0xFF, 0xFF, 0x7F, 0x13, 0x06, 0x02, 0x51, 0x26, 0x01,
|
0xFF, 0xFF, 0x7F, 0x13, 0x06, 0x02, 0x50, 0x26, 0x01, 0x08, 0x0E, 0x09,
|
||||||
0x08, 0x0E, 0x09, 0x03, 0x00, 0x04, 0x66, 0x22, 0x02, 0x00, 0x00, 0x00,
|
0x03, 0x00, 0x04, 0x66, 0x22, 0x02, 0x00, 0x00, 0x00, 0x81, 0x19, 0x23,
|
||||||
0x81, 0x1B, 0x23, 0x01, 0x81, 0x7F, 0x12, 0x06, 0x09, 0x81, 0x2A, 0x01,
|
0x01, 0x81, 0x7F, 0x12, 0x06, 0x09, 0x81, 0x28, 0x01, 0x00, 0x63, 0x34,
|
||||||
0x00, 0x65, 0x35, 0x01, 0x00, 0x00, 0x23, 0x65, 0x35, 0x65, 0x3D, 0x81,
|
0x01, 0x00, 0x00, 0x23, 0x63, 0x34, 0x63, 0x3C, 0x81, 0x11, 0x01, 0x7F,
|
||||||
0x13, 0x01, 0x7F, 0x00, 0x01, 0x81, 0x22, 0x03, 0x00, 0x02, 0x00, 0x01,
|
0x00, 0x01, 0x81, 0x20, 0x03, 0x00, 0x02, 0x00, 0x01, 0x05, 0x14, 0x01,
|
||||||
0x05, 0x14, 0x01, 0x01, 0x15, 0x2C, 0x02, 0x00, 0x01, 0x06, 0x14, 0x23,
|
0x01, 0x15, 0x2B, 0x02, 0x00, 0x01, 0x06, 0x14, 0x23, 0x01, 0x01, 0x15,
|
||||||
0x01, 0x01, 0x15, 0x06, 0x02, 0x43, 0x26, 0x01, 0x04, 0x0E, 0x02, 0x00,
|
0x06, 0x02, 0x42, 0x26, 0x01, 0x04, 0x0E, 0x02, 0x00, 0x01, 0x1F, 0x15,
|
||||||
0x01, 0x1F, 0x15, 0x23, 0x01, 0x1F, 0x11, 0x06, 0x02, 0x44, 0x26, 0x09,
|
0x23, 0x01, 0x1F, 0x11, 0x06, 0x02, 0x43, 0x26, 0x09, 0x00, 0x00, 0x23,
|
||||||
0x00, 0x00, 0x23, 0x05, 0x05, 0x01, 0x00, 0x01, 0x7F, 0x00, 0x81, 0x20,
|
0x05, 0x05, 0x01, 0x00, 0x01, 0x7F, 0x00, 0x81, 0x1E, 0x00, 0x00, 0x23,
|
||||||
0x00, 0x00, 0x23, 0x05, 0x02, 0x4C, 0x26, 0x3E, 0x81, 0x23, 0x00, 0x00,
|
0x05, 0x02, 0x4B, 0x26, 0x3D, 0x81, 0x21, 0x00, 0x00, 0x2F, 0x23, 0x01,
|
||||||
0x30, 0x23, 0x01, 0x00, 0x13, 0x06, 0x01, 0x00, 0x22, 0x19, 0x04, 0x74,
|
0x00, 0x13, 0x06, 0x01, 0x00, 0x22, 0x19, 0x04, 0x74, 0x00, 0x01, 0x01,
|
||||||
0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x0B, 0x00, 0x00, 0x01, 0x15, 0x00,
|
0x00, 0x00, 0x01, 0x0B, 0x00, 0x00, 0x01, 0x15, 0x00, 0x00, 0x01, 0x1F,
|
||||||
0x00, 0x01, 0x1F, 0x00, 0x00, 0x01, 0x29, 0x00, 0x00, 0x01, 0x33, 0x00,
|
0x00, 0x00, 0x01, 0x29, 0x00, 0x00, 0x01, 0x33, 0x00, 0x00, 0x81, 0x29,
|
||||||
0x00, 0x81, 0x2B, 0x22, 0x00, 0x00, 0x23, 0x06, 0x08, 0x81, 0x2C, 0x23,
|
0x22, 0x00, 0x00, 0x23, 0x06, 0x08, 0x81, 0x2A, 0x23, 0x06, 0x01, 0x19,
|
||||||
0x06, 0x01, 0x19, 0x04, 0x75, 0x00, 0x00, 0x01, 0x00, 0x2E, 0x2F, 0x0B,
|
0x04, 0x75, 0x00, 0x00, 0x01, 0x00, 0x2D, 0x2E, 0x0B, 0x3E, 0x00, 0x00,
|
||||||
0x3F, 0x00, 0x00, 0x01, 0x81, 0x6C, 0x00, 0x00, 0x01, 0x81, 0x7C, 0x00,
|
0x01, 0x81, 0x6C, 0x00, 0x00, 0x01, 0x81, 0x7C, 0x00, 0x00, 0x01, 0x82,
|
||||||
0x00, 0x01, 0x82, 0x11, 0x00, 0x00, 0x01, 0x81, 0x74, 0x00, 0x00, 0x01,
|
0x11, 0x00, 0x00, 0x01, 0x81, 0x74, 0x00, 0x00, 0x01, 0x03, 0x30, 0x01,
|
||||||
0x03, 0x31, 0x01, 0x03, 0x31, 0x00
|
0x03, 0x30, 0x00
|
||||||
};
|
};
|
||||||
|
|
||||||
static const uint16_t t0_caddr[] = {
|
static const uint16_t t0_caddr[] = {
|
||||||
|
|
@ -736,98 +736,97 @@ static const uint16_t t0_caddr[] = {
|
||||||
112,
|
112,
|
||||||
116,
|
116,
|
||||||
120,
|
120,
|
||||||
124,
|
125,
|
||||||
129,
|
130,
|
||||||
134,
|
135,
|
||||||
139,
|
140,
|
||||||
144,
|
145,
|
||||||
149,
|
150,
|
||||||
154,
|
155,
|
||||||
159,
|
160,
|
||||||
164,
|
168,
|
||||||
172,
|
173,
|
||||||
177,
|
178,
|
||||||
182,
|
183,
|
||||||
187,
|
188,
|
||||||
192,
|
193,
|
||||||
197,
|
198,
|
||||||
202,
|
203,
|
||||||
207,
|
208,
|
||||||
212,
|
213,
|
||||||
217,
|
218,
|
||||||
222,
|
223,
|
||||||
227,
|
228,
|
||||||
232,
|
257,
|
||||||
261,
|
272,
|
||||||
276,
|
278,
|
||||||
282,
|
284,
|
||||||
288,
|
289,
|
||||||
293,
|
297,
|
||||||
301,
|
305,
|
||||||
309,
|
311,
|
||||||
315,
|
316,
|
||||||
320,
|
327,
|
||||||
331,
|
1029,
|
||||||
|
1044,
|
||||||
|
1048,
|
||||||
1053,
|
1053,
|
||||||
|
1058,
|
||||||
|
1063,
|
||||||
1068,
|
1068,
|
||||||
1072,
|
1073,
|
||||||
1077,
|
1078,
|
||||||
1082,
|
1083,
|
||||||
1087,
|
1087,
|
||||||
1092,
|
1092,
|
||||||
1097,
|
1097,
|
||||||
1102,
|
1102,
|
||||||
1107,
|
1107,
|
||||||
1111,
|
1120,
|
||||||
1116,
|
1125,
|
||||||
1121,
|
1130,
|
||||||
1126,
|
1145,
|
||||||
1131,
|
1150,
|
||||||
1144,
|
1164,
|
||||||
1149,
|
1202,
|
||||||
1154,
|
1255,
|
||||||
1165,
|
1352,
|
||||||
1170,
|
1478,
|
||||||
1184,
|
1487,
|
||||||
1222,
|
1502,
|
||||||
1275,
|
1516,
|
||||||
1363,
|
1533,
|
||||||
1489,
|
1765,
|
||||||
1498,
|
1781,
|
||||||
1513,
|
1799,
|
||||||
1527,
|
|
||||||
1544,
|
|
||||||
1776,
|
|
||||||
1792,
|
|
||||||
1810,
|
1810,
|
||||||
1821,
|
1881,
|
||||||
1892,
|
1939,
|
||||||
1950,
|
1945,
|
||||||
1956,
|
1951,
|
||||||
1962,
|
1958,
|
||||||
1969,
|
2009,
|
||||||
2020,
|
2038,
|
||||||
2049,
|
2083,
|
||||||
2094,
|
2095,
|
||||||
2106,
|
2105,
|
||||||
2116,
|
2118,
|
||||||
2129,
|
2122,
|
||||||
2133,
|
2126,
|
||||||
2137,
|
2130,
|
||||||
2141,
|
2134,
|
||||||
2145,
|
2138,
|
||||||
2149,
|
2142,
|
||||||
2153,
|
2147,
|
||||||
2158,
|
2160,
|
||||||
2171,
|
2168,
|
||||||
2179,
|
2173,
|
||||||
2184,
|
2178,
|
||||||
2189,
|
2183,
|
||||||
2194,
|
2188
|
||||||
2199
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#define T0_INTERPRETED 59
|
#define T0_INTERPRETED 58
|
||||||
|
|
||||||
#define T0_ENTER(ip, rp, slot) do { \
|
#define T0_ENTER(ip, rp, slot) do { \
|
||||||
const unsigned char *t0_newip; \
|
const unsigned char *t0_newip; \
|
||||||
|
|
@ -848,7 +847,7 @@ name(void *ctx) \
|
||||||
T0_ENTER(t0ctx->ip, t0ctx->rp, slot); \
|
T0_ENTER(t0ctx->ip, t0ctx->rp, slot); \
|
||||||
}
|
}
|
||||||
|
|
||||||
T0_DEFENTRY(br_x509_minimal_init_main, 138)
|
T0_DEFENTRY(br_x509_minimal_init_main, 136)
|
||||||
|
|
||||||
void
|
void
|
||||||
br_x509_minimal_run(void *t0ctx)
|
br_x509_minimal_run(void *t0ctx)
|
||||||
|
|
@ -1100,7 +1099,7 @@ br_x509_minimal_run(void *t0ctx)
|
||||||
if (ta->flags & BR_X509_TA_CA) {
|
if (ta->flags & BR_X509_TA_CA) {
|
||||||
continue;
|
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)) {
|
if (memcmp(hashed_DN, CTX->current_dn_hash, DNHASH_LEN)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -1161,7 +1160,7 @@ br_x509_minimal_run(void *t0ctx)
|
||||||
if (!(ta->flags & BR_X509_TA_CA)) {
|
if (!(ta->flags & BR_X509_TA_CA)) {
|
||||||
continue;
|
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)) {
|
if (memcmp(hashed_DN, CTX->saved_dn_hash, DNHASH_LEN)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -1360,14 +1359,6 @@ br_x509_minimal_run(void *t0ctx)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 42: {
|
case 42: {
|
||||||
/* get8 */
|
|
||||||
|
|
||||||
uint32_t addr = T0_POP();
|
|
||||||
T0_PUSH(*((unsigned char *)CTX + addr));
|
|
||||||
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 43: {
|
|
||||||
/* match-server-name */
|
/* match-server-name */
|
||||||
|
|
||||||
size_t n1, n2;
|
size_t n1, n2;
|
||||||
|
|
@ -1402,7 +1393,7 @@ br_x509_minimal_run(void *t0ctx)
|
||||||
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 44: {
|
case 43: {
|
||||||
/* neg */
|
/* neg */
|
||||||
|
|
||||||
uint32_t a = T0_POP();
|
uint32_t a = T0_POP();
|
||||||
|
|
@ -1410,7 +1401,7 @@ br_x509_minimal_run(void *t0ctx)
|
||||||
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 45: {
|
case 44: {
|
||||||
/* or */
|
/* or */
|
||||||
|
|
||||||
uint32_t b = T0_POP();
|
uint32_t b = T0_POP();
|
||||||
|
|
@ -1419,12 +1410,12 @@ br_x509_minimal_run(void *t0ctx)
|
||||||
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 46: {
|
case 45: {
|
||||||
/* over */
|
/* over */
|
||||||
T0_PUSH(T0_PEEK(1));
|
T0_PUSH(T0_PEEK(1));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 47: {
|
case 46: {
|
||||||
/* read-blob-inner */
|
/* read-blob-inner */
|
||||||
|
|
||||||
uint32_t len = T0_POP();
|
uint32_t len = T0_POP();
|
||||||
|
|
@ -1450,7 +1441,7 @@ br_x509_minimal_run(void *t0ctx)
|
||||||
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 48: {
|
case 47: {
|
||||||
/* read8-low */
|
/* read8-low */
|
||||||
|
|
||||||
if (CTX->hlen == 0) {
|
if (CTX->hlen == 0) {
|
||||||
|
|
@ -1469,17 +1460,17 @@ br_x509_minimal_run(void *t0ctx)
|
||||||
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 49: {
|
case 48: {
|
||||||
/* roll */
|
/* roll */
|
||||||
T0_ROLL(T0_POP());
|
T0_ROLL(T0_POP());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 50: {
|
case 49: {
|
||||||
/* rot */
|
/* rot */
|
||||||
T0_ROT();
|
T0_ROT();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 51: {
|
case 50: {
|
||||||
/* set16 */
|
/* set16 */
|
||||||
|
|
||||||
uint32_t addr = T0_POP();
|
uint32_t addr = T0_POP();
|
||||||
|
|
@ -1487,7 +1478,7 @@ br_x509_minimal_run(void *t0ctx)
|
||||||
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 52: {
|
case 51: {
|
||||||
/* set32 */
|
/* set32 */
|
||||||
|
|
||||||
uint32_t addr = T0_POP();
|
uint32_t addr = T0_POP();
|
||||||
|
|
@ -1495,7 +1486,7 @@ br_x509_minimal_run(void *t0ctx)
|
||||||
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 53: {
|
case 52: {
|
||||||
/* set8 */
|
/* set8 */
|
||||||
|
|
||||||
uint32_t addr = T0_POP();
|
uint32_t addr = T0_POP();
|
||||||
|
|
@ -1503,7 +1494,7 @@ br_x509_minimal_run(void *t0ctx)
|
||||||
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 54: {
|
case 53: {
|
||||||
/* start-dn-hash */
|
/* start-dn-hash */
|
||||||
|
|
||||||
CTX->dn_hash_impl->init(&CTX->dn_hash.vtable);
|
CTX->dn_hash_impl->init(&CTX->dn_hash.vtable);
|
||||||
|
|
@ -1511,7 +1502,7 @@ br_x509_minimal_run(void *t0ctx)
|
||||||
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 55: {
|
case 54: {
|
||||||
/* start-tbs-hash */
|
/* start-tbs-hash */
|
||||||
|
|
||||||
br_multihash_init(&CTX->mhash);
|
br_multihash_init(&CTX->mhash);
|
||||||
|
|
@ -1519,19 +1510,19 @@ br_x509_minimal_run(void *t0ctx)
|
||||||
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 56: {
|
case 55: {
|
||||||
/* stop-tbs-hash */
|
/* stop-tbs-hash */
|
||||||
|
|
||||||
CTX->do_mhash = 0;
|
CTX->do_mhash = 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 57: {
|
case 56: {
|
||||||
/* swap */
|
/* swap */
|
||||||
T0_SWAP();
|
T0_SWAP();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 58: {
|
case 57: {
|
||||||
/* zero-server-name */
|
/* zero-server-name */
|
||||||
|
|
||||||
T0_PUSHi(-(CTX->server_name == NULL));
|
T0_PUSHi(-(CTX->server_name == NULL));
|
||||||
|
|
|
||||||
|
|
@ -188,8 +188,7 @@ br_x509_minimal_init(br_x509_minimal_context *ctx,
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
xm_start_chain(const br_x509_class **ctx,
|
xm_start_chain(const br_x509_class **ctx, const char *server_name)
|
||||||
unsigned expected_key_type, const char *server_name)
|
|
||||||
{
|
{
|
||||||
br_x509_minimal_context *cc;
|
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.dp = cc->dp_stack;
|
||||||
cc->cpu.rp = cc->rp_stack;
|
cc->cpu.rp = cc->rp_stack;
|
||||||
br_x509_minimal_init_main(&cc->cpu);
|
br_x509_minimal_init_main(&cc->cpu);
|
||||||
cc->expected_key_type = expected_key_type;
|
|
||||||
if (server_name == NULL || *server_name == 0) {
|
if (server_name == NULL || *server_name == 0) {
|
||||||
cc->server_name = NULL;
|
cc->server_name = NULL;
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -269,7 +267,7 @@ xm_end_chain(const br_x509_class **ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
static const br_x509_pkey *
|
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;
|
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
|
if (cc->err == BR_ERR_X509_OK
|
||||||
|| cc->err == BR_ERR_X509_NOT_TRUSTED)
|
|| cc->err == BR_ERR_X509_NOT_TRUSTED)
|
||||||
{
|
{
|
||||||
|
if (usages != NULL) {
|
||||||
|
*usages = cc->key_usages;
|
||||||
|
}
|
||||||
return &((br_x509_minimal_context *)ctx)->pkey;
|
return &((br_x509_minimal_context *)ctx)->pkey;
|
||||||
} else {
|
} else {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
@ -472,7 +473,7 @@ cc: zero-server-name ( -- bool ) {
|
||||||
T0_PUSHi(-(CTX->server_name == NULL));
|
T0_PUSHi(-(CTX->server_name == NULL));
|
||||||
}
|
}
|
||||||
|
|
||||||
addr: expected_key_type
|
addr: key_usages
|
||||||
addr: cert_sig
|
addr: cert_sig
|
||||||
addr: cert_sig_len
|
addr: cert_sig_len
|
||||||
addr: cert_signer_key_type
|
addr: cert_signer_key_type
|
||||||
|
|
@ -705,7 +706,7 @@ cc: check-direct-trust ( -- ) {
|
||||||
if (ta->flags & BR_X509_TA_CA) {
|
if (ta->flags & BR_X509_TA_CA) {
|
||||||
continue;
|
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)) {
|
if (memcmp(hashed_DN, CTX->current_dn_hash, DNHASH_LEN)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -765,7 +766,7 @@ cc: check-trust-anchor-CA ( -- ) {
|
||||||
if (!(ta->flags & BR_X509_TA_CA)) {
|
if (!(ta->flags & BR_X509_TA_CA)) {
|
||||||
continue;
|
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)) {
|
if (memcmp(hashed_DN, CTX->saved_dn_hash, DNHASH_LEN)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -892,20 +893,14 @@ OID: subjectInfoAccess 1.3.6.1.5.5.7.1.11
|
||||||
|
|
||||||
\ Process a Key Usage extension.
|
\ Process a Key Usage extension.
|
||||||
\ For the EE certificate:
|
\ For the EE certificate:
|
||||||
\ -- if the expected key usage is "key exchange", then the extension
|
\ -- if the key usage contains keyEncipherment (2), dataEncipherment (3)
|
||||||
\ must contain either keyEncipherment (2) or dataEncipherment (3);
|
\ or keyAgreement (4), then the "key exchange" usage is allowed;
|
||||||
\ -- if the expected key usage is "signature", then the extension
|
\ -- if the key usage contains digitalSignature (0) or nonRepudiation (1),
|
||||||
\ must contain either digitalSignature (0) or nonRepudiation (1).
|
\ then the "signature" usage is allowed.
|
||||||
\ For CA certificates, the extension must contain keyCertSign (5).
|
\ For CA certificates, the extension must contain keyCertSign (5).
|
||||||
: process-keyUsage ( lim ee -- lim )
|
: process-keyUsage ( lim ee -- lim )
|
||||||
\ Compute flags, depending on EE status and expected key usage.
|
{ ee }
|
||||||
\ 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 }
|
|
||||||
\ Read tag for the BIT STRING and open it.
|
\ Read tag for the BIT STRING and open it.
|
||||||
read-tag 0x03 check-tag-primitive
|
read-tag 0x03 check-tag-primitive
|
||||||
read-length-open-elt
|
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
|
1 of read8 ign >> ign << endof
|
||||||
drop read8 0
|
drop read8 0
|
||||||
endcase
|
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 ;
|
skip-close-elt ;
|
||||||
|
|
||||||
\ Process a Subject Alt Name extension. Returned value is a boolean set
|
\ 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.
|
\ Process public key.
|
||||||
ee if
|
ee if
|
||||||
\ For the EE certificate, check that the key type
|
\ For the EE certificate, copy the key data to the
|
||||||
\ matches that which was expected, then copy the
|
\ relevant buffer.
|
||||||
\ 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
|
|
||||||
pkey-type case
|
pkey-type case
|
||||||
KEYTYPE_RSA of nlen elen copy-ee-rsa-pkey endof
|
KEYTYPE_RSA of nlen elen copy-ee-rsa-pkey endof
|
||||||
KEYTYPE_EC of curve qlen copy-ee-ec-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 ;
|
check-trust-anchor-CA ;
|
||||||
|
|
||||||
: main
|
: main
|
||||||
|
\ Unless restricted by a Key Usage extension, all usages are
|
||||||
|
\ deemed allowed.
|
||||||
|
0x30 addr-key_usages set8
|
||||||
-1 decode-certificate
|
-1 decode-certificate
|
||||||
co
|
co
|
||||||
begin
|
begin
|
||||||
|
|
|
||||||
|
|
@ -1438,6 +1438,7 @@ run_test_case(test_case *tc)
|
||||||
blob *certs;
|
blob *certs;
|
||||||
br_x509_pkey *ee_pkey_ref;
|
br_x509_pkey *ee_pkey_ref;
|
||||||
const br_x509_pkey *ee_pkey;
|
const br_x509_pkey *ee_pkey;
|
||||||
|
unsigned usages;
|
||||||
unsigned status;
|
unsigned status;
|
||||||
|
|
||||||
printf("%s: ", tc->name);
|
printf("%s: ", tc->name);
|
||||||
|
|
@ -1477,8 +1478,8 @@ run_test_case(test_case *tc)
|
||||||
tta->key_name);
|
tta->key_name);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
anchors[u].dn = tta->dn;
|
anchors[u].dn.data = tta->dn;
|
||||||
anchors[u].dn_len = tta->dn_len;
|
anchors[u].dn.len = tta->dn_len;
|
||||||
anchors[u].flags = tta->flags;
|
anchors[u].flags = tta->flags;
|
||||||
anchors[u].pkey = *tak;
|
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
|
* Run the engine. We inject certificates by chunks of 100 bytes
|
||||||
* in order to exercise the coroutine API.
|
* in order to exercise the coroutine API.
|
||||||
*/
|
*/
|
||||||
ctx.vtable->start_chain(&ctx.vtable,
|
ctx.vtable->start_chain(&ctx.vtable, tc->servername);
|
||||||
tc->key_type_usage, tc->servername);
|
|
||||||
for (u = 0; u < num_certs; u ++) {
|
for (u = 0; u < num_certs; u ++) {
|
||||||
size_t v;
|
size_t v;
|
||||||
|
|
||||||
|
|
@ -1561,7 +1561,22 @@ run_test_case(test_case *tc)
|
||||||
ctx.vtable->end_cert(&ctx.vtable);
|
ctx.vtable->end_cert(&ctx.vtable);
|
||||||
}
|
}
|
||||||
status = ctx.vtable->end_chain(&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
|
* Check results. Note that we may still get a public key if
|
||||||
|
|
|
||||||
|
|
@ -279,6 +279,11 @@ void list_names(void);
|
||||||
*/
|
*/
|
||||||
const char *ec_curve_name(int curve);
|
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()
|
* Read a file completely. The returned block is allocated with xmalloc()
|
||||||
* and must be released by the caller.
|
* 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);
|
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
|
* Interpret a certificate as a trust anchor. The trust anchor is
|
||||||
* newly allocated with xmalloc() and the caller must release it.
|
* 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);
|
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
|
* Special "no anchor" X.509 validator that wraps around another X.509
|
||||||
* validator and turns "not trusted" error codes into success. This is
|
* 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);
|
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
|
* Find the symbolic name and the description for an error. If 'err' is
|
||||||
* recognised then the error symbolic name is returned; if 'comment' is
|
* recognised then the error symbolic name is returned; if 'comment' is
|
||||||
|
|
|
||||||
|
|
@ -53,8 +53,8 @@ certificate_to_trust_anchor_inner(br_x509_trust_anchor *ta,
|
||||||
VEC_CLEAR(vdn);
|
VEC_CLEAR(vdn);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
ta->dn = VEC_TOARRAY(vdn);
|
ta->dn.data = VEC_TOARRAY(vdn);
|
||||||
ta->dn_len = VEC_LEN(vdn);
|
ta->dn.len = VEC_LEN(vdn);
|
||||||
VEC_CLEAR(vdn);
|
VEC_CLEAR(vdn);
|
||||||
ta->flags = 0;
|
ta->flags = 0;
|
||||||
if (br_x509_decoder_isCA(&dc)) {
|
if (br_x509_decoder_isCA(&dc)) {
|
||||||
|
|
@ -76,7 +76,7 @@ certificate_to_trust_anchor_inner(br_x509_trust_anchor *ta,
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
fprintf(stderr, "ERROR: unsupported public key type in CA\n");
|
fprintf(stderr, "ERROR: unsupported public key type in CA\n");
|
||||||
xfree(ta->dn);
|
xfree(ta->dn.data);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -99,7 +99,7 @@ certificate_to_trust_anchor(br_x509_certificate *xc)
|
||||||
void
|
void
|
||||||
free_ta_contents(br_x509_trust_anchor *ta)
|
free_ta_contents(br_x509_trust_anchor *ta)
|
||||||
{
|
{
|
||||||
xfree(ta->dn);
|
xfree(ta->dn.data);
|
||||||
switch (ta->pkey.key_type) {
|
switch (ta->pkey.key_type) {
|
||||||
case BR_KEYTYPE_RSA:
|
case BR_KEYTYPE_RSA:
|
||||||
xfree(ta->pkey.key.rsa.n);
|
xfree(ta->pkey.key.rsa.n);
|
||||||
|
|
@ -137,15 +137,32 @@ read_trust_anchors(anchor_list *dst, const char *fname)
|
||||||
return num;
|
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
|
static void
|
||||||
xwc_start_chain(const br_x509_class **ctx,
|
xwc_start_chain(const br_x509_class **ctx, const char *server_name)
|
||||||
unsigned expected_key_type, const char *server_name)
|
|
||||||
{
|
{
|
||||||
x509_noanchor_context *xwc;
|
x509_noanchor_context *xwc;
|
||||||
|
|
||||||
xwc = (x509_noanchor_context *)ctx;
|
xwc = (x509_noanchor_context *)ctx;
|
||||||
(*xwc->inner)->start_chain(xwc->inner,
|
(*xwc->inner)->start_chain(xwc->inner, server_name);
|
||||||
expected_key_type, server_name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
@ -190,12 +207,12 @@ xwc_end_chain(const br_x509_class **ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
static const br_x509_pkey *
|
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;
|
x509_noanchor_context *xwc;
|
||||||
|
|
||||||
xwc = (x509_noanchor_context *)ctx;
|
xwc = (x509_noanchor_context *)ctx;
|
||||||
return (*xwc->inner)->get_pkey(xwc->inner);
|
return (*xwc->inner)->get_pkey(xwc->inner, usages);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* see brssl.h */
|
/* see brssl.h */
|
||||||
|
|
|
||||||
396
tools/client.c
396
tools/client.c
|
|
@ -117,6 +117,308 @@ host_connect(const char *host, const char *port, int verbose)
|
||||||
return fd;
|
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
|
static void
|
||||||
usage_client(void)
|
usage_client(void)
|
||||||
{
|
{
|
||||||
|
|
@ -139,6 +441,12 @@ usage_client(void)
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
" -CA file add certificates in 'file' to trust anchors\n");
|
" -CA file add certificates in 'file' to trust anchors\n");
|
||||||
fprintf(stderr,
|
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");
|
" -list list supported names (protocols, algorithms...)\n");
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
" -vmin name set minimum supported version (default: TLS-1.0)\n");
|
" -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;
|
br_x509_minimal_context xc;
|
||||||
x509_noanchor_context xwc;
|
x509_noanchor_context xwc;
|
||||||
const br_hash_class *dnhash;
|
const br_hash_class *dnhash;
|
||||||
|
ccert_context zc;
|
||||||
|
br_x509_certificate *chain;
|
||||||
|
size_t chain_len;
|
||||||
|
private_key *sk;
|
||||||
|
int nostaticecdh;
|
||||||
unsigned char *iobuf;
|
unsigned char *iobuf;
|
||||||
size_t iobuf_len;
|
size_t iobuf_len;
|
||||||
size_t minhello_len;
|
size_t minhello_len;
|
||||||
|
|
@ -200,6 +513,10 @@ do_client(int argc, char *argv[])
|
||||||
num_suites = 0;
|
num_suites = 0;
|
||||||
hfuns = 0;
|
hfuns = 0;
|
||||||
suite_ids = NULL;
|
suite_ids = NULL;
|
||||||
|
chain = NULL;
|
||||||
|
chain_len = 0;
|
||||||
|
sk = NULL;
|
||||||
|
nostaticecdh = 0;
|
||||||
iobuf = NULL;
|
iobuf = NULL;
|
||||||
iobuf_len = 0;
|
iobuf_len = 0;
|
||||||
minhello_len = (size_t)-1;
|
minhello_len = (size_t)-1;
|
||||||
|
|
@ -279,6 +596,44 @@ do_client(int argc, char *argv[])
|
||||||
usage_client();
|
usage_client();
|
||||||
goto client_exit_error;
|
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")) {
|
} else if (eqstr(arg, "-list")) {
|
||||||
list_names();
|
list_names();
|
||||||
goto client_exit;
|
goto client_exit;
|
||||||
|
|
@ -412,7 +767,7 @@ do_client(int argc, char *argv[])
|
||||||
}
|
}
|
||||||
if (u == 0) {
|
if (u == 0) {
|
||||||
host = xstrdup(server_name);
|
host = xstrdup(server_name);
|
||||||
port = "443";
|
port = xstrdup("443");
|
||||||
} else {
|
} else {
|
||||||
port = xstrdup(server_name + u);
|
port = xstrdup(server_name + u);
|
||||||
host = xmalloc(u);
|
host = xmalloc(u);
|
||||||
|
|
@ -423,6 +778,19 @@ do_client(int argc, char *argv[])
|
||||||
sni = host;
|
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) {
|
if (vmin == 0) {
|
||||||
vmin = BR_TLS10;
|
vmin = BR_TLS10;
|
||||||
}
|
}
|
||||||
|
|
@ -560,11 +928,13 @@ do_client(int argc, char *argv[])
|
||||||
}
|
}
|
||||||
if ((req & REQ_ECDHE_RSA) != 0) {
|
if ((req & REQ_ECDHE_RSA) != 0) {
|
||||||
br_ssl_engine_set_ec(&cc.eng, &br_ec_prime_i31);
|
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) {
|
if ((req & REQ_ECDHE_ECDSA) != 0) {
|
||||||
br_ssl_engine_set_ec(&cc.eng, &br_ec_prime_i31);
|
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) {
|
if ((req & REQ_ECDH) != 0) {
|
||||||
br_ssl_engine_set_ec(&cc.eng, &br_ec_prime_i31);
|
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);
|
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_engine_set_buffer(&cc.eng, iobuf, iobuf_len, bidi);
|
||||||
br_ssl_client_reset(&cc, sni, 0);
|
br_ssl_client_reset(&cc, sni, 0);
|
||||||
|
|
||||||
|
|
@ -657,9 +1044,12 @@ do_client(int argc, char *argv[])
|
||||||
*/
|
*/
|
||||||
client_exit:
|
client_exit:
|
||||||
xfree(host);
|
xfree(host);
|
||||||
|
xfree(port);
|
||||||
xfree(suites);
|
xfree(suites);
|
||||||
xfree(suite_ids);
|
xfree(suite_ids);
|
||||||
VEC_CLEAREXT(anchors, &free_ta_contents);
|
VEC_CLEAREXT(anchors, &free_ta_contents);
|
||||||
|
free_certificates(chain, chain_len);
|
||||||
|
free_private_key(sk);
|
||||||
xfree(iobuf);
|
xfree(iobuf);
|
||||||
if (fd >= 0) {
|
if (fd >= 0) {
|
||||||
close(fd);
|
close(fd);
|
||||||
|
|
|
||||||
|
|
@ -157,7 +157,18 @@ static struct {
|
||||||
}, {
|
}, {
|
||||||
BR_ERR_BAD_SIGNATURE,
|
BR_ERR_BAD_SIGNATURE,
|
||||||
"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,
|
||||||
"BR_ERR_IO",
|
"BR_ERR_IO",
|
||||||
|
|
|
||||||
|
|
@ -300,3 +300,15 @@ read_certificates(const char *fname, size_t *num)
|
||||||
VEC_CLEAR(cert_list);
|
VEC_CLEAR(cert_list);
|
||||||
return xcs;
|
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);
|
||||||
|
}
|
||||||
|
|
|
||||||
61
tools/keys.c
61
tools/keys.c
|
|
@ -168,3 +168,64 @@ free_private_key(private_key *sk)
|
||||||
}
|
}
|
||||||
xfree(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;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -651,3 +651,20 @@ ec_curve_name(int curve)
|
||||||
return "unknown";
|
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";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
218
tools/server.c
218
tools/server.c
|
|
@ -214,6 +214,10 @@ usage_server(void)
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
" -key fname read private key from file 'fname'\n");
|
" -key fname read private key from file 'fname'\n");
|
||||||
fprintf(stderr,
|
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");
|
" -list list supported names (protocols, algorithms...)\n");
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
" -vmin name set minimum supported version (default: TLS-1.0)\n");
|
" -vmin name set minimum supported version (default: TLS-1.0)\n");
|
||||||
|
|
@ -237,20 +241,43 @@ typedef struct {
|
||||||
private_key *sk;
|
private_key *sk;
|
||||||
} policy_context;
|
} policy_context;
|
||||||
|
|
||||||
static int
|
static void
|
||||||
get_cert_signer_algo(br_x509_certificate *xc)
|
print_hashes(unsigned chashes)
|
||||||
{
|
{
|
||||||
br_x509_decoder_context dc;
|
int i;
|
||||||
int err;
|
|
||||||
|
|
||||||
br_x509_decoder_init(&dc, 0, 0);
|
for (i = 2; i <= 6; i ++) {
|
||||||
br_x509_decoder_push(&dc, xc->data, xc->data_len);
|
if ((chashes >> i) & 1) {
|
||||||
err = br_x509_decoder_last_error(&dc);
|
int z;
|
||||||
if (err != 0) {
|
|
||||||
return -err;
|
switch (i) {
|
||||||
} else {
|
case 3: z = 224; break;
|
||||||
return br_x509_decoder_get_signer_key_type(&dc);
|
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
|
static int
|
||||||
|
|
@ -262,16 +289,10 @@ sp_choose(const br_ssl_server_policy_class **pctx,
|
||||||
const br_suite_translated *st;
|
const br_suite_translated *st;
|
||||||
size_t u, st_num;
|
size_t u, st_num;
|
||||||
unsigned chashes;
|
unsigned chashes;
|
||||||
int hash_id;
|
|
||||||
|
|
||||||
pc = (policy_context *)pctx;
|
pc = (policy_context *)pctx;
|
||||||
st = br_ssl_server_get_client_suites(cc, &st_num);
|
st = br_ssl_server_get_client_suites(cc, &st_num);
|
||||||
chashes = br_ssl_server_get_client_hashes(cc);
|
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) {
|
if (pc->verbose) {
|
||||||
fprintf(stderr, "Client parameters:\n");
|
fprintf(stderr, "Client parameters:\n");
|
||||||
fprintf(stderr, " Maximum version: ");
|
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);
|
get_suite_name_ext(st[u][0], csn, sizeof csn);
|
||||||
fprintf(stderr, " %s\n", csn);
|
fprintf(stderr, " %s\n", csn);
|
||||||
}
|
}
|
||||||
fprintf(stderr, " Common hash functions:");
|
fprintf(stderr, " Common sign+hash functions:\n");
|
||||||
for (u = 2; u <= 6; u ++) {
|
if ((chashes & 0xFF) != 0) {
|
||||||
if ((chashes >> u) & 1) {
|
fprintf(stderr, " with RSA:");
|
||||||
int z;
|
print_hashes(chashes);
|
||||||
|
|
||||||
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, "\n");
|
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 ++) {
|
for (u = 0; u < st_num; u ++) {
|
||||||
unsigned tt;
|
unsigned tt;
|
||||||
|
|
||||||
|
|
@ -337,9 +351,10 @@ sp_choose(const br_ssl_server_policy_class **pctx,
|
||||||
if (br_ssl_engine_get_version(&cc->eng)
|
if (br_ssl_engine_get_version(&cc->eng)
|
||||||
< BR_TLS12)
|
< BR_TLS12)
|
||||||
{
|
{
|
||||||
hash_id = 0;
|
choices->hash_id = 0;
|
||||||
|
} else {
|
||||||
|
choices->hash_id = choose_hash(chashes);
|
||||||
}
|
}
|
||||||
choices->hash_id = hash_id;
|
|
||||||
goto choose_ok;
|
goto choose_ok;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
@ -349,9 +364,11 @@ sp_choose(const br_ssl_server_policy_class **pctx,
|
||||||
if (br_ssl_engine_get_version(&cc->eng)
|
if (br_ssl_engine_get_version(&cc->eng)
|
||||||
< BR_TLS12)
|
< 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;
|
goto choose_ok;
|
||||||
}
|
}
|
||||||
break;
|
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
|
static size_t
|
||||||
sp_do_sign(const br_ssl_server_policy_class **pctx,
|
sp_do_sign(const br_ssl_server_policy_class **pctx,
|
||||||
int hash_id, size_t hv_len, unsigned char *data, size_t len)
|
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;
|
const br_hash_class *hc;
|
||||||
|
|
||||||
case BR_KEYTYPE_RSA:
|
case BR_KEYTYPE_RSA:
|
||||||
if (hash_id == 0) {
|
hash_oid = get_hash_oid(hash_id);
|
||||||
hash_oid = NULL;
|
if (hash_oid == NULL && hash_id != 0) {
|
||||||
} else if (hash_id >= 2 && hash_id <= 6) {
|
|
||||||
hash_oid = HASH_OID[hash_id - 2];
|
|
||||||
} else {
|
|
||||||
if (pc->verbose) {
|
if (pc->verbose) {
|
||||||
fprintf(stderr, "ERROR: cannot RSA-sign with"
|
fprintf(stderr, "ERROR: cannot RSA-sign with"
|
||||||
" unknown hash function: %d\n",
|
" unknown hash function: %d\n",
|
||||||
|
|
@ -566,6 +531,9 @@ do_server(int argc, char *argv[])
|
||||||
size_t chain_len;
|
size_t chain_len;
|
||||||
int cert_signer_algo;
|
int cert_signer_algo;
|
||||||
private_key *sk;
|
private_key *sk;
|
||||||
|
anchor_list anchors = VEC_INIT;
|
||||||
|
br_x509_minimal_context xc;
|
||||||
|
const br_hash_class *dnhash;
|
||||||
size_t u;
|
size_t u;
|
||||||
br_ssl_server_context cc;
|
br_ssl_server_context cc;
|
||||||
policy_context pc;
|
policy_context pc;
|
||||||
|
|
@ -713,6 +681,20 @@ do_server(int argc, char *argv[])
|
||||||
if (sk == NULL) {
|
if (sk == NULL) {
|
||||||
goto server_exit_error;
|
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")) {
|
} else if (eqstr(arg, "-list")) {
|
||||||
list_names();
|
list_names();
|
||||||
goto server_exit;
|
goto server_exit;
|
||||||
|
|
@ -872,11 +854,10 @@ do_server(int argc, char *argv[])
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
cert_signer_algo = get_cert_signer_algo(chain);
|
cert_signer_algo = get_cert_signer_algo(chain);
|
||||||
if (cert_signer_algo < 0) {
|
if (cert_signer_algo == 0) {
|
||||||
fprintf(stderr, "ERROR: server certificate cannot be"
|
|
||||||
" decoded (err=%d)\n", -cert_signer_algo);
|
|
||||||
goto server_exit_error;
|
goto server_exit_error;
|
||||||
} else if (verbose) {
|
}
|
||||||
|
if (verbose) {
|
||||||
const char *csas;
|
const char *csas;
|
||||||
|
|
||||||
switch (cert_signer_algo) {
|
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);
|
br_ssl_engine_set_suites(&cc.eng, suite_ids, num_suites);
|
||||||
|
|
||||||
|
dnhash = NULL;
|
||||||
for (u = 0; hash_functions[u].name; u ++) {
|
for (u = 0; hash_functions[u].name; u ++) {
|
||||||
const br_hash_class *hc;
|
const br_hash_class *hc;
|
||||||
int id;
|
int id;
|
||||||
|
|
@ -987,6 +969,7 @@ do_server(int argc, char *argv[])
|
||||||
hc = hash_functions[u].hclass;
|
hc = hash_functions[u].hclass;
|
||||||
id = (hc->desc >> BR_HASHDESC_ID_OFF) & BR_HASHDESC_ID_MASK;
|
id = (hc->desc >> BR_HASHDESC_ID_OFF) & BR_HASHDESC_ID_MASK;
|
||||||
if ((hfuns & ((unsigned)1 << id)) != 0) {
|
if ((hfuns & ((unsigned)1 << id)) != 0) {
|
||||||
|
dnhash = hc;
|
||||||
br_ssl_engine_set_hash(&cc.eng, id, 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_session_cache_lru_init(&lru, cache, cache_len);
|
||||||
br_ssl_server_set_cache(&cc, &lru.vtable);
|
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.vtable = &policy_vtable;
|
||||||
pc.verbose = verbose;
|
pc.verbose = verbose;
|
||||||
pc.chain = chain;
|
pc.chain = chain;
|
||||||
|
|
@ -1015,6 +1003,36 @@ do_server(int argc, char *argv[])
|
||||||
pc.sk = sk;
|
pc.sk = sk;
|
||||||
br_ssl_server_set_policy(&cc, &pc.vtable);
|
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);
|
br_ssl_engine_set_buffer(&cc.eng, iobuf, iobuf_len, bidi);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -1061,13 +1079,9 @@ do_server(int argc, char *argv[])
|
||||||
server_exit:
|
server_exit:
|
||||||
xfree(suites);
|
xfree(suites);
|
||||||
xfree(suite_ids);
|
xfree(suite_ids);
|
||||||
if (chain != NULL) {
|
free_certificates(chain, chain_len);
|
||||||
for (u = 0; u < chain_len; u ++) {
|
|
||||||
xfree(chain[u].data);
|
|
||||||
}
|
|
||||||
xfree(chain);
|
|
||||||
}
|
|
||||||
free_private_key(sk);
|
free_private_key(sk);
|
||||||
|
VEC_CLEAREXT(anchors, &free_ta_contents);
|
||||||
xfree(iobuf);
|
xfree(iobuf);
|
||||||
xfree(cache);
|
xfree(cache);
|
||||||
if (fd >= 0) {
|
if (fd >= 0) {
|
||||||
|
|
|
||||||
|
|
@ -93,7 +93,7 @@ print_ta_internals(br_x509_trust_anchor *ta, long ctr)
|
||||||
char tmp[25];
|
char tmp[25];
|
||||||
|
|
||||||
sprintf(tmp, "TA%ld_DN", ctr);
|
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) {
|
switch (ta->pkey.key_type) {
|
||||||
case BR_KEYTYPE_RSA:
|
case BR_KEYTYPE_RSA:
|
||||||
sprintf(tmp, "TA%ld_RSA_N", ctr);
|
sprintf(tmp, "TA%ld_RSA_N", ctr);
|
||||||
|
|
@ -119,7 +119,8 @@ print_ta(br_x509_trust_anchor *ta, long ctr)
|
||||||
char tmp[25];
|
char tmp[25];
|
||||||
|
|
||||||
printf("\t{\n");
|
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)
|
printf("\t\t%s,\n", (ta->flags & BR_X509_TA_CA)
|
||||||
? "BR_X509_TA_CA" : "0");
|
? "BR_X509_TA_CA" : "0");
|
||||||
printf("\t\t{\n");
|
printf("\t\t{\n");
|
||||||
|
|
|
||||||
|
|
@ -181,9 +181,11 @@ do_verify(int argc, char *argv[])
|
||||||
cert_list chain = VEC_INIT;
|
cert_list chain = VEC_INIT;
|
||||||
size_t u;
|
size_t u;
|
||||||
br_x509_minimal_context mc;
|
br_x509_minimal_context mc;
|
||||||
int err_keyx, err_sign;
|
int err;
|
||||||
int print_text, print_C;
|
int print_text, print_C;
|
||||||
br_x509_pkey *pk;
|
br_x509_pkey *pk;
|
||||||
|
const br_x509_pkey *tpk;
|
||||||
|
unsigned usages;
|
||||||
|
|
||||||
retcode = 0;
|
retcode = 0;
|
||||||
verbose = 1;
|
verbose = 1;
|
||||||
|
|
@ -191,8 +193,6 @@ do_verify(int argc, char *argv[])
|
||||||
print_text = 0;
|
print_text = 0;
|
||||||
print_C = 0;
|
print_C = 0;
|
||||||
pk = NULL;
|
pk = NULL;
|
||||||
err_keyx = 0;
|
|
||||||
err_sign = 0;
|
|
||||||
for (i = 0; i < argc; i ++) {
|
for (i = 0; i < argc; i ++) {
|
||||||
const char *arg;
|
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_rsa(&mc, &br_rsa_i31_pkcs1_vrfy);
|
||||||
br_x509_minimal_set_ecdsa(&mc,
|
br_x509_minimal_set_ecdsa(&mc,
|
||||||
&br_ec_prime_i31, &br_ecdsa_i31_vrfy_asn1);
|
&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,
|
mc.vtable->start_chain(&mc.vtable, sni);
|
||||||
i == 0 ? BR_KEYTYPE_KEYX : BR_KEYTYPE_SIGN, sni);
|
|
||||||
for (u = 0; u < VEC_LEN(chain); u ++) {
|
for (u = 0; u < VEC_LEN(chain); u ++) {
|
||||||
br_x509_certificate *xc;
|
br_x509_certificate *xc;
|
||||||
|
|
||||||
|
|
@ -281,40 +277,33 @@ do_verify(int argc, char *argv[])
|
||||||
mc.vtable->end_cert(&mc.vtable);
|
mc.vtable->end_cert(&mc.vtable);
|
||||||
}
|
}
|
||||||
err = mc.vtable->end_chain(&mc.vtable);
|
err = mc.vtable->end_chain(&mc.vtable);
|
||||||
if (i == 0) {
|
tpk = mc.vtable->get_pkey(&mc.vtable, &usages);
|
||||||
err_keyx = err;
|
if (tpk != NULL) {
|
||||||
} else {
|
|
||||||
err_sign = err;
|
|
||||||
}
|
|
||||||
tpk = mc.vtable->get_pkey(&mc.vtable);
|
|
||||||
if (pk == NULL && tpk != NULL) {
|
|
||||||
pk = xpkeydup(tpk);
|
pk = xpkeydup(tpk);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (err_keyx == 0 || err_sign == 0) {
|
if (err == 0) {
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
fprintf(stderr, "Validation success");
|
int hkx;
|
||||||
if (err_keyx == 0 && err_sign == 0) {
|
|
||||||
fprintf(stderr, " (key exchange, sign)\n");
|
fprintf(stderr, "Validation success; usages:");
|
||||||
} else if (err_keyx == 0) {
|
hkx = 0;
|
||||||
fprintf(stderr, " (key exchange)\n");
|
if (usages & BR_KEYTYPE_KEYX) {
|
||||||
} else if (err_sign == 0) {
|
fprintf(stderr, " key exchange");
|
||||||
fprintf(stderr, " (signature)\n");
|
hkx = 1;
|
||||||
}
|
}
|
||||||
|
if (usages & BR_KEYTYPE_SIGN) {
|
||||||
|
if (hkx) {
|
||||||
|
fprintf(stderr, ",");
|
||||||
|
}
|
||||||
|
fprintf(stderr, " signature");
|
||||||
|
}
|
||||||
|
fprintf(stderr, "\n");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
int err;
|
|
||||||
const char *errname, *errmsg;
|
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);
|
fprintf(stderr, "Validation failed, err = %d", err);
|
||||||
errname = find_error_name(err, &errmsg);
|
errname = find_error_name(err, &errmsg);
|
||||||
if (errname != NULL) {
|
if (errname != NULL) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue