From e61ad42191511226309bad2cbde8cd9e8cc743cb Mon Sep 17 00:00:00 2001 From: Thomas Pornin Date: Sat, 10 Dec 2016 17:35:06 +0100 Subject: [PATCH] Added support for client certificates (both client-side and server-side, but still missing an API for extracting the client identity from the certificate). --- Makefile | 16 +- inc/bearssl_ssl.h | 682 +++++++++- inc/bearssl_x509.h | 72 +- src/ssl/ssl_ccert_single_ec.c | 150 +++ src/ssl/ssl_ccert_single_rsa.c | 149 +++ src/ssl/ssl_client_full.c | 4 +- src/ssl/ssl_hs_client.c | 1046 +++++++++------ src/ssl/ssl_hs_client.t0 | 400 ++++-- src/ssl/ssl_hs_common.t0 | 201 ++- src/ssl/ssl_hs_server.c | 1127 +++++++++++------ src/ssl/ssl_hs_server.t0 | 551 ++++++-- ...{ssl_single_ec.c => ssl_scert_single_ec.c} | 2 +- ...sl_single_rsa.c => ssl_scert_single_rsa.c} | 0 src/x509/x509_knownkey.c | 20 +- src/x509/x509_minimal.c | 551 ++++---- src/x509/x509_minimal.t0 | 62 +- test/test_x509.c | 25 +- tools/brssl.h | 31 + tools/certs.c | 37 +- tools/client.c | 396 +++++- tools/errors.c | 13 +- tools/files.c | 12 + tools/keys.c | 61 + tools/names.c | 17 + tools/server.c | 216 ++-- tools/ta.c | 5 +- tools/verify.c | 73 +- 27 files changed, 4439 insertions(+), 1480 deletions(-) create mode 100644 src/ssl/ssl_ccert_single_ec.c create mode 100644 src/ssl/ssl_ccert_single_rsa.c rename src/ssl/{ssl_single_ec.c => ssl_scert_single_ec.c} (99%) rename src/ssl/{ssl_single_rsa.c => ssl_scert_single_rsa.c} (100%) diff --git a/Makefile b/Makefile index 5eabd31..57a0867 100644 --- a/Makefile +++ b/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 OBJRAND = $(BUILD)/hmac_drbg.o OBJRSA = $(BUILD)/rsa_i31_pkcs1_sign.o $(BUILD)/rsa_i31_pkcs1_vrfy.o $(BUILD)/rsa_i31_priv.o $(BUILD)/rsa_i31_pub.o $(BUILD)/rsa_i32_pkcs1_sign.o $(BUILD)/rsa_i32_pkcs1_vrfy.o $(BUILD)/rsa_i32_priv.o $(BUILD)/rsa_i32_pub.o $(BUILD)/rsa_ssl_decrypt.o -OBJSSL = $(BUILD)/prf.o $(BUILD)/prf_md5sha1.o $(BUILD)/prf_sha256.o $(BUILD)/prf_sha384.o $(BUILD)/ssl_client.o $(BUILD)/ssl_client_full.o $(BUILD)/ssl_engine.o $(BUILD)/ssl_hashes.o $(BUILD)/ssl_hs_client.o $(BUILD)/ssl_hs_server.o $(BUILD)/ssl_io.o $(BUILD)/ssl_lru.o $(BUILD)/ssl_rec_cbc.o $(BUILD)/ssl_rec_gcm.o $(BUILD)/ssl_server.o $(BUILD)/ssl_server_mine2g.o $(BUILD)/ssl_server_minf2g.o $(BUILD)/ssl_server_minr2g.o $(BUILD)/ssl_server_minu2g.o $(BUILD)/ssl_server_minv2g.o $(BUILD)/ssl_server_full_ec.o $(BUILD)/ssl_server_full_rsa.o $(BUILD)/ssl_single_ec.o $(BUILD)/ssl_single_rsa.o +OBJSSL = $(BUILD)/prf.o $(BUILD)/prf_md5sha1.o $(BUILD)/prf_sha256.o $(BUILD)/prf_sha384.o $(BUILD)/ssl_ccert_single_ec.o $(BUILD)/ssl_ccert_single_rsa.o $(BUILD)/ssl_client.o $(BUILD)/ssl_client_full.o $(BUILD)/ssl_engine.o $(BUILD)/ssl_hashes.o $(BUILD)/ssl_hs_client.o $(BUILD)/ssl_hs_server.o $(BUILD)/ssl_io.o $(BUILD)/ssl_lru.o $(BUILD)/ssl_rec_cbc.o $(BUILD)/ssl_rec_gcm.o $(BUILD)/ssl_server.o $(BUILD)/ssl_server_mine2g.o $(BUILD)/ssl_server_minf2g.o $(BUILD)/ssl_server_minr2g.o $(BUILD)/ssl_server_minu2g.o $(BUILD)/ssl_server_minv2g.o $(BUILD)/ssl_server_full_ec.o $(BUILD)/ssl_server_full_rsa.o $(BUILD)/ssl_scert_single_ec.o $(BUILD)/ssl_scert_single_rsa.o OBJSYMCIPHER = $(BUILD)/aes_big_cbcdec.o $(BUILD)/aes_big_cbcenc.o $(BUILD)/aes_big_ctr.o $(BUILD)/aes_big_dec.o $(BUILD)/aes_big_enc.o $(BUILD)/aes_common.o $(BUILD)/aes_ct.o $(BUILD)/aes_ct64.o $(BUILD)/aes_ct64_cbcdec.o $(BUILD)/aes_ct64_cbcenc.o $(BUILD)/aes_ct64_ctr.o $(BUILD)/aes_ct64_dec.o $(BUILD)/aes_ct64_enc.o $(BUILD)/aes_ct_cbcdec.o $(BUILD)/aes_ct_cbcenc.o $(BUILD)/aes_ct_ctr.o $(BUILD)/aes_ct_dec.o $(BUILD)/aes_ct_enc.o $(BUILD)/aes_small_cbcdec.o $(BUILD)/aes_small_cbcenc.o $(BUILD)/aes_small_ctr.o $(BUILD)/aes_small_dec.o $(BUILD)/aes_small_enc.o $(BUILD)/des_ct.o $(BUILD)/des_ct_cbcdec.o $(BUILD)/des_ct_cbcenc.o $(BUILD)/des_support.o $(BUILD)/des_tab.o $(BUILD)/des_tab_cbcdec.o $(BUILD)/des_tab_cbcenc.o OBJX509 = $(BUILD)/skey_decoder.o $(BUILD)/x509_decoder.o $(BUILD)/x509_knownkey.o $(BUILD)/x509_minimal.o OBJ = $(OBJCODEC) $(OBJEC) $(OBJHASH) $(OBJINT31) $(OBJINT32) $(OBJMAC) $(OBJRAND) $(OBJRSA) $(OBJSSL) $(OBJSYMCIPHER) $(OBJX509) @@ -386,6 +386,12 @@ $(BUILD)/prf_sha256.o: src/ssl/prf_sha256.c $(HEADERS) $(BUILD)/prf_sha384.o: src/ssl/prf_sha384.c $(HEADERS) $(CC) $(CFLAGS) -c -o $(BUILD)/prf_sha384.o src/ssl/prf_sha384.c +$(BUILD)/ssl_ccert_single_ec.o: src/ssl/ssl_ccert_single_ec.c $(HEADERS) + $(CC) $(CFLAGS) -c -o $(BUILD)/ssl_ccert_single_ec.o src/ssl/ssl_ccert_single_ec.c + +$(BUILD)/ssl_ccert_single_rsa.o: src/ssl/ssl_ccert_single_rsa.c $(HEADERS) + $(CC) $(CFLAGS) -c -o $(BUILD)/ssl_ccert_single_rsa.o src/ssl/ssl_ccert_single_rsa.c + $(BUILD)/ssl_client.o: src/ssl/ssl_client.c $(HEADERS) $(CC) $(CFLAGS) -c -o $(BUILD)/ssl_client.o src/ssl/ssl_client.c @@ -440,11 +446,11 @@ $(BUILD)/ssl_server_full_ec.o: src/ssl/ssl_server_full_ec.c $(HEADERS) $(BUILD)/ssl_server_full_rsa.o: src/ssl/ssl_server_full_rsa.c $(HEADERS) $(CC) $(CFLAGS) -c -o $(BUILD)/ssl_server_full_rsa.o src/ssl/ssl_server_full_rsa.c -$(BUILD)/ssl_single_ec.o: src/ssl/ssl_single_ec.c $(HEADERS) - $(CC) $(CFLAGS) -c -o $(BUILD)/ssl_single_ec.o src/ssl/ssl_single_ec.c +$(BUILD)/ssl_scert_single_ec.o: src/ssl/ssl_scert_single_ec.c $(HEADERS) + $(CC) $(CFLAGS) -c -o $(BUILD)/ssl_scert_single_ec.o src/ssl/ssl_scert_single_ec.c -$(BUILD)/ssl_single_rsa.o: src/ssl/ssl_single_rsa.c $(HEADERS) - $(CC) $(CFLAGS) -c -o $(BUILD)/ssl_single_rsa.o src/ssl/ssl_single_rsa.c +$(BUILD)/ssl_scert_single_rsa.o: src/ssl/ssl_scert_single_rsa.c $(HEADERS) + $(CC) $(CFLAGS) -c -o $(BUILD)/ssl_scert_single_rsa.o src/ssl/ssl_scert_single_rsa.c $(BUILD)/aes_big_cbcdec.o: src/symcipher/aes_big_cbcdec.c $(HEADERS) $(CC) $(CFLAGS) -c -o $(BUILD)/aes_big_cbcdec.o src/symcipher/aes_big_cbcdec.c diff --git a/inc/bearssl_ssl.h b/inc/bearssl_ssl.h index 463e616..b038500 100644 --- a/inc/bearssl_ssl.h +++ b/inc/bearssl_ssl.h @@ -191,9 +191,18 @@ signature algorithm, hash function). */ #define BR_ERR_INVALID_ALGORITHM 26 -/** \brief SSL status: invalid signature on ServerKeyExchange message. */ +/** \brief SSL status: invalid signature (on ServerKeyExchange from + server, or in CertificateVerify from client). */ #define BR_ERR_BAD_SIGNATURE 27 +/** \brief SSL status: peer's public key does not have the proper type + or is not allowed for requested operation. */ +#define BR_ERR_WRONG_KEY_USAGE 28 + +/** \brief SSL status: client did not send a certificate upon request, + or the client certificate could not be validated. */ +#define BR_ERR_NO_CLIENT_AUTH 29 + /** \brief SSL status: I/O error or premature close on underlying transport stream. This error code is set only by the simplified I/O API ("br_sslio_*"). */ @@ -769,12 +778,11 @@ typedef struct { uint32_t flags; /* - * Context variables for the handshake processor. - * The 'pad' must be large enough to accommodate an - * RSA-encrypted pre-master secret, or a RSA signature on - * key exchange parameters; since we want to support up to - * RSA-4096, this means at least 512 bytes. - * (Other pad usages require its length to be at least 256.) + * Context variables for the handshake processor. The 'pad' must + * be large enough to accommodate an RSA-encrypted pre-master + * secret, or an RSA signature; since we want to support up to + * RSA-4096, this means at least 512 bytes. (Other pad usages + * require its length to be at least 256.) */ struct { uint32_t *dp; @@ -825,6 +833,16 @@ typedef struct { */ const br_x509_class **x509ctx; + /* + * Certificate chain to send. This is used by both client and + * server, when they send their respective Certificate messages. + * If chain_len is 0, then chain may be NULL. + */ + const br_x509_certificate *chain; + size_t chain_len; + const unsigned char *cert_cur; + size_t cert_len; + /* * Pointers to implementations; left to NULL for unsupported * functions. For the raw hash functions, implementations are @@ -844,6 +862,8 @@ typedef struct { const br_sslrec_in_gcm_class *igcm_in; const br_sslrec_out_gcm_class *igcm_out; const br_ec_impl *iec; + br_rsa_pkcs1_vrfy irsavrfy; + br_ecdsa_vrfy iecdsa; #endif } br_ssl_engine_context; @@ -909,7 +929,7 @@ br_ssl_engine_remove_flags(br_ssl_engine_context *cc, uint32_t flags) */ #define BR_OPT_ENFORCE_SERVER_PREFERENCES ((uint32_t)1 << 0) -/* +/** * \brief Behavioural flag: disable renegotiation. * * If this flag is set, then renegotiations are rejected unconditionally: @@ -918,6 +938,26 @@ br_ssl_engine_remove_flags(br_ssl_engine_context *cc, uint32_t flags) */ #define BR_OPT_NO_RENEGOTIATION ((uint32_t)1 << 1) +/** + * \brief Behavioural flag: tolerate lack of client authentication. + * + * If this flag is set in a server and the server requests a client + * certificate, but the authentication fails (the client does not send + * a certificate, or the client's certificate chain cannot be validated), + * then the connection keeps on. Without this flag, a failed client + * authentication terminates the connection. + * + * Notes: + * + * - If the client's certificate can be validated and its public key is + * supported, then a wrong signature value terminates the connection + * regardless of that flag. + * + * - If using full-static ECDH, then a failure to validate the client's + * certificate prevents the handshake from succeeding. + */ +#define BR_OPT_TOLERATE_NO_CLIENT_AUTH ((uint32_t)1 << 2) + /** * \brief Set the minimum and maximum supported protocol versions. * @@ -1157,6 +1197,44 @@ br_ssl_engine_set_ec(br_ssl_engine_context *cc, const br_ec_impl *iec) cc->iec = iec; } +/** + * \brief Set the RSA signature verification implementation. + * + * On the client, this is used to verify the server's signature on its + * ServerKeyExchange message (for ECDHE_RSA cipher suites). On the server, + * this is used to verify the client's CertificateVerify message (if a + * client certificate is requested, and that certificate contains a RSA key). + * + * \param cc SSL engine context. + * \param irsavrfy RSA signature verification implementation. + */ +static inline void +br_ssl_engine_set_rsavrfy(br_ssl_engine_context *cc, br_rsa_pkcs1_vrfy irsavrfy) +{ + cc->irsavrfy = irsavrfy; +} + +/* + * \brief Set the ECDSA implementation (signature verification). + * + * On the client, this is used to verify the server's signature on its + * ServerKeyExchange message (for ECDHE_ECDSA cipher suites). On the server, + * this is used to verify the client's CertificateVerify message (if a + * client certificate is requested, that certificate contains an EC key, + * and full-static ECDH is not used). + * + * The ECDSA implementation will use the EC core implementation configured + * in the engine context. + * + * \param cc client context. + * \param iecdsa ECDSA verification implementation. + */ +static inline void +br_ssl_engine_set_ecdsa(br_ssl_engine_context *cc, br_ecdsa_vrfy iecdsa) +{ + cc->iecdsa = iecdsa; +} + /** * \brief Set the I/O buffer for the SSL engine. * @@ -1597,6 +1675,326 @@ void br_ssl_engine_close(br_ssl_engine_context *cc); */ int br_ssl_engine_renegotiate(br_ssl_engine_context *cc); +/* + * Pre-declaration for the SSL client context. + */ +typedef struct br_ssl_client_context_ br_ssl_client_context; + +/** + * \brief Type for the client certificate, if requested by the server. + */ +typedef struct { + /** + * \brief Authentication type. + * + * This is either `BR_AUTH_RSA` (RSA signature), `BR_AUTH_ECDSA` + * (ECDSA signature), or `BR_AUTH_ECDH` (static ECDH key exchange). + */ + int auth_type; + + /** + * \brief Hash function for computing the CertificateVerify. + * + * This is the symbolic identifier for the hash function that + * will be used to produce the hash of handshake messages, to + * be signed into the CertificateVerify. For full static ECDH + * (client and server certificates are both EC in the same + * curve, and static ECDH is used), this value is set to -1. + * + * Take care that with TLS 1.0 and 1.1, that value MUST match + * the protocol requirements: value must be 0 (MD5+SHA-1) for + * a RSA signature, or 2 (SHA-1) for an ECDSA signature. Only + * TLS 1.2 allows for other hash functions. + */ + int hash_id; + + /** + * \brief Certificate chain to send to the server. + * + * This is an array of `br_x509_certificate` objects, each + * normally containing a DER-encoded certificate. The client + * code does not try to decode these elements. If there is no + * chain to send to the server, then this pointer shall be + * set to `NULL`. + */ + const br_x509_certificate *chain; + + /** + * \brief Certificate chain length (number of certificates). + * + * If there is no chain to send to the server, then this value + * shall be set to 0. + */ + size_t chain_len; + +} br_ssl_client_certificate; + +/* + * Note: the constants below for signatures match the TLS constants. + */ + +/** \brief Client authentication type: static ECDH. */ +#define BR_AUTH_ECDH 0 +/** \brief Client authentication type: RSA signature. */ +#define BR_AUTH_RSA 1 +/** \brief Client authentication type: ECDSA signature. */ +#define BR_AUTH_ECDSA 3 + +/** + * \brief Class type for a certificate handler (client side). + * + * A certificate handler selects a client certificate chain to send to + * the server, upon explicit request from that server. It receives + * the list of trust anchor DN from the server, and supported types + * of certificates and signatures, and returns the chain to use. It + * is also invoked to perform the corresponding private key operation + * (a signature, or an ECDH computation). + * + * The SSL client engine will first push the trust anchor DN with + * `start_name_list()`, `start_name()`, `append_name()`, `end_name()` + * and `end_name_list()`. Then it will call `choose()`, to select the + * actual chain (and signature/hash algorithms). Finally, it will call + * either `do_sign()` or `do_keyx()`, depending on the algorithm choices. + */ +typedef struct br_ssl_client_certificate_class_ br_ssl_client_certificate_class; +struct br_ssl_client_certificate_class_ { + /** + * \brief Context size (in bytes). + */ + size_t context_size; + + /** + * \brief Begin reception of a list of trust anchor names. This + * is called while parsing the incoming CertificateRequest. + * + * \param pctx certificate handler context. + */ + void (*start_name_list)(const br_ssl_client_certificate_class **pctx); + + /** + * \brief Begin reception of a new trust anchor name. + * + * The total encoded name length is provided; it is less than + * 65535 bytes. + * + * \param pctx certificate handler context. + * \param len encoded name length (in bytes). + */ + void (*start_name)(const br_ssl_client_certificate_class **pctx, + size_t len); + + /** + * \brief Receive some more bytes for the current trust anchor name. + * + * The provided reference (`data`) points to a transient buffer + * they may be reused as soon as this function returns. The chunk + * length (`len`) is never zero. + * + * \param pctx certificate handler context. + * \param data anchor name chunk. + * \param len anchor name chunk length (in bytes). + */ + void (*append_name)(const br_ssl_client_certificate_class **pctx, + const unsigned char *data, size_t len); + + /** + * \brief End current trust anchor name. + * + * This function is called when all the encoded anchor name data + * has been provided. + * + * \param pctx certificate handler context. + */ + void (*end_name)(const br_ssl_client_certificate_class **pctx); + + /** + * \brief End list of trust anchor names. + * + * This function is called when all the anchor names in the + * CertificateRequest message have been obtained. + * + * \param pctx certificate handler context. + */ + void (*end_name_list)(const br_ssl_client_certificate_class **pctx); + + /** + * \brief Select client certificate and algorithms. + * + * This callback function shall fill the provided `choices` + * structure with the selected algorithms and certificate chain. + * The `hash_id`, `chain` and `chain_len` fields must be set. If + * the client cannot or does not wish to send a certificate, + * then it shall set `chain` to `NULL` and `chain_len` to 0. + * + * The `auth_types` parameter describes the authentication types, + * signature algorithms and hash functions that are supported by + * both the client context and the server, and compatible with + * the current protocol version. This is a bit field with the + * following contents: + * + * - If RSA signatures with hash function x are supported, then + * bit x is set. + * + * - If ECDSA signatures with hash function x are supported, + * then bit 8+x is set. + * + * - If static ECDH is supported, with a RSA-signed certificate, + * then bit 16 is set. + * + * - If static ECDH is supported, with an ECDSA-signed certificate, + * then bit 17 is set. + * + * Notes: + * + * - When using TLS 1.0 or 1.1, the hash function for RSA + * signatures is always the special MD5+SHA-1 (id 0), and the + * hash function for ECDSA signatures is always SHA-1 (id 2). + * + * - When using TLS 1.2, the list of hash functions is trimmed + * down to include only hash functions that the client context + * can support. The actual server list can be obtained with + * `br_ssl_client_get_server_hashes()`; that list may be used + * to select the certificate chain to send to the server. + * + * \param pctx certificate handler context. + * \param cc SSL client context. + * \param auth_types supported authentication types and algorithms. + * \param choices destination structure for the policy choices. + */ + void (*choose)(const br_ssl_client_certificate_class **pctx, + const br_ssl_client_context *cc, uint32_t auth_types, + br_ssl_client_certificate *choices); + + /** + * \brief Perform key exchange (client part). + * + * This callback is invoked in case of a full static ECDH key + * exchange: + * + * - the cipher suite uses `ECDH_RSA` or `ECDH_ECDSA`; + * + * - the server requests a client certificate; + * + * - the client has, and sends, a client certificate that + * uses an EC key in the same curve as the server's key, + * and chooses static ECDH (the `hash_id` field in the choice + * structure was set to -1). + * + * In that situation, this callback is invoked to compute the + * client-side ECDH: the provided `data` (of length `len` bytes) + * is the server's public key point (as decoded from its + * certificate), and the client shall multiply that point with + * its own private key, and write back the X coordinate of the + * resulting point in the same buffer, starting at offset 1 + * (therefore, writing back the complete encoded point works). + * + * The callback must uphold the following: + * + * - If the input array does not have the proper length for + * an encoded curve point, then an error (0) shall be reported. + * + * - If the input array has the proper length, then processing + * MUST be constant-time, even if the data is not a valid + * encoded point. + * + * - This callback MUST check that the input point is valid. + * + * Returned value is 1 on success, 0 on error. + * + * \param pctx certificate handler context. + * \param data server public key point. + * \param len server public key point length (in bytes). + * \return 1 on success, 0 on error. + */ + uint32_t (*do_keyx)(const br_ssl_client_certificate_class **pctx, + unsigned char *data, size_t len); + + /** + * \brief Perform a signature (client authentication). + * + * This callback is invoked when a client certificate was sent, + * and static ECDH is not used. It shall compute a signature, + * using the client's private key, over the provided hash value + * (which is the hash of all previous handshake messages). + * + * On input, the hash value to sign is in `data`, of size + * `hv_len`; the involved hash function is identified by + * `hash_id`. The signature shall be computed and written + * back into `data`; the total size of that buffer is `len` + * bytes. + * + * This callback shall verify that the signature length does not + * exceed `len` bytes, and abstain from writing the signature if + * it does not fit. + * + * For RSA signatures, the `hash_id` may be 0, in which case + * this is the special header-less signature specified in TLS 1.0 + * and 1.1, with a 36-byte hash value. Otherwise, normal PKCS#1 + * v1.5 signatures shall be computed. + * + * For ECDSA signatures, the signature value shall use the ASN.1 + * based encoding. + * + * Returned value is the signature length (in bytes), or 0 on error. + * + * \param pctx certificate handler context. + * \param hash_id hash function identifier. + * \param hv_len hash value length (in bytes). + * \param data input/output buffer (hash value, then signature). + * \param len total buffer length (in bytes). + * \return signature length (in bytes) on success, or 0 on error. + */ + size_t (*do_sign)(const br_ssl_client_certificate_class **pctx, + int hash_id, size_t hv_len, unsigned char *data, size_t len); +}; + +/** + * \brief A single-chain RSA client certificate handler. + * + * This handler uses a single certificate chain, with a RSA + * signature. The list of trust anchor DN is ignored. + * + * Apart from the first field (vtable pointer), its contents are + * opaque and shall not be accessed directly. + */ +typedef struct { + /** \brief Pointer to vtable. */ + const br_ssl_client_certificate_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + const br_x509_certificate *chain; + size_t chain_len; + const br_rsa_private_key *sk; + br_rsa_pkcs1_sign irsasign; +#endif +} br_ssl_client_certificate_rsa_context; + +/** + * \brief A single-chain EC client certificate handler. + * + * This handler uses a single certificate chain, with a RSA + * signature. The list of trust anchor DN is ignored. + * + * This handler may support both static ECDH, and ECDSA signatures + * (either usage may be selectively disabled). + * + * Apart from the first field (vtable pointer), its contents are + * opaque and shall not be accessed directly. + */ +typedef struct { + /** \brief Pointer to vtable. */ + const br_ssl_client_certificate_class *vtable; +#ifndef BR_DOXYGEN_IGNORE + const br_x509_certificate *chain; + size_t chain_len; + const br_ec_private_key *sk; + unsigned allowed_usages; + unsigned issuer_key_type; + const br_multihash_context *mhash; + const br_ec_impl *iec; + br_ecdsa_sign iecdsa; +#endif +} br_ssl_client_certificate_ec_context; + /** * \brief Context structure for a SSL client. * @@ -1605,7 +2003,7 @@ int br_ssl_engine_renegotiate(br_ssl_engine_context *cc); * a pointer to that field. The other structure fields are opaque and * must not be accessed directly. */ -typedef struct { +struct br_ssl_client_context_ { /** * \brief The encapsulated engine context. */ @@ -1620,14 +2018,82 @@ typedef struct { */ uint16_t min_clienthello_len; + /* + * Bit field for algoithms (hash + signature) supported by the + * server when requesting a client certificate. + */ + uint16_t hashes; + + /* + * Server's public key curve. + */ + int server_curve; + + /* + * Context for certificate handler. + */ + const br_ssl_client_certificate_class **client_auth_vtable; + + /* + * Client authentication type. + */ + unsigned char auth_type; + + /* + * Hash function to use for the client signature. This is 0xFF + * if static ECDH is used. + */ + unsigned char hash_id; + + /* + * For the core certificate handlers, thus avoiding (in most + * cases) the need for an externally provided policy context. + */ + union { + const br_ssl_client_certificate_class *vtable; + br_ssl_client_certificate_rsa_context single_rsa; + br_ssl_client_certificate_ec_context single_ec; + } client_auth; + /* * Implementations. */ br_rsa_public irsapub; - br_rsa_pkcs1_vrfy irsavrfy; - br_ecdsa_vrfy iecdsa; #endif -} br_ssl_client_context; +}; + +/** + * \brief Get the hash functions and signature algorithms supported by + * the server. + * + * This is a field of bits: for hash function of ID x, bit x is set if + * the hash function is supported in RSA signatures, 8+x if it is supported + * with ECDSA. This information is conveyed by the server when requesting + * a client certificate. + * + * \param cc client context. + * \return the server-supported hash functions (for signatures). + */ +static inline uint16_t +br_ssl_client_get_server_hashes(const br_ssl_client_context *cc) +{ + return cc->hashes; +} + +/** + * \brief Get the server key curve. + * + * This function returns the ID for the curve used by the server's public + * key. This is set when the server's certificate chain is processed; + * this value is 0 if the server's key is not an EC key. + * + * \return the server's public key curve ID, or 0. + */ +static inline int +br_ssl_client_get_server_curve(const br_ssl_client_context *cc) +{ + return cc->server_curve; +} /* * Each br_ssl_client_init_xxx() function sets the list of supported @@ -1668,48 +2134,34 @@ void br_ssl_client_init_full(br_ssl_client_context *cc, void br_ssl_client_zero(br_ssl_client_context *cc); /** - * \brief Set the RSA public-key operations implementation. + * \brief Set an externally provided client certificate handler context. * - * This will be used to encrypt the pre-master secret with the server's - * RSA public key (RSA-encryption cipher suites only). + * The handler's methods are invoked when the server requests a client + * certificate. * - * \param cc client context. - * \param irsapub RSA public-key encryption implementation. + * \param cc client context. + * \param pctx certificate handler context (pointer to its vtable field). */ static inline void -br_ssl_client_set_rsapub(br_ssl_client_context *cc, br_rsa_public irsapub) +br_ssl_client_set_client_certificate(br_ssl_client_context *cc, + const br_ssl_client_certificate_class **pctx) { - cc->irsapub = irsapub; + cc->client_auth_vtable = pctx; } /** - * \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). + * \brief Set the RSA public-key operations implementation. * - * The ECDSA implementation will use the EC core implementation configured - * in the engine context. + * This will be used to encrypt the pre-master secret with the server's + * RSA public key (RSA-encryption cipher suites only). * - * \param cc client context. - * \param iecdsa ECDSA verification implementation. + * \param cc client context. + * \param irsapub RSA public-key encryption implementation. */ static inline void -br_ssl_client_set_ecdsa(br_ssl_client_context *cc, br_ecdsa_vrfy iecdsa) +br_ssl_client_set_rsapub(br_ssl_client_context *cc, br_rsa_public irsapub) { - cc->iecdsa = iecdsa; + cc->irsapub = irsapub; } /** @@ -1783,6 +2235,73 @@ br_ssl_client_forget_session(br_ssl_client_context *cc) cc->eng.session.session_id_len = 0; } +/** + * \brief Set client certificate chain and key (single RSA case). + * + * This function sets a client certificate chain, that the client will + * send to the server whenever a client certificate is requested. This + * certificate uses an RSA public key; the corresponding private key is + * invoked for authentication. Trust anchor names sent by the server are + * ignored. + * + * The provided chain and private key are linked in the client context; + * they must remain valid as long as they may be used, i.e. normally + * for the duration of the connection, since they might be invoked + * again upon renegotiations. + * + * \param cc SSL client context. + * \param chain client certificate chain (SSL order: EE comes first). + * \param chain_len client chain length (number of certificates). + * \param sk client private key. + * \param irsasign RSA signature implementation (PKCS#1 v1.5). + */ +void br_ssl_client_set_single_rsa(br_ssl_client_context *cc, + const br_x509_certificate *chain, size_t chain_len, + const br_rsa_private_key *sk, br_rsa_pkcs1_sign irsasign); + +/* + * \brief Set the client certificate chain and key (single EC case). + * + * This function sets a client certificate chain, that the client will + * send to the server whenever a client certificate is requested. This + * certificate uses an EC public key; the corresponding private key is + * invoked for authentication. Trust anchor names sent by the server are + * ignored. + * + * The provided chain and private key are linked in the client context; + * they must remain valid as long as they may be used, i.e. normally + * for the duration of the connection, since they might be invoked + * again upon renegotiations. + * + * The `allowed_usages` is a combination of usages, namely + * `BR_KEYTYPE_KEYX` and/or `BR_KEYTYPE_SIGN`. The `BR_KEYTYPE_KEYX` + * value allows full static ECDH, while the `BR_KEYTYPE_SIGN` value + * allows ECDSA signatures. If ECDSA signatures are used, then an ECDSA + * signature implementation must be provided; otherwise, the `iecdsa` + * parameter may be 0. + * + * The `cert_issuer_key_type` value is either `BR_KEYTYPE_RSA` or + * `BR_KEYTYPE_EC`; it is the type of the public key used the the CA + * that issued (signed) the client certificate. That value is used with + * full static ECDH: support of the certificate by the server depends + * on how the certificate was signed. (Note: when using TLS 1.2, this + * parameter is ignored; but its value matters for TLS 1.0 and 1.1.) + * + * \param cc server context. + * \param chain server certificate chain to send. + * \param chain_len chain length (number of certificates). + * \param sk server private key (EC). + * \param allowed_usages allowed private key usages. + * \param cert_issuer_key_type issuing CA's key type. + * \param iec EC core implementation. + * \param iecdsa ECDSA signature implementation ("asn1" format). + */ +void br_ssl_client_set_single_ec(br_ssl_client_context *cc, + const br_x509_certificate *chain, size_t chain_len, + const br_ec_private_key *sk, unsigned allowed_usages, + unsigned cert_issuer_key_type, + const br_ec_impl *iec, br_ecdsa_sign iecdsa); + /** * \brief Type for a "translated cipher suite", as an array of two * 16-bit integers. @@ -1906,6 +2425,7 @@ typedef struct { * \brief Certificate chain length (number of certificates). */ size_t chain_len; + } br_ssl_server_choices; /** @@ -2244,10 +2764,6 @@ struct br_ssl_server_context_ { * Context for chain handler. */ const br_ssl_server_policy_class **policy_vtable; - const br_x509_certificate *chain; - size_t chain_len; - const unsigned char *cert_cur; - size_t cert_len; unsigned char sign_hash_id; /* @@ -2266,6 +2782,25 @@ struct br_ssl_server_context_ { unsigned char ecdhe_key[70]; size_t ecdhe_key_len; + /* + * Trust anchor names for client authentication. "ta_names" and + * "tas" cannot be both non-NULL. + */ + const br_x500_name *ta_names; + const br_x509_trust_anchor *tas; + size_t num_tas; + size_t cur_dn_index; + const unsigned char *cur_dn; + size_t cur_dn_len; + + /* + * Buffer for the hash value computed over all handshake messages + * prior to CertificateVerify, and identifier for the hash function. + */ + unsigned char hash_CV[64]; + size_t hash_CV_len; + int hash_CV_id; + /* * Server-specific implementations. * (none for now) @@ -2539,7 +3074,7 @@ void br_ssl_server_set_single_rsa(br_ssl_server_context *cc, const br_rsa_private_key *sk, unsigned allowed_usages, br_rsa_private irsacore, br_rsa_pkcs1_sign irsasign); -/* +/** * \brief Set the server certificate chain and key (single EC case). * * This function uses a policy context included in the server context. @@ -2569,6 +3104,61 @@ void br_ssl_server_set_single_ec(br_ssl_server_context *cc, unsigned cert_issuer_key_type, const br_ec_impl *iec, br_ecdsa_sign iecdsa); +/** + * \brief Activate client certificate authentication. + * + * The trust anchor encoded X.500 names (DN) to send to the client are + * provided. A client certificate will be requested and validated through + * the X.509 validator configured in the SSL engine. If `num` is 0, then + * client certificate authentication is disabled. + * + * If the client does not send a certificate, or on validation failure, + * the handshake aborts. Unauthenticated clients can be tolerated by + * setting the `BR_OPT_TOLERATE_NO_CLIENT_AUTH` flag. + * + * The provided array is linked in, not copied, so that pointer must + * remain valid as long as anchor names may be used. + * + * \param cc server context. + * \param ta_names encoded trust anchor names. + * \param num number of encoded trust anchor names. + */ +static inline void +br_ssl_server_set_trust_anchor_names(br_ssl_server_context *cc, + const br_x500_name *ta_names, size_t num) +{ + cc->ta_names = ta_names; + cc->tas = NULL; + cc->num_tas = num; +} + +/** + * \brief Activate client certificate authentication. + * + * This is a variant for `br_ssl_server_set_trust_anchor_names()`: the + * trust anchor names are provided not as an array of stand-alone names + * (`br_x500_name` structures), but as an array of trust anchors + * (`br_x509_trust_anchor` structures). The server engine itself will + * only use the `dn` field of each trust anchor. This is meant to allow + * defining a single array of trust anchors, to be used here and in the + * X.509 validation engine itself. + * + * The provided array is linked in, not copied, so that pointer must + * remain valid as long as anchor names may be used. + * + * \param cc server context. + * \param tas trust anchors (only names are used). + * \param num number of trust anchors. + */ +static inline void +br_ssl_server_set_trust_anchor_names_alt(br_ssl_server_context *cc, + const br_x509_trust_anchor *tas, size_t num) +{ + cc->ta_names = NULL; + cc->tas = tas; + cc->num_tas = num; +} + /** * \brief Configure the cache for session parameters. * diff --git a/inc/bearssl_x509.h b/inc/bearssl_x509.h index 84e73dc..c73b5b3 100644 --- a/inc/bearssl_x509.h +++ b/inc/bearssl_x509.h @@ -95,12 +95,12 @@ * include some limited processing for case-insensitive matching and * whitespace normalisation). * - * - When doing validation, a target public key type is provided. That - * type is the combination of a key algorithm (RSA or EC) and an - * intended key usage (key exchange or signature); in the context - * of a SSL/TLS client validating a server's certificate, the algorithm - * and usage are obtained from the cipher suite (e.g. ECDHE_RSA means - * that an RSA key for signatures is expected). + * - Successful validation produces a public key type but also a set + * of allowed usages (`BR_KEYTYPE_KEYX` and/or `BR_KEYTYPE_SIGN`). + * The caller is responsible for checking that the key type and + * usages are compatible with the expected values (e.g. with the + * selected cipher suite, when the client validates the server's + * certificate). * * **Important caveats:** * @@ -233,14 +233,24 @@ typedef struct { } key; } br_x509_pkey; +/** + * \brief Distinguished Name (X.500) structure. + * + * The DN is DER-encoded. + */ +typedef struct { + /** \brief Encoded DN data. */ + unsigned char *data; + /** \brief Encoded DN length (in bytes). */ + size_t len; +} br_x500_name; + /** * \brief Trust anchor structure. */ typedef struct { /** \brief Encoded DN (X.500 name). */ - unsigned char *dn; - /** \brief Encoded DN length (in bytes). */ - size_t dn_len; + br_x500_name dn; /** \brief Anchor flags (e.g. `BR_X509_TA_CA`). */ unsigned flags; /** \brief Anchor public key. */ @@ -364,22 +374,16 @@ struct br_x509_class_ { * This method shall set the vtable (first field) of the context * structure. * - * The `expected_key_type` is a combination of the algorithm type - * (`BR_KEYTYPE_RSA` or `BR_KEYTYPE_EC`) and the key usage - * (`BR_KEYTYPE_KEYX` or `BR_KEYTYPE_SIGN`). - * * The `server_name`, if not `NULL`, will be considered as a * fully qualified domain name, to be matched against the `dNSName` * elements of the end-entity certificate's SAN extension (if there * is no SAN, then the Common Name from the subjectDN will be used). * If `server_name` is `NULL` then no such matching is performed. * - * \param ctx validation context. - * \param expected_key_type expected key type (algorithm and usage). - * \param server_name server name to match (or `NULL`). + * \param ctx validation context. + * \param server_name server name to match (or `NULL`). */ void (*start_chain)(const br_x509_class **ctx, - unsigned expected_key_type, const char *server_name); /** @@ -446,10 +450,17 @@ struct br_x509_class_ { * a decoded public key even if the chain did not end on a * trusted anchor. * + * If validation succeeded and `usage` is not `NULL`, then + * `*usage` is filled with a combination of `BR_KEYTYPE_SIGN` + * and/or `BR_KEYTYPE_KEYX` that specifies the validated key + * usage types. It is the caller's responsibility to check + * that value against the intended use of the public key. + * * \param ctx validation context. * \return the end-entity public key, or `NULL`. */ - const br_x509_pkey *(*get_pkey)(const br_x509_class *const *ctx); + const br_x509_pkey *(*get_pkey)( + const br_x509_class *const *ctx, unsigned *usages); }; /** @@ -466,6 +477,7 @@ typedef struct { const br_x509_class *vtable; #ifndef BR_DOXYGEN_IGNORE br_x509_pkey pkey; + unsigned usages; #endif } br_x509_knownkey_context; @@ -477,26 +489,34 @@ extern const br_x509_class br_x509_knownkey_vtable; /** * \brief Initialize a "known key" X.509 engine with a known RSA public key. * + * The `usages` parameter indicates the allowed key usages for that key + * (`BR_KEYTYPE_KEYX` and/or `BR_KEYTYPE_SIGN`). + * * The provided pointers are linked in, not copied, so they must remain * valid while the public key may be in usage. * - * \param ctx context to initialise. - * \param pk known public key. + * \param ctx context to initialise. + * \param pk known public key. + * \param usages allowed key usages. */ void br_x509_knownkey_init_rsa(br_x509_knownkey_context *ctx, - const br_rsa_public_key *pk); + const br_rsa_public_key *pk, unsigned usages); /** * \brief Initialize a "known key" X.509 engine with a known EC public key. * + * The `usages` parameter indicates the allowed key usages for that key + * (`BR_KEYTYPE_KEYX` and/or `BR_KEYTYPE_SIGN`). + * * The provided pointers are linked in, not copied, so they must remain * valid while the public key may be in usage. * - * \param ctx context to initialise. - * \param pk known public key. + * \param ctx context to initialise. + * \param pk known public key. + * \param usages allowed key usages. */ void br_x509_knownkey_init_ec(br_x509_knownkey_context *ctx, - const br_ec_public_key *pk); + const br_ec_public_key *pk, unsigned usages); #ifndef BR_DOXYGEN_IGNORE /* @@ -560,8 +580,8 @@ typedef struct { /* Server name to match with the SAN / CN of the EE certificate. */ const char *server_name; - /* Expected EE key type and usage. */ - unsigned char expected_key_type; + /* Validated key usages. */ + unsigned char key_usages; /* Explicitly set date and time. */ uint32_t days, seconds; diff --git a/src/ssl/ssl_ccert_single_ec.c b/src/ssl/ssl_ccert_single_ec.c new file mode 100644 index 0000000..1df19a9 --- /dev/null +++ b/src/ssl/ssl_ccert_single_ec.c @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * 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; +} diff --git a/src/ssl/ssl_ccert_single_rsa.c b/src/ssl/ssl_ccert_single_rsa.c new file mode 100644 index 0000000..690df20 --- /dev/null +++ b/src/ssl/ssl_ccert_single_rsa.c @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2016 Thomas Pornin + * + * 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; +} diff --git a/src/ssl/ssl_client_full.c b/src/ssl/ssl_client_full.c index ad1f0cc..64f9327 100644 --- a/src/ssl/ssl_client_full.c +++ b/src/ssl/ssl_client_full.c @@ -123,9 +123,9 @@ br_ssl_client_init_full(br_ssl_client_context *cc, br_ssl_engine_set_suites(&cc->eng, suites, (sizeof suites) / (sizeof suites[0])); br_ssl_client_set_rsapub(cc, &br_rsa_i31_public); - br_ssl_client_set_rsavrfy(cc, &br_rsa_i31_pkcs1_vrfy); + br_ssl_engine_set_rsavrfy(&cc->eng, &br_rsa_i31_pkcs1_vrfy); br_ssl_engine_set_ec(&cc->eng, &br_ec_prime_i31); - br_ssl_client_set_ecdsa(cc, &br_ecdsa_i31_vrfy_asn1); + br_ssl_engine_set_ecdsa(&cc->eng, &br_ecdsa_i31_vrfy_asn1); br_x509_minimal_set_rsa(xc, &br_rsa_i31_pkcs1_vrfy); br_x509_minimal_set_ecdsa(xc, &br_ec_prime_i31, &br_ecdsa_i31_vrfy_asn1); diff --git a/src/ssl/ssl_hs_client.c b/src/ssl/ssl_hs_client.c index a347cc6..e7334de 100644 --- a/src/ssl/ssl_hs_client.c +++ b/src/ssl/ssl_hs_client.c @@ -110,7 +110,7 @@ make_pms_rsa(br_ssl_client_context *ctx, int prf_id) size_t nlen, u; xc = ctx->eng.x509ctx; - pk = (*xc)->get_pkey(xc); + pk = (*xc)->get_pkey(xc, NULL); /* * Compute actual RSA key length, in case there are leading zeros. @@ -200,9 +200,11 @@ static const unsigned char *HASH_OID[] = { /* * Check the RSA signature on the ServerKeyExchange message. + * * hash hash function ID (2 to 6), or 0 for MD5+SHA-1 (with RSA only) * use_rsa non-zero for RSA signature, zero for ECDSA * sig_len signature length (in bytes); signature value is in the pad + * * Returned value is 0 on success, or an error code. */ static int @@ -216,7 +218,7 @@ verify_SKE_sig(br_ssl_client_context *ctx, size_t hv_len; xc = ctx->eng.x509ctx; - pk = (*xc)->get_pkey(xc); + pk = (*xc)->get_pkey(xc, NULL); br_multihash_zero(&mhc); br_multihash_copyimpl(&mhc, &ctx->eng.mhash); br_multihash_init(&mhc); @@ -253,14 +255,14 @@ verify_SKE_sig(br_ssl_client_context *ctx, } else { hash_oid = NULL; } - if (!ctx->irsavrfy(ctx->eng.pad, sig_len, + if (!ctx->eng.irsavrfy(ctx->eng.pad, sig_len, hash_oid, hv_len, &pk->key.rsa, tmp) || memcmp(tmp, hv, hv_len) != 0) { return BR_ERR_BAD_SIGNATURE; } } else { - if (!ctx->iecdsa(ctx->eng.iec, hv, hv_len, &pk->key.ec, + if (!ctx->eng.iecdsa(ctx->eng.iec, hv, hv_len, &pk->key.ec, ctx->eng.pad, sig_len)) { return BR_ERR_BAD_SIGNATURE; @@ -270,7 +272,7 @@ verify_SKE_sig(br_ssl_client_context *ctx, } /* - * Perform client-size ECDH (or ECDHE). The point that should be sent to + * Perform client-side ECDH (or ECDHE). The point that should be sent to * the server is written in the pad; returned value is either the point * length (in bytes), or -x on error, with 'x' being an error code. * @@ -296,7 +298,7 @@ make_pms_ecdh(br_ssl_client_context *ctx, unsigned ecdhe, int prf_id) const br_x509_pkey *pk; xc = ctx->eng.x509ctx; - pk = (*xc)->get_pkey(xc); + pk = (*xc)->get_pkey(xc, NULL); curve = pk->key.ec.curve; point_src = pk->key.ec.q; point_len = pk->key.ec.qlen; @@ -347,6 +349,73 @@ make_pms_ecdh(br_ssl_client_context *ctx, unsigned ecdhe, int prf_id) return (int)glen; } +/* + * Perform full static ECDH. This occurs only in the context of client + * authentication with certificates: the server uses an EC public key, + * the cipher suite is of type ECDH (not ECDHE), the server requested a + * client certificate and accepts static ECDH, the client has a + * certificate with an EC public key in the same curve, and accepts + * static ECDH as well. + * + * Returned value is 0 on success, -1 on error. + */ +static int +make_pms_static_ecdh(br_ssl_client_context *ctx, int prf_id) +{ + unsigned char point[133]; + size_t point_len; + const br_x509_class **xc; + const br_x509_pkey *pk; + + xc = ctx->eng.x509ctx; + pk = (*xc)->get_pkey(xc, NULL); + point_len = pk->key.ec.qlen; + if (point_len > sizeof point) { + return -1; + } + memcpy(point, pk->key.ec.q, point_len); + if (!(*ctx->client_auth_vtable)->do_keyx( + ctx->client_auth_vtable, point, point_len)) + { + return -1; + } + br_ssl_engine_compute_master(&ctx->eng, + prf_id, point + 1, point_len >> 1); + return 0; +} + +/* + * Compute the client-side signature. This is invoked only when a + * signature-based client authentication was selected. The computed + * signature is in the pad; its length (in bytes) is returned. On + * error, 0 is returned. + */ +static size_t +make_client_sign(br_ssl_client_context *ctx) +{ + size_t hv_len; + + /* + * Compute hash of handshake messages so far. This "cannot" fail + * because the list of supported hash functions provided to the + * client certificate handler was trimmed to include only the + * hash functions that the multi-hasher supports. + */ + if (ctx->hash_id) { + hv_len = br_multihash_out(&ctx->eng.mhash, + ctx->hash_id, ctx->eng.pad); + } else { + br_multihash_out(&ctx->eng.mhash, + br_md5_ID, ctx->eng.pad); + br_multihash_out(&ctx->eng.mhash, + br_sha1_ID, ctx->eng.pad + 16); + hv_len = 36; + } + return (*ctx->client_auth_vtable)->do_sign( + ctx->client_auth_vtable, ctx->hash_id, hv_len, + ctx->eng.pad, sizeof ctx->eng.pad); +} + static const uint8_t t0_datablock[] = { @@ -366,10 +435,10 @@ static const uint8_t t0_datablock[] = { }; static const uint8_t t0_codeblock[] = { - 0x00, 0x01, 0x00, 0x0A, 0x00, 0x00, 0x01, 0x00, 0x0C, 0x00, 0x00, 0x01, - 0x00, 0x0D, 0x00, 0x00, 0x01, 0x00, 0x0E, 0x00, 0x00, 0x01, 0x01, 0x08, + 0x00, 0x01, 0x00, 0x0A, 0x00, 0x00, 0x01, 0x00, 0x0D, 0x00, 0x00, 0x01, + 0x00, 0x0E, 0x00, 0x00, 0x01, 0x00, 0x0F, 0x00, 0x00, 0x01, 0x01, 0x08, 0x00, 0x00, 0x01, 0x01, 0x09, 0x00, 0x00, 0x01, 0x02, 0x08, 0x00, 0x00, - 0x01, 0x02, 0x09, 0x00, 0x00, 0x1A, 0x1A, 0x00, 0x00, 0x01, + 0x01, 0x02, 0x09, 0x00, 0x00, 0x24, 0x24, 0x00, 0x00, 0x01, T0_INT1(BR_ERR_BAD_CCS), 0x00, 0x00, 0x01, T0_INT1(BR_ERR_BAD_CIPHER_SUITE), 0x00, 0x00, 0x01, T0_INT1(BR_ERR_BAD_COMPRESSION), 0x00, 0x00, 0x01, @@ -387,9 +456,11 @@ static const uint8_t t0_codeblock[] = { T0_INT1(BR_ERR_RESUME_MISMATCH), 0x00, 0x00, 0x01, T0_INT1(BR_ERR_UNEXPECTED), 0x00, 0x00, 0x01, T0_INT1(BR_ERR_UNSUPPORTED_VERSION), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_WRONG_KEY_USAGE), 0x00, 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, action)), 0x00, 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, alert)), 0x00, 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, application_data)), 0x00, 0x00, + 0x01, T0_INT2(offsetof(br_ssl_client_context, auth_type)), 0x00, 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, session) + offsetof(br_ssl_session_parameters, cipher_suite)), 0x00, 0x00, 0x01, @@ -400,6 +471,8 @@ static const uint8_t t0_codeblock[] = { T0_INT2(offsetof(br_ssl_engine_context, ecdhe_point)), 0x00, 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, ecdhe_point_len)), 0x00, 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, flags)), 0x00, + 0x00, 0x01, T0_INT2(offsetof(br_ssl_client_context, hash_id)), 0x00, + 0x00, 0x01, T0_INT2(offsetof(br_ssl_client_context, hashes)), 0x00, 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, log_max_frag_len)), 0x00, 0x00, 0x01, T0_INT2(offsetof(br_ssl_client_context, min_clienthello_len)), 0x00, @@ -426,218 +499,259 @@ static const uint8_t t0_codeblock[] = { T0_INT2(offsetof(br_ssl_engine_context, version_max)), 0x00, 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, version_min)), 0x00, 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, version_out)), - 0x00, 0x00, 0x09, 0x1B, 0x42, 0x06, 0x02, 0x52, 0x1C, 0x00, 0x00, 0x06, - 0x08, 0x1E, 0x0D, 0x05, 0x02, 0x5B, 0x1C, 0x04, 0x01, 0x2D, 0x00, 0x00, - 0x01, 0x01, 0x00, 0x01, 0x03, 0x00, 0x7D, 0x1B, 0x48, 0x34, 0x81, 0x01, - 0x1B, 0x05, 0x04, 0x4A, 0x01, 0x00, 0x00, 0x02, 0x00, 0x0D, 0x06, 0x03, - 0x81, 0x01, 0x00, 0x48, 0x04, 0x69, 0x00, 0x06, 0x02, 0x52, 0x1C, 0x00, - 0x00, 0x1B, 0x6E, 0x34, 0x05, 0x03, 0x01, 0x0C, 0x08, 0x34, 0x61, 0x1E, - 0x81, 0x0F, 0x15, 0x6A, 0x01, 0x0C, 0x23, 0x00, 0x00, 0x1B, 0x16, 0x01, - 0x08, 0x0B, 0x34, 0x46, 0x16, 0x08, 0x00, 0x01, 0x03, 0x00, 0x01, 0x00, - 0x60, 0x2E, 0x1D, 0x13, 0x28, 0x06, 0x08, 0x02, 0x00, 0x81, 0x2E, 0x03, - 0x00, 0x04, 0x74, 0x01, 0x00, 0x81, 0x26, 0x02, 0x00, 0x1B, 0x13, 0x11, - 0x06, 0x02, 0x59, 0x1C, 0x81, 0x2E, 0x04, 0x75, 0x01, 0x01, 0x00, 0x60, - 0x2E, 0x01, 0x16, 0x6C, 0x2E, 0x26, 0x81, 0x32, 0x1D, 0x81, 0x16, 0x06, - 0x0B, 0x01, 0x7F, 0x81, 0x12, 0x01, 0x7F, 0x81, 0x31, 0x04, 0x80, 0x42, - 0x81, 0x13, 0x61, 0x1E, 0x81, 0x05, 0x01, T0_INT1(BR_KEYTYPE_SIGN), - 0x11, 0x06, 0x02, 0x81, 0x17, 0x81, 0x1A, 0x1B, 0x01, 0x0D, 0x0D, 0x06, - 0x09, 0x1A, 0x81, 0x19, 0x81, 0x1A, 0x01, 0x7F, 0x04, 0x02, 0x01, 0x00, - 0x03, 0x00, 0x01, 0x0E, 0x0D, 0x05, 0x02, 0x5C, 0x1C, 0x06, 0x02, 0x51, - 0x1C, 0x25, 0x06, 0x02, 0x5C, 0x1C, 0x02, 0x00, 0x06, 0x02, 0x81, 0x38, - 0x81, 0x33, 0x01, 0x7F, 0x81, 0x31, 0x01, 0x7F, 0x81, 0x12, 0x01, 0x01, - 0x60, 0x2E, 0x01, 0x17, 0x6C, 0x2E, 0x00, 0x00, 0x2A, 0x2A, 0x00, 0x00, - 0x7E, 0x01, 0x0C, 0x10, 0x01, 0x00, 0x2A, 0x0D, 0x06, 0x05, 0x1A, 0x01, - T0_INT1(BR_KEYTYPE_RSA | BR_KEYTYPE_KEYX), 0x04, 0x30, 0x01, 0x01, - 0x2A, 0x0D, 0x06, 0x05, 0x1A, 0x01, + 0x00, 0x00, 0x09, 0x25, 0x50, 0x06, 0x02, 0x60, 0x26, 0x00, 0x00, 0x06, + 0x08, 0x2A, 0x0E, 0x05, 0x02, 0x69, 0x26, 0x04, 0x01, 0x3A, 0x00, 0x00, + 0x01, 0x01, 0x00, 0x01, 0x03, 0x00, 0x81, 0x0F, 0x25, 0x56, 0x41, 0x81, + 0x13, 0x25, 0x05, 0x04, 0x58, 0x01, 0x00, 0x00, 0x02, 0x00, 0x0E, 0x06, + 0x03, 0x81, 0x13, 0x00, 0x56, 0x04, 0x69, 0x00, 0x06, 0x02, 0x60, 0x26, + 0x00, 0x00, 0x25, 0x81, 0x00, 0x41, 0x05, 0x03, 0x01, 0x0C, 0x08, 0x41, + 0x71, 0x2A, 0x81, 0x21, 0x1C, 0x7C, 0x01, 0x0C, 0x2F, 0x00, 0x00, 0x25, + 0x1E, 0x01, 0x08, 0x0B, 0x41, 0x54, 0x1E, 0x08, 0x00, 0x01, 0x03, 0x00, + 0x01, 0x00, 0x6F, 0x3B, 0x27, 0x1A, 0x34, 0x06, 0x08, 0x02, 0x00, 0x81, + 0x43, 0x03, 0x00, 0x04, 0x74, 0x01, 0x00, 0x81, 0x3A, 0x02, 0x00, 0x25, + 0x1A, 0x17, 0x06, 0x02, 0x67, 0x26, 0x81, 0x43, 0x04, 0x75, 0x01, 0x01, + 0x00, 0x6F, 0x3B, 0x01, 0x16, 0x7E, 0x3B, 0x32, 0x81, 0x49, 0x27, 0x81, + 0x29, 0x06, 0x0B, 0x01, 0x7F, 0x81, 0x24, 0x01, 0x7F, 0x81, 0x46, 0x04, + 0x80, 0x62, 0x81, 0x26, 0x71, 0x2A, 0x81, 0x17, 0x01, + T0_INT1(BR_KEYTYPE_SIGN), 0x17, 0x06, 0x02, 0x81, 0x2A, 0x81, 0x2D, + 0x25, 0x01, 0x0D, 0x0E, 0x06, 0x09, 0x24, 0x81, 0x2C, 0x81, 0x2D, 0x01, + 0x7F, 0x04, 0x02, 0x01, 0x00, 0x03, 0x00, 0x01, 0x0E, 0x0E, 0x05, 0x02, + 0x6A, 0x26, 0x06, 0x02, 0x5F, 0x26, 0x31, 0x06, 0x02, 0x6A, 0x26, 0x02, + 0x00, 0x06, 0x22, 0x81, 0x47, 0x78, 0x2C, 0x01, 0x81, 0x7F, 0x0E, 0x06, + 0x10, 0x24, 0x01, 0x10, 0x81, 0x52, 0x01, 0x00, 0x81, 0x51, 0x71, 0x2A, + 0x81, 0x21, 0x23, 0x04, 0x06, 0x81, 0x4A, 0x06, 0x02, 0x81, 0x48, 0x04, + 0x02, 0x81, 0x4A, 0x01, 0x7F, 0x81, 0x46, 0x01, 0x7F, 0x81, 0x24, 0x01, + 0x01, 0x6F, 0x3B, 0x01, 0x17, 0x7E, 0x3B, 0x00, 0x00, 0x36, 0x36, 0x00, + 0x00, 0x81, 0x10, 0x01, 0x0C, 0x11, 0x01, 0x00, 0x36, 0x0E, 0x06, 0x05, + 0x24, 0x01, T0_INT1(BR_KEYTYPE_RSA | BR_KEYTYPE_KEYX), 0x04, 0x30, + 0x01, 0x01, 0x36, 0x0E, 0x06, 0x05, 0x24, 0x01, T0_INT1(BR_KEYTYPE_RSA | BR_KEYTYPE_SIGN), 0x04, 0x25, 0x01, 0x02, - 0x2A, 0x0D, 0x06, 0x05, 0x1A, 0x01, + 0x36, 0x0E, 0x06, 0x05, 0x24, 0x01, T0_INT1(BR_KEYTYPE_EC | BR_KEYTYPE_SIGN), 0x04, 0x1A, 0x01, 0x03, - 0x2A, 0x0D, 0x06, 0x05, 0x1A, 0x01, + 0x36, 0x0E, 0x06, 0x05, 0x24, 0x01, T0_INT1(BR_KEYTYPE_EC | BR_KEYTYPE_KEYX), 0x04, 0x0F, 0x01, 0x04, - 0x2A, 0x0D, 0x06, 0x05, 0x1A, 0x01, + 0x36, 0x0E, 0x06, 0x05, 0x24, 0x01, T0_INT1(BR_KEYTYPE_EC | BR_KEYTYPE_KEYX), 0x04, 0x04, 0x01, 0x00, - 0x34, 0x1A, 0x00, 0x00, 0x68, 0x20, 0x01, 0x0E, 0x0D, 0x06, 0x04, 0x01, - 0x00, 0x04, 0x02, 0x01, 0x05, 0x00, 0x00, 0x30, 0x06, 0x04, 0x01, 0x06, - 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x6D, 0x20, 0x1B, 0x06, 0x08, 0x01, - 0x01, 0x09, 0x01, 0x11, 0x07, 0x04, 0x03, 0x1A, 0x01, 0x05, 0x00, 0x01, - 0x31, 0x03, 0x00, 0x1A, 0x01, 0x00, 0x33, 0x06, 0x03, 0x02, 0x00, 0x08, - 0x32, 0x06, 0x03, 0x02, 0x00, 0x08, 0x1B, 0x06, 0x06, 0x01, 0x01, 0x0B, - 0x01, 0x06, 0x08, 0x00, 0x00, 0x6F, 0x2F, 0x1B, 0x06, 0x03, 0x01, 0x09, - 0x08, 0x00, 0x01, 0x30, 0x1B, 0x06, 0x1E, 0x01, 0x00, 0x03, 0x00, 0x1B, - 0x06, 0x0E, 0x1B, 0x01, 0x01, 0x11, 0x02, 0x00, 0x08, 0x03, 0x00, 0x01, - 0x01, 0x10, 0x04, 0x6F, 0x1A, 0x02, 0x00, 0x01, 0x01, 0x0B, 0x01, 0x06, - 0x08, 0x00, 0x00, 0x67, 0x1F, 0x34, 0x10, 0x01, 0x01, 0x11, 0x27, 0x00, - 0x00, 0x81, 0x03, 0x81, 0x2D, 0x1B, 0x01, 0x07, 0x11, 0x01, 0x00, 0x2A, - 0x0D, 0x06, 0x0A, 0x1A, 0x01, 0x10, 0x11, 0x06, 0x02, 0x81, 0x03, 0x04, - 0x32, 0x01, 0x01, 0x2A, 0x0D, 0x06, 0x29, 0x1A, 0x1A, 0x01, 0x00, 0x60, - 0x2E, 0x81, 0x15, 0x6D, 0x20, 0x01, 0x01, 0x0D, 0x01, 0x01, 0x81, 0x0C, - 0x29, 0x06, 0x11, 0x1D, 0x13, 0x28, 0x06, 0x05, 0x81, 0x2D, 0x1A, 0x04, - 0x77, 0x01, 0x80, 0x64, 0x81, 0x26, 0x04, 0x02, 0x81, 0x03, 0x04, 0x03, - 0x5C, 0x1C, 0x1A, 0x04, 0xFF, 0x35, 0x01, 0x1B, 0x03, 0x00, 0x09, 0x1B, - 0x42, 0x06, 0x02, 0x52, 0x1C, 0x02, 0x00, 0x00, 0x00, 0x7E, 0x01, 0x0F, - 0x11, 0x00, 0x00, 0x5F, 0x20, 0x01, 0x00, 0x2A, 0x0D, 0x06, 0x10, 0x1A, - 0x1B, 0x01, 0x01, 0x0C, 0x06, 0x03, 0x1A, 0x01, 0x02, 0x5F, 0x2E, 0x01, - 0x00, 0x04, 0x22, 0x01, 0x01, 0x2A, 0x0D, 0x06, 0x15, 0x1A, 0x01, 0x00, - 0x5F, 0x2E, 0x1B, 0x01, 0x80, 0x64, 0x0D, 0x06, 0x05, 0x01, 0x82, 0x00, - 0x08, 0x1C, 0x44, 0x00, 0x04, 0x07, 0x1A, 0x01, 0x82, 0x00, 0x08, 0x1C, - 0x1A, 0x00, 0x00, 0x01, 0x00, 0x21, 0x06, 0x06, 0x2C, 0x81, 0x10, 0x29, - 0x04, 0x77, 0x1B, 0x06, 0x04, 0x01, 0x01, 0x73, 0x2E, 0x00, 0x00, 0x21, - 0x06, 0x0B, 0x6B, 0x20, 0x01, 0x14, 0x0C, 0x06, 0x02, 0x5C, 0x1C, 0x04, - 0x12, 0x81, 0x2D, 0x01, 0x07, 0x11, 0x1B, 0x01, 0x02, 0x0C, 0x06, 0x06, - 0x06, 0x02, 0x5C, 0x1C, 0x04, 0x6F, 0x1A, 0x81, 0x23, 0x01, 0x01, 0x0C, - 0x25, 0x29, 0x06, 0x02, 0x4B, 0x1C, 0x1B, 0x01, 0x01, 0x81, 0x29, 0x28, - 0x81, 0x14, 0x00, 0x01, 0x81, 0x1A, 0x01, 0x0B, 0x0D, 0x05, 0x02, 0x5C, - 0x1C, 0x61, 0x1E, 0x81, 0x05, 0x41, 0x81, 0x21, 0x81, 0x0E, 0x1B, 0x06, - 0x26, 0x81, 0x21, 0x81, 0x0E, 0x1B, 0x40, 0x1B, 0x06, 0x19, 0x1B, 0x01, - 0x82, 0x00, 0x0E, 0x06, 0x05, 0x01, 0x82, 0x00, 0x04, 0x01, 0x1B, 0x03, - 0x00, 0x6A, 0x02, 0x00, 0x81, 0x18, 0x02, 0x00, 0x3D, 0x04, 0x64, 0x7F, - 0x3E, 0x04, 0x57, 0x7F, 0x7F, 0x3F, 0x1B, 0x06, 0x01, 0x1C, 0x1A, 0x00, - 0x00, 0x81, 0x00, 0x81, 0x1A, 0x01, 0x14, 0x0C, 0x06, 0x02, 0x5C, 0x1C, - 0x6A, 0x01, 0x0C, 0x08, 0x01, 0x0C, 0x81, 0x18, 0x7F, 0x6A, 0x1B, 0x01, - 0x0C, 0x08, 0x01, 0x0C, 0x22, 0x05, 0x02, 0x4E, 0x1C, 0x00, 0x00, 0x81, - 0x1B, 0x06, 0x02, 0x5C, 0x1C, 0x06, 0x02, 0x50, 0x1C, 0x00, 0x09, 0x81, - 0x1A, 0x01, 0x02, 0x0D, 0x05, 0x02, 0x5C, 0x1C, 0x81, 0x20, 0x03, 0x00, - 0x02, 0x00, 0x79, 0x1E, 0x0A, 0x02, 0x00, 0x78, 0x1E, 0x0E, 0x29, 0x06, - 0x02, 0x5D, 0x1C, 0x02, 0x00, 0x77, 0x1E, 0x0C, 0x06, 0x02, 0x55, 0x1C, - 0x02, 0x00, 0x7A, 0x2D, 0x70, 0x01, 0x20, 0x81, 0x18, 0x01, 0x00, 0x03, - 0x01, 0x81, 0x22, 0x03, 0x02, 0x02, 0x02, 0x01, 0x20, 0x0E, 0x06, 0x02, - 0x5A, 0x1C, 0x6A, 0x02, 0x02, 0x81, 0x18, 0x02, 0x02, 0x72, 0x20, 0x0D, - 0x02, 0x02, 0x01, 0x00, 0x0E, 0x11, 0x06, 0x0B, 0x71, 0x6A, 0x02, 0x02, - 0x22, 0x06, 0x04, 0x01, 0x7F, 0x03, 0x01, 0x71, 0x6A, 0x02, 0x02, 0x23, - 0x02, 0x02, 0x72, 0x2E, 0x02, 0x00, 0x76, 0x02, 0x01, 0x7C, 0x81, 0x20, - 0x1B, 0x81, 0x24, 0x42, 0x06, 0x02, 0x4C, 0x1C, 0x61, 0x02, 0x01, 0x7C, - 0x81, 0x22, 0x06, 0x02, 0x4D, 0x1C, 0x1B, 0x06, 0x81, 0x3D, 0x81, 0x20, - 0x81, 0x0E, 0x81, 0x0A, 0x03, 0x03, 0x81, 0x08, 0x03, 0x04, 0x81, 0x06, - 0x03, 0x05, 0x81, 0x09, 0x03, 0x06, 0x81, 0x0B, 0x03, 0x07, 0x81, 0x07, - 0x03, 0x08, 0x1B, 0x06, 0x81, 0x0B, 0x81, 0x20, 0x01, 0x00, 0x2A, 0x0D, - 0x06, 0x10, 0x1A, 0x02, 0x03, 0x05, 0x02, 0x56, 0x1C, 0x01, 0x00, 0x03, - 0x03, 0x81, 0x1F, 0x04, 0x80, 0x70, 0x01, 0x01, 0x2A, 0x0D, 0x06, 0x10, - 0x1A, 0x02, 0x05, 0x05, 0x02, 0x56, 0x1C, 0x01, 0x00, 0x03, 0x05, 0x81, - 0x1D, 0x04, 0x80, 0x5A, 0x01, 0x83, 0xFE, 0x01, 0x2A, 0x0D, 0x06, 0x10, - 0x1A, 0x02, 0x04, 0x05, 0x02, 0x56, 0x1C, 0x01, 0x00, 0x03, 0x04, 0x81, - 0x1E, 0x04, 0x80, 0x42, 0x01, 0x0D, 0x2A, 0x0D, 0x06, 0x0F, 0x1A, 0x02, - 0x06, 0x05, 0x02, 0x56, 0x1C, 0x01, 0x00, 0x03, 0x06, 0x81, 0x1C, 0x04, - 0x2D, 0x01, 0x0A, 0x2A, 0x0D, 0x06, 0x0F, 0x1A, 0x02, 0x07, 0x05, 0x02, - 0x56, 0x1C, 0x01, 0x00, 0x03, 0x07, 0x81, 0x1C, 0x04, 0x18, 0x01, 0x0B, - 0x2A, 0x0D, 0x06, 0x0F, 0x1A, 0x02, 0x08, 0x05, 0x02, 0x56, 0x1C, 0x01, - 0x00, 0x03, 0x08, 0x81, 0x1C, 0x04, 0x03, 0x56, 0x1C, 0x1A, 0x04, 0xFE, - 0x71, 0x02, 0x04, 0x06, 0x0D, 0x02, 0x04, 0x01, 0x05, 0x0E, 0x06, 0x02, - 0x53, 0x1C, 0x01, 0x01, 0x6D, 0x2E, 0x7F, 0x7F, 0x02, 0x01, 0x00, 0x04, - 0x81, 0x1A, 0x01, 0x0C, 0x0D, 0x05, 0x02, 0x5C, 0x1C, 0x81, 0x22, 0x01, - 0x03, 0x0D, 0x05, 0x02, 0x57, 0x1C, 0x81, 0x20, 0x1B, 0x64, 0x2E, 0x1B, - 0x01, 0x20, 0x0F, 0x06, 0x02, 0x57, 0x1C, 0x30, 0x34, 0x10, 0x01, 0x01, - 0x11, 0x05, 0x02, 0x57, 0x1C, 0x81, 0x22, 0x1B, 0x01, 0x81, 0x05, 0x0E, - 0x06, 0x02, 0x57, 0x1C, 0x1B, 0x66, 0x2E, 0x65, 0x34, 0x81, 0x18, 0x76, - 0x1E, 0x01, 0x86, 0x03, 0x0F, 0x03, 0x00, 0x61, 0x1E, 0x81, 0x2B, 0x03, - 0x01, 0x01, 0x02, 0x03, 0x02, 0x02, 0x00, 0x06, 0x23, 0x81, 0x22, 0x1B, - 0x1B, 0x01, 0x02, 0x0A, 0x34, 0x01, 0x06, 0x0E, 0x29, 0x06, 0x02, 0x57, - 0x1C, 0x03, 0x02, 0x81, 0x22, 0x02, 0x01, 0x01, 0x01, 0x0B, 0x01, 0x03, - 0x08, 0x0D, 0x05, 0x02, 0x57, 0x1C, 0x04, 0x08, 0x02, 0x01, 0x06, 0x04, - 0x01, 0x00, 0x03, 0x02, 0x81, 0x20, 0x1B, 0x03, 0x03, 0x1B, 0x01, 0x84, - 0x00, 0x0E, 0x06, 0x02, 0x58, 0x1C, 0x6A, 0x34, 0x81, 0x18, 0x02, 0x02, - 0x02, 0x01, 0x02, 0x03, 0x3A, 0x1B, 0x06, 0x01, 0x1C, 0x1A, 0x7F, 0x00, - 0x02, 0x03, 0x00, 0x03, 0x01, 0x02, 0x00, 0x7B, 0x02, 0x01, 0x02, 0x00, - 0x2B, 0x1B, 0x01, 0x00, 0x0D, 0x06, 0x02, 0x4A, 0x00, 0x81, 0x2F, 0x04, - 0x73, 0x00, 0x1B, 0x06, 0x05, 0x81, 0x22, 0x1A, 0x04, 0x78, 0x1A, 0x00, - 0x00, 0x81, 0x1B, 0x1B, 0x44, 0x06, 0x07, 0x1A, 0x06, 0x02, 0x50, 0x1C, - 0x04, 0x73, 0x00, 0x00, 0x81, 0x23, 0x01, 0x03, 0x81, 0x21, 0x34, 0x1A, - 0x34, 0x00, 0x00, 0x81, 0x20, 0x81, 0x27, 0x00, 0x00, 0x81, 0x20, 0x01, - 0x01, 0x0D, 0x05, 0x02, 0x4F, 0x1C, 0x81, 0x22, 0x01, 0x08, 0x08, 0x68, - 0x20, 0x0D, 0x05, 0x02, 0x4F, 0x1C, 0x00, 0x00, 0x81, 0x20, 0x6D, 0x20, - 0x05, 0x16, 0x01, 0x01, 0x0D, 0x05, 0x02, 0x53, 0x1C, 0x81, 0x22, 0x01, - 0x00, 0x0D, 0x05, 0x02, 0x53, 0x1C, 0x01, 0x02, 0x6D, 0x2E, 0x04, 0x1E, - 0x01, 0x19, 0x0D, 0x05, 0x02, 0x53, 0x1C, 0x81, 0x22, 0x01, 0x18, 0x0D, - 0x05, 0x02, 0x53, 0x1C, 0x6A, 0x01, 0x18, 0x81, 0x18, 0x6E, 0x6A, 0x01, - 0x18, 0x22, 0x05, 0x02, 0x53, 0x1C, 0x00, 0x00, 0x81, 0x20, 0x06, 0x02, - 0x54, 0x1C, 0x00, 0x00, 0x01, 0x02, 0x7B, 0x81, 0x23, 0x01, 0x08, 0x0B, - 0x81, 0x23, 0x08, 0x00, 0x00, 0x01, 0x03, 0x7B, 0x81, 0x23, 0x01, 0x08, - 0x0B, 0x81, 0x23, 0x08, 0x01, 0x08, 0x0B, 0x81, 0x23, 0x08, 0x00, 0x00, - 0x01, 0x01, 0x7B, 0x81, 0x23, 0x00, 0x00, 0x2C, 0x1B, 0x42, 0x05, 0x01, - 0x00, 0x1A, 0x81, 0x2F, 0x04, 0x75, 0x02, 0x03, 0x00, 0x75, 0x20, 0x03, - 0x01, 0x01, 0x00, 0x1B, 0x02, 0x01, 0x0A, 0x06, 0x10, 0x1B, 0x01, 0x01, - 0x0B, 0x74, 0x08, 0x1E, 0x02, 0x00, 0x0D, 0x06, 0x01, 0x00, 0x46, 0x04, - 0x6A, 0x1A, 0x01, 0x7F, 0x00, 0x00, 0x01, 0x15, 0x6C, 0x2E, 0x34, 0x3C, - 0x1A, 0x3C, 0x1A, 0x1D, 0x00, 0x00, 0x01, 0x01, 0x34, 0x81, 0x25, 0x00, - 0x00, 0x34, 0x2A, 0x7B, 0x34, 0x1B, 0x06, 0x06, 0x81, 0x23, 0x1A, 0x47, - 0x04, 0x77, 0x1A, 0x00, 0x00, 0x1B, 0x01, 0x81, 0xAC, 0x00, 0x0D, 0x06, - 0x04, 0x1A, 0x01, 0x7F, 0x00, 0x7E, 0x43, 0x00, 0x02, 0x03, 0x00, 0x61, - 0x1E, 0x7E, 0x03, 0x01, 0x02, 0x01, 0x01, 0x0F, 0x11, 0x02, 0x01, 0x01, - 0x04, 0x10, 0x01, 0x0F, 0x11, 0x02, 0x01, 0x01, 0x08, 0x10, 0x01, 0x0F, - 0x11, 0x01, 0x00, 0x2A, 0x0D, 0x06, 0x10, 0x1A, 0x01, 0x00, 0x01, 0x18, - 0x02, 0x00, 0x06, 0x03, 0x37, 0x04, 0x01, 0x38, 0x04, 0x80, 0x56, 0x01, - 0x01, 0x2A, 0x0D, 0x06, 0x10, 0x1A, 0x01, 0x01, 0x01, 0x10, 0x02, 0x00, - 0x06, 0x03, 0x37, 0x04, 0x01, 0x38, 0x04, 0x80, 0x40, 0x01, 0x02, 0x2A, - 0x0D, 0x06, 0x0F, 0x1A, 0x01, 0x01, 0x01, 0x20, 0x02, 0x00, 0x06, 0x03, - 0x37, 0x04, 0x01, 0x38, 0x04, 0x2B, 0x01, 0x03, 0x2A, 0x0D, 0x06, 0x0E, - 0x1A, 0x1A, 0x01, 0x10, 0x02, 0x00, 0x06, 0x03, 0x35, 0x04, 0x01, 0x36, - 0x04, 0x17, 0x01, 0x04, 0x2A, 0x0D, 0x06, 0x0E, 0x1A, 0x1A, 0x01, 0x20, - 0x02, 0x00, 0x06, 0x03, 0x35, 0x04, 0x01, 0x36, 0x04, 0x03, 0x52, 0x1C, - 0x1A, 0x00, 0x00, 0x7E, 0x01, 0x0C, 0x10, 0x1B, 0x45, 0x34, 0x01, 0x03, - 0x0A, 0x11, 0x00, 0x00, 0x7E, 0x01, 0x0C, 0x10, 0x01, 0x01, 0x0D, 0x00, - 0x00, 0x7E, 0x01, 0x0C, 0x10, 0x44, 0x00, 0x00, 0x14, 0x01, 0x00, 0x5E, - 0x20, 0x1B, 0x06, 0x20, 0x01, 0x01, 0x2A, 0x0D, 0x06, 0x07, 0x1A, 0x01, - 0x00, 0x81, 0x02, 0x04, 0x11, 0x01, 0x02, 0x2A, 0x0D, 0x06, 0x0A, 0x1A, - 0x60, 0x20, 0x06, 0x03, 0x01, 0x10, 0x29, 0x04, 0x01, 0x1A, 0x04, 0x01, - 0x1A, 0x63, 0x20, 0x05, 0x35, 0x21, 0x06, 0x32, 0x6B, 0x20, 0x01, 0x14, - 0x2A, 0x0D, 0x06, 0x06, 0x1A, 0x01, 0x02, 0x29, 0x04, 0x24, 0x01, 0x15, - 0x2A, 0x0D, 0x06, 0x0B, 0x1A, 0x81, 0x11, 0x06, 0x04, 0x01, 0x7F, 0x81, - 0x02, 0x04, 0x13, 0x01, 0x16, 0x2A, 0x0D, 0x06, 0x06, 0x1A, 0x01, 0x01, - 0x29, 0x04, 0x07, 0x1A, 0x01, 0x04, 0x29, 0x01, 0x00, 0x1A, 0x13, 0x06, - 0x03, 0x01, 0x08, 0x29, 0x00, 0x00, 0x14, 0x1B, 0x05, 0x10, 0x21, 0x06, - 0x0D, 0x6B, 0x20, 0x01, 0x15, 0x0D, 0x06, 0x05, 0x1A, 0x81, 0x11, 0x04, - 0x01, 0x17, 0x00, 0x00, 0x81, 0x2D, 0x01, 0x07, 0x11, 0x01, 0x01, 0x0E, - 0x06, 0x02, 0x5C, 0x1C, 0x00, 0x01, 0x03, 0x00, 0x1D, 0x13, 0x06, 0x05, - 0x02, 0x00, 0x6C, 0x2E, 0x00, 0x81, 0x2D, 0x1A, 0x04, 0x73, 0x00, 0x01, - 0x14, 0x81, 0x30, 0x01, 0x01, 0x81, 0x3C, 0x1D, 0x1B, 0x01, 0x00, 0x81, - 0x29, 0x01, 0x16, 0x81, 0x30, 0x81, 0x34, 0x1D, 0x00, 0x02, 0x81, 0x08, - 0x81, 0x0A, 0x08, 0x81, 0x06, 0x08, 0x81, 0x09, 0x08, 0x81, 0x0B, 0x08, - 0x81, 0x07, 0x08, 0x03, 0x00, 0x01, 0x01, 0x81, 0x3C, 0x01, 0x27, 0x72, - 0x20, 0x08, 0x75, 0x20, 0x01, 0x01, 0x0B, 0x08, 0x02, 0x00, 0x06, 0x04, - 0x48, 0x02, 0x00, 0x08, 0x69, 0x1E, 0x2A, 0x09, 0x1B, 0x45, 0x06, 0x24, - 0x02, 0x00, 0x05, 0x04, 0x34, 0x48, 0x34, 0x49, 0x01, 0x04, 0x09, 0x1B, - 0x42, 0x06, 0x03, 0x1A, 0x01, 0x00, 0x1B, 0x01, 0x04, 0x08, 0x02, 0x00, - 0x08, 0x03, 0x00, 0x34, 0x01, 0x04, 0x08, 0x2A, 0x08, 0x34, 0x04, 0x03, - 0x1A, 0x01, 0x7F, 0x03, 0x01, 0x81, 0x3B, 0x78, 0x1E, 0x81, 0x3A, 0x62, - 0x01, 0x04, 0x12, 0x62, 0x01, 0x04, 0x08, 0x01, 0x1C, 0x24, 0x62, 0x01, - 0x20, 0x81, 0x35, 0x71, 0x72, 0x20, 0x81, 0x37, 0x75, 0x20, 0x1B, 0x01, - 0x01, 0x0B, 0x81, 0x3A, 0x74, 0x34, 0x1B, 0x06, 0x11, 0x47, 0x2A, 0x1E, - 0x1B, 0x81, 0x28, 0x05, 0x02, 0x4C, 0x1C, 0x81, 0x3A, 0x34, 0x48, 0x34, - 0x04, 0x6C, 0x4A, 0x01, 0x01, 0x81, 0x3C, 0x01, 0x00, 0x81, 0x3C, 0x02, - 0x00, 0x06, 0x81, 0x47, 0x02, 0x00, 0x81, 0x3A, 0x81, 0x08, 0x06, 0x12, - 0x01, 0x83, 0xFE, 0x01, 0x81, 0x3A, 0x6E, 0x81, 0x08, 0x01, 0x04, 0x09, - 0x1B, 0x81, 0x3A, 0x47, 0x81, 0x37, 0x81, 0x0A, 0x06, 0x1C, 0x01, 0x00, - 0x81, 0x3A, 0x6F, 0x81, 0x0A, 0x01, 0x04, 0x09, 0x1B, 0x81, 0x3A, 0x01, - 0x02, 0x09, 0x1B, 0x81, 0x3A, 0x01, 0x00, 0x81, 0x3C, 0x01, 0x03, 0x09, - 0x81, 0x36, 0x81, 0x06, 0x06, 0x0F, 0x01, 0x01, 0x81, 0x3A, 0x01, 0x01, - 0x81, 0x3A, 0x68, 0x20, 0x01, 0x08, 0x09, 0x81, 0x3C, 0x81, 0x09, 0x06, - 0x1F, 0x01, 0x0D, 0x81, 0x3A, 0x81, 0x09, 0x01, 0x04, 0x09, 0x1B, 0x81, - 0x3A, 0x01, 0x02, 0x09, 0x81, 0x3A, 0x32, 0x06, 0x04, 0x01, 0x03, 0x81, - 0x39, 0x33, 0x06, 0x04, 0x01, 0x01, 0x81, 0x39, 0x81, 0x0B, 0x1B, 0x06, - 0x27, 0x01, 0x0A, 0x81, 0x3A, 0x01, 0x04, 0x09, 0x1B, 0x81, 0x3A, 0x49, - 0x81, 0x3A, 0x30, 0x01, 0x00, 0x1B, 0x01, 0x20, 0x0A, 0x06, 0x0E, 0x81, - 0x04, 0x10, 0x01, 0x01, 0x11, 0x06, 0x03, 0x1B, 0x81, 0x3A, 0x46, 0x04, - 0x6C, 0x4A, 0x04, 0x01, 0x1A, 0x81, 0x07, 0x06, 0x0D, 0x01, 0x0B, 0x81, - 0x3A, 0x01, 0x02, 0x81, 0x3A, 0x01, 0x82, 0x00, 0x81, 0x3A, 0x02, 0x01, - 0x42, 0x05, 0x14, 0x01, 0x15, 0x81, 0x3A, 0x02, 0x01, 0x1B, 0x81, 0x3A, - 0x1B, 0x06, 0x07, 0x47, 0x01, 0x00, 0x81, 0x3C, 0x04, 0x76, 0x1A, 0x00, - 0x00, 0x01, 0x10, 0x81, 0x3C, 0x61, 0x1E, 0x1B, 0x81, 0x2C, 0x06, 0x10, - 0x81, 0x0F, 0x19, 0x1B, 0x48, 0x81, 0x3B, 0x1B, 0x81, 0x3A, 0x6A, 0x34, - 0x81, 0x35, 0x04, 0x12, 0x1B, 0x81, 0x2A, 0x34, 0x81, 0x0F, 0x18, 0x1B, - 0x46, 0x81, 0x3B, 0x1B, 0x81, 0x3C, 0x6A, 0x34, 0x81, 0x35, 0x00, 0x00, - 0x81, 0x00, 0x01, 0x14, 0x81, 0x3C, 0x01, 0x0C, 0x81, 0x3B, 0x6A, 0x01, - 0x0C, 0x81, 0x35, 0x00, 0x00, 0x3B, 0x1B, 0x01, 0x00, 0x0D, 0x06, 0x02, - 0x4A, 0x00, 0x81, 0x2D, 0x1A, 0x04, 0x72, 0x00, 0x1B, 0x81, 0x3A, 0x81, - 0x35, 0x00, 0x00, 0x1B, 0x81, 0x3C, 0x81, 0x35, 0x00, 0x00, 0x01, 0x0B, - 0x81, 0x3C, 0x01, 0x03, 0x81, 0x3B, 0x01, 0x00, 0x81, 0x3B, 0x00, 0x01, - 0x03, 0x00, 0x31, 0x1A, 0x1B, 0x01, 0x10, 0x11, 0x06, 0x08, 0x01, 0x04, - 0x81, 0x3C, 0x02, 0x00, 0x81, 0x3C, 0x1B, 0x01, 0x08, 0x11, 0x06, 0x08, - 0x01, 0x03, 0x81, 0x3C, 0x02, 0x00, 0x81, 0x3C, 0x1B, 0x01, 0x20, 0x11, - 0x06, 0x08, 0x01, 0x05, 0x81, 0x3C, 0x02, 0x00, 0x81, 0x3C, 0x1B, 0x01, - 0x80, 0x40, 0x11, 0x06, 0x08, 0x01, 0x06, 0x81, 0x3C, 0x02, 0x00, 0x81, - 0x3C, 0x01, 0x04, 0x11, 0x06, 0x08, 0x01, 0x02, 0x81, 0x3C, 0x02, 0x00, - 0x81, 0x3C, 0x00, 0x00, 0x1B, 0x01, 0x08, 0x39, 0x81, 0x3C, 0x81, 0x3C, - 0x00, 0x00, 0x1B, 0x01, 0x10, 0x39, 0x81, 0x3C, 0x81, 0x3A, 0x00, 0x00, - 0x1B, 0x3C, 0x06, 0x02, 0x1A, 0x00, 0x81, 0x2D, 0x1A, 0x04, 0x75 + 0x41, 0x24, 0x00, 0x00, 0x7A, 0x2C, 0x01, 0x0E, 0x0E, 0x06, 0x04, 0x01, + 0x00, 0x04, 0x02, 0x01, 0x05, 0x00, 0x00, 0x3D, 0x06, 0x04, 0x01, 0x06, + 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x7F, 0x2C, 0x25, 0x06, 0x08, 0x01, + 0x01, 0x09, 0x01, 0x11, 0x07, 0x04, 0x03, 0x24, 0x01, 0x05, 0x00, 0x01, + 0x3E, 0x03, 0x00, 0x24, 0x01, 0x00, 0x40, 0x06, 0x03, 0x02, 0x00, 0x08, + 0x3F, 0x06, 0x03, 0x02, 0x00, 0x08, 0x25, 0x06, 0x06, 0x01, 0x01, 0x0B, + 0x01, 0x06, 0x08, 0x00, 0x00, 0x81, 0x01, 0x3C, 0x25, 0x06, 0x03, 0x01, + 0x09, 0x08, 0x00, 0x01, 0x3D, 0x25, 0x06, 0x1E, 0x01, 0x00, 0x03, 0x00, + 0x25, 0x06, 0x0E, 0x25, 0x01, 0x01, 0x17, 0x02, 0x00, 0x08, 0x03, 0x00, + 0x01, 0x01, 0x11, 0x04, 0x6F, 0x24, 0x02, 0x00, 0x01, 0x01, 0x0B, 0x01, + 0x06, 0x08, 0x00, 0x00, 0x77, 0x2B, 0x41, 0x11, 0x01, 0x01, 0x17, 0x33, + 0x00, 0x00, 0x81, 0x15, 0x81, 0x42, 0x25, 0x01, 0x07, 0x17, 0x01, 0x00, + 0x36, 0x0E, 0x06, 0x0A, 0x24, 0x01, 0x10, 0x17, 0x06, 0x02, 0x81, 0x15, + 0x04, 0x32, 0x01, 0x01, 0x36, 0x0E, 0x06, 0x29, 0x24, 0x24, 0x01, 0x00, + 0x6F, 0x3B, 0x81, 0x28, 0x7F, 0x2C, 0x01, 0x01, 0x0E, 0x01, 0x01, 0x81, + 0x1E, 0x35, 0x06, 0x11, 0x27, 0x1A, 0x34, 0x06, 0x05, 0x81, 0x42, 0x24, + 0x04, 0x77, 0x01, 0x80, 0x64, 0x81, 0x3A, 0x04, 0x02, 0x81, 0x15, 0x04, + 0x03, 0x6A, 0x26, 0x24, 0x04, 0xFF, 0x35, 0x01, 0x25, 0x03, 0x00, 0x09, + 0x25, 0x50, 0x06, 0x02, 0x60, 0x26, 0x02, 0x00, 0x00, 0x00, 0x81, 0x10, + 0x01, 0x0F, 0x17, 0x00, 0x00, 0x6E, 0x2C, 0x01, 0x00, 0x36, 0x0E, 0x06, + 0x10, 0x24, 0x25, 0x01, 0x01, 0x0D, 0x06, 0x03, 0x24, 0x01, 0x02, 0x6E, + 0x3B, 0x01, 0x00, 0x04, 0x22, 0x01, 0x01, 0x36, 0x0E, 0x06, 0x15, 0x24, + 0x01, 0x00, 0x6E, 0x3B, 0x25, 0x01, 0x80, 0x64, 0x0E, 0x06, 0x05, 0x01, + 0x82, 0x00, 0x08, 0x26, 0x52, 0x00, 0x04, 0x07, 0x24, 0x01, 0x82, 0x00, + 0x08, 0x26, 0x24, 0x00, 0x00, 0x01, 0x00, 0x2D, 0x06, 0x06, 0x38, 0x81, + 0x22, 0x35, 0x04, 0x77, 0x25, 0x06, 0x05, 0x01, 0x01, 0x81, 0x05, 0x3B, + 0x00, 0x00, 0x2D, 0x06, 0x0B, 0x7D, 0x2C, 0x01, 0x14, 0x0D, 0x06, 0x02, + 0x6A, 0x26, 0x04, 0x12, 0x81, 0x42, 0x01, 0x07, 0x17, 0x25, 0x01, 0x02, + 0x0D, 0x06, 0x06, 0x06, 0x02, 0x6A, 0x26, 0x04, 0x6F, 0x24, 0x81, 0x37, + 0x01, 0x01, 0x0D, 0x31, 0x35, 0x06, 0x02, 0x59, 0x26, 0x25, 0x01, 0x01, + 0x81, 0x3D, 0x34, 0x81, 0x27, 0x00, 0x01, 0x81, 0x2D, 0x01, 0x0B, 0x0E, + 0x05, 0x02, 0x6A, 0x26, 0x25, 0x01, 0x03, 0x0E, 0x06, 0x09, 0x81, 0x35, + 0x06, 0x02, 0x60, 0x26, 0x41, 0x24, 0x00, 0x41, 0x4F, 0x81, 0x35, 0x81, + 0x20, 0x25, 0x06, 0x27, 0x81, 0x35, 0x81, 0x20, 0x25, 0x4E, 0x25, 0x06, + 0x19, 0x25, 0x01, 0x82, 0x00, 0x0F, 0x06, 0x05, 0x01, 0x82, 0x00, 0x04, + 0x01, 0x25, 0x03, 0x00, 0x7C, 0x02, 0x00, 0x81, 0x2B, 0x02, 0x00, 0x4B, + 0x04, 0x64, 0x81, 0x11, 0x4C, 0x04, 0x56, 0x81, 0x11, 0x81, 0x11, 0x4D, + 0x25, 0x06, 0x02, 0x33, 0x00, 0x24, 0x29, 0x00, 0x00, 0x71, 0x2A, 0x81, + 0x17, 0x01, 0x7F, 0x81, 0x25, 0x25, 0x50, 0x06, 0x02, 0x33, 0x26, 0x25, + 0x05, 0x02, 0x6A, 0x26, 0x36, 0x17, 0x0D, 0x06, 0x02, 0x6C, 0x26, 0x39, + 0x00, 0x00, 0x81, 0x12, 0x81, 0x2D, 0x01, 0x14, 0x0D, 0x06, 0x02, 0x6A, + 0x26, 0x7C, 0x01, 0x0C, 0x08, 0x01, 0x0C, 0x81, 0x2B, 0x81, 0x11, 0x7C, + 0x25, 0x01, 0x0C, 0x08, 0x01, 0x0C, 0x2E, 0x05, 0x02, 0x5C, 0x26, 0x00, + 0x00, 0x81, 0x2E, 0x06, 0x02, 0x6A, 0x26, 0x06, 0x02, 0x5E, 0x26, 0x00, + 0x09, 0x81, 0x2D, 0x01, 0x02, 0x0E, 0x05, 0x02, 0x6A, 0x26, 0x81, 0x34, + 0x03, 0x00, 0x02, 0x00, 0x81, 0x0B, 0x2A, 0x0A, 0x02, 0x00, 0x81, 0x0A, + 0x2A, 0x0F, 0x35, 0x06, 0x02, 0x6B, 0x26, 0x02, 0x00, 0x81, 0x09, 0x2A, + 0x0D, 0x06, 0x02, 0x63, 0x26, 0x02, 0x00, 0x81, 0x0C, 0x3A, 0x81, 0x02, + 0x01, 0x20, 0x81, 0x2B, 0x01, 0x00, 0x03, 0x01, 0x81, 0x36, 0x03, 0x02, + 0x02, 0x02, 0x01, 0x20, 0x0F, 0x06, 0x02, 0x68, 0x26, 0x7C, 0x02, 0x02, + 0x81, 0x2B, 0x02, 0x02, 0x81, 0x04, 0x2C, 0x0E, 0x02, 0x02, 0x01, 0x00, + 0x0F, 0x17, 0x06, 0x0C, 0x81, 0x03, 0x7C, 0x02, 0x02, 0x2E, 0x06, 0x04, + 0x01, 0x7F, 0x03, 0x01, 0x81, 0x03, 0x7C, 0x02, 0x02, 0x2F, 0x02, 0x02, + 0x81, 0x04, 0x3B, 0x02, 0x00, 0x81, 0x08, 0x02, 0x01, 0x81, 0x0E, 0x81, + 0x34, 0x25, 0x81, 0x38, 0x50, 0x06, 0x02, 0x5A, 0x26, 0x71, 0x02, 0x01, + 0x81, 0x0E, 0x81, 0x36, 0x06, 0x02, 0x5B, 0x26, 0x25, 0x06, 0x81, 0x3E, + 0x81, 0x34, 0x81, 0x20, 0x81, 0x1C, 0x03, 0x03, 0x81, 0x1A, 0x03, 0x04, + 0x81, 0x18, 0x03, 0x05, 0x81, 0x1B, 0x03, 0x06, 0x81, 0x1D, 0x03, 0x07, + 0x81, 0x19, 0x03, 0x08, 0x25, 0x06, 0x81, 0x0B, 0x81, 0x34, 0x01, 0x00, + 0x36, 0x0E, 0x06, 0x10, 0x24, 0x02, 0x03, 0x05, 0x02, 0x64, 0x26, 0x01, + 0x00, 0x03, 0x03, 0x81, 0x33, 0x04, 0x80, 0x70, 0x01, 0x01, 0x36, 0x0E, + 0x06, 0x10, 0x24, 0x02, 0x05, 0x05, 0x02, 0x64, 0x26, 0x01, 0x00, 0x03, + 0x05, 0x81, 0x31, 0x04, 0x80, 0x5A, 0x01, 0x83, 0xFE, 0x01, 0x36, 0x0E, + 0x06, 0x10, 0x24, 0x02, 0x04, 0x05, 0x02, 0x64, 0x26, 0x01, 0x00, 0x03, + 0x04, 0x81, 0x32, 0x04, 0x80, 0x42, 0x01, 0x0D, 0x36, 0x0E, 0x06, 0x0F, + 0x24, 0x02, 0x06, 0x05, 0x02, 0x64, 0x26, 0x01, 0x00, 0x03, 0x06, 0x81, + 0x2F, 0x04, 0x2D, 0x01, 0x0A, 0x36, 0x0E, 0x06, 0x0F, 0x24, 0x02, 0x07, + 0x05, 0x02, 0x64, 0x26, 0x01, 0x00, 0x03, 0x07, 0x81, 0x2F, 0x04, 0x18, + 0x01, 0x0B, 0x36, 0x0E, 0x06, 0x0F, 0x24, 0x02, 0x08, 0x05, 0x02, 0x64, + 0x26, 0x01, 0x00, 0x03, 0x08, 0x81, 0x2F, 0x04, 0x03, 0x64, 0x26, 0x24, + 0x04, 0xFE, 0x71, 0x02, 0x04, 0x06, 0x0D, 0x02, 0x04, 0x01, 0x05, 0x0F, + 0x06, 0x02, 0x61, 0x26, 0x01, 0x01, 0x7F, 0x3B, 0x81, 0x11, 0x81, 0x11, + 0x02, 0x01, 0x00, 0x04, 0x81, 0x2D, 0x01, 0x0C, 0x0E, 0x05, 0x02, 0x6A, + 0x26, 0x81, 0x36, 0x01, 0x03, 0x0E, 0x05, 0x02, 0x65, 0x26, 0x81, 0x34, + 0x25, 0x74, 0x3B, 0x25, 0x01, 0x20, 0x10, 0x06, 0x02, 0x65, 0x26, 0x3D, + 0x41, 0x11, 0x01, 0x01, 0x17, 0x05, 0x02, 0x65, 0x26, 0x81, 0x36, 0x25, + 0x01, 0x81, 0x05, 0x0F, 0x06, 0x02, 0x65, 0x26, 0x25, 0x76, 0x3B, 0x75, + 0x41, 0x81, 0x2B, 0x81, 0x08, 0x2A, 0x01, 0x86, 0x03, 0x10, 0x03, 0x00, + 0x71, 0x2A, 0x81, 0x40, 0x03, 0x01, 0x01, 0x02, 0x03, 0x02, 0x02, 0x00, + 0x06, 0x23, 0x81, 0x36, 0x25, 0x25, 0x01, 0x02, 0x0A, 0x41, 0x01, 0x06, + 0x0F, 0x35, 0x06, 0x02, 0x65, 0x26, 0x03, 0x02, 0x81, 0x36, 0x02, 0x01, + 0x01, 0x01, 0x0B, 0x01, 0x03, 0x08, 0x0E, 0x05, 0x02, 0x65, 0x26, 0x04, + 0x08, 0x02, 0x01, 0x06, 0x04, 0x01, 0x00, 0x03, 0x02, 0x81, 0x34, 0x25, + 0x03, 0x03, 0x25, 0x01, 0x84, 0x00, 0x0F, 0x06, 0x02, 0x66, 0x26, 0x7C, + 0x41, 0x81, 0x2B, 0x02, 0x02, 0x02, 0x01, 0x02, 0x03, 0x48, 0x25, 0x06, + 0x01, 0x26, 0x24, 0x81, 0x11, 0x00, 0x02, 0x03, 0x00, 0x03, 0x01, 0x02, + 0x00, 0x81, 0x0D, 0x02, 0x01, 0x02, 0x00, 0x37, 0x25, 0x01, 0x00, 0x0E, + 0x06, 0x02, 0x58, 0x00, 0x81, 0x44, 0x04, 0x73, 0x02, 0x01, 0x00, 0x03, + 0x00, 0x81, 0x36, 0x81, 0x20, 0x25, 0x06, 0x80, 0x44, 0x81, 0x36, 0x01, + 0x01, 0x36, 0x0E, 0x06, 0x06, 0x24, 0x01, 0x81, 0x7F, 0x04, 0x2E, 0x01, + 0x80, 0x40, 0x36, 0x0E, 0x06, 0x07, 0x24, 0x01, 0x83, 0xFE, 0x00, 0x04, + 0x20, 0x01, 0x80, 0x41, 0x36, 0x0E, 0x06, 0x07, 0x24, 0x01, 0x84, 0x80, + 0x00, 0x04, 0x12, 0x01, 0x80, 0x42, 0x36, 0x0E, 0x06, 0x07, 0x24, 0x01, + 0x88, 0x80, 0x00, 0x04, 0x04, 0x01, 0x00, 0x41, 0x24, 0x02, 0x00, 0x35, + 0x03, 0x00, 0x04, 0xFF, 0x38, 0x81, 0x11, 0x71, 0x2A, 0x81, 0x3E, 0x05, + 0x09, 0x02, 0x00, 0x01, 0x83, 0xFF, 0x7F, 0x17, 0x03, 0x00, 0x81, 0x08, + 0x2A, 0x01, 0x86, 0x03, 0x10, 0x06, 0x3B, 0x81, 0x30, 0x25, 0x79, 0x3A, + 0x3E, 0x24, 0x25, 0x01, 0x08, 0x0B, 0x35, 0x01, 0x8C, 0x80, 0x00, 0x35, + 0x17, 0x02, 0x00, 0x17, 0x02, 0x00, 0x01, 0x8C, 0x80, 0x00, 0x17, 0x06, + 0x19, 0x25, 0x01, 0x81, 0x7F, 0x17, 0x06, 0x05, 0x01, 0x84, 0x80, 0x00, + 0x35, 0x25, 0x01, 0x83, 0xFE, 0x00, 0x17, 0x06, 0x05, 0x01, 0x88, 0x80, + 0x00, 0x35, 0x03, 0x00, 0x04, 0x09, 0x02, 0x00, 0x01, 0x8C, 0x88, 0x01, + 0x17, 0x03, 0x00, 0x16, 0x81, 0x34, 0x81, 0x20, 0x25, 0x06, 0x27, 0x81, + 0x34, 0x81, 0x20, 0x25, 0x15, 0x25, 0x06, 0x19, 0x25, 0x01, 0x82, 0x00, + 0x0F, 0x06, 0x05, 0x01, 0x82, 0x00, 0x04, 0x01, 0x25, 0x03, 0x01, 0x7C, + 0x02, 0x01, 0x81, 0x2B, 0x02, 0x01, 0x12, 0x04, 0x64, 0x81, 0x11, 0x13, + 0x04, 0x56, 0x81, 0x11, 0x14, 0x81, 0x11, 0x02, 0x00, 0x28, 0x00, 0x00, + 0x81, 0x2E, 0x25, 0x52, 0x06, 0x07, 0x24, 0x06, 0x02, 0x5E, 0x26, 0x04, + 0x73, 0x00, 0x00, 0x81, 0x37, 0x01, 0x03, 0x81, 0x35, 0x41, 0x24, 0x41, + 0x00, 0x00, 0x81, 0x34, 0x81, 0x3B, 0x00, 0x03, 0x01, 0x00, 0x03, 0x00, + 0x81, 0x34, 0x81, 0x20, 0x25, 0x06, 0x34, 0x81, 0x36, 0x03, 0x01, 0x81, + 0x36, 0x03, 0x02, 0x02, 0x01, 0x01, 0x02, 0x10, 0x02, 0x01, 0x01, 0x06, + 0x0C, 0x17, 0x02, 0x02, 0x01, 0x01, 0x0E, 0x02, 0x02, 0x01, 0x03, 0x0E, + 0x35, 0x17, 0x06, 0x11, 0x02, 0x00, 0x01, 0x01, 0x02, 0x02, 0x55, 0x01, + 0x02, 0x0B, 0x02, 0x01, 0x08, 0x0B, 0x35, 0x03, 0x00, 0x04, 0x49, 0x81, + 0x11, 0x02, 0x00, 0x00, 0x00, 0x81, 0x34, 0x01, 0x01, 0x0E, 0x05, 0x02, + 0x5D, 0x26, 0x81, 0x36, 0x01, 0x08, 0x08, 0x7A, 0x2C, 0x0E, 0x05, 0x02, + 0x5D, 0x26, 0x00, 0x00, 0x81, 0x34, 0x7F, 0x2C, 0x05, 0x16, 0x01, 0x01, + 0x0E, 0x05, 0x02, 0x61, 0x26, 0x81, 0x36, 0x01, 0x00, 0x0E, 0x05, 0x02, + 0x61, 0x26, 0x01, 0x02, 0x7F, 0x3B, 0x04, 0x1F, 0x01, 0x19, 0x0E, 0x05, + 0x02, 0x61, 0x26, 0x81, 0x36, 0x01, 0x18, 0x0E, 0x05, 0x02, 0x61, 0x26, + 0x7C, 0x01, 0x18, 0x81, 0x2B, 0x81, 0x00, 0x7C, 0x01, 0x18, 0x2E, 0x05, + 0x02, 0x61, 0x26, 0x00, 0x00, 0x81, 0x34, 0x06, 0x02, 0x62, 0x26, 0x00, + 0x00, 0x01, 0x02, 0x81, 0x0D, 0x81, 0x37, 0x01, 0x08, 0x0B, 0x81, 0x37, + 0x08, 0x00, 0x00, 0x01, 0x03, 0x81, 0x0D, 0x81, 0x37, 0x01, 0x08, 0x0B, + 0x81, 0x37, 0x08, 0x01, 0x08, 0x0B, 0x81, 0x37, 0x08, 0x00, 0x00, 0x01, + 0x01, 0x81, 0x0D, 0x81, 0x37, 0x00, 0x00, 0x38, 0x25, 0x50, 0x05, 0x01, + 0x00, 0x24, 0x81, 0x44, 0x04, 0x75, 0x02, 0x03, 0x00, 0x81, 0x07, 0x2C, + 0x03, 0x01, 0x01, 0x00, 0x25, 0x02, 0x01, 0x0A, 0x06, 0x11, 0x25, 0x01, + 0x01, 0x0B, 0x81, 0x06, 0x08, 0x2A, 0x02, 0x00, 0x0E, 0x06, 0x01, 0x00, + 0x54, 0x04, 0x69, 0x24, 0x01, 0x7F, 0x00, 0x00, 0x01, 0x15, 0x7E, 0x3B, + 0x41, 0x4A, 0x24, 0x4A, 0x24, 0x27, 0x00, 0x00, 0x01, 0x01, 0x41, 0x81, + 0x39, 0x00, 0x00, 0x41, 0x36, 0x81, 0x0D, 0x41, 0x25, 0x06, 0x06, 0x81, + 0x37, 0x24, 0x55, 0x04, 0x77, 0x24, 0x00, 0x00, 0x25, 0x01, 0x81, 0xAC, + 0x00, 0x0E, 0x06, 0x04, 0x24, 0x01, 0x7F, 0x00, 0x81, 0x10, 0x51, 0x00, + 0x02, 0x03, 0x00, 0x71, 0x2A, 0x81, 0x10, 0x03, 0x01, 0x02, 0x01, 0x01, + 0x0F, 0x17, 0x02, 0x01, 0x01, 0x04, 0x11, 0x01, 0x0F, 0x17, 0x02, 0x01, + 0x01, 0x08, 0x11, 0x01, 0x0F, 0x17, 0x01, 0x00, 0x36, 0x0E, 0x06, 0x10, + 0x24, 0x01, 0x00, 0x01, 0x18, 0x02, 0x00, 0x06, 0x03, 0x44, 0x04, 0x01, + 0x45, 0x04, 0x80, 0x56, 0x01, 0x01, 0x36, 0x0E, 0x06, 0x10, 0x24, 0x01, + 0x01, 0x01, 0x10, 0x02, 0x00, 0x06, 0x03, 0x44, 0x04, 0x01, 0x45, 0x04, + 0x80, 0x40, 0x01, 0x02, 0x36, 0x0E, 0x06, 0x0F, 0x24, 0x01, 0x01, 0x01, + 0x20, 0x02, 0x00, 0x06, 0x03, 0x44, 0x04, 0x01, 0x45, 0x04, 0x2B, 0x01, + 0x03, 0x36, 0x0E, 0x06, 0x0E, 0x24, 0x24, 0x01, 0x10, 0x02, 0x00, 0x06, + 0x03, 0x42, 0x04, 0x01, 0x43, 0x04, 0x17, 0x01, 0x04, 0x36, 0x0E, 0x06, + 0x0E, 0x24, 0x24, 0x01, 0x20, 0x02, 0x00, 0x06, 0x03, 0x42, 0x04, 0x01, + 0x43, 0x04, 0x03, 0x60, 0x26, 0x24, 0x00, 0x00, 0x81, 0x10, 0x01, 0x0C, + 0x11, 0x01, 0x02, 0x0F, 0x00, 0x00, 0x81, 0x10, 0x01, 0x0C, 0x11, 0x25, + 0x53, 0x41, 0x01, 0x03, 0x0A, 0x17, 0x00, 0x00, 0x81, 0x10, 0x01, 0x0C, + 0x11, 0x01, 0x01, 0x0E, 0x00, 0x00, 0x81, 0x10, 0x01, 0x0C, 0x11, 0x52, + 0x00, 0x00, 0x1B, 0x01, 0x00, 0x6D, 0x2C, 0x25, 0x06, 0x20, 0x01, 0x01, + 0x36, 0x0E, 0x06, 0x07, 0x24, 0x01, 0x00, 0x81, 0x14, 0x04, 0x11, 0x01, + 0x02, 0x36, 0x0E, 0x06, 0x0A, 0x24, 0x6F, 0x2C, 0x06, 0x03, 0x01, 0x10, + 0x35, 0x04, 0x01, 0x24, 0x04, 0x01, 0x24, 0x73, 0x2C, 0x05, 0x35, 0x2D, + 0x06, 0x32, 0x7D, 0x2C, 0x01, 0x14, 0x36, 0x0E, 0x06, 0x06, 0x24, 0x01, + 0x02, 0x35, 0x04, 0x24, 0x01, 0x15, 0x36, 0x0E, 0x06, 0x0B, 0x24, 0x81, + 0x23, 0x06, 0x04, 0x01, 0x7F, 0x81, 0x14, 0x04, 0x13, 0x01, 0x16, 0x36, + 0x0E, 0x06, 0x06, 0x24, 0x01, 0x01, 0x35, 0x04, 0x07, 0x24, 0x01, 0x04, + 0x35, 0x01, 0x00, 0x24, 0x1A, 0x06, 0x03, 0x01, 0x08, 0x35, 0x00, 0x00, + 0x1B, 0x25, 0x05, 0x10, 0x2D, 0x06, 0x0D, 0x7D, 0x2C, 0x01, 0x15, 0x0E, + 0x06, 0x05, 0x24, 0x81, 0x23, 0x04, 0x01, 0x1F, 0x00, 0x00, 0x81, 0x42, + 0x01, 0x07, 0x17, 0x01, 0x01, 0x0F, 0x06, 0x02, 0x6A, 0x26, 0x00, 0x01, + 0x03, 0x00, 0x27, 0x1A, 0x06, 0x05, 0x02, 0x00, 0x7E, 0x3B, 0x00, 0x81, + 0x42, 0x24, 0x04, 0x73, 0x00, 0x01, 0x14, 0x81, 0x45, 0x01, 0x01, 0x81, + 0x52, 0x27, 0x25, 0x01, 0x00, 0x81, 0x3D, 0x01, 0x16, 0x81, 0x45, 0x81, + 0x4B, 0x27, 0x00, 0x00, 0x01, 0x0B, 0x81, 0x52, 0x46, 0x25, 0x25, 0x01, + 0x03, 0x08, 0x81, 0x51, 0x81, 0x51, 0x18, 0x25, 0x50, 0x06, 0x02, 0x24, + 0x00, 0x81, 0x51, 0x1D, 0x25, 0x06, 0x06, 0x7C, 0x41, 0x81, 0x4C, 0x04, + 0x76, 0x24, 0x04, 0x6A, 0x00, 0x20, 0x01, 0x0F, 0x81, 0x52, 0x25, 0x81, + 0x08, 0x2A, 0x01, 0x86, 0x03, 0x10, 0x06, 0x0F, 0x01, 0x04, 0x08, 0x81, + 0x51, 0x78, 0x2C, 0x81, 0x52, 0x70, 0x2C, 0x81, 0x52, 0x04, 0x03, 0x56, + 0x81, 0x51, 0x25, 0x81, 0x50, 0x7C, 0x41, 0x81, 0x4C, 0x00, 0x02, 0x81, + 0x1A, 0x81, 0x1C, 0x08, 0x81, 0x18, 0x08, 0x81, 0x1B, 0x08, 0x81, 0x1D, + 0x08, 0x81, 0x19, 0x08, 0x03, 0x00, 0x01, 0x01, 0x81, 0x52, 0x01, 0x27, + 0x81, 0x04, 0x2C, 0x08, 0x81, 0x07, 0x2C, 0x01, 0x01, 0x0B, 0x08, 0x02, + 0x00, 0x06, 0x04, 0x56, 0x02, 0x00, 0x08, 0x7B, 0x2A, 0x36, 0x09, 0x25, + 0x53, 0x06, 0x24, 0x02, 0x00, 0x05, 0x04, 0x41, 0x56, 0x41, 0x57, 0x01, + 0x04, 0x09, 0x25, 0x50, 0x06, 0x03, 0x24, 0x01, 0x00, 0x25, 0x01, 0x04, + 0x08, 0x02, 0x00, 0x08, 0x03, 0x00, 0x41, 0x01, 0x04, 0x08, 0x36, 0x08, + 0x41, 0x04, 0x03, 0x24, 0x01, 0x7F, 0x03, 0x01, 0x81, 0x51, 0x81, 0x0A, + 0x2A, 0x81, 0x50, 0x72, 0x01, 0x04, 0x19, 0x72, 0x01, 0x04, 0x08, 0x01, + 0x1C, 0x30, 0x72, 0x01, 0x20, 0x81, 0x4C, 0x81, 0x03, 0x81, 0x04, 0x2C, + 0x81, 0x4E, 0x81, 0x07, 0x2C, 0x25, 0x01, 0x01, 0x0B, 0x81, 0x50, 0x81, + 0x06, 0x41, 0x25, 0x06, 0x11, 0x55, 0x36, 0x2A, 0x25, 0x81, 0x3C, 0x05, + 0x02, 0x5A, 0x26, 0x81, 0x50, 0x41, 0x56, 0x41, 0x04, 0x6C, 0x58, 0x01, + 0x01, 0x81, 0x52, 0x01, 0x00, 0x81, 0x52, 0x02, 0x00, 0x06, 0x81, 0x49, + 0x02, 0x00, 0x81, 0x50, 0x81, 0x1A, 0x06, 0x13, 0x01, 0x83, 0xFE, 0x01, + 0x81, 0x50, 0x81, 0x00, 0x81, 0x1A, 0x01, 0x04, 0x09, 0x25, 0x81, 0x50, + 0x55, 0x81, 0x4E, 0x81, 0x1C, 0x06, 0x1D, 0x01, 0x00, 0x81, 0x50, 0x81, + 0x01, 0x81, 0x1C, 0x01, 0x04, 0x09, 0x25, 0x81, 0x50, 0x01, 0x02, 0x09, + 0x25, 0x81, 0x50, 0x01, 0x00, 0x81, 0x52, 0x01, 0x03, 0x09, 0x81, 0x4D, + 0x81, 0x18, 0x06, 0x0F, 0x01, 0x01, 0x81, 0x50, 0x01, 0x01, 0x81, 0x50, + 0x7A, 0x2C, 0x01, 0x08, 0x09, 0x81, 0x52, 0x81, 0x1B, 0x06, 0x1F, 0x01, + 0x0D, 0x81, 0x50, 0x81, 0x1B, 0x01, 0x04, 0x09, 0x25, 0x81, 0x50, 0x01, + 0x02, 0x09, 0x81, 0x50, 0x3F, 0x06, 0x04, 0x01, 0x03, 0x81, 0x4F, 0x40, + 0x06, 0x04, 0x01, 0x01, 0x81, 0x4F, 0x81, 0x1D, 0x25, 0x06, 0x27, 0x01, + 0x0A, 0x81, 0x50, 0x01, 0x04, 0x09, 0x25, 0x81, 0x50, 0x57, 0x81, 0x50, + 0x3D, 0x01, 0x00, 0x25, 0x01, 0x20, 0x0A, 0x06, 0x0E, 0x81, 0x16, 0x11, + 0x01, 0x01, 0x17, 0x06, 0x03, 0x25, 0x81, 0x50, 0x54, 0x04, 0x6C, 0x58, + 0x04, 0x01, 0x24, 0x81, 0x19, 0x06, 0x0D, 0x01, 0x0B, 0x81, 0x50, 0x01, + 0x02, 0x81, 0x50, 0x01, 0x82, 0x00, 0x81, 0x50, 0x02, 0x01, 0x50, 0x05, + 0x14, 0x01, 0x15, 0x81, 0x50, 0x02, 0x01, 0x25, 0x81, 0x50, 0x25, 0x06, + 0x07, 0x55, 0x01, 0x00, 0x81, 0x52, 0x04, 0x76, 0x24, 0x00, 0x00, 0x01, + 0x10, 0x81, 0x52, 0x71, 0x2A, 0x25, 0x81, 0x41, 0x06, 0x10, 0x81, 0x21, + 0x22, 0x25, 0x56, 0x81, 0x51, 0x25, 0x81, 0x50, 0x7C, 0x41, 0x81, 0x4C, + 0x04, 0x12, 0x25, 0x81, 0x3F, 0x41, 0x81, 0x21, 0x21, 0x25, 0x54, 0x81, + 0x51, 0x25, 0x81, 0x52, 0x7C, 0x41, 0x81, 0x4C, 0x00, 0x00, 0x81, 0x12, + 0x01, 0x14, 0x81, 0x52, 0x01, 0x0C, 0x81, 0x51, 0x7C, 0x01, 0x0C, 0x81, + 0x4C, 0x00, 0x00, 0x49, 0x25, 0x01, 0x00, 0x0E, 0x06, 0x02, 0x58, 0x00, + 0x81, 0x42, 0x24, 0x04, 0x72, 0x00, 0x25, 0x81, 0x50, 0x81, 0x4C, 0x00, + 0x00, 0x25, 0x81, 0x52, 0x81, 0x4C, 0x00, 0x01, 0x03, 0x00, 0x3E, 0x24, + 0x25, 0x01, 0x10, 0x17, 0x06, 0x08, 0x01, 0x04, 0x81, 0x52, 0x02, 0x00, + 0x81, 0x52, 0x25, 0x01, 0x08, 0x17, 0x06, 0x08, 0x01, 0x03, 0x81, 0x52, + 0x02, 0x00, 0x81, 0x52, 0x25, 0x01, 0x20, 0x17, 0x06, 0x08, 0x01, 0x05, + 0x81, 0x52, 0x02, 0x00, 0x81, 0x52, 0x25, 0x01, 0x80, 0x40, 0x17, 0x06, + 0x08, 0x01, 0x06, 0x81, 0x52, 0x02, 0x00, 0x81, 0x52, 0x01, 0x04, 0x17, + 0x06, 0x08, 0x01, 0x02, 0x81, 0x52, 0x02, 0x00, 0x81, 0x52, 0x00, 0x00, + 0x25, 0x01, 0x08, 0x47, 0x81, 0x52, 0x81, 0x52, 0x00, 0x00, 0x25, 0x01, + 0x10, 0x47, 0x81, 0x52, 0x81, 0x50, 0x00, 0x00, 0x25, 0x4A, 0x06, 0x02, + 0x24, 0x00, 0x81, 0x42, 0x24, 0x04, 0x75 }; static const uint16_t t0_caddr[] = { @@ -670,103 +784,111 @@ static const uint16_t t0_caddr[] = { 112, 116, 120, - 125, - 130, - 135, - 140, - 145, - 150, - 155, - 160, - 165, - 170, - 175, - 180, - 185, - 190, - 195, - 200, - 205, - 210, - 215, - 220, - 225, - 230, - 235, - 240, - 245, - 250, - 255, - 260, - 265, + 124, + 129, + 134, + 139, + 144, + 149, + 154, + 159, + 164, + 169, + 174, + 179, + 184, + 189, + 194, + 199, + 204, + 209, + 214, + 219, + 224, + 229, + 234, + 239, + 244, + 249, + 254, + 259, + 264, + 269, 274, - 287, - 291, - 318, - 324, + 279, + 284, + 293, + 306, + 310, + 338, 344, - 355, - 392, - 495, - 499, - 564, - 579, - 590, - 608, - 637, - 647, - 683, - 693, - 771, - 785, - 791, - 851, - 871, - 924, - 993, - 1027, - 1039, - 1364, - 1521, - 1546, - 1557, - 1572, - 1583, - 1589, - 1612, - 1672, - 1680, - 1693, - 1712, - 1719, - 1731, - 1766, - 1778, - 1785, - 1801, - 1817, - 1955, - 1968, - 1977, - 1984, - 2090, - 2112, - 2126, - 2143, - 2166, - 2529, - 2576, - 2593, - 2608, - 2615, - 2622, - 2636, - 2712, - 2722, - 2732 + 365, + 376, + 413, + 548, + 552, + 618, + 633, + 644, + 662, + 691, + 702, + 738, + 748, + 826, + 840, + 847, + 907, + 928, + 981, + 1067, + 1096, + 1131, + 1143, + 1482, + 1641, + 1667, + 1898, + 1913, + 1924, + 1930, + 1999, + 2022, + 2083, + 2091, + 2105, + 2125, + 2133, + 2145, + 2182, + 2194, + 2201, + 2218, + 2235, + 2374, + 2384, + 2398, + 2408, + 2416, + 2522, + 2544, + 2558, + 2575, + 2598, + 2635, + 2677, + 3049, + 3096, + 3113, + 3128, + 3135, + 3142, + 3218, + 3228, + 3238 }; -#define T0_INTERPRETED 66 +#define T0_INTERPRETED 80 #define T0_ENTER(ip, rp, slot) do { \ const unsigned char *t0_newip; \ @@ -787,7 +909,7 @@ name(void *ctx) \ T0_ENTER(t0ctx->ip, t0ctx->rp, slot); \ } -T0_DEFENTRY(br_ssl_hs_client_init_main, 141) +T0_DEFENTRY(br_ssl_hs_client_init_main, 159) void br_ssl_hs_client_run(void *t0ctx) @@ -930,6 +1052,15 @@ br_ssl_hs_client_run(void *t0ctx) } break; case 12: { + /* <= */ + + int32_t b = T0_POPi(); + int32_t a = T0_POPi(); + T0_PUSH(-(uint32_t)(a <= b)); + + } + break; + case 13: { /* <> */ uint32_t b = T0_POP(); @@ -938,7 +1069,7 @@ br_ssl_hs_client_run(void *t0ctx) } break; - case 13: { + case 14: { /* = */ uint32_t b = T0_POP(); @@ -947,7 +1078,7 @@ br_ssl_hs_client_run(void *t0ctx) } break; - case 14: { + case 15: { /* > */ int32_t b = T0_POPi(); @@ -956,7 +1087,7 @@ br_ssl_hs_client_run(void *t0ctx) } break; - case 15: { + case 16: { /* >= */ int32_t b = T0_POPi(); @@ -965,7 +1096,7 @@ br_ssl_hs_client_run(void *t0ctx) } break; - case 16: { + case 17: { /* >> */ int c = (int)T0_POPi(); @@ -974,7 +1105,63 @@ br_ssl_hs_client_run(void *t0ctx) } break; - case 17: { + case 18: { + /* anchor-dn-append-name */ + + 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); + } + + } + break; + case 19: { + /* anchor-dn-end-name */ + + if (CTX->client_auth_vtable != NULL) { + (*CTX->client_auth_vtable)->end_name( + CTX->client_auth_vtable); + } + + } + break; + case 20: { + /* anchor-dn-end-name-list */ + + if (CTX->client_auth_vtable != NULL) { + (*CTX->client_auth_vtable)->end_name_list( + CTX->client_auth_vtable); + } + + } + break; + case 21: { + /* anchor-dn-start-name */ + + size_t len; + + len = T0_POP(); + if (CTX->client_auth_vtable != NULL) { + (*CTX->client_auth_vtable)->start_name( + CTX->client_auth_vtable, len); + } + + } + break; + case 22: { + /* anchor-dn-start-name-list */ + + if (CTX->client_auth_vtable != NULL) { + (*CTX->client_auth_vtable)->start_name_list( + CTX->client_auth_vtable); + } + + } + break; + case 23: { /* and */ uint32_t b = T0_POP(); @@ -983,7 +1170,22 @@ br_ssl_hs_client_run(void *t0ctx) } break; - case 18: { + case 24: { + /* begin-cert */ + + 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); + } + + } + break; + case 25: { /* bzero */ size_t len = (size_t)T0_POP(); @@ -992,19 +1194,19 @@ br_ssl_hs_client_run(void *t0ctx) } break; - case 19: { + case 26: { /* can-output? */ T0_PUSHi(-(ENG->hlen_out > 0)); } break; - case 20: { + case 27: { /* co */ T0_CO(); } break; - case 21: { + case 28: { /* compute-Finished-inner */ int prf_id = T0_POP(); @@ -1027,7 +1229,23 @@ br_ssl_hs_client_run(void *t0ctx) } break; - case 22: { + case 29: { + /* copy-cert-chunk */ + + 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); + + } + break; + case 30: { /* data-get8 */ size_t addr = T0_POP(); @@ -1035,14 +1253,28 @@ br_ssl_hs_client_run(void *t0ctx) } break; - case 23: { + case 31: { /* discard-input */ ENG->hlen_in = 0; } break; - case 24: { + case 32: { + /* do-client-sign */ + + 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); + + } + break; + case 33: { /* do-ecdh */ unsigned prf_id = T0_POP(); @@ -1059,7 +1291,7 @@ br_ssl_hs_client_run(void *t0ctx) } break; - case 25: { + case 34: { /* do-rsa-encrypt */ int x; @@ -1074,17 +1306,29 @@ br_ssl_hs_client_run(void *t0ctx) } break; - case 26: { + case 35: { + /* do-static-ecdh */ + + 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(); + } + + } + break; + case 36: { /* drop */ (void)T0_POP(); } break; - case 27: { + case 37: { /* dup */ T0_PUSH(T0_PEEK(0)); } break; - case 28: { + case 38: { /* fail */ br_ssl_engine_fail(ENG, (int)T0_POPi()); @@ -1092,14 +1336,53 @@ br_ssl_hs_client_run(void *t0ctx) } break; - case 29: { + case 39: { /* flush-record */ br_ssl_engine_flush_record(ENG); } break; - case 30: { + case 40: { + /* get-client-chain */ + + 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; + } + + } + break; + case 41: { + /* get-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); + } + + } + break; + case 42: { /* get16 */ size_t addr = (size_t)T0_POP(); @@ -1107,7 +1390,7 @@ br_ssl_hs_client_run(void *t0ctx) } break; - case 31: { + case 43: { /* get32 */ size_t addr = (size_t)T0_POP(); @@ -1115,7 +1398,7 @@ br_ssl_hs_client_run(void *t0ctx) } break; - case 32: { + case 44: { /* get8 */ size_t addr = (size_t)T0_POP(); @@ -1123,14 +1406,14 @@ br_ssl_hs_client_run(void *t0ctx) } break; - case 33: { + case 45: { /* has-input? */ T0_PUSHi(-(ENG->hlen_in != 0)); } break; - case 34: { + case 46: { /* memcmp */ size_t len = (size_t)T0_POP(); @@ -1141,7 +1424,7 @@ br_ssl_hs_client_run(void *t0ctx) } break; - case 35: { + case 47: { /* memcpy */ size_t len = (size_t)T0_POP(); @@ -1151,7 +1434,7 @@ br_ssl_hs_client_run(void *t0ctx) } break; - case 36: { + case 48: { /* mkrand */ size_t len = (size_t)T0_POP(); @@ -1160,21 +1443,21 @@ br_ssl_hs_client_run(void *t0ctx) } break; - case 37: { + case 49: { /* more-incoming-bytes? */ T0_PUSHi(ENG->hlen_in != 0 || !br_ssl_engine_recvrec_finished(ENG)); } break; - case 38: { + case 50: { /* multihash-init */ br_multihash_init(&ENG->mhash); } break; - case 39: { + case 51: { /* neg */ uint32_t a = T0_POP(); @@ -1182,7 +1465,7 @@ br_ssl_hs_client_run(void *t0ctx) } break; - case 40: { + case 52: { /* not */ uint32_t a = T0_POP(); @@ -1190,7 +1473,7 @@ br_ssl_hs_client_run(void *t0ctx) } break; - case 41: { + case 53: { /* or */ uint32_t b = T0_POP(); @@ -1199,12 +1482,12 @@ br_ssl_hs_client_run(void *t0ctx) } break; - case 42: { + case 54: { /* over */ T0_PUSH(T0_PEEK(1)); } break; - case 43: { + case 55: { /* read-chunk-native */ size_t clen = ENG->hlen_in; @@ -1228,7 +1511,7 @@ br_ssl_hs_client_run(void *t0ctx) } break; - case 44: { + case 56: { /* read8-native */ if (ENG->hlen_in > 0) { @@ -1246,7 +1529,20 @@ br_ssl_hs_client_run(void *t0ctx) } break; - case 45: { + case 57: { + /* set-server-curve */ + + const br_x509_class *xc; + const br_x509_pkey *pk; + + xc = *(ENG->x509ctx); + pk = xc->get_pkey(ENG->x509ctx, NULL); + CTX->server_curve = + (pk->key_type == BR_KEYTYPE_EC) ? pk->key.ec.curve : 0; + + } + break; + case 58: { /* set16 */ size_t addr = (size_t)T0_POP(); @@ -1254,7 +1550,7 @@ br_ssl_hs_client_run(void *t0ctx) } break; - case 46: { + case 59: { /* set8 */ size_t addr = (size_t)T0_POP(); @@ -1262,7 +1558,7 @@ br_ssl_hs_client_run(void *t0ctx) } break; - case 47: { + case 60: { /* strlen */ void *str = (unsigned char *)ENG + (size_t)T0_POP(); @@ -1270,7 +1566,7 @@ br_ssl_hs_client_run(void *t0ctx) } break; - case 48: { + case 61: { /* supported-curves */ uint32_t x = ENG->iec == NULL ? 0 : ENG->iec->supported_curves; @@ -1278,7 +1574,7 @@ br_ssl_hs_client_run(void *t0ctx) } break; - case 49: { + case 62: { /* supported-hash-functions */ int i; @@ -1297,26 +1593,26 @@ br_ssl_hs_client_run(void *t0ctx) } break; - case 50: { + case 63: { /* supports-ecdsa? */ - T0_PUSHi(-(CTX->iecdsa != 0)); + T0_PUSHi(-(ENG->iecdsa != 0)); } break; - case 51: { + case 64: { /* supports-rsa-sign? */ - T0_PUSHi(-(CTX->irsavrfy != 0)); + T0_PUSHi(-(ENG->irsavrfy != 0)); } break; - case 52: { + case 65: { /* swap */ T0_SWAP(); } break; - case 53: { + case 66: { /* switch-aesgcm-in */ int is_client, prf_id; @@ -1330,7 +1626,7 @@ br_ssl_hs_client_run(void *t0ctx) } break; - case 54: { + case 67: { /* switch-aesgcm-out */ int is_client, prf_id; @@ -1344,7 +1640,7 @@ br_ssl_hs_client_run(void *t0ctx) } break; - case 55: { + case 68: { /* switch-cbc-in */ int is_client, prf_id, mac_id, aes; @@ -1360,7 +1656,7 @@ br_ssl_hs_client_run(void *t0ctx) } break; - case 56: { + case 69: { /* switch-cbc-out */ int is_client, prf_id, mac_id, aes; @@ -1376,7 +1672,21 @@ br_ssl_hs_client_run(void *t0ctx) } break; - case 57: { + case 70: { + /* total-chain-length */ + + 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); + + } + break; + case 71: { /* u>> */ int c = (int)T0_POPi(); @@ -1385,7 +1695,7 @@ br_ssl_hs_client_run(void *t0ctx) } break; - case 58: { + case 72: { /* verify-SKE-sig */ size_t sig_len = T0_POP(); @@ -1396,7 +1706,7 @@ br_ssl_hs_client_run(void *t0ctx) } break; - case 59: { + case 73: { /* write-blob-chunk */ size_t clen = ENG->hlen_out; @@ -1420,7 +1730,7 @@ br_ssl_hs_client_run(void *t0ctx) } break; - case 60: { + case 74: { /* write8-native */ unsigned char x; @@ -1439,7 +1749,7 @@ br_ssl_hs_client_run(void *t0ctx) } break; - case 61: { + case 75: { /* x509-append */ const br_x509_class *xc; @@ -1451,7 +1761,7 @@ br_ssl_hs_client_run(void *t0ctx) } break; - case 62: { + case 76: { /* x509-end-cert */ const br_x509_class *xc; @@ -1461,7 +1771,7 @@ br_ssl_hs_client_run(void *t0ctx) } break; - case 63: { + case 77: { /* x509-end-chain */ const br_x509_class *xc; @@ -1471,7 +1781,7 @@ br_ssl_hs_client_run(void *t0ctx) } break; - case 64: { + case 78: { /* x509-start-cert */ const br_x509_class *xc; @@ -1481,13 +1791,15 @@ br_ssl_hs_client_run(void *t0ctx) } break; - case 65: { + case 79: { /* x509-start-chain */ const br_x509_class *xc; + uint32_t bc; + bc = T0_POP(); xc = *(ENG->x509ctx); - xc->start_chain(ENG->x509ctx, T0_POP(), ENG->server_name); + xc->start_chain(ENG->x509ctx, bc ? ENG->server_name : NULL); } break; diff --git a/src/ssl/ssl_hs_client.t0 b/src/ssl/ssl_hs_client.t0 index ea9f5b5..37c554c 100644 --- a/src/ssl/ssl_hs_client.t0 +++ b/src/ssl/ssl_hs_client.t0 @@ -55,7 +55,7 @@ make_pms_rsa(br_ssl_client_context *ctx, int prf_id) size_t nlen, u; xc = ctx->eng.x509ctx; - pk = (*xc)->get_pkey(xc); + pk = (*xc)->get_pkey(xc, NULL); /* * Compute actual RSA key length, in case there are leading zeros. @@ -145,9 +145,11 @@ static const unsigned char *HASH_OID[] = { /* * Check the RSA signature on the ServerKeyExchange message. + * * hash hash function ID (2 to 6), or 0 for MD5+SHA-1 (with RSA only) * use_rsa non-zero for RSA signature, zero for ECDSA * sig_len signature length (in bytes); signature value is in the pad + * * Returned value is 0 on success, or an error code. */ static int @@ -161,7 +163,7 @@ verify_SKE_sig(br_ssl_client_context *ctx, size_t hv_len; xc = ctx->eng.x509ctx; - pk = (*xc)->get_pkey(xc); + pk = (*xc)->get_pkey(xc, NULL); br_multihash_zero(&mhc); br_multihash_copyimpl(&mhc, &ctx->eng.mhash); br_multihash_init(&mhc); @@ -198,14 +200,14 @@ verify_SKE_sig(br_ssl_client_context *ctx, } else { hash_oid = NULL; } - if (!ctx->irsavrfy(ctx->eng.pad, sig_len, + if (!ctx->eng.irsavrfy(ctx->eng.pad, sig_len, hash_oid, hv_len, &pk->key.rsa, tmp) || memcmp(tmp, hv, hv_len) != 0) { return BR_ERR_BAD_SIGNATURE; } } else { - if (!ctx->iecdsa(ctx->eng.iec, hv, hv_len, &pk->key.ec, + if (!ctx->eng.iecdsa(ctx->eng.iec, hv, hv_len, &pk->key.ec, ctx->eng.pad, sig_len)) { return BR_ERR_BAD_SIGNATURE; @@ -215,7 +217,7 @@ verify_SKE_sig(br_ssl_client_context *ctx, } /* - * Perform client-size ECDH (or ECDHE). The point that should be sent to + * Perform client-side ECDH (or ECDHE). The point that should be sent to * the server is written in the pad; returned value is either the point * length (in bytes), or -x on error, with 'x' being an error code. * @@ -241,7 +243,7 @@ make_pms_ecdh(br_ssl_client_context *ctx, unsigned ecdhe, int prf_id) const br_x509_pkey *pk; xc = ctx->eng.x509ctx; - pk = (*xc)->get_pkey(xc); + pk = (*xc)->get_pkey(xc, NULL); curve = pk->key.ec.curve; point_src = pk->key.ec.q; point_len = pk->key.ec.qlen; @@ -292,6 +294,73 @@ make_pms_ecdh(br_ssl_client_context *ctx, unsigned ecdhe, int prf_id) return (int)glen; } +/* + * Perform full static ECDH. This occurs only in the context of client + * authentication with certificates: the server uses an EC public key, + * the cipher suite is of type ECDH (not ECDHE), the server requested a + * client certificate and accepts static ECDH, the client has a + * certificate with an EC public key in the same curve, and accepts + * static ECDH as well. + * + * Returned value is 0 on success, -1 on error. + */ +static int +make_pms_static_ecdh(br_ssl_client_context *ctx, int prf_id) +{ + unsigned char point[133]; + size_t point_len; + const br_x509_class **xc; + const br_x509_pkey *pk; + + xc = ctx->eng.x509ctx; + pk = (*xc)->get_pkey(xc, NULL); + point_len = pk->key.ec.qlen; + if (point_len > sizeof point) { + return -1; + } + memcpy(point, pk->key.ec.q, point_len); + if (!(*ctx->client_auth_vtable)->do_keyx( + ctx->client_auth_vtable, point, point_len)) + { + return -1; + } + br_ssl_engine_compute_master(&ctx->eng, + prf_id, point + 1, point_len >> 1); + return 0; +} + +/* + * Compute the client-side signature. This is invoked only when a + * signature-based client authentication was selected. The computed + * signature is in the pad; its length (in bytes) is returned. On + * error, 0 is returned. + */ +static size_t +make_client_sign(br_ssl_client_context *ctx) +{ + size_t hv_len; + + /* + * Compute hash of handshake messages so far. This "cannot" fail + * because the list of supported hash functions provided to the + * client certificate handler was trimmed to include only the + * hash functions that the multi-hasher supports. + */ + if (ctx->hash_id) { + hv_len = br_multihash_out(&ctx->eng.mhash, + ctx->hash_id, ctx->eng.pad); + } else { + br_multihash_out(&ctx->eng.mhash, + br_md5_ID, ctx->eng.pad); + br_multihash_out(&ctx->eng.mhash, + br_sha1_ID, ctx->eng.pad + 16); + hv_len = 36; + } + return (*ctx->client_auth_vtable)->do_sign( + ctx->client_auth_vtable, ctx->hash_id, hv_len, + ctx->eng.pad, sizeof ctx->eng.pad); +} + } \ ======================================================================= @@ -303,6 +372,9 @@ make_pms_ecdh(br_ssl_client_context *ctx, unsigned ecdhe, int prf_id) postpone literal postpone ; ; addr-ctx: min_clienthello_len +addr-ctx: hashes +addr-ctx: auth_type +addr-ctx: hash_id \ Length of the Secure Renegotiation extension. This is 5 for the \ first handshake, 17 for a renegotiation (if the server supports the @@ -319,16 +391,6 @@ addr-ctx: min_clienthello_len : ext-frag-length ( -- len ) addr-log_max_frag_len get8 14 = if 0 else 5 then ; -\ Test support for RSA signatures. -cc: supports-rsa-sign? ( -- bool ) { - T0_PUSHi(-(CTX->irsavrfy != 0)); -} - -\ Test support for ECDSA signatures. -cc: supports-ecdsa? ( -- bool ) { - T0_PUSHi(-(CTX->iecdsa != 0)); -} - \ Length of Signatures extension. : ext-signatures-length ( -- len ) supported-hash-functions { x } drop @@ -709,80 +771,26 @@ cc: DEBUG-BLOB ( addr len -- ) { resume ; -cc: x509-start-chain ( expected-key-type -- ) { - const br_x509_class *xc; - - xc = *(ENG->x509ctx); - xc->start_chain(ENG->x509ctx, T0_POP(), ENG->server_name); -} - -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 ) { +cc: set-server-curve ( -- ) { const br_x509_class *xc; + const br_x509_pkey *pk; xc = *(ENG->x509ctx); - T0_PUSH(xc->end_chain(ENG->x509ctx)); + pk = xc->get_pkey(ENG->x509ctx, NULL); + CTX->server_curve = + (pk->key_type == BR_KEYTYPE_EC) ? pk->key.ec.curve : 0; } -\ Parse Certificate -: read-Certificate ( -- ) - \ Get header, and check message type. - read-handshake-header 11 = ifnot ERR_UNEXPECTED fail then - - \ Start processing the chain through the X.509 engine. +\ Read Certificate message from server. +: read-Certificate-from-server ( -- ) addr-cipher_suite get16 expected-key-type - x509-start-chain - - \ 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 + -1 read-Certificate + dup 0< if neg fail then + dup ifnot ERR_UNEXPECTED fail then + over and <> if ERR_WRONG_KEY_USAGE fail then - \ Chain processing is finished; get the error code. - x509-end-chain - dup if fail then drop - ; + \ Set server curve (used for static ECDH). + set-server-curve ; \ Verify signature on ECDHE point sent by the server. \ 'hash' is the hash function to use (1 to 6, or 0 for RSA with MD5+SHA-1) @@ -851,15 +859,166 @@ cc: verify-SKE-sig ( hash use-rsa sig-len -- err ) { close-elt ; +\ Client certificate: start processing of anchor names. +cc: anchor-dn-start-name-list ( -- ) { + if (CTX->client_auth_vtable != NULL) { + (*CTX->client_auth_vtable)->start_name_list( + CTX->client_auth_vtable); + } +} + +\ Client certificate: start a new anchor DN (length is 16-bit). +cc: anchor-dn-start-name ( length -- ) { + size_t len; + + len = T0_POP(); + if (CTX->client_auth_vtable != NULL) { + (*CTX->client_auth_vtable)->start_name( + CTX->client_auth_vtable, len); + } +} + +\ Client certificate: push some data for current anchor DN. +cc: anchor-dn-append-name ( length -- ) { + size_t len; + + len = T0_POP(); + if (CTX->client_auth_vtable != NULL) { + (*CTX->client_auth_vtable)->append_name( + CTX->client_auth_vtable, ENG->pad, len); + } +} + +\ Client certificate: end current anchor DN. +cc: anchor-dn-end-name ( -- ) { + if (CTX->client_auth_vtable != NULL) { + (*CTX->client_auth_vtable)->end_name( + CTX->client_auth_vtable); + } +} + +\ Client certificate: end list of anchor DN. +cc: anchor-dn-end-name-list ( -- ) { + if (CTX->client_auth_vtable != NULL) { + (*CTX->client_auth_vtable)->end_name_list( + CTX->client_auth_vtable); + } +} + +\ Client certificate: obtain the client certificate chain. +cc: get-client-chain ( auth_types -- ) { + uint32_t auth_types; + + auth_types = T0_POP(); + if (CTX->client_auth_vtable != NULL) { + br_ssl_client_certificate ux; + + (*CTX->client_auth_vtable)->choose(CTX->client_auth_vtable, + CTX, auth_types, &ux); + CTX->auth_type = (unsigned char)ux.auth_type; + CTX->hash_id = (unsigned char)ux.hash_id; + ENG->chain = ux.chain; + ENG->chain_len = ux.chain_len; + } else { + CTX->hash_id = 0; + ENG->chain_len = 0; + } +} + \ Parse CertificateRequest. Header has already been read. : read-contents-CertificateRequest ( lim -- ) - \ TODO: implement client certificates. Right now, we simply - \ drop the complete message. - begin dup while read8 drop repeat drop ; + \ Read supported client authentification types. We keep only + \ RSA, ECDSA, and ECDH. + 0 { auth_types } + read8 open-elt + begin dup while + read8 case + 1 of 0x0000FF endof + 64 of 0x00FF00 endof + 65 of 0x010000 endof + 66 of 0x020000 endof + 0 swap + endcase + auth_types or >auth_types + repeat + close-elt + + \ Full static ECDH is allowed only if the cipher suite is ECDH + \ (not ECDHE). It would be theoretically feasible to use static + \ ECDH on the client side with an ephemeral key pair from the + \ server, but RFC 4492 (section 3) forbids it because ECDHE suites + \ are supposed to provide forward secrecy, and static ECDH would + \ negate that property. + addr-cipher_suite get16 use-ecdh? ifnot + auth_types 0xFFFF and >auth_types + then + + \ Note: if the cipher suite is ECDH, then the X.509 validation + \ engine was invoked with the BR_KEYTYPE_EC | BR_KEYTYPE_KEYX + \ combination, so the server's public key has already been + \ checked to be fit for a key exchange. + + \ With TLS 1.2: + \ - rsa_fixed_ecdh and ecdsa_fixed_ecdh are synoymous. + \ - There is an explicit list of supported sign+hash. + \ With TLS 1.0, + addr-version get16 0x0303 >= if + \ With TLS 1.2: + \ - There is an explicit list of supported sign+hash. + \ - The ECDH flags must be adjusted for RSA/ECDSA + \ support. + read-list-sign-algos dup addr-hashes set16 + + \ Trim down the list depending on what hash functions + \ we support (since the hashing itself is done by the SSL + \ engine, not by the certificate handler). + supported-hash-functions drop dup 8 << or 0x030000 or and + + auth_types and + auth_types 0x030000 and if + dup 0x0000FF and if 0x010000 or then + dup 0x00FF00 and if 0x020000 or then + then + >auth_types + else + \ TLS 1.0 or 1.1. The hash function is fixed for signatures + \ (MD5+SHA-1 for RSA, SHA-1 for ECDSA). + auth_types 0x030401 and >auth_types + then + + \ Parse list of anchor DN. + anchor-dn-start-name-list + read16 open-elt + begin dup while + read16 open-elt + dup anchor-dn-start-name + + \ We read the DN by chunks through the pad, so + \ as to use the existing reading function (read-blob) + \ that also ensures proper hashing. + begin + dup while + dup 256 > if 256 else dup then { len } + addr-pad len read-blob + len anchor-dn-append-name + repeat + close-elt + anchor-dn-end-name + repeat + close-elt + anchor-dn-end-name-list + + \ We should have reached the message end. + close-elt + + \ Obtain the client chain. + auth_types get-client-chain + ; +\ (obsolete) \ Write an empty Certificate message. -: write-empty-Certificate ( -- ) - 11 write8 3 write24 0 write24 ; +\ : write-empty-Certificate ( -- ) +\ 11 write8 3 write24 0 write24 ; cc: do-rsa-encrypt ( prf_id -- nlen ) { int x; @@ -887,7 +1046,27 @@ cc: do-ecdh ( echde prf_id -- ulen ) { } } -\ Write ClientKeyExchange +cc: do-static-ecdh ( prf-id -- ) { + unsigned prf_id = T0_POP(); + + if (make_pms_static_ecdh(CTX, prf_id) < 0) { + br_ssl_engine_fail(ENG, BR_ERR_INVALID_ALGORITHM); + T0_CO(); + } +} + +cc: do-client-sign ( -- sig_len ) { + size_t sig_len; + + sig_len = make_client_sign(CTX); + if (sig_len == 0) { + br_ssl_engine_fail(ENG, BR_ERR_INVALID_ALGORITHM); + T0_CO(); + } + T0_PUSH(sig_len); +} + +\ Write ClientKeyExchange. : write-ClientKeyExchange ( -- ) 16 write8 addr-cipher_suite get16 @@ -903,6 +1082,20 @@ cc: do-ecdh ( echde prf_id -- ulen ) { addr-pad swap write-blob then ; +\ Write CertificateVerify. This is invoked only if a client certificate +\ was requested and sent, and the authentication is not full static ECDH. +: write-CertificateVerify ( -- ) + do-client-sign + 15 write8 dup + addr-version get16 0x0303 >= if + 4 + write24 + addr-hash_id get8 write8 + addr-auth_type get8 write8 + else + 2+ write24 + then + dup write16 addr-pad swap write-blob ; + \ ======================================================================= \ Perform a handshake. @@ -924,7 +1117,9 @@ cc: do-ecdh ( echde prf_id -- ulen ) { \ Not a session resumption. - read-Certificate + \ Read certificate; then check key type and usages against + \ cipher suite. + read-Certificate-from-server \ Depending on cipher suite, we may now expect a \ ServerKeyExchange. @@ -956,12 +1151,27 @@ cc: do-ecdh ( echde prf_id -- ulen ) { more-incoming-bytes? if ERR_UNEXPECTED fail then seen-CR if - \ TODO: client certificate support. - write-empty-Certificate + \ If the server requested a client certificate, then + \ we must write a Certificate message (it may be + \ empty). + write-Certificate + + \ 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 - write-ClientKeyExchange - - \ TODO: CertificateVerify -1 write-CCS-Finished -1 read-CCS-Finished diff --git a/src/ssl/ssl_hs_common.t0 b/src/ssl/ssl_hs_common.t0 index 1eb5347..da6fc8a 100644 --- a/src/ssl/ssl_hs_common.t0 +++ b/src/ssl/ssl_hs_common.t0 @@ -145,12 +145,8 @@ addr-eng: version_max addr-eng: suites_buf addr-eng: suites_num addr-eng: server_name -\ addr-eng: version -\ addr-eng: cipher_suite addr-eng: client_random addr-eng: server_random -\ addr-eng: session_id_len -\ addr-eng: session_id addr-eng: ecdhe_curve addr-eng: ecdhe_point addr-eng: ecdhe_point_len @@ -212,6 +208,9 @@ err: ERR_LIMIT_EXCEEDED err: ERR_BAD_FINISHED err: ERR_RESUME_MISMATCH err: ERR_INVALID_ALGORITHM +err: ERR_BAD_SIGNATURE +err: ERR_WRONG_KEY_USAGE +err: ERR_NO_CLIENT_AUTH \ Get supported curves (bit mask). cc: supported-curves ( -- x ) { @@ -220,6 +219,7 @@ cc: supported-curves ( -- x ) { } \ Get supported hash functions (bit mask and number). +\ Note: this (on purpose) skips MD5. cc: supported-hash-functions ( -- x num ) { int i; unsigned x, num; @@ -236,6 +236,16 @@ cc: supported-hash-functions ( -- x num ) { T0_PUSH(num); } +\ Test support for RSA signatures. +cc: supports-rsa-sign? ( -- bool ) { + T0_PUSHi(-(ENG->irsavrfy != 0)); +} + +\ Test support for ECDSA signatures. +cc: supports-ecdsa? ( -- bool ) { + T0_PUSHi(-(ENG->iecdsa != 0)); +} + \ (Re)initialise the multihasher. cc: multihash-init ( -- ) { br_multihash_init(&ENG->mhash); @@ -1020,3 +1030,186 @@ cc: compute-Finished-inner ( from_client prf_id -- ) { 22 wait-rectype-out write-Finished flush-record ; + +\ Read and parse a list of supported signature algorithms (with hash +\ functions). The resulting bit field is returned. +: read-list-sign-algos ( lim -- lim value ) + 0 { hashes } + read16 open-elt + begin dup while + read8 { hash } read8 { sign } + \ We keep the value if the signature is either 1 (RSA) + \ or 3 (ECDSA), and the hash is one of the SHA-* functions + \ (2 to 6, from SHA-1 to SHA-512); we reject MD5. + hash 2 >= hash 6 <= and + sign 1 = sign 3 = or + and if + hashes 1 sign 1- 2 << hash + << or >hashes + then + repeat + close-elt + hashes ; + +\ ======================================================================= + +\ Compute total chain length. This includes the individual certificate +\ headers, but not the total chain header. This also sets the cert_cur, +\ cert_len and chain_len context fields. +cc: total-chain-length ( -- len ) { + size_t u; + uint32_t total; + + total = 0; + for (u = 0; u < ENG->chain_len; u ++) { + total += 3 + (uint32_t)ENG->chain[u].data_len; + } + T0_PUSH(total); +} + +\ Get length for current certificate in the chain; if the chain end was +\ reached, then this returns -1. +cc: begin-cert ( -- len ) { + if (ENG->chain_len == 0) { + T0_PUSHi(-1); + } else { + ENG->cert_cur = ENG->chain->data; + ENG->cert_len = ENG->chain->data_len; + ENG->chain ++; + ENG->chain_len --; + T0_PUSH(ENG->cert_len); + } +} + +\ Copy a chunk of certificate data into the pad. Returned value is the +\ chunk length, or 0 if the certificate end is reached. +cc: copy-cert-chunk ( -- len ) { + size_t clen; + + clen = ENG->cert_len; + if (clen > sizeof ENG->pad) { + clen = sizeof ENG->pad; + } + memcpy(ENG->pad, ENG->cert_cur, clen); + ENG->cert_cur += clen; + ENG->cert_len -= clen; + T0_PUSH(clen); +} + +\ Write a Certificate message. Total chain length (excluding the 3-byte +\ header) is returned; it is 0 if the chain is empty. +: write-Certificate ( -- total_chain_len ) + 11 write8 + total-chain-length dup + dup 3 + write24 write24 + begin + begin-cert + dup 0< if drop ret then write24 + begin copy-cert-chunk dup while + addr-pad swap write-blob + repeat + drop + again ; + +cc: x509-start-chain ( by_client -- ) { + const br_x509_class *xc; + uint32_t bc; + + bc = T0_POP(); + xc = *(ENG->x509ctx); + xc->start_chain(ENG->x509ctx, bc ? ENG->server_name : NULL); +} + +cc: x509-start-cert ( length -- ) { + const br_x509_class *xc; + + xc = *(ENG->x509ctx); + xc->start_cert(ENG->x509ctx, T0_POP()); +} + +cc: x509-append ( length -- ) { + const br_x509_class *xc; + size_t len; + + xc = *(ENG->x509ctx); + len = T0_POP(); + xc->append(ENG->x509ctx, ENG->pad, len); +} + +cc: x509-end-cert ( -- ) { + const br_x509_class *xc; + + xc = *(ENG->x509ctx); + xc->end_cert(ENG->x509ctx); +} + +cc: x509-end-chain ( -- err ) { + const br_x509_class *xc; + + xc = *(ENG->x509ctx); + T0_PUSH(xc->end_chain(ENG->x509ctx)); +} + +cc: get-key-type-usages ( -- key-type-usages ) { + const br_x509_class *xc; + const br_x509_pkey *pk; + unsigned usages; + + xc = *(ENG->x509ctx); + pk = xc->get_pkey(ENG->x509ctx, &usages); + if (pk == NULL) { + T0_PUSH(0); + } else { + T0_PUSH(pk->key_type | usages); + } +} + +\ Read a Certificate message. +\ Parameter: non-zero if this is a read by the client of a certificate +\ sent by the server; zero otherwise. +\ Returned value: +\ - Empty: 0 +\ - Valid: combination of key type and allowed key usages. +\ - Invalid: negative (-x for error code x) +: read-Certificate ( by_client -- key-type-usages ) + \ Get header, and check message type. + read-handshake-header 11 = ifnot ERR_UNEXPECTED fail then + + \ If the chain is empty, do some special processing. + dup 3 = if + read24 if ERR_BAD_PARAM fail then + swap drop ret + then + + \ Start processing the chain through the X.509 engine. + swap x509-start-chain + + \ Total chain length is a 24-bit integer. + read24 open-elt + begin + dup while + read24 open-elt + dup x509-start-cert + + \ We read the certificate by chunks through the pad, so + \ as to use the existing reading function (read-blob) + \ that also ensures proper hashing. + begin + dup while + dup 256 > if 256 else dup then { len } + addr-pad len read-blob + len x509-append + repeat + close-elt + x509-end-cert + repeat + + \ We must close the chain AND the handshake message. + close-elt + close-elt + + \ Chain processing is finished; get the error code. + x509-end-chain + dup if neg ret then drop + + \ Return key type and usages. + get-key-type-usages ; diff --git a/src/ssl/ssl_hs_server.c b/src/ssl/ssl_hs_server.c index a46734d..14dcf33 100644 --- a/src/ssl/ssl_hs_server.c +++ b/src/ssl/ssl_hs_server.c @@ -195,6 +195,35 @@ do_ecdh(br_ssl_server_context *ctx, int prf_id, ecdh_common(ctx, prf_id, cpoint, cpoint_len, x); } +/* + * Do the full static ECDH key exchange. When this function is called, + * it has already been verified that the cipher suite uses ECDH (not ECDHE), + * and the client's public key (from its certificate) has type EC and is + * apt for key exchange. + */ +static void +do_static_ecdh(br_ssl_server_context *ctx, int prf_id) +{ + unsigned char cpoint[133]; + size_t cpoint_len; + const br_x509_class **xc; + const br_x509_pkey *pk; + + xc = ctx->eng.x509ctx; + pk = (*xc)->get_pkey(xc, NULL); + cpoint_len = pk->key.ec.qlen; + if (cpoint_len > sizeof cpoint) { + /* + * If the point is larger than our buffer then we need to + * restrict it. Length 2 is not a valid point length, so + * the ECDH will fail. + */ + cpoint_len = 2; + } + memcpy(cpoint, pk->key.ec.q, cpoint_len); + do_ecdh(ctx, prf_id, cpoint, cpoint_len); +} + /* * Do the ECDHE key exchange (part 1: generation of transient key, and * computing of the point to send to the client). Returned value is the @@ -313,6 +342,94 @@ do_ecdhe_part2(br_ssl_server_context *ctx, int prf_id, memset(ctx->ecdhe_key, 0, ctx->ecdhe_key_len); } +/* + * Offset for hash value within the pad (when obtaining all hash values, + * in preparation for verification of the CertificateVerify message). + * Order is MD5, SHA-1, SHA-224, SHA-256, SHA-384, SHA-512; last value + * is used to get the total length. + */ +static const unsigned char HASH_PAD_OFF[] = { 0, 16, 36, 64, 96, 144, 208 }; + +/* + * OID for hash functions in RSA signatures. + */ +static const unsigned char HASH_OID_SHA1[] = { + 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A +}; + +static const unsigned char HASH_OID_SHA224[] = { + 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04 +}; + +static const unsigned char HASH_OID_SHA256[] = { + 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01 +}; + +static const unsigned char HASH_OID_SHA384[] = { + 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02 +}; + +static const unsigned char HASH_OID_SHA512[] = { + 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03 +}; + +static const unsigned char *HASH_OID[] = { + HASH_OID_SHA1, + HASH_OID_SHA224, + HASH_OID_SHA256, + HASH_OID_SHA384, + HASH_OID_SHA512 +}; + +/* + * Verify the signature in CertificateVerify. Returned value is 0 on + * success, or a non-zero error code. Lack of implementation of the + * designated signature algorithm is reported as a "bad signature" + * error (because it means that the peer did not honour our advertised + * set of supported signature algorithms). + */ +static int +verify_CV_sig(br_ssl_server_context *ctx, size_t sig_len) +{ + const br_x509_class **xc; + const br_x509_pkey *pk; + int id; + + id = ctx->hash_CV_id; + xc = ctx->eng.x509ctx; + pk = (*xc)->get_pkey(xc, NULL); + if (pk->key_type == BR_KEYTYPE_RSA) { + unsigned char tmp[64]; + const unsigned char *hash_oid; + + if (id == 0) { + hash_oid = NULL; + } else { + hash_oid = HASH_OID[id - 2]; + } + if (ctx->eng.irsavrfy == 0) { + return BR_ERR_BAD_SIGNATURE; + } + if (!ctx->eng.irsavrfy(ctx->eng.pad, sig_len, + hash_oid, ctx->hash_CV_len, &pk->key.rsa, tmp) + || memcmp(tmp, ctx->hash_CV, ctx->hash_CV_len) != 0) + { + return BR_ERR_BAD_SIGNATURE; + } + } else { + if (ctx->eng.iecdsa == 0) { + return BR_ERR_BAD_SIGNATURE; + } + if (!ctx->eng.iecdsa(ctx->eng.iec, + ctx->hash_CV, ctx->hash_CV_len, + &pk->key.ec, ctx->eng.pad, sig_len)) + { + return BR_ERR_BAD_SIGNATURE; + } + } + return 0; +} + static const uint8_t t0_datablock[] = { @@ -332,19 +449,23 @@ static const uint8_t t0_datablock[] = { }; static const uint8_t t0_codeblock[] = { - 0x00, 0x01, 0x00, 0x0A, 0x00, 0x00, 0x01, 0x00, 0x0D, 0x00, 0x00, 0x01, - 0x00, 0x0E, 0x00, 0x00, 0x01, 0x00, 0x0F, 0x00, 0x00, 0x01, 0x01, 0x08, + 0x00, 0x01, 0x00, 0x0B, 0x00, 0x00, 0x01, 0x00, 0x0E, 0x00, 0x00, 0x01, + 0x00, 0x0F, 0x00, 0x00, 0x01, 0x00, 0x10, 0x00, 0x00, 0x01, 0x01, 0x08, 0x00, 0x00, 0x01, 0x01, 0x09, 0x00, 0x00, 0x01, 0x02, 0x08, 0x00, 0x00, - 0x21, 0x21, 0x00, 0x00, 0x01, T0_INT1(BR_ERR_BAD_CCS), 0x00, 0x00, + 0x28, 0x28, 0x00, 0x00, 0x01, T0_INT1(BR_ERR_BAD_CCS), 0x00, 0x00, 0x01, T0_INT1(BR_ERR_BAD_FINISHED), 0x00, 0x00, 0x01, T0_INT1(BR_ERR_BAD_FRAGLEN), 0x00, 0x00, 0x01, T0_INT1(BR_ERR_BAD_HANDSHAKE), 0x00, 0x00, 0x01, T0_INT1(BR_ERR_BAD_PARAM), 0x00, 0x00, 0x01, T0_INT1(BR_ERR_BAD_SECRENEG), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_BAD_SIGNATURE), 0x00, 0x00, 0x01, T0_INT1(BR_ERR_BAD_VERSION), 0x00, 0x00, 0x01, - T0_INT1(BR_ERR_LIMIT_EXCEEDED), 0x00, 0x00, 0x01, T0_INT1(BR_ERR_OK), + T0_INT1(BR_ERR_INVALID_ALGORITHM), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_LIMIT_EXCEEDED), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_NO_CLIENT_AUTH), 0x00, 0x00, 0x01, T0_INT1(BR_ERR_OK), 0x00, 0x00, 0x01, T0_INT1(BR_ERR_OVERSIZED_ID), 0x00, 0x00, 0x01, T0_INT1(BR_ERR_UNEXPECTED), 0x00, 0x00, 0x01, + T0_INT1(BR_ERR_WRONG_KEY_USAGE), 0x00, 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, action)), 0x00, 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, alert)), 0x00, 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, application_data)), 0x00, 0x00, @@ -363,7 +484,7 @@ static const uint8_t t0_codeblock[] = { 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, ecdhe_point_len)), 0x00, 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, flags)), 0x00, 0x00, 0x01, T0_INT2(offsetof(br_ssl_server_context, hashes)), - 0x00, 0x00, 0x5D, 0x01, + 0x00, 0x00, 0x73, 0x01, T0_INT2(BR_MAX_CIPHER_SUITES * sizeof(br_suite_translated)), 0x00, 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, log_max_frag_len)), 0x00, 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, pad)), 0x00, @@ -393,203 +514,257 @@ static const uint8_t t0_codeblock[] = { T0_INT2(offsetof(br_ssl_engine_context, version_max)), 0x00, 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, version_min)), 0x00, 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, version_out)), - 0x00, 0x00, 0x09, 0x22, 0x44, 0x06, 0x02, 0x50, 0x23, 0x00, 0x00, 0x01, - 0x01, 0x00, 0x01, 0x03, 0x00, 0x7B, 0x22, 0x4A, 0x3B, 0x7F, 0x22, 0x05, - 0x04, 0x4B, 0x01, 0x00, 0x00, 0x02, 0x00, 0x0E, 0x06, 0x02, 0x7F, 0x00, - 0x4A, 0x04, 0x6B, 0x00, 0x06, 0x02, 0x50, 0x23, 0x00, 0x00, 0x22, 0x6C, - 0x3B, 0x05, 0x03, 0x01, 0x0C, 0x08, 0x3B, 0x5A, 0x25, 0x81, 0x07, 0x19, - 0x67, 0x01, 0x0C, 0x2A, 0x00, 0x00, 0x22, 0x1B, 0x01, 0x08, 0x0B, 0x3B, - 0x48, 0x1B, 0x08, 0x00, 0x01, 0x03, 0x00, 0x01, 0x00, 0x59, 0x38, 0x24, - 0x16, 0x2F, 0x06, 0x08, 0x02, 0x00, 0x81, 0x26, 0x03, 0x00, 0x04, 0x74, - 0x01, 0x00, 0x81, 0x1E, 0x02, 0x00, 0x22, 0x16, 0x12, 0x06, 0x02, 0x54, - 0x23, 0x81, 0x26, 0x04, 0x75, 0x00, 0x01, 0x00, 0x59, 0x38, 0x01, 0x16, - 0x6A, 0x38, 0x2D, 0x81, 0x0B, 0x2C, 0x06, 0x02, 0x56, 0x23, 0x06, 0x0C, - 0x81, 0x2C, 0x01, 0x00, 0x81, 0x29, 0x01, 0x00, 0x81, 0x0A, 0x04, 0x14, - 0x81, 0x2C, 0x81, 0x2A, 0x81, 0x2E, 0x81, 0x2D, 0x24, 0x81, 0x0C, 0x01, - 0x00, 0x81, 0x0A, 0x01, 0x00, 0x81, 0x29, 0x34, 0x01, 0x01, 0x59, 0x38, - 0x01, 0x17, 0x6A, 0x38, 0x00, 0x00, 0x31, 0x31, 0x00, 0x01, 0x03, 0x00, - 0x24, 0x16, 0x2F, 0x06, 0x05, 0x81, 0x25, 0x21, 0x04, 0x77, 0x01, 0x02, - 0x02, 0x00, 0x81, 0x1D, 0x16, 0x2F, 0x06, 0x05, 0x81, 0x25, 0x21, 0x04, - 0x77, 0x02, 0x00, 0x01, 0x84, 0x00, 0x08, 0x23, 0x00, 0x00, 0x63, 0x26, - 0x3B, 0x11, 0x01, 0x01, 0x12, 0x2E, 0x00, 0x00, 0x01, 0x7F, 0x81, 0x01, - 0x81, 0x25, 0x22, 0x01, 0x07, 0x12, 0x01, 0x00, 0x31, 0x0E, 0x06, 0x0A, - 0x21, 0x01, 0x10, 0x12, 0x06, 0x02, 0x81, 0x1C, 0x04, 0x2E, 0x01, 0x01, - 0x31, 0x0E, 0x06, 0x25, 0x21, 0x21, 0x6B, 0x27, 0x01, 0x01, 0x0E, 0x01, - 0x01, 0x81, 0x04, 0x30, 0x06, 0x11, 0x24, 0x16, 0x2F, 0x06, 0x05, 0x81, - 0x25, 0x21, 0x04, 0x77, 0x01, 0x80, 0x64, 0x81, 0x1E, 0x04, 0x04, 0x01, - 0x00, 0x81, 0x01, 0x04, 0x03, 0x56, 0x23, 0x21, 0x04, 0xFF, 0x39, 0x01, - 0x22, 0x03, 0x00, 0x09, 0x22, 0x44, 0x06, 0x02, 0x50, 0x23, 0x02, 0x00, - 0x00, 0x00, 0x7C, 0x01, 0x0F, 0x12, 0x00, 0x00, 0x58, 0x27, 0x01, 0x00, - 0x31, 0x0E, 0x06, 0x10, 0x21, 0x22, 0x01, 0x01, 0x0D, 0x06, 0x03, 0x21, - 0x01, 0x02, 0x58, 0x38, 0x01, 0x00, 0x04, 0x22, 0x01, 0x01, 0x31, 0x0E, - 0x06, 0x15, 0x21, 0x01, 0x00, 0x58, 0x38, 0x22, 0x01, 0x80, 0x64, 0x0E, - 0x06, 0x05, 0x01, 0x82, 0x00, 0x08, 0x23, 0x46, 0x00, 0x04, 0x07, 0x21, - 0x01, 0x82, 0x00, 0x08, 0x23, 0x21, 0x00, 0x00, 0x01, 0x00, 0x28, 0x06, - 0x06, 0x33, 0x81, 0x08, 0x30, 0x04, 0x77, 0x22, 0x06, 0x04, 0x01, 0x01, - 0x71, 0x38, 0x00, 0x00, 0x28, 0x06, 0x0B, 0x69, 0x27, 0x01, 0x14, 0x0D, - 0x06, 0x02, 0x56, 0x23, 0x04, 0x12, 0x81, 0x25, 0x01, 0x07, 0x12, 0x22, - 0x01, 0x02, 0x0D, 0x06, 0x06, 0x06, 0x02, 0x56, 0x23, 0x04, 0x6F, 0x21, - 0x81, 0x1A, 0x01, 0x01, 0x0D, 0x2C, 0x30, 0x06, 0x02, 0x4C, 0x23, 0x22, - 0x01, 0x01, 0x81, 0x20, 0x2F, 0x81, 0x0D, 0x00, 0x0A, 0x81, 0x12, 0x01, - 0x01, 0x0E, 0x05, 0x02, 0x56, 0x23, 0x81, 0x17, 0x22, 0x03, 0x00, 0x5B, - 0x36, 0x5C, 0x01, 0x20, 0x81, 0x0E, 0x81, 0x19, 0x22, 0x01, 0x20, 0x0F, - 0x06, 0x02, 0x55, 0x23, 0x22, 0x70, 0x38, 0x6F, 0x3B, 0x81, 0x0E, 0x17, - 0x03, 0x01, 0x81, 0x17, 0x81, 0x06, 0x01, 0x00, 0x03, 0x02, 0x01, 0x00, - 0x03, 0x03, 0x65, 0x81, 0x02, 0x14, 0x31, 0x08, 0x03, 0x04, 0x03, 0x05, - 0x22, 0x06, 0x80, 0x70, 0x81, 0x17, 0x22, 0x03, 0x06, 0x02, 0x01, 0x06, - 0x0A, 0x22, 0x5A, 0x25, 0x0E, 0x06, 0x04, 0x01, 0x7F, 0x03, 0x03, 0x22, - 0x01, 0x81, 0x7F, 0x0E, 0x06, 0x0A, 0x6B, 0x27, 0x06, 0x02, 0x51, 0x23, - 0x01, 0x7F, 0x03, 0x02, 0x22, 0x01, 0x81, 0xAC, 0x00, 0x0E, 0x06, 0x11, - 0x02, 0x00, 0x78, 0x25, 0x10, 0x02, 0x00, 0x77, 0x25, 0x0A, 0x12, 0x06, - 0x04, 0x01, 0x7F, 0x03, 0x00, 0x81, 0x1B, 0x22, 0x44, 0x06, 0x03, 0x21, - 0x04, 0x27, 0x01, 0x00, 0x81, 0x04, 0x06, 0x0B, 0x01, 0x02, 0x0B, 0x5D, - 0x08, 0x02, 0x06, 0x3B, 0x36, 0x04, 0x16, 0x21, 0x02, 0x05, 0x02, 0x04, - 0x10, 0x06, 0x02, 0x4F, 0x23, 0x02, 0x06, 0x02, 0x05, 0x36, 0x02, 0x05, - 0x01, 0x04, 0x08, 0x03, 0x05, 0x04, 0xFF, 0x0C, 0x21, 0x01, 0x00, 0x03, - 0x07, 0x81, 0x19, 0x81, 0x06, 0x22, 0x06, 0x0A, 0x81, 0x19, 0x05, 0x04, - 0x01, 0x7F, 0x03, 0x07, 0x04, 0x73, 0x7D, 0x01, 0x00, 0x6D, 0x38, 0x01, - 0x88, 0x04, 0x64, 0x36, 0x01, 0x84, 0x80, 0x80, 0x00, 0x60, 0x37, 0x22, - 0x06, 0x80, 0x4D, 0x81, 0x17, 0x81, 0x06, 0x22, 0x06, 0x80, 0x44, 0x81, - 0x17, 0x01, 0x00, 0x31, 0x0E, 0x06, 0x05, 0x21, 0x81, 0x11, 0x04, 0x34, - 0x01, 0x01, 0x31, 0x0E, 0x06, 0x05, 0x21, 0x81, 0x0F, 0x04, 0x29, 0x01, - 0x83, 0xFE, 0x01, 0x31, 0x0E, 0x06, 0x05, 0x21, 0x81, 0x10, 0x04, 0x1C, - 0x01, 0x0D, 0x31, 0x0E, 0x06, 0x05, 0x21, 0x81, 0x15, 0x04, 0x11, 0x01, - 0x0A, 0x31, 0x0E, 0x06, 0x05, 0x21, 0x81, 0x16, 0x04, 0x06, 0x21, 0x81, - 0x14, 0x01, 0x00, 0x21, 0x04, 0xFF, 0x38, 0x7D, 0x7D, 0x02, 0x01, 0x02, - 0x03, 0x12, 0x03, 0x01, 0x02, 0x00, 0x44, 0x06, 0x09, 0x5B, 0x25, 0x79, - 0x36, 0x01, 0x80, 0x56, 0x81, 0x03, 0x77, 0x25, 0x22, 0x02, 0x00, 0x0F, - 0x06, 0x03, 0x21, 0x02, 0x00, 0x22, 0x01, 0x86, 0x00, 0x0A, 0x06, 0x02, - 0x52, 0x23, 0x02, 0x00, 0x78, 0x25, 0x0A, 0x06, 0x05, 0x01, 0x80, 0x46, - 0x81, 0x03, 0x02, 0x01, 0x06, 0x10, 0x75, 0x25, 0x02, 0x00, 0x0C, 0x06, - 0x05, 0x21, 0x75, 0x25, 0x04, 0x04, 0x01, 0x00, 0x03, 0x01, 0x22, 0x75, - 0x36, 0x22, 0x76, 0x36, 0x22, 0x79, 0x36, 0x01, 0x86, 0x03, 0x10, 0x03, - 0x08, 0x02, 0x02, 0x06, 0x04, 0x01, 0x02, 0x6B, 0x38, 0x02, 0x07, 0x05, - 0x04, 0x01, 0x28, 0x81, 0x03, 0x3A, 0x21, 0x01, 0x82, 0x01, 0x07, 0x64, - 0x25, 0x12, 0x22, 0x64, 0x36, 0x45, 0x03, 0x09, 0x60, 0x26, 0x39, 0x12, - 0x22, 0x60, 0x37, 0x05, 0x04, 0x01, 0x00, 0x03, 0x09, 0x02, 0x01, 0x06, - 0x03, 0x01, 0x7F, 0x00, 0x6F, 0x01, 0x20, 0x2B, 0x01, 0x20, 0x70, 0x38, - 0x5D, 0x22, 0x03, 0x05, 0x22, 0x02, 0x04, 0x0A, 0x06, 0x80, 0x47, 0x22, - 0x25, 0x22, 0x7C, 0x02, 0x09, 0x05, 0x13, 0x22, 0x01, 0x0C, 0x11, 0x22, - 0x01, 0x01, 0x0E, 0x3B, 0x01, 0x02, 0x0E, 0x30, 0x06, 0x04, 0x4B, 0x01, - 0x00, 0x22, 0x02, 0x08, 0x05, 0x0E, 0x22, 0x01, 0x81, 0x70, 0x12, 0x01, - 0x20, 0x0D, 0x06, 0x04, 0x4B, 0x01, 0x00, 0x22, 0x22, 0x06, 0x10, 0x02, - 0x05, 0x4A, 0x36, 0x02, 0x05, 0x36, 0x02, 0x05, 0x01, 0x04, 0x08, 0x03, - 0x05, 0x04, 0x01, 0x4B, 0x01, 0x04, 0x08, 0x04, 0xFF, 0x32, 0x21, 0x02, - 0x05, 0x5D, 0x09, 0x01, 0x02, 0x11, 0x22, 0x05, 0x04, 0x01, 0x28, 0x81, - 0x03, 0x5E, 0x38, 0x15, 0x05, 0x04, 0x01, 0x28, 0x81, 0x03, 0x01, 0x00, - 0x00, 0x04, 0x81, 0x12, 0x01, 0x10, 0x0E, 0x05, 0x02, 0x56, 0x23, 0x5A, - 0x25, 0x81, 0x24, 0x06, 0x19, 0x81, 0x17, 0x22, 0x01, 0x84, 0x00, 0x0F, - 0x06, 0x02, 0x53, 0x23, 0x22, 0x03, 0x00, 0x67, 0x3B, 0x81, 0x0E, 0x02, - 0x00, 0x5A, 0x25, 0x81, 0x07, 0x20, 0x5A, 0x25, 0x22, 0x81, 0x22, 0x3B, - 0x81, 0x21, 0x03, 0x01, 0x03, 0x02, 0x02, 0x01, 0x02, 0x02, 0x30, 0x06, - 0x17, 0x81, 0x19, 0x22, 0x03, 0x03, 0x67, 0x3B, 0x81, 0x0E, 0x02, 0x03, - 0x5A, 0x25, 0x81, 0x07, 0x02, 0x02, 0x06, 0x03, 0x1F, 0x04, 0x01, 0x1D, - 0x7D, 0x00, 0x00, 0x7E, 0x81, 0x12, 0x01, 0x14, 0x0D, 0x06, 0x02, 0x56, - 0x23, 0x67, 0x01, 0x0C, 0x08, 0x01, 0x0C, 0x81, 0x0E, 0x7D, 0x67, 0x22, - 0x01, 0x0C, 0x08, 0x01, 0x0C, 0x29, 0x05, 0x02, 0x4D, 0x23, 0x00, 0x02, - 0x03, 0x00, 0x03, 0x01, 0x02, 0x00, 0x7A, 0x02, 0x01, 0x02, 0x00, 0x32, - 0x22, 0x01, 0x00, 0x0E, 0x06, 0x02, 0x4B, 0x00, 0x81, 0x27, 0x04, 0x73, - 0x00, 0x81, 0x17, 0x01, 0x01, 0x0D, 0x06, 0x02, 0x4E, 0x23, 0x81, 0x19, - 0x22, 0x22, 0x46, 0x3B, 0x01, 0x05, 0x10, 0x30, 0x06, 0x02, 0x4E, 0x23, - 0x01, 0x08, 0x08, 0x22, 0x66, 0x27, 0x0A, 0x06, 0x0D, 0x22, 0x01, 0x01, - 0x3B, 0x0B, 0x35, 0x22, 0x66, 0x38, 0x68, 0x38, 0x04, 0x01, 0x21, 0x00, - 0x00, 0x81, 0x17, 0x6B, 0x27, 0x01, 0x00, 0x31, 0x0E, 0x06, 0x14, 0x21, - 0x01, 0x01, 0x0E, 0x05, 0x02, 0x51, 0x23, 0x81, 0x19, 0x06, 0x02, 0x51, - 0x23, 0x01, 0x02, 0x6B, 0x38, 0x04, 0x2A, 0x01, 0x02, 0x31, 0x0E, 0x06, - 0x21, 0x21, 0x01, 0x0D, 0x0E, 0x05, 0x02, 0x51, 0x23, 0x81, 0x19, 0x01, - 0x0C, 0x0E, 0x05, 0x02, 0x51, 0x23, 0x67, 0x01, 0x0C, 0x81, 0x0E, 0x6C, - 0x67, 0x01, 0x0C, 0x29, 0x05, 0x02, 0x51, 0x23, 0x04, 0x03, 0x51, 0x23, - 0x21, 0x00, 0x00, 0x81, 0x17, 0x81, 0x06, 0x81, 0x17, 0x81, 0x06, 0x22, - 0x06, 0x22, 0x81, 0x19, 0x06, 0x04, 0x81, 0x14, 0x04, 0x18, 0x81, 0x17, - 0x22, 0x01, 0x81, 0x7F, 0x0C, 0x06, 0x0D, 0x22, 0x6D, 0x08, 0x01, 0x00, - 0x3B, 0x38, 0x6D, 0x3B, 0x81, 0x0E, 0x04, 0x02, 0x81, 0x1F, 0x04, 0x5B, - 0x7D, 0x7D, 0x00, 0x00, 0x81, 0x13, 0x22, 0x46, 0x06, 0x07, 0x21, 0x06, - 0x02, 0x4F, 0x23, 0x04, 0x73, 0x00, 0x00, 0x81, 0x1A, 0x01, 0x03, 0x81, - 0x18, 0x3B, 0x21, 0x3B, 0x00, 0x00, 0x81, 0x17, 0x81, 0x1F, 0x00, 0x02, - 0x81, 0x17, 0x81, 0x06, 0x01, 0x00, 0x64, 0x36, 0x81, 0x17, 0x81, 0x06, - 0x22, 0x06, 0x34, 0x81, 0x19, 0x03, 0x00, 0x81, 0x19, 0x03, 0x01, 0x02, - 0x00, 0x01, 0x02, 0x10, 0x02, 0x00, 0x01, 0x06, 0x0C, 0x12, 0x02, 0x01, - 0x01, 0x01, 0x0E, 0x02, 0x01, 0x01, 0x03, 0x0E, 0x30, 0x12, 0x06, 0x11, - 0x64, 0x25, 0x01, 0x01, 0x02, 0x01, 0x49, 0x01, 0x02, 0x0B, 0x02, 0x00, - 0x08, 0x0B, 0x30, 0x64, 0x36, 0x04, 0x49, 0x7D, 0x7D, 0x00, 0x00, 0x81, - 0x17, 0x81, 0x06, 0x81, 0x17, 0x81, 0x06, 0x01, 0x00, 0x60, 0x37, 0x22, - 0x06, 0x16, 0x81, 0x17, 0x22, 0x01, 0x20, 0x0A, 0x06, 0x0B, 0x01, 0x01, - 0x3B, 0x0B, 0x60, 0x26, 0x30, 0x60, 0x37, 0x04, 0x01, 0x21, 0x04, 0x67, - 0x7D, 0x7D, 0x00, 0x00, 0x01, 0x02, 0x7A, 0x81, 0x1A, 0x01, 0x08, 0x0B, - 0x81, 0x1A, 0x08, 0x00, 0x00, 0x01, 0x03, 0x7A, 0x81, 0x1A, 0x01, 0x08, - 0x0B, 0x81, 0x1A, 0x08, 0x01, 0x08, 0x0B, 0x81, 0x1A, 0x08, 0x00, 0x00, - 0x01, 0x01, 0x7A, 0x81, 0x1A, 0x00, 0x00, 0x33, 0x22, 0x44, 0x05, 0x01, - 0x00, 0x21, 0x81, 0x27, 0x04, 0x75, 0x02, 0x03, 0x00, 0x74, 0x27, 0x03, - 0x01, 0x01, 0x00, 0x22, 0x02, 0x01, 0x0A, 0x06, 0x10, 0x22, 0x01, 0x01, - 0x0B, 0x73, 0x08, 0x25, 0x02, 0x00, 0x0E, 0x06, 0x01, 0x00, 0x48, 0x04, - 0x6A, 0x21, 0x01, 0x7F, 0x00, 0x00, 0x24, 0x16, 0x2F, 0x06, 0x05, 0x81, - 0x25, 0x21, 0x04, 0x77, 0x01, 0x16, 0x6A, 0x38, 0x01, 0x00, 0x81, 0x33, - 0x01, 0x00, 0x81, 0x32, 0x24, 0x01, 0x17, 0x6A, 0x38, 0x00, 0x00, 0x01, - 0x15, 0x6A, 0x38, 0x3B, 0x43, 0x21, 0x43, 0x21, 0x24, 0x00, 0x00, 0x01, - 0x01, 0x3B, 0x81, 0x1D, 0x00, 0x00, 0x3B, 0x31, 0x7A, 0x3B, 0x22, 0x06, - 0x06, 0x81, 0x1A, 0x21, 0x49, 0x04, 0x77, 0x21, 0x00, 0x02, 0x03, 0x00, - 0x5A, 0x25, 0x7C, 0x03, 0x01, 0x02, 0x01, 0x01, 0x0F, 0x12, 0x02, 0x01, - 0x01, 0x04, 0x11, 0x01, 0x0F, 0x12, 0x02, 0x01, 0x01, 0x08, 0x11, 0x01, - 0x0F, 0x12, 0x01, 0x00, 0x31, 0x0E, 0x06, 0x10, 0x21, 0x01, 0x00, 0x01, - 0x18, 0x02, 0x00, 0x06, 0x03, 0x3E, 0x04, 0x01, 0x3F, 0x04, 0x80, 0x56, - 0x01, 0x01, 0x31, 0x0E, 0x06, 0x10, 0x21, 0x01, 0x01, 0x01, 0x10, 0x02, - 0x00, 0x06, 0x03, 0x3E, 0x04, 0x01, 0x3F, 0x04, 0x80, 0x40, 0x01, 0x02, - 0x31, 0x0E, 0x06, 0x0F, 0x21, 0x01, 0x01, 0x01, 0x20, 0x02, 0x00, 0x06, - 0x03, 0x3E, 0x04, 0x01, 0x3F, 0x04, 0x2B, 0x01, 0x03, 0x31, 0x0E, 0x06, - 0x0E, 0x21, 0x21, 0x01, 0x10, 0x02, 0x00, 0x06, 0x03, 0x3C, 0x04, 0x01, - 0x3D, 0x04, 0x17, 0x01, 0x04, 0x31, 0x0E, 0x06, 0x0E, 0x21, 0x21, 0x01, - 0x20, 0x02, 0x00, 0x06, 0x03, 0x3C, 0x04, 0x01, 0x3D, 0x04, 0x03, 0x50, - 0x23, 0x21, 0x00, 0x00, 0x7C, 0x01, 0x0C, 0x11, 0x01, 0x02, 0x0F, 0x00, - 0x00, 0x7C, 0x01, 0x0C, 0x11, 0x22, 0x47, 0x3B, 0x01, 0x03, 0x0A, 0x12, - 0x00, 0x00, 0x7C, 0x01, 0x0C, 0x11, 0x01, 0x01, 0x0E, 0x00, 0x00, 0x7C, - 0x01, 0x0C, 0x11, 0x46, 0x00, 0x00, 0x18, 0x01, 0x00, 0x57, 0x27, 0x22, - 0x06, 0x20, 0x01, 0x01, 0x31, 0x0E, 0x06, 0x07, 0x21, 0x01, 0x00, 0x81, - 0x00, 0x04, 0x11, 0x01, 0x02, 0x31, 0x0E, 0x06, 0x0A, 0x21, 0x59, 0x27, - 0x06, 0x03, 0x01, 0x10, 0x30, 0x04, 0x01, 0x21, 0x04, 0x01, 0x21, 0x5F, - 0x27, 0x05, 0x35, 0x28, 0x06, 0x32, 0x69, 0x27, 0x01, 0x14, 0x31, 0x0E, - 0x06, 0x06, 0x21, 0x01, 0x02, 0x30, 0x04, 0x24, 0x01, 0x15, 0x31, 0x0E, - 0x06, 0x0B, 0x21, 0x81, 0x09, 0x06, 0x04, 0x01, 0x7F, 0x81, 0x00, 0x04, - 0x13, 0x01, 0x16, 0x31, 0x0E, 0x06, 0x06, 0x21, 0x01, 0x01, 0x30, 0x04, - 0x07, 0x21, 0x01, 0x04, 0x30, 0x01, 0x00, 0x21, 0x16, 0x06, 0x03, 0x01, - 0x08, 0x30, 0x00, 0x00, 0x18, 0x22, 0x05, 0x10, 0x28, 0x06, 0x0D, 0x69, - 0x27, 0x01, 0x15, 0x0E, 0x06, 0x05, 0x21, 0x81, 0x09, 0x04, 0x01, 0x1C, - 0x00, 0x00, 0x81, 0x25, 0x01, 0x07, 0x12, 0x01, 0x01, 0x0F, 0x06, 0x02, - 0x56, 0x23, 0x00, 0x01, 0x03, 0x00, 0x24, 0x16, 0x06, 0x05, 0x02, 0x00, - 0x6A, 0x38, 0x00, 0x81, 0x25, 0x21, 0x04, 0x73, 0x00, 0x01, 0x14, 0x81, - 0x28, 0x01, 0x01, 0x81, 0x33, 0x24, 0x22, 0x01, 0x00, 0x81, 0x20, 0x01, - 0x16, 0x81, 0x28, 0x81, 0x2B, 0x24, 0x00, 0x00, 0x01, 0x0B, 0x81, 0x33, - 0x40, 0x22, 0x01, 0x03, 0x08, 0x81, 0x32, 0x81, 0x32, 0x13, 0x22, 0x44, - 0x06, 0x02, 0x21, 0x00, 0x81, 0x32, 0x1A, 0x22, 0x06, 0x06, 0x67, 0x3B, - 0x81, 0x2F, 0x04, 0x76, 0x21, 0x04, 0x6A, 0x00, 0x7E, 0x01, 0x14, 0x81, - 0x33, 0x01, 0x0C, 0x81, 0x32, 0x67, 0x01, 0x0C, 0x81, 0x2F, 0x00, 0x03, - 0x03, 0x00, 0x01, 0x02, 0x81, 0x33, 0x01, 0x80, 0x46, 0x6B, 0x27, 0x01, - 0x02, 0x0E, 0x06, 0x0C, 0x02, 0x00, 0x06, 0x04, 0x01, 0x05, 0x04, 0x02, - 0x01, 0x1D, 0x04, 0x02, 0x01, 0x00, 0x03, 0x01, 0x68, 0x27, 0x06, 0x04, - 0x01, 0x05, 0x04, 0x02, 0x01, 0x00, 0x03, 0x02, 0x02, 0x01, 0x02, 0x02, - 0x08, 0x22, 0x06, 0x03, 0x01, 0x02, 0x08, 0x08, 0x81, 0x32, 0x75, 0x25, - 0x81, 0x31, 0x6E, 0x01, 0x04, 0x14, 0x6E, 0x01, 0x04, 0x08, 0x01, 0x1C, - 0x2B, 0x6E, 0x01, 0x20, 0x81, 0x2F, 0x01, 0x20, 0x81, 0x33, 0x6F, 0x01, - 0x20, 0x81, 0x2F, 0x5A, 0x25, 0x81, 0x31, 0x01, 0x00, 0x81, 0x33, 0x02, - 0x01, 0x02, 0x02, 0x08, 0x22, 0x06, 0x30, 0x81, 0x31, 0x02, 0x01, 0x22, - 0x06, 0x13, 0x01, 0x83, 0xFE, 0x01, 0x81, 0x31, 0x01, 0x04, 0x09, 0x22, - 0x81, 0x31, 0x49, 0x6C, 0x3B, 0x81, 0x30, 0x04, 0x01, 0x21, 0x02, 0x02, - 0x06, 0x0F, 0x01, 0x01, 0x81, 0x31, 0x01, 0x01, 0x81, 0x31, 0x68, 0x27, - 0x01, 0x08, 0x09, 0x81, 0x33, 0x04, 0x01, 0x21, 0x00, 0x00, 0x01, 0x0E, - 0x81, 0x33, 0x01, 0x00, 0x81, 0x32, 0x00, 0x03, 0x5A, 0x25, 0x81, 0x22, - 0x05, 0x01, 0x00, 0x60, 0x26, 0x01, 0x00, 0x81, 0x02, 0x11, 0x01, 0x01, - 0x12, 0x46, 0x06, 0x03, 0x48, 0x04, 0x74, 0x03, 0x00, 0x21, 0x02, 0x00, - 0x1E, 0x22, 0x44, 0x06, 0x02, 0x2E, 0x23, 0x03, 0x01, 0x75, 0x25, 0x01, - 0x86, 0x03, 0x10, 0x03, 0x02, 0x01, 0x0C, 0x81, 0x33, 0x02, 0x01, 0x62, - 0x27, 0x08, 0x02, 0x02, 0x01, 0x02, 0x12, 0x08, 0x01, 0x06, 0x08, 0x81, - 0x32, 0x01, 0x03, 0x81, 0x33, 0x02, 0x00, 0x81, 0x31, 0x61, 0x62, 0x27, - 0x81, 0x30, 0x02, 0x02, 0x06, 0x10, 0x72, 0x27, 0x81, 0x33, 0x5A, 0x25, - 0x81, 0x23, 0x01, 0x01, 0x0B, 0x01, 0x03, 0x08, 0x81, 0x33, 0x02, 0x01, - 0x81, 0x31, 0x67, 0x02, 0x01, 0x81, 0x2F, 0x00, 0x00, 0x42, 0x22, 0x01, - 0x00, 0x0E, 0x06, 0x02, 0x4B, 0x00, 0x81, 0x25, 0x21, 0x04, 0x72, 0x00, - 0x22, 0x81, 0x33, 0x81, 0x2F, 0x00, 0x00, 0x22, 0x01, 0x08, 0x41, 0x81, - 0x33, 0x81, 0x33, 0x00, 0x00, 0x22, 0x01, 0x10, 0x41, 0x81, 0x33, 0x81, - 0x31, 0x00, 0x00, 0x22, 0x43, 0x06, 0x02, 0x21, 0x00, 0x81, 0x25, 0x21, - 0x04, 0x75 + 0x00, 0x00, 0x09, 0x29, 0x56, 0x06, 0x02, 0x62, 0x2A, 0x00, 0x00, 0x01, + 0x01, 0x00, 0x01, 0x03, 0x00, 0x81, 0x11, 0x29, 0x5C, 0x46, 0x81, 0x15, + 0x29, 0x05, 0x04, 0x5D, 0x01, 0x00, 0x00, 0x02, 0x00, 0x0F, 0x06, 0x03, + 0x81, 0x15, 0x00, 0x5C, 0x04, 0x69, 0x00, 0x06, 0x02, 0x62, 0x2A, 0x00, + 0x00, 0x29, 0x81, 0x02, 0x46, 0x05, 0x03, 0x01, 0x0C, 0x08, 0x46, 0x70, + 0x2D, 0x81, 0x1D, 0x1C, 0x7D, 0x01, 0x0C, 0x32, 0x00, 0x00, 0x29, 0x21, + 0x01, 0x08, 0x0C, 0x46, 0x5A, 0x21, 0x08, 0x00, 0x01, 0x03, 0x00, 0x01, + 0x00, 0x6F, 0x41, 0x2B, 0x19, 0x37, 0x06, 0x08, 0x02, 0x00, 0x81, 0x43, + 0x03, 0x00, 0x04, 0x74, 0x01, 0x00, 0x81, 0x3B, 0x02, 0x00, 0x29, 0x19, + 0x13, 0x06, 0x02, 0x69, 0x2A, 0x81, 0x43, 0x04, 0x75, 0x00, 0x01, 0x00, + 0x6F, 0x41, 0x01, 0x16, 0x81, 0x00, 0x41, 0x35, 0x81, 0x25, 0x34, 0x06, + 0x02, 0x6B, 0x2A, 0x06, 0x0D, 0x81, 0x4A, 0x01, 0x00, 0x81, 0x46, 0x01, + 0x00, 0x81, 0x21, 0x04, 0x80, 0x59, 0x81, 0x4A, 0x81, 0x47, 0x28, 0x81, + 0x4C, 0x4B, 0x06, 0x02, 0x81, 0x48, 0x81, 0x4B, 0x2B, 0x4B, 0x06, 0x3C, + 0x01, 0x00, 0x81, 0x22, 0x29, 0x56, 0x06, 0x13, 0x01, 0x02, 0x81, 0x1A, + 0x05, 0x02, 0x36, 0x2A, 0x28, 0x81, 0x26, 0x81, 0x24, 0x29, 0x81, 0x3C, + 0x28, 0x04, 0x1F, 0x29, 0x58, 0x06, 0x0D, 0x28, 0x01, 0x02, 0x81, 0x1A, + 0x05, 0x02, 0x68, 0x2A, 0x81, 0x26, 0x04, 0x0E, 0x81, 0x28, 0x29, 0x05, + 0x05, 0x28, 0x81, 0x20, 0x04, 0x04, 0x81, 0x27, 0x81, 0x23, 0x04, 0x02, + 0x81, 0x26, 0x01, 0x00, 0x81, 0x21, 0x01, 0x00, 0x81, 0x46, 0x3D, 0x01, + 0x01, 0x6F, 0x41, 0x01, 0x17, 0x81, 0x00, 0x41, 0x00, 0x00, 0x39, 0x39, + 0x00, 0x01, 0x03, 0x00, 0x2B, 0x19, 0x37, 0x06, 0x05, 0x81, 0x42, 0x28, + 0x04, 0x77, 0x01, 0x02, 0x02, 0x00, 0x81, 0x3A, 0x19, 0x37, 0x06, 0x05, + 0x81, 0x42, 0x28, 0x04, 0x77, 0x02, 0x00, 0x01, 0x84, 0x00, 0x08, 0x2A, + 0x00, 0x00, 0x79, 0x2E, 0x46, 0x12, 0x01, 0x01, 0x13, 0x36, 0x00, 0x00, + 0x01, 0x7F, 0x81, 0x17, 0x81, 0x42, 0x29, 0x01, 0x07, 0x13, 0x01, 0x00, + 0x39, 0x0F, 0x06, 0x0A, 0x28, 0x01, 0x10, 0x13, 0x06, 0x02, 0x81, 0x39, + 0x04, 0x2F, 0x01, 0x01, 0x39, 0x0F, 0x06, 0x26, 0x28, 0x28, 0x81, 0x01, + 0x2F, 0x01, 0x01, 0x0F, 0x01, 0x01, 0x81, 0x1A, 0x38, 0x06, 0x11, 0x2B, + 0x19, 0x37, 0x06, 0x05, 0x81, 0x42, 0x28, 0x04, 0x77, 0x01, 0x80, 0x64, + 0x81, 0x3B, 0x04, 0x04, 0x01, 0x00, 0x81, 0x17, 0x04, 0x03, 0x6B, 0x2A, + 0x28, 0x04, 0xFF, 0x38, 0x01, 0x29, 0x03, 0x00, 0x09, 0x29, 0x56, 0x06, + 0x02, 0x62, 0x2A, 0x02, 0x00, 0x00, 0x00, 0x81, 0x12, 0x01, 0x0F, 0x13, + 0x00, 0x00, 0x6E, 0x2F, 0x01, 0x00, 0x39, 0x0F, 0x06, 0x10, 0x28, 0x29, + 0x01, 0x01, 0x0E, 0x06, 0x03, 0x28, 0x01, 0x02, 0x6E, 0x41, 0x01, 0x00, + 0x04, 0x22, 0x01, 0x01, 0x39, 0x0F, 0x06, 0x15, 0x28, 0x01, 0x00, 0x6E, + 0x41, 0x29, 0x01, 0x80, 0x64, 0x0F, 0x06, 0x05, 0x01, 0x82, 0x00, 0x08, + 0x2A, 0x58, 0x00, 0x04, 0x07, 0x28, 0x01, 0x82, 0x00, 0x08, 0x2A, 0x28, + 0x00, 0x00, 0x01, 0x00, 0x30, 0x06, 0x06, 0x3C, 0x81, 0x1E, 0x38, 0x04, + 0x77, 0x29, 0x06, 0x05, 0x01, 0x01, 0x81, 0x07, 0x41, 0x00, 0x00, 0x01, + 0x1F, 0x13, 0x01, 0x12, 0x0F, 0x05, 0x02, 0x6C, 0x2A, 0x70, 0x2D, 0x29, + 0x81, 0x3E, 0x05, 0x02, 0x6B, 0x2A, 0x81, 0x1D, 0x27, 0x00, 0x00, 0x30, + 0x06, 0x0B, 0x7F, 0x2F, 0x01, 0x14, 0x0E, 0x06, 0x02, 0x6B, 0x2A, 0x04, + 0x12, 0x81, 0x42, 0x01, 0x07, 0x13, 0x29, 0x01, 0x02, 0x0E, 0x06, 0x06, + 0x06, 0x02, 0x6B, 0x2A, 0x04, 0x6F, 0x28, 0x81, 0x37, 0x01, 0x01, 0x0E, + 0x34, 0x38, 0x06, 0x02, 0x5E, 0x2A, 0x29, 0x01, 0x01, 0x81, 0x3D, 0x37, + 0x81, 0x29, 0x00, 0x01, 0x81, 0x2E, 0x01, 0x0B, 0x0F, 0x05, 0x02, 0x6B, + 0x2A, 0x29, 0x01, 0x03, 0x0F, 0x06, 0x09, 0x81, 0x35, 0x06, 0x02, 0x62, + 0x2A, 0x46, 0x28, 0x00, 0x46, 0x55, 0x81, 0x35, 0x81, 0x1C, 0x29, 0x06, + 0x27, 0x81, 0x35, 0x81, 0x1C, 0x29, 0x54, 0x29, 0x06, 0x19, 0x29, 0x01, + 0x82, 0x00, 0x10, 0x06, 0x05, 0x01, 0x82, 0x00, 0x04, 0x01, 0x29, 0x03, + 0x00, 0x7D, 0x02, 0x00, 0x81, 0x2A, 0x02, 0x00, 0x51, 0x04, 0x64, 0x81, + 0x13, 0x52, 0x04, 0x56, 0x81, 0x13, 0x81, 0x13, 0x53, 0x29, 0x06, 0x02, + 0x36, 0x00, 0x28, 0x2C, 0x00, 0x02, 0x29, 0x01, 0x20, 0x13, 0x05, 0x02, + 0x6C, 0x2A, 0x01, 0x0F, 0x13, 0x03, 0x00, 0x81, 0x24, 0x81, 0x0B, 0x2D, + 0x01, 0x86, 0x03, 0x11, 0x06, 0x24, 0x81, 0x34, 0x29, 0x01, 0x81, 0x7F, + 0x13, 0x5A, 0x01, 0x01, 0x12, 0x02, 0x00, 0x0F, 0x05, 0x02, 0x64, 0x2A, + 0x01, 0x08, 0x12, 0x29, 0x01, 0x02, 0x0B, 0x39, 0x01, 0x06, 0x10, 0x38, + 0x06, 0x02, 0x66, 0x2A, 0x04, 0x0D, 0x02, 0x00, 0x01, 0x01, 0x0F, 0x06, + 0x04, 0x01, 0x00, 0x04, 0x02, 0x01, 0x02, 0x20, 0x05, 0x02, 0x66, 0x2A, + 0x81, 0x34, 0x29, 0x03, 0x01, 0x29, 0x01, 0x84, 0x00, 0x10, 0x06, 0x02, + 0x67, 0x2A, 0x7D, 0x46, 0x81, 0x2A, 0x02, 0x01, 0x4E, 0x29, 0x06, 0x01, + 0x2A, 0x28, 0x81, 0x13, 0x00, 0x00, 0x1D, 0x81, 0x2E, 0x01, 0x0F, 0x0F, + 0x05, 0x02, 0x6B, 0x2A, 0x00, 0x0A, 0x81, 0x2E, 0x01, 0x01, 0x0F, 0x05, + 0x02, 0x6B, 0x2A, 0x81, 0x34, 0x29, 0x03, 0x00, 0x71, 0x3F, 0x72, 0x01, + 0x20, 0x81, 0x2A, 0x81, 0x36, 0x29, 0x01, 0x20, 0x10, 0x06, 0x02, 0x6A, + 0x2A, 0x29, 0x81, 0x06, 0x41, 0x81, 0x05, 0x46, 0x81, 0x2A, 0x1A, 0x03, + 0x01, 0x81, 0x34, 0x81, 0x1C, 0x01, 0x00, 0x03, 0x02, 0x01, 0x00, 0x03, + 0x03, 0x7B, 0x81, 0x18, 0x17, 0x39, 0x08, 0x03, 0x04, 0x03, 0x05, 0x29, + 0x06, 0x80, 0x73, 0x81, 0x34, 0x29, 0x03, 0x06, 0x02, 0x01, 0x06, 0x0A, + 0x29, 0x70, 0x2D, 0x0F, 0x06, 0x04, 0x01, 0x7F, 0x03, 0x03, 0x29, 0x01, + 0x81, 0x7F, 0x0F, 0x06, 0x0B, 0x81, 0x01, 0x2F, 0x06, 0x02, 0x63, 0x2A, + 0x01, 0x7F, 0x03, 0x02, 0x29, 0x01, 0x81, 0xAC, 0x00, 0x0F, 0x06, 0x13, + 0x02, 0x00, 0x81, 0x0E, 0x2D, 0x11, 0x02, 0x00, 0x81, 0x0D, 0x2D, 0x0B, + 0x13, 0x06, 0x04, 0x01, 0x7F, 0x03, 0x00, 0x81, 0x38, 0x29, 0x56, 0x06, + 0x03, 0x28, 0x04, 0x27, 0x01, 0x00, 0x81, 0x1A, 0x06, 0x0B, 0x01, 0x02, + 0x0C, 0x73, 0x08, 0x02, 0x06, 0x46, 0x3F, 0x04, 0x16, 0x28, 0x02, 0x05, + 0x02, 0x04, 0x11, 0x06, 0x02, 0x61, 0x2A, 0x02, 0x06, 0x02, 0x05, 0x3F, + 0x02, 0x05, 0x01, 0x04, 0x08, 0x03, 0x05, 0x04, 0xFF, 0x09, 0x28, 0x01, + 0x00, 0x03, 0x07, 0x81, 0x36, 0x81, 0x1C, 0x29, 0x06, 0x0A, 0x81, 0x36, + 0x05, 0x04, 0x01, 0x7F, 0x03, 0x07, 0x04, 0x73, 0x81, 0x13, 0x01, 0x00, + 0x81, 0x03, 0x41, 0x01, 0x88, 0x04, 0x7A, 0x3F, 0x01, 0x84, 0x80, 0x80, + 0x00, 0x76, 0x40, 0x29, 0x06, 0x80, 0x4E, 0x81, 0x34, 0x81, 0x1C, 0x29, + 0x06, 0x80, 0x44, 0x81, 0x34, 0x01, 0x00, 0x39, 0x0F, 0x06, 0x05, 0x28, + 0x81, 0x2D, 0x04, 0x34, 0x01, 0x01, 0x39, 0x0F, 0x06, 0x05, 0x28, 0x81, + 0x2B, 0x04, 0x29, 0x01, 0x83, 0xFE, 0x01, 0x39, 0x0F, 0x06, 0x05, 0x28, + 0x81, 0x2C, 0x04, 0x1C, 0x01, 0x0D, 0x39, 0x0F, 0x06, 0x05, 0x28, 0x81, + 0x32, 0x04, 0x11, 0x01, 0x0A, 0x39, 0x0F, 0x06, 0x05, 0x28, 0x81, 0x33, + 0x04, 0x06, 0x28, 0x81, 0x30, 0x01, 0x00, 0x28, 0x04, 0xFF, 0x38, 0x81, + 0x13, 0x81, 0x13, 0x02, 0x01, 0x02, 0x03, 0x13, 0x03, 0x01, 0x02, 0x00, + 0x56, 0x06, 0x0A, 0x71, 0x2D, 0x81, 0x0F, 0x3F, 0x01, 0x80, 0x56, 0x81, + 0x19, 0x81, 0x0D, 0x2D, 0x29, 0x02, 0x00, 0x10, 0x06, 0x03, 0x28, 0x02, + 0x00, 0x29, 0x01, 0x86, 0x00, 0x0B, 0x06, 0x02, 0x65, 0x2A, 0x02, 0x00, + 0x81, 0x0E, 0x2D, 0x0B, 0x06, 0x05, 0x01, 0x80, 0x46, 0x81, 0x19, 0x02, + 0x01, 0x06, 0x12, 0x81, 0x0B, 0x2D, 0x02, 0x00, 0x0D, 0x06, 0x06, 0x28, + 0x81, 0x0B, 0x2D, 0x04, 0x04, 0x01, 0x00, 0x03, 0x01, 0x29, 0x81, 0x0B, + 0x3F, 0x29, 0x81, 0x0C, 0x3F, 0x29, 0x81, 0x0F, 0x3F, 0x01, 0x86, 0x03, + 0x11, 0x03, 0x08, 0x02, 0x02, 0x06, 0x05, 0x01, 0x02, 0x81, 0x01, 0x41, + 0x02, 0x07, 0x05, 0x04, 0x01, 0x28, 0x81, 0x19, 0x43, 0x28, 0x01, 0x82, + 0x01, 0x07, 0x7A, 0x2D, 0x13, 0x29, 0x7A, 0x3F, 0x29, 0x01, 0x81, 0x7F, + 0x13, 0x57, 0x36, 0x46, 0x01, 0x08, 0x12, 0x57, 0x01, 0x02, 0x13, 0x38, + 0x03, 0x09, 0x76, 0x2E, 0x42, 0x13, 0x29, 0x76, 0x40, 0x05, 0x04, 0x01, + 0x00, 0x03, 0x09, 0x02, 0x01, 0x06, 0x03, 0x01, 0x7F, 0x00, 0x81, 0x05, + 0x01, 0x20, 0x33, 0x01, 0x20, 0x81, 0x06, 0x41, 0x73, 0x29, 0x03, 0x05, + 0x29, 0x02, 0x04, 0x0B, 0x06, 0x80, 0x4A, 0x29, 0x2D, 0x29, 0x81, 0x12, + 0x29, 0x01, 0x0C, 0x12, 0x29, 0x01, 0x01, 0x0F, 0x46, 0x01, 0x02, 0x0F, + 0x38, 0x06, 0x0A, 0x29, 0x02, 0x09, 0x13, 0x05, 0x04, 0x5D, 0x01, 0x00, + 0x29, 0x02, 0x08, 0x05, 0x0E, 0x29, 0x01, 0x81, 0x70, 0x13, 0x01, 0x20, + 0x0E, 0x06, 0x04, 0x5D, 0x01, 0x00, 0x29, 0x29, 0x06, 0x10, 0x02, 0x05, + 0x5C, 0x3F, 0x02, 0x05, 0x3F, 0x02, 0x05, 0x01, 0x04, 0x08, 0x03, 0x05, + 0x04, 0x01, 0x5D, 0x01, 0x04, 0x08, 0x04, 0xFF, 0x2F, 0x28, 0x02, 0x05, + 0x73, 0x09, 0x01, 0x02, 0x12, 0x29, 0x05, 0x04, 0x01, 0x28, 0x81, 0x19, + 0x74, 0x41, 0x18, 0x05, 0x04, 0x01, 0x28, 0x81, 0x19, 0x01, 0x00, 0x00, + 0x00, 0x81, 0x28, 0x81, 0x27, 0x00, 0x04, 0x70, 0x2D, 0x81, 0x41, 0x06, + 0x19, 0x81, 0x34, 0x29, 0x01, 0x84, 0x00, 0x10, 0x06, 0x02, 0x67, 0x2A, + 0x29, 0x03, 0x00, 0x7D, 0x46, 0x81, 0x2A, 0x02, 0x00, 0x70, 0x2D, 0x81, + 0x1D, 0x26, 0x70, 0x2D, 0x29, 0x81, 0x3F, 0x46, 0x81, 0x3E, 0x03, 0x01, + 0x03, 0x02, 0x02, 0x01, 0x02, 0x02, 0x38, 0x06, 0x17, 0x81, 0x36, 0x29, + 0x03, 0x03, 0x7D, 0x46, 0x81, 0x2A, 0x02, 0x03, 0x70, 0x2D, 0x81, 0x1D, + 0x02, 0x02, 0x06, 0x03, 0x25, 0x04, 0x01, 0x23, 0x81, 0x13, 0x00, 0x00, + 0x81, 0x2E, 0x01, 0x10, 0x0F, 0x05, 0x02, 0x6B, 0x2A, 0x00, 0x00, 0x81, + 0x14, 0x81, 0x2E, 0x01, 0x14, 0x0E, 0x06, 0x02, 0x6B, 0x2A, 0x7D, 0x01, + 0x0C, 0x08, 0x01, 0x0C, 0x81, 0x2A, 0x81, 0x13, 0x7D, 0x29, 0x01, 0x0C, + 0x08, 0x01, 0x0C, 0x31, 0x05, 0x02, 0x5F, 0x2A, 0x00, 0x02, 0x03, 0x00, + 0x03, 0x01, 0x02, 0x00, 0x81, 0x10, 0x02, 0x01, 0x02, 0x00, 0x3B, 0x29, + 0x01, 0x00, 0x0F, 0x06, 0x02, 0x5D, 0x00, 0x81, 0x44, 0x04, 0x73, 0x00, + 0x81, 0x34, 0x01, 0x01, 0x0E, 0x06, 0x02, 0x60, 0x2A, 0x81, 0x36, 0x29, + 0x29, 0x58, 0x46, 0x01, 0x05, 0x11, 0x38, 0x06, 0x02, 0x60, 0x2A, 0x01, + 0x08, 0x08, 0x29, 0x7C, 0x2F, 0x0B, 0x06, 0x0D, 0x29, 0x01, 0x01, 0x46, + 0x0C, 0x3E, 0x29, 0x7C, 0x41, 0x7E, 0x41, 0x04, 0x01, 0x28, 0x00, 0x00, + 0x81, 0x34, 0x81, 0x01, 0x2F, 0x01, 0x00, 0x39, 0x0F, 0x06, 0x15, 0x28, + 0x01, 0x01, 0x0F, 0x05, 0x02, 0x63, 0x2A, 0x81, 0x36, 0x06, 0x02, 0x63, + 0x2A, 0x01, 0x02, 0x81, 0x01, 0x41, 0x04, 0x2B, 0x01, 0x02, 0x39, 0x0F, + 0x06, 0x22, 0x28, 0x01, 0x0D, 0x0F, 0x05, 0x02, 0x63, 0x2A, 0x81, 0x36, + 0x01, 0x0C, 0x0F, 0x05, 0x02, 0x63, 0x2A, 0x7D, 0x01, 0x0C, 0x81, 0x2A, + 0x81, 0x02, 0x7D, 0x01, 0x0C, 0x31, 0x05, 0x02, 0x63, 0x2A, 0x04, 0x03, + 0x63, 0x2A, 0x28, 0x00, 0x00, 0x81, 0x34, 0x81, 0x1C, 0x81, 0x34, 0x81, + 0x1C, 0x29, 0x06, 0x24, 0x81, 0x36, 0x06, 0x04, 0x81, 0x30, 0x04, 0x1A, + 0x81, 0x34, 0x29, 0x01, 0x81, 0x7F, 0x0D, 0x06, 0x0F, 0x29, 0x81, 0x03, + 0x08, 0x01, 0x00, 0x46, 0x41, 0x81, 0x03, 0x46, 0x81, 0x2A, 0x04, 0x02, + 0x81, 0x3C, 0x04, 0x59, 0x81, 0x13, 0x81, 0x13, 0x00, 0x00, 0x81, 0x2F, + 0x29, 0x58, 0x06, 0x07, 0x28, 0x06, 0x02, 0x61, 0x2A, 0x04, 0x73, 0x00, + 0x00, 0x81, 0x37, 0x01, 0x03, 0x81, 0x35, 0x46, 0x28, 0x46, 0x00, 0x00, + 0x81, 0x34, 0x81, 0x3C, 0x00, 0x03, 0x01, 0x00, 0x03, 0x00, 0x81, 0x34, + 0x81, 0x1C, 0x29, 0x06, 0x34, 0x81, 0x36, 0x03, 0x01, 0x81, 0x36, 0x03, + 0x02, 0x02, 0x01, 0x01, 0x02, 0x11, 0x02, 0x01, 0x01, 0x06, 0x0D, 0x13, + 0x02, 0x02, 0x01, 0x01, 0x0F, 0x02, 0x02, 0x01, 0x03, 0x0F, 0x38, 0x13, + 0x06, 0x11, 0x02, 0x00, 0x01, 0x01, 0x02, 0x02, 0x5B, 0x01, 0x02, 0x0C, + 0x02, 0x01, 0x08, 0x0C, 0x38, 0x03, 0x00, 0x04, 0x49, 0x81, 0x13, 0x02, + 0x00, 0x00, 0x00, 0x81, 0x34, 0x81, 0x1C, 0x81, 0x31, 0x7A, 0x3F, 0x81, + 0x13, 0x00, 0x00, 0x81, 0x34, 0x81, 0x1C, 0x81, 0x34, 0x81, 0x1C, 0x01, + 0x00, 0x76, 0x40, 0x29, 0x06, 0x16, 0x81, 0x34, 0x29, 0x01, 0x20, 0x0B, + 0x06, 0x0B, 0x01, 0x01, 0x46, 0x0C, 0x76, 0x2E, 0x38, 0x76, 0x40, 0x04, + 0x01, 0x28, 0x04, 0x67, 0x81, 0x13, 0x81, 0x13, 0x00, 0x00, 0x01, 0x02, + 0x81, 0x10, 0x81, 0x37, 0x01, 0x08, 0x0C, 0x81, 0x37, 0x08, 0x00, 0x00, + 0x01, 0x03, 0x81, 0x10, 0x81, 0x37, 0x01, 0x08, 0x0C, 0x81, 0x37, 0x08, + 0x01, 0x08, 0x0C, 0x81, 0x37, 0x08, 0x00, 0x00, 0x01, 0x01, 0x81, 0x10, + 0x81, 0x37, 0x00, 0x00, 0x3C, 0x29, 0x56, 0x05, 0x01, 0x00, 0x28, 0x81, + 0x44, 0x04, 0x75, 0x02, 0x03, 0x00, 0x81, 0x0A, 0x2F, 0x03, 0x01, 0x01, + 0x00, 0x29, 0x02, 0x01, 0x0B, 0x06, 0x11, 0x29, 0x01, 0x01, 0x0C, 0x81, + 0x09, 0x08, 0x2D, 0x02, 0x00, 0x0F, 0x06, 0x01, 0x00, 0x5A, 0x04, 0x69, + 0x28, 0x01, 0x7F, 0x00, 0x00, 0x2B, 0x19, 0x37, 0x06, 0x05, 0x81, 0x42, + 0x28, 0x04, 0x77, 0x01, 0x16, 0x81, 0x00, 0x41, 0x01, 0x00, 0x81, 0x55, + 0x01, 0x00, 0x81, 0x54, 0x2B, 0x01, 0x17, 0x81, 0x00, 0x41, 0x00, 0x00, + 0x01, 0x15, 0x81, 0x00, 0x41, 0x46, 0x50, 0x28, 0x50, 0x28, 0x2B, 0x00, + 0x00, 0x01, 0x01, 0x46, 0x81, 0x3A, 0x00, 0x00, 0x46, 0x39, 0x81, 0x10, + 0x46, 0x29, 0x06, 0x06, 0x81, 0x37, 0x28, 0x5B, 0x04, 0x77, 0x28, 0x00, + 0x02, 0x03, 0x00, 0x70, 0x2D, 0x81, 0x12, 0x03, 0x01, 0x02, 0x01, 0x01, + 0x0F, 0x13, 0x02, 0x01, 0x01, 0x04, 0x12, 0x01, 0x0F, 0x13, 0x02, 0x01, + 0x01, 0x08, 0x12, 0x01, 0x0F, 0x13, 0x01, 0x00, 0x39, 0x0F, 0x06, 0x10, + 0x28, 0x01, 0x00, 0x01, 0x18, 0x02, 0x00, 0x06, 0x03, 0x49, 0x04, 0x01, + 0x4A, 0x04, 0x80, 0x56, 0x01, 0x01, 0x39, 0x0F, 0x06, 0x10, 0x28, 0x01, + 0x01, 0x01, 0x10, 0x02, 0x00, 0x06, 0x03, 0x49, 0x04, 0x01, 0x4A, 0x04, + 0x80, 0x40, 0x01, 0x02, 0x39, 0x0F, 0x06, 0x0F, 0x28, 0x01, 0x01, 0x01, + 0x20, 0x02, 0x00, 0x06, 0x03, 0x49, 0x04, 0x01, 0x4A, 0x04, 0x2B, 0x01, + 0x03, 0x39, 0x0F, 0x06, 0x0E, 0x28, 0x28, 0x01, 0x10, 0x02, 0x00, 0x06, + 0x03, 0x47, 0x04, 0x01, 0x48, 0x04, 0x17, 0x01, 0x04, 0x39, 0x0F, 0x06, + 0x0E, 0x28, 0x28, 0x01, 0x20, 0x02, 0x00, 0x06, 0x03, 0x47, 0x04, 0x01, + 0x48, 0x04, 0x03, 0x62, 0x2A, 0x28, 0x00, 0x00, 0x81, 0x12, 0x01, 0x0C, + 0x12, 0x01, 0x02, 0x10, 0x00, 0x00, 0x81, 0x12, 0x01, 0x0C, 0x12, 0x29, + 0x59, 0x46, 0x01, 0x03, 0x0B, 0x13, 0x00, 0x00, 0x81, 0x12, 0x01, 0x0C, + 0x12, 0x01, 0x01, 0x0F, 0x00, 0x00, 0x81, 0x12, 0x01, 0x0C, 0x12, 0x58, + 0x00, 0x00, 0x1B, 0x01, 0x00, 0x6D, 0x2F, 0x29, 0x06, 0x20, 0x01, 0x01, + 0x39, 0x0F, 0x06, 0x07, 0x28, 0x01, 0x00, 0x81, 0x16, 0x04, 0x11, 0x01, + 0x02, 0x39, 0x0F, 0x06, 0x0A, 0x28, 0x6F, 0x2F, 0x06, 0x03, 0x01, 0x10, + 0x38, 0x04, 0x01, 0x28, 0x04, 0x01, 0x28, 0x75, 0x2F, 0x05, 0x35, 0x30, + 0x06, 0x32, 0x7F, 0x2F, 0x01, 0x14, 0x39, 0x0F, 0x06, 0x06, 0x28, 0x01, + 0x02, 0x38, 0x04, 0x24, 0x01, 0x15, 0x39, 0x0F, 0x06, 0x0B, 0x28, 0x81, + 0x1F, 0x06, 0x04, 0x01, 0x7F, 0x81, 0x16, 0x04, 0x13, 0x01, 0x16, 0x39, + 0x0F, 0x06, 0x06, 0x28, 0x01, 0x01, 0x38, 0x04, 0x07, 0x28, 0x01, 0x04, + 0x38, 0x01, 0x00, 0x28, 0x19, 0x06, 0x03, 0x01, 0x08, 0x38, 0x00, 0x00, + 0x1B, 0x29, 0x05, 0x10, 0x30, 0x06, 0x0D, 0x7F, 0x2F, 0x01, 0x15, 0x0F, + 0x06, 0x05, 0x28, 0x81, 0x1F, 0x04, 0x01, 0x22, 0x00, 0x00, 0x81, 0x42, + 0x01, 0x07, 0x13, 0x01, 0x01, 0x10, 0x06, 0x02, 0x6B, 0x2A, 0x00, 0x01, + 0x03, 0x00, 0x2B, 0x19, 0x06, 0x06, 0x02, 0x00, 0x81, 0x00, 0x41, 0x00, + 0x81, 0x42, 0x28, 0x04, 0x72, 0x00, 0x01, 0x14, 0x81, 0x45, 0x01, 0x01, + 0x81, 0x55, 0x2B, 0x29, 0x01, 0x00, 0x81, 0x3D, 0x01, 0x16, 0x81, 0x45, + 0x81, 0x49, 0x2B, 0x00, 0x00, 0x01, 0x0B, 0x81, 0x55, 0x4C, 0x29, 0x29, + 0x01, 0x03, 0x08, 0x81, 0x54, 0x81, 0x54, 0x14, 0x29, 0x56, 0x06, 0x02, + 0x28, 0x00, 0x81, 0x54, 0x1E, 0x29, 0x06, 0x06, 0x7D, 0x46, 0x81, 0x4D, + 0x04, 0x76, 0x28, 0x04, 0x6A, 0x00, 0x01, 0x00, 0x81, 0x4F, 0x81, 0x0B, + 0x2D, 0x01, 0x86, 0x03, 0x11, 0x06, 0x06, 0x5C, 0x01, 0x00, 0x81, 0x50, + 0x08, 0x4B, 0x08, 0x01, 0x03, 0x08, 0x01, 0x0D, 0x81, 0x55, 0x81, 0x54, + 0x01, 0x00, 0x81, 0x4F, 0x81, 0x55, 0x01, 0x01, 0x81, 0x4F, 0x28, 0x81, + 0x0B, 0x2D, 0x01, 0x86, 0x03, 0x11, 0x06, 0x0B, 0x01, 0x00, 0x81, 0x50, + 0x81, 0x53, 0x01, 0x01, 0x81, 0x50, 0x28, 0x4B, 0x81, 0x53, 0x16, 0x15, + 0x29, 0x56, 0x06, 0x02, 0x28, 0x00, 0x81, 0x53, 0x1F, 0x29, 0x06, 0x06, + 0x7D, 0x46, 0x81, 0x4D, 0x04, 0x76, 0x28, 0x04, 0x6A, 0x00, 0x81, 0x14, + 0x01, 0x14, 0x81, 0x55, 0x01, 0x0C, 0x81, 0x54, 0x7D, 0x01, 0x0C, 0x81, + 0x4D, 0x00, 0x03, 0x03, 0x00, 0x01, 0x02, 0x81, 0x55, 0x01, 0x80, 0x46, + 0x81, 0x01, 0x2F, 0x01, 0x02, 0x0F, 0x06, 0x0C, 0x02, 0x00, 0x06, 0x04, + 0x01, 0x05, 0x04, 0x02, 0x01, 0x1D, 0x04, 0x02, 0x01, 0x00, 0x03, 0x01, + 0x7E, 0x2F, 0x06, 0x04, 0x01, 0x05, 0x04, 0x02, 0x01, 0x00, 0x03, 0x02, + 0x02, 0x01, 0x02, 0x02, 0x08, 0x29, 0x06, 0x03, 0x01, 0x02, 0x08, 0x08, + 0x81, 0x54, 0x81, 0x0B, 0x2D, 0x81, 0x53, 0x81, 0x04, 0x01, 0x04, 0x17, + 0x81, 0x04, 0x01, 0x04, 0x08, 0x01, 0x1C, 0x33, 0x81, 0x04, 0x01, 0x20, + 0x81, 0x4D, 0x01, 0x20, 0x81, 0x55, 0x81, 0x05, 0x01, 0x20, 0x81, 0x4D, + 0x70, 0x2D, 0x81, 0x53, 0x01, 0x00, 0x81, 0x55, 0x02, 0x01, 0x02, 0x02, + 0x08, 0x29, 0x06, 0x31, 0x81, 0x53, 0x02, 0x01, 0x29, 0x06, 0x14, 0x01, + 0x83, 0xFE, 0x01, 0x81, 0x53, 0x01, 0x04, 0x09, 0x29, 0x81, 0x53, 0x5B, + 0x81, 0x02, 0x46, 0x81, 0x4E, 0x04, 0x01, 0x28, 0x02, 0x02, 0x06, 0x0F, + 0x01, 0x01, 0x81, 0x53, 0x01, 0x01, 0x81, 0x53, 0x7E, 0x2F, 0x01, 0x08, + 0x09, 0x81, 0x55, 0x04, 0x01, 0x28, 0x00, 0x00, 0x01, 0x0E, 0x81, 0x55, + 0x01, 0x00, 0x81, 0x54, 0x00, 0x03, 0x70, 0x2D, 0x81, 0x3F, 0x05, 0x01, + 0x00, 0x76, 0x2E, 0x01, 0x00, 0x81, 0x18, 0x12, 0x01, 0x01, 0x13, 0x58, + 0x06, 0x03, 0x5A, 0x04, 0x74, 0x03, 0x00, 0x28, 0x02, 0x00, 0x24, 0x29, + 0x56, 0x06, 0x02, 0x36, 0x2A, 0x03, 0x01, 0x81, 0x0B, 0x2D, 0x01, 0x86, + 0x03, 0x11, 0x03, 0x02, 0x01, 0x0C, 0x81, 0x55, 0x02, 0x01, 0x78, 0x2F, + 0x08, 0x02, 0x02, 0x01, 0x02, 0x13, 0x08, 0x01, 0x06, 0x08, 0x81, 0x54, + 0x01, 0x03, 0x81, 0x55, 0x02, 0x00, 0x81, 0x53, 0x77, 0x78, 0x2F, 0x81, + 0x4E, 0x02, 0x02, 0x06, 0x11, 0x81, 0x08, 0x2F, 0x81, 0x55, 0x70, 0x2D, + 0x81, 0x40, 0x01, 0x01, 0x0C, 0x01, 0x03, 0x08, 0x81, 0x55, 0x02, 0x01, + 0x81, 0x53, 0x7D, 0x02, 0x01, 0x81, 0x4D, 0x00, 0x00, 0x4F, 0x29, 0x01, + 0x00, 0x0F, 0x06, 0x02, 0x5D, 0x00, 0x81, 0x42, 0x28, 0x04, 0x72, 0x00, + 0x29, 0x81, 0x55, 0x81, 0x4D, 0x00, 0x00, 0x01, 0x00, 0x70, 0x2D, 0x81, + 0x3E, 0x06, 0x0E, 0x5C, 0x39, 0x06, 0x0A, 0x01, 0x80, 0x41, 0x81, 0x55, + 0x01, 0x80, 0x42, 0x81, 0x55, 0x45, 0x06, 0x08, 0x5A, 0x39, 0x06, 0x04, + 0x01, 0x01, 0x81, 0x55, 0x44, 0x06, 0x09, 0x5A, 0x39, 0x06, 0x05, 0x01, + 0x80, 0x40, 0x81, 0x55, 0x46, 0x28, 0x00, 0x01, 0x01, 0x00, 0x03, 0x00, + 0x45, 0x44, 0x38, 0x05, 0x16, 0x01, 0x01, 0x01, 0x80, 0x7C, 0x81, 0x51, + 0x03, 0x00, 0x01, 0x03, 0x01, 0x80, 0x7C, 0x81, 0x51, 0x02, 0x00, 0x08, + 0x46, 0x28, 0x00, 0x45, 0x06, 0x08, 0x01, 0x01, 0x43, 0x28, 0x81, 0x51, + 0x03, 0x00, 0x44, 0x06, 0x0B, 0x01, 0x03, 0x43, 0x28, 0x81, 0x51, 0x02, + 0x00, 0x08, 0x03, 0x00, 0x28, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, + 0x04, 0x81, 0x52, 0x01, 0x05, 0x81, 0x52, 0x01, 0x06, 0x81, 0x52, 0x01, + 0x03, 0x81, 0x52, 0x01, 0x02, 0x81, 0x52, 0x0A, 0x5D, 0x00, 0x01, 0x03, + 0x00, 0x39, 0x01, 0x01, 0x02, 0x00, 0x0C, 0x13, 0x05, 0x01, 0x00, 0x5C, + 0x01, 0x03, 0x3A, 0x06, 0x09, 0x02, 0x00, 0x81, 0x55, 0x01, 0x02, 0x3A, + 0x81, 0x55, 0x00, 0x00, 0x29, 0x01, 0x08, 0x4D, 0x81, 0x55, 0x81, 0x55, + 0x00, 0x00, 0x29, 0x01, 0x10, 0x4D, 0x81, 0x55, 0x81, 0x53, 0x00, 0x00, + 0x29, 0x50, 0x06, 0x02, 0x28, 0x00, 0x81, 0x42, 0x28, 0x04, 0x75 }; static const uint16_t t0_caddr[] = { @@ -613,101 +788,117 @@ static const uint16_t t0_caddr[] = { 75, 79, 83, - 88, - 93, - 98, - 103, - 108, - 113, - 118, - 123, - 128, - 133, - 138, - 143, - 148, - 153, + 87, + 91, + 95, + 99, + 104, + 109, + 114, + 119, + 124, + 129, + 134, + 139, + 144, + 149, + 154, 159, 164, 169, - 174, - 179, - 184, - 189, - 194, - 199, - 204, - 209, - 214, - 219, - 224, - 229, - 234, - 239, - 244, - 249, - 254, - 259, - 268, - 272, - 297, - 303, - 323, - 334, - 371, - 431, - 435, - 471, - 481, - 557, - 571, - 577, - 637, - 657, - 710, - 1267, - 1352, - 1385, - 1410, - 1458, - 1532, - 1581, - 1596, - 1607, - 1613, - 1684, - 1725, - 1738, - 1757, - 1764, - 1776, - 1811, - 1840, - 1852, - 1859, - 1875, - 2013, - 2022, - 2035, - 2044, - 2051, - 2157, - 2179, - 2193, + 175, + 180, + 185, + 190, + 195, + 200, + 205, + 210, + 215, + 220, + 225, + 230, + 235, + 240, + 245, + 250, + 255, + 260, + 265, + 270, + 275, + 284, + 288, + 316, + 322, + 343, + 354, + 391, + 523, + 527, + 563, + 573, + 650, + 664, + 671, + 731, + 752, + 776, + 829, + 915, + 1023, + 1035, + 1630, + 1636, + 1713, + 1724, + 1759, + 1785, + 1833, + 1910, + 1963, + 1978, + 1989, + 1995, + 2064, + 2076, + 2119, + 2133, + 2153, + 2161, + 2173, 2210, - 2233, - 2269, - 2285, - 2439, - 2449, - 2558, - 2573, - 2580, - 2590, - 2600 + 2241, + 2254, + 2261, + 2278, + 2417, + 2427, + 2441, + 2451, + 2459, + 2565, + 2587, + 2601, + 2619, + 2642, + 2679, + 2767, + 2784, + 2945, + 2955, + 3066, + 3081, + 3088, + 3137, + 3198, + 3224, + 3253, + 3263, + 3273 }; -#define T0_INTERPRETED 68 +#define T0_INTERPRETED 86 #define T0_ENTER(ip, rp, slot) do { \ const unsigned char *t0_newip; \ @@ -728,7 +919,7 @@ name(void *ctx) \ T0_ENTER(t0ctx->ip, t0ctx->rp, slot); \ } -T0_DEFENTRY(br_ssl_hs_server_init_main, 133) +T0_DEFENTRY(br_ssl_hs_server_init_main, 155) void br_ssl_hs_server_run(void *t0ctx) @@ -853,6 +1044,11 @@ br_ssl_hs_server_run(void *t0ctx) } break; case 10: { + /* -rot */ + T0_NROT(); + } + break; + case 11: { /* < */ int32_t b = T0_POPi(); @@ -861,7 +1057,7 @@ br_ssl_hs_server_run(void *t0ctx) } break; - case 11: { + case 12: { /* << */ int c = (int)T0_POPi(); @@ -870,7 +1066,7 @@ br_ssl_hs_server_run(void *t0ctx) } break; - case 12: { + case 13: { /* <= */ int32_t b = T0_POPi(); @@ -879,7 +1075,7 @@ br_ssl_hs_server_run(void *t0ctx) } break; - case 13: { + case 14: { /* <> */ uint32_t b = T0_POP(); @@ -888,7 +1084,7 @@ br_ssl_hs_server_run(void *t0ctx) } break; - case 14: { + case 15: { /* = */ uint32_t b = T0_POP(); @@ -897,7 +1093,7 @@ br_ssl_hs_server_run(void *t0ctx) } break; - case 15: { + case 16: { /* > */ int32_t b = T0_POPi(); @@ -906,7 +1102,7 @@ br_ssl_hs_server_run(void *t0ctx) } break; - case 16: { + case 17: { /* >= */ int32_t b = T0_POPi(); @@ -915,7 +1111,7 @@ br_ssl_hs_server_run(void *t0ctx) } break; - case 17: { + case 18: { /* >> */ int c = (int)T0_POPi(); @@ -924,7 +1120,7 @@ br_ssl_hs_server_run(void *t0ctx) } break; - case 18: { + case 19: { /* and */ uint32_t b = T0_POP(); @@ -933,22 +1129,49 @@ br_ssl_hs_server_run(void *t0ctx) } break; - case 19: { + case 20: { /* begin-cert */ - if (CTX->chain_len == 0) { + if (ENG->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); + ENG->cert_cur = ENG->chain->data; + ENG->cert_len = ENG->chain->data_len; + ENG->chain ++; + ENG->chain_len --; + T0_PUSH(ENG->cert_len); } } break; - case 20: { + case 21: { + /* begin-ta-name */ + + 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); + } + + } + break; + case 22: { + /* begin-ta-name-list */ + + CTX->cur_dn_index = 0; + + } + break; + case 23: { /* bzero */ size_t len = (size_t)T0_POP(); @@ -957,7 +1180,7 @@ br_ssl_hs_server_run(void *t0ctx) } break; - case 21: { + case 24: { /* call-policy-handler */ int x; @@ -967,20 +1190,20 @@ br_ssl_hs_server_run(void *t0ctx) CTX->policy_vtable, CTX, &choices); ENG->session.cipher_suite = choices.cipher_suite; CTX->sign_hash_id = choices.hash_id; - CTX->chain = choices.chain; - CTX->chain_len = choices.chain_len; + ENG->chain = choices.chain; + ENG->chain_len = choices.chain_len; T0_PUSHi(-(x != 0)); } break; - case 22: { + case 25: { /* can-output? */ T0_PUSHi(-(ENG->hlen_out > 0)); } break; - case 23: { + case 26: { /* check-resume */ if (ENG->session.session_id_len == 32 @@ -994,12 +1217,12 @@ br_ssl_hs_server_run(void *t0ctx) } break; - case 24: { + case 27: { /* co */ T0_CO(); } break; - case 25: { + case 28: { /* compute-Finished-inner */ int prf_id = T0_POP(); @@ -1022,23 +1245,75 @@ br_ssl_hs_server_run(void *t0ctx) } break; - case 26: { + case 29: { + /* compute-hash-CV */ + + int i; + + for (i = 1; i <= 6; i ++) { + br_multihash_out(&ENG->mhash, i, + ENG->pad + HASH_PAD_OFF[i - 1]); + } + + } + break; + case 30: { /* copy-cert-chunk */ size_t clen; - clen = CTX->cert_len; + clen = ENG->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; + memcpy(ENG->pad, ENG->cert_cur, clen); + ENG->cert_cur += clen; + ENG->cert_len -= clen; T0_PUSH(clen); } break; - case 27: { + case 31: { + /* copy-dn-chunk */ + + 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); + + } + break; + case 32: { + /* copy-hash-CV */ + + 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); + + } + break; + case 33: { /* data-get8 */ size_t addr = T0_POP(); @@ -1046,14 +1321,14 @@ br_ssl_hs_server_run(void *t0ctx) } break; - case 28: { + case 34: { /* discard-input */ ENG->hlen_in = 0; } break; - case 29: { + case 35: { /* do-ecdh */ int prf_id = T0_POPi(); @@ -1062,7 +1337,7 @@ br_ssl_hs_server_run(void *t0ctx) } break; - case 30: { + case 36: { /* do-ecdhe-part1 */ int curve = T0_POPi(); @@ -1070,7 +1345,7 @@ br_ssl_hs_server_run(void *t0ctx) } break; - case 31: { + case 37: { /* do-ecdhe-part2 */ int prf_id = T0_POPi(); @@ -1079,7 +1354,7 @@ br_ssl_hs_server_run(void *t0ctx) } break; - case 32: { + case 38: { /* do-rsa-decrypt */ int prf_id = T0_POPi(); @@ -1088,17 +1363,24 @@ br_ssl_hs_server_run(void *t0ctx) } break; - case 33: { + case 39: { + /* do-static-ecdh */ + + do_static_ecdh(CTX, T0_POP()); + + } + break; + case 40: { /* drop */ (void)T0_POP(); } break; - case 34: { + case 41: { /* dup */ T0_PUSH(T0_PEEK(0)); } break; - case 35: { + case 42: { /* fail */ br_ssl_engine_fail(ENG, (int)T0_POPi()); @@ -1106,14 +1388,31 @@ br_ssl_hs_server_run(void *t0ctx) } break; - case 36: { + case 43: { /* flush-record */ br_ssl_engine_flush_record(ENG); } break; - case 37: { + case 44: { + /* get-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); + } + + } + break; + case 45: { /* get16 */ size_t addr = (size_t)T0_POP(); @@ -1121,7 +1420,7 @@ br_ssl_hs_server_run(void *t0ctx) } break; - case 38: { + case 46: { /* get32 */ size_t addr = (size_t)T0_POP(); @@ -1129,7 +1428,7 @@ br_ssl_hs_server_run(void *t0ctx) } break; - case 39: { + case 47: { /* get8 */ size_t addr = (size_t)T0_POP(); @@ -1137,14 +1436,14 @@ br_ssl_hs_server_run(void *t0ctx) } break; - case 40: { + case 48: { /* has-input? */ T0_PUSHi(-(ENG->hlen_in != 0)); } break; - case 41: { + case 49: { /* memcmp */ size_t len = (size_t)T0_POP(); @@ -1155,7 +1454,7 @@ br_ssl_hs_server_run(void *t0ctx) } break; - case 42: { + case 50: { /* memcpy */ size_t len = (size_t)T0_POP(); @@ -1165,7 +1464,7 @@ br_ssl_hs_server_run(void *t0ctx) } break; - case 43: { + case 51: { /* mkrand */ size_t len = (size_t)T0_POP(); @@ -1174,21 +1473,21 @@ br_ssl_hs_server_run(void *t0ctx) } break; - case 44: { + case 52: { /* more-incoming-bytes? */ T0_PUSHi(ENG->hlen_in != 0 || !br_ssl_engine_recvrec_finished(ENG)); } break; - case 45: { + case 53: { /* multihash-init */ br_multihash_init(&ENG->mhash); } break; - case 46: { + case 54: { /* neg */ uint32_t a = T0_POP(); @@ -1196,7 +1495,7 @@ br_ssl_hs_server_run(void *t0ctx) } break; - case 47: { + case 55: { /* not */ uint32_t a = T0_POP(); @@ -1204,7 +1503,7 @@ br_ssl_hs_server_run(void *t0ctx) } break; - case 48: { + case 56: { /* or */ uint32_t b = T0_POP(); @@ -1213,12 +1512,17 @@ br_ssl_hs_server_run(void *t0ctx) } break; - case 49: { + case 57: { /* over */ T0_PUSH(T0_PEEK(1)); } break; - case 50: { + case 58: { + /* pick */ + T0_PICK(T0_POP()); + } + break; + case 59: { /* read-chunk-native */ size_t clen = ENG->hlen_in; @@ -1242,7 +1546,7 @@ br_ssl_hs_server_run(void *t0ctx) } break; - case 51: { + case 60: { /* read8-native */ if (ENG->hlen_in > 0) { @@ -1260,7 +1564,7 @@ br_ssl_hs_server_run(void *t0ctx) } break; - case 52: { + case 61: { /* save-session */ if (CTX->cache_vtable != NULL) { @@ -1270,7 +1574,7 @@ br_ssl_hs_server_run(void *t0ctx) } break; - case 53: { + case 62: { /* set-max-frag-len */ size_t max_frag_len = T0_POP(); @@ -1289,7 +1593,7 @@ br_ssl_hs_server_run(void *t0ctx) } break; - case 54: { + case 63: { /* set16 */ size_t addr = (size_t)T0_POP(); @@ -1297,7 +1601,7 @@ br_ssl_hs_server_run(void *t0ctx) } break; - case 55: { + case 64: { /* set32 */ size_t addr = (size_t)T0_POP(); @@ -1305,7 +1609,7 @@ br_ssl_hs_server_run(void *t0ctx) } break; - case 56: { + case 65: { /* set8 */ size_t addr = (size_t)T0_POP(); @@ -1313,7 +1617,7 @@ br_ssl_hs_server_run(void *t0ctx) } break; - case 57: { + case 66: { /* supported-curves */ uint32_t x = ENG->iec == NULL ? 0 : ENG->iec->supported_curves; @@ -1321,7 +1625,7 @@ br_ssl_hs_server_run(void *t0ctx) } break; - case 58: { + case 67: { /* supported-hash-functions */ int i; @@ -1340,12 +1644,26 @@ br_ssl_hs_server_run(void *t0ctx) } break; - case 59: { + case 68: { + /* supports-ecdsa? */ + + T0_PUSHi(-(ENG->iecdsa != 0)); + + } + break; + case 69: { + /* supports-rsa-sign? */ + + T0_PUSHi(-(ENG->irsavrfy != 0)); + + } + break; + case 70: { /* swap */ T0_SWAP(); } break; - case 60: { + case 71: { /* switch-aesgcm-in */ int is_client, prf_id; @@ -1359,7 +1677,7 @@ br_ssl_hs_server_run(void *t0ctx) } break; - case 61: { + case 72: { /* switch-aesgcm-out */ int is_client, prf_id; @@ -1373,7 +1691,7 @@ br_ssl_hs_server_run(void *t0ctx) } break; - case 62: { + case 73: { /* switch-cbc-in */ int is_client, prf_id, mac_id, aes; @@ -1389,7 +1707,7 @@ br_ssl_hs_server_run(void *t0ctx) } break; - case 63: { + case 74: { /* switch-cbc-out */ int is_client, prf_id, mac_id, aes; @@ -1405,21 +1723,40 @@ br_ssl_hs_server_run(void *t0ctx) } break; - case 64: { + case 75: { + /* ta-names-total-length */ + + 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); + + } + break; + case 76: { /* total-chain-length */ 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; + for (u = 0; u < ENG->chain_len; u ++) { + total += 3 + (uint32_t)ENG->chain[u].data_len; } T0_PUSH(total); } break; - case 65: { + case 77: { /* u>> */ int c = (int)T0_POPi(); @@ -1428,7 +1765,17 @@ br_ssl_hs_server_run(void *t0ctx) } break; - case 66: { + case 78: { + /* verify-CV-sig */ + + int err; + + err = verify_CV_sig(CTX, T0_POP()); + T0_PUSHi(err); + + } + break; + case 79: { /* write-blob-chunk */ size_t clen = ENG->hlen_out; @@ -1452,7 +1799,7 @@ br_ssl_hs_server_run(void *t0ctx) } break; - case 67: { + case 80: { /* write8-native */ unsigned char x; @@ -1469,6 +1816,60 @@ br_ssl_hs_server_run(void *t0ctx) T0_PUSHi(0); } + } + break; + case 81: { + /* x509-append */ + + const br_x509_class *xc; + size_t len; + + xc = *(ENG->x509ctx); + len = T0_POP(); + xc->append(ENG->x509ctx, ENG->pad, len); + + } + break; + case 82: { + /* x509-end-cert */ + + const br_x509_class *xc; + + xc = *(ENG->x509ctx); + xc->end_cert(ENG->x509ctx); + + } + break; + case 83: { + /* x509-end-chain */ + + const br_x509_class *xc; + + xc = *(ENG->x509ctx); + T0_PUSH(xc->end_chain(ENG->x509ctx)); + + } + break; + case 84: { + /* x509-start-cert */ + + const br_x509_class *xc; + + xc = *(ENG->x509ctx); + xc->start_cert(ENG->x509ctx, T0_POP()); + + } + break; + case 85: { + /* x509-start-chain */ + + const br_x509_class *xc; + uint32_t bc; + + bc = T0_POP(); + xc = *(ENG->x509ctx); + xc->start_chain(ENG->x509ctx, bc ? ENG->server_name : NULL); + } break; } diff --git a/src/ssl/ssl_hs_server.t0 b/src/ssl/ssl_hs_server.t0 index 8176429..862e0fb 100644 --- a/src/ssl/ssl_hs_server.t0 +++ b/src/ssl/ssl_hs_server.t0 @@ -140,6 +140,35 @@ do_ecdh(br_ssl_server_context *ctx, int prf_id, ecdh_common(ctx, prf_id, cpoint, cpoint_len, x); } +/* + * Do the full static ECDH key exchange. When this function is called, + * it has already been verified that the cipher suite uses ECDH (not ECDHE), + * and the client's public key (from its certificate) has type EC and is + * apt for key exchange. + */ +static void +do_static_ecdh(br_ssl_server_context *ctx, int prf_id) +{ + unsigned char cpoint[133]; + size_t cpoint_len; + const br_x509_class **xc; + const br_x509_pkey *pk; + + xc = ctx->eng.x509ctx; + pk = (*xc)->get_pkey(xc, NULL); + cpoint_len = pk->key.ec.qlen; + if (cpoint_len > sizeof cpoint) { + /* + * If the point is larger than our buffer then we need to + * restrict it. Length 2 is not a valid point length, so + * the ECDH will fail. + */ + cpoint_len = 2; + } + memcpy(cpoint, pk->key.ec.q, cpoint_len); + do_ecdh(ctx, prf_id, cpoint, cpoint_len); +} + /* * Do the ECDHE key exchange (part 1: generation of transient key, and * computing of the point to send to the client). Returned value is the @@ -258,6 +287,94 @@ do_ecdhe_part2(br_ssl_server_context *ctx, int prf_id, memset(ctx->ecdhe_key, 0, ctx->ecdhe_key_len); } +/* + * Offset for hash value within the pad (when obtaining all hash values, + * in preparation for verification of the CertificateVerify message). + * Order is MD5, SHA-1, SHA-224, SHA-256, SHA-384, SHA-512; last value + * is used to get the total length. + */ +static const unsigned char HASH_PAD_OFF[] = { 0, 16, 36, 64, 96, 144, 208 }; + +/* + * OID for hash functions in RSA signatures. + */ +static const unsigned char HASH_OID_SHA1[] = { + 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A +}; + +static const unsigned char HASH_OID_SHA224[] = { + 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04 +}; + +static const unsigned char HASH_OID_SHA256[] = { + 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01 +}; + +static const unsigned char HASH_OID_SHA384[] = { + 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02 +}; + +static const unsigned char HASH_OID_SHA512[] = { + 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03 +}; + +static const unsigned char *HASH_OID[] = { + HASH_OID_SHA1, + HASH_OID_SHA224, + HASH_OID_SHA256, + HASH_OID_SHA384, + HASH_OID_SHA512 +}; + +/* + * Verify the signature in CertificateVerify. Returned value is 0 on + * success, or a non-zero error code. Lack of implementation of the + * designated signature algorithm is reported as a "bad signature" + * error (because it means that the peer did not honour our advertised + * set of supported signature algorithms). + */ +static int +verify_CV_sig(br_ssl_server_context *ctx, size_t sig_len) +{ + const br_x509_class **xc; + const br_x509_pkey *pk; + int id; + + id = ctx->hash_CV_id; + xc = ctx->eng.x509ctx; + pk = (*xc)->get_pkey(xc, NULL); + if (pk->key_type == BR_KEYTYPE_RSA) { + unsigned char tmp[64]; + const unsigned char *hash_oid; + + if (id == 0) { + hash_oid = NULL; + } else { + hash_oid = HASH_OID[id - 2]; + } + if (ctx->eng.irsavrfy == 0) { + return BR_ERR_BAD_SIGNATURE; + } + if (!ctx->eng.irsavrfy(ctx->eng.pad, sig_len, + hash_oid, ctx->hash_CV_len, &pk->key.rsa, tmp) + || memcmp(tmp, ctx->hash_CV, ctx->hash_CV_len) != 0) + { + return BR_ERR_BAD_SIGNATURE; + } + } else { + if (ctx->eng.iecdsa == 0) { + return BR_ERR_BAD_SIGNATURE; + } + if (!ctx->eng.iecdsa(ctx->eng.iec, + ctx->hash_CV, ctx->hash_CV_len, + &pk->key.ec, ctx->eng.pad, sig_len)) + { + return BR_ERR_BAD_SIGNATURE; + } + } + return 0; +} + } \ ======================================================================= @@ -386,26 +503,7 @@ cc: set-max-frag-len ( len -- ) { \ Open extension value. read16 open-elt - \ Clear list of supported signature algorithms. - 0 addr-hashes set16 - - \ Get list of algorithms length. - read16 open-elt - begin dup while - read8 { hash } read8 { sign } - \ We keep the value if the signature is either 1 (RSA) or - \ 3 (ECDSA), and the hash is one of the SHA-* functions - \ (2 to 6, from SHA-1 to SHA-512). Note that we reject - \ any use of MD5. Also, we do not keep track of the client - \ preferences. - hash 2 >= hash 6 <= and - sign 1 = sign 3 = or - and if - addr-hashes get16 - 1 sign 1- 2 << hash + << or addr-hashes set16 - then - repeat - close-elt + read-list-sign-algos addr-hashes set16 \ Close extension value. close-elt ; @@ -440,8 +538,8 @@ cc: call-policy-handler ( -- bool ) { CTX->policy_vtable, CTX, &choices); ENG->session.cipher_suite = choices.cipher_suite; CTX->sign_hash_id = choices.hash_id; - CTX->chain = choices.chain; - CTX->chain_len = choices.chain_len; + ENG->chain = choices.chain; + ENG->chain_len = choices.chain_len; T0_PUSHi(-(x != 0)); } @@ -667,11 +765,14 @@ cc: save-session ( -- ) { ok-compression ifnot 40 fail-alert then \ Filter hash function support by what the server also supports. - \ If no common hash function remains, then ECDHE suites are not - \ possible. + \ If no common hash function remains with RSA and/or ECDSA, then + \ the corresponding ECDHE suites are not possible. supported-hash-functions drop 257 * addr-hashes get16 and dup addr-hashes set16 - 0<> { can-ecdhe } + \ In 'can-ecdhe', bit 12 is set if ECDHE_RSA is possible, bit 13 is + \ set if ECDHE_ECDSA is possible. + dup 0xFF and 0<> neg + swap 8 >> 0<> 2 and or { can-ecdhe } \ Filter supported curves. If there is no common curve between \ client and us, then ECDHE suites cannot be used. Note that we @@ -684,6 +785,11 @@ cc: save-session ( -- ) { resume if -1 ret then \ We are not resuming, so a new session ID should be generated. + \ We don't check that the new ID is distinct from the one sent + \ by the client because probability of such an event is 2^(-256), + \ i.e. much (much) lower than that of an undetected transmission + \ error or hardware miscomputation, and with similar consequences + \ (handshake simply fails). addr-session_id 32 mkrand 32 addr-session_id_len set8 @@ -692,14 +798,14 @@ cc: save-session ( -- ) { \ server preference order is enforced, and also in case some \ suites are filtered out. In particular: \ -- ECDHE suites are removed if there is no common hash function - \ (for signatures) or no common curve. + \ (for the relevant signature algorithm) or no common curve. \ -- TLS-1.2-only suites are removed if the negociated version is \ TLS-1.1 or lower. addr-client_suites dup >css-off begin dup css-max < while dup get16 dup cipher-suite-to-elements - can-ecdhe ifnot - dup 12 >> dup 1 = swap 2 = or if + dup 12 >> dup 1 = swap 2 = or if + dup can-ecdhe and ifnot 2drop 0 dup then then @@ -791,63 +897,6 @@ cc: save-session ( -- ) { drop then ; -\ Compute total chain length. This includes the individual certificate -\ headers, but not the total chain header. This also sets the cert_cur, -\ cert_len and chain_len context fields. -cc: total-chain-length ( -- len ) { - size_t u; - uint32_t total; - - total = 0; - for (u = 0; u < CTX->chain_len; u ++) { - total += 3 + (uint32_t)CTX->chain[u].data_len; - } - T0_PUSH(total); -} - -\ Get length for current certificate in the chain; if the chain end was -\ reached, then this returns -1. -cc: begin-cert ( -- len ) { - if (CTX->chain_len == 0) { - T0_PUSHi(-1); - } else { - CTX->cert_cur = CTX->chain->data; - CTX->cert_len = CTX->chain->data_len; - CTX->chain ++; - CTX->chain_len --; - T0_PUSH(CTX->cert_len); - } -} - -\ Copy a chunk of certificate data into the pad. Returned value is the -\ chunk length, or 0 if the certificate end is reached. -cc: copy-cert-chunk ( -- len ) { - size_t clen; - - clen = CTX->cert_len; - if (clen > sizeof ENG->pad) { - clen = sizeof ENG->pad; - } - memcpy(ENG->pad, CTX->cert_cur, clen); - CTX->cert_cur += clen; - CTX->cert_len -= clen; - T0_PUSH(clen); -} - -\ Write the server Certificate. -: write-Certificate ( -- ) - 11 write8 - total-chain-length - dup 3 + write24 write24 - begin - begin-cert - dup 0< if drop ret then write24 - begin copy-cert-chunk dup while - addr-pad swap write-blob - repeat - drop - again ; - \ Do the first part of ECDHE. Returned value is the computed signature \ length, or a negative error code on error. cc: do-ecdhe-part1 ( curve -- len ) { @@ -900,6 +949,166 @@ cc: do-ecdhe-part1 ( curve -- len ) { sig-len write16 addr-pad sig-len write-blob ; +\ Get length of the list of anchor names to send to the client. The length +\ includes the per-name 2-byte header, but _not_ the 2-byte header for +\ the list itself. If no client certificate is requested, then this +\ returns 0. +cc: ta-names-total-length ( -- len ) { + size_t u, len; + + len = 0; + if (CTX->ta_names != NULL) { + for (u = 0; u < CTX->num_tas; u ++) { + len += CTX->ta_names[u].len + 2; + } + } else if (CTX->tas != NULL) { + for (u = 0; u < CTX->num_tas; u ++) { + len += CTX->tas[u].dn.len + 2; + } + } + T0_PUSH(len); +} + +\ Compute length and optionally write the contents of the list of +\ supported client authentication methods. +: write-list-auth ( do_write -- len ) + 0 + addr-cipher_suite get16 use-ecdh? if + 2+ over if 65 write8 66 write8 then + then + supports-rsa-sign? if 1+ over if 1 write8 then then + supports-ecdsa? if 1+ over if 64 write8 then then + swap drop ; + +: write-signhash-inner2 ( dow algo hashes len id -- dow algo hashes len ) + { id } + over 1 id << and ifnot ret then + 2+ + 3 pick if id write8 2 pick write8 then ; + +: write-signhash-inner1 ( dow algo hashes -- dow len ) + 0 + 4 write-signhash-inner2 + 5 write-signhash-inner2 + 6 write-signhash-inner2 + 3 write-signhash-inner2 + 2 write-signhash-inner2 + -rot 2drop ; + +\ Compute length and optionally write the contents of the list of +\ supported sign+hash algorithms. +: write-list-signhash ( do_write -- len ) + 0 { len } + \ If supporting neither RSA nor ECDSA in the engine, then we + \ will do only static ECDH, and thus we claim support for + \ everything (for the X.509 validator). + supports-rsa-sign? supports-ecdsa? or ifnot + 1 0x7C write-signhash-inner1 >len + 3 0x7C write-signhash-inner1 len + + swap drop ret + then + supports-rsa-sign? if + 1 supported-hash-functions drop + write-signhash-inner1 >len + then + supports-ecdsa? if + 3 supported-hash-functions drop + write-signhash-inner1 len + >len + then + drop len ; + +\ Initialise index for sending the list of anchor DN. +cc: begin-ta-name-list ( -- ) { + CTX->cur_dn_index = 0; +} + +\ Switch to next DN in the list. Returned value is the DN length, or -1 +\ if the end of the list was reached. +cc: begin-ta-name ( -- len ) { + const br_x500_name *dn; + if (CTX->cur_dn_index >= CTX->num_tas) { + T0_PUSHi(-1); + } else { + if (CTX->ta_names == NULL) { + dn = &CTX->tas[CTX->cur_dn_index].dn; + } else { + dn = &CTX->ta_names[CTX->cur_dn_index]; + } + CTX->cur_dn_index ++; + CTX->cur_dn = dn->data; + CTX->cur_dn_len = dn->len; + T0_PUSH(CTX->cur_dn_len); + } +} + +\ Copy a chunk of the current DN into the pad. Returned value is the +\ chunk length; this is 0 when the end of the current DN is reached. +cc: copy-dn-chunk ( -- len ) { + size_t clen; + + clen = CTX->cur_dn_len; + if (clen > sizeof ENG->pad) { + clen = sizeof ENG->pad; + } + memcpy(ENG->pad, CTX->cur_dn, clen); + CTX->cur_dn += clen; + CTX->cur_dn_len -= clen; + T0_PUSH(clen); +} + +\ Write a CertificateRequest message. +: write-CertificateRequest ( -- ) + \ The list of client authentication types includes: + \ rsa_sign (1) + \ ecdsa_sign (64) + \ rsa_fixed_ecdh (65) + \ ecdsa_fixed_ecdh (66) + \ rsa_sign and ecdsa_sign require, respectively, RSA and ECDSA + \ support. Static ECDH requires that the cipher suite is ECDH. + \ When we ask for static ECDH, we always send both rsa_fixed_ecdh + \ and ecdsa_fixed_ecdh because what matters there is what the + \ X.509 engine may support, and we do not control that. + \ + \ With TLS 1.2, we must also send a list of supported signature + \ and hash algorithms. That list is supposed to qualify both + \ the engine itself, and the X.509 validator, which are separate + \ in BearSSL. There again, we use the engine capabilities in that + \ list, and resort to a generic all-support list if only + \ static ECDH is accepted. + \ + \ (In practice, client implementations tend to have at most one + \ or two certificates, and send the chain regardless of what + \ algorithms are used in it.) + + 0 write-list-auth + addr-version get16 0x0303 >= if + 2+ 0 write-list-signhash + + then + ta-names-total-length + 3 + + + \ Message header + 13 write8 write24 + + \ List of authentication methods + 0 write-list-auth write8 1 write-list-auth drop + + \ For TLS 1.2+, list of sign+hash + addr-version get16 0x0303 >= if + 0 write-list-signhash write16 1 write-list-signhash drop + then + + \ Trust anchor names + ta-names-total-length write16 + begin-ta-name-list + begin + begin-ta-name + dup 0< if drop ret then write16 + begin copy-dn-chunk dup while + addr-pad swap write-blob + repeat + drop + again ; + \ Write the Server Hello Done message. : write-ServerHelloDone ( -- ) 14 write8 0 write24 ; @@ -927,11 +1136,18 @@ cc: do-ecdhe-part2 ( len prf_id -- ) { do_ecdhe_part2(CTX, prf_id, ENG->pad, len); } -\ Read the Client Key Exchange. -: read-ClientKeyExchange ( -- ) - \ Get header, and check message type. - read-handshake-header 16 = ifnot ERR_UNEXPECTED fail then +\ Perform static ECDH. The point from the client is the public key +\ extracted from its certificate. +cc: do-static-ecdh ( prf_id -- ) { + do_static_ecdh(CTX, T0_POP()); +} +\ Read a ClientKeyExchange header. +: read-ClientKeyExchange-header ( -- len ) + read-handshake-header 16 = ifnot ERR_UNEXPECTED fail then ; + +\ Read the Client Key Exchange contents (non-empty case). +: read-ClientKeyExchange-contents ( lim -- ) \ What we should get depends on the cipher suite. addr-cipher_suite get16 use-rsa-keyx? if \ RSA key exchange: we expect a RSA-encrypted value. @@ -951,6 +1167,116 @@ cc: do-ecdhe-part2 ( len prf_id -- ) { then close-elt ; +\ Read the Client Key Exchange (normal case). +: read-ClientKeyExchange ( -- ) + read-ClientKeyExchange-header + read-ClientKeyExchange-contents ; + +\ Obtain all possible hash values for handshake messages so far. This +\ is done because we need the hash value for the CertificateVerify +\ _before_ knowing which hash function will actually be used, as this +\ information is obtained from decoding the message header itself. +\ All hash values are stored in the pad (208 bytes in total). +cc: compute-hash-CV ( -- ) { + int i; + + for (i = 1; i <= 6; i ++) { + br_multihash_out(&ENG->mhash, i, + ENG->pad + HASH_PAD_OFF[i - 1]); + } +} + +\ Copy the proper hash value from the pad into the dedicated buffer. +\ Returned value is true (-1) on success, false (0) on error (error +\ being an unimplemented hash function). The id has already been verified +\ to be either 0 (for MD5+SHA-1) or one of the SHA-* functions. +cc: copy-hash-CV ( hash_id -- bool ) { + int id = T0_POP(); + size_t off, len; + + if (id == 0) { + off = 0; + len = 36; + } else { + if (br_multihash_getimpl(&ENG->mhash, id) == 0) { + T0_PUSH(0); + T0_RET(); + } + off = HASH_PAD_OFF[id - 1]; + len = HASH_PAD_OFF[id] - off; + } + memcpy(CTX->hash_CV, ENG->pad + off, len); + CTX->hash_CV_len = len; + CTX->hash_CV_id = id; + T0_PUSHi(-1); +} + +\ Verify signature in CertificateVerify. Output is 0 on success, or a +\ non-zero error code. +cc: verify-CV-sig ( sig-len -- err ) { + int err; + + err = verify_CV_sig(CTX, T0_POP()); + T0_PUSHi(err); +} + +\ Process static ECDH. +: process-static-ECDH ( ktu -- ) + \ Static ECDH is allowed only if the cipher suite uses ECDH, and + \ the client's public key has type EC and allows key exchange. + \ BR_KEYTYPE_KEYX is 0x10, and BR_KEYTYPE_EC is 2. + 0x1F and 0x12 = ifnot ERR_WRONG_KEY_USAGE fail then + addr-cipher_suite get16 + dup use-ecdh? ifnot ERR_UNEXPECTED fail then + prf-id + do-static-ecdh ; + +\ Read CertificateVerify header. +: read-CertificateVerify-header ( -- lim ) + compute-hash-CV + read-handshake-header 15 = ifnot ERR_UNEXPECTED fail then ; + +\ Read CertificateVerify. The client key type + usage is expected on the +\ stack. +: read-CertificateVerify ( ktu -- ) + \ Check that the key allows for signatures. + dup 0x20 and ifnot ERR_WRONG_KEY_USAGE fail then + 0x0F and { key-type } + + \ Get header. + read-CertificateVerify-header + + \ With TLS 1.2+, there is an explicit hash + signature indication, + \ which must be compatible with the key type. + addr-version get16 0x0303 >= if + \ Get hash function, then signature algorithm. The + \ signature algorithm is 1 (RSA) or 3 (ECDSA) while our + \ symbolic constants for key types are 1 (RSA) or 2 (EC). + read16 + dup 0xFF and 1+ 1 >> key-type = ifnot + ERR_BAD_SIGNATURE fail + then + 8 >> + + \ We support only SHA-1, SHA-224, SHA-256, SHA-384 + \ and SHA-512. We explicitly reject MD5. + dup 2 < over 6 > or if ERR_INVALID_ALGORITHM fail then + else + \ With TLS 1.0 and 1.1, hash is MD5+SHA-1 (0) for RSA, + \ SHA-1 (2) for ECDSA. + key-type 0x01 = if 0 else 2 then + then + copy-hash-CV ifnot ERR_INVALID_ALGORITHM fail then + + \ Read signature. + read16 dup { sig-len } + dup 512 > if ERR_LIMIT_EXCEEDED fail then + addr-pad swap read-blob + sig-len verify-CV-sig + dup if fail then drop + + close-elt ; + \ Send a HelloRequest. : send-HelloRequest ( -- ) flush-record @@ -974,11 +1300,54 @@ cc: do-ecdhe-part2 ( len prf_id -- ) { else \ Not a session resumption write-ServerHello - write-Certificate + write-Certificate drop write-ServerKeyExchange + ta-names-total-length if + write-CertificateRequest + then write-ServerHelloDone flush-record - read-ClientKeyExchange + + \ If we sent a CertificateRequest then we expect a + \ Certificate message. + ta-names-total-length if + \ Read client certificate. + 0 read-Certificate + + choice + dup 0< uf + \ Client certificate validation failed. + 2 flag? ifnot neg fail then + drop + read-ClientKeyExchange + read-CertificateVerify-header + dup skip-blob drop + enduf + dup 0= uf + \ Client sent no certificate at all. + drop + 2 flag? ifnot + ERR_NO_CLIENT_AUTH fail + then + read-ClientKeyExchange + enduf + + \ Client certificate was validated. + read-ClientKeyExchange-header + dup ifnot + \ Empty ClientKeyExchange. + drop + process-static-ECDH + else + read-ClientKeyExchange-contents + read-CertificateVerify + then + endchoice + else + \ No client certificate request, we just expect + \ a non-empty ClientKeyExchange. + read-ClientKeyExchange + then 0 read-CCS-Finished 0 write-CCS-Finished save-session diff --git a/src/ssl/ssl_single_ec.c b/src/ssl/ssl_scert_single_ec.c similarity index 99% rename from src/ssl/ssl_single_ec.c rename to src/ssl/ssl_scert_single_ec.c index 4edaca3..2648670 100644 --- a/src/ssl/ssl_single_ec.c +++ b/src/ssl/ssl_scert_single_ec.c @@ -36,7 +36,7 @@ se_choose(const br_ssl_server_policy_class **pctx, pc = (br_ssl_server_policy_ec_context *)pctx; st = br_ssl_server_get_client_suites(cc, &st_num); - hash_id = br_ssl_choose_hash(br_ssl_server_get_client_hashes(cc)); + hash_id = br_ssl_choose_hash(br_ssl_server_get_client_hashes(cc) >> 8); if (cc->eng.session.version < BR_TLS12) { hash_id = br_sha1_ID; } diff --git a/src/ssl/ssl_single_rsa.c b/src/ssl/ssl_scert_single_rsa.c similarity index 100% rename from src/ssl/ssl_single_rsa.c rename to src/ssl/ssl_scert_single_rsa.c diff --git a/src/x509/x509_knownkey.c b/src/x509/x509_knownkey.c index f00c32b..7674f3f 100644 --- a/src/x509/x509_knownkey.c +++ b/src/x509/x509_knownkey.c @@ -27,29 +27,29 @@ /* see bearssl_x509.h */ void br_x509_knownkey_init_rsa(br_x509_knownkey_context *ctx, - const br_rsa_public_key *pk) + const br_rsa_public_key *pk, unsigned usages) { ctx->vtable = &br_x509_knownkey_vtable; ctx->pkey.key_type = BR_KEYTYPE_RSA; ctx->pkey.key.rsa = *pk; + ctx->usages = usages; } /* see bearssl_x509.h */ void br_x509_knownkey_init_ec(br_x509_knownkey_context *ctx, - const br_ec_public_key *pk) + const br_ec_public_key *pk, unsigned usages) { ctx->vtable = &br_x509_knownkey_vtable; ctx->pkey.key_type = BR_KEYTYPE_EC; ctx->pkey.key.ec = *pk; + ctx->usages = usages; } static void -kk_start_chain(const br_x509_class **ctx, - unsigned expected_key_type, const char *server_name) +kk_start_chain(const br_x509_class **ctx, const char *server_name) { (void)ctx; - (void)expected_key_type; (void)server_name; } @@ -82,9 +82,15 @@ kk_end_chain(const br_x509_class **ctx) } static const br_x509_pkey * -kk_get_pkey(const br_x509_class *const *ctx) +kk_get_pkey(const br_x509_class *const *ctx, unsigned *usages) { - return &((const br_x509_knownkey_context *)ctx)->pkey; + const br_x509_knownkey_context *xc; + + xc = (const br_x509_knownkey_context *)ctx; + if (usages != NULL) { + *usages = xc->usages; + } + return &xc->pkey; } /* see bearssl_x509.h */ diff --git a/src/x509/x509_minimal.c b/src/x509/x509_minimal.c index 55d9e23..d022b00 100644 --- a/src/x509/x509_minimal.c +++ b/src/x509/x509_minimal.c @@ -239,8 +239,7 @@ br_x509_minimal_init(br_x509_minimal_context *ctx, } static void -xm_start_chain(const br_x509_class **ctx, - unsigned expected_key_type, const char *server_name) +xm_start_chain(const br_x509_class **ctx, const char *server_name) { br_x509_minimal_context *cc; @@ -251,7 +250,6 @@ xm_start_chain(const br_x509_class **ctx, cc->cpu.dp = cc->dp_stack; cc->cpu.rp = cc->rp_stack; br_x509_minimal_init_main(&cc->cpu); - cc->expected_key_type = expected_key_type; if (server_name == NULL || *server_name == 0) { cc->server_name = NULL; } else { @@ -320,7 +318,7 @@ xm_end_chain(const br_x509_class **ctx) } static const br_x509_pkey * -xm_get_pkey(const br_x509_class *const *ctx) +xm_get_pkey(const br_x509_class *const *ctx, unsigned *usages) { br_x509_minimal_context *cc; @@ -328,6 +326,9 @@ xm_get_pkey(const br_x509_class *const *ctx) if (cc->err == BR_ERR_X509_OK || cc->err == BR_ERR_X509_NOT_TRUSTED) { + if (usages != NULL) { + *usages = cc->key_usages; + } return &((br_x509_minimal_context *)ctx)->pkey; } else { return NULL; @@ -518,7 +519,6 @@ static const uint8_t t0_codeblock[] = { T0_INT1(BR_ERR_X509_UNEXPECTED), 0x00, 0x00, 0x01, T0_INT1(BR_ERR_X509_UNSUPPORTED), 0x00, 0x00, 0x01, T0_INT1(BR_ERR_X509_WEAK_PUBLIC_KEY), 0x00, 0x00, 0x01, - T0_INT1(BR_ERR_X509_WRONG_KEY_TYPE), 0x00, 0x00, 0x01, T0_INT1(BR_KEYTYPE_EC), 0x00, 0x00, 0x01, T0_INT1(BR_KEYTYPE_RSA), 0x00, 0x00, 0x01, T0_INT2(offsetof(CONTEXT_NAME, cert_length)), 0x00, 0x00, 0x01, T0_INT2(offsetof(CONTEXT_NAME, cert_sig)), 0x00, 0x00, @@ -527,182 +527,182 @@ static const uint8_t t0_codeblock[] = { 0x01, T0_INT2(offsetof(CONTEXT_NAME, cert_sig_len)), 0x00, 0x00, 0x01, T0_INT2(offsetof(CONTEXT_NAME, cert_signer_key_type)), 0x00, 0x00, 0x01, T0_INT2(offsetof(CONTEXT_NAME, current_dn_hash)), 0x00, 0x00, - 0x01, T0_INT2(offsetof(CONTEXT_NAME, expected_key_type)), 0x00, 0x00, - 0x01, T0_INT2(offsetof(br_x509_minimal_context, pkey_data)), 0x01, + 0x01, T0_INT2(offsetof(CONTEXT_NAME, key_usages)), 0x00, 0x00, 0x01, + T0_INT2(offsetof(br_x509_minimal_context, pkey_data)), 0x01, T0_INT2(BR_X509_BUFSIZE_KEY), 0x00, 0x00, 0x01, T0_INT2(offsetof(CONTEXT_NAME, min_rsa_size)), 0x00, 0x00, 0x01, T0_INT2(offsetof(CONTEXT_NAME, next_dn_hash)), 0x00, 0x00, 0x01, T0_INT2(offsetof(CONTEXT_NAME, num_certs)), 0x00, 0x00, 0x01, T0_INT2(offsetof(CONTEXT_NAME, pad)), 0x00, 0x00, 0x01, - T0_INT2(offsetof(CONTEXT_NAME, saved_dn_hash)), 0x00, 0x00, 0x81, 0x31, - 0x6E, 0x00, 0x00, 0x01, 0x80, 0x73, 0x00, 0x00, 0x01, 0x80, 0x7C, 0x00, + T0_INT2(offsetof(CONTEXT_NAME, saved_dn_hash)), 0x00, 0x00, 0x81, 0x2F, + 0x6C, 0x00, 0x00, 0x01, 0x80, 0x73, 0x00, 0x00, 0x01, 0x80, 0x7C, 0x00, 0x00, 0x01, 0x81, 0x02, 0x00, 0x00, 0x01, 0x82, 0x08, 0x00, 0x00, 0x01, 0x81, 0x70, 0x00, 0x00, 0x01, 0x81, 0x64, 0x00, 0x04, 0x03, 0x00, 0x03, 0x01, 0x03, 0x02, 0x03, 0x03, 0x02, 0x03, 0x02, 0x01, 0x11, 0x06, 0x07, 0x02, 0x02, 0x02, 0x00, 0x0D, 0x04, 0x05, 0x02, 0x03, 0x02, 0x01, 0x0D, - 0x00, 0x02, 0x03, 0x00, 0x03, 0x01, 0x23, 0x02, 0x01, 0x13, 0x39, 0x02, - 0x00, 0x0F, 0x15, 0x00, 0x00, 0x05, 0x02, 0x4F, 0x26, 0x00, 0x00, 0x06, - 0x02, 0x50, 0x26, 0x00, 0x00, 0x01, 0x10, 0x73, 0x00, 0x00, 0x11, 0x05, - 0x02, 0x53, 0x26, 0x70, 0x00, 0x00, 0x11, 0x05, 0x02, 0x53, 0x26, 0x71, - 0x00, 0x00, 0x06, 0x02, 0x49, 0x26, 0x00, 0x00, 0x01, 0x82, 0x00, 0x00, - 0x00, 0x23, 0x1E, 0x01, 0x08, 0x0E, 0x39, 0x3D, 0x1E, 0x09, 0x00, 0x09, - 0x03, 0x00, 0x59, 0x29, 0x81, 0x1D, 0x37, 0x81, 0x1D, 0x81, 0x20, 0x23, - 0x01, 0x20, 0x11, 0x06, 0x15, 0x22, 0x70, 0x81, 0x1B, 0x81, 0x20, 0x01, - 0x02, 0x74, 0x81, 0x1E, 0x01, 0x02, 0x12, 0x06, 0x02, 0x54, 0x26, 0x75, - 0x81, 0x20, 0x01, 0x02, 0x74, 0x81, 0x1C, 0x81, 0x1D, 0x81, 0x2A, 0x81, - 0x10, 0x63, 0x5F, 0x1F, 0x16, 0x81, 0x1D, 0x81, 0x15, 0x27, 0x67, 0x06, - 0x02, 0x48, 0x26, 0x81, 0x15, 0x27, 0x6E, 0x06, 0x02, 0x48, 0x26, 0x75, - 0x81, 0x10, 0x02, 0x00, 0x06, 0x05, 0x2B, 0x03, 0x01, 0x04, 0x08, 0x5F, - 0x66, 0x1F, 0x25, 0x05, 0x02, 0x47, 0x26, 0x66, 0x63, 0x1F, 0x16, 0x81, - 0x1D, 0x81, 0x1D, 0x81, 0x11, 0x05, 0x02, 0x54, 0x26, 0x81, 0x24, 0x24, - 0x06, 0x2C, 0x81, 0x2A, 0x81, 0x12, 0x81, 0x1D, 0x61, 0x81, 0x18, 0x03, - 0x03, 0x61, 0x39, 0x02, 0x03, 0x09, 0x39, 0x02, 0x03, 0x0A, 0x81, 0x18, - 0x03, 0x04, 0x75, 0x62, 0x28, 0x01, 0x81, 0x00, 0x09, 0x02, 0x03, 0x12, - 0x06, 0x02, 0x55, 0x26, 0x75, 0x58, 0x03, 0x02, 0x04, 0x3E, 0x81, 0x01, - 0x24, 0x06, 0x37, 0x81, 0x11, 0x05, 0x02, 0x54, 0x26, 0x68, 0x24, 0x06, - 0x04, 0x01, 0x17, 0x04, 0x12, 0x69, 0x24, 0x06, 0x04, 0x01, 0x18, 0x04, - 0x0A, 0x6A, 0x24, 0x06, 0x04, 0x01, 0x19, 0x04, 0x02, 0x54, 0x26, 0x03, - 0x05, 0x75, 0x81, 0x12, 0x23, 0x03, 0x06, 0x23, 0x61, 0x32, 0x0D, 0x06, - 0x02, 0x4D, 0x26, 0x81, 0x13, 0x57, 0x03, 0x02, 0x04, 0x02, 0x54, 0x26, - 0x75, 0x02, 0x00, 0x06, 0x33, 0x60, 0x2A, 0x01, 0x0F, 0x15, 0x23, 0x06, - 0x09, 0x02, 0x02, 0x11, 0x05, 0x02, 0x56, 0x26, 0x04, 0x01, 0x22, 0x02, - 0x02, 0x58, 0x2E, 0x11, 0x06, 0x08, 0x22, 0x02, 0x03, 0x02, 0x04, 0x1D, - 0x04, 0x10, 0x57, 0x2E, 0x11, 0x06, 0x08, 0x22, 0x02, 0x05, 0x02, 0x06, - 0x1C, 0x04, 0x03, 0x54, 0x26, 0x22, 0x04, 0x24, 0x02, 0x02, 0x58, 0x2E, - 0x11, 0x06, 0x08, 0x22, 0x02, 0x03, 0x02, 0x04, 0x21, 0x04, 0x10, 0x57, - 0x2E, 0x11, 0x06, 0x08, 0x22, 0x02, 0x05, 0x02, 0x06, 0x20, 0x04, 0x03, - 0x54, 0x26, 0x22, 0x23, 0x06, 0x01, 0x26, 0x22, 0x01, 0x00, 0x03, 0x07, - 0x81, 0x21, 0x01, 0x21, 0x81, 0x07, 0x01, 0x22, 0x81, 0x07, 0x23, 0x01, - 0x23, 0x11, 0x06, 0x81, 0x36, 0x22, 0x70, 0x81, 0x1B, 0x81, 0x1D, 0x23, - 0x06, 0x81, 0x28, 0x01, 0x00, 0x03, 0x08, 0x81, 0x1D, 0x81, 0x11, 0x22, - 0x81, 0x20, 0x23, 0x01, 0x01, 0x11, 0x06, 0x06, 0x81, 0x14, 0x03, 0x08, - 0x81, 0x20, 0x01, 0x04, 0x74, 0x81, 0x1B, 0x6D, 0x24, 0x06, 0x11, 0x02, - 0x00, 0x06, 0x04, 0x81, 0x2B, 0x04, 0x06, 0x81, 0x0E, 0x01, 0x7F, 0x03, - 0x07, 0x04, 0x80, 0x72, 0x81, 0x09, 0x24, 0x06, 0x07, 0x02, 0x00, 0x81, - 0x0F, 0x04, 0x80, 0x66, 0x81, 0x2D, 0x24, 0x06, 0x13, 0x02, 0x00, 0x06, - 0x0A, 0x01, 0x00, 0x03, 0x01, 0x81, 0x0D, 0x03, 0x01, 0x04, 0x02, 0x81, - 0x2B, 0x04, 0x80, 0x4E, 0x6C, 0x24, 0x06, 0x05, 0x81, 0x2B, 0x04, 0x80, - 0x45, 0x81, 0x30, 0x24, 0x06, 0x04, 0x81, 0x2B, 0x04, 0x3C, 0x81, 0x08, - 0x24, 0x06, 0x04, 0x81, 0x2B, 0x04, 0x33, 0x81, 0x2E, 0x24, 0x06, 0x04, - 0x81, 0x2B, 0x04, 0x2A, 0x76, 0x24, 0x06, 0x04, 0x81, 0x2B, 0x04, 0x22, - 0x81, 0x00, 0x24, 0x06, 0x04, 0x81, 0x2B, 0x04, 0x19, 0x6B, 0x24, 0x06, - 0x04, 0x81, 0x2B, 0x04, 0x11, 0x81, 0x2F, 0x24, 0x06, 0x04, 0x81, 0x2B, - 0x04, 0x08, 0x02, 0x08, 0x06, 0x02, 0x46, 0x26, 0x81, 0x2B, 0x75, 0x75, - 0x04, 0xFE, 0x54, 0x75, 0x75, 0x04, 0x08, 0x01, 0x7F, 0x11, 0x05, 0x02, - 0x53, 0x26, 0x22, 0x75, 0x38, 0x02, 0x00, 0x06, 0x08, 0x02, 0x01, 0x3A, - 0x2D, 0x05, 0x02, 0x42, 0x26, 0x02, 0x00, 0x06, 0x01, 0x17, 0x02, 0x00, - 0x02, 0x07, 0x2D, 0x05, 0x02, 0x4E, 0x26, 0x81, 0x20, 0x72, 0x81, 0x1B, - 0x81, 0x11, 0x06, 0x81, 0x07, 0x81, 0x25, 0x24, 0x06, 0x08, 0x01, 0x02, - 0x58, 0x81, 0x02, 0x04, 0x80, 0x6C, 0x81, 0x26, 0x24, 0x06, 0x08, 0x01, - 0x03, 0x58, 0x81, 0x03, 0x04, 0x80, 0x5F, 0x81, 0x27, 0x24, 0x06, 0x08, - 0x01, 0x04, 0x58, 0x81, 0x04, 0x04, 0x80, 0x52, 0x81, 0x28, 0x24, 0x06, - 0x08, 0x01, 0x05, 0x58, 0x81, 0x05, 0x04, 0x80, 0x45, 0x81, 0x29, 0x24, - 0x06, 0x07, 0x01, 0x06, 0x58, 0x81, 0x06, 0x04, 0x39, 0x7B, 0x24, 0x06, - 0x07, 0x01, 0x02, 0x57, 0x81, 0x02, 0x04, 0x2E, 0x7C, 0x24, 0x06, 0x07, - 0x01, 0x03, 0x57, 0x81, 0x03, 0x04, 0x23, 0x7D, 0x24, 0x06, 0x07, 0x01, - 0x04, 0x57, 0x81, 0x04, 0x04, 0x18, 0x7E, 0x24, 0x06, 0x07, 0x01, 0x05, - 0x57, 0x81, 0x05, 0x04, 0x0D, 0x7F, 0x24, 0x06, 0x07, 0x01, 0x06, 0x57, - 0x81, 0x06, 0x04, 0x02, 0x54, 0x26, 0x5C, 0x33, 0x5E, 0x35, 0x1B, 0x23, - 0x05, 0x02, 0x54, 0x26, 0x5B, 0x35, 0x04, 0x02, 0x54, 0x26, 0x81, 0x2A, - 0x81, 0x12, 0x23, 0x01, T0_INT2(BR_X509_BUFSIZE_SIG), 0x12, 0x06, 0x02, - 0x4D, 0x26, 0x23, 0x5D, 0x33, 0x5A, 0x81, 0x13, 0x75, 0x75, 0x01, 0x00, - 0x59, 0x34, 0x18, 0x00, 0x00, 0x01, 0x30, 0x0A, 0x23, 0x01, 0x00, 0x01, - 0x09, 0x6F, 0x05, 0x02, 0x45, 0x26, 0x00, 0x00, 0x2E, 0x2E, 0x00, 0x00, - 0x01, 0x81, 0x08, 0x00, 0x00, 0x01, 0x81, 0x10, 0x00, 0x00, 0x01, 0x81, - 0x19, 0x00, 0x00, 0x01, 0x81, 0x22, 0x00, 0x00, 0x01, 0x81, 0x2B, 0x00, - 0x00, 0x01, 0x82, 0x04, 0x00, 0x00, 0x01, 0x80, 0x6B, 0x00, 0x00, 0x01, - 0x3D, 0x00, 0x00, 0x01, 0x80, 0x43, 0x00, 0x00, 0x01, 0x80, 0x4D, 0x00, - 0x00, 0x01, 0x80, 0x57, 0x00, 0x00, 0x01, 0x80, 0x61, 0x00, 0x00, 0x2E, - 0x11, 0x06, 0x07, 0x3F, 0x81, 0x1B, 0x81, 0x2A, 0x81, 0x21, 0x00, 0x00, - 0x01, 0x81, 0x78, 0x00, 0x00, 0x01, 0x81, 0x68, 0x00, 0x00, 0x01, 0x7F, - 0x78, 0x19, 0x01, 0x00, 0x78, 0x19, 0x04, 0x7A, 0x00, 0x01, 0x81, 0x34, - 0x00, 0x01, 0x7A, 0x0D, 0x06, 0x02, 0x4C, 0x26, 0x23, 0x03, 0x00, 0x0A, - 0x02, 0x00, 0x00, 0x01, 0x01, 0x00, 0x03, 0x00, 0x81, 0x1D, 0x23, 0x06, - 0x18, 0x81, 0x20, 0x01, 0x22, 0x11, 0x06, 0x0C, 0x71, 0x81, 0x1F, 0x22, - 0x2B, 0x02, 0x00, 0x2D, 0x03, 0x00, 0x04, 0x03, 0x22, 0x81, 0x1C, 0x04, - 0x65, 0x75, 0x02, 0x00, 0x00, 0x00, 0x81, 0x1D, 0x81, 0x21, 0x23, 0x01, - 0x01, 0x11, 0x06, 0x0A, 0x81, 0x14, 0x05, 0x02, 0x4E, 0x26, 0x81, 0x21, - 0x04, 0x02, 0x4E, 0x26, 0x23, 0x01, 0x02, 0x11, 0x06, 0x0E, 0x22, 0x71, - 0x81, 0x1E, 0x64, 0x29, 0x3E, 0x0D, 0x06, 0x02, 0x4E, 0x26, 0x81, 0x21, - 0x01, 0x7F, 0x10, 0x06, 0x02, 0x53, 0x26, 0x22, 0x75, 0x00, 0x02, 0x06, - 0x10, 0x60, 0x2A, 0x01, 0x10, 0x15, 0x06, 0x04, 0x01, 0x30, 0x04, 0x03, - 0x01, 0x81, 0x40, 0x04, 0x02, 0x01, 0x04, 0x03, 0x00, 0x81, 0x20, 0x01, - 0x03, 0x74, 0x81, 0x1B, 0x81, 0x22, 0x03, 0x01, 0x02, 0x01, 0x01, 0x07, - 0x12, 0x06, 0x02, 0x53, 0x26, 0x23, 0x01, 0x00, 0x2E, 0x11, 0x06, 0x05, - 0x22, 0x4A, 0x26, 0x04, 0x17, 0x01, 0x01, 0x2E, 0x11, 0x06, 0x0B, 0x22, - 0x81, 0x22, 0x02, 0x01, 0x14, 0x02, 0x01, 0x0E, 0x04, 0x06, 0x22, 0x81, - 0x22, 0x01, 0x00, 0x22, 0x02, 0x00, 0x15, 0x05, 0x02, 0x4A, 0x26, 0x81, - 0x2A, 0x00, 0x02, 0x36, 0x01, 0x00, 0x65, 0x35, 0x81, 0x1D, 0x23, 0x06, - 0x80, 0x6F, 0x81, 0x20, 0x01, 0x11, 0x73, 0x81, 0x1B, 0x23, 0x05, 0x02, - 0x41, 0x26, 0x23, 0x06, 0x80, 0x5B, 0x81, 0x1D, 0x81, 0x20, 0x01, 0x06, - 0x74, 0x81, 0x1B, 0x23, 0x01, 0x03, 0x11, 0x06, 0x1E, 0x81, 0x22, 0x01, - 0x10, 0x0E, 0x03, 0x00, 0x81, 0x22, 0x01, 0x08, 0x0E, 0x02, 0x00, 0x09, - 0x03, 0x00, 0x81, 0x22, 0x02, 0x00, 0x09, 0x01, 0x82, 0xD4, 0x88, 0x03, - 0x11, 0x03, 0x01, 0x81, 0x2A, 0x02, 0x01, 0x06, 0x23, 0x81, 0x20, 0x23, - 0x23, 0x01, 0x0C, 0x11, 0x39, 0x01, 0x13, 0x11, 0x2D, 0x39, 0x01, 0x14, - 0x11, 0x2D, 0x06, 0x07, 0x71, 0x81, 0x1F, 0x22, 0x75, 0x04, 0x07, 0x22, - 0x01, 0x00, 0x65, 0x35, 0x81, 0x2A, 0x04, 0x02, 0x81, 0x2A, 0x04, 0xFF, - 0x21, 0x75, 0x04, 0xFF, 0x0D, 0x75, 0x1A, 0x00, 0x00, 0x81, 0x20, 0x01, - 0x06, 0x74, 0x81, 0x1F, 0x00, 0x00, 0x81, 0x20, 0x01, 0x03, 0x74, 0x81, - 0x1B, 0x81, 0x22, 0x06, 0x02, 0x52, 0x26, 0x00, 0x00, 0x39, 0x23, 0x06, - 0x07, 0x2F, 0x23, 0x06, 0x01, 0x19, 0x04, 0x76, 0x3F, 0x00, 0x00, 0x01, - 0x01, 0x74, 0x81, 0x1A, 0x01, 0x01, 0x10, 0x06, 0x02, 0x40, 0x26, 0x81, - 0x22, 0x3B, 0x00, 0x04, 0x81, 0x20, 0x23, 0x01, 0x17, 0x01, 0x18, 0x6F, - 0x05, 0x02, 0x45, 0x26, 0x01, 0x18, 0x11, 0x03, 0x00, 0x71, 0x81, 0x1B, - 0x81, 0x16, 0x02, 0x00, 0x06, 0x0D, 0x01, 0x80, 0x64, 0x08, 0x03, 0x01, - 0x81, 0x16, 0x02, 0x01, 0x09, 0x04, 0x0E, 0x23, 0x01, 0x32, 0x0D, 0x06, - 0x04, 0x01, 0x80, 0x64, 0x09, 0x01, 0x8E, 0x6C, 0x09, 0x03, 0x01, 0x02, - 0x01, 0x01, 0x82, 0x6D, 0x08, 0x02, 0x01, 0x01, 0x03, 0x09, 0x01, 0x04, - 0x0C, 0x09, 0x02, 0x01, 0x01, 0x80, 0x63, 0x09, 0x01, 0x80, 0x64, 0x0C, - 0x0A, 0x02, 0x01, 0x01, 0x83, 0x0F, 0x09, 0x01, 0x83, 0x10, 0x0C, 0x09, - 0x03, 0x03, 0x01, 0x01, 0x01, 0x0C, 0x81, 0x17, 0x3E, 0x01, 0x01, 0x0E, - 0x02, 0x01, 0x01, 0x04, 0x07, 0x3C, 0x02, 0x01, 0x01, 0x80, 0x64, 0x07, - 0x3B, 0x02, 0x01, 0x01, 0x83, 0x10, 0x07, 0x3C, 0x2D, 0x15, 0x06, 0x03, - 0x01, 0x18, 0x09, 0x81, 0x0B, 0x09, 0x77, 0x23, 0x01, 0x05, 0x14, 0x02, - 0x03, 0x09, 0x03, 0x03, 0x01, 0x1F, 0x15, 0x01, 0x01, 0x39, 0x81, 0x17, - 0x02, 0x03, 0x09, 0x3E, 0x03, 0x03, 0x01, 0x00, 0x01, 0x17, 0x81, 0x17, - 0x01, 0x9C, 0x10, 0x08, 0x03, 0x02, 0x01, 0x00, 0x01, 0x3B, 0x81, 0x17, - 0x01, 0x3C, 0x08, 0x02, 0x02, 0x09, 0x03, 0x02, 0x01, 0x00, 0x01, 0x3C, - 0x81, 0x17, 0x02, 0x02, 0x09, 0x03, 0x02, 0x81, 0x22, 0x23, 0x01, 0x2E, - 0x11, 0x06, 0x0E, 0x22, 0x81, 0x22, 0x23, 0x01, 0x30, 0x01, 0x39, 0x6F, - 0x06, 0x03, 0x22, 0x04, 0x73, 0x01, 0x80, 0x5A, 0x10, 0x06, 0x02, 0x45, - 0x26, 0x75, 0x02, 0x03, 0x02, 0x02, 0x00, 0x01, 0x81, 0x22, 0x79, 0x01, - 0x0A, 0x08, 0x03, 0x00, 0x81, 0x22, 0x79, 0x02, 0x00, 0x09, 0x00, 0x02, - 0x03, 0x00, 0x03, 0x01, 0x81, 0x16, 0x23, 0x02, 0x01, 0x02, 0x00, 0x6F, - 0x05, 0x02, 0x45, 0x26, 0x00, 0x00, 0x32, 0x81, 0x20, 0x01, 0x02, 0x74, - 0x0B, 0x81, 0x19, 0x00, 0x03, 0x23, 0x03, 0x00, 0x03, 0x01, 0x03, 0x02, - 0x81, 0x1B, 0x81, 0x22, 0x23, 0x01, 0x81, 0x00, 0x13, 0x06, 0x02, 0x51, - 0x26, 0x23, 0x01, 0x00, 0x11, 0x06, 0x0C, 0x22, 0x23, 0x05, 0x04, 0x22, - 0x01, 0x00, 0x00, 0x81, 0x22, 0x04, 0x6E, 0x02, 0x01, 0x23, 0x05, 0x02, - 0x4D, 0x26, 0x3E, 0x03, 0x01, 0x02, 0x02, 0x35, 0x02, 0x02, 0x3D, 0x03, - 0x02, 0x23, 0x06, 0x04, 0x81, 0x22, 0x04, 0x67, 0x22, 0x02, 0x00, 0x02, - 0x01, 0x0A, 0x00, 0x01, 0x81, 0x22, 0x23, 0x01, 0x81, 0x00, 0x0D, 0x06, - 0x01, 0x00, 0x01, 0x81, 0x00, 0x0A, 0x23, 0x05, 0x02, 0x4B, 0x26, 0x03, - 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x12, 0x06, 0x1A, 0x02, 0x00, - 0x3E, 0x03, 0x00, 0x23, 0x01, 0x87, 0xFF, 0xFF, 0x7F, 0x12, 0x06, 0x02, - 0x4C, 0x26, 0x01, 0x08, 0x0E, 0x39, 0x81, 0x22, 0x32, 0x09, 0x04, 0x5F, - 0x00, 0x00, 0x81, 0x1A, 0x81, 0x0C, 0x00, 0x00, 0x81, 0x1B, 0x81, 0x2A, - 0x00, 0x00, 0x81, 0x20, 0x72, 0x81, 0x1B, 0x00, 0x01, 0x81, 0x1B, 0x23, - 0x05, 0x02, 0x51, 0x26, 0x81, 0x22, 0x23, 0x01, 0x81, 0x00, 0x13, 0x06, - 0x02, 0x51, 0x26, 0x03, 0x00, 0x23, 0x06, 0x17, 0x81, 0x22, 0x02, 0x00, - 0x23, 0x01, 0x87, 0xFF, 0xFF, 0x7F, 0x13, 0x06, 0x02, 0x51, 0x26, 0x01, - 0x08, 0x0E, 0x09, 0x03, 0x00, 0x04, 0x66, 0x22, 0x02, 0x00, 0x00, 0x00, - 0x81, 0x1B, 0x23, 0x01, 0x81, 0x7F, 0x12, 0x06, 0x09, 0x81, 0x2A, 0x01, - 0x00, 0x65, 0x35, 0x01, 0x00, 0x00, 0x23, 0x65, 0x35, 0x65, 0x3D, 0x81, - 0x13, 0x01, 0x7F, 0x00, 0x01, 0x81, 0x22, 0x03, 0x00, 0x02, 0x00, 0x01, - 0x05, 0x14, 0x01, 0x01, 0x15, 0x2C, 0x02, 0x00, 0x01, 0x06, 0x14, 0x23, - 0x01, 0x01, 0x15, 0x06, 0x02, 0x43, 0x26, 0x01, 0x04, 0x0E, 0x02, 0x00, - 0x01, 0x1F, 0x15, 0x23, 0x01, 0x1F, 0x11, 0x06, 0x02, 0x44, 0x26, 0x09, - 0x00, 0x00, 0x23, 0x05, 0x05, 0x01, 0x00, 0x01, 0x7F, 0x00, 0x81, 0x20, - 0x00, 0x00, 0x23, 0x05, 0x02, 0x4C, 0x26, 0x3E, 0x81, 0x23, 0x00, 0x00, - 0x30, 0x23, 0x01, 0x00, 0x13, 0x06, 0x01, 0x00, 0x22, 0x19, 0x04, 0x74, - 0x00, 0x01, 0x01, 0x00, 0x00, 0x01, 0x0B, 0x00, 0x00, 0x01, 0x15, 0x00, - 0x00, 0x01, 0x1F, 0x00, 0x00, 0x01, 0x29, 0x00, 0x00, 0x01, 0x33, 0x00, - 0x00, 0x81, 0x2B, 0x22, 0x00, 0x00, 0x23, 0x06, 0x08, 0x81, 0x2C, 0x23, - 0x06, 0x01, 0x19, 0x04, 0x75, 0x00, 0x00, 0x01, 0x00, 0x2E, 0x2F, 0x0B, - 0x3F, 0x00, 0x00, 0x01, 0x81, 0x6C, 0x00, 0x00, 0x01, 0x81, 0x7C, 0x00, - 0x00, 0x01, 0x82, 0x11, 0x00, 0x00, 0x01, 0x81, 0x74, 0x00, 0x00, 0x01, - 0x03, 0x31, 0x01, 0x03, 0x31, 0x00 + 0x00, 0x02, 0x03, 0x00, 0x03, 0x01, 0x23, 0x02, 0x01, 0x13, 0x38, 0x02, + 0x00, 0x0F, 0x15, 0x00, 0x00, 0x05, 0x02, 0x4E, 0x26, 0x00, 0x00, 0x06, + 0x02, 0x4F, 0x26, 0x00, 0x00, 0x01, 0x10, 0x71, 0x00, 0x00, 0x11, 0x05, + 0x02, 0x52, 0x26, 0x6E, 0x00, 0x00, 0x11, 0x05, 0x02, 0x52, 0x26, 0x6F, + 0x00, 0x00, 0x06, 0x02, 0x48, 0x26, 0x00, 0x00, 0x01, 0x82, 0x00, 0x00, + 0x00, 0x23, 0x1E, 0x01, 0x08, 0x0E, 0x38, 0x3C, 0x1E, 0x09, 0x00, 0x09, + 0x03, 0x00, 0x57, 0x29, 0x81, 0x1B, 0x36, 0x81, 0x1B, 0x81, 0x1E, 0x23, + 0x01, 0x20, 0x11, 0x06, 0x15, 0x22, 0x6E, 0x81, 0x19, 0x81, 0x1E, 0x01, + 0x02, 0x72, 0x81, 0x1C, 0x01, 0x02, 0x12, 0x06, 0x02, 0x53, 0x26, 0x73, + 0x81, 0x1E, 0x01, 0x02, 0x72, 0x81, 0x1A, 0x81, 0x1B, 0x81, 0x28, 0x81, + 0x0E, 0x61, 0x5D, 0x1F, 0x16, 0x81, 0x1B, 0x81, 0x13, 0x27, 0x65, 0x06, + 0x02, 0x47, 0x26, 0x81, 0x13, 0x27, 0x6C, 0x06, 0x02, 0x47, 0x26, 0x73, + 0x81, 0x0E, 0x02, 0x00, 0x06, 0x05, 0x2A, 0x03, 0x01, 0x04, 0x08, 0x5D, + 0x64, 0x1F, 0x25, 0x05, 0x02, 0x46, 0x26, 0x64, 0x61, 0x1F, 0x16, 0x81, + 0x1B, 0x81, 0x1B, 0x81, 0x0F, 0x05, 0x02, 0x53, 0x26, 0x81, 0x22, 0x24, + 0x06, 0x2C, 0x81, 0x28, 0x81, 0x10, 0x81, 0x1B, 0x5F, 0x81, 0x16, 0x03, + 0x03, 0x5F, 0x38, 0x02, 0x03, 0x09, 0x38, 0x02, 0x03, 0x0A, 0x81, 0x16, + 0x03, 0x04, 0x73, 0x60, 0x28, 0x01, 0x81, 0x00, 0x09, 0x02, 0x03, 0x12, + 0x06, 0x02, 0x54, 0x26, 0x73, 0x56, 0x03, 0x02, 0x04, 0x3D, 0x7F, 0x24, + 0x06, 0x37, 0x81, 0x0F, 0x05, 0x02, 0x53, 0x26, 0x66, 0x24, 0x06, 0x04, + 0x01, 0x17, 0x04, 0x12, 0x67, 0x24, 0x06, 0x04, 0x01, 0x18, 0x04, 0x0A, + 0x68, 0x24, 0x06, 0x04, 0x01, 0x19, 0x04, 0x02, 0x53, 0x26, 0x03, 0x05, + 0x73, 0x81, 0x10, 0x23, 0x03, 0x06, 0x23, 0x5F, 0x31, 0x0D, 0x06, 0x02, + 0x4C, 0x26, 0x81, 0x11, 0x55, 0x03, 0x02, 0x04, 0x02, 0x53, 0x26, 0x73, + 0x02, 0x00, 0x06, 0x21, 0x02, 0x02, 0x56, 0x2D, 0x11, 0x06, 0x08, 0x22, + 0x02, 0x03, 0x02, 0x04, 0x1D, 0x04, 0x10, 0x55, 0x2D, 0x11, 0x06, 0x08, + 0x22, 0x02, 0x05, 0x02, 0x06, 0x1C, 0x04, 0x03, 0x53, 0x26, 0x22, 0x04, + 0x24, 0x02, 0x02, 0x56, 0x2D, 0x11, 0x06, 0x08, 0x22, 0x02, 0x03, 0x02, + 0x04, 0x21, 0x04, 0x10, 0x55, 0x2D, 0x11, 0x06, 0x08, 0x22, 0x02, 0x05, + 0x02, 0x06, 0x20, 0x04, 0x03, 0x53, 0x26, 0x22, 0x23, 0x06, 0x01, 0x26, + 0x22, 0x01, 0x00, 0x03, 0x07, 0x81, 0x1F, 0x01, 0x21, 0x81, 0x05, 0x01, + 0x22, 0x81, 0x05, 0x23, 0x01, 0x23, 0x11, 0x06, 0x81, 0x35, 0x22, 0x6E, + 0x81, 0x19, 0x81, 0x1B, 0x23, 0x06, 0x81, 0x27, 0x01, 0x00, 0x03, 0x08, + 0x81, 0x1B, 0x81, 0x0F, 0x22, 0x81, 0x1E, 0x23, 0x01, 0x01, 0x11, 0x06, + 0x06, 0x81, 0x12, 0x03, 0x08, 0x81, 0x1E, 0x01, 0x04, 0x72, 0x81, 0x19, + 0x6B, 0x24, 0x06, 0x11, 0x02, 0x00, 0x06, 0x04, 0x81, 0x29, 0x04, 0x06, + 0x81, 0x0C, 0x01, 0x7F, 0x03, 0x07, 0x04, 0x80, 0x71, 0x81, 0x07, 0x24, + 0x06, 0x07, 0x02, 0x00, 0x81, 0x0D, 0x04, 0x80, 0x65, 0x81, 0x2B, 0x24, + 0x06, 0x13, 0x02, 0x00, 0x06, 0x0A, 0x01, 0x00, 0x03, 0x01, 0x81, 0x0B, + 0x03, 0x01, 0x04, 0x02, 0x81, 0x29, 0x04, 0x80, 0x4D, 0x6A, 0x24, 0x06, + 0x05, 0x81, 0x29, 0x04, 0x80, 0x44, 0x81, 0x2E, 0x24, 0x06, 0x04, 0x81, + 0x29, 0x04, 0x3B, 0x81, 0x06, 0x24, 0x06, 0x04, 0x81, 0x29, 0x04, 0x32, + 0x81, 0x2C, 0x24, 0x06, 0x04, 0x81, 0x29, 0x04, 0x29, 0x74, 0x24, 0x06, + 0x04, 0x81, 0x29, 0x04, 0x21, 0x7E, 0x24, 0x06, 0x04, 0x81, 0x29, 0x04, + 0x19, 0x69, 0x24, 0x06, 0x04, 0x81, 0x29, 0x04, 0x11, 0x81, 0x2D, 0x24, + 0x06, 0x04, 0x81, 0x29, 0x04, 0x08, 0x02, 0x08, 0x06, 0x02, 0x45, 0x26, + 0x81, 0x29, 0x73, 0x73, 0x04, 0xFE, 0x55, 0x73, 0x73, 0x04, 0x08, 0x01, + 0x7F, 0x11, 0x05, 0x02, 0x52, 0x26, 0x22, 0x73, 0x37, 0x02, 0x00, 0x06, + 0x08, 0x02, 0x01, 0x39, 0x2C, 0x05, 0x02, 0x41, 0x26, 0x02, 0x00, 0x06, + 0x01, 0x17, 0x02, 0x00, 0x02, 0x07, 0x2C, 0x05, 0x02, 0x4D, 0x26, 0x81, + 0x1E, 0x70, 0x81, 0x19, 0x81, 0x0F, 0x06, 0x81, 0x07, 0x81, 0x23, 0x24, + 0x06, 0x08, 0x01, 0x02, 0x56, 0x81, 0x00, 0x04, 0x80, 0x6C, 0x81, 0x24, + 0x24, 0x06, 0x08, 0x01, 0x03, 0x56, 0x81, 0x01, 0x04, 0x80, 0x5F, 0x81, + 0x25, 0x24, 0x06, 0x08, 0x01, 0x04, 0x56, 0x81, 0x02, 0x04, 0x80, 0x52, + 0x81, 0x26, 0x24, 0x06, 0x08, 0x01, 0x05, 0x56, 0x81, 0x03, 0x04, 0x80, + 0x45, 0x81, 0x27, 0x24, 0x06, 0x07, 0x01, 0x06, 0x56, 0x81, 0x04, 0x04, + 0x39, 0x79, 0x24, 0x06, 0x07, 0x01, 0x02, 0x55, 0x81, 0x00, 0x04, 0x2E, + 0x7A, 0x24, 0x06, 0x07, 0x01, 0x03, 0x55, 0x81, 0x01, 0x04, 0x23, 0x7B, + 0x24, 0x06, 0x07, 0x01, 0x04, 0x55, 0x81, 0x02, 0x04, 0x18, 0x7C, 0x24, + 0x06, 0x07, 0x01, 0x05, 0x55, 0x81, 0x03, 0x04, 0x0D, 0x7D, 0x24, 0x06, + 0x07, 0x01, 0x06, 0x55, 0x81, 0x04, 0x04, 0x02, 0x53, 0x26, 0x5A, 0x32, + 0x5C, 0x34, 0x1B, 0x23, 0x05, 0x02, 0x53, 0x26, 0x59, 0x34, 0x04, 0x02, + 0x53, 0x26, 0x81, 0x28, 0x81, 0x10, 0x23, 0x01, + T0_INT2(BR_X509_BUFSIZE_SIG), 0x12, 0x06, 0x02, 0x4C, 0x26, 0x23, 0x5B, + 0x32, 0x58, 0x81, 0x11, 0x73, 0x73, 0x01, 0x00, 0x57, 0x33, 0x18, 0x00, + 0x00, 0x01, 0x30, 0x0A, 0x23, 0x01, 0x00, 0x01, 0x09, 0x6D, 0x05, 0x02, + 0x44, 0x26, 0x00, 0x00, 0x2D, 0x2D, 0x00, 0x00, 0x01, 0x81, 0x08, 0x00, + 0x00, 0x01, 0x81, 0x10, 0x00, 0x00, 0x01, 0x81, 0x19, 0x00, 0x00, 0x01, + 0x81, 0x22, 0x00, 0x00, 0x01, 0x81, 0x2B, 0x00, 0x00, 0x01, 0x82, 0x04, + 0x00, 0x00, 0x01, 0x80, 0x6B, 0x00, 0x00, 0x01, 0x3D, 0x00, 0x00, 0x01, + 0x80, 0x43, 0x00, 0x00, 0x01, 0x80, 0x4D, 0x00, 0x00, 0x01, 0x80, 0x57, + 0x00, 0x00, 0x01, 0x80, 0x61, 0x00, 0x00, 0x2D, 0x11, 0x06, 0x07, 0x3E, + 0x81, 0x19, 0x81, 0x28, 0x81, 0x1F, 0x00, 0x00, 0x01, 0x81, 0x78, 0x00, + 0x00, 0x01, 0x81, 0x68, 0x00, 0x00, 0x01, 0x30, 0x5E, 0x34, 0x01, 0x7F, + 0x76, 0x19, 0x01, 0x00, 0x76, 0x19, 0x04, 0x7A, 0x00, 0x01, 0x81, 0x34, + 0x00, 0x01, 0x78, 0x0D, 0x06, 0x02, 0x4B, 0x26, 0x23, 0x03, 0x00, 0x0A, + 0x02, 0x00, 0x00, 0x01, 0x01, 0x00, 0x03, 0x00, 0x81, 0x1B, 0x23, 0x06, + 0x18, 0x81, 0x1E, 0x01, 0x22, 0x11, 0x06, 0x0C, 0x6F, 0x81, 0x1D, 0x22, + 0x2A, 0x02, 0x00, 0x2C, 0x03, 0x00, 0x04, 0x03, 0x22, 0x81, 0x1A, 0x04, + 0x65, 0x73, 0x02, 0x00, 0x00, 0x00, 0x81, 0x1B, 0x81, 0x1F, 0x23, 0x01, + 0x01, 0x11, 0x06, 0x0A, 0x81, 0x12, 0x05, 0x02, 0x4D, 0x26, 0x81, 0x1F, + 0x04, 0x02, 0x4D, 0x26, 0x23, 0x01, 0x02, 0x11, 0x06, 0x0E, 0x22, 0x6F, + 0x81, 0x1C, 0x62, 0x29, 0x3D, 0x0D, 0x06, 0x02, 0x4D, 0x26, 0x81, 0x1F, + 0x01, 0x7F, 0x10, 0x06, 0x02, 0x52, 0x26, 0x22, 0x73, 0x00, 0x02, 0x03, + 0x00, 0x81, 0x1E, 0x01, 0x03, 0x72, 0x81, 0x19, 0x81, 0x20, 0x03, 0x01, + 0x02, 0x01, 0x01, 0x07, 0x12, 0x06, 0x02, 0x52, 0x26, 0x23, 0x01, 0x00, + 0x2D, 0x11, 0x06, 0x05, 0x22, 0x49, 0x26, 0x04, 0x17, 0x01, 0x01, 0x2D, + 0x11, 0x06, 0x0B, 0x22, 0x81, 0x20, 0x02, 0x01, 0x14, 0x02, 0x01, 0x0E, + 0x04, 0x06, 0x22, 0x81, 0x20, 0x01, 0x00, 0x22, 0x02, 0x00, 0x06, 0x19, + 0x01, 0x00, 0x2D, 0x01, 0x38, 0x15, 0x06, 0x03, 0x01, 0x10, 0x2C, 0x38, + 0x01, 0x81, 0x40, 0x15, 0x06, 0x03, 0x01, 0x20, 0x2C, 0x5E, 0x34, 0x04, + 0x07, 0x01, 0x04, 0x15, 0x05, 0x02, 0x49, 0x26, 0x81, 0x28, 0x00, 0x02, + 0x35, 0x01, 0x00, 0x63, 0x34, 0x81, 0x1B, 0x23, 0x06, 0x80, 0x6F, 0x81, + 0x1E, 0x01, 0x11, 0x71, 0x81, 0x19, 0x23, 0x05, 0x02, 0x40, 0x26, 0x23, + 0x06, 0x80, 0x5B, 0x81, 0x1B, 0x81, 0x1E, 0x01, 0x06, 0x72, 0x81, 0x19, + 0x23, 0x01, 0x03, 0x11, 0x06, 0x1E, 0x81, 0x20, 0x01, 0x10, 0x0E, 0x03, + 0x00, 0x81, 0x20, 0x01, 0x08, 0x0E, 0x02, 0x00, 0x09, 0x03, 0x00, 0x81, + 0x20, 0x02, 0x00, 0x09, 0x01, 0x82, 0xD4, 0x88, 0x03, 0x11, 0x03, 0x01, + 0x81, 0x28, 0x02, 0x01, 0x06, 0x23, 0x81, 0x1E, 0x23, 0x23, 0x01, 0x0C, + 0x11, 0x38, 0x01, 0x13, 0x11, 0x2C, 0x38, 0x01, 0x14, 0x11, 0x2C, 0x06, + 0x07, 0x6F, 0x81, 0x1D, 0x22, 0x73, 0x04, 0x07, 0x22, 0x01, 0x00, 0x63, + 0x34, 0x81, 0x28, 0x04, 0x02, 0x81, 0x28, 0x04, 0xFF, 0x21, 0x73, 0x04, + 0xFF, 0x0D, 0x73, 0x1A, 0x00, 0x00, 0x81, 0x1E, 0x01, 0x06, 0x72, 0x81, + 0x1D, 0x00, 0x00, 0x81, 0x1E, 0x01, 0x03, 0x72, 0x81, 0x19, 0x81, 0x20, + 0x06, 0x02, 0x51, 0x26, 0x00, 0x00, 0x38, 0x23, 0x06, 0x07, 0x2E, 0x23, + 0x06, 0x01, 0x19, 0x04, 0x76, 0x3E, 0x00, 0x00, 0x01, 0x01, 0x72, 0x81, + 0x18, 0x01, 0x01, 0x10, 0x06, 0x02, 0x3F, 0x26, 0x81, 0x20, 0x3A, 0x00, + 0x04, 0x81, 0x1E, 0x23, 0x01, 0x17, 0x01, 0x18, 0x6D, 0x05, 0x02, 0x44, + 0x26, 0x01, 0x18, 0x11, 0x03, 0x00, 0x6F, 0x81, 0x19, 0x81, 0x14, 0x02, + 0x00, 0x06, 0x0D, 0x01, 0x80, 0x64, 0x08, 0x03, 0x01, 0x81, 0x14, 0x02, + 0x01, 0x09, 0x04, 0x0E, 0x23, 0x01, 0x32, 0x0D, 0x06, 0x04, 0x01, 0x80, + 0x64, 0x09, 0x01, 0x8E, 0x6C, 0x09, 0x03, 0x01, 0x02, 0x01, 0x01, 0x82, + 0x6D, 0x08, 0x02, 0x01, 0x01, 0x03, 0x09, 0x01, 0x04, 0x0C, 0x09, 0x02, + 0x01, 0x01, 0x80, 0x63, 0x09, 0x01, 0x80, 0x64, 0x0C, 0x0A, 0x02, 0x01, + 0x01, 0x83, 0x0F, 0x09, 0x01, 0x83, 0x10, 0x0C, 0x09, 0x03, 0x03, 0x01, + 0x01, 0x01, 0x0C, 0x81, 0x15, 0x3D, 0x01, 0x01, 0x0E, 0x02, 0x01, 0x01, + 0x04, 0x07, 0x3B, 0x02, 0x01, 0x01, 0x80, 0x64, 0x07, 0x3A, 0x02, 0x01, + 0x01, 0x83, 0x10, 0x07, 0x3B, 0x2C, 0x15, 0x06, 0x03, 0x01, 0x18, 0x09, + 0x81, 0x09, 0x09, 0x75, 0x23, 0x01, 0x05, 0x14, 0x02, 0x03, 0x09, 0x03, + 0x03, 0x01, 0x1F, 0x15, 0x01, 0x01, 0x38, 0x81, 0x15, 0x02, 0x03, 0x09, + 0x3D, 0x03, 0x03, 0x01, 0x00, 0x01, 0x17, 0x81, 0x15, 0x01, 0x9C, 0x10, + 0x08, 0x03, 0x02, 0x01, 0x00, 0x01, 0x3B, 0x81, 0x15, 0x01, 0x3C, 0x08, + 0x02, 0x02, 0x09, 0x03, 0x02, 0x01, 0x00, 0x01, 0x3C, 0x81, 0x15, 0x02, + 0x02, 0x09, 0x03, 0x02, 0x81, 0x20, 0x23, 0x01, 0x2E, 0x11, 0x06, 0x0E, + 0x22, 0x81, 0x20, 0x23, 0x01, 0x30, 0x01, 0x39, 0x6D, 0x06, 0x03, 0x22, + 0x04, 0x73, 0x01, 0x80, 0x5A, 0x10, 0x06, 0x02, 0x44, 0x26, 0x73, 0x02, + 0x03, 0x02, 0x02, 0x00, 0x01, 0x81, 0x20, 0x77, 0x01, 0x0A, 0x08, 0x03, + 0x00, 0x81, 0x20, 0x77, 0x02, 0x00, 0x09, 0x00, 0x02, 0x03, 0x00, 0x03, + 0x01, 0x81, 0x14, 0x23, 0x02, 0x01, 0x02, 0x00, 0x6D, 0x05, 0x02, 0x44, + 0x26, 0x00, 0x00, 0x31, 0x81, 0x1E, 0x01, 0x02, 0x72, 0x0B, 0x81, 0x17, + 0x00, 0x03, 0x23, 0x03, 0x00, 0x03, 0x01, 0x03, 0x02, 0x81, 0x19, 0x81, + 0x20, 0x23, 0x01, 0x81, 0x00, 0x13, 0x06, 0x02, 0x50, 0x26, 0x23, 0x01, + 0x00, 0x11, 0x06, 0x0C, 0x22, 0x23, 0x05, 0x04, 0x22, 0x01, 0x00, 0x00, + 0x81, 0x20, 0x04, 0x6E, 0x02, 0x01, 0x23, 0x05, 0x02, 0x4C, 0x26, 0x3D, + 0x03, 0x01, 0x02, 0x02, 0x34, 0x02, 0x02, 0x3C, 0x03, 0x02, 0x23, 0x06, + 0x04, 0x81, 0x20, 0x04, 0x67, 0x22, 0x02, 0x00, 0x02, 0x01, 0x0A, 0x00, + 0x01, 0x81, 0x20, 0x23, 0x01, 0x81, 0x00, 0x0D, 0x06, 0x01, 0x00, 0x01, + 0x81, 0x00, 0x0A, 0x23, 0x05, 0x02, 0x4A, 0x26, 0x03, 0x00, 0x01, 0x00, + 0x02, 0x00, 0x01, 0x00, 0x12, 0x06, 0x1A, 0x02, 0x00, 0x3D, 0x03, 0x00, + 0x23, 0x01, 0x87, 0xFF, 0xFF, 0x7F, 0x12, 0x06, 0x02, 0x4B, 0x26, 0x01, + 0x08, 0x0E, 0x38, 0x81, 0x20, 0x31, 0x09, 0x04, 0x5F, 0x00, 0x00, 0x81, + 0x18, 0x81, 0x0A, 0x00, 0x00, 0x81, 0x19, 0x81, 0x28, 0x00, 0x00, 0x81, + 0x1E, 0x70, 0x81, 0x19, 0x00, 0x01, 0x81, 0x19, 0x23, 0x05, 0x02, 0x50, + 0x26, 0x81, 0x20, 0x23, 0x01, 0x81, 0x00, 0x13, 0x06, 0x02, 0x50, 0x26, + 0x03, 0x00, 0x23, 0x06, 0x17, 0x81, 0x20, 0x02, 0x00, 0x23, 0x01, 0x87, + 0xFF, 0xFF, 0x7F, 0x13, 0x06, 0x02, 0x50, 0x26, 0x01, 0x08, 0x0E, 0x09, + 0x03, 0x00, 0x04, 0x66, 0x22, 0x02, 0x00, 0x00, 0x00, 0x81, 0x19, 0x23, + 0x01, 0x81, 0x7F, 0x12, 0x06, 0x09, 0x81, 0x28, 0x01, 0x00, 0x63, 0x34, + 0x01, 0x00, 0x00, 0x23, 0x63, 0x34, 0x63, 0x3C, 0x81, 0x11, 0x01, 0x7F, + 0x00, 0x01, 0x81, 0x20, 0x03, 0x00, 0x02, 0x00, 0x01, 0x05, 0x14, 0x01, + 0x01, 0x15, 0x2B, 0x02, 0x00, 0x01, 0x06, 0x14, 0x23, 0x01, 0x01, 0x15, + 0x06, 0x02, 0x42, 0x26, 0x01, 0x04, 0x0E, 0x02, 0x00, 0x01, 0x1F, 0x15, + 0x23, 0x01, 0x1F, 0x11, 0x06, 0x02, 0x43, 0x26, 0x09, 0x00, 0x00, 0x23, + 0x05, 0x05, 0x01, 0x00, 0x01, 0x7F, 0x00, 0x81, 0x1E, 0x00, 0x00, 0x23, + 0x05, 0x02, 0x4B, 0x26, 0x3D, 0x81, 0x21, 0x00, 0x00, 0x2F, 0x23, 0x01, + 0x00, 0x13, 0x06, 0x01, 0x00, 0x22, 0x19, 0x04, 0x74, 0x00, 0x01, 0x01, + 0x00, 0x00, 0x01, 0x0B, 0x00, 0x00, 0x01, 0x15, 0x00, 0x00, 0x01, 0x1F, + 0x00, 0x00, 0x01, 0x29, 0x00, 0x00, 0x01, 0x33, 0x00, 0x00, 0x81, 0x29, + 0x22, 0x00, 0x00, 0x23, 0x06, 0x08, 0x81, 0x2A, 0x23, 0x06, 0x01, 0x19, + 0x04, 0x75, 0x00, 0x00, 0x01, 0x00, 0x2D, 0x2E, 0x0B, 0x3E, 0x00, 0x00, + 0x01, 0x81, 0x6C, 0x00, 0x00, 0x01, 0x81, 0x7C, 0x00, 0x00, 0x01, 0x82, + 0x11, 0x00, 0x00, 0x01, 0x81, 0x74, 0x00, 0x00, 0x01, 0x03, 0x30, 0x01, + 0x03, 0x30, 0x00 }; static const uint16_t t0_caddr[] = { @@ -736,98 +736,97 @@ static const uint16_t t0_caddr[] = { 112, 116, 120, - 124, - 129, - 134, - 139, - 144, - 149, - 154, - 159, - 164, - 172, - 177, - 182, - 187, - 192, - 197, - 202, - 207, - 212, - 217, - 222, - 227, - 232, - 261, - 276, - 282, - 288, - 293, - 301, - 309, - 315, - 320, - 331, + 125, + 130, + 135, + 140, + 145, + 150, + 155, + 160, + 168, + 173, + 178, + 183, + 188, + 193, + 198, + 203, + 208, + 213, + 218, + 223, + 228, + 257, + 272, + 278, + 284, + 289, + 297, + 305, + 311, + 316, + 327, + 1029, + 1044, + 1048, 1053, + 1058, + 1063, 1068, - 1072, - 1077, - 1082, + 1073, + 1078, + 1083, 1087, 1092, 1097, 1102, 1107, - 1111, - 1116, - 1121, - 1126, - 1131, - 1144, - 1149, - 1154, - 1165, - 1170, - 1184, - 1222, - 1275, - 1363, - 1489, - 1498, - 1513, - 1527, - 1544, - 1776, - 1792, + 1120, + 1125, + 1130, + 1145, + 1150, + 1164, + 1202, + 1255, + 1352, + 1478, + 1487, + 1502, + 1516, + 1533, + 1765, + 1781, + 1799, 1810, - 1821, - 1892, - 1950, - 1956, - 1962, - 1969, - 2020, - 2049, - 2094, - 2106, - 2116, - 2129, - 2133, - 2137, - 2141, - 2145, - 2149, - 2153, - 2158, - 2171, - 2179, - 2184, - 2189, - 2194, - 2199 + 1881, + 1939, + 1945, + 1951, + 1958, + 2009, + 2038, + 2083, + 2095, + 2105, + 2118, + 2122, + 2126, + 2130, + 2134, + 2138, + 2142, + 2147, + 2160, + 2168, + 2173, + 2178, + 2183, + 2188 }; -#define T0_INTERPRETED 59 +#define T0_INTERPRETED 58 #define T0_ENTER(ip, rp, slot) do { \ const unsigned char *t0_newip; \ @@ -848,7 +847,7 @@ name(void *ctx) \ T0_ENTER(t0ctx->ip, t0ctx->rp, slot); \ } -T0_DEFENTRY(br_x509_minimal_init_main, 138) +T0_DEFENTRY(br_x509_minimal_init_main, 136) void br_x509_minimal_run(void *t0ctx) @@ -1100,7 +1099,7 @@ br_x509_minimal_run(void *t0ctx) if (ta->flags & BR_X509_TA_CA) { continue; } - hash_dn(CTX, ta->dn, ta->dn_len, hashed_DN); + hash_dn(CTX, ta->dn.data, ta->dn.len, hashed_DN); if (memcmp(hashed_DN, CTX->current_dn_hash, DNHASH_LEN)) { continue; } @@ -1161,7 +1160,7 @@ br_x509_minimal_run(void *t0ctx) if (!(ta->flags & BR_X509_TA_CA)) { continue; } - hash_dn(CTX, ta->dn, ta->dn_len, hashed_DN); + hash_dn(CTX, ta->dn.data, ta->dn.len, hashed_DN); if (memcmp(hashed_DN, CTX->saved_dn_hash, DNHASH_LEN)) { continue; } @@ -1360,14 +1359,6 @@ br_x509_minimal_run(void *t0ctx) } break; case 42: { - /* get8 */ - - uint32_t addr = T0_POP(); - T0_PUSH(*((unsigned char *)CTX + addr)); - - } - break; - case 43: { /* match-server-name */ size_t n1, n2; @@ -1402,7 +1393,7 @@ br_x509_minimal_run(void *t0ctx) } break; - case 44: { + case 43: { /* neg */ uint32_t a = T0_POP(); @@ -1410,7 +1401,7 @@ br_x509_minimal_run(void *t0ctx) } break; - case 45: { + case 44: { /* or */ uint32_t b = T0_POP(); @@ -1419,12 +1410,12 @@ br_x509_minimal_run(void *t0ctx) } break; - case 46: { + case 45: { /* over */ T0_PUSH(T0_PEEK(1)); } break; - case 47: { + case 46: { /* read-blob-inner */ uint32_t len = T0_POP(); @@ -1450,7 +1441,7 @@ br_x509_minimal_run(void *t0ctx) } break; - case 48: { + case 47: { /* read8-low */ if (CTX->hlen == 0) { @@ -1469,17 +1460,17 @@ br_x509_minimal_run(void *t0ctx) } break; - case 49: { + case 48: { /* roll */ T0_ROLL(T0_POP()); } break; - case 50: { + case 49: { /* rot */ T0_ROT(); } break; - case 51: { + case 50: { /* set16 */ uint32_t addr = T0_POP(); @@ -1487,7 +1478,7 @@ br_x509_minimal_run(void *t0ctx) } break; - case 52: { + case 51: { /* set32 */ uint32_t addr = T0_POP(); @@ -1495,7 +1486,7 @@ br_x509_minimal_run(void *t0ctx) } break; - case 53: { + case 52: { /* set8 */ uint32_t addr = T0_POP(); @@ -1503,7 +1494,7 @@ br_x509_minimal_run(void *t0ctx) } break; - case 54: { + case 53: { /* start-dn-hash */ CTX->dn_hash_impl->init(&CTX->dn_hash.vtable); @@ -1511,7 +1502,7 @@ br_x509_minimal_run(void *t0ctx) } break; - case 55: { + case 54: { /* start-tbs-hash */ br_multihash_init(&CTX->mhash); @@ -1519,19 +1510,19 @@ br_x509_minimal_run(void *t0ctx) } break; - case 56: { + case 55: { /* stop-tbs-hash */ CTX->do_mhash = 0; } break; - case 57: { + case 56: { /* swap */ T0_SWAP(); } break; - case 58: { + case 57: { /* zero-server-name */ T0_PUSHi(-(CTX->server_name == NULL)); diff --git a/src/x509/x509_minimal.t0 b/src/x509/x509_minimal.t0 index bdb3e18..385972b 100644 --- a/src/x509/x509_minimal.t0 +++ b/src/x509/x509_minimal.t0 @@ -188,8 +188,7 @@ br_x509_minimal_init(br_x509_minimal_context *ctx, } static void -xm_start_chain(const br_x509_class **ctx, - unsigned expected_key_type, const char *server_name) +xm_start_chain(const br_x509_class **ctx, const char *server_name) { br_x509_minimal_context *cc; @@ -200,7 +199,6 @@ xm_start_chain(const br_x509_class **ctx, cc->cpu.dp = cc->dp_stack; cc->cpu.rp = cc->rp_stack; br_x509_minimal_init_main(&cc->cpu); - cc->expected_key_type = expected_key_type; if (server_name == NULL || *server_name == 0) { cc->server_name = NULL; } else { @@ -269,7 +267,7 @@ xm_end_chain(const br_x509_class **ctx) } static const br_x509_pkey * -xm_get_pkey(const br_x509_class *const *ctx) +xm_get_pkey(const br_x509_class *const *ctx, unsigned *usages) { br_x509_minimal_context *cc; @@ -277,6 +275,9 @@ xm_get_pkey(const br_x509_class *const *ctx) if (cc->err == BR_ERR_X509_OK || cc->err == BR_ERR_X509_NOT_TRUSTED) { + if (usages != NULL) { + *usages = cc->key_usages; + } return &((br_x509_minimal_context *)ctx)->pkey; } else { return NULL; @@ -472,7 +473,7 @@ cc: zero-server-name ( -- bool ) { T0_PUSHi(-(CTX->server_name == NULL)); } -addr: expected_key_type +addr: key_usages addr: cert_sig addr: cert_sig_len addr: cert_signer_key_type @@ -705,7 +706,7 @@ cc: check-direct-trust ( -- ) { if (ta->flags & BR_X509_TA_CA) { continue; } - hash_dn(CTX, ta->dn, ta->dn_len, hashed_DN); + hash_dn(CTX, ta->dn.data, ta->dn.len, hashed_DN); if (memcmp(hashed_DN, CTX->current_dn_hash, DNHASH_LEN)) { continue; } @@ -765,7 +766,7 @@ cc: check-trust-anchor-CA ( -- ) { if (!(ta->flags & BR_X509_TA_CA)) { continue; } - hash_dn(CTX, ta->dn, ta->dn_len, hashed_DN); + hash_dn(CTX, ta->dn.data, ta->dn.len, hashed_DN); if (memcmp(hashed_DN, CTX->saved_dn_hash, DNHASH_LEN)) { continue; } @@ -892,20 +893,14 @@ OID: subjectInfoAccess 1.3.6.1.5.5.7.1.11 \ Process a Key Usage extension. \ For the EE certificate: -\ -- if the expected key usage is "key exchange", then the extension -\ must contain either keyEncipherment (2) or dataEncipherment (3); -\ -- if the expected key usage is "signature", then the extension -\ must contain either digitalSignature (0) or nonRepudiation (1). +\ -- if the key usage contains keyEncipherment (2), dataEncipherment (3) +\ or keyAgreement (4), then the "key exchange" usage is allowed; +\ -- if the key usage contains digitalSignature (0) or nonRepudiation (1), +\ then the "signature" usage is allowed. \ For CA certificates, the extension must contain keyCertSign (5). : process-keyUsage ( lim ee -- lim ) - \ Compute flags, depending on EE status and expected key usage. - \ This is a mask of bits in the first byte. - if - addr-expected_key_type get8 0x10 and if 0x30 else 0xC0 then - else - 0x04 - then - { mask } + { ee } + \ Read tag for the BIT STRING and open it. read-tag 0x03 check-tag-primitive read-length-open-elt @@ -919,7 +914,20 @@ OID: subjectInfoAccess 1.3.6.1.5.5.7.1.11 1 of read8 ign >> ign << endof drop read8 0 endcase - mask and ifnot ERR_X509_FORBIDDEN_KEY_USAGE fail then + + \ Check bits. + ee if + \ EE: get usages. + 0 + over 0x38 and if 0x10 or then + swap 0xC0 and if 0x20 or then + addr-key_usages set8 + else + \ Not EE: keyCertSign must be set. + 0x04 and ifnot ERR_X509_FORBIDDEN_KEY_USAGE fail then + then + + \ We don't care about subsequent bytes. skip-close-elt ; \ Process a Subject Alt Name extension. Returned value is a boolean set @@ -1070,15 +1078,8 @@ OID: subjectInfoAccess 1.3.6.1.5.5.7.1.11 \ Process public key. ee if - \ For the EE certificate, check that the key type - \ matches that which was expected, then copy the - \ data to the relevant buffer. - addr-expected_key_type get8 0x0F and - dup if - pkey-type = ifnot ERR_X509_WRONG_KEY_TYPE fail then - else - drop - then + \ For the EE certificate, copy the key data to the + \ relevant buffer. pkey-type case KEYTYPE_RSA of nlen elen copy-ee-rsa-pkey endof KEYTYPE_EC of curve qlen copy-ee-ec-pkey endof @@ -1286,6 +1287,9 @@ OID: subjectInfoAccess 1.3.6.1.5.5.7.1.11 check-trust-anchor-CA ; : main + \ Unless restricted by a Key Usage extension, all usages are + \ deemed allowed. + 0x30 addr-key_usages set8 -1 decode-certificate co begin diff --git a/test/test_x509.c b/test/test_x509.c index 52a9e2c..c4f0885 100644 --- a/test/test_x509.c +++ b/test/test_x509.c @@ -1438,6 +1438,7 @@ run_test_case(test_case *tc) blob *certs; br_x509_pkey *ee_pkey_ref; const br_x509_pkey *ee_pkey; + unsigned usages; unsigned status; printf("%s: ", tc->name); @@ -1477,8 +1478,8 @@ run_test_case(test_case *tc) tta->key_name); exit(EXIT_FAILURE); } - anchors[u].dn = tta->dn; - anchors[u].dn_len = tta->dn_len; + anchors[u].dn.data = tta->dn; + anchors[u].dn.len = tta->dn_len; anchors[u].flags = tta->flags; anchors[u].pkey = *tak; } @@ -1541,8 +1542,7 @@ run_test_case(test_case *tc) * Run the engine. We inject certificates by chunks of 100 bytes * in order to exercise the coroutine API. */ - ctx.vtable->start_chain(&ctx.vtable, - tc->key_type_usage, tc->servername); + ctx.vtable->start_chain(&ctx.vtable, tc->servername); for (u = 0; u < num_certs; u ++) { size_t v; @@ -1561,7 +1561,22 @@ run_test_case(test_case *tc) ctx.vtable->end_cert(&ctx.vtable); } status = ctx.vtable->end_chain(&ctx.vtable); - ee_pkey = ctx.vtable->get_pkey(&ctx.vtable); + ee_pkey = ctx.vtable->get_pkey(&ctx.vtable, &usages); + + /* + * Check key type and usage. + */ + if (ee_pkey != NULL) { + unsigned ktu; + + ktu = ee_pkey->key_type | usages; + if (tc->key_type_usage != (ktu & tc->key_type_usage)) { + fprintf(stderr, "wrong key type + usage" + " (expected 0x%02X, got 0x%02X)\n", + tc->key_type_usage, ktu); + exit(EXIT_FAILURE); + } + } /* * Check results. Note that we may still get a public key if diff --git a/tools/brssl.h b/tools/brssl.h index a3ceb14..e93ed4c 100644 --- a/tools/brssl.h +++ b/tools/brssl.h @@ -279,6 +279,11 @@ void list_names(void); */ const char *ec_curve_name(int curve); +/* + * Get the symbolic name for a hash function name (by ID). + */ +const char *hash_function_name(int id); + /* * Read a file completely. The returned block is allocated with xmalloc() * and must be released by the caller. @@ -342,6 +347,12 @@ pem_object *decode_pem(const void *src, size_t len, size_t *num); */ br_x509_certificate *read_certificates(const char *fname, size_t *num); +/* + * Release certificates. This releases all certificate data arrays, + * and the whole array as well. + */ +void free_certificates(br_x509_certificate *certs, size_t num); + /* * Interpret a certificate as a trust anchor. The trust anchor is * newly allocated with xmalloc() and the caller must release it. @@ -369,6 +380,12 @@ void free_ta_contents(br_x509_trust_anchor *ta); */ size_t read_trust_anchors(anchor_list *dst, const char *fname); +/* + * Get the "signer key type" for the certificate (key type of the + * issuing CA). On error, this prints a message on stderr, and returns 0. + */ +int get_cert_signer_algo(br_x509_certificate *xc); + /* * Special "no anchor" X.509 validator that wraps around another X.509 * validator and turns "not trusted" error codes into success. This is @@ -408,6 +425,20 @@ private_key *read_private_key(const char *fname); */ void free_private_key(private_key *sk); +/* + * Get the encoded OID for a given hash function (to use with PKCS#1 + * signatures). If the hash function ID is 0 (for MD5+SHA-1), or if + * the ID is not one of the SHA-* functions (SHA-1, SHA-224, SHA-256, + * SHA-384, SHA-512), then this function returns NULL. + */ +const unsigned char *get_hash_oid(int id); + +/* + * Get a hash implementation by ID. This returns NULL if the hash + * implementation is not available. + */ +const br_hash_class *get_hash_impl(int id); + /* * Find the symbolic name and the description for an error. If 'err' is * recognised then the error symbolic name is returned; if 'comment' is diff --git a/tools/certs.c b/tools/certs.c index fdee5c6..91ca9b9 100644 --- a/tools/certs.c +++ b/tools/certs.c @@ -53,8 +53,8 @@ certificate_to_trust_anchor_inner(br_x509_trust_anchor *ta, VEC_CLEAR(vdn); return -1; } - ta->dn = VEC_TOARRAY(vdn); - ta->dn_len = VEC_LEN(vdn); + ta->dn.data = VEC_TOARRAY(vdn); + ta->dn.len = VEC_LEN(vdn); VEC_CLEAR(vdn); ta->flags = 0; if (br_x509_decoder_isCA(&dc)) { @@ -76,7 +76,7 @@ certificate_to_trust_anchor_inner(br_x509_trust_anchor *ta, break; default: fprintf(stderr, "ERROR: unsupported public key type in CA\n"); - xfree(ta->dn); + xfree(ta->dn.data); return -1; } return 0; @@ -99,7 +99,7 @@ certificate_to_trust_anchor(br_x509_certificate *xc) void free_ta_contents(br_x509_trust_anchor *ta) { - xfree(ta->dn); + xfree(ta->dn.data); switch (ta->pkey.key_type) { case BR_KEYTYPE_RSA: xfree(ta->pkey.key.rsa.n); @@ -137,15 +137,32 @@ read_trust_anchors(anchor_list *dst, const char *fname) return num; } +/* see brssl.h */ +int +get_cert_signer_algo(br_x509_certificate *xc) +{ + br_x509_decoder_context dc; + int err; + + br_x509_decoder_init(&dc, 0, 0); + br_x509_decoder_push(&dc, xc->data, xc->data_len); + err = br_x509_decoder_last_error(&dc); + if (err != 0) { + fprintf(stderr, + "ERROR: certificate decoding failed with error %d\n", + -err); + return 0; + } + return br_x509_decoder_get_signer_key_type(&dc); +} + static void -xwc_start_chain(const br_x509_class **ctx, - unsigned expected_key_type, const char *server_name) +xwc_start_chain(const br_x509_class **ctx, const char *server_name) { x509_noanchor_context *xwc; xwc = (x509_noanchor_context *)ctx; - (*xwc->inner)->start_chain(xwc->inner, - expected_key_type, server_name); + (*xwc->inner)->start_chain(xwc->inner, server_name); } static void @@ -190,12 +207,12 @@ xwc_end_chain(const br_x509_class **ctx) } static const br_x509_pkey * -xwc_get_pkey(const br_x509_class *const *ctx) +xwc_get_pkey(const br_x509_class *const *ctx, unsigned *usages) { x509_noanchor_context *xwc; xwc = (x509_noanchor_context *)ctx; - return (*xwc->inner)->get_pkey(xwc->inner); + return (*xwc->inner)->get_pkey(xwc->inner, usages); } /* see brssl.h */ diff --git a/tools/client.c b/tools/client.c index 72bdbd1..102d43b 100644 --- a/tools/client.c +++ b/tools/client.c @@ -117,6 +117,308 @@ host_connect(const char *host, const char *port, int verbose) return fd; } +typedef struct { + const br_ssl_client_certificate_class *vtable; + int verbose; + br_x509_certificate *chain; + size_t chain_len; + private_key *sk; + int issuer_key_type; +} ccert_context; + +static void +cc_start_name_list(const br_ssl_client_certificate_class **pctx) +{ + ccert_context *zc; + + zc = (ccert_context *)pctx; + if (zc->verbose) { + fprintf(stderr, "Server requests a client certificate.\n"); + fprintf(stderr, "--- anchor DN list start ---\n"); + } +} + +static void +cc_start_name(const br_ssl_client_certificate_class **pctx, size_t len) +{ + ccert_context *zc; + + zc = (ccert_context *)pctx; + if (zc->verbose) { + fprintf(stderr, "new anchor name, length = %u\n", + (unsigned)len); + } +} + +static void +cc_append_name(const br_ssl_client_certificate_class **pctx, + const unsigned char *data, size_t len) +{ + ccert_context *zc; + + zc = (ccert_context *)pctx; + if (zc->verbose) { + size_t u; + + for (u = 0; u < len; u ++) { + if (u == 0) { + fprintf(stderr, " "); + } else if (u > 0 && u % 16 == 0) { + fprintf(stderr, "\n "); + } + fprintf(stderr, " %02x", data[u]); + } + if (len > 0) { + fprintf(stderr, "\n"); + } + } +} + +static void +cc_end_name(const br_ssl_client_certificate_class **pctx) +{ + (void)pctx; +} + +static void +cc_end_name_list(const br_ssl_client_certificate_class **pctx) +{ + ccert_context *zc; + + zc = (ccert_context *)pctx; + if (zc->verbose) { + fprintf(stderr, "--- anchor DN list end ---\n"); + } +} + +static void +print_hashes(unsigned hh, unsigned hh2) +{ + int i; + + for (i = 0; i < 8; i ++) { + const char *name; + + name = hash_function_name(i); + if (((hh >> i) & 1) != 0) { + fprintf(stderr, " %s", name); + } else if (((hh2 >> i) & 1) != 0) { + fprintf(stderr, " (%s)", name); + } + } +} + +static int +choose_hash(unsigned hh) +{ + static const int f[] = { + br_sha256_ID, br_sha224_ID, br_sha384_ID, br_sha512_ID, + br_sha1_ID, br_md5sha1_ID, -1 + }; + + size_t u; + + for (u = 0; f[u] >= 0; u ++) { + if (((hh >> f[u]) & 1) != 0) { + return f[u]; + } + } + return -1; +} + +static void +cc_choose(const br_ssl_client_certificate_class **pctx, + const br_ssl_client_context *cc, uint32_t auth_types, + br_ssl_client_certificate *choices) +{ + ccert_context *zc; + int scurve; + + zc = (ccert_context *)pctx; + scurve = br_ssl_client_get_server_curve(cc); + if (zc->verbose) { + unsigned hashes; + + hashes = br_ssl_client_get_server_hashes(cc); + if ((auth_types & 0x00FF) != 0) { + fprintf(stderr, "supported: RSA signatures:"); + print_hashes(auth_types, hashes); + fprintf(stderr, "\n"); + } + if ((auth_types & 0xFF00) != 0) { + fprintf(stderr, "supported: ECDSA signatures:"); + print_hashes(auth_types >> 8, hashes >> 8); + fprintf(stderr, "\n"); + } + if ((auth_types & 0x010000) != 0) { + fprintf(stderr, "supported:" + " fixed ECDH (cert signed with RSA)\n"); + } + if ((auth_types & 0x020000) != 0) { + fprintf(stderr, "supported:" + " fixed ECDH (cert signed with ECDSA)\n"); + } + if (scurve) { + fprintf(stderr, "server key curve: %s (%d)\n", + ec_curve_name(scurve), scurve); + } else { + fprintf(stderr, "server key is not EC\n"); + } + } + switch (zc->sk->key_type) { + case BR_KEYTYPE_RSA: + if ((choices->hash_id = choose_hash(auth_types)) >= 0) { + if (zc->verbose) { + fprintf(stderr, "using RSA, hash = %d (%s)\n", + choices->hash_id, + hash_function_name(choices->hash_id)); + } + choices->auth_type = BR_AUTH_RSA; + choices->chain = zc->chain; + choices->chain_len = zc->chain_len; + return; + } + break; + case BR_KEYTYPE_EC: + if (zc->issuer_key_type != 0 + && scurve == zc->sk->key.ec.curve) + { + int x; + + x = (zc->issuer_key_type == BR_KEYTYPE_RSA) ? 16 : 17; + if (((auth_types >> x) & 1) != 0) { + if (zc->verbose) { + fprintf(stderr, "using static ECDH\n"); + } + choices->auth_type = BR_AUTH_ECDH; + choices->hash_id = -1; + choices->chain = zc->chain; + choices->chain_len = zc->chain_len; + return; + } + } + if ((choices->hash_id = choose_hash(auth_types >> 8)) >= 0) { + if (zc->verbose) { + fprintf(stderr, "using ECDSA, hash = %d (%s)\n", + choices->hash_id, + hash_function_name(choices->hash_id)); + } + choices->auth_type = BR_AUTH_ECDSA; + choices->chain = zc->chain; + choices->chain_len = zc->chain_len; + return; + } + break; + } + if (zc->verbose) { + fprintf(stderr, "no matching client certificate\n"); + } + choices->chain = NULL; + choices->chain_len = 0; +} + +static uint32_t +cc_do_keyx(const br_ssl_client_certificate_class **pctx, + unsigned char *data, size_t len) +{ + ccert_context *zc; + + zc = (ccert_context *)pctx; + return br_ec_prime_i31.mul(data, len, zc->sk->key.ec.x, + zc->sk->key.ec.xlen, zc->sk->key.ec.curve); +} + +static size_t +cc_do_sign(const br_ssl_client_certificate_class **pctx, + int hash_id, size_t hv_len, unsigned char *data, size_t len) +{ + ccert_context *zc; + unsigned char hv[64]; + + zc = (ccert_context *)pctx; + memcpy(hv, data, hv_len); + switch (zc->sk->key_type) { + const br_hash_class *hc; + const unsigned char *hash_oid; + uint32_t x; + size_t sig_len; + + case BR_KEYTYPE_RSA: + hash_oid = get_hash_oid(hash_id); + if (hash_oid == NULL && hash_id != 0) { + if (zc->verbose) { + fprintf(stderr, "ERROR: cannot RSA-sign with" + " unknown hash function: %d\n", + hash_id); + } + return 0; + } + sig_len = (zc->sk->key.rsa.n_bitlen + 7) >> 3; + if (len < sig_len) { + if (zc->verbose) { + fprintf(stderr, "ERROR: cannot RSA-sign," + " buffer is too small" + " (sig=%lu, buf=%lu)\n", + (unsigned long)sig_len, + (unsigned long)len); + } + return 0; + } + x = br_rsa_i31_pkcs1_sign(hash_oid, hv, hv_len, + &zc->sk->key.rsa, data); + if (!x) { + if (zc->verbose) { + fprintf(stderr, "ERROR: RSA-sign failure\n"); + } + return 0; + } + return sig_len; + + case BR_KEYTYPE_EC: + hc = get_hash_impl(hash_id); + if (hc == NULL) { + if (zc->verbose) { + fprintf(stderr, "ERROR: cannot ECDSA-sign with" + " unknown hash function: %d\n", + hash_id); + } + return 0; + } + if (len < 139) { + if (zc->verbose) { + fprintf(stderr, "ERROR: cannot ECDSA-sign" + " (output buffer = %lu)\n", + (unsigned long)len); + } + return 0; + } + sig_len = br_ecdsa_i31_sign_asn1(&br_ec_prime_i31, + hc, hv, &zc->sk->key.ec, data); + if (sig_len == 0) { + if (zc->verbose) { + fprintf(stderr, "ERROR: ECDSA-sign failure\n"); + } + return 0; + } + return sig_len; + + default: + return 0; + } +} + +static const br_ssl_client_certificate_class ccert_vtable = { + sizeof(ccert_context), + cc_start_name_list, + cc_start_name, + cc_append_name, + cc_end_name, + cc_end_name_list, + cc_choose, + cc_do_keyx, + cc_do_sign +}; + static void usage_client(void) { @@ -139,6 +441,12 @@ usage_client(void) fprintf(stderr, " -CA file add certificates in 'file' to trust anchors\n"); fprintf(stderr, +" -cert file set client certificate chain\n"); + fprintf(stderr, +" -key file set client private key (for certificate authentication)\n"); + fprintf(stderr, +" -nostaticecdh prohibit full-static ECDH (client certificate)\n"); + fprintf(stderr, " -list list supported names (protocols, algorithms...)\n"); fprintf(stderr, " -vmin name set minimum supported version (default: TLS-1.0)\n"); @@ -179,6 +487,11 @@ do_client(int argc, char *argv[]) br_x509_minimal_context xc; x509_noanchor_context xwc; const br_hash_class *dnhash; + ccert_context zc; + br_x509_certificate *chain; + size_t chain_len; + private_key *sk; + int nostaticecdh; unsigned char *iobuf; size_t iobuf_len; size_t minhello_len; @@ -200,6 +513,10 @@ do_client(int argc, char *argv[]) num_suites = 0; hfuns = 0; suite_ids = NULL; + chain = NULL; + chain_len = 0; + sk = NULL; + nostaticecdh = 0; iobuf = NULL; iobuf_len = 0; minhello_len = (size_t)-1; @@ -279,6 +596,44 @@ do_client(int argc, char *argv[]) usage_client(); goto client_exit_error; } + } else if (eqstr(arg, "-cert")) { + if (++ i >= argc) { + fprintf(stderr, + "ERROR: no argument for '-cert'\n"); + usage_client(); + goto client_exit_error; + } + if (chain != NULL) { + fprintf(stderr, + "ERROR: duplicate certificate chain\n"); + usage_client(); + goto client_exit_error; + } + arg = argv[i]; + chain = read_certificates(arg, &chain_len); + if (chain == NULL || chain_len == 0) { + goto client_exit_error; + } + } else if (eqstr(arg, "-key")) { + if (++ i >= argc) { + fprintf(stderr, + "ERROR: no argument for '-key'\n"); + usage_client(); + goto client_exit_error; + } + if (sk != NULL) { + fprintf(stderr, + "ERROR: duplicate private key\n"); + usage_client(); + goto client_exit_error; + } + arg = argv[i]; + sk = read_private_key(arg); + if (sk == NULL) { + goto client_exit_error; + } + } else if (eqstr(arg, "-nostaticecdh")) { + nostaticecdh = 1; } else if (eqstr(arg, "-list")) { list_names(); goto client_exit; @@ -412,7 +767,7 @@ do_client(int argc, char *argv[]) } if (u == 0) { host = xstrdup(server_name); - port = "443"; + port = xstrdup("443"); } else { port = xstrdup(server_name + u); host = xmalloc(u); @@ -423,6 +778,19 @@ do_client(int argc, char *argv[]) sni = host; } + if (chain == NULL && sk != NULL) { + fprintf(stderr, "ERROR: private key specified, but" + " no certificate chain\n"); + usage_client(); + goto client_exit_error; + } + if (chain != NULL && sk == NULL) { + fprintf(stderr, "ERROR: certificate chain specified, but" + " no private key\n"); + usage_client(); + goto client_exit_error; + } + if (vmin == 0) { vmin = BR_TLS10; } @@ -560,11 +928,13 @@ do_client(int argc, char *argv[]) } if ((req & REQ_ECDHE_RSA) != 0) { br_ssl_engine_set_ec(&cc.eng, &br_ec_prime_i31); - br_ssl_client_set_rsavrfy(&cc, &br_rsa_i31_pkcs1_vrfy); + br_ssl_engine_set_rsavrfy(&cc.eng, + &br_rsa_i31_pkcs1_vrfy); } if ((req & REQ_ECDHE_ECDSA) != 0) { br_ssl_engine_set_ec(&cc.eng, &br_ec_prime_i31); - br_ssl_client_set_ecdsa(&cc, &br_ecdsa_i31_vrfy_asn1); + br_ssl_engine_set_ecdsa(&cc.eng, + &br_ecdsa_i31_vrfy_asn1); } if ((req & REQ_ECDH) != 0) { br_ssl_engine_set_ec(&cc.eng, &br_ec_prime_i31); @@ -624,6 +994,23 @@ do_client(int argc, char *argv[]) } br_ssl_engine_set_all_flags(&cc.eng, flags); + if (chain != NULL) { + zc.vtable = &ccert_vtable; + zc.verbose = verbose; + zc.chain = chain; + zc.chain_len = chain_len; + zc.sk = sk; + if (nostaticecdh || sk->key_type != BR_KEYTYPE_EC) { + zc.issuer_key_type = 0; + } else { + zc.issuer_key_type = get_cert_signer_algo(&chain[0]); + if (zc.issuer_key_type == 0) { + goto client_exit_error; + } + } + br_ssl_client_set_client_certificate(&cc, &zc.vtable); + } + br_ssl_engine_set_buffer(&cc.eng, iobuf, iobuf_len, bidi); br_ssl_client_reset(&cc, sni, 0); @@ -657,9 +1044,12 @@ do_client(int argc, char *argv[]) */ client_exit: xfree(host); + xfree(port); xfree(suites); xfree(suite_ids); VEC_CLEAREXT(anchors, &free_ta_contents); + free_certificates(chain, chain_len); + free_private_key(sk); xfree(iobuf); if (fd >= 0) { close(fd); diff --git a/tools/errors.c b/tools/errors.c index e9c6dfa..22f0c30 100644 --- a/tools/errors.c +++ b/tools/errors.c @@ -157,7 +157,18 @@ static struct { }, { BR_ERR_BAD_SIGNATURE, "BR_ERR_BAD_SIGNATURE", - "Invalid signature on ServerKeyExchange message." + "Invalid signature in ServerKeyExchange or" + " CertificateVerify message." + }, { + BR_ERR_WRONG_KEY_USAGE, + "BR_ERR_WRONG_KEY_USAGE", + "Peer's public key does not have the proper type or is" + " not allowed for the requested operation." + }, { + BR_ERR_NO_CLIENT_AUTH, + "BR_ERR_NO_CLIENT_AUTH", + "Client did not send a certificate upon request, or the" + " client certificate could not be validated." }, { BR_ERR_IO, "BR_ERR_IO", diff --git a/tools/files.c b/tools/files.c index 21c8166..651d51a 100644 --- a/tools/files.c +++ b/tools/files.c @@ -300,3 +300,15 @@ read_certificates(const char *fname, size_t *num) VEC_CLEAR(cert_list); return xcs; } + +/* see brssl.h */ +void +free_certificates(br_x509_certificate *certs, size_t num) +{ + size_t u; + + for (u = 0; u < num; u ++) { + xfree(certs[u].data); + } + xfree(certs); +} diff --git a/tools/keys.c b/tools/keys.c index 278a3b2..f7394be 100644 --- a/tools/keys.c +++ b/tools/keys.c @@ -168,3 +168,64 @@ free_private_key(private_key *sk) } xfree(sk); } + +/* + * OID for hash functions in RSA signatures. + */ +static const unsigned char HASH_OID_SHA1[] = { + 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A +}; + +static const unsigned char HASH_OID_SHA224[] = { + 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04 +}; + +static const unsigned char HASH_OID_SHA256[] = { + 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01 +}; + +static const unsigned char HASH_OID_SHA384[] = { + 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02 +}; + +static const unsigned char HASH_OID_SHA512[] = { + 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03 +}; + +static const unsigned char *HASH_OID[] = { + HASH_OID_SHA1, + HASH_OID_SHA224, + HASH_OID_SHA256, + HASH_OID_SHA384, + HASH_OID_SHA512 +}; + +/* see brssl.h */ +const unsigned char * +get_hash_oid(int id) +{ + if (id >= 2 && id <= 6) { + return HASH_OID[id - 2]; + } else { + return NULL; + } +} + +/* see brssl.h */ +const br_hash_class * +get_hash_impl(int hash_id) +{ + size_t u; + + for (u = 0; hash_functions[u].name; u ++) { + const br_hash_class *hc; + int id; + + hc = hash_functions[u].hclass; + id = (hc->desc >> BR_HASHDESC_ID_OFF) & BR_HASHDESC_ID_MASK; + if (id == hash_id) { + return hc; + } + } + return NULL; +} diff --git a/tools/names.c b/tools/names.c index 191dfeb..06b2cdb 100644 --- a/tools/names.c +++ b/tools/names.c @@ -651,3 +651,20 @@ ec_curve_name(int curve) return "unknown"; } } + +/* see brssl.h */ +const char * +hash_function_name(int id) +{ + switch (id) { + case br_md5sha1_ID: return "MD5+SHA-1"; + case br_md5_ID: return "MD5"; + case br_sha1_ID: return "SHA-1"; + case br_sha224_ID: return "SHA-224"; + case br_sha256_ID: return "SHA-256"; + case br_sha384_ID: return "SHA-384"; + case br_sha512_ID: return "SHA-512"; + default: + return "unknown"; + } +} diff --git a/tools/server.c b/tools/server.c index b81ce07..5e9315d 100644 --- a/tools/server.c +++ b/tools/server.c @@ -214,6 +214,10 @@ usage_server(void) fprintf(stderr, " -key fname read private key from file 'fname'\n"); fprintf(stderr, +" -CA file add trust anchors from 'file' (for client auth)\n"); + fprintf(stderr, +" -anon_ok request but do not require a client certificate\n"); + fprintf(stderr, " -list list supported names (protocols, algorithms...)\n"); fprintf(stderr, " -vmin name set minimum supported version (default: TLS-1.0)\n"); @@ -237,20 +241,43 @@ typedef struct { private_key *sk; } policy_context; +static void +print_hashes(unsigned chashes) +{ + int i; + + for (i = 2; i <= 6; i ++) { + if ((chashes >> i) & 1) { + int z; + + switch (i) { + case 3: z = 224; break; + case 4: z = 256; break; + case 5: z = 384; break; + case 6: z = 512; break; + default: + z = 1; + break; + } + fprintf(stderr, " sha%d", z); + } + } +} + static int -get_cert_signer_algo(br_x509_certificate *xc) +choose_hash(unsigned chashes) { - br_x509_decoder_context dc; - int err; + int hash_id; - br_x509_decoder_init(&dc, 0, 0); - br_x509_decoder_push(&dc, xc->data, xc->data_len); - err = br_x509_decoder_last_error(&dc); - if (err != 0) { - return -err; - } else { - return br_x509_decoder_get_signer_key_type(&dc); + for (hash_id = 6; hash_id >= 2; hash_id --) { + if (((chashes >> hash_id) & 1) != 0) { + return hash_id; + } } + /* + * Normally unreachable. + */ + return 0; } static int @@ -262,16 +289,10 @@ sp_choose(const br_ssl_server_policy_class **pctx, const br_suite_translated *st; size_t u, st_num; unsigned chashes; - int hash_id; pc = (policy_context *)pctx; st = br_ssl_server_get_client_suites(cc, &st_num); chashes = br_ssl_server_get_client_hashes(cc); - for (hash_id = 6; hash_id >= 2; hash_id --) { - if ((chashes >> hash_id) & 1) { - break; - } - } if (pc->verbose) { fprintf(stderr, "Client parameters:\n"); fprintf(stderr, " Maximum version: "); @@ -301,24 +322,17 @@ sp_choose(const br_ssl_server_policy_class **pctx, get_suite_name_ext(st[u][0], csn, sizeof csn); fprintf(stderr, " %s\n", csn); } - fprintf(stderr, " Common hash functions:"); - for (u = 2; u <= 6; u ++) { - if ((chashes >> u) & 1) { - int z; - - switch (u) { - case 3: z = 224; break; - case 4: z = 256; break; - case 5: z = 384; break; - case 6: z = 512; break; - default: - z = 1; - break; - } - fprintf(stderr, " sha%d", z); - } + fprintf(stderr, " Common sign+hash functions:\n"); + if ((chashes & 0xFF) != 0) { + fprintf(stderr, " with RSA:"); + print_hashes(chashes); + fprintf(stderr, "\n"); + } + if ((chashes >> 8) != 0) { + fprintf(stderr, " with ECDSA:"); + print_hashes(chashes >> 8); + fprintf(stderr, "\n"); } - fprintf(stderr, "\n"); } for (u = 0; u < st_num; u ++) { unsigned tt; @@ -337,9 +351,10 @@ sp_choose(const br_ssl_server_policy_class **pctx, if (br_ssl_engine_get_version(&cc->eng) < BR_TLS12) { - hash_id = 0; + choices->hash_id = 0; + } else { + choices->hash_id = choose_hash(chashes); } - choices->hash_id = hash_id; goto choose_ok; } break; @@ -349,9 +364,11 @@ sp_choose(const br_ssl_server_policy_class **pctx, if (br_ssl_engine_get_version(&cc->eng) < BR_TLS12) { - hash_id = br_sha1_ID; + choices->hash_id = br_sha1_ID; + } else { + choices->hash_id = + choose_hash(chashes >> 8); } - choices->hash_id = hash_id; goto choose_ok; } break; @@ -409,55 +426,6 @@ sp_do_keyx(const br_ssl_server_policy_class **pctx, } } -/* - * OID for hash functions in RSA signatures. - */ -static const unsigned char HASH_OID_SHA1[] = { - 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A -}; - -static const unsigned char HASH_OID_SHA224[] = { - 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04 -}; - -static const unsigned char HASH_OID_SHA256[] = { - 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01 -}; - -static const unsigned char HASH_OID_SHA384[] = { - 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02 -}; - -static const unsigned char HASH_OID_SHA512[] = { - 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03 -}; - -static const unsigned char *HASH_OID[] = { - HASH_OID_SHA1, - HASH_OID_SHA224, - HASH_OID_SHA256, - HASH_OID_SHA384, - HASH_OID_SHA512 -}; - -static const br_hash_class * -get_hash_impl(int hash_id) -{ - size_t u; - - for (u = 0; hash_functions[u].name; u ++) { - const br_hash_class *hc; - int id; - - hc = hash_functions[u].hclass; - id = (hc->desc >> BR_HASHDESC_ID_OFF) & BR_HASHDESC_ID_MASK; - if (id == hash_id) { - return hc; - } - } - return NULL; -} - static size_t sp_do_sign(const br_ssl_server_policy_class **pctx, int hash_id, size_t hv_len, unsigned char *data, size_t len) @@ -474,11 +442,8 @@ sp_do_sign(const br_ssl_server_policy_class **pctx, const br_hash_class *hc; case BR_KEYTYPE_RSA: - if (hash_id == 0) { - hash_oid = NULL; - } else if (hash_id >= 2 && hash_id <= 6) { - hash_oid = HASH_OID[hash_id - 2]; - } else { + hash_oid = get_hash_oid(hash_id); + if (hash_oid == NULL && hash_id != 0) { if (pc->verbose) { fprintf(stderr, "ERROR: cannot RSA-sign with" " unknown hash function: %d\n", @@ -566,6 +531,9 @@ do_server(int argc, char *argv[]) size_t chain_len; int cert_signer_algo; private_key *sk; + anchor_list anchors = VEC_INIT; + br_x509_minimal_context xc; + const br_hash_class *dnhash; size_t u; br_ssl_server_context cc; policy_context pc; @@ -713,6 +681,20 @@ do_server(int argc, char *argv[]) if (sk == NULL) { goto server_exit_error; } + } else if (eqstr(arg, "-CA")) { + if (++ i >= argc) { + fprintf(stderr, + "ERROR: no argument for '-CA'\n"); + usage_server(); + goto server_exit_error; + } + arg = argv[i]; + if (read_trust_anchors(&anchors, arg) == 0) { + usage_server(); + goto server_exit_error; + } + } else if (eqstr(arg, "-anon_ok")) { + flags |= BR_OPT_TOLERATE_NO_CLIENT_AUTH; } else if (eqstr(arg, "-list")) { list_names(); goto server_exit; @@ -872,11 +854,10 @@ do_server(int argc, char *argv[]) break; } cert_signer_algo = get_cert_signer_algo(chain); - if (cert_signer_algo < 0) { - fprintf(stderr, "ERROR: server certificate cannot be" - " decoded (err=%d)\n", -cert_signer_algo); + if (cert_signer_algo == 0) { goto server_exit_error; - } else if (verbose) { + } + if (verbose) { const char *csas; switch (cert_signer_algo) { @@ -980,6 +961,7 @@ do_server(int argc, char *argv[]) } br_ssl_engine_set_suites(&cc.eng, suite_ids, num_suites); + dnhash = NULL; for (u = 0; hash_functions[u].name; u ++) { const br_hash_class *hc; int id; @@ -987,6 +969,7 @@ do_server(int argc, char *argv[]) hc = hash_functions[u].hclass; id = (hc->desc >> BR_HASHDESC_ID_OFF) & BR_HASHDESC_ID_MASK; if ((hfuns & ((unsigned)1 << id)) != 0) { + dnhash = hc; br_ssl_engine_set_hash(&cc.eng, id, hc); } } @@ -1007,6 +990,11 @@ do_server(int argc, char *argv[]) br_ssl_session_cache_lru_init(&lru, cache, cache_len); br_ssl_server_set_cache(&cc, &lru.vtable); + /* + * Set the policy handler (that chooses the actual cipher suite, + * selects the certificate chain, and runs the private key + * operations). + */ pc.vtable = &policy_vtable; pc.verbose = verbose; pc.chain = chain; @@ -1015,6 +1003,36 @@ do_server(int argc, char *argv[]) pc.sk = sk; br_ssl_server_set_policy(&cc, &pc.vtable); + /* + * If trust anchors have been configured, then set an X.509 + * validation engine and activate client certificate + * authentication. + */ + if (VEC_LEN(anchors) != 0) { + br_x509_minimal_init(&xc, dnhash, + &VEC_ELT(anchors, 0), VEC_LEN(anchors)); + for (u = 0; hash_functions[u].name; u ++) { + const br_hash_class *hc; + int id; + + hc = hash_functions[u].hclass; + id = (hc->desc >> BR_HASHDESC_ID_OFF) + & BR_HASHDESC_ID_MASK; + if ((hfuns & ((unsigned)1 << id)) != 0) { + br_x509_minimal_set_hash(&xc, id, hc); + } + } + br_ssl_engine_set_rsavrfy(&cc.eng, &br_rsa_i31_pkcs1_vrfy); + br_ssl_engine_set_ec(&cc.eng, &br_ec_prime_i31); + br_ssl_engine_set_ecdsa(&cc.eng, &br_ecdsa_i31_vrfy_asn1); + br_x509_minimal_set_rsa(&xc, &br_rsa_i31_pkcs1_vrfy); + br_x509_minimal_set_ecdsa(&xc, + &br_ec_prime_i31, &br_ecdsa_i31_vrfy_asn1); + br_ssl_engine_set_x509(&cc.eng, &xc.vtable); + br_ssl_server_set_trust_anchor_names_alt(&cc, + &VEC_ELT(anchors, 0), VEC_LEN(anchors)); + } + br_ssl_engine_set_buffer(&cc.eng, iobuf, iobuf_len, bidi); /* @@ -1061,13 +1079,9 @@ do_server(int argc, char *argv[]) server_exit: xfree(suites); xfree(suite_ids); - if (chain != NULL) { - for (u = 0; u < chain_len; u ++) { - xfree(chain[u].data); - } - xfree(chain); - } + free_certificates(chain, chain_len); free_private_key(sk); + VEC_CLEAREXT(anchors, &free_ta_contents); xfree(iobuf); xfree(cache); if (fd >= 0) { diff --git a/tools/ta.c b/tools/ta.c index a29aae0..df72e2b 100644 --- a/tools/ta.c +++ b/tools/ta.c @@ -93,7 +93,7 @@ print_ta_internals(br_x509_trust_anchor *ta, long ctr) char tmp[25]; sprintf(tmp, "TA%ld_DN", ctr); - print_blob(tmp, ta->dn, ta->dn_len); + print_blob(tmp, ta->dn.data, ta->dn.len); switch (ta->pkey.key_type) { case BR_KEYTYPE_RSA: sprintf(tmp, "TA%ld_RSA_N", ctr); @@ -119,7 +119,8 @@ print_ta(br_x509_trust_anchor *ta, long ctr) char tmp[25]; printf("\t{\n"); - printf("\t\t(unsigned char *)TA%ld_DN, sizeof TA%ld_DN,\n", ctr, ctr); + printf("\t\t{ (unsigned char *)TA%ld_DN, sizeof TA%ld_DN },\n", + ctr, ctr); printf("\t\t%s,\n", (ta->flags & BR_X509_TA_CA) ? "BR_X509_TA_CA" : "0"); printf("\t\t{\n"); diff --git a/tools/verify.c b/tools/verify.c index 064a61f..7405578 100644 --- a/tools/verify.c +++ b/tools/verify.c @@ -181,9 +181,11 @@ do_verify(int argc, char *argv[]) cert_list chain = VEC_INIT; size_t u; br_x509_minimal_context mc; - int err_keyx, err_sign; + int err; int print_text, print_C; br_x509_pkey *pk; + const br_x509_pkey *tpk; + unsigned usages; retcode = 0; verbose = 1; @@ -191,8 +193,6 @@ do_verify(int argc, char *argv[]) print_text = 0; print_C = 0; pk = NULL; - err_keyx = 0; - err_sign = 0; for (i = 0; i < argc; i ++) { const char *arg; @@ -266,55 +266,44 @@ do_verify(int argc, char *argv[]) br_x509_minimal_set_rsa(&mc, &br_rsa_i31_pkcs1_vrfy); br_x509_minimal_set_ecdsa(&mc, &br_ec_prime_i31, &br_ecdsa_i31_vrfy_asn1); - for (i = 0; i < 2; i ++) { - const br_x509_pkey *tpk; - int err; - mc.vtable->start_chain(&mc.vtable, - i == 0 ? BR_KEYTYPE_KEYX : BR_KEYTYPE_SIGN, sni); - for (u = 0; u < VEC_LEN(chain); u ++) { - br_x509_certificate *xc; + mc.vtable->start_chain(&mc.vtable, sni); + for (u = 0; u < VEC_LEN(chain); u ++) { + br_x509_certificate *xc; - xc = &VEC_ELT(chain, u); - mc.vtable->start_cert(&mc.vtable, xc->data_len); - mc.vtable->append(&mc.vtable, xc->data, xc->data_len); - mc.vtable->end_cert(&mc.vtable); - } - err = mc.vtable->end_chain(&mc.vtable); - if (i == 0) { - err_keyx = err; - } else { - err_sign = err; - } - tpk = mc.vtable->get_pkey(&mc.vtable); - if (pk == NULL && tpk != NULL) { - pk = xpkeydup(tpk); - } + xc = &VEC_ELT(chain, u); + mc.vtable->start_cert(&mc.vtable, xc->data_len); + mc.vtable->append(&mc.vtable, xc->data, xc->data_len); + mc.vtable->end_cert(&mc.vtable); + } + err = mc.vtable->end_chain(&mc.vtable); + tpk = mc.vtable->get_pkey(&mc.vtable, &usages); + if (tpk != NULL) { + pk = xpkeydup(tpk); } - if (err_keyx == 0 || err_sign == 0) { + + if (err == 0) { if (verbose) { - fprintf(stderr, "Validation success"); - if (err_keyx == 0 && err_sign == 0) { - fprintf(stderr, " (key exchange, sign)\n"); - } else if (err_keyx == 0) { - fprintf(stderr, " (key exchange)\n"); - } else if (err_sign == 0) { - fprintf(stderr, " (signature)\n"); + int hkx; + + fprintf(stderr, "Validation success; usages:"); + hkx = 0; + if (usages & BR_KEYTYPE_KEYX) { + fprintf(stderr, " key exchange"); + hkx = 1; } + if (usages & BR_KEYTYPE_SIGN) { + if (hkx) { + fprintf(stderr, ","); + } + fprintf(stderr, " signature"); + } + fprintf(stderr, "\n"); } } else { if (verbose) { - int err; const char *errname, *errmsg; - /* - * If the two error codes differ, we want the one - * which is not a "forbidden key usage". - */ - err = err_keyx; - if (err == BR_ERR_X509_FORBIDDEN_KEY_USAGE) { - err = err_sign; - } fprintf(stderr, "Validation failed, err = %d", err); errname = find_error_name(err, &errmsg); if (errname != NULL) { -- 2.17.1