aboutsummaryrefslogtreecommitdiffstats
path: root/test/monniaux/BearSSL/src/ssl
diff options
context:
space:
mode:
Diffstat (limited to 'test/monniaux/BearSSL/src/ssl')
-rw-r--r--test/monniaux/BearSSL/src/ssl/prf.c73
-rw-r--r--test/monniaux/BearSSL/src/ssl/prf_md5sha1.c43
-rw-r--r--test/monniaux/BearSSL/src/ssl/prf_sha256.c36
-rw-r--r--test/monniaux/BearSSL/src/ssl/prf_sha384.c36
-rw-r--r--test/monniaux/BearSSL/src/ssl/ssl_ccert_single_ec.c156
-rw-r--r--test/monniaux/BearSSL/src/ssl/ssl_ccert_single_rsa.c149
-rw-r--r--test/monniaux/BearSSL/src/ssl/ssl_client.c78
-rw-r--r--test/monniaux/BearSSL/src/ssl/ssl_client_default_rsapub.c32
-rw-r--r--test/monniaux/BearSSL/src/ssl/ssl_client_full.c179
-rw-r--r--test/monniaux/BearSSL/src/ssl/ssl_engine.c1569
-rw-r--r--test/monniaux/BearSSL/src/ssl/ssl_engine_default_aescbc.c64
-rw-r--r--test/monniaux/BearSSL/src/ssl/ssl_engine_default_aesccm.c67
-rw-r--r--test/monniaux/BearSSL/src/ssl/ssl_engine_default_aesgcm.c89
-rw-r--r--test/monniaux/BearSSL/src/ssl/ssl_engine_default_chapol.c65
-rw-r--r--test/monniaux/BearSSL/src/ssl/ssl_engine_default_descbc.c37
-rw-r--r--test/monniaux/BearSSL/src/ssl/ssl_engine_default_ec.c36
-rw-r--r--test/monniaux/BearSSL/src/ssl/ssl_engine_default_ecdsa.c38
-rw-r--r--test/monniaux/BearSSL/src/ssl/ssl_engine_default_rsavrfy.c32
-rw-r--r--test/monniaux/BearSSL/src/ssl/ssl_hashes.c46
-rw-r--r--test/monniaux/BearSSL/src/ssl/ssl_hs_client.c1915
-rw-r--r--test/monniaux/BearSSL/src/ssl/ssl_hs_client.t01276
-rw-r--r--test/monniaux/BearSSL/src/ssl/ssl_hs_common.t01382
-rw-r--r--test/monniaux/BearSSL/src/ssl/ssl_hs_server.c2009
-rw-r--r--test/monniaux/BearSSL/src/ssl/ssl_hs_server.t01510
-rw-r--r--test/monniaux/BearSSL/src/ssl/ssl_io.c261
-rw-r--r--test/monniaux/BearSSL/src/ssl/ssl_keyexport.c83
-rw-r--r--test/monniaux/BearSSL/src/ssl/ssl_lru.c537
-rw-r--r--test/monniaux/BearSSL/src/ssl/ssl_rec_cbc.c440
-rw-r--r--test/monniaux/BearSSL/src/ssl/ssl_rec_ccm.c213
-rw-r--r--test/monniaux/BearSSL/src/ssl/ssl_rec_chapol.c177
-rw-r--r--test/monniaux/BearSSL/src/ssl/ssl_rec_gcm.c235
-rw-r--r--test/monniaux/BearSSL/src/ssl/ssl_scert_single_ec.c142
-rw-r--r--test/monniaux/BearSSL/src/ssl/ssl_scert_single_rsa.c162
-rw-r--r--test/monniaux/BearSSL/src/ssl/ssl_server.c52
-rw-r--r--test/monniaux/BearSSL/src/ssl/ssl_server_full_ec.c149
-rw-r--r--test/monniaux/BearSSL/src/ssl/ssl_server_full_rsa.c132
-rw-r--r--test/monniaux/BearSSL/src/ssl/ssl_server_mine2c.c71
-rw-r--r--test/monniaux/BearSSL/src/ssl/ssl_server_mine2g.c71
-rw-r--r--test/monniaux/BearSSL/src/ssl/ssl_server_minf2c.c71
-rw-r--r--test/monniaux/BearSSL/src/ssl/ssl_server_minf2g.c71
-rw-r--r--test/monniaux/BearSSL/src/ssl/ssl_server_minr2g.c70
-rw-r--r--test/monniaux/BearSSL/src/ssl/ssl_server_minu2g.c70
-rw-r--r--test/monniaux/BearSSL/src/ssl/ssl_server_minv2g.c70
43 files changed, 13994 insertions, 0 deletions
diff --git a/test/monniaux/BearSSL/src/ssl/prf.c b/test/monniaux/BearSSL/src/ssl/prf.c
new file mode 100644
index 00000000..f04a5fb7
--- /dev/null
+++ b/test/monniaux/BearSSL/src/ssl/prf.c
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see inner.h */
+void
+br_tls_phash(void *dst, size_t len,
+ const br_hash_class *dig,
+ const void *secret, size_t secret_len, const char *label,
+ size_t seed_num, const br_tls_prf_seed_chunk *seed)
+{
+ unsigned char *buf;
+ unsigned char tmp[64], a[64];
+ br_hmac_key_context kc;
+ br_hmac_context hc;
+ size_t label_len, hlen, u;
+
+ if (len == 0) {
+ return;
+ }
+ buf = dst;
+ for (label_len = 0; label[label_len]; label_len ++);
+ hlen = br_digest_size(dig);
+ br_hmac_key_init(&kc, dig, secret, secret_len);
+ br_hmac_init(&hc, &kc, 0);
+ br_hmac_update(&hc, label, label_len);
+ for (u = 0; u < seed_num; u ++) {
+ br_hmac_update(&hc, seed[u].data, seed[u].len);
+ }
+ br_hmac_out(&hc, a);
+ for (;;) {
+ br_hmac_init(&hc, &kc, 0);
+ br_hmac_update(&hc, a, hlen);
+ br_hmac_update(&hc, label, label_len);
+ for (u = 0; u < seed_num; u ++) {
+ br_hmac_update(&hc, seed[u].data, seed[u].len);
+ }
+ br_hmac_out(&hc, tmp);
+ for (u = 0; u < hlen && u < len; u ++) {
+ buf[u] ^= tmp[u];
+ }
+ buf += u;
+ len -= u;
+ if (len == 0) {
+ return;
+ }
+ br_hmac_init(&hc, &kc, 0);
+ br_hmac_update(&hc, a, hlen);
+ br_hmac_out(&hc, a);
+ }
+}
diff --git a/test/monniaux/BearSSL/src/ssl/prf_md5sha1.c b/test/monniaux/BearSSL/src/ssl/prf_md5sha1.c
new file mode 100644
index 00000000..3212833a
--- /dev/null
+++ b/test/monniaux/BearSSL/src/ssl/prf_md5sha1.c
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl.h */
+void
+br_tls10_prf(void *dst, size_t len,
+ const void *secret, size_t secret_len, const char *label,
+ size_t seed_num, const br_tls_prf_seed_chunk *seed)
+{
+ const unsigned char *s1;
+ size_t slen;
+
+ s1 = secret;
+ slen = (secret_len + 1) >> 1;
+ memset(dst, 0, len);
+ br_tls_phash(dst, len, &br_md5_vtable,
+ s1, slen, label, seed_num, seed);
+ br_tls_phash(dst, len, &br_sha1_vtable,
+ s1 + secret_len - slen, slen, label, seed_num, seed);
+}
diff --git a/test/monniaux/BearSSL/src/ssl/prf_sha256.c b/test/monniaux/BearSSL/src/ssl/prf_sha256.c
new file mode 100644
index 00000000..76041de8
--- /dev/null
+++ b/test/monniaux/BearSSL/src/ssl/prf_sha256.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl.h */
+void
+br_tls12_sha256_prf(void *dst, size_t len,
+ const void *secret, size_t secret_len, const char *label,
+ size_t seed_num, const br_tls_prf_seed_chunk *seed)
+{
+ memset(dst, 0, len);
+ br_tls_phash(dst, len, &br_sha256_vtable,
+ secret, secret_len, label, seed_num, seed);
+}
diff --git a/test/monniaux/BearSSL/src/ssl/prf_sha384.c b/test/monniaux/BearSSL/src/ssl/prf_sha384.c
new file mode 100644
index 00000000..c20c4e65
--- /dev/null
+++ b/test/monniaux/BearSSL/src/ssl/prf_sha384.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl.h */
+void
+br_tls12_sha384_prf(void *dst, size_t len,
+ const void *secret, size_t secret_len, const char *label,
+ size_t seed_num, const br_tls_prf_seed_chunk *seed)
+{
+ memset(dst, 0, len);
+ br_tls_phash(dst, len, &br_sha384_vtable,
+ secret, secret_len, label, seed_num, seed);
+}
diff --git a/test/monniaux/BearSSL/src/ssl/ssl_ccert_single_ec.c b/test/monniaux/BearSSL/src/ssl/ssl_ccert_single_ec.c
new file mode 100644
index 00000000..93ebcde6
--- /dev/null
+++ b/test/monniaux/BearSSL/src/ssl/ssl_ccert_single_ec.c
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+static void
+cc_none0(const br_ssl_client_certificate_class **pctx)
+{
+ (void)pctx;
+}
+
+static void
+cc_none1(const br_ssl_client_certificate_class **pctx, size_t len)
+{
+ (void)pctx;
+ (void)len;
+}
+
+static void
+cc_none2(const br_ssl_client_certificate_class **pctx,
+ const unsigned char *data, size_t len)
+{
+ (void)pctx;
+ (void)data;
+ (void)len;
+}
+
+static void
+cc_choose(const br_ssl_client_certificate_class **pctx,
+ const br_ssl_client_context *cc, uint32_t auth_types,
+ br_ssl_client_certificate *choices)
+{
+ br_ssl_client_certificate_ec_context *zc;
+ int x;
+ int scurve;
+
+ zc = (br_ssl_client_certificate_ec_context *)pctx;
+ scurve = br_ssl_client_get_server_curve(cc);
+
+ if ((zc->allowed_usages & BR_KEYTYPE_KEYX) != 0
+ && scurve == zc->sk->curve)
+ {
+ int x;
+
+ x = (zc->issuer_key_type == BR_KEYTYPE_RSA) ? 16 : 17;
+ if (((auth_types >> x) & 1) != 0) {
+ choices->auth_type = BR_AUTH_ECDH;
+ choices->hash_id = -1;
+ choices->chain = zc->chain;
+ choices->chain_len = zc->chain_len;
+ }
+ }
+
+ /*
+ * For ECDSA authentication, we must choose an appropriate
+ * hash function.
+ */
+ x = br_ssl_choose_hash((unsigned)(auth_types >> 8));
+ if (x == 0 || (zc->allowed_usages & BR_KEYTYPE_SIGN) == 0) {
+ memset(choices, 0, sizeof *choices);
+ return;
+ }
+ choices->auth_type = BR_AUTH_ECDSA;
+ choices->hash_id = x;
+ choices->chain = zc->chain;
+ choices->chain_len = zc->chain_len;
+}
+
+static uint32_t
+cc_do_keyx(const br_ssl_client_certificate_class **pctx,
+ unsigned char *data, size_t *len)
+{
+ br_ssl_client_certificate_ec_context *zc;
+ uint32_t r;
+ size_t xoff, xlen;
+
+ zc = (br_ssl_client_certificate_ec_context *)pctx;
+ r = zc->iec->mul(data, *len, zc->sk->x, zc->sk->xlen, zc->sk->curve);
+ xoff = zc->iec->xoff(zc->sk->curve, &xlen);
+ memmove(data, data + xoff, xlen);
+ *len = xlen;
+ return r;
+}
+
+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/test/monniaux/BearSSL/src/ssl/ssl_ccert_single_rsa.c b/test/monniaux/BearSSL/src/ssl/ssl_ccert_single_rsa.c
new file mode 100644
index 00000000..690df20f
--- /dev/null
+++ b/test/monniaux/BearSSL/src/ssl/ssl_ccert_single_rsa.c
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+static void
+cc_none0(const br_ssl_client_certificate_class **pctx)
+{
+ (void)pctx;
+}
+
+static void
+cc_none1(const br_ssl_client_certificate_class **pctx, size_t len)
+{
+ (void)pctx;
+ (void)len;
+}
+
+static void
+cc_none2(const br_ssl_client_certificate_class **pctx,
+ const unsigned char *data, size_t len)
+{
+ (void)pctx;
+ (void)data;
+ (void)len;
+}
+
+static void
+cc_choose(const br_ssl_client_certificate_class **pctx,
+ const br_ssl_client_context *cc, uint32_t auth_types,
+ br_ssl_client_certificate *choices)
+{
+ br_ssl_client_certificate_rsa_context *zc;
+ int x;
+
+ (void)cc;
+ zc = (br_ssl_client_certificate_rsa_context *)pctx;
+ x = br_ssl_choose_hash((unsigned)auth_types);
+ if (x == 0 && (auth_types & 1) == 0) {
+ memset(choices, 0, sizeof *choices);
+ }
+ choices->auth_type = BR_AUTH_RSA;
+ choices->hash_id = x;
+ choices->chain = zc->chain;
+ choices->chain_len = zc->chain_len;
+}
+
+/*
+ * OID for hash functions in RSA signatures.
+ */
+static const unsigned char HASH_OID_SHA1[] = {
+ 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A
+};
+
+static const unsigned char HASH_OID_SHA224[] = {
+ 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04
+};
+
+static const unsigned char HASH_OID_SHA256[] = {
+ 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01
+};
+
+static const unsigned char HASH_OID_SHA384[] = {
+ 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02
+};
+
+static const unsigned char HASH_OID_SHA512[] = {
+ 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03
+};
+
+static const unsigned char *HASH_OID[] = {
+ HASH_OID_SHA1,
+ HASH_OID_SHA224,
+ HASH_OID_SHA256,
+ HASH_OID_SHA384,
+ HASH_OID_SHA512
+};
+
+static size_t
+cc_do_sign(const br_ssl_client_certificate_class **pctx,
+ int hash_id, size_t hv_len, unsigned char *data, size_t len)
+{
+ br_ssl_client_certificate_rsa_context *zc;
+ unsigned char hv[64];
+ const unsigned char *hash_oid;
+ size_t sig_len;
+
+ zc = (br_ssl_client_certificate_rsa_context *)pctx;
+ memcpy(hv, data, hv_len);
+ if (hash_id == 0) {
+ hash_oid = NULL;
+ } else if (hash_id >= 2 && hash_id <= 6) {
+ hash_oid = HASH_OID[hash_id - 2];
+ } else {
+ return 0;
+ }
+ sig_len = (zc->sk->n_bitlen + 7) >> 3;
+ if (len < sig_len) {
+ return 0;
+ }
+ return zc->irsasign(hash_oid, hv, hv_len, zc->sk, data) ? sig_len : 0;
+}
+
+static const br_ssl_client_certificate_class ccert_vtable = {
+ sizeof(br_ssl_client_certificate_rsa_context),
+ cc_none0, /* start_name_list */
+ cc_none1, /* start_name */
+ cc_none2, /* append_name */
+ cc_none0, /* end_name */
+ cc_none0, /* end_name_list */
+ cc_choose,
+ 0,
+ cc_do_sign
+};
+
+/* see bearssl_ssl.h */
+void
+br_ssl_client_set_single_rsa(br_ssl_client_context *cc,
+ const br_x509_certificate *chain, size_t chain_len,
+ const br_rsa_private_key *sk, br_rsa_pkcs1_sign irsasign)
+{
+ cc->client_auth.single_rsa.vtable = &ccert_vtable;
+ cc->client_auth.single_rsa.chain = chain;
+ cc->client_auth.single_rsa.chain_len = chain_len;
+ cc->client_auth.single_rsa.sk = sk;
+ cc->client_auth.single_rsa.irsasign = irsasign;
+ cc->client_auth_vtable = &cc->client_auth.single_rsa.vtable;
+}
diff --git a/test/monniaux/BearSSL/src/ssl/ssl_client.c b/test/monniaux/BearSSL/src/ssl/ssl_client.c
new file mode 100644
index 00000000..28c404b8
--- /dev/null
+++ b/test/monniaux/BearSSL/src/ssl/ssl_client.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_ssl.h */
+void
+br_ssl_client_zero(br_ssl_client_context *cc)
+{
+ /*
+ * For really standard C, we should explicitly set to NULL all
+ * pointers, and 0 all other fields. However, on all our target
+ * architectures, a direct memset() will work, be faster, and
+ * use a lot less code.
+ */
+ memset(cc, 0, sizeof *cc);
+}
+
+/* see bearssl_ssl.h */
+int
+br_ssl_client_reset(br_ssl_client_context *cc,
+ const char *server_name, int resume_session)
+{
+ size_t n;
+
+ br_ssl_engine_set_buffer(&cc->eng, NULL, 0, 0);
+ cc->eng.version_out = cc->eng.version_min;
+ if (!resume_session) {
+ br_ssl_client_forget_session(cc);
+ }
+ if (!br_ssl_engine_init_rand(&cc->eng)) {
+ return 0;
+ }
+
+ /*
+ * We always set back the "reneg" flag to 0 because we use it
+ * to distinguish between first handshake and renegotiation.
+ * Note that "renegotiation" and "session resumption" are two
+ * different things.
+ */
+ cc->eng.reneg = 0;
+
+ if (server_name == NULL) {
+ cc->eng.server_name[0] = 0;
+ } else {
+ n = strlen(server_name) + 1;
+ if (n > sizeof cc->eng.server_name) {
+ br_ssl_engine_fail(&cc->eng, BR_ERR_BAD_PARAM);
+ return 0;
+ }
+ memcpy(cc->eng.server_name, server_name, n);
+ }
+
+ br_ssl_engine_hs_reset(&cc->eng,
+ br_ssl_hs_client_init_main, br_ssl_hs_client_run);
+ return br_ssl_engine_last_error(&cc->eng) == BR_ERR_OK;
+}
diff --git a/test/monniaux/BearSSL/src/ssl/ssl_client_default_rsapub.c b/test/monniaux/BearSSL/src/ssl/ssl_client_default_rsapub.c
new file mode 100644
index 00000000..2cdaab89
--- /dev/null
+++ b/test/monniaux/BearSSL/src/ssl/ssl_client_default_rsapub.c
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_ssl.h */
+void
+br_ssl_client_set_default_rsapub(br_ssl_client_context *cc)
+{
+ br_ssl_client_set_rsapub(cc, br_rsa_public_get_default());
+}
diff --git a/test/monniaux/BearSSL/src/ssl/ssl_client_full.c b/test/monniaux/BearSSL/src/ssl/ssl_client_full.c
new file mode 100644
index 00000000..98143499
--- /dev/null
+++ b/test/monniaux/BearSSL/src/ssl/ssl_client_full.c
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_ssl.h */
+void
+br_ssl_client_init_full(br_ssl_client_context *cc,
+ br_x509_minimal_context *xc,
+ const br_x509_trust_anchor *trust_anchors, size_t trust_anchors_num)
+{
+ /*
+ * The "full" profile supports all implemented cipher suites.
+ *
+ * Rationale for suite order, from most important to least
+ * important rule:
+ *
+ * -- Don't use 3DES if AES or ChaCha20 is available.
+ * -- Try to have Forward Secrecy (ECDHE suite) if possible.
+ * -- When not using Forward Secrecy, ECDH key exchange is
+ * better than RSA key exchange (slightly more expensive on the
+ * client, but much cheaper on the server, and it implies smaller
+ * messages).
+ * -- ChaCha20+Poly1305 is better than AES/GCM (faster, smaller code).
+ * -- GCM is better than CCM and CBC. CCM is better than CBC.
+ * -- CCM is preferable over CCM_8 (with CCM_8, forgeries may succeed
+ * with probability 2^(-64)).
+ * -- AES-128 is preferred over AES-256 (AES-128 is already
+ * strong enough, and AES-256 is 40% more expensive).
+ */
+ static const uint16_t suites[] = {
+ BR_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
+ BR_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
+ BR_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ BR_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ BR_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+ BR_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+ BR_TLS_ECDHE_ECDSA_WITH_AES_128_CCM,
+ BR_TLS_ECDHE_ECDSA_WITH_AES_256_CCM,
+ BR_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8,
+ BR_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8,
+ BR_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
+ BR_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
+ BR_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
+ BR_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
+ BR_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
+ BR_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+ BR_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
+ BR_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+ BR_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256,
+ BR_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256,
+ BR_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384,
+ BR_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384,
+ BR_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256,
+ BR_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256,
+ BR_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384,
+ BR_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384,
+ BR_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
+ BR_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,
+ BR_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,
+ BR_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,
+ BR_TLS_RSA_WITH_AES_128_GCM_SHA256,
+ BR_TLS_RSA_WITH_AES_256_GCM_SHA384,
+ BR_TLS_RSA_WITH_AES_128_CCM,
+ BR_TLS_RSA_WITH_AES_256_CCM,
+ BR_TLS_RSA_WITH_AES_128_CCM_8,
+ BR_TLS_RSA_WITH_AES_256_CCM_8,
+ BR_TLS_RSA_WITH_AES_128_CBC_SHA256,
+ BR_TLS_RSA_WITH_AES_256_CBC_SHA256,
+ BR_TLS_RSA_WITH_AES_128_CBC_SHA,
+ BR_TLS_RSA_WITH_AES_256_CBC_SHA,
+ BR_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
+ BR_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
+ BR_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,
+ BR_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA,
+ BR_TLS_RSA_WITH_3DES_EDE_CBC_SHA
+ };
+
+ /*
+ * All hash functions are activated.
+ * Note: the X.509 validation engine will nonetheless refuse to
+ * validate signatures that use MD5 as hash function.
+ */
+ static const br_hash_class *hashes[] = {
+ &br_md5_vtable,
+ &br_sha1_vtable,
+ &br_sha224_vtable,
+ &br_sha256_vtable,
+ &br_sha384_vtable,
+ &br_sha512_vtable
+ };
+
+ int id;
+
+ /*
+ * Reset client context and set supported versions from TLS-1.0
+ * to TLS-1.2 (inclusive).
+ */
+ br_ssl_client_zero(cc);
+ br_ssl_engine_set_versions(&cc->eng, BR_TLS10, BR_TLS12);
+
+ /*
+ * X.509 engine uses SHA-256 to hash certificate DN (for
+ * comparisons).
+ */
+ br_x509_minimal_init(xc, &br_sha256_vtable,
+ trust_anchors, trust_anchors_num);
+
+ /*
+ * Set suites and asymmetric crypto implementations. We use the
+ * "i31" code for RSA (it is somewhat faster than the "i32"
+ * implementation).
+ * TODO: change that when better implementations are made available.
+ */
+ br_ssl_engine_set_suites(&cc->eng, suites,
+ (sizeof suites) / (sizeof suites[0]));
+ br_ssl_client_set_default_rsapub(cc);
+ br_ssl_engine_set_default_rsavrfy(&cc->eng);
+ br_ssl_engine_set_default_ecdsa(&cc->eng);
+ br_x509_minimal_set_rsa(xc, br_ssl_engine_get_rsavrfy(&cc->eng));
+ br_x509_minimal_set_ecdsa(xc,
+ br_ssl_engine_get_ec(&cc->eng),
+ br_ssl_engine_get_ecdsa(&cc->eng));
+
+ /*
+ * Set supported hash functions, for the SSL engine and for the
+ * X.509 engine.
+ */
+ for (id = br_md5_ID; id <= br_sha512_ID; id ++) {
+ const br_hash_class *hc;
+
+ hc = hashes[id - 1];
+ br_ssl_engine_set_hash(&cc->eng, id, hc);
+ br_x509_minimal_set_hash(xc, id, hc);
+ }
+
+ /*
+ * Link the X.509 engine in the SSL engine.
+ */
+ br_ssl_engine_set_x509(&cc->eng, &xc->vtable);
+
+ /*
+ * Set the PRF implementations.
+ */
+ br_ssl_engine_set_prf10(&cc->eng, &br_tls10_prf);
+ br_ssl_engine_set_prf_sha256(&cc->eng, &br_tls12_sha256_prf);
+ br_ssl_engine_set_prf_sha384(&cc->eng, &br_tls12_sha384_prf);
+
+ /*
+ * Symmetric encryption. We use the "default" implementations
+ * (fastest among constant-time implementations).
+ */
+ br_ssl_engine_set_default_aes_cbc(&cc->eng);
+ br_ssl_engine_set_default_aes_ccm(&cc->eng);
+ br_ssl_engine_set_default_aes_gcm(&cc->eng);
+ br_ssl_engine_set_default_des_cbc(&cc->eng);
+ br_ssl_engine_set_default_chapol(&cc->eng);
+}
diff --git a/test/monniaux/BearSSL/src/ssl/ssl_engine.c b/test/monniaux/BearSSL/src/ssl/ssl_engine.c
new file mode 100644
index 00000000..f4ffe185
--- /dev/null
+++ b/test/monniaux/BearSSL/src/ssl/ssl_engine.c
@@ -0,0 +1,1569 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+#if 0
+/* obsolete */
+
+/*
+ * If BR_USE_URANDOM is not defined, then try to autodetect its presence
+ * through compiler macros.
+ */
+#ifndef BR_USE_URANDOM
+
+/*
+ * Macro values documented on:
+ * https://sourceforge.net/p/predef/wiki/OperatingSystems/
+ *
+ * Only the most common systems have been included here for now. This
+ * should be enriched later on.
+ */
+#if defined _AIX \
+ || defined __ANDROID__ \
+ || defined __FreeBSD__ \
+ || defined __NetBSD__ \
+ || defined __OpenBSD__ \
+ || defined __DragonFly__ \
+ || defined __linux__ \
+ || (defined __sun && (defined __SVR4 || defined __svr4__)) \
+ || (defined __APPLE__ && defined __MACH__)
+#define BR_USE_URANDOM 1
+#endif
+
+#endif
+
+/*
+ * If BR_USE_WIN32_RAND is not defined, perform autodetection here.
+ */
+#ifndef BR_USE_WIN32_RAND
+
+#if defined _WIN32 || defined _WIN64
+#define BR_USE_WIN32_RAND 1
+#endif
+
+#endif
+
+#if BR_USE_URANDOM
+#include <sys/types.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#endif
+
+#if BR_USE_WIN32_RAND
+#include <windows.h>
+#include <wincrypt.h>
+#pragma comment(lib, "advapi32")
+#endif
+
+#endif
+
+/* ==================================================================== */
+/*
+ * This part of the file does the low-level record management.
+ */
+
+/*
+ * IMPLEMENTATION NOTES
+ * ====================
+ *
+ * In this file, we designate by "input" (and the "i" letter) the "recv"
+ * operations: incoming records from the peer, from which payload data
+ * is obtained, and must be extracted by the application (or the SSL
+ * handshake engine). Similarly, "output" (and the "o" letter) is for
+ * "send": payload data injected by the application (and SSL handshake
+ * engine), to be wrapped into records, that are then conveyed to the
+ * peer over the transport medium.
+ *
+ * The input and output buffers may be distinct or shared. When
+ * shared, input and output cannot occur concurrently; the caller
+ * must make sure that it never needs to output data while input
+ * data has been received. In practice, a shared buffer prevents
+ * pipelining of HTTP requests, or similar protocols; however, a
+ * shared buffer saves RAM.
+ *
+ * The input buffer is pointed to by 'ibuf' and has size 'ibuf_len';
+ * the output buffer is pointed to by 'obuf' and has size 'obuf_len'.
+ * From the size of these buffers is derived the maximum fragment
+ * length, which will be honoured upon sending records; regardless of
+ * that length, incoming records will be processed as long as they
+ * fit in the input buffer, and their length still complies with the
+ * protocol specification (maximum plaintext payload length is 16384
+ * bytes).
+ *
+ * Three registers are used to manage buffering in ibuf, called ixa,
+ * ixb and ixc. Similarly, three registers are used to manage buffering
+ * in obuf, called oxa, oxb and oxc.
+ *
+ *
+ * At any time, the engine is in one of the following modes:
+ * -- Failed mode: an error occurs, no I/O can happen.
+ * -- Input mode: the engine can either receive record bytes from the
+ * transport layer, or it has some buffered payload bytes to yield.
+ * -- Output mode: the engine can either receive payload bytes, or it
+ * has some record bytes to send to the transport layer.
+ * -- Input/Output mode: both input and output modes are active. When
+ * the buffer is shared, this can happen only when the buffer is empty
+ * (no buffered payload bytes or record bytes in either direction).
+ *
+ *
+ * Failed mode:
+ * ------------
+ *
+ * I/O failed for some reason (invalid received data, not enough room
+ * for the next record...). No I/O may ever occur again for this context,
+ * until an explicit reset is performed. This mode, and the error code,
+ * are also used for protocol errors, especially handshake errors.
+ *
+ *
+ * Input mode:
+ * -----------
+ *
+ * ixa index within ibuf[] for the currently read data
+ * ixb maximum index within ibuf[] for the currently read data
+ * ixc number of bytes not yet received for the current record
+ *
+ * -- When ixa == ixb, there is no available data for readers. When
+ * ixa != ixb, there is available data and it starts at offset ixa.
+ *
+ * -- When waiting for the next record header, ixa and ixb are equal
+ * and contain a value ranging from 0 to 4; ixc is equal to 5-ixa.
+ *
+ * -- When the header has been received, record data is obtained. The
+ * ixc field records how many bytes are still needed to reach the
+ * end of the current record.
+ *
+ * ** If encryption is active, then ixa and ixb are kept equal, and
+ * point to the end of the currently received record bytes. When
+ * ixc reaches 0, decryption/MAC is applied, and ixa and ixb are
+ * adjusted.
+ *
+ * ** If encryption is not active, then ixa and ixb are distinct
+ * and data can be read right away. Additional record data is
+ * obtained only when ixa == ixb.
+ *
+ * Note: in input mode and no encryption, records larger than the buffer
+ * size are allowed. When encryption is active, the complete record must
+ * fit within the buffer, since it cannot be decrypted/MACed until it
+ * has been completely received.
+ *
+ * -- When receiving the next record header, 'version_in' contains the
+ * expected input version (0 if not expecting a specific version); on
+ * mismatch, the mode switches to 'failed'.
+ *
+ * -- When the header has been received, 'version_in' contains the received
+ * version. It is up to the caller to check and adjust the 'version_in' field
+ * to implement the required semantics.
+ *
+ * -- The 'record_type_in' field is updated with the incoming record type
+ * when the next record header has been received.
+ *
+ *
+ * Output mode:
+ * ------------
+ *
+ * oxa index within obuf[] for the currently accumulated data
+ * oxb maximum index within obuf[] for record data
+ * oxc pointer for start of record data, and for record sending
+ *
+ * -- When oxa != oxb, more data can be accumulated into the current
+ * record; when oxa == oxb, a closed record is being sent.
+ *
+ * -- When accumulating data, oxc points to the start of the data.
+ *
+ * -- During record sending, oxa (and oxb) point to the next record byte
+ * to send, and oxc indicates the end of the current record.
+ *
+ * Note: sent records must fit within the buffer, since the header is
+ * adjusted only when the complete record has been assembled.
+ *
+ * -- The 'version_out' and 'record_type_out' fields are used to build the
+ * record header when the mode is switched to 'sending'.
+ *
+ *
+ * Modes:
+ * ------
+ *
+ * The state register iomode contains one of the following values:
+ *
+ * BR_IO_FAILED I/O failed
+ * BR_IO_IN input mode
+ * BR_IO_OUT output mode
+ * BR_IO_INOUT input/output mode
+ *
+ * Whether encryption is active on incoming records is indicated by the
+ * incrypt flag. For outgoing records, there is no such flag; "encryption"
+ * is always considered active, but initially uses functions that do not
+ * encrypt anything. The 'incrypt' flag is needed because when there is
+ * no active encryption, records larger than the I/O buffer are accepted.
+ *
+ * Note: we do not support no-encryption modes (MAC only).
+ *
+ * TODO: implement GCM support
+ *
+ *
+ * Misc:
+ * -----
+ *
+ * 'max_frag_len' is the maximum plaintext size for an outgoing record.
+ * By default, it is set to the maximum value that fits in the provided
+ * buffers, in the following list: 512, 1024, 2048, 4096, 16384. The
+ * caller may change it if needed, but the new value MUST still fit in
+ * the buffers, and it MUST be one of the list above for compatibility
+ * with the Maximum Fragment Length extension.
+ *
+ * For incoming records, only the total buffer length and current
+ * encryption mode impact the maximum length for incoming records. The
+ * 'max_frag_len' value is still adjusted so that records up to that
+ * length can be both received and sent.
+ *
+ *
+ * Offsets and lengths:
+ * --------------------
+ *
+ * When sending fragments with TLS-1.1+, the maximum overhead is:
+ * 5 bytes for the record header
+ * 16 bytes for the explicit IV
+ * 48 bytes for the MAC (HMAC/SHA-384)
+ * 16 bytes for the padding (AES)
+ * so a total of 85 extra bytes. Note that we support block cipher sizes
+ * up to 16 bytes (AES) and HMAC output sizes up to 48 bytes (SHA-384).
+ *
+ * With TLS-1.0 and CBC mode, we apply a 1/n-1 split, for a maximum
+ * overhead of:
+ * 5 bytes for the first record header
+ * 32 bytes for the first record payload (AES-CBC + HMAC/SHA-1)
+ * 5 bytes for the second record header
+ * 20 bytes for the MAC (HMAC/SHA-1)
+ * 16 bytes for the padding (AES)
+ * -1 byte to account for the payload byte in the first record
+ * so a total of 77 extra bytes at most, less than the 85 bytes above.
+ * Note that with TLS-1.0, the MAC is HMAC with either MD5 or SHA-1, but
+ * no other hash function.
+ *
+ * The implementation does not try to send larger records when the current
+ * encryption mode has less overhead.
+ *
+ * Maximum input record overhead is:
+ * 5 bytes for the record header
+ * 16 bytes for the explicit IV (TLS-1.1+)
+ * 48 bytes for the MAC (HMAC/SHA-384)
+ * 256 bytes for the padding
+ * so a total of 325 extra bytes.
+ *
+ * When receiving the next record header, it is written into the buffer
+ * bytes 0 to 4 (inclusive). Record data is always written into buf[]
+ * starting at offset 5. When encryption is active, the plaintext data
+ * may start at a larger offset (e.g. because of an explicit IV).
+ */
+
+#define MAX_OUT_OVERHEAD 85
+#define MAX_IN_OVERHEAD 325
+
+/* see inner.h */
+void
+br_ssl_engine_fail(br_ssl_engine_context *rc, int err)
+{
+ if (rc->iomode != BR_IO_FAILED) {
+ rc->iomode = BR_IO_FAILED;
+ rc->err = err;
+ }
+}
+
+/*
+ * Adjust registers for a new incoming record.
+ */
+static void
+make_ready_in(br_ssl_engine_context *rc)
+{
+ rc->ixa = rc->ixb = 0;
+ rc->ixc = 5;
+ if (rc->iomode == BR_IO_IN) {
+ rc->iomode = BR_IO_INOUT;
+ }
+}
+
+/*
+ * Adjust registers for a new outgoing record.
+ */
+static void
+make_ready_out(br_ssl_engine_context *rc)
+{
+ size_t a, b;
+
+ a = 5;
+ b = rc->obuf_len - a;
+ rc->out.vtable->max_plaintext(&rc->out.vtable, &a, &b);
+ if ((b - a) > rc->max_frag_len) {
+ b = a + rc->max_frag_len;
+ }
+ rc->oxa = a;
+ rc->oxb = b;
+ rc->oxc = a;
+ if (rc->iomode == BR_IO_OUT) {
+ rc->iomode = BR_IO_INOUT;
+ }
+}
+
+/* see inner.h */
+void
+br_ssl_engine_new_max_frag_len(br_ssl_engine_context *rc, unsigned max_frag_len)
+{
+ size_t nxb;
+
+ rc->max_frag_len = max_frag_len;
+ nxb = rc->oxc + max_frag_len;
+ if (rc->oxa < rc->oxb && rc->oxb > nxb && rc->oxa < nxb) {
+ rc->oxb = nxb;
+ }
+}
+
+/* see bearssl_ssl.h */
+void
+br_ssl_engine_set_buffer(br_ssl_engine_context *rc,
+ void *buf, size_t buf_len, int bidi)
+{
+ if (buf == NULL) {
+ br_ssl_engine_set_buffers_bidi(rc, NULL, 0, NULL, 0);
+ } else {
+ /*
+ * In bidirectional mode, we want to maximise input
+ * buffer size, since we support arbitrary fragmentation
+ * when sending, but the peer will not necessarily
+ * comply to any low fragment length (in particular if
+ * we are the server, because the maximum fragment
+ * length extension is under client control).
+ *
+ * We keep a minimum size of 512 bytes for the plaintext
+ * of our outgoing records.
+ *
+ * br_ssl_engine_set_buffers_bidi() will compute the maximum
+ * fragment length for outgoing records by using the minimum
+ * of allocated spaces for both input and output records,
+ * rounded down to a standard length.
+ */
+ if (bidi) {
+ size_t w;
+
+ if (buf_len < (512 + MAX_IN_OVERHEAD
+ + 512 + MAX_OUT_OVERHEAD))
+ {
+ rc->iomode = BR_IO_FAILED;
+ rc->err = BR_ERR_BAD_PARAM;
+ return;
+ } else if (buf_len < (16384 + MAX_IN_OVERHEAD
+ + 512 + MAX_OUT_OVERHEAD))
+ {
+ w = 512 + MAX_OUT_OVERHEAD;
+ } else {
+ w = buf_len - (16384 + MAX_IN_OVERHEAD);
+ }
+ br_ssl_engine_set_buffers_bidi(rc,
+ buf, buf_len - w,
+ (unsigned char *)buf + w, w);
+ } else {
+ br_ssl_engine_set_buffers_bidi(rc,
+ buf, buf_len, NULL, 0);
+ }
+ }
+}
+
+/* see bearssl_ssl.h */
+void
+br_ssl_engine_set_buffers_bidi(br_ssl_engine_context *rc,
+ void *ibuf, size_t ibuf_len, void *obuf, size_t obuf_len)
+{
+ rc->iomode = BR_IO_INOUT;
+ rc->incrypt = 0;
+ rc->err = BR_ERR_OK;
+ rc->version_in = 0;
+ rc->record_type_in = 0;
+ rc->version_out = 0;
+ rc->record_type_out = 0;
+ if (ibuf == NULL) {
+ if (rc->ibuf == NULL) {
+ br_ssl_engine_fail(rc, BR_ERR_BAD_PARAM);
+ }
+ } else {
+ unsigned u;
+
+ rc->ibuf = ibuf;
+ rc->ibuf_len = ibuf_len;
+ if (obuf == NULL) {
+ obuf = ibuf;
+ obuf_len = ibuf_len;
+ }
+ rc->obuf = obuf;
+ rc->obuf_len = obuf_len;
+
+ /*
+ * Compute the maximum fragment length, that fits for
+ * both incoming and outgoing records. This length will
+ * be used in fragment length negotiation, so we must
+ * honour it both ways. Regardless, larger incoming
+ * records will be accepted, as long as they fit in the
+ * actual buffer size.
+ */
+ for (u = 14; u >= 9; u --) {
+ size_t flen;
+
+ flen = (size_t)1 << u;
+ if (obuf_len >= flen + MAX_OUT_OVERHEAD
+ && ibuf_len >= flen + MAX_IN_OVERHEAD)
+ {
+ break;
+ }
+ }
+ if (u == 8) {
+ br_ssl_engine_fail(rc, BR_ERR_BAD_PARAM);
+ return;
+ } else if (u == 13) {
+ u = 12;
+ }
+ rc->max_frag_len = (size_t)1 << u;
+ rc->log_max_frag_len = u;
+ rc->peer_log_max_frag_len = 0;
+ }
+ rc->out.vtable = &br_sslrec_out_clear_vtable;
+ make_ready_in(rc);
+ make_ready_out(rc);
+}
+
+/*
+ * Clear buffers in both directions.
+ */
+static void
+engine_clearbuf(br_ssl_engine_context *rc)
+{
+ make_ready_in(rc);
+ make_ready_out(rc);
+}
+
+/*
+ * Make sure the internal PRNG is initialised (but not necessarily
+ * seeded properly yet).
+ */
+static int
+rng_init(br_ssl_engine_context *cc)
+{
+ const br_hash_class *h;
+
+ if (cc->rng_init_done != 0) {
+ return 1;
+ }
+
+ /*
+ * If using TLS-1.2, then SHA-256 or SHA-384 must be present (or
+ * both); we prefer SHA-256 which is faster for 32-bit systems.
+ *
+ * If using TLS-1.0 or 1.1 then SHA-1 must be present.
+ *
+ * Though HMAC_DRBG/SHA-1 is, as far as we know, as safe as
+ * these things can be, we still prefer the SHA-2 functions over
+ * SHA-1, if only for public relations (known theoretical
+ * weaknesses of SHA-1 with regards to collisions are mostly
+ * irrelevant here, but they still make people nervous).
+ */
+ h = br_multihash_getimpl(&cc->mhash, br_sha256_ID);
+ if (!h) {
+ h = br_multihash_getimpl(&cc->mhash, br_sha384_ID);
+ if (!h) {
+ h = br_multihash_getimpl(&cc->mhash,
+ br_sha1_ID);
+ if (!h) {
+ br_ssl_engine_fail(cc, BR_ERR_BAD_STATE);
+ return 0;
+ }
+ }
+ }
+ br_hmac_drbg_init(&cc->rng, h, NULL, 0);
+ cc->rng_init_done = 1;
+ return 1;
+}
+
+/* see inner.h */
+int
+br_ssl_engine_init_rand(br_ssl_engine_context *cc)
+{
+ if (!rng_init(cc)) {
+ return 0;
+ }
+
+ /*
+ * We always try OS/hardware seeding once. If it works, then
+ * we assume proper seeding. If not, then external entropy must
+ * have been injected; otherwise, we report an error.
+ */
+ if (!cc->rng_os_rand_done) {
+ br_prng_seeder sd;
+
+ sd = br_prng_seeder_system(NULL);
+ if (sd != 0 && sd(&cc->rng.vtable)) {
+ cc->rng_init_done = 2;
+ }
+ cc->rng_os_rand_done = 1;
+ }
+ if (cc->rng_init_done < 2) {
+ br_ssl_engine_fail(cc, BR_ERR_NO_RANDOM);
+ return 0;
+ }
+ return 1;
+}
+
+/* see bearssl_ssl.h */
+void
+br_ssl_engine_inject_entropy(br_ssl_engine_context *cc,
+ const void *data, size_t len)
+{
+ /*
+ * Externally provided entropy is assumed to be "good enough"
+ * (we cannot really test its quality) so if the RNG structure
+ * could be initialised at all, then we marked the RNG as
+ * "properly seeded".
+ */
+ if (!rng_init(cc)) {
+ return;
+ }
+ br_hmac_drbg_update(&cc->rng, data, len);
+ cc->rng_init_done = 2;
+}
+
+/*
+ * We define a few internal functions that implement the low-level engine
+ * API for I/O; the external API (br_ssl_engine_sendapp_buf() and similar
+ * functions) is built upon these function, with special processing for
+ * records which are not of type "application data".
+ *
+ * recvrec_buf, recvrec_ack receives bytes from transport medium
+ * sendrec_buf, sendrec_ack send bytes to transport medium
+ * recvpld_buf, recvpld_ack receives payload data from engine
+ * sendpld_buf, sendpld_ack send payload data to engine
+ */
+
+static unsigned char *
+recvrec_buf(const br_ssl_engine_context *rc, size_t *len)
+{
+ if (rc->shutdown_recv) {
+ *len = 0;
+ return NULL;
+ }
+
+ /*
+ * Bytes from the transport can be injected only if the mode is
+ * compatible (in or in/out), and ixa == ixb; ixc then contains
+ * the number of bytes that are still expected (but it may
+ * exceed our buffer size).
+ *
+ * We cannot get "stuck" here (buffer is full, but still more
+ * data is expected) because oversized records are detected when
+ * their header is processed.
+ */
+ switch (rc->iomode) {
+ case BR_IO_IN:
+ case BR_IO_INOUT:
+ if (rc->ixa == rc->ixb) {
+ size_t z;
+
+ z = rc->ixc;
+ if (z > rc->ibuf_len - rc->ixa) {
+ z = rc->ibuf_len - rc->ixa;
+ }
+ *len = z;
+ return rc->ibuf + rc->ixa;
+ }
+ break;
+ }
+ *len = 0;
+ return NULL;
+}
+
+static void
+recvrec_ack(br_ssl_engine_context *rc, size_t len)
+{
+ unsigned char *pbuf;
+ size_t pbuf_len;
+
+ /*
+ * Adjust state if necessary (for a shared input/output buffer):
+ * we got some incoming bytes, so we cannot (temporarily) handle
+ * outgoing data.
+ */
+ if (rc->iomode == BR_IO_INOUT && rc->ibuf == rc->obuf) {
+ rc->iomode = BR_IO_IN;
+ }
+
+ /*
+ * Adjust data pointers.
+ */
+ rc->ixb = (rc->ixa += len);
+ rc->ixc -= len;
+
+ /*
+ * If we are receiving a header and did not fully obtained it
+ * yet, then just wait for the next bytes.
+ */
+ if (rc->ixa < 5) {
+ return;
+ }
+
+ /*
+ * If we just obtained a full header, process it.
+ */
+ if (rc->ixa == 5) {
+ unsigned version;
+ unsigned rlen;
+
+ /*
+ * Get record type and version. We support only versions
+ * 3.x (if the version major number does not match, then
+ * we suppose that the record format is too alien for us
+ * to process it).
+ *
+ * Note: right now, we reject clients that try to send
+ * a ClientHello in a format compatible with SSL-2.0. It
+ * is unclear whether this will ever be supported; and
+ * if we want to support it, then this might be done in
+ * in the server-specific code, not here.
+ */
+ rc->record_type_in = rc->ibuf[0];
+ version = br_dec16be(rc->ibuf + 1);
+ if ((version >> 8) != 3) {
+ br_ssl_engine_fail(rc, BR_ERR_UNSUPPORTED_VERSION);
+ return;
+ }
+
+ /*
+ * We ensure that successive records have the same
+ * version. The handshake code must check and adjust the
+ * variables when necessary to accommodate the protocol
+ * negotiation details.
+ */
+ if (rc->version_in != 0 && rc->version_in != version) {
+ br_ssl_engine_fail(rc, BR_ERR_BAD_VERSION);
+ return;
+ }
+ rc->version_in = version;
+
+ /*
+ * Decode record length. We must check that the length
+ * is valid (relatively to the current encryption mode)
+ * and also (if encryption is active) that the record
+ * will fit in our buffer.
+ *
+ * When no encryption is active, we can process records
+ * by chunks, and thus accept any record up to the
+ * maximum allowed plaintext length (16384 bytes).
+ */
+ rlen = br_dec16be(rc->ibuf + 3);
+ if (rc->incrypt) {
+ if (!rc->in.vtable->check_length(
+ &rc->in.vtable, rlen))
+ {
+ br_ssl_engine_fail(rc, BR_ERR_BAD_LENGTH);
+ return;
+ }
+ if (rlen > (rc->ibuf_len - 5)) {
+ br_ssl_engine_fail(rc, BR_ERR_TOO_LARGE);
+ return;
+ }
+ } else {
+ if (rlen > 16384) {
+ br_ssl_engine_fail(rc, BR_ERR_BAD_LENGTH);
+ return;
+ }
+ }
+
+ /*
+ * If the record is completely empty then we must switch
+ * to a new record. Note that, in that case, we
+ * completely ignore the record type, which is fitting
+ * since we received no actual data of that type.
+ *
+ * A completely empty record is technically allowed as
+ * long as encryption/MAC is not active, i.e. before
+ * completion of the first handshake. It it still weird;
+ * it might conceptually be useful as a heartbeat or
+ * keep-alive mechanism while some lengthy operation is
+ * going on, e.g. interaction with a human user.
+ */
+ if (rlen == 0) {
+ make_ready_in(rc);
+ } else {
+ rc->ixa = rc->ixb = 5;
+ rc->ixc = rlen;
+ }
+ return;
+ }
+
+ /*
+ * If there is no active encryption, then the data can be read
+ * right away. Note that we do not receive bytes from the
+ * transport medium when we still have payload bytes to be
+ * acknowledged.
+ */
+ if (!rc->incrypt) {
+ rc->ixa = 5;
+ return;
+ }
+
+ /*
+ * Since encryption is active, we must wait for a full record
+ * before processing it.
+ */
+ if (rc->ixc != 0) {
+ return;
+ }
+
+ /*
+ * We got the full record. Decrypt it.
+ */
+ pbuf_len = rc->ixa - 5;
+ pbuf = rc->in.vtable->decrypt(&rc->in.vtable,
+ rc->record_type_in, rc->version_in, rc->ibuf + 5, &pbuf_len);
+ if (pbuf == 0) {
+ br_ssl_engine_fail(rc, BR_ERR_BAD_MAC);
+ return;
+ }
+ rc->ixa = (size_t)(pbuf - rc->ibuf);
+ rc->ixb = rc->ixa + pbuf_len;
+
+ /*
+ * Decryption may have yielded an empty record, in which case
+ * we get back to "ready" state immediately.
+ */
+ if (rc->ixa == rc->ixb) {
+ make_ready_in(rc);
+ }
+}
+
+/* see inner.h */
+int
+br_ssl_engine_recvrec_finished(const br_ssl_engine_context *rc)
+{
+ switch (rc->iomode) {
+ case BR_IO_IN:
+ case BR_IO_INOUT:
+ return rc->ixc == 0 || rc->ixa < 5;
+ default:
+ return 1;
+ }
+}
+
+static unsigned char *
+recvpld_buf(const br_ssl_engine_context *rc, size_t *len)
+{
+ /*
+ * There is payload data to be read only if the mode is
+ * compatible, and ixa != ixb.
+ */
+ switch (rc->iomode) {
+ case BR_IO_IN:
+ case BR_IO_INOUT:
+ *len = rc->ixb - rc->ixa;
+ return (*len == 0) ? NULL : (rc->ibuf + rc->ixa);
+ default:
+ *len = 0;
+ return NULL;
+ }
+}
+
+static void
+recvpld_ack(br_ssl_engine_context *rc, size_t len)
+{
+ rc->ixa += len;
+
+ /*
+ * If we read all the available data, then we either expect
+ * the remainder of the current record (if the current record
+ * was not finished; this may happen when encryption is not
+ * active), or go to "ready" state.
+ */
+ if (rc->ixa == rc->ixb) {
+ if (rc->ixc == 0) {
+ make_ready_in(rc);
+ } else {
+ rc->ixa = rc->ixb = 5;
+ }
+ }
+}
+
+static unsigned char *
+sendpld_buf(const br_ssl_engine_context *rc, size_t *len)
+{
+ /*
+ * Payload data can be injected only if the current mode is
+ * compatible, and oxa != oxb.
+ */
+ switch (rc->iomode) {
+ case BR_IO_OUT:
+ case BR_IO_INOUT:
+ *len = rc->oxb - rc->oxa;
+ return (*len == 0) ? NULL : (rc->obuf + rc->oxa);
+ default:
+ *len = 0;
+ return NULL;
+ }
+}
+
+/*
+ * If some payload bytes have been accumulated, then wrap them into
+ * an outgoing record. Otherwise, this function does nothing, unless
+ * 'force' is non-zero, in which case an empty record is assembled.
+ *
+ * The caller must take care not to invoke this function if the engine
+ * is not currently ready to receive payload bytes to send.
+ */
+static void
+sendpld_flush(br_ssl_engine_context *rc, int force)
+{
+ size_t xlen;
+ unsigned char *buf;
+
+ if (rc->oxa == rc->oxb) {
+ return;
+ }
+ xlen = rc->oxa - rc->oxc;
+ if (xlen == 0 && !force) {
+ return;
+ }
+ buf = rc->out.vtable->encrypt(&rc->out.vtable,
+ rc->record_type_out, rc->version_out,
+ rc->obuf + rc->oxc, &xlen);
+ rc->oxb = rc->oxa = (size_t)(buf - rc->obuf);
+ rc->oxc = rc->oxa + xlen;
+}
+
+static void
+sendpld_ack(br_ssl_engine_context *rc, size_t len)
+{
+ /*
+ * If using a shared buffer, then we may have to modify the
+ * current mode.
+ */
+ if (rc->iomode == BR_IO_INOUT && rc->ibuf == rc->obuf) {
+ rc->iomode = BR_IO_OUT;
+ }
+ rc->oxa += len;
+ if (rc->oxa >= rc->oxb) {
+ /*
+ * Set oxb to one more than oxa so that sendpld_flush()
+ * does not mistakingly believe that a record is
+ * already prepared and being sent.
+ */
+ rc->oxb = rc->oxa + 1;
+ sendpld_flush(rc, 0);
+ }
+}
+
+static unsigned char *
+sendrec_buf(const br_ssl_engine_context *rc, size_t *len)
+{
+ /*
+ * When still gathering payload bytes, oxc points to the start
+ * of the record data, so oxc <= oxa. However, when a full
+ * record has been completed, oxc points to the end of the record,
+ * so oxc > oxa.
+ */
+ switch (rc->iomode) {
+ case BR_IO_OUT:
+ case BR_IO_INOUT:
+ if (rc->oxc > rc->oxa) {
+ *len = rc->oxc - rc->oxa;
+ return rc->obuf + rc->oxa;
+ }
+ break;
+ }
+ *len = 0;
+ return NULL;
+}
+
+static void
+sendrec_ack(br_ssl_engine_context *rc, size_t len)
+{
+ rc->oxb = (rc->oxa += len);
+ if (rc->oxa == rc->oxc) {
+ make_ready_out(rc);
+ }
+}
+
+/*
+ * Test whether there is some buffered outgoing record that still must
+ * sent.
+ */
+static inline int
+has_rec_tosend(const br_ssl_engine_context *rc)
+{
+ return rc->oxa == rc->oxb && rc->oxa != rc->oxc;
+}
+
+/*
+ * The "no encryption" mode has no overhead. It limits the payload size
+ * to the maximum size allowed by the standard (16384 bytes); the caller
+ * is responsible for possibly enforcing a smaller fragment length.
+ */
+static void
+clear_max_plaintext(const br_sslrec_out_clear_context *cc,
+ size_t *start, size_t *end)
+{
+ size_t len;
+
+ (void)cc;
+ len = *end - *start;
+ if (len > 16384) {
+ *end = *start + 16384;
+ }
+}
+
+/*
+ * In "no encryption" mode, encryption is trivial (a no-operation) so
+ * we just have to encode the header.
+ */
+static unsigned char *
+clear_encrypt(br_sslrec_out_clear_context *cc,
+ int record_type, unsigned version, void *data, size_t *data_len)
+{
+ unsigned char *buf;
+
+ (void)cc;
+ buf = (unsigned char *)data - 5;
+ buf[0] = record_type;
+ br_enc16be(buf + 1, version);
+ br_enc16be(buf + 3, *data_len);
+ *data_len += 5;
+ return buf;
+}
+
+/* see bearssl_ssl.h */
+const br_sslrec_out_class br_sslrec_out_clear_vtable = {
+ sizeof(br_sslrec_out_clear_context),
+ (void (*)(const br_sslrec_out_class *const *, size_t *, size_t *))
+ &clear_max_plaintext,
+ (unsigned char *(*)(const br_sslrec_out_class **,
+ int, unsigned, void *, size_t *))
+ &clear_encrypt
+};
+
+/* ==================================================================== */
+/*
+ * In this part of the file, we handle the various record types, and
+ * communications with the handshake processor.
+ */
+
+/*
+ * IMPLEMENTATION NOTES
+ * ====================
+ *
+ * The handshake processor is written in T0 and runs as a coroutine.
+ * It receives the contents of all records except application data, and
+ * is responsible for producing the contents of all records except
+ * application data.
+ *
+ * A state flag is maintained, which specifies whether application data
+ * is acceptable or not. When it is set:
+ *
+ * -- Application data can be injected as payload data (provided that
+ * the output buffer is ready for that).
+ *
+ * -- Incoming application data records are accepted, and yield data
+ * that the caller may retrieve.
+ *
+ * When the flag is cleared, application data is not accepted from the
+ * application, and incoming application data records trigger an error.
+ *
+ *
+ * Records of type handshake, alert or change-cipher-spec are handled
+ * by the handshake processor. The handshake processor is written in T0
+ * and runs as a coroutine; it gets invoked whenever one of the following
+ * situations is reached:
+ *
+ * -- An incoming record has type handshake, alert or change-cipher-spec,
+ * and yields data that can be read (zero-length records are thus
+ * ignored).
+ *
+ * -- An outgoing record has just finished being sent, and the "application
+ * data" flag is cleared.
+ *
+ * -- The caller wishes to perform a close (call to br_ssl_engine_close()).
+ *
+ * -- The caller wishes to perform a renegotiation (call to
+ * br_ssl_engine_renegotiate()).
+ *
+ * Whenever the handshake processor is entered, access to the payload
+ * buffers is provided, along with some information about explicit
+ * closures or renegotiations.
+ */
+
+/* see bearssl_ssl.h */
+void
+br_ssl_engine_set_suites(br_ssl_engine_context *cc,
+ const uint16_t *suites, size_t suites_num)
+{
+ if ((suites_num * sizeof *suites) > sizeof cc->suites_buf) {
+ br_ssl_engine_fail(cc, BR_ERR_BAD_PARAM);
+ return;
+ }
+ memcpy(cc->suites_buf, suites, suites_num * sizeof *suites);
+ cc->suites_num = suites_num;
+}
+
+/*
+ * Give control to handshake processor. 'action' is 1 for a close,
+ * 2 for a renegotiation, or 0 for a jump due to I/O completion.
+ */
+static void
+jump_handshake(br_ssl_engine_context *cc, int action)
+{
+ /*
+ * We use a loop because the handshake processor actions may
+ * allow for more actions; namely, if the processor reads all
+ * input data, then it may allow for output data to be produced,
+ * in case of a shared in/out buffer.
+ */
+ for (;;) {
+ size_t hlen_in, hlen_out;
+
+ /*
+ * Get input buffer. We do not want to provide
+ * application data to the handshake processor (we could
+ * get called with an explicit close or renegotiation
+ * while there is application data ready to be read).
+ */
+ cc->hbuf_in = recvpld_buf(cc, &hlen_in);
+ if (cc->hbuf_in != NULL
+ && cc->record_type_in == BR_SSL_APPLICATION_DATA)
+ {
+ hlen_in = 0;
+ }
+
+ /*
+ * Get output buffer. The handshake processor never
+ * leaves an unfinished outgoing record, so if there is
+ * buffered output, then it MUST be some application
+ * data, so the processor cannot write to it.
+ */
+ cc->saved_hbuf_out = cc->hbuf_out = sendpld_buf(cc, &hlen_out);
+ if (cc->hbuf_out != NULL && br_ssl_engine_has_pld_to_send(cc)) {
+ hlen_out = 0;
+ }
+
+ /*
+ * Note: hlen_in and hlen_out can be both non-zero only if
+ * the input and output buffers are disjoint. Thus, we can
+ * offer both buffers to the handshake code.
+ */
+
+ cc->hlen_in = hlen_in;
+ cc->hlen_out = hlen_out;
+ cc->action = action;
+ cc->hsrun(&cc->cpu);
+ if (br_ssl_engine_closed(cc)) {
+ return;
+ }
+ if (cc->hbuf_out != cc->saved_hbuf_out) {
+ sendpld_ack(cc, cc->hbuf_out - cc->saved_hbuf_out);
+ }
+ if (hlen_in != cc->hlen_in) {
+ recvpld_ack(cc, hlen_in - cc->hlen_in);
+ if (cc->hlen_in == 0) {
+ /*
+ * We read all data bytes, which may have
+ * released the output buffer in case it
+ * is shared with the input buffer, and
+ * the handshake code might be waiting for
+ * that.
+ */
+ action = 0;
+ continue;
+ }
+ }
+ break;
+ }
+}
+
+/* see inner.h */
+void
+br_ssl_engine_flush_record(br_ssl_engine_context *cc)
+{
+ if (cc->hbuf_out != cc->saved_hbuf_out) {
+ sendpld_ack(cc, cc->hbuf_out - cc->saved_hbuf_out);
+ }
+ if (br_ssl_engine_has_pld_to_send(cc)) {
+ sendpld_flush(cc, 0);
+ }
+ cc->saved_hbuf_out = cc->hbuf_out = sendpld_buf(cc, &cc->hlen_out);
+}
+
+/* see bearssl_ssl.h */
+unsigned char *
+br_ssl_engine_sendapp_buf(const br_ssl_engine_context *cc, size_t *len)
+{
+ if (!(cc->application_data & 1)) {
+ *len = 0;
+ return NULL;
+ }
+ return sendpld_buf(cc, len);
+}
+
+/* see bearssl_ssl.h */
+void
+br_ssl_engine_sendapp_ack(br_ssl_engine_context *cc, size_t len)
+{
+ sendpld_ack(cc, len);
+}
+
+/* see bearssl_ssl.h */
+unsigned char *
+br_ssl_engine_recvapp_buf(const br_ssl_engine_context *cc, size_t *len)
+{
+ if (!(cc->application_data & 1)
+ || cc->record_type_in != BR_SSL_APPLICATION_DATA)
+ {
+ *len = 0;
+ return NULL;
+ }
+ return recvpld_buf(cc, len);
+}
+
+/* see bearssl_ssl.h */
+void
+br_ssl_engine_recvapp_ack(br_ssl_engine_context *cc, size_t len)
+{
+ recvpld_ack(cc, len);
+}
+
+/* see bearssl_ssl.h */
+unsigned char *
+br_ssl_engine_sendrec_buf(const br_ssl_engine_context *cc, size_t *len)
+{
+ return sendrec_buf(cc, len);
+}
+
+/* see bearssl_ssl.h */
+void
+br_ssl_engine_sendrec_ack(br_ssl_engine_context *cc, size_t len)
+{
+ sendrec_ack(cc, len);
+ if (len != 0 && !has_rec_tosend(cc)
+ && (cc->record_type_out != BR_SSL_APPLICATION_DATA
+ || (cc->application_data & 1) == 0))
+ {
+ jump_handshake(cc, 0);
+ }
+}
+
+/* see bearssl_ssl.h */
+unsigned char *
+br_ssl_engine_recvrec_buf(const br_ssl_engine_context *cc, size_t *len)
+{
+ return recvrec_buf(cc, len);
+}
+
+/* see bearssl_ssl.h */
+void
+br_ssl_engine_recvrec_ack(br_ssl_engine_context *cc, size_t len)
+{
+ unsigned char *buf;
+
+ recvrec_ack(cc, len);
+ if (br_ssl_engine_closed(cc)) {
+ return;
+ }
+
+ /*
+ * We just received some bytes from the peer. This may have
+ * yielded some payload bytes, in which case we must process
+ * them according to the record type.
+ */
+ buf = recvpld_buf(cc, &len);
+ if (buf != NULL) {
+ switch (cc->record_type_in) {
+ case BR_SSL_CHANGE_CIPHER_SPEC:
+ case BR_SSL_ALERT:
+ case BR_SSL_HANDSHAKE:
+ jump_handshake(cc, 0);
+ break;
+ case BR_SSL_APPLICATION_DATA:
+ if (cc->application_data == 1) {
+ break;
+ }
+
+ /*
+ * If we are currently closing, and waiting for
+ * a close_notify from the peer, then incoming
+ * application data should be discarded.
+ */
+ if (cc->application_data == 2) {
+ recvpld_ack(cc, len);
+ break;
+ }
+
+ /* Fall through */
+ default:
+ br_ssl_engine_fail(cc, BR_ERR_UNEXPECTED);
+ break;
+ }
+ }
+}
+
+/* see bearssl_ssl.h */
+void
+br_ssl_engine_close(br_ssl_engine_context *cc)
+{
+ if (!br_ssl_engine_closed(cc)) {
+ jump_handshake(cc, 1);
+ }
+}
+
+/* see bearssl_ssl.h */
+int
+br_ssl_engine_renegotiate(br_ssl_engine_context *cc)
+{
+ size_t len;
+
+ if (br_ssl_engine_closed(cc) || cc->reneg == 1
+ || (cc->flags & BR_OPT_NO_RENEGOTIATION) != 0
+ || br_ssl_engine_recvapp_buf(cc, &len) != NULL)
+ {
+ return 0;
+ }
+ jump_handshake(cc, 2);
+ return 1;
+}
+
+/* see bearssl.h */
+unsigned
+br_ssl_engine_current_state(const br_ssl_engine_context *cc)
+{
+ unsigned s;
+ size_t len;
+
+ if (br_ssl_engine_closed(cc)) {
+ return BR_SSL_CLOSED;
+ }
+
+ s = 0;
+ if (br_ssl_engine_sendrec_buf(cc, &len) != NULL) {
+ s |= BR_SSL_SENDREC;
+ }
+ if (br_ssl_engine_recvrec_buf(cc, &len) != NULL) {
+ s |= BR_SSL_RECVREC;
+ }
+ if (br_ssl_engine_sendapp_buf(cc, &len) != NULL) {
+ s |= BR_SSL_SENDAPP;
+ }
+ if (br_ssl_engine_recvapp_buf(cc, &len) != NULL) {
+ s |= BR_SSL_RECVAPP;
+ }
+ return s;
+}
+
+/* see bearssl_ssl.h */
+void
+br_ssl_engine_flush(br_ssl_engine_context *cc, int force)
+{
+ if (!br_ssl_engine_closed(cc) && (cc->application_data & 1) != 0) {
+ sendpld_flush(cc, force);
+ }
+}
+
+/* see inner.h */
+void
+br_ssl_engine_hs_reset(br_ssl_engine_context *cc,
+ void (*hsinit)(void *), void (*hsrun)(void *))
+{
+ engine_clearbuf(cc);
+ cc->cpu.dp = cc->dp_stack;
+ cc->cpu.rp = cc->rp_stack;
+ hsinit(&cc->cpu);
+ cc->hsrun = hsrun;
+ cc->shutdown_recv = 0;
+ cc->application_data = 0;
+ cc->alert = 0;
+ jump_handshake(cc, 0);
+}
+
+/* see inner.h */
+br_tls_prf_impl
+br_ssl_engine_get_PRF(br_ssl_engine_context *cc, int prf_id)
+{
+ if (cc->session.version >= BR_TLS12) {
+ if (prf_id == br_sha384_ID) {
+ return cc->prf_sha384;
+ } else {
+ return cc->prf_sha256;
+ }
+ } else {
+ return cc->prf10;
+ }
+}
+
+/* see inner.h */
+void
+br_ssl_engine_compute_master(br_ssl_engine_context *cc,
+ int prf_id, const void *pms, size_t pms_len)
+{
+ br_tls_prf_impl iprf;
+ br_tls_prf_seed_chunk seed[2] = {
+ { cc->client_random, sizeof cc->client_random },
+ { cc->server_random, sizeof cc->server_random }
+ };
+
+ iprf = br_ssl_engine_get_PRF(cc, prf_id);
+ iprf(cc->session.master_secret, sizeof cc->session.master_secret,
+ pms, pms_len, "master secret", 2, seed);
+}
+
+/*
+ * Compute key block.
+ */
+static void
+compute_key_block(br_ssl_engine_context *cc, int prf_id,
+ size_t half_len, unsigned char *kb)
+{
+ br_tls_prf_impl iprf;
+ br_tls_prf_seed_chunk seed[2] = {
+ { cc->server_random, sizeof cc->server_random },
+ { cc->client_random, sizeof cc->client_random }
+ };
+
+ iprf = br_ssl_engine_get_PRF(cc, prf_id);
+ iprf(kb, half_len << 1,
+ cc->session.master_secret, sizeof cc->session.master_secret,
+ "key expansion", 2, seed);
+}
+
+/* see inner.h */
+void
+br_ssl_engine_switch_cbc_in(br_ssl_engine_context *cc,
+ int is_client, int prf_id, int mac_id,
+ const br_block_cbcdec_class *bc_impl, size_t cipher_key_len)
+{
+ unsigned char kb[192];
+ unsigned char *cipher_key, *mac_key, *iv;
+ const br_hash_class *imh;
+ size_t mac_key_len, mac_out_len, iv_len;
+
+ imh = br_ssl_engine_get_hash(cc, mac_id);
+ mac_out_len = (imh->desc >> BR_HASHDESC_OUT_OFF) & BR_HASHDESC_OUT_MASK;
+ mac_key_len = mac_out_len;
+
+ /*
+ * TLS 1.1+ uses per-record explicit IV, so no IV to generate here.
+ */
+ if (cc->session.version >= BR_TLS11) {
+ iv_len = 0;
+ } else {
+ iv_len = bc_impl->block_size;
+ }
+ compute_key_block(cc, prf_id,
+ mac_key_len + cipher_key_len + iv_len, kb);
+ if (is_client) {
+ mac_key = &kb[mac_key_len];
+ cipher_key = &kb[(mac_key_len << 1) + cipher_key_len];
+ iv = &kb[((mac_key_len + cipher_key_len) << 1) + iv_len];
+ } else {
+ mac_key = &kb[0];
+ cipher_key = &kb[mac_key_len << 1];
+ iv = &kb[(mac_key_len + cipher_key_len) << 1];
+ }
+ if (iv_len == 0) {
+ iv = NULL;
+ }
+ cc->icbc_in->init(&cc->in.cbc.vtable,
+ bc_impl, cipher_key, cipher_key_len,
+ imh, mac_key, mac_key_len, mac_out_len, iv);
+ cc->incrypt = 1;
+}
+
+/* see inner.h */
+void
+br_ssl_engine_switch_cbc_out(br_ssl_engine_context *cc,
+ int is_client, int prf_id, int mac_id,
+ const br_block_cbcenc_class *bc_impl, size_t cipher_key_len)
+{
+ unsigned char kb[192];
+ unsigned char *cipher_key, *mac_key, *iv;
+ const br_hash_class *imh;
+ size_t mac_key_len, mac_out_len, iv_len;
+
+ imh = br_ssl_engine_get_hash(cc, mac_id);
+ mac_out_len = (imh->desc >> BR_HASHDESC_OUT_OFF) & BR_HASHDESC_OUT_MASK;
+ mac_key_len = mac_out_len;
+
+ /*
+ * TLS 1.1+ uses per-record explicit IV, so no IV to generate here.
+ */
+ if (cc->session.version >= BR_TLS11) {
+ iv_len = 0;
+ } else {
+ iv_len = bc_impl->block_size;
+ }
+ compute_key_block(cc, prf_id,
+ mac_key_len + cipher_key_len + iv_len, kb);
+ if (is_client) {
+ mac_key = &kb[0];
+ cipher_key = &kb[mac_key_len << 1];
+ iv = &kb[(mac_key_len + cipher_key_len) << 1];
+ } else {
+ mac_key = &kb[mac_key_len];
+ cipher_key = &kb[(mac_key_len << 1) + cipher_key_len];
+ iv = &kb[((mac_key_len + cipher_key_len) << 1) + iv_len];
+ }
+ if (iv_len == 0) {
+ iv = NULL;
+ }
+ cc->icbc_out->init(&cc->out.cbc.vtable,
+ bc_impl, cipher_key, cipher_key_len,
+ imh, mac_key, mac_key_len, mac_out_len, iv);
+}
+
+/* see inner.h */
+void
+br_ssl_engine_switch_gcm_in(br_ssl_engine_context *cc,
+ int is_client, int prf_id,
+ const br_block_ctr_class *bc_impl, size_t cipher_key_len)
+{
+ unsigned char kb[72];
+ unsigned char *cipher_key, *iv;
+
+ compute_key_block(cc, prf_id, cipher_key_len + 4, kb);
+ if (is_client) {
+ cipher_key = &kb[cipher_key_len];
+ iv = &kb[(cipher_key_len << 1) + 4];
+ } else {
+ cipher_key = &kb[0];
+ iv = &kb[cipher_key_len << 1];
+ }
+ cc->igcm_in->init(&cc->in.gcm.vtable.in,
+ bc_impl, cipher_key, cipher_key_len, cc->ighash, iv);
+ cc->incrypt = 1;
+}
+
+/* see inner.h */
+void
+br_ssl_engine_switch_gcm_out(br_ssl_engine_context *cc,
+ int is_client, int prf_id,
+ const br_block_ctr_class *bc_impl, size_t cipher_key_len)
+{
+ unsigned char kb[72];
+ unsigned char *cipher_key, *iv;
+
+ compute_key_block(cc, prf_id, cipher_key_len + 4, kb);
+ if (is_client) {
+ cipher_key = &kb[0];
+ iv = &kb[cipher_key_len << 1];
+ } else {
+ cipher_key = &kb[cipher_key_len];
+ iv = &kb[(cipher_key_len << 1) + 4];
+ }
+ cc->igcm_out->init(&cc->out.gcm.vtable.out,
+ bc_impl, cipher_key, cipher_key_len, cc->ighash, iv);
+}
+
+/* see inner.h */
+void
+br_ssl_engine_switch_chapol_in(br_ssl_engine_context *cc,
+ int is_client, int prf_id)
+{
+ unsigned char kb[88];
+ unsigned char *cipher_key, *iv;
+
+ compute_key_block(cc, prf_id, 44, kb);
+ if (is_client) {
+ cipher_key = &kb[32];
+ iv = &kb[76];
+ } else {
+ cipher_key = &kb[0];
+ iv = &kb[64];
+ }
+ cc->ichapol_in->init(&cc->in.chapol.vtable.in,
+ cc->ichacha, cc->ipoly, cipher_key, iv);
+ cc->incrypt = 1;
+}
+
+/* see inner.h */
+void
+br_ssl_engine_switch_chapol_out(br_ssl_engine_context *cc,
+ int is_client, int prf_id)
+{
+ unsigned char kb[88];
+ unsigned char *cipher_key, *iv;
+
+ compute_key_block(cc, prf_id, 44, kb);
+ if (is_client) {
+ cipher_key = &kb[0];
+ iv = &kb[64];
+ } else {
+ cipher_key = &kb[32];
+ iv = &kb[76];
+ }
+ cc->ichapol_out->init(&cc->out.chapol.vtable.out,
+ cc->ichacha, cc->ipoly, cipher_key, iv);
+}
+
+/* see inner.h */
+void
+br_ssl_engine_switch_ccm_in(br_ssl_engine_context *cc,
+ int is_client, int prf_id,
+ const br_block_ctrcbc_class *bc_impl,
+ size_t cipher_key_len, size_t tag_len)
+{
+ unsigned char kb[72];
+ unsigned char *cipher_key, *iv;
+
+ compute_key_block(cc, prf_id, cipher_key_len + 4, kb);
+ if (is_client) {
+ cipher_key = &kb[cipher_key_len];
+ iv = &kb[(cipher_key_len << 1) + 4];
+ } else {
+ cipher_key = &kb[0];
+ iv = &kb[cipher_key_len << 1];
+ }
+ cc->iccm_in->init(&cc->in.ccm.vtable.in,
+ bc_impl, cipher_key, cipher_key_len, iv, tag_len);
+ cc->incrypt = 1;
+}
+
+/* see inner.h */
+void
+br_ssl_engine_switch_ccm_out(br_ssl_engine_context *cc,
+ int is_client, int prf_id,
+ const br_block_ctrcbc_class *bc_impl,
+ size_t cipher_key_len, size_t tag_len)
+{
+ unsigned char kb[72];
+ unsigned char *cipher_key, *iv;
+
+ compute_key_block(cc, prf_id, cipher_key_len + 4, kb);
+ if (is_client) {
+ cipher_key = &kb[0];
+ iv = &kb[cipher_key_len << 1];
+ } else {
+ cipher_key = &kb[cipher_key_len];
+ iv = &kb[(cipher_key_len << 1) + 4];
+ }
+ cc->iccm_out->init(&cc->out.ccm.vtable.out,
+ bc_impl, cipher_key, cipher_key_len, iv, tag_len);
+}
diff --git a/test/monniaux/BearSSL/src/ssl/ssl_engine_default_aescbc.c b/test/monniaux/BearSSL/src/ssl/ssl_engine_default_aescbc.c
new file mode 100644
index 00000000..8c5cdb57
--- /dev/null
+++ b/test/monniaux/BearSSL/src/ssl/ssl_engine_default_aescbc.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_ssl.h */
+void
+br_ssl_engine_set_default_aes_cbc(br_ssl_engine_context *cc)
+{
+#if BR_AES_X86NI || BR_POWER8
+ const br_block_cbcenc_class *ienc;
+ const br_block_cbcdec_class *idec;
+#endif
+
+ br_ssl_engine_set_cbc(cc,
+ &br_sslrec_in_cbc_vtable,
+ &br_sslrec_out_cbc_vtable);
+#if BR_AES_X86NI
+ ienc = br_aes_x86ni_cbcenc_get_vtable();
+ idec = br_aes_x86ni_cbcdec_get_vtable();
+ if (ienc != NULL && idec != NULL) {
+ br_ssl_engine_set_aes_cbc(cc, ienc, idec);
+ return;
+ }
+#endif
+#if BR_POWER8
+ ienc = br_aes_pwr8_cbcenc_get_vtable();
+ idec = br_aes_pwr8_cbcdec_get_vtable();
+ if (ienc != NULL && idec != NULL) {
+ br_ssl_engine_set_aes_cbc(cc, ienc, idec);
+ return;
+ }
+#endif
+#if BR_64
+ br_ssl_engine_set_aes_cbc(cc,
+ &br_aes_ct64_cbcenc_vtable,
+ &br_aes_ct64_cbcdec_vtable);
+#else
+ br_ssl_engine_set_aes_cbc(cc,
+ &br_aes_ct_cbcenc_vtable,
+ &br_aes_ct_cbcdec_vtable);
+#endif
+}
diff --git a/test/monniaux/BearSSL/src/ssl/ssl_engine_default_aesccm.c b/test/monniaux/BearSSL/src/ssl/ssl_engine_default_aesccm.c
new file mode 100644
index 00000000..15c0a78f
--- /dev/null
+++ b/test/monniaux/BearSSL/src/ssl/ssl_engine_default_aesccm.c
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_ssl.h */
+void
+br_ssl_engine_set_default_aes_ccm(br_ssl_engine_context *cc)
+{
+#if BR_AES_X86NI || BR_POWER8
+ const br_block_ctrcbc_class *ictrcbc;
+#endif
+
+ br_ssl_engine_set_ccm(cc,
+ &br_sslrec_in_ccm_vtable,
+ &br_sslrec_out_ccm_vtable);
+#if BR_AES_X86NI
+ ictrcbc = br_aes_x86ni_ctrcbc_get_vtable();
+ if (ictrcbc != NULL) {
+ br_ssl_engine_set_aes_ctrcbc(cc, ictrcbc);
+ } else {
+#if BR_64
+ br_ssl_engine_set_aes_ctrcbc(cc, &br_aes_ct64_ctrcbc_vtable);
+#else
+ br_ssl_engine_set_aes_ctrcbc(cc, &br_aes_ct_ctrcbc_vtable);
+#endif
+ }
+#elif BR_POWER8
+ ictrcbc = br_aes_pwr8_ctrcbc_get_vtable();
+ if (ictrcbc != NULL) {
+ br_ssl_engine_set_aes_ctrcbc(cc, ictrcbc);
+ } else {
+#if BR_64
+ br_ssl_engine_set_aes_ctrcbc(cc, &br_aes_ct64_ctrcbc_vtable);
+#else
+ br_ssl_engine_set_aes_ctrcbc(cc, &br_aes_ct_ctrcbc_vtable);
+#endif
+ }
+#else
+#if BR_64
+ br_ssl_engine_set_aes_ctrcbc(cc, &br_aes_ct64_ctrcbc_vtable);
+#else
+ br_ssl_engine_set_aes_ctrcbc(cc, &br_aes_ct_ctrcbc_vtable);
+#endif
+#endif
+}
diff --git a/test/monniaux/BearSSL/src/ssl/ssl_engine_default_aesgcm.c b/test/monniaux/BearSSL/src/ssl/ssl_engine_default_aesgcm.c
new file mode 100644
index 00000000..c44a7074
--- /dev/null
+++ b/test/monniaux/BearSSL/src/ssl/ssl_engine_default_aesgcm.c
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_ssl.h */
+void
+br_ssl_engine_set_default_aes_gcm(br_ssl_engine_context *cc)
+{
+#if BR_AES_X86NI || BR_POWER8
+ const br_block_ctr_class *ictr;
+ br_ghash ighash;
+#endif
+
+ br_ssl_engine_set_gcm(cc,
+ &br_sslrec_in_gcm_vtable,
+ &br_sslrec_out_gcm_vtable);
+#if BR_AES_X86NI
+ ictr = br_aes_x86ni_ctr_get_vtable();
+ if (ictr != NULL) {
+ br_ssl_engine_set_aes_ctr(cc, ictr);
+ } else {
+#if BR_64
+ br_ssl_engine_set_aes_ctr(cc, &br_aes_ct64_ctr_vtable);
+#else
+ br_ssl_engine_set_aes_ctr(cc, &br_aes_ct_ctr_vtable);
+#endif
+ }
+#elif BR_POWER8
+ ictr = br_aes_pwr8_ctr_get_vtable();
+ if (ictr != NULL) {
+ br_ssl_engine_set_aes_ctr(cc, ictr);
+ } else {
+#if BR_64
+ br_ssl_engine_set_aes_ctr(cc, &br_aes_ct64_ctr_vtable);
+#else
+ br_ssl_engine_set_aes_ctr(cc, &br_aes_ct_ctr_vtable);
+#endif
+ }
+#else
+#if BR_64
+ br_ssl_engine_set_aes_ctr(cc, &br_aes_ct64_ctr_vtable);
+#else
+ br_ssl_engine_set_aes_ctr(cc, &br_aes_ct_ctr_vtable);
+#endif
+#endif
+#if BR_AES_X86NI
+ ighash = br_ghash_pclmul_get();
+ if (ighash != 0) {
+ br_ssl_engine_set_ghash(cc, ighash);
+ return;
+ }
+#endif
+#if BR_POWER8
+ ighash = br_ghash_pwr8_get();
+ if (ighash != 0) {
+ br_ssl_engine_set_ghash(cc, ighash);
+ return;
+ }
+#endif
+#if BR_LOMUL
+ br_ssl_engine_set_ghash(cc, &br_ghash_ctmul32);
+#elif BR_64
+ br_ssl_engine_set_ghash(cc, &br_ghash_ctmul64);
+#else
+ br_ssl_engine_set_ghash(cc, &br_ghash_ctmul);
+#endif
+}
diff --git a/test/monniaux/BearSSL/src/ssl/ssl_engine_default_chapol.c b/test/monniaux/BearSSL/src/ssl/ssl_engine_default_chapol.c
new file mode 100644
index 00000000..47a0c984
--- /dev/null
+++ b/test/monniaux/BearSSL/src/ssl/ssl_engine_default_chapol.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_ssl.h */
+void
+br_ssl_engine_set_default_chapol(br_ssl_engine_context *cc)
+{
+#if BR_INT128 || BR_UMUL128
+ br_poly1305_run bp;
+#endif
+#if BR_SSE2
+ br_chacha20_run bc;
+#endif
+
+ br_ssl_engine_set_chapol(cc,
+ &br_sslrec_in_chapol_vtable,
+ &br_sslrec_out_chapol_vtable);
+#if BR_SSE2
+ bc = br_chacha20_sse2_get();
+ if (bc) {
+ br_ssl_engine_set_chacha20(cc, bc);
+ } else {
+#endif
+ br_ssl_engine_set_chacha20(cc, &br_chacha20_ct_run);
+#if BR_SSE2
+ }
+#endif
+#if BR_INT128 || BR_UMUL128
+ bp = br_poly1305_ctmulq_get();
+ if (bp) {
+ br_ssl_engine_set_poly1305(cc, bp);
+ } else {
+#endif
+#if BR_LOMUL
+ br_ssl_engine_set_poly1305(cc, &br_poly1305_ctmul32_run);
+#else
+ br_ssl_engine_set_poly1305(cc, &br_poly1305_ctmul_run);
+#endif
+#if BR_INT128 || BR_UMUL128
+ }
+#endif
+}
diff --git a/test/monniaux/BearSSL/src/ssl/ssl_engine_default_descbc.c b/test/monniaux/BearSSL/src/ssl/ssl_engine_default_descbc.c
new file mode 100644
index 00000000..0253cb2f
--- /dev/null
+++ b/test/monniaux/BearSSL/src/ssl/ssl_engine_default_descbc.c
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_ssl.h */
+void
+br_ssl_engine_set_default_des_cbc(br_ssl_engine_context *cc)
+{
+ br_ssl_engine_set_cbc(cc,
+ &br_sslrec_in_cbc_vtable,
+ &br_sslrec_out_cbc_vtable);
+ br_ssl_engine_set_des_cbc(cc,
+ &br_des_ct_cbcenc_vtable,
+ &br_des_ct_cbcdec_vtable);
+}
diff --git a/test/monniaux/BearSSL/src/ssl/ssl_engine_default_ec.c b/test/monniaux/BearSSL/src/ssl/ssl_engine_default_ec.c
new file mode 100644
index 00000000..0213ae63
--- /dev/null
+++ b/test/monniaux/BearSSL/src/ssl/ssl_engine_default_ec.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_ssl.h */
+void
+br_ssl_engine_set_default_ec(br_ssl_engine_context *cc)
+{
+#if BR_LOMUL
+ br_ssl_engine_set_ec(cc, &br_ec_all_m15);
+#else
+ br_ssl_engine_set_ec(cc, &br_ec_all_m31);
+#endif
+}
diff --git a/test/monniaux/BearSSL/src/ssl/ssl_engine_default_ecdsa.c b/test/monniaux/BearSSL/src/ssl/ssl_engine_default_ecdsa.c
new file mode 100644
index 00000000..13040025
--- /dev/null
+++ b/test/monniaux/BearSSL/src/ssl/ssl_engine_default_ecdsa.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_ssl.h */
+void
+br_ssl_engine_set_default_ecdsa(br_ssl_engine_context *cc)
+{
+#if BR_LOMUL
+ br_ssl_engine_set_ec(cc, &br_ec_all_m15);
+ br_ssl_engine_set_ecdsa(cc, &br_ecdsa_i15_vrfy_asn1);
+#else
+ br_ssl_engine_set_ec(cc, &br_ec_all_m31);
+ br_ssl_engine_set_ecdsa(cc, &br_ecdsa_i31_vrfy_asn1);
+#endif
+}
diff --git a/test/monniaux/BearSSL/src/ssl/ssl_engine_default_rsavrfy.c b/test/monniaux/BearSSL/src/ssl/ssl_engine_default_rsavrfy.c
new file mode 100644
index 00000000..ad0628ab
--- /dev/null
+++ b/test/monniaux/BearSSL/src/ssl/ssl_engine_default_rsavrfy.c
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_ssl.h */
+void
+br_ssl_engine_set_default_rsavrfy(br_ssl_engine_context *cc)
+{
+ br_ssl_engine_set_rsavrfy(cc, br_rsa_pkcs1_vrfy_get_default());
+}
diff --git a/test/monniaux/BearSSL/src/ssl/ssl_hashes.c b/test/monniaux/BearSSL/src/ssl/ssl_hashes.c
new file mode 100644
index 00000000..e10a980c
--- /dev/null
+++ b/test/monniaux/BearSSL/src/ssl/ssl_hashes.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see inner.h */
+int
+br_ssl_choose_hash(unsigned bf)
+{
+ static const unsigned char pref[] = {
+ br_sha256_ID, br_sha384_ID, br_sha512_ID,
+ br_sha224_ID, br_sha1_ID
+ };
+ size_t u;
+
+ for (u = 0; u < sizeof pref; u ++) {
+ int x;
+
+ x = pref[u];
+ if ((bf >> x) & 1) {
+ return x;
+ }
+ }
+ return 0;
+}
diff --git a/test/monniaux/BearSSL/src/ssl/ssl_hs_client.c b/test/monniaux/BearSSL/src/ssl/ssl_hs_client.c
new file mode 100644
index 00000000..de36165a
--- /dev/null
+++ b/test/monniaux/BearSSL/src/ssl/ssl_hs_client.c
@@ -0,0 +1,1915 @@
+/* Automatically generated code; do not modify directly. */
+
+#include <stddef.h>
+#include <stdint.h>
+
+typedef struct {
+ uint32_t *dp;
+ uint32_t *rp;
+ const unsigned char *ip;
+} t0_context;
+
+static uint32_t
+t0_parse7E_unsigned(const unsigned char **p)
+{
+ uint32_t x;
+
+ x = 0;
+ for (;;) {
+ unsigned y;
+
+ y = *(*p) ++;
+ x = (x << 7) | (uint32_t)(y & 0x7F);
+ if (y < 0x80) {
+ return x;
+ }
+ }
+}
+
+static int32_t
+t0_parse7E_signed(const unsigned char **p)
+{
+ int neg;
+ uint32_t x;
+
+ neg = ((**p) >> 6) & 1;
+ x = (uint32_t)-neg;
+ for (;;) {
+ unsigned y;
+
+ y = *(*p) ++;
+ x = (x << 7) | (uint32_t)(y & 0x7F);
+ if (y < 0x80) {
+ if (neg) {
+ return -(int32_t)~x - 1;
+ } else {
+ return (int32_t)x;
+ }
+ }
+ }
+}
+
+#define T0_VBYTE(x, n) (unsigned char)((((uint32_t)(x) >> (n)) & 0x7F) | 0x80)
+#define T0_FBYTE(x, n) (unsigned char)(((uint32_t)(x) >> (n)) & 0x7F)
+#define T0_SBYTE(x) (unsigned char)((((uint32_t)(x) >> 28) + 0xF8) ^ 0xF8)
+#define T0_INT1(x) T0_FBYTE(x, 0)
+#define T0_INT2(x) T0_VBYTE(x, 7), T0_FBYTE(x, 0)
+#define T0_INT3(x) T0_VBYTE(x, 14), T0_VBYTE(x, 7), T0_FBYTE(x, 0)
+#define T0_INT4(x) T0_VBYTE(x, 21), T0_VBYTE(x, 14), T0_VBYTE(x, 7), T0_FBYTE(x, 0)
+#define T0_INT5(x) T0_SBYTE(x), T0_VBYTE(x, 21), T0_VBYTE(x, 14), T0_VBYTE(x, 7), T0_FBYTE(x, 0)
+
+/* static const unsigned char t0_datablock[]; */
+
+
+void br_ssl_hs_client_init_main(void *t0ctx);
+
+void br_ssl_hs_client_run(void *t0ctx);
+
+
+
+#include <stddef.h>
+#include <string.h>
+
+#include "inner.h"
+
+/*
+ * This macro evaluates to a pointer to the current engine context.
+ */
+#define ENG ((br_ssl_engine_context *)(void *)((unsigned char *)t0ctx - offsetof(br_ssl_engine_context, cpu)))
+
+
+
+
+
+/*
+ * This macro evaluates to a pointer to the client context, under that
+ * specific name. It must be noted that since the engine context is the
+ * first field of the br_ssl_client_context structure ('eng'), then
+ * pointers values of both types are interchangeable, modulo an
+ * appropriate cast. This also means that "addresses" computed as offsets
+ * within the structure work for both kinds of context.
+ */
+#define CTX ((br_ssl_client_context *)ENG)
+
+/*
+ * Generate the pre-master secret for RSA key exchange, and encrypt it
+ * with the server's public key. Returned value is either the encrypted
+ * data length (in bytes), or -x on error, with 'x' being an error code.
+ *
+ * This code assumes that the public key has been already verified (it
+ * was properly obtained by the X.509 engine, and it has the right type,
+ * i.e. it is of type RSA and suitable for encryption).
+ */
+static int
+make_pms_rsa(br_ssl_client_context *ctx, int prf_id)
+{
+ const br_x509_class **xc;
+ const br_x509_pkey *pk;
+ const unsigned char *n;
+ unsigned char *pms;
+ size_t nlen, u;
+
+ xc = ctx->eng.x509ctx;
+ pk = (*xc)->get_pkey(xc, NULL);
+
+ /*
+ * Compute actual RSA key length, in case there are leading zeros.
+ */
+ n = pk->key.rsa.n;
+ nlen = pk->key.rsa.nlen;
+ while (nlen > 0 && *n == 0) {
+ n ++;
+ nlen --;
+ }
+
+ /*
+ * We need at least 59 bytes (48 bytes for pre-master secret, and
+ * 11 bytes for the PKCS#1 type 2 padding). Note that the X.509
+ * minimal engine normally blocks RSA keys shorter than 128 bytes,
+ * so this is mostly for public keys provided explicitly by the
+ * caller.
+ */
+ if (nlen < 59) {
+ return -BR_ERR_X509_WEAK_PUBLIC_KEY;
+ }
+ if (nlen > sizeof ctx->eng.pad) {
+ return -BR_ERR_LIMIT_EXCEEDED;
+ }
+
+ /*
+ * Make PMS.
+ */
+ pms = ctx->eng.pad + nlen - 48;
+ br_enc16be(pms, ctx->eng.version_max);
+ br_hmac_drbg_generate(&ctx->eng.rng, pms + 2, 46);
+ br_ssl_engine_compute_master(&ctx->eng, prf_id, pms, 48);
+
+ /*
+ * Apply PKCS#1 type 2 padding.
+ */
+ ctx->eng.pad[0] = 0x00;
+ ctx->eng.pad[1] = 0x02;
+ ctx->eng.pad[nlen - 49] = 0x00;
+ br_hmac_drbg_generate(&ctx->eng.rng, ctx->eng.pad + 2, nlen - 51);
+ for (u = 2; u < nlen - 49; u ++) {
+ while (ctx->eng.pad[u] == 0) {
+ br_hmac_drbg_generate(&ctx->eng.rng,
+ &ctx->eng.pad[u], 1);
+ }
+ }
+
+ /*
+ * Compute RSA encryption.
+ */
+ if (!ctx->irsapub(ctx->eng.pad, nlen, &pk->key.rsa)) {
+ return -BR_ERR_LIMIT_EXCEEDED;
+ }
+ return (int)nlen;
+}
+
+/*
+ * OID for hash functions in RSA signatures.
+ */
+static const unsigned char *HASH_OID[] = {
+ BR_HASH_OID_SHA1,
+ BR_HASH_OID_SHA224,
+ BR_HASH_OID_SHA256,
+ BR_HASH_OID_SHA384,
+ BR_HASH_OID_SHA512
+};
+
+/*
+ * 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
+verify_SKE_sig(br_ssl_client_context *ctx,
+ int hash, int use_rsa, size_t sig_len)
+{
+ const br_x509_class **xc;
+ const br_x509_pkey *pk;
+ br_multihash_context mhc;
+ unsigned char hv[64], head[4];
+ size_t hv_len;
+
+ xc = ctx->eng.x509ctx;
+ pk = (*xc)->get_pkey(xc, NULL);
+ br_multihash_zero(&mhc);
+ br_multihash_copyimpl(&mhc, &ctx->eng.mhash);
+ br_multihash_init(&mhc);
+ br_multihash_update(&mhc,
+ ctx->eng.client_random, sizeof ctx->eng.client_random);
+ br_multihash_update(&mhc,
+ ctx->eng.server_random, sizeof ctx->eng.server_random);
+ head[0] = 3;
+ head[1] = 0;
+ head[2] = ctx->eng.ecdhe_curve;
+ head[3] = ctx->eng.ecdhe_point_len;
+ br_multihash_update(&mhc, head, sizeof head);
+ br_multihash_update(&mhc,
+ ctx->eng.ecdhe_point, ctx->eng.ecdhe_point_len);
+ if (hash) {
+ hv_len = br_multihash_out(&mhc, hash, hv);
+ if (hv_len == 0) {
+ return BR_ERR_INVALID_ALGORITHM;
+ }
+ } else {
+ if (!br_multihash_out(&mhc, br_md5_ID, hv)
+ || !br_multihash_out(&mhc, br_sha1_ID, hv + 16))
+ {
+ return BR_ERR_INVALID_ALGORITHM;
+ }
+ hv_len = 36;
+ }
+ if (use_rsa) {
+ unsigned char tmp[64];
+ const unsigned char *hash_oid;
+
+ if (hash) {
+ hash_oid = HASH_OID[hash - 2];
+ } else {
+ hash_oid = NULL;
+ }
+ 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->eng.iecdsa(ctx->eng.iec, hv, hv_len, &pk->key.ec,
+ ctx->eng.pad, sig_len))
+ {
+ return BR_ERR_BAD_SIGNATURE;
+ }
+ }
+ return 0;
+}
+
+/*
+ * 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.
+ *
+ * The point _from_ the server is taken from ecdhe_point[] if 'ecdhe'
+ * is non-zero, or from the X.509 engine context if 'ecdhe' is zero
+ * (for static ECDH).
+ */
+static int
+make_pms_ecdh(br_ssl_client_context *ctx, unsigned ecdhe, int prf_id)
+{
+ int curve;
+ unsigned char key[66], point[133];
+ const unsigned char *order, *point_src;
+ size_t glen, olen, point_len, xoff, xlen;
+ unsigned char mask;
+
+ if (ecdhe) {
+ curve = ctx->eng.ecdhe_curve;
+ point_src = ctx->eng.ecdhe_point;
+ point_len = ctx->eng.ecdhe_point_len;
+ } else {
+ const br_x509_class **xc;
+ const br_x509_pkey *pk;
+
+ xc = ctx->eng.x509ctx;
+ pk = (*xc)->get_pkey(xc, NULL);
+ curve = pk->key.ec.curve;
+ point_src = pk->key.ec.q;
+ point_len = pk->key.ec.qlen;
+ }
+ if ((ctx->eng.iec->supported_curves & ((uint32_t)1 << curve)) == 0) {
+ return -BR_ERR_INVALID_ALGORITHM;
+ }
+
+ /*
+ * We need to generate our key, as a non-zero random value which
+ * is lower than the curve order, in a "large enough" range. We
+ * force top bit to 0 and bottom bit to 1, which guarantees that
+ * the value is in the proper range.
+ */
+ order = ctx->eng.iec->order(curve, &olen);
+ mask = 0xFF;
+ while (mask >= order[0]) {
+ mask >>= 1;
+ }
+ br_hmac_drbg_generate(&ctx->eng.rng, key, olen);
+ key[0] &= mask;
+ key[olen - 1] |= 0x01;
+
+ /*
+ * Compute the common ECDH point, whose X coordinate is the
+ * pre-master secret.
+ */
+ ctx->eng.iec->generator(curve, &glen);
+ if (glen != point_len) {
+ return -BR_ERR_INVALID_ALGORITHM;
+ }
+
+ memcpy(point, point_src, glen);
+ if (!ctx->eng.iec->mul(point, glen, key, olen, curve)) {
+ return -BR_ERR_INVALID_ALGORITHM;
+ }
+
+ /*
+ * The pre-master secret is the X coordinate.
+ */
+ xoff = ctx->eng.iec->xoff(curve, &xlen);
+ br_ssl_engine_compute_master(&ctx->eng, prf_id, point + xoff, xlen);
+
+ ctx->eng.iec->mulgen(point, key, olen, curve);
+ memcpy(ctx->eng.pad, point, glen);
+ return (int)glen;
+}
+
+/*
+ * Perform full static ECDH. This occurs only in the context of client
+ * authentication with certificates: the server uses an EC public key,
+ * the cipher suite is of type ECDH (not ECDHE), the server requested a
+ * client certificate and accepts static ECDH, the client has a
+ * certificate with an EC public key in the same curve, and accepts
+ * static ECDH as well.
+ *
+ * Returned value is 0 on success, -1 on error.
+ */
+static int
+make_pms_static_ecdh(br_ssl_client_context *ctx, int prf_id)
+{
+ unsigned char point[133];
+ size_t point_len;
+ const br_x509_class **xc;
+ const br_x509_pkey *pk;
+
+ xc = ctx->eng.x509ctx;
+ pk = (*xc)->get_pkey(xc, NULL);
+ point_len = pk->key.ec.qlen;
+ if (point_len > sizeof point) {
+ return -1;
+ }
+ memcpy(point, pk->key.ec.q, point_len);
+ if (!(*ctx->client_auth_vtable)->do_keyx(
+ ctx->client_auth_vtable, point, &point_len))
+ {
+ return -1;
+ }
+ br_ssl_engine_compute_master(&ctx->eng,
+ prf_id, point, point_len);
+ 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 unsigned char t0_datablock[] = {
+ 0x00, 0x00, 0x0A, 0x00, 0x24, 0x00, 0x2F, 0x01, 0x24, 0x00, 0x35, 0x02,
+ 0x24, 0x00, 0x3C, 0x01, 0x44, 0x00, 0x3D, 0x02, 0x44, 0x00, 0x9C, 0x03,
+ 0x04, 0x00, 0x9D, 0x04, 0x05, 0xC0, 0x03, 0x40, 0x24, 0xC0, 0x04, 0x41,
+ 0x24, 0xC0, 0x05, 0x42, 0x24, 0xC0, 0x08, 0x20, 0x24, 0xC0, 0x09, 0x21,
+ 0x24, 0xC0, 0x0A, 0x22, 0x24, 0xC0, 0x0D, 0x30, 0x24, 0xC0, 0x0E, 0x31,
+ 0x24, 0xC0, 0x0F, 0x32, 0x24, 0xC0, 0x12, 0x10, 0x24, 0xC0, 0x13, 0x11,
+ 0x24, 0xC0, 0x14, 0x12, 0x24, 0xC0, 0x23, 0x21, 0x44, 0xC0, 0x24, 0x22,
+ 0x55, 0xC0, 0x25, 0x41, 0x44, 0xC0, 0x26, 0x42, 0x55, 0xC0, 0x27, 0x11,
+ 0x44, 0xC0, 0x28, 0x12, 0x55, 0xC0, 0x29, 0x31, 0x44, 0xC0, 0x2A, 0x32,
+ 0x55, 0xC0, 0x2B, 0x23, 0x04, 0xC0, 0x2C, 0x24, 0x05, 0xC0, 0x2D, 0x43,
+ 0x04, 0xC0, 0x2E, 0x44, 0x05, 0xC0, 0x2F, 0x13, 0x04, 0xC0, 0x30, 0x14,
+ 0x05, 0xC0, 0x31, 0x33, 0x04, 0xC0, 0x32, 0x34, 0x05, 0xC0, 0x9C, 0x06,
+ 0x04, 0xC0, 0x9D, 0x07, 0x04, 0xC0, 0xA0, 0x08, 0x04, 0xC0, 0xA1, 0x09,
+ 0x04, 0xC0, 0xAC, 0x26, 0x04, 0xC0, 0xAD, 0x27, 0x04, 0xC0, 0xAE, 0x28,
+ 0x04, 0xC0, 0xAF, 0x29, 0x04, 0xCC, 0xA8, 0x15, 0x04, 0xCC, 0xA9, 0x25,
+ 0x04, 0x00, 0x00
+};
+
+static const unsigned char 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, 0x00, 0x01, 0x01, 0x09, 0x00, 0x00, 0x01, 0x02, 0x08, 0x00, 0x00,
+ 0x01, 0x02, 0x09, 0x00, 0x00, 0x25, 0x25, 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,
+ 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_HELLO_DONE), 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_SNI), 0x00, 0x00, 0x01, T0_INT1(BR_ERR_BAD_VERSION),
+ 0x00, 0x00, 0x01, T0_INT1(BR_ERR_EXTRA_EXTENSION), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_INVALID_ALGORITHM), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_LIMIT_EXCEEDED), 0x00, 0x00, 0x01, T0_INT1(BR_ERR_OK),
+ 0x00, 0x00, 0x01, T0_INT1(BR_ERR_OVERSIZED_ID), 0x00, 0x00, 0x01,
+ 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,
+ T0_INT2(offsetof(br_ssl_engine_context, client_random)), 0x00, 0x00,
+ 0x01, T0_INT2(offsetof(br_ssl_engine_context, close_received)), 0x00,
+ 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, ecdhe_curve)),
+ 0x00, 0x00, 0x01,
+ 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,
+ 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, pad)), 0x00, 0x00,
+ 0x01, T0_INT2(offsetof(br_ssl_engine_context, protocol_names_num)),
+ 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(br_ssl_engine_context, record_type_in)), 0x00, 0x00,
+ 0x01, T0_INT2(offsetof(br_ssl_engine_context, record_type_out)), 0x00,
+ 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, reneg)), 0x00,
+ 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, saved_finished)),
+ 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(br_ssl_engine_context, selected_protocol)), 0x00,
+ 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, server_name)),
+ 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(br_ssl_engine_context, server_random)), 0x00, 0x00,
+ 0x01,
+ T0_INT2(offsetof(br_ssl_engine_context, session) + offsetof(br_ssl_session_parameters, session_id)),
+ 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(br_ssl_engine_context, session) + offsetof(br_ssl_session_parameters, session_id_len)),
+ 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(br_ssl_engine_context, shutdown_recv)), 0x00, 0x00,
+ 0x01, T0_INT2(offsetof(br_ssl_engine_context, suites_buf)), 0x00, 0x00,
+ 0x01, T0_INT2(offsetof(br_ssl_engine_context, suites_num)), 0x00, 0x00,
+ 0x01,
+ T0_INT2(offsetof(br_ssl_engine_context, session) + offsetof(br_ssl_session_parameters, version)),
+ 0x00, 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, version_in)),
+ 0x00, 0x00, 0x01,
+ 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, 0x26, 0x58, 0x06, 0x02, 0x68, 0x28, 0x00, 0x00, 0x06,
+ 0x08, 0x2C, 0x0E, 0x05, 0x02, 0x71, 0x28, 0x04, 0x01, 0x3C, 0x00, 0x00,
+ 0x01, 0x01, 0x00, 0x01, 0x03, 0x00, 0x99, 0x26, 0x5E, 0x44, 0x9D, 0x26,
+ 0x05, 0x04, 0x60, 0x01, 0x00, 0x00, 0x02, 0x00, 0x0E, 0x06, 0x02, 0x9D,
+ 0x00, 0x5E, 0x04, 0x6B, 0x00, 0x06, 0x02, 0x68, 0x28, 0x00, 0x00, 0x26,
+ 0x89, 0x44, 0x05, 0x03, 0x01, 0x0C, 0x08, 0x44, 0x79, 0x2C, 0xAB, 0x1C,
+ 0x84, 0x01, 0x0C, 0x31, 0x00, 0x00, 0x26, 0x1F, 0x01, 0x08, 0x0B, 0x44,
+ 0x5C, 0x1F, 0x08, 0x00, 0x01, 0x03, 0x00, 0x77, 0x2E, 0x02, 0x00, 0x36,
+ 0x17, 0x01, 0x01, 0x0B, 0x77, 0x3E, 0x29, 0x1A, 0x36, 0x06, 0x07, 0x02,
+ 0x00, 0xCF, 0x03, 0x00, 0x04, 0x75, 0x01, 0x00, 0xC5, 0x02, 0x00, 0x26,
+ 0x1A, 0x17, 0x06, 0x02, 0x6F, 0x28, 0xCF, 0x04, 0x76, 0x01, 0x01, 0x00,
+ 0x77, 0x3E, 0x01, 0x16, 0x87, 0x3E, 0x01, 0x00, 0x8A, 0x3C, 0x34, 0xD5,
+ 0x29, 0xB4, 0x06, 0x09, 0x01, 0x7F, 0xAF, 0x01, 0x7F, 0xD2, 0x04, 0x80,
+ 0x53, 0xB1, 0x79, 0x2C, 0xA1, 0x01, T0_INT1(BR_KEYTYPE_SIGN), 0x17,
+ 0x06, 0x01, 0xB5, 0xB8, 0x26, 0x01, 0x0D, 0x0E, 0x06, 0x07, 0x25, 0xB7,
+ 0xB8, 0x01, 0x7F, 0x04, 0x02, 0x01, 0x00, 0x03, 0x00, 0x01, 0x0E, 0x0E,
+ 0x05, 0x02, 0x72, 0x28, 0x06, 0x02, 0x67, 0x28, 0x33, 0x06, 0x02, 0x72,
+ 0x28, 0x02, 0x00, 0x06, 0x1C, 0xD3, 0x80, 0x2E, 0x01, 0x81, 0x7F, 0x0E,
+ 0x06, 0x0D, 0x25, 0x01, 0x10, 0xDE, 0x01, 0x00, 0xDD, 0x79, 0x2C, 0xAB,
+ 0x24, 0x04, 0x04, 0xD6, 0x06, 0x01, 0xD4, 0x04, 0x01, 0xD6, 0x01, 0x7F,
+ 0xD2, 0x01, 0x7F, 0xAF, 0x01, 0x01, 0x77, 0x3E, 0x01, 0x17, 0x87, 0x3E,
+ 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x9A, 0x01, 0x0C, 0x11, 0x01, 0x00,
+ 0x38, 0x0E, 0x06, 0x05, 0x25, 0x01,
+ T0_INT1(BR_KEYTYPE_RSA | BR_KEYTYPE_KEYX), 0x04, 0x30, 0x01, 0x01,
+ 0x38, 0x0E, 0x06, 0x05, 0x25, 0x01,
+ T0_INT1(BR_KEYTYPE_RSA | BR_KEYTYPE_SIGN), 0x04, 0x25, 0x01, 0x02,
+ 0x38, 0x0E, 0x06, 0x05, 0x25, 0x01,
+ T0_INT1(BR_KEYTYPE_EC | BR_KEYTYPE_SIGN), 0x04, 0x1A, 0x01, 0x03,
+ 0x38, 0x0E, 0x06, 0x05, 0x25, 0x01,
+ T0_INT1(BR_KEYTYPE_EC | BR_KEYTYPE_KEYX), 0x04, 0x0F, 0x01, 0x04,
+ 0x38, 0x0E, 0x06, 0x05, 0x25, 0x01,
+ T0_INT1(BR_KEYTYPE_EC | BR_KEYTYPE_KEYX), 0x04, 0x04, 0x01, 0x00,
+ 0x44, 0x25, 0x00, 0x00, 0x82, 0x2E, 0x01, 0x0E, 0x0E, 0x06, 0x04, 0x01,
+ 0x00, 0x04, 0x02, 0x01, 0x05, 0x00, 0x00, 0x40, 0x06, 0x04, 0x01, 0x06,
+ 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x88, 0x2E, 0x26, 0x06, 0x08, 0x01,
+ 0x01, 0x09, 0x01, 0x11, 0x07, 0x04, 0x03, 0x25, 0x01, 0x05, 0x00, 0x01,
+ 0x41, 0x03, 0x00, 0x25, 0x01, 0x00, 0x43, 0x06, 0x03, 0x02, 0x00, 0x08,
+ 0x42, 0x06, 0x03, 0x02, 0x00, 0x08, 0x26, 0x06, 0x06, 0x01, 0x01, 0x0B,
+ 0x01, 0x06, 0x08, 0x00, 0x00, 0x8B, 0x3F, 0x26, 0x06, 0x03, 0x01, 0x09,
+ 0x08, 0x00, 0x01, 0x40, 0x26, 0x06, 0x1E, 0x01, 0x00, 0x03, 0x00, 0x26,
+ 0x06, 0x0E, 0x26, 0x01, 0x01, 0x17, 0x02, 0x00, 0x08, 0x03, 0x00, 0x01,
+ 0x01, 0x11, 0x04, 0x6F, 0x25, 0x02, 0x00, 0x01, 0x01, 0x0B, 0x01, 0x06,
+ 0x08, 0x00, 0x00, 0x7F, 0x2D, 0x44, 0x11, 0x01, 0x01, 0x17, 0x35, 0x00,
+ 0x00, 0x9F, 0xCE, 0x26, 0x01, 0x07, 0x17, 0x01, 0x00, 0x38, 0x0E, 0x06,
+ 0x09, 0x25, 0x01, 0x10, 0x17, 0x06, 0x01, 0x9F, 0x04, 0x35, 0x01, 0x01,
+ 0x38, 0x0E, 0x06, 0x2C, 0x25, 0x25, 0x01, 0x00, 0x77, 0x3E, 0xB3, 0x88,
+ 0x2E, 0x01, 0x01, 0x0E, 0x01, 0x01, 0xA8, 0x37, 0x06, 0x17, 0x29, 0x1A,
+ 0x36, 0x06, 0x04, 0xCE, 0x25, 0x04, 0x78, 0x01, 0x80, 0x64, 0xC5, 0x01,
+ 0x01, 0x77, 0x3E, 0x01, 0x17, 0x87, 0x3E, 0x04, 0x01, 0x9F, 0x04, 0x03,
+ 0x72, 0x28, 0x25, 0x04, 0xFF, 0x34, 0x01, 0x26, 0x03, 0x00, 0x09, 0x26,
+ 0x58, 0x06, 0x02, 0x68, 0x28, 0x02, 0x00, 0x00, 0x00, 0x9A, 0x01, 0x0F,
+ 0x17, 0x00, 0x00, 0x76, 0x2E, 0x01, 0x00, 0x38, 0x0E, 0x06, 0x10, 0x25,
+ 0x26, 0x01, 0x01, 0x0D, 0x06, 0x03, 0x25, 0x01, 0x02, 0x76, 0x3E, 0x01,
+ 0x00, 0x04, 0x21, 0x01, 0x01, 0x38, 0x0E, 0x06, 0x14, 0x25, 0x01, 0x00,
+ 0x76, 0x3E, 0x26, 0x01, 0x80, 0x64, 0x0E, 0x06, 0x05, 0x01, 0x82, 0x00,
+ 0x08, 0x28, 0x5A, 0x04, 0x07, 0x25, 0x01, 0x82, 0x00, 0x08, 0x28, 0x25,
+ 0x00, 0x00, 0x01, 0x00, 0x2F, 0x06, 0x05, 0x3A, 0xAC, 0x37, 0x04, 0x78,
+ 0x26, 0x06, 0x04, 0x01, 0x01, 0x8F, 0x3E, 0x00, 0x01, 0xBF, 0xAA, 0xBF,
+ 0xAA, 0xC1, 0x84, 0x44, 0x26, 0x03, 0x00, 0xB6, 0x9B, 0x9B, 0x02, 0x00,
+ 0x4D, 0x26, 0x58, 0x06, 0x0A, 0x01, 0x03, 0xA8, 0x06, 0x02, 0x72, 0x28,
+ 0x25, 0x04, 0x03, 0x5C, 0x8A, 0x3C, 0x00, 0x00, 0x2F, 0x06, 0x0B, 0x86,
+ 0x2E, 0x01, 0x14, 0x0D, 0x06, 0x02, 0x72, 0x28, 0x04, 0x11, 0xCE, 0x01,
+ 0x07, 0x17, 0x26, 0x01, 0x02, 0x0D, 0x06, 0x06, 0x06, 0x02, 0x72, 0x28,
+ 0x04, 0x70, 0x25, 0xC2, 0x01, 0x01, 0x0D, 0x33, 0x37, 0x06, 0x02, 0x61,
+ 0x28, 0x26, 0x01, 0x01, 0xC8, 0x36, 0xB2, 0x00, 0x01, 0xB8, 0x01, 0x0B,
+ 0x0E, 0x05, 0x02, 0x72, 0x28, 0x26, 0x01, 0x03, 0x0E, 0x06, 0x08, 0xC0,
+ 0x06, 0x02, 0x68, 0x28, 0x44, 0x25, 0x00, 0x44, 0x57, 0xC0, 0xAA, 0x26,
+ 0x06, 0x23, 0xC0, 0xAA, 0x26, 0x56, 0x26, 0x06, 0x18, 0x26, 0x01, 0x82,
+ 0x00, 0x0F, 0x06, 0x05, 0x01, 0x82, 0x00, 0x04, 0x01, 0x26, 0x03, 0x00,
+ 0x84, 0x02, 0x00, 0xB6, 0x02, 0x00, 0x53, 0x04, 0x65, 0x9B, 0x54, 0x04,
+ 0x5A, 0x9B, 0x9B, 0x55, 0x26, 0x06, 0x02, 0x35, 0x00, 0x25, 0x2B, 0x00,
+ 0x00, 0x79, 0x2C, 0xA1, 0x01, 0x7F, 0xB0, 0x26, 0x58, 0x06, 0x02, 0x35,
+ 0x28, 0x26, 0x05, 0x02, 0x72, 0x28, 0x38, 0x17, 0x0D, 0x06, 0x02, 0x74,
+ 0x28, 0x3B, 0x00, 0x00, 0x9C, 0xB8, 0x01, 0x14, 0x0D, 0x06, 0x02, 0x72,
+ 0x28, 0x84, 0x01, 0x0C, 0x08, 0x01, 0x0C, 0xB6, 0x9B, 0x84, 0x26, 0x01,
+ 0x0C, 0x08, 0x01, 0x0C, 0x30, 0x05, 0x02, 0x64, 0x28, 0x00, 0x00, 0xB9,
+ 0x06, 0x02, 0x72, 0x28, 0x06, 0x02, 0x66, 0x28, 0x00, 0x0A, 0xB8, 0x01,
+ 0x02, 0x0E, 0x05, 0x02, 0x72, 0x28, 0xBF, 0x03, 0x00, 0x02, 0x00, 0x95,
+ 0x2C, 0x0A, 0x02, 0x00, 0x94, 0x2C, 0x0F, 0x37, 0x06, 0x02, 0x73, 0x28,
+ 0x02, 0x00, 0x93, 0x2C, 0x0D, 0x06, 0x02, 0x6B, 0x28, 0x02, 0x00, 0x96,
+ 0x3C, 0x8C, 0x01, 0x20, 0xB6, 0x01, 0x00, 0x03, 0x01, 0xC1, 0x03, 0x02,
+ 0x02, 0x02, 0x01, 0x20, 0x0F, 0x06, 0x02, 0x70, 0x28, 0x84, 0x02, 0x02,
+ 0xB6, 0x02, 0x02, 0x8E, 0x2E, 0x0E, 0x02, 0x02, 0x01, 0x00, 0x0F, 0x17,
+ 0x06, 0x0B, 0x8D, 0x84, 0x02, 0x02, 0x30, 0x06, 0x04, 0x01, 0x7F, 0x03,
+ 0x01, 0x8D, 0x84, 0x02, 0x02, 0x31, 0x02, 0x02, 0x8E, 0x3E, 0x02, 0x00,
+ 0x92, 0x02, 0x01, 0x98, 0xBF, 0x26, 0xC3, 0x58, 0x06, 0x02, 0x62, 0x28,
+ 0x26, 0xCD, 0x02, 0x00, 0x01, 0x86, 0x03, 0x0A, 0x17, 0x06, 0x02, 0x62,
+ 0x28, 0x79, 0x02, 0x01, 0x98, 0xC1, 0x06, 0x02, 0x63, 0x28, 0x26, 0x06,
+ 0x81, 0x47, 0xBF, 0xAA, 0xA6, 0x03, 0x03, 0xA4, 0x03, 0x04, 0xA2, 0x03,
+ 0x05, 0xA5, 0x03, 0x06, 0xA7, 0x03, 0x07, 0xA3, 0x03, 0x08, 0x27, 0x03,
+ 0x09, 0x26, 0x06, 0x81, 0x18, 0xBF, 0x01, 0x00, 0x38, 0x0E, 0x06, 0x0F,
+ 0x25, 0x02, 0x03, 0x05, 0x02, 0x6C, 0x28, 0x01, 0x00, 0x03, 0x03, 0xBE,
+ 0x04, 0x80, 0x7F, 0x01, 0x01, 0x38, 0x0E, 0x06, 0x0F, 0x25, 0x02, 0x05,
+ 0x05, 0x02, 0x6C, 0x28, 0x01, 0x00, 0x03, 0x05, 0xBC, 0x04, 0x80, 0x6A,
+ 0x01, 0x83, 0xFE, 0x01, 0x38, 0x0E, 0x06, 0x0F, 0x25, 0x02, 0x04, 0x05,
+ 0x02, 0x6C, 0x28, 0x01, 0x00, 0x03, 0x04, 0xBD, 0x04, 0x80, 0x53, 0x01,
+ 0x0D, 0x38, 0x0E, 0x06, 0x0E, 0x25, 0x02, 0x06, 0x05, 0x02, 0x6C, 0x28,
+ 0x01, 0x00, 0x03, 0x06, 0xBA, 0x04, 0x3F, 0x01, 0x0A, 0x38, 0x0E, 0x06,
+ 0x0E, 0x25, 0x02, 0x07, 0x05, 0x02, 0x6C, 0x28, 0x01, 0x00, 0x03, 0x07,
+ 0xBA, 0x04, 0x2B, 0x01, 0x0B, 0x38, 0x0E, 0x06, 0x0E, 0x25, 0x02, 0x08,
+ 0x05, 0x02, 0x6C, 0x28, 0x01, 0x00, 0x03, 0x08, 0xBA, 0x04, 0x17, 0x01,
+ 0x10, 0x38, 0x0E, 0x06, 0x0E, 0x25, 0x02, 0x09, 0x05, 0x02, 0x6C, 0x28,
+ 0x01, 0x00, 0x03, 0x09, 0xAE, 0x04, 0x03, 0x6C, 0x28, 0x25, 0x04, 0xFE,
+ 0x64, 0x02, 0x04, 0x06, 0x0D, 0x02, 0x04, 0x01, 0x05, 0x0F, 0x06, 0x02,
+ 0x69, 0x28, 0x01, 0x01, 0x88, 0x3E, 0x9B, 0x04, 0x0C, 0xA4, 0x01, 0x05,
+ 0x0F, 0x06, 0x02, 0x69, 0x28, 0x01, 0x01, 0x88, 0x3E, 0x9B, 0x02, 0x01,
+ 0x00, 0x04, 0xB8, 0x01, 0x0C, 0x0E, 0x05, 0x02, 0x72, 0x28, 0xC1, 0x01,
+ 0x03, 0x0E, 0x05, 0x02, 0x6D, 0x28, 0xBF, 0x26, 0x7C, 0x3E, 0x26, 0x01,
+ 0x20, 0x10, 0x06, 0x02, 0x6D, 0x28, 0x40, 0x44, 0x11, 0x01, 0x01, 0x17,
+ 0x05, 0x02, 0x6D, 0x28, 0xC1, 0x26, 0x01, 0x81, 0x05, 0x0F, 0x06, 0x02,
+ 0x6D, 0x28, 0x26, 0x7E, 0x3E, 0x7D, 0x44, 0xB6, 0x92, 0x2C, 0x01, 0x86,
+ 0x03, 0x10, 0x03, 0x00, 0x79, 0x2C, 0xCB, 0x03, 0x01, 0x01, 0x02, 0x03,
+ 0x02, 0x02, 0x00, 0x06, 0x21, 0xC1, 0x26, 0x26, 0x01, 0x02, 0x0A, 0x44,
+ 0x01, 0x06, 0x0F, 0x37, 0x06, 0x02, 0x6D, 0x28, 0x03, 0x02, 0xC1, 0x02,
+ 0x01, 0x01, 0x01, 0x0B, 0x01, 0x03, 0x08, 0x0E, 0x05, 0x02, 0x6D, 0x28,
+ 0x04, 0x08, 0x02, 0x01, 0x06, 0x04, 0x01, 0x00, 0x03, 0x02, 0xBF, 0x26,
+ 0x03, 0x03, 0x26, 0x01, 0x84, 0x00, 0x0F, 0x06, 0x02, 0x6E, 0x28, 0x84,
+ 0x44, 0xB6, 0x02, 0x02, 0x02, 0x01, 0x02, 0x03, 0x50, 0x26, 0x06, 0x01,
+ 0x28, 0x25, 0x9B, 0x00, 0x02, 0x03, 0x00, 0x03, 0x01, 0x02, 0x00, 0x97,
+ 0x02, 0x01, 0x02, 0x00, 0x39, 0x26, 0x01, 0x00, 0x0E, 0x06, 0x02, 0x60,
+ 0x00, 0xD0, 0x04, 0x74, 0x02, 0x01, 0x00, 0x03, 0x00, 0xC1, 0xAA, 0x26,
+ 0x06, 0x80, 0x43, 0xC1, 0x01, 0x01, 0x38, 0x0E, 0x06, 0x06, 0x25, 0x01,
+ 0x81, 0x7F, 0x04, 0x2E, 0x01, 0x80, 0x40, 0x38, 0x0E, 0x06, 0x07, 0x25,
+ 0x01, 0x83, 0xFE, 0x00, 0x04, 0x20, 0x01, 0x80, 0x41, 0x38, 0x0E, 0x06,
+ 0x07, 0x25, 0x01, 0x84, 0x80, 0x00, 0x04, 0x12, 0x01, 0x80, 0x42, 0x38,
+ 0x0E, 0x06, 0x07, 0x25, 0x01, 0x88, 0x80, 0x00, 0x04, 0x04, 0x01, 0x00,
+ 0x44, 0x25, 0x02, 0x00, 0x37, 0x03, 0x00, 0x04, 0xFF, 0x39, 0x9B, 0x79,
+ 0x2C, 0xC9, 0x05, 0x09, 0x02, 0x00, 0x01, 0x83, 0xFF, 0x7F, 0x17, 0x03,
+ 0x00, 0x92, 0x2C, 0x01, 0x86, 0x03, 0x10, 0x06, 0x3A, 0xBB, 0x26, 0x81,
+ 0x3D, 0x41, 0x25, 0x26, 0x01, 0x08, 0x0B, 0x37, 0x01, 0x8C, 0x80, 0x00,
+ 0x37, 0x17, 0x02, 0x00, 0x17, 0x02, 0x00, 0x01, 0x8C, 0x80, 0x00, 0x17,
+ 0x06, 0x19, 0x26, 0x01, 0x81, 0x7F, 0x17, 0x06, 0x05, 0x01, 0x84, 0x80,
+ 0x00, 0x37, 0x26, 0x01, 0x83, 0xFE, 0x00, 0x17, 0x06, 0x05, 0x01, 0x88,
+ 0x80, 0x00, 0x37, 0x03, 0x00, 0x04, 0x09, 0x02, 0x00, 0x01, 0x8C, 0x88,
+ 0x01, 0x17, 0x03, 0x00, 0x16, 0xBF, 0xAA, 0x26, 0x06, 0x23, 0xBF, 0xAA,
+ 0x26, 0x15, 0x26, 0x06, 0x18, 0x26, 0x01, 0x82, 0x00, 0x0F, 0x06, 0x05,
+ 0x01, 0x82, 0x00, 0x04, 0x01, 0x26, 0x03, 0x01, 0x84, 0x02, 0x01, 0xB6,
+ 0x02, 0x01, 0x12, 0x04, 0x65, 0x9B, 0x13, 0x04, 0x5A, 0x9B, 0x14, 0x9B,
+ 0x02, 0x00, 0x2A, 0x00, 0x00, 0xB9, 0x26, 0x5A, 0x06, 0x07, 0x25, 0x06,
+ 0x02, 0x66, 0x28, 0x04, 0x74, 0x00, 0x00, 0xC2, 0x01, 0x03, 0xC0, 0x44,
+ 0x25, 0x44, 0x00, 0x00, 0xBF, 0xC6, 0x00, 0x03, 0x01, 0x00, 0x03, 0x00,
+ 0xBF, 0xAA, 0x26, 0x06, 0x80, 0x50, 0xC1, 0x03, 0x01, 0xC1, 0x03, 0x02,
+ 0x02, 0x01, 0x01, 0x08, 0x0E, 0x06, 0x16, 0x02, 0x02, 0x01, 0x0F, 0x0C,
+ 0x06, 0x0D, 0x01, 0x01, 0x02, 0x02, 0x01, 0x10, 0x08, 0x0B, 0x02, 0x00,
+ 0x37, 0x03, 0x00, 0x04, 0x2A, 0x02, 0x01, 0x01, 0x02, 0x10, 0x02, 0x01,
+ 0x01, 0x06, 0x0C, 0x17, 0x02, 0x02, 0x01, 0x01, 0x0E, 0x02, 0x02, 0x01,
+ 0x03, 0x0E, 0x37, 0x17, 0x06, 0x11, 0x02, 0x00, 0x01, 0x01, 0x02, 0x02,
+ 0x5D, 0x01, 0x02, 0x0B, 0x02, 0x01, 0x08, 0x0B, 0x37, 0x03, 0x00, 0x04,
+ 0xFF, 0x2C, 0x9B, 0x02, 0x00, 0x00, 0x00, 0xBF, 0x01, 0x01, 0x0E, 0x05,
+ 0x02, 0x65, 0x28, 0xC1, 0x01, 0x08, 0x08, 0x82, 0x2E, 0x0E, 0x05, 0x02,
+ 0x65, 0x28, 0x00, 0x00, 0xBF, 0x88, 0x2E, 0x05, 0x15, 0x01, 0x01, 0x0E,
+ 0x05, 0x02, 0x69, 0x28, 0xC1, 0x01, 0x00, 0x0E, 0x05, 0x02, 0x69, 0x28,
+ 0x01, 0x02, 0x88, 0x3E, 0x04, 0x1C, 0x01, 0x19, 0x0E, 0x05, 0x02, 0x69,
+ 0x28, 0xC1, 0x01, 0x18, 0x0E, 0x05, 0x02, 0x69, 0x28, 0x84, 0x01, 0x18,
+ 0xB6, 0x89, 0x84, 0x01, 0x18, 0x30, 0x05, 0x02, 0x69, 0x28, 0x00, 0x00,
+ 0xBF, 0x06, 0x02, 0x6A, 0x28, 0x00, 0x00, 0x01, 0x02, 0x97, 0xC2, 0x01,
+ 0x08, 0x0B, 0xC2, 0x08, 0x00, 0x00, 0x01, 0x03, 0x97, 0xC2, 0x01, 0x08,
+ 0x0B, 0xC2, 0x08, 0x01, 0x08, 0x0B, 0xC2, 0x08, 0x00, 0x00, 0x01, 0x01,
+ 0x97, 0xC2, 0x00, 0x00, 0x3A, 0x26, 0x58, 0x05, 0x01, 0x00, 0x25, 0xD0,
+ 0x04, 0x76, 0x02, 0x03, 0x00, 0x91, 0x2E, 0x03, 0x01, 0x01, 0x00, 0x26,
+ 0x02, 0x01, 0x0A, 0x06, 0x10, 0x26, 0x01, 0x01, 0x0B, 0x90, 0x08, 0x2C,
+ 0x02, 0x00, 0x0E, 0x06, 0x01, 0x00, 0x5C, 0x04, 0x6A, 0x25, 0x01, 0x7F,
+ 0x00, 0x00, 0x01, 0x15, 0x87, 0x3E, 0x44, 0x52, 0x25, 0x52, 0x25, 0x29,
+ 0x00, 0x00, 0x01, 0x01, 0x44, 0xC4, 0x00, 0x00, 0x44, 0x38, 0x97, 0x44,
+ 0x26, 0x06, 0x05, 0xC2, 0x25, 0x5D, 0x04, 0x78, 0x25, 0x00, 0x00, 0x26,
+ 0x01, 0x81, 0xAC, 0x00, 0x0E, 0x06, 0x04, 0x25, 0x01, 0x7F, 0x00, 0x9A,
+ 0x59, 0x00, 0x02, 0x03, 0x00, 0x79, 0x2C, 0x9A, 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, 0x38, 0x0E, 0x06,
+ 0x10, 0x25, 0x01, 0x00, 0x01, 0x18, 0x02, 0x00, 0x06, 0x03, 0x49, 0x04,
+ 0x01, 0x4A, 0x04, 0x81, 0x0D, 0x01, 0x01, 0x38, 0x0E, 0x06, 0x10, 0x25,
+ 0x01, 0x01, 0x01, 0x10, 0x02, 0x00, 0x06, 0x03, 0x49, 0x04, 0x01, 0x4A,
+ 0x04, 0x80, 0x77, 0x01, 0x02, 0x38, 0x0E, 0x06, 0x10, 0x25, 0x01, 0x01,
+ 0x01, 0x20, 0x02, 0x00, 0x06, 0x03, 0x49, 0x04, 0x01, 0x4A, 0x04, 0x80,
+ 0x61, 0x01, 0x03, 0x38, 0x0E, 0x06, 0x0F, 0x25, 0x25, 0x01, 0x10, 0x02,
+ 0x00, 0x06, 0x03, 0x47, 0x04, 0x01, 0x48, 0x04, 0x80, 0x4C, 0x01, 0x04,
+ 0x38, 0x0E, 0x06, 0x0E, 0x25, 0x25, 0x01, 0x20, 0x02, 0x00, 0x06, 0x03,
+ 0x47, 0x04, 0x01, 0x48, 0x04, 0x38, 0x01, 0x05, 0x38, 0x0E, 0x06, 0x0C,
+ 0x25, 0x25, 0x02, 0x00, 0x06, 0x03, 0x4B, 0x04, 0x01, 0x4C, 0x04, 0x26,
+ 0x26, 0x01, 0x09, 0x0F, 0x06, 0x02, 0x68, 0x28, 0x44, 0x25, 0x26, 0x01,
+ 0x01, 0x17, 0x01, 0x04, 0x0B, 0x01, 0x10, 0x08, 0x44, 0x01, 0x08, 0x17,
+ 0x01, 0x10, 0x44, 0x09, 0x02, 0x00, 0x06, 0x03, 0x45, 0x04, 0x01, 0x46,
+ 0x00, 0x25, 0x00, 0x00, 0x9A, 0x01, 0x0C, 0x11, 0x01, 0x02, 0x0F, 0x00,
+ 0x00, 0x9A, 0x01, 0x0C, 0x11, 0x26, 0x5B, 0x44, 0x01, 0x03, 0x0A, 0x17,
+ 0x00, 0x00, 0x9A, 0x01, 0x0C, 0x11, 0x01, 0x01, 0x0E, 0x00, 0x00, 0x9A,
+ 0x01, 0x0C, 0x11, 0x5A, 0x00, 0x00, 0x9A, 0x01, 0x81, 0x70, 0x17, 0x01,
+ 0x20, 0x0D, 0x00, 0x00, 0x1B, 0x01, 0x00, 0x75, 0x2E, 0x26, 0x06, 0x22,
+ 0x01, 0x01, 0x38, 0x0E, 0x06, 0x06, 0x25, 0x01, 0x00, 0x9E, 0x04, 0x14,
+ 0x01, 0x02, 0x38, 0x0E, 0x06, 0x0D, 0x25, 0x77, 0x2E, 0x01, 0x01, 0x0E,
+ 0x06, 0x03, 0x01, 0x10, 0x37, 0x04, 0x01, 0x25, 0x04, 0x01, 0x25, 0x7B,
+ 0x2E, 0x05, 0x33, 0x2F, 0x06, 0x30, 0x86, 0x2E, 0x01, 0x14, 0x38, 0x0E,
+ 0x06, 0x06, 0x25, 0x01, 0x02, 0x37, 0x04, 0x22, 0x01, 0x15, 0x38, 0x0E,
+ 0x06, 0x09, 0x25, 0xAD, 0x06, 0x03, 0x01, 0x7F, 0x9E, 0x04, 0x13, 0x01,
+ 0x16, 0x38, 0x0E, 0x06, 0x06, 0x25, 0x01, 0x01, 0x37, 0x04, 0x07, 0x25,
+ 0x01, 0x04, 0x37, 0x01, 0x00, 0x25, 0x1A, 0x06, 0x03, 0x01, 0x08, 0x37,
+ 0x00, 0x00, 0x1B, 0x26, 0x05, 0x13, 0x2F, 0x06, 0x10, 0x86, 0x2E, 0x01,
+ 0x15, 0x0E, 0x06, 0x08, 0x25, 0xAD, 0x01, 0x00, 0x77, 0x3E, 0x04, 0x01,
+ 0x20, 0x00, 0x00, 0xCE, 0x01, 0x07, 0x17, 0x01, 0x01, 0x0F, 0x06, 0x02,
+ 0x72, 0x28, 0x00, 0x01, 0x03, 0x00, 0x29, 0x1A, 0x06, 0x05, 0x02, 0x00,
+ 0x87, 0x3E, 0x00, 0xCE, 0x25, 0x04, 0x74, 0x00, 0x01, 0x14, 0xD1, 0x01,
+ 0x01, 0xDE, 0x29, 0x26, 0x01, 0x00, 0xC8, 0x01, 0x16, 0xD1, 0xD7, 0x29,
+ 0x00, 0x00, 0x01, 0x0B, 0xDE, 0x4E, 0x26, 0x26, 0x01, 0x03, 0x08, 0xDD,
+ 0xDD, 0x18, 0x26, 0x58, 0x06, 0x02, 0x25, 0x00, 0xDD, 0x1D, 0x26, 0x06,
+ 0x05, 0x84, 0x44, 0xD8, 0x04, 0x77, 0x25, 0x04, 0x6C, 0x00, 0x21, 0x01,
+ 0x0F, 0xDE, 0x26, 0x92, 0x2C, 0x01, 0x86, 0x03, 0x10, 0x06, 0x0C, 0x01,
+ 0x04, 0x08, 0xDD, 0x80, 0x2E, 0xDE, 0x78, 0x2E, 0xDE, 0x04, 0x02, 0x5E,
+ 0xDD, 0x26, 0xDC, 0x84, 0x44, 0xD8, 0x00, 0x02, 0xA4, 0xA6, 0x08, 0xA2,
+ 0x08, 0xA5, 0x08, 0xA7, 0x08, 0xA3, 0x08, 0x27, 0x08, 0x03, 0x00, 0x01,
+ 0x01, 0xDE, 0x01, 0x27, 0x8E, 0x2E, 0x08, 0x91, 0x2E, 0x01, 0x01, 0x0B,
+ 0x08, 0x02, 0x00, 0x06, 0x04, 0x5E, 0x02, 0x00, 0x08, 0x83, 0x2C, 0x38,
+ 0x09, 0x26, 0x5B, 0x06, 0x24, 0x02, 0x00, 0x05, 0x04, 0x44, 0x5E, 0x44,
+ 0x5F, 0x01, 0x04, 0x09, 0x26, 0x58, 0x06, 0x03, 0x25, 0x01, 0x00, 0x26,
+ 0x01, 0x04, 0x08, 0x02, 0x00, 0x08, 0x03, 0x00, 0x44, 0x01, 0x04, 0x08,
+ 0x38, 0x08, 0x44, 0x04, 0x03, 0x25, 0x01, 0x7F, 0x03, 0x01, 0xDD, 0x94,
+ 0x2C, 0xDC, 0x7A, 0x01, 0x04, 0x19, 0x7A, 0x01, 0x04, 0x08, 0x01, 0x1C,
+ 0x32, 0x7A, 0x01, 0x20, 0xD8, 0x8D, 0x8E, 0x2E, 0xDA, 0x91, 0x2E, 0x26,
+ 0x01, 0x01, 0x0B, 0xDC, 0x90, 0x44, 0x26, 0x06, 0x0F, 0x5D, 0x38, 0x2C,
+ 0x26, 0xC7, 0x05, 0x02, 0x62, 0x28, 0xDC, 0x44, 0x5E, 0x44, 0x04, 0x6E,
+ 0x60, 0x01, 0x01, 0xDE, 0x01, 0x00, 0xDE, 0x02, 0x00, 0x06, 0x81, 0x5A,
+ 0x02, 0x00, 0xDC, 0xA4, 0x06, 0x0E, 0x01, 0x83, 0xFE, 0x01, 0xDC, 0x89,
+ 0xA4, 0x01, 0x04, 0x09, 0x26, 0xDC, 0x5D, 0xDA, 0xA6, 0x06, 0x16, 0x01,
+ 0x00, 0xDC, 0x8B, 0xA6, 0x01, 0x04, 0x09, 0x26, 0xDC, 0x01, 0x02, 0x09,
+ 0x26, 0xDC, 0x01, 0x00, 0xDE, 0x01, 0x03, 0x09, 0xD9, 0xA2, 0x06, 0x0C,
+ 0x01, 0x01, 0xDC, 0x01, 0x01, 0xDC, 0x82, 0x2E, 0x01, 0x08, 0x09, 0xDE,
+ 0xA5, 0x06, 0x19, 0x01, 0x0D, 0xDC, 0xA5, 0x01, 0x04, 0x09, 0x26, 0xDC,
+ 0x01, 0x02, 0x09, 0xDC, 0x42, 0x06, 0x03, 0x01, 0x03, 0xDB, 0x43, 0x06,
+ 0x03, 0x01, 0x01, 0xDB, 0xA7, 0x26, 0x06, 0x36, 0x01, 0x0A, 0xDC, 0x01,
+ 0x04, 0x09, 0x26, 0xDC, 0x5F, 0xDC, 0x40, 0x01, 0x00, 0x26, 0x01, 0x82,
+ 0x80, 0x80, 0x80, 0x00, 0x17, 0x06, 0x0A, 0x01, 0xFD, 0xFF, 0xFF, 0xFF,
+ 0x7F, 0x17, 0x01, 0x1D, 0xDC, 0x26, 0x01, 0x20, 0x0A, 0x06, 0x0C, 0xA0,
+ 0x11, 0x01, 0x01, 0x17, 0x06, 0x02, 0x26, 0xDC, 0x5C, 0x04, 0x6E, 0x60,
+ 0x04, 0x01, 0x25, 0xA3, 0x06, 0x0A, 0x01, 0x0B, 0xDC, 0x01, 0x02, 0xDC,
+ 0x01, 0x82, 0x00, 0xDC, 0x27, 0x26, 0x06, 0x1F, 0x01, 0x10, 0xDC, 0x01,
+ 0x04, 0x09, 0x26, 0xDC, 0x5F, 0xDC, 0x85, 0x2C, 0x01, 0x00, 0xA0, 0x0F,
+ 0x06, 0x0A, 0x26, 0x1E, 0x26, 0xDE, 0x84, 0x44, 0xD8, 0x5C, 0x04, 0x72,
+ 0x60, 0x04, 0x01, 0x25, 0x02, 0x01, 0x58, 0x05, 0x11, 0x01, 0x15, 0xDC,
+ 0x02, 0x01, 0x26, 0xDC, 0x26, 0x06, 0x06, 0x5D, 0x01, 0x00, 0xDE, 0x04,
+ 0x77, 0x25, 0x00, 0x00, 0x01, 0x10, 0xDE, 0x79, 0x2C, 0x26, 0xCC, 0x06,
+ 0x0C, 0xAB, 0x23, 0x26, 0x5E, 0xDD, 0x26, 0xDC, 0x84, 0x44, 0xD8, 0x04,
+ 0x0D, 0x26, 0xCA, 0x44, 0xAB, 0x22, 0x26, 0x5C, 0xDD, 0x26, 0xDE, 0x84,
+ 0x44, 0xD8, 0x00, 0x00, 0x9C, 0x01, 0x14, 0xDE, 0x01, 0x0C, 0xDD, 0x84,
+ 0x01, 0x0C, 0xD8, 0x00, 0x00, 0x51, 0x26, 0x01, 0x00, 0x0E, 0x06, 0x02,
+ 0x60, 0x00, 0xCE, 0x25, 0x04, 0x73, 0x00, 0x26, 0xDC, 0xD8, 0x00, 0x00,
+ 0x26, 0xDE, 0xD8, 0x00, 0x01, 0x03, 0x00, 0x41, 0x25, 0x26, 0x01, 0x10,
+ 0x17, 0x06, 0x06, 0x01, 0x04, 0xDE, 0x02, 0x00, 0xDE, 0x26, 0x01, 0x08,
+ 0x17, 0x06, 0x06, 0x01, 0x03, 0xDE, 0x02, 0x00, 0xDE, 0x26, 0x01, 0x20,
+ 0x17, 0x06, 0x06, 0x01, 0x05, 0xDE, 0x02, 0x00, 0xDE, 0x26, 0x01, 0x80,
+ 0x40, 0x17, 0x06, 0x06, 0x01, 0x06, 0xDE, 0x02, 0x00, 0xDE, 0x01, 0x04,
+ 0x17, 0x06, 0x06, 0x01, 0x02, 0xDE, 0x02, 0x00, 0xDE, 0x00, 0x00, 0x26,
+ 0x01, 0x08, 0x4F, 0xDE, 0xDE, 0x00, 0x00, 0x26, 0x01, 0x10, 0x4F, 0xDE,
+ 0xDC, 0x00, 0x00, 0x26, 0x52, 0x06, 0x02, 0x25, 0x00, 0xCE, 0x25, 0x04,
+ 0x76
+};
+
+static const uint16_t t0_caddr[] = {
+ 0,
+ 5,
+ 10,
+ 15,
+ 20,
+ 25,
+ 30,
+ 35,
+ 40,
+ 44,
+ 48,
+ 52,
+ 56,
+ 60,
+ 64,
+ 68,
+ 72,
+ 76,
+ 80,
+ 84,
+ 88,
+ 92,
+ 96,
+ 100,
+ 104,
+ 108,
+ 112,
+ 116,
+ 120,
+ 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,
+ 279,
+ 284,
+ 289,
+ 294,
+ 303,
+ 316,
+ 320,
+ 345,
+ 351,
+ 370,
+ 381,
+ 422,
+ 542,
+ 546,
+ 611,
+ 626,
+ 637,
+ 655,
+ 684,
+ 694,
+ 730,
+ 740,
+ 818,
+ 832,
+ 838,
+ 897,
+ 916,
+ 951,
+ 1000,
+ 1076,
+ 1103,
+ 1134,
+ 1145,
+ 1497,
+ 1644,
+ 1668,
+ 1884,
+ 1898,
+ 1907,
+ 1911,
+ 2006,
+ 2027,
+ 2083,
+ 2090,
+ 2101,
+ 2117,
+ 2123,
+ 2134,
+ 2169,
+ 2181,
+ 2187,
+ 2202,
+ 2218,
+ 2411,
+ 2420,
+ 2433,
+ 2442,
+ 2449,
+ 2459,
+ 2565,
+ 2590,
+ 2603,
+ 2619,
+ 2637,
+ 2669,
+ 2703,
+ 3071,
+ 3107,
+ 3120,
+ 3134,
+ 3139,
+ 3144,
+ 3210,
+ 3218,
+ 3226
+};
+
+#define T0_INTERPRETED 88
+
+#define T0_ENTER(ip, rp, slot) do { \
+ const unsigned char *t0_newip; \
+ uint32_t t0_lnum; \
+ t0_newip = &t0_codeblock[t0_caddr[(slot) - T0_INTERPRETED]]; \
+ t0_lnum = t0_parse7E_unsigned(&t0_newip); \
+ (rp) += t0_lnum; \
+ *((rp) ++) = (uint32_t)((ip) - &t0_codeblock[0]) + (t0_lnum << 16); \
+ (ip) = t0_newip; \
+ } while (0)
+
+#define T0_DEFENTRY(name, slot) \
+void \
+name(void *ctx) \
+{ \
+ t0_context *t0ctx = ctx; \
+ t0ctx->ip = &t0_codeblock[0]; \
+ T0_ENTER(t0ctx->ip, t0ctx->rp, slot); \
+}
+
+T0_DEFENTRY(br_ssl_hs_client_init_main, 169)
+
+#define T0_NEXT(t0ipp) (*(*(t0ipp)) ++)
+
+void
+br_ssl_hs_client_run(void *t0ctx)
+{
+ uint32_t *dp, *rp;
+ const unsigned char *ip;
+
+#define T0_LOCAL(x) (*(rp - 2 - (x)))
+#define T0_POP() (*-- dp)
+#define T0_POPi() (*(int32_t *)(-- dp))
+#define T0_PEEK(x) (*(dp - 1 - (x)))
+#define T0_PEEKi(x) (*(int32_t *)(dp - 1 - (x)))
+#define T0_PUSH(v) do { *dp = (v); dp ++; } while (0)
+#define T0_PUSHi(v) do { *(int32_t *)dp = (v); dp ++; } while (0)
+#define T0_RPOP() (*-- rp)
+#define T0_RPOPi() (*(int32_t *)(-- rp))
+#define T0_RPUSH(v) do { *rp = (v); rp ++; } while (0)
+#define T0_RPUSHi(v) do { *(int32_t *)rp = (v); rp ++; } while (0)
+#define T0_ROLL(x) do { \
+ size_t t0len = (size_t)(x); \
+ uint32_t t0tmp = *(dp - 1 - t0len); \
+ memmove(dp - t0len - 1, dp - t0len, t0len * sizeof *dp); \
+ *(dp - 1) = t0tmp; \
+} while (0)
+#define T0_SWAP() do { \
+ uint32_t t0tmp = *(dp - 2); \
+ *(dp - 2) = *(dp - 1); \
+ *(dp - 1) = t0tmp; \
+} while (0)
+#define T0_ROT() do { \
+ uint32_t t0tmp = *(dp - 3); \
+ *(dp - 3) = *(dp - 2); \
+ *(dp - 2) = *(dp - 1); \
+ *(dp - 1) = t0tmp; \
+} while (0)
+#define T0_NROT() do { \
+ uint32_t t0tmp = *(dp - 1); \
+ *(dp - 1) = *(dp - 2); \
+ *(dp - 2) = *(dp - 3); \
+ *(dp - 3) = t0tmp; \
+} while (0)
+#define T0_PICK(x) do { \
+ uint32_t t0depth = (x); \
+ T0_PUSH(T0_PEEK(t0depth)); \
+} while (0)
+#define T0_CO() do { \
+ goto t0_exit; \
+} while (0)
+#define T0_RET() goto t0_next
+
+ dp = ((t0_context *)t0ctx)->dp;
+ rp = ((t0_context *)t0ctx)->rp;
+ ip = ((t0_context *)t0ctx)->ip;
+ goto t0_next;
+ for (;;) {
+ uint32_t t0x;
+
+ t0_next:
+ t0x = T0_NEXT(&ip);
+ if (t0x < T0_INTERPRETED) {
+ switch (t0x) {
+ int32_t t0off;
+
+ case 0: /* ret */
+ t0x = T0_RPOP();
+ rp -= (t0x >> 16);
+ t0x &= 0xFFFF;
+ if (t0x == 0) {
+ ip = NULL;
+ goto t0_exit;
+ }
+ ip = &t0_codeblock[t0x];
+ break;
+ case 1: /* literal constant */
+ T0_PUSHi(t0_parse7E_signed(&ip));
+ break;
+ case 2: /* read local */
+ T0_PUSH(T0_LOCAL(t0_parse7E_unsigned(&ip)));
+ break;
+ case 3: /* write local */
+ T0_LOCAL(t0_parse7E_unsigned(&ip)) = T0_POP();
+ break;
+ case 4: /* jump */
+ t0off = t0_parse7E_signed(&ip);
+ ip += t0off;
+ break;
+ case 5: /* jump if */
+ t0off = t0_parse7E_signed(&ip);
+ if (T0_POP()) {
+ ip += t0off;
+ }
+ break;
+ case 6: /* jump if not */
+ t0off = t0_parse7E_signed(&ip);
+ if (!T0_POP()) {
+ ip += t0off;
+ }
+ break;
+ case 7: {
+ /* * */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a * b);
+
+ }
+ break;
+ case 8: {
+ /* + */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a + b);
+
+ }
+ break;
+ case 9: {
+ /* - */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a - b);
+
+ }
+ break;
+ case 10: {
+ /* < */
+
+ int32_t b = T0_POPi();
+ int32_t a = T0_POPi();
+ T0_PUSH(-(uint32_t)(a < b));
+
+ }
+ break;
+ case 11: {
+ /* << */
+
+ int c = (int)T0_POPi();
+ uint32_t x = T0_POP();
+ T0_PUSH(x << c);
+
+ }
+ 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();
+ uint32_t a = T0_POP();
+ T0_PUSH(-(uint32_t)(a != b));
+
+ }
+ break;
+ case 14: {
+ /* = */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(-(uint32_t)(a == b));
+
+ }
+ break;
+ case 15: {
+ /* > */
+
+ int32_t b = T0_POPi();
+ int32_t a = T0_POPi();
+ T0_PUSH(-(uint32_t)(a > b));
+
+ }
+ break;
+ case 16: {
+ /* >= */
+
+ int32_t b = T0_POPi();
+ int32_t a = T0_POPi();
+ T0_PUSH(-(uint32_t)(a >= b));
+
+ }
+ break;
+ case 17: {
+ /* >> */
+
+ int c = (int)T0_POPi();
+ int32_t x = T0_POPi();
+ T0_PUSHi(x >> c);
+
+ }
+ break;
+ 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();
+ uint32_t a = T0_POP();
+ T0_PUSH(a & b);
+
+ }
+ break;
+ 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();
+ void *addr = (unsigned char *)ENG + (size_t)T0_POP();
+ memset(addr, 0, len);
+
+ }
+ break;
+ case 26: {
+ /* can-output? */
+
+ T0_PUSHi(-(ENG->hlen_out > 0));
+
+ }
+ break;
+ case 27: {
+ /* co */
+ T0_CO();
+ }
+ break;
+ case 28: {
+ /* compute-Finished-inner */
+
+ int prf_id = T0_POP();
+ int from_client = T0_POPi();
+ unsigned char tmp[48];
+ br_tls_prf_seed_chunk seed;
+
+ br_tls_prf_impl prf = br_ssl_engine_get_PRF(ENG, prf_id);
+ seed.data = tmp;
+ if (ENG->session.version >= BR_TLS12) {
+ seed.len = br_multihash_out(&ENG->mhash, prf_id, tmp);
+ } else {
+ br_multihash_out(&ENG->mhash, br_md5_ID, tmp);
+ br_multihash_out(&ENG->mhash, br_sha1_ID, tmp + 16);
+ seed.len = 36;
+ }
+ prf(ENG->pad, 12, ENG->session.master_secret,
+ sizeof ENG->session.master_secret,
+ from_client ? "client finished" : "server finished",
+ 1, &seed);
+
+ }
+ break;
+ 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: {
+ /* copy-protocol-name */
+
+ size_t idx = T0_POP();
+ size_t len = strlen(ENG->protocol_names[idx]);
+ memcpy(ENG->pad, ENG->protocol_names[idx], len);
+ T0_PUSH(len);
+
+ }
+ break;
+ case 31: {
+ /* data-get8 */
+
+ size_t addr = T0_POP();
+ T0_PUSH(t0_datablock[addr]);
+
+ }
+ break;
+ case 32: {
+ /* discard-input */
+
+ ENG->hlen_in = 0;
+
+ }
+ break;
+ case 33: {
+ /* 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 34: {
+ /* do-ecdh */
+
+ unsigned prf_id = T0_POP();
+ unsigned ecdhe = T0_POP();
+ int x;
+
+ x = make_pms_ecdh(CTX, ecdhe, prf_id);
+ if (x < 0) {
+ br_ssl_engine_fail(ENG, -x);
+ T0_CO();
+ } else {
+ T0_PUSH(x);
+ }
+
+ }
+ break;
+ case 35: {
+ /* do-rsa-encrypt */
+
+ int x;
+
+ x = make_pms_rsa(CTX, T0_POP());
+ if (x < 0) {
+ br_ssl_engine_fail(ENG, -x);
+ T0_CO();
+ } else {
+ T0_PUSH(x);
+ }
+
+ }
+ break;
+ case 36: {
+ /* 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 37: {
+ /* drop */
+ (void)T0_POP();
+ }
+ break;
+ case 38: {
+ /* dup */
+ T0_PUSH(T0_PEEK(0));
+ }
+ break;
+ case 39: {
+ /* ext-ALPN-length */
+
+ size_t u, len;
+
+ if (ENG->protocol_names_num == 0) {
+ T0_PUSH(0);
+ T0_RET();
+ }
+ len = 6;
+ for (u = 0; u < ENG->protocol_names_num; u ++) {
+ len += 1 + strlen(ENG->protocol_names[u]);
+ }
+ T0_PUSH(len);
+
+ }
+ break;
+ case 40: {
+ /* fail */
+
+ br_ssl_engine_fail(ENG, (int)T0_POPi());
+ T0_CO();
+
+ }
+ break;
+ case 41: {
+ /* flush-record */
+
+ br_ssl_engine_flush_record(ENG);
+
+ }
+ break;
+ case 42: {
+ /* 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 43: {
+ /* 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 44: {
+ /* get16 */
+
+ size_t addr = (size_t)T0_POP();
+ T0_PUSH(*(uint16_t *)(void *)((unsigned char *)ENG + addr));
+
+ }
+ break;
+ case 45: {
+ /* get32 */
+
+ size_t addr = (size_t)T0_POP();
+ T0_PUSH(*(uint32_t *)(void *)((unsigned char *)ENG + addr));
+
+ }
+ break;
+ case 46: {
+ /* get8 */
+
+ size_t addr = (size_t)T0_POP();
+ T0_PUSH(*((unsigned char *)ENG + addr));
+
+ }
+ break;
+ case 47: {
+ /* has-input? */
+
+ T0_PUSHi(-(ENG->hlen_in != 0));
+
+ }
+ break;
+ case 48: {
+ /* memcmp */
+
+ size_t len = (size_t)T0_POP();
+ void *addr2 = (unsigned char *)ENG + (size_t)T0_POP();
+ void *addr1 = (unsigned char *)ENG + (size_t)T0_POP();
+ int x = memcmp(addr1, addr2, len);
+ T0_PUSH((uint32_t)-(x == 0));
+
+ }
+ break;
+ case 49: {
+ /* memcpy */
+
+ size_t len = (size_t)T0_POP();
+ void *src = (unsigned char *)ENG + (size_t)T0_POP();
+ void *dst = (unsigned char *)ENG + (size_t)T0_POP();
+ memcpy(dst, src, len);
+
+ }
+ break;
+ case 50: {
+ /* mkrand */
+
+ size_t len = (size_t)T0_POP();
+ void *addr = (unsigned char *)ENG + (size_t)T0_POP();
+ br_hmac_drbg_generate(&ENG->rng, addr, len);
+
+ }
+ break;
+ case 51: {
+ /* more-incoming-bytes? */
+
+ T0_PUSHi(ENG->hlen_in != 0 || !br_ssl_engine_recvrec_finished(ENG));
+
+ }
+ break;
+ case 52: {
+ /* multihash-init */
+
+ br_multihash_init(&ENG->mhash);
+
+ }
+ break;
+ case 53: {
+ /* neg */
+
+ uint32_t a = T0_POP();
+ T0_PUSH(-a);
+
+ }
+ break;
+ case 54: {
+ /* not */
+
+ uint32_t a = T0_POP();
+ T0_PUSH(~a);
+
+ }
+ break;
+ case 55: {
+ /* or */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a | b);
+
+ }
+ break;
+ case 56: {
+ /* over */
+ T0_PUSH(T0_PEEK(1));
+ }
+ break;
+ case 57: {
+ /* read-chunk-native */
+
+ size_t clen = ENG->hlen_in;
+ if (clen > 0) {
+ uint32_t addr, len;
+
+ len = T0_POP();
+ addr = T0_POP();
+ if ((size_t)len < clen) {
+ clen = (size_t)len;
+ }
+ memcpy((unsigned char *)ENG + addr, ENG->hbuf_in, clen);
+ if (ENG->record_type_in == BR_SSL_HANDSHAKE) {
+ br_multihash_update(&ENG->mhash, ENG->hbuf_in, clen);
+ }
+ T0_PUSH(addr + (uint32_t)clen);
+ T0_PUSH(len - (uint32_t)clen);
+ ENG->hbuf_in += clen;
+ ENG->hlen_in -= clen;
+ }
+
+ }
+ break;
+ case 58: {
+ /* read8-native */
+
+ if (ENG->hlen_in > 0) {
+ unsigned char x;
+
+ x = *ENG->hbuf_in ++;
+ if (ENG->record_type_in == BR_SSL_HANDSHAKE) {
+ br_multihash_update(&ENG->mhash, &x, 1);
+ }
+ T0_PUSH(x);
+ ENG->hlen_in --;
+ } else {
+ T0_PUSHi(-1);
+ }
+
+ }
+ break;
+ case 59: {
+ /* 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 60: {
+ /* set16 */
+
+ size_t addr = (size_t)T0_POP();
+ *(uint16_t *)(void *)((unsigned char *)ENG + addr) = (uint16_t)T0_POP();
+
+ }
+ break;
+ case 61: {
+ /* set32 */
+
+ size_t addr = (size_t)T0_POP();
+ *(uint32_t *)(void *)((unsigned char *)ENG + addr) = (uint32_t)T0_POP();
+
+ }
+ break;
+ case 62: {
+ /* set8 */
+
+ size_t addr = (size_t)T0_POP();
+ *((unsigned char *)ENG + addr) = (unsigned char)T0_POP();
+
+ }
+ break;
+ case 63: {
+ /* strlen */
+
+ void *str = (unsigned char *)ENG + (size_t)T0_POP();
+ T0_PUSH((uint32_t)strlen(str));
+
+ }
+ break;
+ case 64: {
+ /* supported-curves */
+
+ uint32_t x = ENG->iec == NULL ? 0 : ENG->iec->supported_curves;
+ T0_PUSH(x);
+
+ }
+ break;
+ case 65: {
+ /* supported-hash-functions */
+
+ int i;
+ unsigned x, num;
+
+ x = 0;
+ num = 0;
+ for (i = br_sha1_ID; i <= br_sha512_ID; i ++) {
+ if (br_multihash_getimpl(&ENG->mhash, i)) {
+ x |= 1U << i;
+ num ++;
+ }
+ }
+ T0_PUSH(x);
+ T0_PUSH(num);
+
+ }
+ break;
+ case 66: {
+ /* supports-ecdsa? */
+
+ T0_PUSHi(-(ENG->iecdsa != 0));
+
+ }
+ break;
+ case 67: {
+ /* supports-rsa-sign? */
+
+ T0_PUSHi(-(ENG->irsavrfy != 0));
+
+ }
+ break;
+ case 68: {
+ /* swap */
+ T0_SWAP();
+ }
+ break;
+ case 69: {
+ /* switch-aesccm-in */
+
+ int is_client, prf_id;
+ unsigned cipher_key_len, tag_len;
+
+ tag_len = T0_POP();
+ cipher_key_len = T0_POP();
+ prf_id = T0_POP();
+ is_client = T0_POP();
+ br_ssl_engine_switch_ccm_in(ENG, is_client, prf_id,
+ ENG->iaes_ctrcbc, cipher_key_len, tag_len);
+
+ }
+ break;
+ case 70: {
+ /* switch-aesccm-out */
+
+ int is_client, prf_id;
+ unsigned cipher_key_len, tag_len;
+
+ tag_len = T0_POP();
+ cipher_key_len = T0_POP();
+ prf_id = T0_POP();
+ is_client = T0_POP();
+ br_ssl_engine_switch_ccm_out(ENG, is_client, prf_id,
+ ENG->iaes_ctrcbc, cipher_key_len, tag_len);
+
+ }
+ break;
+ case 71: {
+ /* switch-aesgcm-in */
+
+ int is_client, prf_id;
+ unsigned cipher_key_len;
+
+ cipher_key_len = T0_POP();
+ prf_id = T0_POP();
+ is_client = T0_POP();
+ br_ssl_engine_switch_gcm_in(ENG, is_client, prf_id,
+ ENG->iaes_ctr, cipher_key_len);
+
+ }
+ break;
+ case 72: {
+ /* switch-aesgcm-out */
+
+ int is_client, prf_id;
+ unsigned cipher_key_len;
+
+ cipher_key_len = T0_POP();
+ prf_id = T0_POP();
+ is_client = T0_POP();
+ br_ssl_engine_switch_gcm_out(ENG, is_client, prf_id,
+ ENG->iaes_ctr, cipher_key_len);
+
+ }
+ break;
+ case 73: {
+ /* switch-cbc-in */
+
+ int is_client, prf_id, mac_id, aes;
+ unsigned cipher_key_len;
+
+ cipher_key_len = T0_POP();
+ aes = T0_POP();
+ mac_id = T0_POP();
+ prf_id = T0_POP();
+ is_client = T0_POP();
+ br_ssl_engine_switch_cbc_in(ENG, is_client, prf_id, mac_id,
+ aes ? ENG->iaes_cbcdec : ENG->ides_cbcdec, cipher_key_len);
+
+ }
+ break;
+ case 74: {
+ /* switch-cbc-out */
+
+ int is_client, prf_id, mac_id, aes;
+ unsigned cipher_key_len;
+
+ cipher_key_len = T0_POP();
+ aes = T0_POP();
+ mac_id = T0_POP();
+ prf_id = T0_POP();
+ is_client = T0_POP();
+ br_ssl_engine_switch_cbc_out(ENG, is_client, prf_id, mac_id,
+ aes ? ENG->iaes_cbcenc : ENG->ides_cbcenc, cipher_key_len);
+
+ }
+ break;
+ case 75: {
+ /* switch-chapol-in */
+
+ int is_client, prf_id;
+
+ prf_id = T0_POP();
+ is_client = T0_POP();
+ br_ssl_engine_switch_chapol_in(ENG, is_client, prf_id);
+
+ }
+ break;
+ case 76: {
+ /* switch-chapol-out */
+
+ int is_client, prf_id;
+
+ prf_id = T0_POP();
+ is_client = T0_POP();
+ br_ssl_engine_switch_chapol_out(ENG, is_client, prf_id);
+
+ }
+ break;
+ case 77: {
+ /* test-protocol-name */
+
+ size_t len = T0_POP();
+ size_t u;
+
+ for (u = 0; u < ENG->protocol_names_num; u ++) {
+ const char *name;
+
+ name = ENG->protocol_names[u];
+ if (len == strlen(name) && memcmp(ENG->pad, name, len) == 0) {
+ T0_PUSH(u);
+ T0_RET();
+ }
+ }
+ T0_PUSHi(-1);
+
+ }
+ break;
+ case 78: {
+ /* 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 79: {
+ /* u>> */
+
+ int c = (int)T0_POPi();
+ uint32_t x = T0_POP();
+ T0_PUSH(x >> c);
+
+ }
+ break;
+ case 80: {
+ /* verify-SKE-sig */
+
+ size_t sig_len = T0_POP();
+ int use_rsa = T0_POPi();
+ int hash = T0_POPi();
+
+ T0_PUSH(verify_SKE_sig(CTX, hash, use_rsa, sig_len));
+
+ }
+ break;
+ case 81: {
+ /* write-blob-chunk */
+
+ size_t clen = ENG->hlen_out;
+ if (clen > 0) {
+ uint32_t addr, len;
+
+ len = T0_POP();
+ addr = T0_POP();
+ if ((size_t)len < clen) {
+ clen = (size_t)len;
+ }
+ memcpy(ENG->hbuf_out, (unsigned char *)ENG + addr, clen);
+ if (ENG->record_type_out == BR_SSL_HANDSHAKE) {
+ br_multihash_update(&ENG->mhash, ENG->hbuf_out, clen);
+ }
+ T0_PUSH(addr + (uint32_t)clen);
+ T0_PUSH(len - (uint32_t)clen);
+ ENG->hbuf_out += clen;
+ ENG->hlen_out -= clen;
+ }
+
+ }
+ break;
+ case 82: {
+ /* write8-native */
+
+ unsigned char x;
+
+ x = (unsigned char)T0_POP();
+ if (ENG->hlen_out > 0) {
+ if (ENG->record_type_out == BR_SSL_HANDSHAKE) {
+ br_multihash_update(&ENG->mhash, &x, 1);
+ }
+ *ENG->hbuf_out ++ = x;
+ ENG->hlen_out --;
+ T0_PUSHi(-1);
+ } else {
+ T0_PUSHi(0);
+ }
+
+ }
+ break;
+ case 83: {
+ /* 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 84: {
+ /* x509-end-cert */
+
+ const br_x509_class *xc;
+
+ xc = *(ENG->x509ctx);
+ xc->end_cert(ENG->x509ctx);
+
+ }
+ break;
+ case 85: {
+ /* x509-end-chain */
+
+ const br_x509_class *xc;
+
+ xc = *(ENG->x509ctx);
+ T0_PUSH(xc->end_chain(ENG->x509ctx));
+
+ }
+ break;
+ case 86: {
+ /* x509-start-cert */
+
+ const br_x509_class *xc;
+
+ xc = *(ENG->x509ctx);
+ xc->start_cert(ENG->x509ctx, T0_POP());
+
+ }
+ break;
+ case 87: {
+ /* 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;
+ }
+
+ } else {
+ T0_ENTER(ip, rp, t0x);
+ }
+ }
+t0_exit:
+ ((t0_context *)t0ctx)->dp = dp;
+ ((t0_context *)t0ctx)->rp = rp;
+ ((t0_context *)t0ctx)->ip = ip;
+}
diff --git a/test/monniaux/BearSSL/src/ssl/ssl_hs_client.t0 b/test/monniaux/BearSSL/src/ssl/ssl_hs_client.t0
new file mode 100644
index 00000000..23b39e71
--- /dev/null
+++ b/test/monniaux/BearSSL/src/ssl/ssl_hs_client.t0
@@ -0,0 +1,1276 @@
+\ Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+\
+\ Permission is hereby granted, free of charge, to any person obtaining
+\ a copy of this software and associated documentation files (the
+\ "Software"), to deal in the Software without restriction, including
+\ without limitation the rights to use, copy, modify, merge, publish,
+\ distribute, sublicense, and/or sell copies of the Software, and to
+\ permit persons to whom the Software is furnished to do so, subject to
+\ the following conditions:
+\
+\ The above copyright notice and this permission notice shall be
+\ included in all copies or substantial portions of the Software.
+\
+\ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+\ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+\ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+\ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+\ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+\ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+\ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+\ SOFTWARE.
+
+\ ----------------------------------------------------------------------
+\ Handshake processing code, for the client.
+\ The common T0 code (ssl_hs_common.t0) shall be read first.
+
+preamble {
+
+/*
+ * This macro evaluates to a pointer to the client context, under that
+ * specific name. It must be noted that since the engine context is the
+ * first field of the br_ssl_client_context structure ('eng'), then
+ * pointers values of both types are interchangeable, modulo an
+ * appropriate cast. This also means that "addresses" computed as offsets
+ * within the structure work for both kinds of context.
+ */
+#define CTX ((br_ssl_client_context *)ENG)
+
+/*
+ * Generate the pre-master secret for RSA key exchange, and encrypt it
+ * with the server's public key. Returned value is either the encrypted
+ * data length (in bytes), or -x on error, with 'x' being an error code.
+ *
+ * This code assumes that the public key has been already verified (it
+ * was properly obtained by the X.509 engine, and it has the right type,
+ * i.e. it is of type RSA and suitable for encryption).
+ */
+static int
+make_pms_rsa(br_ssl_client_context *ctx, int prf_id)
+{
+ const br_x509_class **xc;
+ const br_x509_pkey *pk;
+ const unsigned char *n;
+ unsigned char *pms;
+ size_t nlen, u;
+
+ xc = ctx->eng.x509ctx;
+ pk = (*xc)->get_pkey(xc, NULL);
+
+ /*
+ * Compute actual RSA key length, in case there are leading zeros.
+ */
+ n = pk->key.rsa.n;
+ nlen = pk->key.rsa.nlen;
+ while (nlen > 0 && *n == 0) {
+ n ++;
+ nlen --;
+ }
+
+ /*
+ * We need at least 59 bytes (48 bytes for pre-master secret, and
+ * 11 bytes for the PKCS#1 type 2 padding). Note that the X.509
+ * minimal engine normally blocks RSA keys shorter than 128 bytes,
+ * so this is mostly for public keys provided explicitly by the
+ * caller.
+ */
+ if (nlen < 59) {
+ return -BR_ERR_X509_WEAK_PUBLIC_KEY;
+ }
+ if (nlen > sizeof ctx->eng.pad) {
+ return -BR_ERR_LIMIT_EXCEEDED;
+ }
+
+ /*
+ * Make PMS.
+ */
+ pms = ctx->eng.pad + nlen - 48;
+ br_enc16be(pms, ctx->eng.version_max);
+ br_hmac_drbg_generate(&ctx->eng.rng, pms + 2, 46);
+ br_ssl_engine_compute_master(&ctx->eng, prf_id, pms, 48);
+
+ /*
+ * Apply PKCS#1 type 2 padding.
+ */
+ ctx->eng.pad[0] = 0x00;
+ ctx->eng.pad[1] = 0x02;
+ ctx->eng.pad[nlen - 49] = 0x00;
+ br_hmac_drbg_generate(&ctx->eng.rng, ctx->eng.pad + 2, nlen - 51);
+ for (u = 2; u < nlen - 49; u ++) {
+ while (ctx->eng.pad[u] == 0) {
+ br_hmac_drbg_generate(&ctx->eng.rng,
+ &ctx->eng.pad[u], 1);
+ }
+ }
+
+ /*
+ * Compute RSA encryption.
+ */
+ if (!ctx->irsapub(ctx->eng.pad, nlen, &pk->key.rsa)) {
+ return -BR_ERR_LIMIT_EXCEEDED;
+ }
+ return (int)nlen;
+}
+
+/*
+ * OID for hash functions in RSA signatures.
+ */
+static const unsigned char *HASH_OID[] = {
+ BR_HASH_OID_SHA1,
+ BR_HASH_OID_SHA224,
+ BR_HASH_OID_SHA256,
+ BR_HASH_OID_SHA384,
+ BR_HASH_OID_SHA512
+};
+
+/*
+ * 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
+verify_SKE_sig(br_ssl_client_context *ctx,
+ int hash, int use_rsa, size_t sig_len)
+{
+ const br_x509_class **xc;
+ const br_x509_pkey *pk;
+ br_multihash_context mhc;
+ unsigned char hv[64], head[4];
+ size_t hv_len;
+
+ xc = ctx->eng.x509ctx;
+ pk = (*xc)->get_pkey(xc, NULL);
+ br_multihash_zero(&mhc);
+ br_multihash_copyimpl(&mhc, &ctx->eng.mhash);
+ br_multihash_init(&mhc);
+ br_multihash_update(&mhc,
+ ctx->eng.client_random, sizeof ctx->eng.client_random);
+ br_multihash_update(&mhc,
+ ctx->eng.server_random, sizeof ctx->eng.server_random);
+ head[0] = 3;
+ head[1] = 0;
+ head[2] = ctx->eng.ecdhe_curve;
+ head[3] = ctx->eng.ecdhe_point_len;
+ br_multihash_update(&mhc, head, sizeof head);
+ br_multihash_update(&mhc,
+ ctx->eng.ecdhe_point, ctx->eng.ecdhe_point_len);
+ if (hash) {
+ hv_len = br_multihash_out(&mhc, hash, hv);
+ if (hv_len == 0) {
+ return BR_ERR_INVALID_ALGORITHM;
+ }
+ } else {
+ if (!br_multihash_out(&mhc, br_md5_ID, hv)
+ || !br_multihash_out(&mhc, br_sha1_ID, hv + 16))
+ {
+ return BR_ERR_INVALID_ALGORITHM;
+ }
+ hv_len = 36;
+ }
+ if (use_rsa) {
+ unsigned char tmp[64];
+ const unsigned char *hash_oid;
+
+ if (hash) {
+ hash_oid = HASH_OID[hash - 2];
+ } else {
+ hash_oid = NULL;
+ }
+ 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->eng.iecdsa(ctx->eng.iec, hv, hv_len, &pk->key.ec,
+ ctx->eng.pad, sig_len))
+ {
+ return BR_ERR_BAD_SIGNATURE;
+ }
+ }
+ return 0;
+}
+
+/*
+ * 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.
+ *
+ * The point _from_ the server is taken from ecdhe_point[] if 'ecdhe'
+ * is non-zero, or from the X.509 engine context if 'ecdhe' is zero
+ * (for static ECDH).
+ */
+static int
+make_pms_ecdh(br_ssl_client_context *ctx, unsigned ecdhe, int prf_id)
+{
+ int curve;
+ unsigned char key[66], point[133];
+ const unsigned char *order, *point_src;
+ size_t glen, olen, point_len, xoff, xlen;
+ unsigned char mask;
+
+ if (ecdhe) {
+ curve = ctx->eng.ecdhe_curve;
+ point_src = ctx->eng.ecdhe_point;
+ point_len = ctx->eng.ecdhe_point_len;
+ } else {
+ const br_x509_class **xc;
+ const br_x509_pkey *pk;
+
+ xc = ctx->eng.x509ctx;
+ pk = (*xc)->get_pkey(xc, NULL);
+ curve = pk->key.ec.curve;
+ point_src = pk->key.ec.q;
+ point_len = pk->key.ec.qlen;
+ }
+ if ((ctx->eng.iec->supported_curves & ((uint32_t)1 << curve)) == 0) {
+ return -BR_ERR_INVALID_ALGORITHM;
+ }
+
+ /*
+ * We need to generate our key, as a non-zero random value which
+ * is lower than the curve order, in a "large enough" range. We
+ * force top bit to 0 and bottom bit to 1, which guarantees that
+ * the value is in the proper range.
+ */
+ order = ctx->eng.iec->order(curve, &olen);
+ mask = 0xFF;
+ while (mask >= order[0]) {
+ mask >>= 1;
+ }
+ br_hmac_drbg_generate(&ctx->eng.rng, key, olen);
+ key[0] &= mask;
+ key[olen - 1] |= 0x01;
+
+ /*
+ * Compute the common ECDH point, whose X coordinate is the
+ * pre-master secret.
+ */
+ ctx->eng.iec->generator(curve, &glen);
+ if (glen != point_len) {
+ return -BR_ERR_INVALID_ALGORITHM;
+ }
+
+ memcpy(point, point_src, glen);
+ if (!ctx->eng.iec->mul(point, glen, key, olen, curve)) {
+ return -BR_ERR_INVALID_ALGORITHM;
+ }
+
+ /*
+ * The pre-master secret is the X coordinate.
+ */
+ xoff = ctx->eng.iec->xoff(curve, &xlen);
+ br_ssl_engine_compute_master(&ctx->eng, prf_id, point + xoff, xlen);
+
+ ctx->eng.iec->mulgen(point, key, olen, curve);
+ memcpy(ctx->eng.pad, point, glen);
+ return (int)glen;
+}
+
+/*
+ * Perform full static ECDH. This occurs only in the context of client
+ * authentication with certificates: the server uses an EC public key,
+ * the cipher suite is of type ECDH (not ECDHE), the server requested a
+ * client certificate and accepts static ECDH, the client has a
+ * certificate with an EC public key in the same curve, and accepts
+ * static ECDH as well.
+ *
+ * Returned value is 0 on success, -1 on error.
+ */
+static int
+make_pms_static_ecdh(br_ssl_client_context *ctx, int prf_id)
+{
+ unsigned char point[133];
+ size_t point_len;
+ const br_x509_class **xc;
+ const br_x509_pkey *pk;
+
+ xc = ctx->eng.x509ctx;
+ pk = (*xc)->get_pkey(xc, NULL);
+ point_len = pk->key.ec.qlen;
+ if (point_len > sizeof point) {
+ return -1;
+ }
+ memcpy(point, pk->key.ec.q, point_len);
+ if (!(*ctx->client_auth_vtable)->do_keyx(
+ ctx->client_auth_vtable, point, &point_len))
+ {
+ return -1;
+ }
+ br_ssl_engine_compute_master(&ctx->eng,
+ prf_id, point, point_len);
+ 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);
+}
+
+}
+
+\ =======================================================================
+
+: addr-ctx:
+ next-word { field }
+ "addr-" field + 0 1 define-word
+ 0 8191 "offsetof(br_ssl_client_context, " field + ")" + make-CX
+ 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
+\ extension), or 0 if we know that the server does not support the
+\ extension.
+: ext-reneg-length ( -- n )
+ addr-reneg get8 dup if 1 - 17 * else drop 5 then ;
+
+\ Length of SNI extension.
+: ext-sni-length ( -- len )
+ addr-server_name strlen dup if 9 + then ;
+
+\ Length of Maximum Fragment Length extension.
+: ext-frag-length ( -- len )
+ addr-log_max_frag_len get8 14 = if 0 else 5 then ;
+
+\ Length of Signatures extension.
+: ext-signatures-length ( -- len )
+ supported-hash-functions { num } drop 0
+ supports-rsa-sign? if num + then
+ supports-ecdsa? if num + then
+ dup if 1 << 6 + then ;
+
+\ Write supported hash functions ( sign -- )
+: write-hashes
+ { sign }
+ supported-hash-functions drop
+ \ We advertise hash functions in the following preference order:
+ \ SHA-256 SHA-224 SHA-384 SHA-512 SHA-1
+ \ Rationale:
+ \ -- SHA-256 and SHA-224 are more efficient on 32-bit architectures
+ \ -- SHA-1 is less than ideally collision-resistant
+ dup 0x10 and if 4 write8 sign write8 then
+ dup 0x08 and if 3 write8 sign write8 then
+ dup 0x20 and if 5 write8 sign write8 then
+ dup 0x40 and if 6 write8 sign write8 then
+ 0x04 and if 2 write8 sign write8 then ;
+
+\ Length of Supported Curves extension.
+: ext-supported-curves-length ( -- len )
+ supported-curves dup if
+ 0 { x }
+ begin dup while
+ dup 1 and x + >x
+ 1 >>
+ repeat
+ drop x 1 << 6 +
+ then ;
+
+\ Length of Supported Point Formats extension.
+: ext-point-format-length ( -- len )
+ supported-curves if 6 else 0 then ;
+
+\ Length of ALPN extension.
+cc: ext-ALPN-length ( -- len ) {
+ size_t u, len;
+
+ if (ENG->protocol_names_num == 0) {
+ T0_PUSH(0);
+ T0_RET();
+ }
+ len = 6;
+ for (u = 0; u < ENG->protocol_names_num; u ++) {
+ len += 1 + strlen(ENG->protocol_names[u]);
+ }
+ T0_PUSH(len);
+}
+
+\ Write handshake message: ClientHello
+: write-ClientHello ( -- )
+ { ; total-ext-length }
+
+ \ Compute length for extensions (without the general two-byte header).
+ \ This does not take padding extension into account.
+ ext-reneg-length ext-sni-length + ext-frag-length +
+ ext-signatures-length +
+ ext-supported-curves-length + ext-point-format-length +
+ ext-ALPN-length +
+ >total-ext-length
+
+ \ ClientHello type
+ 1 write8
+
+ \ Compute and write length
+ 39 addr-session_id_len get8 + addr-suites_num get8 1 << +
+ total-ext-length if 2+ total-ext-length + then
+ \ Compute padding (if requested).
+ addr-min_clienthello_len get16 over - dup 0> if
+ \ We well add a Pad ClientHello extension, which has its
+ \ own header (4 bytes) and might be the only extension
+ \ (2 extra bytes for the extension list header).
+ total-ext-length ifnot swap 2+ swap 2- then
+ \ Account for the extension header.
+ 4 - dup 0< if drop 0 then
+ \ Adjust total extension length.
+ dup 4 + total-ext-length + >total-ext-length
+ \ Adjust ClientHello length.
+ swap 4 + over + swap
+ else
+ drop
+ -1
+ then
+ { ext-padding-amount }
+ write24
+
+ \ Protocol version
+ addr-version_max get16 write16
+
+ \ Client random
+ addr-client_random 4 bzero
+ addr-client_random 4 + 28 mkrand
+ addr-client_random 32 write-blob
+
+ \ Session ID
+ addr-session_id addr-session_id_len get8 write-blob-head8
+
+ \ Supported cipher suites. We also check here that we indeed
+ \ support all these suites.
+ addr-suites_num get8 dup 1 << write16
+ addr-suites_buf swap
+ begin
+ dup while 1-
+ over get16
+ dup suite-supported? ifnot ERR_BAD_CIPHER_SUITE fail then
+ write16
+ swap 2+ swap
+ repeat
+ 2drop
+
+ \ Compression methods (only "null" compression)
+ 1 write8 0 write8
+
+ \ Extensions
+ total-ext-length if
+ total-ext-length write16
+ ext-reneg-length if
+ 0xFF01 write16 \ extension type (0xFF01)
+ addr-saved_finished
+ ext-reneg-length 4 - dup write16 \ extension length
+ 1- write-blob-head8 \ verify data
+ then
+ ext-sni-length if
+ 0x0000 write16 \ extension type (0)
+ addr-server_name
+ ext-sni-length 4 - dup write16 \ extension length
+ 2 - dup write16 \ ServerNameList length
+ 0 write8 \ name type: host_name
+ 3 - write-blob-head16 \ the name itself
+ then
+ ext-frag-length if
+ 0x0001 write16 \ extension type (1)
+ 0x0001 write16 \ extension length
+ addr-log_max_frag_len get8 8 - write8
+ then
+ ext-signatures-length if
+ 0x000D write16 \ extension type (13)
+ ext-signatures-length 4 - dup write16 \ extension length
+ 2 - write16 \ list length
+ supports-ecdsa? if 3 write-hashes then
+ supports-rsa-sign? if 1 write-hashes then
+ then
+ \ TODO: add an API to specify preference order for curves.
+ \ Right now we send Curve25519 first, then other curves in
+ \ increasing ID values (hence P-256 in second).
+ ext-supported-curves-length dup if
+ 0x000A write16 \ extension type (10)
+ 4 - dup write16 \ extension length
+ 2- write16 \ list length
+ supported-curves 0
+ dup 0x20000000 and if
+ 0xDFFFFFFF and 29 write16
+ then
+ begin dup 32 < while
+ dup2 >> 1 and if dup write16 then
+ 1+
+ repeat
+ 2drop
+ else
+ drop
+ then
+ ext-point-format-length if
+ 0x000B write16 \ extension type (11)
+ 0x0002 write16 \ extension length
+ 0x0100 write16 \ value: 1 format: uncompressed
+ then
+ ext-ALPN-length dup if
+ 0x0010 write16 \ extension type (16)
+ 4 - dup write16 \ extension length
+ 2- write16 \ list length
+ addr-protocol_names_num get16 0
+ begin
+ dup2 > while
+ dup copy-protocol-name
+ dup write8 addr-pad swap write-blob
+ 1+
+ repeat
+ 2drop
+ else
+ drop
+ then
+ ext-padding-amount 0< ifnot
+ 0x0015 write16 \ extension value (21)
+ ext-padding-amount
+ dup write16 \ extension length
+ begin dup while
+ 1- 0 write8 repeat \ value (only zeros)
+ drop
+ then
+ then
+ ;
+
+\ =======================================================================
+
+\ Parse server SNI extension. If present, then it should be empty.
+: read-server-sni ( lim -- lim )
+ read16 if ERR_BAD_SNI fail then ;
+
+\ Parse server Max Fragment Length extension. If present, then it should
+\ advertise the same length as the client. Note that whether the server
+\ sends it or not changes nothing for us: we won't send any record larger
+\ than the advertised value anyway, and we will accept incoming records
+\ up to our input buffer length.
+: read-server-frag ( lim -- lim )
+ read16 1 = ifnot ERR_BAD_FRAGLEN fail then
+ read8 8 + addr-log_max_frag_len get8 = ifnot ERR_BAD_FRAGLEN fail then ;
+
+\ Parse server Secure Renegotiation extension. This is called only if
+\ the client sent that extension, so we only have two cases to
+\ distinguish: first handshake, and renegotiation; in the latter case,
+\ we know that the server supports the extension, otherwise the client
+\ would not have sent it.
+: read-server-reneg ( lim -- lim )
+ read16
+ addr-reneg get8 ifnot
+ \ "reneg" is 0, so this is a first handshake. The server's
+ \ extension MUST be empty. We also learn that the server
+ \ supports the extension.
+ 1 = ifnot ERR_BAD_SECRENEG fail then
+ read8 0 = ifnot ERR_BAD_SECRENEG fail then
+ 2 addr-reneg set8
+ else
+ \ "reneg" is non-zero, and we sent an extension, so it must
+ \ be 2 and this is a renegotiation. We must verify that
+ \ the extension contents have length exactly 24 bytes and
+ \ match the saved client and server "Finished".
+ 25 = ifnot ERR_BAD_SECRENEG fail then
+ read8 24 = ifnot ERR_BAD_SECRENEG fail then
+ addr-pad 24 read-blob
+ addr-saved_finished addr-pad 24 memcmp ifnot
+ ERR_BAD_SECRENEG fail
+ then
+ then ;
+
+\ Read the ALPN extension from the server. It must contain a single name,
+\ and that name must match one of our names.
+: read-ALPN-from-server ( lim -- lim )
+ \ Extension contents length.
+ read16 open-elt
+ \ Length of list of names.
+ read16 open-elt
+ \ There should be a single name.
+ read8 addr-pad swap dup { len } read-blob
+ close-elt
+ close-elt
+ len test-protocol-name dup 0< if
+ 3 flag? if ERR_UNEXPECTED fail then
+ drop
+ else
+ 1+ addr-selected_protocol set16
+ then ;
+
+\ Save a value in a 16-bit field, or check it in case of session resumption.
+: check-resume ( val addr resume -- )
+ if get16 = ifnot ERR_RESUME_MISMATCH fail then else set16 then ;
+
+cc: DEBUG-BLOB ( addr len -- ) {
+ extern int printf(const char *fmt, ...);
+
+ size_t len = T0_POP();
+ unsigned char *buf = (unsigned char *)CTX + T0_POP();
+ size_t u;
+
+ printf("BLOB:");
+ for (u = 0; u < len; u ++) {
+ if (u % 16 == 0) {
+ printf("\n ");
+ }
+ printf(" %02x", buf[u]);
+ }
+ printf("\n");
+}
+
+\ Parse incoming ServerHello. Returned value is true (-1) on session
+\ resumption.
+: read-ServerHello ( -- bool )
+ \ Get header, and check message type.
+ read-handshake-header 2 = ifnot ERR_UNEXPECTED fail then
+
+ \ Get protocol version.
+ read16 { version }
+ version addr-version_min get16 < version addr-version_max get16 > or if
+ ERR_UNSUPPORTED_VERSION fail
+ then
+
+ \ Enforce chosen version for subsequent records in both directions.
+ version addr-version_in get16 <> if ERR_BAD_VERSION fail then
+ version addr-version_out set16
+
+ \ Server random.
+ addr-server_random 32 read-blob
+
+ \ The "session resumption" flag.
+ 0 { resume }
+
+ \ Session ID.
+ read8 { idlen }
+ idlen 32 > if ERR_OVERSIZED_ID fail then
+ addr-pad idlen read-blob
+ idlen addr-session_id_len get8 = idlen 0 > and if
+ addr-session_id addr-pad idlen memcmp if
+ \ Server session ID is non-empty and matches what
+ \ we sent, so this is a session resumption.
+ -1 >resume
+ then
+ then
+ addr-session_id addr-pad idlen memcpy
+ idlen addr-session_id_len set8
+
+ \ Record version.
+ version addr-version resume check-resume
+
+ \ Cipher suite. We check that it is part of the list of cipher
+ \ suites that we advertised.
+ read16
+ dup scan-suite 0< if ERR_BAD_CIPHER_SUITE fail then
+ \ Also check that the cipher suite is compatible with the
+ \ announced version: suites that don't use HMAC/SHA-1 are
+ \ for TLS-1.2 only, not older versions.
+ dup use-tls12? version 0x0303 < and if ERR_BAD_CIPHER_SUITE fail then
+ addr-cipher_suite resume check-resume
+
+ \ Compression method. Should be 0 (no compression).
+ read8 if ERR_BAD_COMPRESSION fail then
+
+ \ Parse extensions (if any). If there is no extension, then the
+ \ read limit (on the TOS) should be 0 at that point.
+ dup if
+ \ Length of extension list.
+ \ message size.
+ read16 open-elt
+
+ \ Enumerate extensions. For each of them, check that we
+ \ sent an extension of that type, and did not see it
+ \ yet; and then process it.
+ ext-sni-length { ok-sni }
+ ext-reneg-length { ok-reneg }
+ ext-frag-length { ok-frag }
+ ext-signatures-length { ok-signatures }
+ ext-supported-curves-length { ok-curves }
+ ext-point-format-length { ok-points }
+ ext-ALPN-length { ok-ALPN }
+ begin dup while
+ read16
+ case
+ \ Server Name Indication. The server may
+ \ send such an extension if it uses the SNI
+ \ from the client, but that "response
+ \ extension" is supposed to be empty.
+ 0x0000 of
+ ok-sni ifnot
+ ERR_EXTRA_EXTENSION fail
+ then
+ 0 >ok-sni
+ read-server-sni
+ endof
+
+ \ Max Frag Length. The contents shall be
+ \ a single byte whose value matches the one
+ \ sent by the client.
+ 0x0001 of
+ ok-frag ifnot
+ ERR_EXTRA_EXTENSION fail
+ then
+ 0 >ok-frag
+ read-server-frag
+ endof
+
+ \ Secure Renegotiation.
+ 0xFF01 of
+ ok-reneg ifnot
+ ERR_EXTRA_EXTENSION fail
+ then
+ 0 >ok-reneg
+ read-server-reneg
+ endof
+
+ \ Signature Algorithms.
+ \ Normally, the server should never send this
+ \ extension (so says RFC 5246 #7.4.1.4.1),
+ \ but some existing servers do.
+ 0x000D of
+ ok-signatures ifnot
+ ERR_EXTRA_EXTENSION fail
+ then
+ 0 >ok-signatures
+ read-ignore-16
+ endof
+
+ \ Supported Curves.
+ 0x000A of
+ ok-curves ifnot
+ ERR_EXTRA_EXTENSION fail
+ then
+ 0 >ok-curves
+ read-ignore-16
+ endof
+
+ \ Supported Point Formats.
+ 0x000B of
+ ok-points ifnot
+ ERR_EXTRA_EXTENSION fail
+ then
+ 0 >ok-points
+ read-ignore-16
+ endof
+
+ \ ALPN.
+ 0x0010 of
+ ok-ALPN ifnot
+ ERR_EXTRA_EXTENSION fail
+ then
+ 0 >ok-ALPN
+ read-ALPN-from-server
+ endof
+
+ ERR_EXTRA_EXTENSION fail
+ endcase
+ repeat
+
+ \ If we sent a secure renegotiation extension but did not
+ \ receive a response, then the server does not support
+ \ secure renegotiation. This is a hard failure if this
+ \ is a renegotiation.
+ ok-reneg if
+ ok-reneg 5 > if ERR_BAD_SECRENEG fail then
+ 1 addr-reneg set8
+ then
+ close-elt
+ else
+ \ No extension received at all, so the server does not
+ \ support secure renegotiation. This is a hard failure
+ \ if the server was previously known to support it (i.e.
+ \ this is a renegotiation).
+ ext-reneg-length 5 > if ERR_BAD_SECRENEG fail then
+ 1 addr-reneg set8
+ then
+ close-elt
+ resume
+ ;
+
+cc: 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;
+}
+
+\ Read Certificate message from server.
+: read-Certificate-from-server ( -- )
+ addr-cipher_suite get16 expected-key-type
+ -1 read-Certificate
+ dup 0< if neg fail then
+ dup ifnot ERR_UNEXPECTED fail then
+ over and <> if ERR_WRONG_KEY_USAGE fail then
+
+ \ 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)
+\ 'use-rsa' is 0 for ECDSA, -1 for for RSA
+\ 'sig-len' is the signature length (in bytes)
+\ The signature itself is in the pad.
+cc: verify-SKE-sig ( hash use-rsa sig-len -- err ) {
+ size_t sig_len = T0_POP();
+ int use_rsa = T0_POPi();
+ int hash = T0_POPi();
+
+ T0_PUSH(verify_SKE_sig(CTX, hash, use_rsa, sig_len));
+}
+
+\ Parse ServerKeyExchange
+: read-ServerKeyExchange ( -- )
+ \ Get header, and check message type.
+ read-handshake-header 12 = ifnot ERR_UNEXPECTED fail then
+
+ \ We expect a named curve, and we must support it.
+ read8 3 = ifnot ERR_INVALID_ALGORITHM fail then
+ read16 dup addr-ecdhe_curve set8
+ dup 32 >= if ERR_INVALID_ALGORITHM fail then
+ supported-curves swap >> 1 and ifnot ERR_INVALID_ALGORITHM fail then
+
+ \ Read the server point.
+ read8
+ dup 133 > if ERR_INVALID_ALGORITHM fail then
+ dup addr-ecdhe_point_len set8
+ addr-ecdhe_point swap read-blob
+
+ \ If using TLS-1.2+, then the hash function and signature algorithm
+ \ are explicitly provided; the signature algorithm must match what
+ \ the cipher suite specifies. With TLS-1.0 and 1.1, the signature
+ \ algorithm is inferred from the cipher suite, and the hash is
+ \ either MD5+SHA-1 (for RSA signatures) or SHA-1 (for ECDSA).
+ addr-version get16 0x0303 >= { tls1.2+ }
+ addr-cipher_suite get16 use-rsa-ecdhe? { use-rsa }
+ 2 { hash }
+ tls1.2+ if
+ \ Read hash function; accept only the SHA-* identifiers
+ \ (from SHA-1 to SHA-512, no MD5 here).
+ read8
+ dup dup 2 < swap 6 > or if ERR_INVALID_ALGORITHM fail then
+ >hash
+ read8
+ \ Get expected signature algorithm and compare with what
+ \ the server just sent. Expected value is 1 for RSA, 3
+ \ for ECDSA. Note that 'use-rsa' evaluates to -1 for RSA,
+ \ 0 for ECDSA.
+ use-rsa 1 << 3 + = ifnot ERR_INVALID_ALGORITHM fail then
+ else
+ \ For MD5+SHA-1, we set 'hash' to 0.
+ use-rsa if 0 >hash then
+ then
+
+ \ Read signature into the pad.
+ read16 dup { sig-len }
+
+ dup 512 > if ERR_LIMIT_EXCEEDED fail then
+ addr-pad swap read-blob
+
+ \ Verify signature.
+ hash use-rsa sig-len verify-SKE-sig
+ dup if fail then drop
+
+ 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 -- )
+ \ Read supported client authentication 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 set32
+
+ \ 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 ;
+
+cc: do-rsa-encrypt ( prf_id -- nlen ) {
+ int x;
+
+ x = make_pms_rsa(CTX, T0_POP());
+ if (x < 0) {
+ br_ssl_engine_fail(ENG, -x);
+ T0_CO();
+ } else {
+ T0_PUSH(x);
+ }
+}
+
+cc: do-ecdh ( echde prf_id -- ulen ) {
+ unsigned prf_id = T0_POP();
+ unsigned ecdhe = T0_POP();
+ int x;
+
+ x = make_pms_ecdh(CTX, ecdhe, prf_id);
+ if (x < 0) {
+ br_ssl_engine_fail(ENG, -x);
+ T0_CO();
+ } else {
+ T0_PUSH(x);
+ }
+}
+
+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
+ dup use-rsa-keyx? if
+ prf-id do-rsa-encrypt
+ dup 2+ write24
+ dup write16
+ addr-pad swap write-blob
+ else
+ dup use-ecdhe? swap prf-id do-ecdh
+ dup 1+ write24
+ dup write8
+ 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.
+: do-handshake ( -- )
+ 0 addr-application_data set8
+ 22 addr-record_type_out set8
+ 0 addr-selected_protocol set16
+ multihash-init
+
+ write-ClientHello
+ flush-record
+ read-ServerHello
+
+ if
+ \ Session resumption.
+ -1 read-CCS-Finished
+ -1 write-CCS-Finished
+
+ else
+
+ \ Not a session resumption.
+
+ \ 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.
+ addr-cipher_suite get16 expected-key-type
+ CX 0 63 { BR_KEYTYPE_SIGN } and if
+ read-ServerKeyExchange
+ then
+
+ \ Get next header.
+ read-handshake-header
+
+ \ If this is a CertificateRequest, parse it, then read
+ \ next header.
+ dup 13 = if
+ drop read-contents-CertificateRequest
+ read-handshake-header
+ -1
+ else
+ 0
+ then
+ { seen-CR }
+
+ \ At that point, we should have a ServerHelloDone,
+ \ whose length must be 0.
+ 14 = ifnot ERR_UNEXPECTED fail then
+ if ERR_BAD_HELLO_DONE fail then
+
+ \ There should not be more bytes in the record at that point.
+ more-incoming-bytes? if ERR_UNEXPECTED fail then
+
+ seen-CR if
+ \ 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
+
+ -1 write-CCS-Finished
+ -1 read-CCS-Finished
+ then
+
+ \ Now we should be invoked only in case of renegotiation.
+ 1 addr-application_data set8
+ 23 addr-record_type_out set8 ;
+
+\ Read a HelloRequest message.
+: read-HelloRequest ( -- )
+ \ A HelloRequest has length 0 and type 0.
+ read-handshake-header-core
+ if ERR_UNEXPECTED fail then
+ if ERR_BAD_HANDSHAKE fail then ;
+
+\ Entry point.
+: main ( -- ! )
+ \ Perform initial handshake.
+ do-handshake
+
+ begin
+ \ Wait for further invocation. At that point, we should
+ \ get either an explicit call for renegotiation, or
+ \ an incoming HelloRequest handshake message.
+ wait-co
+ dup 0x07 and case
+ 0x00 of
+ 0x10 and if
+ do-handshake
+ then
+ endof
+ 0x01 of
+ drop
+ 0 addr-application_data set8
+ read-HelloRequest
+ \ Reject renegotiations if the peer does not
+ \ support secure renegotiation, or if the
+ \ "no renegotiation" flag is set.
+ addr-reneg get8 1 = 1 flag? or if
+ flush-record
+ begin can-output? not while
+ wait-co drop
+ repeat
+ 100 send-warning
+ \ We rejected the renegotiation,
+ \ but the connection is not dead.
+ \ We must set back things into
+ \ working "application data" state.
+ 1 addr-application_data set8
+ 23 addr-record_type_out set8
+ else
+ do-handshake
+ then
+ endof
+ ERR_UNEXPECTED fail
+ endcase
+ again
+ ;
diff --git a/test/monniaux/BearSSL/src/ssl/ssl_hs_common.t0 b/test/monniaux/BearSSL/src/ssl/ssl_hs_common.t0
new file mode 100644
index 00000000..4674891c
--- /dev/null
+++ b/test/monniaux/BearSSL/src/ssl/ssl_hs_common.t0
@@ -0,0 +1,1382 @@
+\ Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+\
+\ Permission is hereby granted, free of charge, to any person obtaining
+\ a copy of this software and associated documentation files (the
+\ "Software"), to deal in the Software without restriction, including
+\ without limitation the rights to use, copy, modify, merge, publish,
+\ distribute, sublicense, and/or sell copies of the Software, and to
+\ permit persons to whom the Software is furnished to do so, subject to
+\ the following conditions:
+\
+\ The above copyright notice and this permission notice shall be
+\ included in all copies or substantial portions of the Software.
+\
+\ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+\ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+\ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+\ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+\ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+\ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+\ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+\ SOFTWARE.
+
+\ ----------------------------------------------------------------------
+\ This is the common T0 code for processing handshake messages (code that
+\ is used by both client and server).
+
+preamble {
+
+#include <stddef.h>
+#include <string.h>
+
+#include "inner.h"
+
+/*
+ * This macro evaluates to a pointer to the current engine context.
+ */
+#define ENG ((br_ssl_engine_context *)(void *)((unsigned char *)t0ctx - offsetof(br_ssl_engine_context, cpu)))
+
+}
+
+\ IMPLEMENTATION NOTES
+\ ====================
+\
+\ This code handles all records except application data records.
+\ Application data is accepted (incoming records, outgoing payload data)
+\ only when the application_data flag is set, which is done at the end
+\ of the handshake; and it is cleared whenever a renegotiation or a
+\ closure takes place.
+\
+\ Incoming alerts are processed on the fly; fatal alerts terminate the
+\ context, while warnings are ignored, except for close_notify, which
+\ triggers the closure procedure. That procedure never returns (it ends
+\ with an 'ERR_OK fail' call). We can thus make this processing right
+\ into the read functions.
+\
+\ Specific actions from the caller (closure or renegotiation) may happen
+\ only when jumping back into the T0 code, i.e. just after a 'co' call.
+\ Similarly, incoming record type may change only while the caller has
+\ control, so we need to check that type only when returning from a 'co'.
+\
+\ The handshake processor needs to defer back to the caller ('co') only
+\ in one of the following situations:
+\
+\ -- Some handshake data is expected.
+\
+\ -- The handshake is finished, and application data may flow. There may
+\ be some incoming handshake data (HelloRequest from the server). This
+\ is the only situation where a renegotiation call won't be ignored.
+\
+\ -- Some change-cipher-spec data is expected.
+\
+\ -- An alert record is expected. Other types of incoming records will be
+\ skipped.
+\
+\ -- Waiting for the currently accumulated record to be sent and the
+\ output buffer to become free again for another record.
+
+\ Placeholder for handling not yet implemented functionalities.
+: NYI ( -- ! )
+ "NOT YET IMPLEMENTED!" puts cr -1 fail ;
+
+\ Debug function that prints a string (and a newline) on stderr.
+cc: DBG ( addr -- ) {
+ extern void *stderr;
+ extern int fprintf(void *, const char *, ...);
+ fprintf(stderr, "%s\n", &t0_datablock[T0_POPi()]);
+}
+
+\ Debug function that prints a string and an integer value (followed
+\ by a newline) on stderr.
+cc: DBG2 ( addr x -- ) {
+ extern void *stderr;
+ extern int fprintf(void *, const char *, ...);
+ int32_t x = T0_POPi();
+ fprintf(stderr, "%s: %ld (0x%08lX)\n",
+ &t0_datablock[T0_POPi()], (long)x, (unsigned long)(uint32_t)x);
+}
+
+\ Mark the context as failed with a specific error code. This also
+\ returns control to the caller.
+cc: fail ( err -- ! ) {
+ br_ssl_engine_fail(ENG, (int)T0_POPi());
+ T0_CO();
+}
+
+\ Read a byte from the context (address is offset in context).
+cc: get8 ( addr -- val ) {
+ size_t addr = (size_t)T0_POP();
+ T0_PUSH(*((unsigned char *)ENG + addr));
+}
+
+\ Read a 16-bit word from the context (address is offset in context).
+cc: get16 ( addr -- val ) {
+ size_t addr = (size_t)T0_POP();
+ T0_PUSH(*(uint16_t *)(void *)((unsigned char *)ENG + addr));
+}
+
+\ Read a 32-bit word from the context (address is offset in context).
+cc: get32 ( addr -- val ) {
+ size_t addr = (size_t)T0_POP();
+ T0_PUSH(*(uint32_t *)(void *)((unsigned char *)ENG + addr));
+}
+
+\ Set a byte in the context (address is offset in context).
+cc: set8 ( val addr -- ) {
+ size_t addr = (size_t)T0_POP();
+ *((unsigned char *)ENG + addr) = (unsigned char)T0_POP();
+}
+
+\ Set a 16-bit word in the context (address is offset in context).
+cc: set16 ( val addr -- ) {
+ size_t addr = (size_t)T0_POP();
+ *(uint16_t *)(void *)((unsigned char *)ENG + addr) = (uint16_t)T0_POP();
+}
+
+\ Set a 32-bit word in the context (address is offset in context).
+cc: set32 ( val addr -- ) {
+ size_t addr = (size_t)T0_POP();
+ *(uint32_t *)(void *)((unsigned char *)ENG + addr) = (uint32_t)T0_POP();
+}
+
+\ Define a word that evaluates as an address of a field within the
+\ engine context. The field name (C identifier) must follow in the
+\ source. For field 'foo', the defined word is 'addr-foo'.
+: addr-eng:
+ next-word { field }
+ "addr-" field + 0 1 define-word
+ 0 8191 "offsetof(br_ssl_engine_context, " field + ")" + make-CX
+ postpone literal postpone ; ;
+
+addr-eng: max_frag_len
+addr-eng: log_max_frag_len
+addr-eng: peer_log_max_frag_len
+addr-eng: shutdown_recv
+addr-eng: record_type_in
+addr-eng: record_type_out
+addr-eng: version_in
+addr-eng: version_out
+addr-eng: application_data
+addr-eng: version_min
+addr-eng: version_max
+addr-eng: suites_buf
+addr-eng: suites_num
+addr-eng: server_name
+addr-eng: client_random
+addr-eng: server_random
+addr-eng: ecdhe_curve
+addr-eng: ecdhe_point
+addr-eng: ecdhe_point_len
+addr-eng: reneg
+addr-eng: saved_finished
+addr-eng: flags
+addr-eng: pad
+addr-eng: action
+addr-eng: alert
+addr-eng: close_received
+addr-eng: protocol_names_num
+addr-eng: selected_protocol
+
+\ Similar to 'addr-eng:', for fields in the 'session' substructure.
+: addr-session-field:
+ next-word { field }
+ "addr-" field + 0 1 define-word
+ 0 8191 "offsetof(br_ssl_engine_context, session) + offsetof(br_ssl_session_parameters, " field + ")" + make-CX
+ postpone literal postpone ; ;
+
+addr-session-field: session_id
+addr-session-field: session_id_len
+addr-session-field: version
+addr-session-field: cipher_suite
+addr-session-field: master_secret
+
+\ Check a server flag by index.
+: flag? ( index -- bool )
+ addr-flags get32 swap >> 1 and neg ;
+
+\ Define a word that evaluates to an error constant. This assumes that
+\ all relevant error codes are in the 0..63 range.
+: err:
+ next-word { name }
+ name 0 1 define-word
+ 0 63 "BR_" name + make-CX postpone literal postpone ; ;
+
+err: ERR_OK
+err: ERR_BAD_PARAM
+err: ERR_BAD_STATE
+err: ERR_UNSUPPORTED_VERSION
+err: ERR_BAD_VERSION
+err: ERR_BAD_LENGTH
+err: ERR_TOO_LARGE
+err: ERR_BAD_MAC
+err: ERR_NO_RANDOM
+err: ERR_UNKNOWN_TYPE
+err: ERR_UNEXPECTED
+err: ERR_BAD_CCS
+err: ERR_BAD_ALERT
+err: ERR_BAD_HANDSHAKE
+err: ERR_OVERSIZED_ID
+err: ERR_BAD_CIPHER_SUITE
+err: ERR_BAD_COMPRESSION
+err: ERR_BAD_FRAGLEN
+err: ERR_BAD_SECRENEG
+err: ERR_EXTRA_EXTENSION
+err: ERR_BAD_SNI
+err: ERR_BAD_HELLO_DONE
+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 ) {
+ uint32_t x = ENG->iec == NULL ? 0 : ENG->iec->supported_curves;
+ T0_PUSH(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;
+
+ x = 0;
+ num = 0;
+ for (i = br_sha1_ID; i <= br_sha512_ID; i ++) {
+ if (br_multihash_getimpl(&ENG->mhash, i)) {
+ x |= 1U << i;
+ num ++;
+ }
+ }
+ T0_PUSH(x);
+ 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);
+}
+
+\ Flush the current record: if some payload data has been accumulated,
+\ close the record and schedule it for sending. If there is no such data,
+\ this function does nothing.
+cc: flush-record ( -- ) {
+ br_ssl_engine_flush_record(ENG);
+}
+
+\ Yield control to the caller.
+\ When the control is returned to us, react to the new context. Returned
+\ value is a bitwise combination of the following:
+\ 0x01 handshake data is available
+\ 0x02 change-cipher-spec data is available
+\ 0x04 some data other than handshake or change-cipher-spec is available
+\ 0x08 output buffer is ready for a new outgoing record
+\ 0x10 renegotiation is requested and not to be ignored
+\ Flags 0x01, 0x02 and 0x04 are mutually exclusive.
+: wait-co ( -- state )
+ co
+ 0
+ addr-action get8 dup if
+ case
+ 1 of 0 do-close endof
+ 2 of addr-application_data get8 1 = if
+ 0x10 or
+ then endof
+ endcase
+ else
+ drop
+ then
+ addr-close_received get8 ifnot
+ has-input? if
+ addr-record_type_in get8 case
+
+ \ ChangeCipherSpec
+ 20 of 0x02 or endof
+
+ \ Alert -- if close_notify received, trigger
+ \ the closure sequence.
+ 21 of process-alerts if -1 do-close then endof
+
+ \ Handshake
+ 22 of 0x01 or endof
+
+ \ Not CCS, Alert or Handshake.
+ drop 0x04 or 0
+ endcase
+ then
+ then
+ can-output? if 0x08 or then ;
+
+\ Send an alert message. This shall be called only when there is room for
+\ an outgoing record.
+: send-alert ( level alert -- )
+ 21 addr-record_type_out set8
+ swap write8-native drop write8-native drop
+ flush-record ;
+
+\ Send an alert message of level "warning". This shall be called only when
+\ there is room for an outgoing record.
+: send-warning ( alert -- )
+ 1 swap send-alert ;
+
+\ Fail by sending a fatal alert.
+: fail-alert ( alert -- ! )
+ { alert }
+ flush-record
+ begin can-output? not while wait-co drop repeat
+ 2 alert send-alert
+ begin can-output? not while wait-co drop repeat
+ alert 512 + fail ;
+
+\ Perform the close operation:
+\ -- Prevent new application data from the caller.
+\ -- Incoming data is discarded (except alerts).
+\ -- Outgoing data is flushed.
+\ -- A close_notify alert is sent.
+\ -- If 'cnr' is zero, then incoming data is discarded until a close_notify
+\ is received.
+\ -- At the end, the context is terminated.
+\
+\ cnr shall be either 0 or -1.
+: do-close ( cnr -- ! )
+ \ 'cnr' is set to non-zero when a close_notify is received from
+ \ the peer.
+ { cnr }
+
+ \ Get out of application data state. If we were accepting
+ \ application data (flag is 1), and we still expect a close_notify
+ \ from the peer (cnr is 0), then we should set the flag to 2.
+ \ In all other cases, flag should be set to 0.
+ addr-application_data get8 cnr not and 1 << addr-application_data set8
+
+ \ Flush existing payload if any.
+ flush-record
+
+ \ Wait for room to send the close_notify. Since individual records
+ \ can always hold at least 512 bytes, we know that when there is
+ \ room, then there is room for a complete close_notify (two bytes).
+ begin can-output? not while cnr wait-for-close >cnr repeat
+
+ \ Write the close_notify and flush it.
+ \ 21 addr-record_type_out set8
+ \ 1 write8-native 0 write8-native 2drop
+ \ flush-record
+ 0 send-warning
+
+ \ Loop until our record has been sent (we know it's gone when
+ \ writing is again possible) and a close_notify has been received.
+ cnr
+ begin
+ dup can-output? and if ERR_OK fail then
+ wait-for-close
+ again ;
+
+\ Yield control to the engine, with a possible flush. If 'cnr' is 0,
+\ then input is analysed: all input is discarded, until a close_notify
+\ is received.
+: wait-for-close ( cnr -- cnr )
+ co
+ dup ifnot
+ has-input? if
+ addr-record_type_in get8 21 = if
+ drop process-alerts
+ \ If we received a close_notify then we
+ \ no longer accept incoming application
+ \ data records.
+ 0 addr-application_data set8
+ else
+ discard-input
+ then
+ then
+ then ;
+
+\ Test whether there is some accumulated payload that still needs to be
+\ sent.
+cc: payload-to-send? ( -- bool ) {
+ T0_PUSHi(-br_ssl_engine_has_pld_to_send(ENG));
+}
+
+\ Test whether there is some available input data.
+cc: has-input? ( -- bool ) {
+ T0_PUSHi(-(ENG->hlen_in != 0));
+}
+
+\ Test whether some payload bytes may be written.
+cc: can-output? ( -- bool ) {
+ T0_PUSHi(-(ENG->hlen_out > 0));
+}
+
+\ Discard current input entirely.
+cc: discard-input ( -- ) {
+ ENG->hlen_in = 0;
+}
+
+\ Low-level read for one byte. If there is no available byte right
+\ away, then -1 is returned. Otherwise, the byte value is returned.
+\ If the current record type is "handshake" then the read byte is also
+\ injected in the multi-hasher.
+cc: read8-native ( -- x ) {
+ if (ENG->hlen_in > 0) {
+ unsigned char x;
+
+ x = *ENG->hbuf_in ++;
+ if (ENG->record_type_in == BR_SSL_HANDSHAKE) {
+ br_multihash_update(&ENG->mhash, &x, 1);
+ }
+ T0_PUSH(x);
+ ENG->hlen_in --;
+ } else {
+ T0_PUSHi(-1);
+ }
+}
+
+\ Low-level read for several bytes. On entry, this expects an address
+\ (offset in the engine context) and a length; these values designate
+\ where the chunk should go. Upon exit, the new address and length
+\ are pushed; that output length contains how many bytes could not be
+\ read. If there is no available byte for reading, the address and
+\ length are unchanged.
+\ If the current record type is "handshake" then the read bytes are
+\ injected in the multi-hasher.
+cc: read-chunk-native ( addr len -- addr len ) {
+ size_t clen = ENG->hlen_in;
+ if (clen > 0) {
+ uint32_t addr, len;
+
+ len = T0_POP();
+ addr = T0_POP();
+ if ((size_t)len < clen) {
+ clen = (size_t)len;
+ }
+ memcpy((unsigned char *)ENG + addr, ENG->hbuf_in, clen);
+ if (ENG->record_type_in == BR_SSL_HANDSHAKE) {
+ br_multihash_update(&ENG->mhash, ENG->hbuf_in, clen);
+ }
+ T0_PUSH(addr + (uint32_t)clen);
+ T0_PUSH(len - (uint32_t)clen);
+ ENG->hbuf_in += clen;
+ ENG->hlen_in -= clen;
+ }
+}
+
+\ Process available alert bytes. If a fatal alert is received, then the
+\ context is terminated; otherwise, this returns either true (-1) if a
+\ close_notify was received, false (0) otherwise.
+: process-alerts ( -- bool )
+ 0
+ begin has-input? while read8-native process-alert-byte or repeat
+ dup if 1 addr-shutdown_recv set8 then ;
+
+\ Process an alert byte. Returned value is non-zero if this is a close_notify,
+\ zero otherwise.
+: process-alert-byte ( x -- bool )
+ addr-alert get8 case
+ 0 of
+ \ 'alert' field is 0, so this byte shall be a level.
+ \ Levels shall be 1 (warning) or 2 (fatal); we convert
+ \ all other values to "fatal".
+ dup 1 <> if drop 2 then
+ addr-alert set8 0
+ endof
+ 1 of
+ 0 addr-alert set8
+ \ close_notify has value 0.
+ \ no_renegotiation has value 100, and we treat it
+ \ as a fatal alert.
+ dup 100 = if 256 + fail then
+ 0=
+ endof
+ \ Fatal alert implies context termination.
+ drop 256 + fail
+ endcase ;
+
+\ In general we only deal with handshake data here. Alerts are processed
+\ in specific code right when they are received, and ChangeCipherSpec has
+\ its own handling code. So we need to check that the data is "handshake"
+\ only when returning from a coroutine call.
+
+\ Yield control to the engine. Alerts are processed; if incoming data is
+\ neither handshake or alert, then an error is triggered.
+: wait-for-handshake ( -- )
+ wait-co 0x07 and 0x01 > if ERR_UNEXPECTED fail then ;
+
+\ Flush outgoing data (if any), then wait for the output buffer to be
+\ clear; when this is done, set the output record type to the specified
+\ value.
+: wait-rectype-out ( rectype -- )
+ { rectype }
+ flush-record
+ begin
+ can-output? if rectype addr-record_type_out set8 ret then
+ wait-co drop
+ again ;
+
+\ Read one byte of handshake data. Block until that byte is available.
+\ This does not check any length.
+: read8-nc ( -- x )
+ begin
+ read8-native dup 0< ifnot ret then
+ drop wait-for-handshake
+ again ;
+
+\ Test whether there are some more bytes in the current record. These
+\ bytes have not necessarily been received yet (processing of unencrypted
+\ records may begin before all bytes are received).
+cc: more-incoming-bytes? ( -- bool ) {
+ T0_PUSHi(ENG->hlen_in != 0 || !br_ssl_engine_recvrec_finished(ENG));
+}
+
+\ For reading functions, the TOS is supposed to contain the number of bytes
+\ that can still be read (from encapsulating structure header), and it is
+\ updated.
+
+: check-len ( lim len -- lim )
+ - dup 0< if ERR_BAD_PARAM fail then ;
+
+\ Read one byte of handshake data. This pushes an integer in the 0..255 range.
+: read8 ( lim -- lim x )
+ 1 check-len read8-nc ;
+
+\ Read a 16-bit value (in the 0..65535 range)
+: read16 ( lim -- lim n )
+ 2 check-len read8-nc 8 << read8-nc + ;
+
+\ Read a 24-bit value (in the 0..16777215 range)
+: read24 ( lim -- lim n )
+ 3 check-len read8-nc 8 << read8-nc + 8 << read8-nc + ;
+
+\ Read some bytes. The "address" is an offset within the context
+\ structure.
+: read-blob ( lim addr len -- lim )
+ { addr len }
+ len check-len
+ addr len
+ begin
+ read-chunk-native
+ dup 0 = if 2drop ret then
+ wait-for-handshake
+ again ;
+
+\ Read some bytes and drop them.
+: skip-blob ( lim len -- lim )
+ swap over check-len swap
+ begin dup while read8-nc drop 1- repeat
+ drop ;
+
+\ Read a 16-bit length, then skip exactly that many bytes.
+: read-ignore-16 ( lim -- lim )
+ read16 skip-blob ;
+
+\ Open a substructure: the inner structure length is checked against,
+\ and subtracted, from the output structure current limit.
+: open-elt ( lim len -- lim-outer lim-inner )
+ dup { len }
+ - dup 0< if ERR_BAD_PARAM fail then
+ len ;
+
+\ Close the current structure. This checks that the limit is 0.
+: close-elt ( lim -- )
+ if ERR_BAD_PARAM fail then ;
+
+\ Write one byte of handshake data.
+: write8 ( n -- )
+ begin
+ dup write8-native if drop ret then
+ wait-co drop
+ again ;
+
+\ Low-level write for one byte. On exit, it pushes either -1 (byte was
+\ written) or 0 (no room in output buffer).
+cc: write8-native ( x -- bool ) {
+ unsigned char x;
+
+ x = (unsigned char)T0_POP();
+ if (ENG->hlen_out > 0) {
+ if (ENG->record_type_out == BR_SSL_HANDSHAKE) {
+ br_multihash_update(&ENG->mhash, &x, 1);
+ }
+ *ENG->hbuf_out ++ = x;
+ ENG->hlen_out --;
+ T0_PUSHi(-1);
+ } else {
+ T0_PUSHi(0);
+ }
+}
+
+\ Write a 16-bit value.
+: write16 ( n -- )
+ dup 8 u>> write8 write8 ;
+
+\ Write a 24-bit value.
+: write24 ( n -- )
+ dup 16 u>> write8 write16 ;
+
+\ Write some bytes. The "address" is an offset within the context
+\ structure.
+: write-blob ( addr len -- )
+ begin
+ write-blob-chunk
+ dup 0 = if 2drop ret then
+ wait-co drop
+ again ;
+
+cc: write-blob-chunk ( addr len -- addr len ) {
+ size_t clen = ENG->hlen_out;
+ if (clen > 0) {
+ uint32_t addr, len;
+
+ len = T0_POP();
+ addr = T0_POP();
+ if ((size_t)len < clen) {
+ clen = (size_t)len;
+ }
+ memcpy(ENG->hbuf_out, (unsigned char *)ENG + addr, clen);
+ if (ENG->record_type_out == BR_SSL_HANDSHAKE) {
+ br_multihash_update(&ENG->mhash, ENG->hbuf_out, clen);
+ }
+ T0_PUSH(addr + (uint32_t)clen);
+ T0_PUSH(len - (uint32_t)clen);
+ ENG->hbuf_out += clen;
+ ENG->hlen_out -= clen;
+ }
+}
+
+\ Write a blob with the length as header (over one byte)
+: write-blob-head8 ( addr len -- )
+ dup write8 write-blob ;
+
+\ Write a blob with the length as header (over two bytes)
+: write-blob-head16 ( addr len -- )
+ dup write16 write-blob ;
+
+\ Perform a byte-to-byte comparison between two blobs. Each blob is
+\ provided as an "address" (offset in the context structure); the
+\ length is common. Returned value is true (-1) if the two blobs are
+\ equal, false (0) otherwise.
+cc: memcmp ( addr1 addr2 len -- bool ) {
+ size_t len = (size_t)T0_POP();
+ void *addr2 = (unsigned char *)ENG + (size_t)T0_POP();
+ void *addr1 = (unsigned char *)ENG + (size_t)T0_POP();
+ int x = memcmp(addr1, addr2, len);
+ T0_PUSH((uint32_t)-(x == 0));
+}
+
+\ Copy bytes between two areas, whose addresses are provided as
+\ offsets in the context structure.
+cc: memcpy ( dst src len -- ) {
+ size_t len = (size_t)T0_POP();
+ void *src = (unsigned char *)ENG + (size_t)T0_POP();
+ void *dst = (unsigned char *)ENG + (size_t)T0_POP();
+ memcpy(dst, src, len);
+}
+
+\ Get string length (zero-terminated). The string address is provided as
+\ an offset relative to the context start. Returned length does not include
+\ the terminated 0.
+cc: strlen ( str -- len ) {
+ void *str = (unsigned char *)ENG + (size_t)T0_POP();
+ T0_PUSH((uint32_t)strlen(str));
+}
+
+\ Fill a buffer with zeros. The buffer address is an offset in the context.
+cc: bzero ( addr len -- ) {
+ size_t len = (size_t)T0_POP();
+ void *addr = (unsigned char *)ENG + (size_t)T0_POP();
+ memset(addr, 0, len);
+}
+
+\ Scan the list of supported cipher suites for a given value. If found,
+\ then the list index at which it was found is returned; otherwise, -1
+\ is returned.
+: scan-suite ( suite -- index )
+ { suite }
+ addr-suites_num get8 { num }
+ 0
+ begin dup num < while
+ dup 1 << addr-suites_buf + get16 suite = if ret then
+ 1+
+ repeat
+ drop -1 ;
+
+\ =======================================================================
+
+\ Generate random bytes into buffer (address is offset in context).
+cc: mkrand ( addr len -- ) {
+ size_t len = (size_t)T0_POP();
+ void *addr = (unsigned char *)ENG + (size_t)T0_POP();
+ br_hmac_drbg_generate(&ENG->rng, addr, len);
+}
+
+\ Read a handshake message header: type and length. These are returned
+\ in reverse order (type is TOS, length is below it).
+: read-handshake-header-core ( -- lim type )
+ read8-nc 3 read24 swap drop swap ;
+
+\ Read a handshake message header: type and length. If the header is for
+\ a HelloRequest message, then it is discarded and a new header is read
+\ (repeatedly if necessary).
+: read-handshake-header ( -- lim type )
+ begin
+ read-handshake-header-core dup 0= while
+ drop if ERR_BAD_HANDSHAKE fail then
+ repeat ;
+
+\ =======================================================================
+
+\ Cipher suite processing.
+\
+\ Unfortunately, cipher suite identifiers are attributed mostly arbitrary,
+\ so we have to map the cipher suite numbers we support into aggregate
+\ words that encode the information we need. Table below is organized
+\ as a sequence of pairs of 16-bit words, the first being the cipher suite
+\ identifier, the second encoding the algorithm elements. The suites are
+\ ordered by increasing cipher suite ID, so that fast lookups may be
+\ performed with a binary search (not implemented for the moment, since it
+\ does not appear to matter much in practice).
+\
+\ Algorithm elements are encoded over 4 bits each, in the following order
+\ (most significant to least significant):
+\
+\ -- Server key type:
+\ 0 RSA (RSA key exchange)
+\ 1 ECDHE-RSA (ECDHE key exchange, RSA signature)
+\ 2 ECDHE-ECDSA (ECDHE key exchange, ECDSA signature)
+\ 3 ECDH-RSA (ECDH key exchange, certificate is RSA-signed)
+\ 4 ECDH-ECDSA (ECDH key exchange, certificate is ECDSA-signed)
+\ -- Encryption algorithm:
+\ 0 3DES/CBC
+\ 1 AES-128/CBC
+\ 2 AES-256/CBC
+\ 3 AES-128/GCM
+\ 4 AES-256/GCM
+\ 5 ChaCha20/Poly1305
+\ 6 AES-128/CCM
+\ 7 AES-256/CCM
+\ 8 AES-128/CCM8
+\ 9 AES-256/CCM8
+\ -- MAC algorithm:
+\ 0 none (for suites with AEAD encryption)
+\ 2 HMAC/SHA-1
+\ 4 HMAC/SHA-256
+\ 5 HMAC/SHA-384
+\ -- PRF for TLS-1.2:
+\ 4 with SHA-256
+\ 5 with SHA-384
+\
+\ WARNING: if adding a new cipher suite that does not use SHA-256 for the
+\ PRF (with TLS 1.2), be sure to check the suites_sha384[] array defined
+\ in ssl/ssl_keyexport.c
+
+data: cipher-suite-def
+
+hexb| 000A 0024 | \ TLS_RSA_WITH_3DES_EDE_CBC_SHA
+hexb| 002F 0124 | \ TLS_RSA_WITH_AES_128_CBC_SHA
+hexb| 0035 0224 | \ TLS_RSA_WITH_AES_256_CBC_SHA
+hexb| 003C 0144 | \ TLS_RSA_WITH_AES_128_CBC_SHA256
+hexb| 003D 0244 | \ TLS_RSA_WITH_AES_256_CBC_SHA256
+
+hexb| 009C 0304 | \ TLS_RSA_WITH_AES_128_GCM_SHA256
+hexb| 009D 0405 | \ TLS_RSA_WITH_AES_256_GCM_SHA384
+
+hexb| C003 4024 | \ TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA
+hexb| C004 4124 | \ TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA
+hexb| C005 4224 | \ TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA
+hexb| C008 2024 | \ TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA
+hexb| C009 2124 | \ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
+hexb| C00A 2224 | \ TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
+hexb| C00D 3024 | \ TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA
+hexb| C00E 3124 | \ TLS_ECDH_RSA_WITH_AES_128_CBC_SHA
+hexb| C00F 3224 | \ TLS_ECDH_RSA_WITH_AES_256_CBC_SHA
+hexb| C012 1024 | \ TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA
+hexb| C013 1124 | \ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
+hexb| C014 1224 | \ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
+
+hexb| C023 2144 | \ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
+hexb| C024 2255 | \ TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
+hexb| C025 4144 | \ TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256
+hexb| C026 4255 | \ TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384
+hexb| C027 1144 | \ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
+hexb| C028 1255 | \ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
+hexb| C029 3144 | \ TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256
+hexb| C02A 3255 | \ TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384
+hexb| C02B 2304 | \ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
+hexb| C02C 2405 | \ TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
+hexb| C02D 4304 | \ TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256
+hexb| C02E 4405 | \ TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384
+hexb| C02F 1304 | \ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
+hexb| C030 1405 | \ TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
+hexb| C031 3304 | \ TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256
+hexb| C032 3405 | \ TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384
+
+hexb| C09C 0604 | \ TLS_RSA_WITH_AES_128_CCM
+hexb| C09D 0704 | \ TLS_RSA_WITH_AES_256_CCM
+hexb| C0A0 0804 | \ TLS_RSA_WITH_AES_128_CCM_8
+hexb| C0A1 0904 | \ TLS_RSA_WITH_AES_256_CCM_8
+hexb| C0AC 2604 | \ TLS_ECDHE_ECDSA_WITH_AES_128_CCM
+hexb| C0AD 2704 | \ TLS_ECDHE_ECDSA_WITH_AES_256_CCM
+hexb| C0AE 2804 | \ TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8
+hexb| C0AF 2904 | \ TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8
+
+hexb| CCA8 1504 | \ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
+hexb| CCA9 2504 | \ TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
+
+hexb| 0000 | \ List terminator.
+
+\ Convert cipher suite identifier to element words. This returns 0 if
+\ the cipher suite is not known.
+: cipher-suite-to-elements ( suite -- elts )
+ { id }
+ cipher-suite-def
+ begin
+ dup 2+ swap data-get16
+ dup ifnot 2drop 0 ret then
+ id = if data-get16 ret then
+ 2+
+ again ;
+
+\ Check that a given cipher suite is supported. Note that this also
+\ returns true (-1) for the TLS_FALLBACK_SCSV pseudo-ciphersuite.
+: suite-supported? ( suite -- bool )
+ dup 0x5600 = if drop -1 ret then
+ cipher-suite-to-elements 0<> ;
+
+\ Get expected key type for cipher suite. The key type is one of
+\ BR_KEYTYPE_RSA or BR_KEYTYPE_EC, combined with either BR_KEYTYPE_KEYX
+\ (RSA encryption or static ECDH) or BR_KEYTYPE_SIGN (RSA or ECDSA
+\ signature, for ECDHE cipher suites).
+: expected-key-type ( suite -- key-type )
+ cipher-suite-to-elements 12 >>
+ case
+ 0 of CX 0 63 { BR_KEYTYPE_RSA | BR_KEYTYPE_KEYX } endof
+ 1 of CX 0 63 { BR_KEYTYPE_RSA | BR_KEYTYPE_SIGN } endof
+ 2 of CX 0 63 { BR_KEYTYPE_EC | BR_KEYTYPE_SIGN } endof
+ 3 of CX 0 63 { BR_KEYTYPE_EC | BR_KEYTYPE_KEYX } endof
+ 4 of CX 0 63 { BR_KEYTYPE_EC | BR_KEYTYPE_KEYX } endof
+ 0 swap
+ endcase ;
+
+\ Test whether the cipher suite uses RSA key exchange.
+: use-rsa-keyx? ( suite -- bool )
+ cipher-suite-to-elements 12 >> 0= ;
+
+\ Test whether the cipher suite uses ECDHE key exchange, signed with RSA.
+: use-rsa-ecdhe? ( suite -- bool )
+ cipher-suite-to-elements 12 >> 1 = ;
+
+\ Test whether the cipher suite uses ECDHE key exchange, signed with ECDSA.
+: use-ecdsa-ecdhe? ( suite -- bool )
+ cipher-suite-to-elements 12 >> 2 = ;
+
+\ Test whether the cipher suite uses ECDHE key exchange (with RSA or ECDSA).
+: use-ecdhe? ( suite -- bool )
+ cipher-suite-to-elements 12 >> dup 0> swap 3 < and ;
+
+\ Test whether the cipher suite uses ECDH (static) key exchange.
+: use-ecdh? ( suite -- bool )
+ cipher-suite-to-elements 12 >> 2 > ;
+
+\ Get identifier for the PRF (TLS 1.2).
+: prf-id ( suite -- id )
+ cipher-suite-to-elements 15 and ;
+
+\ Test whether a cipher suite is only for TLS-1.2. Cipher suites that
+\ can be used with TLS-1.0 or 1.1 use HMAC/SHA-1. RFC do not formally
+\ forbid using a CBC-based TLS-1.2 cipher suite, e.g. based on HMAC/SHA-256,
+\ with older protocol versions; however, servers should not do that, since
+\ it may confuse clients. Since the server code does not try such games,
+\ for consistency, the client should reject it as well (normal servers
+\ don't do that, so any attempt is a sign of foul play).
+: use-tls12? ( suite -- bool )
+ cipher-suite-to-elements 0xF0 and 0x20 <> ;
+
+\ Switch to negotiated security parameters for input or output.
+: switch-encryption ( is-client for-input -- )
+ { for-input }
+ addr-cipher_suite get16 cipher-suite-to-elements { elts }
+
+ \ prf_id
+ elts 15 and
+
+ \ mac_id
+ elts 4 >> 15 and
+
+ \ cipher type and key length
+ elts 8 >> 15 and case
+ \ 3DES/CBC
+ 0 of 0 24
+ for-input if
+ switch-cbc-in
+ else
+ switch-cbc-out
+ then
+ endof
+
+ \ AES-128/CBC
+ 1 of 1 16
+ for-input if
+ switch-cbc-in
+ else
+ switch-cbc-out
+ then
+ endof
+
+ \ AES-256/CBC
+ 2 of 1 32
+ for-input if
+ switch-cbc-in
+ else
+ switch-cbc-out
+ then
+ endof
+
+ \ AES-128/GCM
+ 3 of drop 16
+ for-input if
+ switch-aesgcm-in
+ else
+ switch-aesgcm-out
+ then
+ endof
+
+ \ AES-256/GCM
+ 4 of drop 32
+ for-input if
+ switch-aesgcm-in
+ else
+ switch-aesgcm-out
+ then
+ endof
+
+ \ ChaCha20+Poly1305
+ 5 of drop
+ for-input if
+ switch-chapol-in
+ else
+ switch-chapol-out
+ then
+ endof
+
+ \ Now we only have AES/CCM suites (6 to 9). Since the
+ \ input is between 0 and 15, and we checked values 0 to 5,
+ \ we only need to reject values larger than 9.
+ dup 9 > if
+ ERR_BAD_PARAM fail
+ then
+
+ \ Stack: is_client prf_id mac_id cipher_id
+ \ We want to remove the mac_id (it is zero for CCM suites)
+ \ and replace the cipher_id with the key and tag lengths.
+ \ The following table applies:
+ \ id key length tag length
+ \ 6 16 16
+ \ 7 32 16
+ \ 8 16 8
+ \ 9 32 8
+ swap drop
+ dup 1 and 4 << 16 + swap
+ 8 and 16 swap -
+ for-input if
+ switch-aesccm-in
+ else
+ switch-aesccm-out
+ then
+ ret
+ endcase
+ ;
+
+cc: switch-cbc-out ( is_client prf_id mac_id aes cipher_key_len -- ) {
+ int is_client, prf_id, mac_id, aes;
+ unsigned cipher_key_len;
+
+ cipher_key_len = T0_POP();
+ aes = T0_POP();
+ mac_id = T0_POP();
+ prf_id = T0_POP();
+ is_client = T0_POP();
+ br_ssl_engine_switch_cbc_out(ENG, is_client, prf_id, mac_id,
+ aes ? ENG->iaes_cbcenc : ENG->ides_cbcenc, cipher_key_len);
+}
+
+cc: switch-cbc-in ( is_client prf_id mac_id aes cipher_key_len -- ) {
+ int is_client, prf_id, mac_id, aes;
+ unsigned cipher_key_len;
+
+ cipher_key_len = T0_POP();
+ aes = T0_POP();
+ mac_id = T0_POP();
+ prf_id = T0_POP();
+ is_client = T0_POP();
+ br_ssl_engine_switch_cbc_in(ENG, is_client, prf_id, mac_id,
+ aes ? ENG->iaes_cbcdec : ENG->ides_cbcdec, cipher_key_len);
+}
+
+cc: switch-aesgcm-out ( is_client prf_id cipher_key_len -- ) {
+ int is_client, prf_id;
+ unsigned cipher_key_len;
+
+ cipher_key_len = T0_POP();
+ prf_id = T0_POP();
+ is_client = T0_POP();
+ br_ssl_engine_switch_gcm_out(ENG, is_client, prf_id,
+ ENG->iaes_ctr, cipher_key_len);
+}
+
+cc: switch-aesgcm-in ( is_client prf_id cipher_key_len -- ) {
+ int is_client, prf_id;
+ unsigned cipher_key_len;
+
+ cipher_key_len = T0_POP();
+ prf_id = T0_POP();
+ is_client = T0_POP();
+ br_ssl_engine_switch_gcm_in(ENG, is_client, prf_id,
+ ENG->iaes_ctr, cipher_key_len);
+}
+
+cc: switch-chapol-out ( is_client prf_id -- ) {
+ int is_client, prf_id;
+
+ prf_id = T0_POP();
+ is_client = T0_POP();
+ br_ssl_engine_switch_chapol_out(ENG, is_client, prf_id);
+}
+
+cc: switch-chapol-in ( is_client prf_id -- ) {
+ int is_client, prf_id;
+
+ prf_id = T0_POP();
+ is_client = T0_POP();
+ br_ssl_engine_switch_chapol_in(ENG, is_client, prf_id);
+}
+
+cc: switch-aesccm-out ( is_client prf_id cipher_key_len tag_len -- ) {
+ int is_client, prf_id;
+ unsigned cipher_key_len, tag_len;
+
+ tag_len = T0_POP();
+ cipher_key_len = T0_POP();
+ prf_id = T0_POP();
+ is_client = T0_POP();
+ br_ssl_engine_switch_ccm_out(ENG, is_client, prf_id,
+ ENG->iaes_ctrcbc, cipher_key_len, tag_len);
+}
+
+cc: switch-aesccm-in ( is_client prf_id cipher_key_len tag_len -- ) {
+ int is_client, prf_id;
+ unsigned cipher_key_len, tag_len;
+
+ tag_len = T0_POP();
+ cipher_key_len = T0_POP();
+ prf_id = T0_POP();
+ is_client = T0_POP();
+ br_ssl_engine_switch_ccm_in(ENG, is_client, prf_id,
+ ENG->iaes_ctrcbc, cipher_key_len, tag_len);
+}
+
+\ Write Finished message.
+: write-Finished ( from_client -- )
+ compute-Finished
+ 20 write8 12 write24 addr-pad 12 write-blob ;
+
+\ Read Finished message.
+: read-Finished ( from_client -- )
+ compute-Finished
+ read-handshake-header 20 <> if ERR_UNEXPECTED fail then
+ addr-pad 12 + 12 read-blob
+ close-elt
+ addr-pad dup 12 + 12 memcmp ifnot ERR_BAD_FINISHED fail then ;
+
+\ Compute the "Finished" contents (either the value to send, or the
+\ expected value). The 12-byte string is written in the pad. The
+\ "from_client" value is non-zero for the Finished sent by the client.
+\ The computed value is also saved in the relevant buffer for handling
+\ secure renegotiation.
+: compute-Finished ( from_client -- )
+ dup addr-saved_finished swap ifnot 12 + then swap
+ addr-cipher_suite get16 prf-id compute-Finished-inner
+ addr-pad 12 memcpy ;
+
+cc: compute-Finished-inner ( from_client prf_id -- ) {
+ int prf_id = T0_POP();
+ int from_client = T0_POPi();
+ unsigned char tmp[48];
+ br_tls_prf_seed_chunk seed;
+
+ br_tls_prf_impl prf = br_ssl_engine_get_PRF(ENG, prf_id);
+ seed.data = tmp;
+ if (ENG->session.version >= BR_TLS12) {
+ seed.len = br_multihash_out(&ENG->mhash, prf_id, tmp);
+ } else {
+ br_multihash_out(&ENG->mhash, br_md5_ID, tmp);
+ br_multihash_out(&ENG->mhash, br_sha1_ID, tmp + 16);
+ seed.len = 36;
+ }
+ prf(ENG->pad, 12, ENG->session.master_secret,
+ sizeof ENG->session.master_secret,
+ from_client ? "client finished" : "server finished",
+ 1, &seed);
+}
+
+\ Receive ChangeCipherSpec and Finished from the peer.
+: read-CCS-Finished ( is-client -- )
+ has-input? if
+ addr-record_type_in get8 20 <> if ERR_UNEXPECTED fail then
+ else
+ begin
+ wait-co 0x07 and dup 0x02 <> while
+ if ERR_UNEXPECTED fail then
+ repeat
+ drop
+ then
+ read8-nc 1 <> more-incoming-bytes? or if ERR_BAD_CCS fail then
+ dup 1 switch-encryption
+
+ \ Read and verify Finished from peer.
+ not read-Finished ;
+
+\ Send ChangeCipherSpec and Finished to the peer.
+: write-CCS-Finished ( is-client -- )
+ \ Flush and wait for output buffer to be clear, so that we may
+ \ write our ChangeCipherSpec. We must switch immediately after
+ \ triggering the flush.
+ 20 wait-rectype-out
+ 1 write8
+ flush-record
+ dup 0 switch-encryption
+ 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 }
+
+ \ If hash is 0x08 then this is a "new algorithm" identifier,
+ \ and we set the corresponding bit if it is in the 0..15
+ \ range. Otherwise, we keep the value only if the signature
+ \ is either 1 (RSA) or 3 (ECDSA), and the hash is one of the
+ \ SHA-* functions (2 to 6). Note that we reject MD5.
+ hash 8 = if
+ sign 15 <= if
+ 1 sign 16 + << hashes or >hashes
+ then
+ else
+ hash 2 >= hash 6 <= and
+ sign 1 = sign 3 = or
+ and if
+ hashes 1 sign 1- 2 << hash + << or >hashes
+ then
+ 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 ;
+
+\ =======================================================================
+
+\ Copy a specific protocol name from the list to the pad. The byte
+\ length is returned.
+cc: copy-protocol-name ( idx -- len ) {
+ size_t idx = T0_POP();
+ size_t len = strlen(ENG->protocol_names[idx]);
+ memcpy(ENG->pad, ENG->protocol_names[idx], len);
+ T0_PUSH(len);
+}
+
+\ Compare name in pad with the configured list of protocol names.
+\ If a match is found, then the index is returned; otherwise, -1
+\ is returned.
+cc: test-protocol-name ( len -- n ) {
+ size_t len = T0_POP();
+ size_t u;
+
+ for (u = 0; u < ENG->protocol_names_num; u ++) {
+ const char *name;
+
+ name = ENG->protocol_names[u];
+ if (len == strlen(name) && memcmp(ENG->pad, name, len) == 0) {
+ T0_PUSH(u);
+ T0_RET();
+ }
+ }
+ T0_PUSHi(-1);
+}
diff --git a/test/monniaux/BearSSL/src/ssl/ssl_hs_server.c b/test/monniaux/BearSSL/src/ssl/ssl_hs_server.c
new file mode 100644
index 00000000..5f8cae79
--- /dev/null
+++ b/test/monniaux/BearSSL/src/ssl/ssl_hs_server.c
@@ -0,0 +1,2009 @@
+/* Automatically generated code; do not modify directly. */
+
+#include <stddef.h>
+#include <stdint.h>
+
+typedef struct {
+ uint32_t *dp;
+ uint32_t *rp;
+ const unsigned char *ip;
+} t0_context;
+
+static uint32_t
+t0_parse7E_unsigned(const unsigned char **p)
+{
+ uint32_t x;
+
+ x = 0;
+ for (;;) {
+ unsigned y;
+
+ y = *(*p) ++;
+ x = (x << 7) | (uint32_t)(y & 0x7F);
+ if (y < 0x80) {
+ return x;
+ }
+ }
+}
+
+static int32_t
+t0_parse7E_signed(const unsigned char **p)
+{
+ int neg;
+ uint32_t x;
+
+ neg = ((**p) >> 6) & 1;
+ x = (uint32_t)-neg;
+ for (;;) {
+ unsigned y;
+
+ y = *(*p) ++;
+ x = (x << 7) | (uint32_t)(y & 0x7F);
+ if (y < 0x80) {
+ if (neg) {
+ return -(int32_t)~x - 1;
+ } else {
+ return (int32_t)x;
+ }
+ }
+ }
+}
+
+#define T0_VBYTE(x, n) (unsigned char)((((uint32_t)(x) >> (n)) & 0x7F) | 0x80)
+#define T0_FBYTE(x, n) (unsigned char)(((uint32_t)(x) >> (n)) & 0x7F)
+#define T0_SBYTE(x) (unsigned char)((((uint32_t)(x) >> 28) + 0xF8) ^ 0xF8)
+#define T0_INT1(x) T0_FBYTE(x, 0)
+#define T0_INT2(x) T0_VBYTE(x, 7), T0_FBYTE(x, 0)
+#define T0_INT3(x) T0_VBYTE(x, 14), T0_VBYTE(x, 7), T0_FBYTE(x, 0)
+#define T0_INT4(x) T0_VBYTE(x, 21), T0_VBYTE(x, 14), T0_VBYTE(x, 7), T0_FBYTE(x, 0)
+#define T0_INT5(x) T0_SBYTE(x), T0_VBYTE(x, 21), T0_VBYTE(x, 14), T0_VBYTE(x, 7), T0_FBYTE(x, 0)
+
+/* static const unsigned char t0_datablock[]; */
+
+
+void br_ssl_hs_server_init_main(void *t0ctx);
+
+void br_ssl_hs_server_run(void *t0ctx);
+
+
+
+#include <stddef.h>
+#include <string.h>
+
+#include "inner.h"
+
+/*
+ * This macro evaluates to a pointer to the current engine context.
+ */
+#define ENG ((br_ssl_engine_context *)(void *)((unsigned char *)t0ctx - offsetof(br_ssl_engine_context, cpu)))
+
+
+
+
+
+/*
+ * This macro evaluates to a pointer to the server context, under that
+ * specific name. It must be noted that since the engine context is the
+ * first field of the br_ssl_server_context structure ('eng'), then
+ * pointers values of both types are interchangeable, modulo an
+ * appropriate cast. This also means that "addresses" computed as offsets
+ * within the structure work for both kinds of context.
+ */
+#define CTX ((br_ssl_server_context *)ENG)
+
+/*
+ * Decrypt the pre-master secret (RSA key exchange).
+ */
+static void
+do_rsa_decrypt(br_ssl_server_context *ctx, int prf_id,
+ unsigned char *epms, size_t len)
+{
+ uint32_t x;
+ unsigned char rpms[48];
+
+ /*
+ * Decrypt the PMS.
+ */
+ x = (*ctx->policy_vtable)->do_keyx(ctx->policy_vtable, epms, &len);
+
+ /*
+ * Set the first two bytes to the maximum supported client
+ * protocol version. These bytes are used for version rollback
+ * detection; forceing the two bytes will make the master secret
+ * wrong if the bytes are not correct. This process is
+ * recommended by RFC 5246 (section 7.4.7.1).
+ */
+ br_enc16be(epms, ctx->client_max_version);
+
+ /*
+ * Make a random PMS and copy it above the decrypted value if the
+ * decryption failed. Note that we use a constant-time conditional
+ * copy.
+ */
+ br_hmac_drbg_generate(&ctx->eng.rng, rpms, sizeof rpms);
+ br_ccopy(x ^ 1, epms, rpms, sizeof rpms);
+
+ /*
+ * Compute master secret.
+ */
+ br_ssl_engine_compute_master(&ctx->eng, prf_id, epms, 48);
+
+ /*
+ * Clear the pre-master secret from RAM: it is normally a buffer
+ * in the context, hence potentially long-lived.
+ */
+ memset(epms, 0, len);
+}
+
+/*
+ * Common part for ECDH and ECDHE.
+ */
+static void
+ecdh_common(br_ssl_server_context *ctx, int prf_id,
+ unsigned char *xcoor, size_t xcoor_len, uint32_t ctl)
+{
+ unsigned char rpms[80];
+
+ if (xcoor_len > sizeof rpms) {
+ xcoor_len = sizeof rpms;
+ ctl = 0;
+ }
+
+ /*
+ * Make a random PMS and copy it above the decrypted value if the
+ * decryption failed. Note that we use a constant-time conditional
+ * copy.
+ */
+ br_hmac_drbg_generate(&ctx->eng.rng, rpms, xcoor_len);
+ br_ccopy(ctl ^ 1, xcoor, rpms, xcoor_len);
+
+ /*
+ * Compute master secret.
+ */
+ br_ssl_engine_compute_master(&ctx->eng, prf_id, xcoor, xcoor_len);
+
+ /*
+ * Clear the pre-master secret from RAM: it is normally a buffer
+ * in the context, hence potentially long-lived.
+ */
+ memset(xcoor, 0, xcoor_len);
+}
+
+/*
+ * Do the ECDH key exchange (not ECDHE).
+ */
+static void
+do_ecdh(br_ssl_server_context *ctx, int prf_id,
+ unsigned char *cpoint, size_t cpoint_len)
+{
+ uint32_t x;
+
+ /*
+ * Finalise the key exchange.
+ */
+ x = (*ctx->policy_vtable)->do_keyx(ctx->policy_vtable,
+ cpoint, &cpoint_len);
+ 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);
+}
+
+static size_t
+hash_data(br_ssl_server_context *ctx,
+ void *dst, int hash_id, const void *src, size_t len)
+{
+ const br_hash_class *hf;
+ br_hash_compat_context hc;
+
+ if (hash_id == 0) {
+ unsigned char tmp[36];
+
+ hf = br_multihash_getimpl(&ctx->eng.mhash, br_md5_ID);
+ if (hf == NULL) {
+ return 0;
+ }
+ hf->init(&hc.vtable);
+ hf->update(&hc.vtable, src, len);
+ hf->out(&hc.vtable, tmp);
+ hf = br_multihash_getimpl(&ctx->eng.mhash, br_sha1_ID);
+ if (hf == NULL) {
+ return 0;
+ }
+ hf->init(&hc.vtable);
+ hf->update(&hc.vtable, src, len);
+ hf->out(&hc.vtable, tmp + 16);
+ memcpy(dst, tmp, 36);
+ return 36;
+ } else {
+ hf = br_multihash_getimpl(&ctx->eng.mhash, hash_id);
+ if (hf == NULL) {
+ return 0;
+ }
+ hf->init(&hc.vtable);
+ hf->update(&hc.vtable, src, len);
+ hf->out(&hc.vtable, dst);
+ return (hf->desc >> BR_HASHDESC_OUT_OFF) & BR_HASHDESC_OUT_MASK;
+ }
+}
+
+/*
+ * 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
+ * signature length (in bytes), or -x on error (with x being an error
+ * code). The encoded point is written in the ecdhe_point[] context buffer
+ * (length in ecdhe_point_len).
+ */
+static int
+do_ecdhe_part1(br_ssl_server_context *ctx, int curve)
+{
+ unsigned algo_id;
+ unsigned mask;
+ const unsigned char *order;
+ size_t olen, glen;
+ size_t hv_len, sig_len;
+
+ if (!((ctx->eng.iec->supported_curves >> curve) & 1)) {
+ return -BR_ERR_INVALID_ALGORITHM;
+ }
+ ctx->eng.ecdhe_curve = curve;
+
+ /*
+ * Generate our private key. We need a non-zero random value
+ * which is lower than the curve order, in a "large enough"
+ * range. We force the top bit to 0 and bottom bit to 1, which
+ * does the trick. Note that contrary to what happens in ECDSA,
+ * this is not a problem if we do not cover the full range of
+ * possible values.
+ */
+ order = ctx->eng.iec->order(curve, &olen);
+ mask = 0xFF;
+ while (mask >= order[0]) {
+ mask >>= 1;
+ }
+ br_hmac_drbg_generate(&ctx->eng.rng, ctx->ecdhe_key, olen);
+ ctx->ecdhe_key[0] &= mask;
+ ctx->ecdhe_key[olen - 1] |= 0x01;
+ ctx->ecdhe_key_len = olen;
+
+ /*
+ * Compute our ECDH point.
+ */
+ glen = ctx->eng.iec->mulgen(ctx->eng.ecdhe_point,
+ ctx->ecdhe_key, olen, curve);
+ ctx->eng.ecdhe_point_len = glen;
+
+ /*
+ * Assemble the message to be signed, and possibly hash it.
+ */
+ memcpy(ctx->eng.pad, ctx->eng.client_random, 32);
+ memcpy(ctx->eng.pad + 32, ctx->eng.server_random, 32);
+ ctx->eng.pad[64 + 0] = 0x03;
+ ctx->eng.pad[64 + 1] = 0x00;
+ ctx->eng.pad[64 + 2] = curve;
+ ctx->eng.pad[64 + 3] = ctx->eng.ecdhe_point_len;
+ memcpy(ctx->eng.pad + 64 + 4,
+ ctx->eng.ecdhe_point, ctx->eng.ecdhe_point_len);
+ hv_len = 64 + 4 + ctx->eng.ecdhe_point_len;
+ algo_id = ctx->sign_hash_id;
+ if (algo_id >= (unsigned)0xFF00) {
+ hv_len = hash_data(ctx, ctx->eng.pad, algo_id & 0xFF,
+ ctx->eng.pad, hv_len);
+ if (hv_len == 0) {
+ return -BR_ERR_INVALID_ALGORITHM;
+ }
+ }
+
+ sig_len = (*ctx->policy_vtable)->do_sign(ctx->policy_vtable,
+ algo_id, ctx->eng.pad, hv_len, sizeof ctx->eng.pad);
+ return sig_len ? (int)sig_len : -BR_ERR_INVALID_ALGORITHM;
+}
+
+/*
+ * Do the ECDHE key exchange (part 2: computation of the shared secret
+ * from the point sent by the client).
+ */
+static void
+do_ecdhe_part2(br_ssl_server_context *ctx, int prf_id,
+ unsigned char *cpoint, size_t cpoint_len)
+{
+ int curve;
+ uint32_t ctl;
+ size_t xoff, xlen;
+
+ curve = ctx->eng.ecdhe_curve;
+
+ /*
+ * Finalise the key exchange.
+ */
+ ctl = ctx->eng.iec->mul(cpoint, cpoint_len,
+ ctx->ecdhe_key, ctx->ecdhe_key_len, curve);
+ xoff = ctx->eng.iec->xoff(curve, &xlen);
+ ecdh_common(ctx, prf_id, cpoint + xoff, xlen, ctl);
+
+ /*
+ * Clear the ECDHE private key. Forward Secrecy is achieved insofar
+ * as that key does not get stolen, so we'd better destroy it
+ * as soon as it ceases to be useful.
+ */
+ 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 unsigned char t0_datablock[] = {
+ 0x00, 0x00, 0x0A, 0x00, 0x24, 0x00, 0x2F, 0x01, 0x24, 0x00, 0x35, 0x02,
+ 0x24, 0x00, 0x3C, 0x01, 0x44, 0x00, 0x3D, 0x02, 0x44, 0x00, 0x9C, 0x03,
+ 0x04, 0x00, 0x9D, 0x04, 0x05, 0xC0, 0x03, 0x40, 0x24, 0xC0, 0x04, 0x41,
+ 0x24, 0xC0, 0x05, 0x42, 0x24, 0xC0, 0x08, 0x20, 0x24, 0xC0, 0x09, 0x21,
+ 0x24, 0xC0, 0x0A, 0x22, 0x24, 0xC0, 0x0D, 0x30, 0x24, 0xC0, 0x0E, 0x31,
+ 0x24, 0xC0, 0x0F, 0x32, 0x24, 0xC0, 0x12, 0x10, 0x24, 0xC0, 0x13, 0x11,
+ 0x24, 0xC0, 0x14, 0x12, 0x24, 0xC0, 0x23, 0x21, 0x44, 0xC0, 0x24, 0x22,
+ 0x55, 0xC0, 0x25, 0x41, 0x44, 0xC0, 0x26, 0x42, 0x55, 0xC0, 0x27, 0x11,
+ 0x44, 0xC0, 0x28, 0x12, 0x55, 0xC0, 0x29, 0x31, 0x44, 0xC0, 0x2A, 0x32,
+ 0x55, 0xC0, 0x2B, 0x23, 0x04, 0xC0, 0x2C, 0x24, 0x05, 0xC0, 0x2D, 0x43,
+ 0x04, 0xC0, 0x2E, 0x44, 0x05, 0xC0, 0x2F, 0x13, 0x04, 0xC0, 0x30, 0x14,
+ 0x05, 0xC0, 0x31, 0x33, 0x04, 0xC0, 0x32, 0x34, 0x05, 0xC0, 0x9C, 0x06,
+ 0x04, 0xC0, 0x9D, 0x07, 0x04, 0xC0, 0xA0, 0x08, 0x04, 0xC0, 0xA1, 0x09,
+ 0x04, 0xC0, 0xAC, 0x26, 0x04, 0xC0, 0xAD, 0x27, 0x04, 0xC0, 0xAE, 0x28,
+ 0x04, 0xC0, 0xAF, 0x29, 0x04, 0xCC, 0xA8, 0x15, 0x04, 0xCC, 0xA9, 0x25,
+ 0x04, 0x00, 0x00
+};
+
+static const unsigned char t0_codeblock[] = {
+ 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,
+ 0x01, 0x02, 0x09, 0x00, 0x00, 0x29, 0x29, 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_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,
+ 0x01,
+ T0_INT2(offsetof(br_ssl_engine_context, session) + offsetof(br_ssl_session_parameters, cipher_suite)),
+ 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(br_ssl_server_context, client_max_version)), 0x00,
+ 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, client_random)),
+ 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(br_ssl_server_context, client_suites)), 0x00, 0x00,
+ 0x01, T0_INT2(offsetof(br_ssl_server_context, client_suites_num)),
+ 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(br_ssl_engine_context, close_received)), 0x00, 0x00,
+ 0x01, T0_INT2(offsetof(br_ssl_server_context, curves)), 0x00, 0x00,
+ 0x01, 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_server_context, hashes)),
+ 0x00, 0x00, 0x7B, 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,
+ 0x00, 0x01,
+ T0_INT2(offsetof(br_ssl_engine_context, peer_log_max_frag_len)), 0x00,
+ 0x00, 0x01,
+ T0_INT2(offsetof(br_ssl_engine_context, protocol_names_num)), 0x00,
+ 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, record_type_in)),
+ 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(br_ssl_engine_context, record_type_out)), 0x00, 0x00,
+ 0x01, T0_INT2(offsetof(br_ssl_engine_context, reneg)), 0x00, 0x00,
+ 0x01, T0_INT2(offsetof(br_ssl_engine_context, saved_finished)), 0x00,
+ 0x00, 0x01,
+ T0_INT2(offsetof(br_ssl_engine_context, selected_protocol)), 0x00,
+ 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, server_name)),
+ 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(br_ssl_engine_context, server_random)), 0x00, 0x00,
+ 0x01,
+ T0_INT2(offsetof(br_ssl_engine_context, session) + offsetof(br_ssl_session_parameters, session_id)),
+ 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(br_ssl_engine_context, session) + offsetof(br_ssl_session_parameters, session_id_len)),
+ 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(br_ssl_engine_context, shutdown_recv)), 0x00, 0x00,
+ 0x01, T0_INT2(offsetof(br_ssl_server_context, sign_hash_id)), 0x00,
+ 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, suites_buf)), 0x00,
+ 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, suites_num)), 0x00,
+ 0x00, 0x01,
+ T0_INT2(offsetof(br_ssl_engine_context, session) + offsetof(br_ssl_session_parameters, version)),
+ 0x00, 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, version_in)),
+ 0x00, 0x00, 0x01,
+ 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, 0x2A, 0x5D, 0x06, 0x02, 0x6A, 0x2B, 0x00, 0x00, 0x01,
+ 0x01, 0x00, 0x01, 0x03, 0x00, 0x9B, 0x2A, 0x63, 0x47, 0x9F, 0x2A, 0x05,
+ 0x04, 0x65, 0x01, 0x00, 0x00, 0x02, 0x00, 0x0F, 0x06, 0x02, 0x9F, 0x00,
+ 0x63, 0x04, 0x6B, 0x00, 0x06, 0x02, 0x6A, 0x2B, 0x00, 0x00, 0x2A, 0x8B,
+ 0x47, 0x05, 0x03, 0x01, 0x0C, 0x08, 0x47, 0x78, 0x2E, 0xA8, 0x1C, 0x85,
+ 0x01, 0x0C, 0x33, 0x00, 0x00, 0x2A, 0x22, 0x01, 0x08, 0x0C, 0x47, 0x61,
+ 0x22, 0x08, 0x00, 0x01, 0x03, 0x00, 0x77, 0x30, 0x02, 0x00, 0x38, 0x13,
+ 0x01, 0x01, 0x0C, 0x77, 0x42, 0x2C, 0x19, 0x38, 0x06, 0x07, 0x02, 0x00,
+ 0xD0, 0x03, 0x00, 0x04, 0x75, 0x01, 0x00, 0xC7, 0x02, 0x00, 0x2A, 0x19,
+ 0x13, 0x06, 0x02, 0x71, 0x2B, 0xD0, 0x04, 0x76, 0x00, 0x01, 0x00, 0x77,
+ 0x42, 0x01, 0x16, 0x89, 0x42, 0x01, 0x00, 0x8C, 0x40, 0x36, 0xB1, 0x35,
+ 0x06, 0x02, 0x73, 0x2B, 0x06, 0x0A, 0xD7, 0x01, 0x00, 0xD3, 0x01, 0x00,
+ 0xAD, 0x04, 0x80, 0x46, 0xD7, 0xD4, 0x29, 0xD9, 0x50, 0x06, 0x01, 0xD5,
+ 0xD8, 0x2C, 0x50, 0x06, 0x31, 0x01, 0x00, 0xAE, 0x2A, 0x5D, 0x06, 0x0F,
+ 0x01, 0x02, 0xA4, 0x05, 0x02, 0x37, 0x2B, 0x29, 0xB2, 0xB0, 0x2A, 0xC9,
+ 0x29, 0x04, 0x19, 0x2A, 0x5F, 0x06, 0x0B, 0x29, 0x01, 0x02, 0xA4, 0x05,
+ 0x02, 0x70, 0x2B, 0xB2, 0x04, 0x0A, 0xB4, 0x2A, 0x05, 0x04, 0x29, 0xAB,
+ 0x04, 0x02, 0xB3, 0xAF, 0x04, 0x01, 0xB2, 0x01, 0x00, 0xAD, 0x01, 0x00,
+ 0xD3, 0x3E, 0x01, 0x01, 0x77, 0x42, 0x01, 0x17, 0x89, 0x42, 0x00, 0x00,
+ 0x3A, 0x3A, 0x00, 0x01, 0x03, 0x00, 0x2C, 0x19, 0x38, 0x06, 0x04, 0xCF,
+ 0x29, 0x04, 0x78, 0x01, 0x02, 0x02, 0x00, 0xC6, 0x19, 0x38, 0x06, 0x04,
+ 0xCF, 0x29, 0x04, 0x78, 0x02, 0x00, 0x01, 0x84, 0x00, 0x08, 0x2B, 0x00,
+ 0x00, 0x81, 0x2F, 0x47, 0x12, 0x01, 0x01, 0x13, 0x37, 0x00, 0x00, 0x2A,
+ 0x05, 0x04, 0x29, 0x01, 0x7F, 0x00, 0x01, 0x00, 0xA2, 0x12, 0x01, 0x01,
+ 0x13, 0x5F, 0x06, 0x03, 0x61, 0x04, 0x75, 0x47, 0x29, 0x00, 0x00, 0x01,
+ 0x7F, 0xA1, 0xCF, 0x2A, 0x01, 0x07, 0x13, 0x01, 0x00, 0x3A, 0x0F, 0x06,
+ 0x0D, 0x29, 0x01, 0x10, 0x13, 0x06, 0x05, 0x01, 0x00, 0x77, 0x42, 0xC5,
+ 0x04, 0x33, 0x01, 0x01, 0x3A, 0x0F, 0x06, 0x2A, 0x29, 0x29, 0x8A, 0x30,
+ 0x01, 0x01, 0x0F, 0x01, 0x01, 0xA4, 0x39, 0x06, 0x18, 0xC8, 0x2C, 0x19,
+ 0x38, 0x06, 0x04, 0xCF, 0x29, 0x04, 0x78, 0x01, 0x80, 0x64, 0xC7, 0x01,
+ 0x01, 0x77, 0x42, 0x01, 0x17, 0x89, 0x42, 0x04, 0x03, 0x01, 0x00, 0xA1,
+ 0x04, 0x03, 0x73, 0x2B, 0x29, 0x04, 0xFF, 0x32, 0x01, 0x2A, 0x03, 0x00,
+ 0x09, 0x2A, 0x5D, 0x06, 0x02, 0x6A, 0x2B, 0x02, 0x00, 0x00, 0x00, 0x9C,
+ 0x01, 0x0F, 0x13, 0x00, 0x00, 0x76, 0x30, 0x01, 0x00, 0x3A, 0x0F, 0x06,
+ 0x10, 0x29, 0x2A, 0x01, 0x01, 0x0E, 0x06, 0x03, 0x29, 0x01, 0x02, 0x76,
+ 0x42, 0x01, 0x00, 0x04, 0x21, 0x01, 0x01, 0x3A, 0x0F, 0x06, 0x14, 0x29,
+ 0x01, 0x00, 0x76, 0x42, 0x2A, 0x01, 0x80, 0x64, 0x0F, 0x06, 0x05, 0x01,
+ 0x82, 0x00, 0x08, 0x2B, 0x5F, 0x04, 0x07, 0x29, 0x01, 0x82, 0x00, 0x08,
+ 0x2B, 0x29, 0x00, 0x00, 0x01, 0x00, 0x31, 0x06, 0x05, 0x3D, 0xA9, 0x39,
+ 0x04, 0x78, 0x2A, 0x06, 0x04, 0x01, 0x01, 0x91, 0x42, 0x00, 0x00, 0x01,
+ 0x1F, 0x13, 0x01, 0x12, 0x0F, 0x05, 0x02, 0x74, 0x2B, 0x78, 0x2E, 0x2A,
+ 0xCB, 0x05, 0x02, 0x73, 0x2B, 0xA8, 0x28, 0x00, 0x02, 0x87, 0x2E, 0x05,
+ 0x02, 0xBC, 0x00, 0xC0, 0xA7, 0xC0, 0xA7, 0x01, 0x7E, 0x03, 0x00, 0x2A,
+ 0x06, 0x17, 0xC2, 0x2A, 0x03, 0x01, 0x85, 0x47, 0xB6, 0x02, 0x01, 0x51,
+ 0x2A, 0x02, 0x00, 0x53, 0x06, 0x04, 0x03, 0x00, 0x04, 0x01, 0x29, 0x04,
+ 0x66, 0x9D, 0x9D, 0x02, 0x00, 0x61, 0x8C, 0x40, 0x00, 0x00, 0x31, 0x06,
+ 0x0B, 0x88, 0x30, 0x01, 0x14, 0x0E, 0x06, 0x02, 0x73, 0x2B, 0x04, 0x11,
+ 0xCF, 0x01, 0x07, 0x13, 0x2A, 0x01, 0x02, 0x0E, 0x06, 0x06, 0x06, 0x02,
+ 0x73, 0x2B, 0x04, 0x70, 0x29, 0xC3, 0x01, 0x01, 0x0E, 0x35, 0x39, 0x06,
+ 0x02, 0x66, 0x2B, 0x2A, 0x01, 0x01, 0xCA, 0x38, 0xB5, 0x00, 0x01, 0xBA,
+ 0x01, 0x0B, 0x0F, 0x05, 0x02, 0x73, 0x2B, 0x2A, 0x01, 0x03, 0x0F, 0x06,
+ 0x08, 0xC1, 0x06, 0x02, 0x6A, 0x2B, 0x47, 0x29, 0x00, 0x47, 0x5C, 0xC1,
+ 0xA7, 0x2A, 0x06, 0x23, 0xC1, 0xA7, 0x2A, 0x5B, 0x2A, 0x06, 0x18, 0x2A,
+ 0x01, 0x82, 0x00, 0x10, 0x06, 0x05, 0x01, 0x82, 0x00, 0x04, 0x01, 0x2A,
+ 0x03, 0x00, 0x85, 0x02, 0x00, 0xB6, 0x02, 0x00, 0x58, 0x04, 0x65, 0x9D,
+ 0x59, 0x04, 0x5A, 0x9D, 0x9D, 0x5A, 0x2A, 0x06, 0x02, 0x37, 0x00, 0x29,
+ 0x2D, 0x00, 0x02, 0x2A, 0x01, 0x20, 0x13, 0x05, 0x02, 0x74, 0x2B, 0x01,
+ 0x0F, 0x13, 0x03, 0x00, 0xB0, 0x95, 0x2E, 0x01, 0x86, 0x03, 0x11, 0x06,
+ 0x23, 0xC0, 0x2A, 0x01, 0x81, 0x7F, 0x13, 0x61, 0x01, 0x01, 0x12, 0x02,
+ 0x00, 0x0F, 0x05, 0x02, 0x6C, 0x2B, 0x01, 0x08, 0x12, 0x2A, 0x01, 0x02,
+ 0x0B, 0x3A, 0x01, 0x06, 0x10, 0x39, 0x06, 0x02, 0x6E, 0x2B, 0x04, 0x0D,
+ 0x02, 0x00, 0x01, 0x01, 0x0F, 0x06, 0x04, 0x01, 0x00, 0x04, 0x02, 0x01,
+ 0x02, 0x20, 0x05, 0x02, 0x6E, 0x2B, 0xC0, 0x2A, 0x03, 0x01, 0x2A, 0x01,
+ 0x84, 0x00, 0x10, 0x06, 0x02, 0x6F, 0x2B, 0x85, 0x47, 0xB6, 0x02, 0x01,
+ 0x55, 0x2A, 0x06, 0x01, 0x2B, 0x29, 0x9D, 0x00, 0x00, 0x1D, 0xBA, 0x01,
+ 0x0F, 0x0F, 0x05, 0x02, 0x73, 0x2B, 0x00, 0x0A, 0xBA, 0x01, 0x01, 0x0F,
+ 0x05, 0x02, 0x73, 0x2B, 0xC0, 0x2A, 0x03, 0x00, 0x79, 0x40, 0x7A, 0x01,
+ 0x20, 0xB6, 0xC2, 0x2A, 0x01, 0x20, 0x10, 0x06, 0x02, 0x72, 0x2B, 0x2A,
+ 0x90, 0x42, 0x8F, 0x47, 0xB6, 0x1A, 0x03, 0x01, 0xC0, 0xA7, 0x01, 0x00,
+ 0x03, 0x02, 0x01, 0x00, 0x03, 0x03, 0x83, 0xA2, 0x17, 0x3A, 0x08, 0x03,
+ 0x04, 0x03, 0x05, 0x2A, 0x06, 0x80, 0x6D, 0xC0, 0x2A, 0x03, 0x06, 0x02,
+ 0x01, 0x06, 0x0A, 0x2A, 0x78, 0x2E, 0x0F, 0x06, 0x04, 0x01, 0x7F, 0x03,
+ 0x03, 0x2A, 0x01, 0x81, 0x7F, 0x0F, 0x06, 0x0A, 0x8A, 0x30, 0x06, 0x02,
+ 0x6B, 0x2B, 0x01, 0x7F, 0x03, 0x02, 0x2A, 0x01, 0x81, 0xAC, 0x00, 0x0F,
+ 0x06, 0x11, 0x02, 0x00, 0x98, 0x2E, 0x11, 0x02, 0x00, 0x97, 0x2E, 0x0B,
+ 0x13, 0x06, 0x04, 0x01, 0x7F, 0x03, 0x00, 0xC4, 0x2A, 0x5D, 0x06, 0x03,
+ 0x29, 0x04, 0x26, 0x01, 0x00, 0xA4, 0x06, 0x0B, 0x01, 0x02, 0x0C, 0x7B,
+ 0x08, 0x02, 0x06, 0x47, 0x40, 0x04, 0x16, 0x29, 0x02, 0x05, 0x02, 0x04,
+ 0x11, 0x06, 0x02, 0x69, 0x2B, 0x02, 0x06, 0x02, 0x05, 0x40, 0x02, 0x05,
+ 0x01, 0x04, 0x08, 0x03, 0x05, 0x04, 0xFF, 0x0F, 0x29, 0x01, 0x00, 0x03,
+ 0x07, 0xC2, 0xA7, 0x2A, 0x06, 0x09, 0xC2, 0x05, 0x04, 0x01, 0x7F, 0x03,
+ 0x07, 0x04, 0x74, 0x9D, 0x01, 0x00, 0x8D, 0x42, 0x01, 0x88, 0x04, 0x82,
+ 0x41, 0x01, 0x84, 0x80, 0x80, 0x00, 0x7E, 0x41, 0x2A, 0x06, 0x80, 0x4E,
+ 0xC0, 0xA7, 0x2A, 0x06, 0x80, 0x47, 0xC0, 0x01, 0x00, 0x3A, 0x0F, 0x06,
+ 0x04, 0x29, 0xB9, 0x04, 0x39, 0x01, 0x01, 0x3A, 0x0F, 0x06, 0x04, 0x29,
+ 0xB7, 0x04, 0x2F, 0x01, 0x83, 0xFE, 0x01, 0x3A, 0x0F, 0x06, 0x04, 0x29,
+ 0xB8, 0x04, 0x23, 0x01, 0x0D, 0x3A, 0x0F, 0x06, 0x04, 0x29, 0xBE, 0x04,
+ 0x19, 0x01, 0x0A, 0x3A, 0x0F, 0x06, 0x04, 0x29, 0xBF, 0x04, 0x0F, 0x01,
+ 0x10, 0x3A, 0x0F, 0x06, 0x04, 0x29, 0xAC, 0x04, 0x05, 0x29, 0xBC, 0x01,
+ 0x00, 0x29, 0x04, 0xFF, 0x35, 0x9D, 0x9D, 0x02, 0x01, 0x02, 0x03, 0x13,
+ 0x03, 0x01, 0x02, 0x00, 0x5D, 0x06, 0x08, 0x79, 0x2E, 0x99, 0x40, 0x01,
+ 0x80, 0x56, 0xA3, 0x97, 0x2E, 0x2A, 0x02, 0x00, 0x10, 0x06, 0x03, 0x29,
+ 0x02, 0x00, 0x2A, 0x01, 0x86, 0x00, 0x0B, 0x06, 0x02, 0x6D, 0x2B, 0x02,
+ 0x00, 0x98, 0x2E, 0x0B, 0x06, 0x04, 0x01, 0x80, 0x46, 0xA3, 0x02, 0x01,
+ 0x06, 0x10, 0x95, 0x2E, 0x02, 0x00, 0x0D, 0x06, 0x05, 0x29, 0x95, 0x2E,
+ 0x04, 0x04, 0x01, 0x00, 0x03, 0x01, 0x2A, 0x95, 0x40, 0x2A, 0x96, 0x40,
+ 0x2A, 0x99, 0x40, 0x01, 0x86, 0x03, 0x11, 0x03, 0x08, 0x02, 0x02, 0x06,
+ 0x04, 0x01, 0x02, 0x8A, 0x42, 0x8A, 0x30, 0x05, 0x04, 0x01, 0x01, 0x8A,
+ 0x42, 0x02, 0x07, 0x05, 0x03, 0x01, 0x28, 0xA3, 0x44, 0x29, 0x01, 0x82,
+ 0x01, 0x07, 0x01, 0xFC, 0x80, 0x00, 0x39, 0x82, 0x2F, 0x13, 0x2A, 0x82,
+ 0x41, 0x2A, 0x01, 0x81, 0x7F, 0x13, 0x5E, 0x37, 0x47, 0x01, 0x08, 0x12,
+ 0x5E, 0x01, 0x02, 0x13, 0x39, 0x01, 0x0C, 0x0C, 0x03, 0x09, 0x7E, 0x2F,
+ 0x43, 0x13, 0x2A, 0x7E, 0x41, 0x05, 0x04, 0x01, 0x00, 0x03, 0x09, 0x02,
+ 0x01, 0x06, 0x03, 0x01, 0x7F, 0x00, 0x8F, 0x01, 0x20, 0x34, 0x01, 0x20,
+ 0x90, 0x42, 0x7B, 0x2A, 0x03, 0x05, 0x2A, 0x02, 0x04, 0x0B, 0x06, 0x80,
+ 0x49, 0x2A, 0x2E, 0x2A, 0x9C, 0x2A, 0x01, 0x0C, 0x12, 0x2A, 0x01, 0x01,
+ 0x0F, 0x47, 0x01, 0x02, 0x0F, 0x39, 0x06, 0x0A, 0x2A, 0x02, 0x09, 0x13,
+ 0x05, 0x04, 0x65, 0x01, 0x00, 0x2A, 0x02, 0x08, 0x05, 0x0E, 0x2A, 0x01,
+ 0x81, 0x70, 0x13, 0x01, 0x20, 0x0E, 0x06, 0x04, 0x65, 0x01, 0x00, 0x2A,
+ 0x2A, 0x06, 0x10, 0x02, 0x05, 0x63, 0x40, 0x02, 0x05, 0x40, 0x02, 0x05,
+ 0x01, 0x04, 0x08, 0x03, 0x05, 0x04, 0x01, 0x65, 0x01, 0x04, 0x08, 0x04,
+ 0xFF, 0x30, 0x29, 0x02, 0x05, 0x7B, 0x09, 0x01, 0x02, 0x12, 0x2A, 0x05,
+ 0x03, 0x01, 0x28, 0xA3, 0x7C, 0x42, 0x8C, 0x2E, 0x01, 0x83, 0xFF, 0x7F,
+ 0x0F, 0x06, 0x0D, 0x01, 0x03, 0xA4, 0x06, 0x04, 0x01, 0x80, 0x78, 0xA3,
+ 0x01, 0x00, 0x8C, 0x40, 0x18, 0x05, 0x03, 0x01, 0x28, 0xA3, 0x01, 0x00,
+ 0x00, 0x00, 0xB4, 0xB3, 0x00, 0x04, 0x78, 0x2E, 0xCE, 0x06, 0x16, 0xC0,
+ 0x2A, 0x01, 0x84, 0x00, 0x10, 0x06, 0x02, 0x6F, 0x2B, 0x2A, 0x03, 0x00,
+ 0x85, 0x47, 0xB6, 0x02, 0x00, 0x78, 0x2E, 0xA8, 0x27, 0x78, 0x2E, 0x2A,
+ 0xCC, 0x47, 0xCB, 0x03, 0x01, 0x03, 0x02, 0x02, 0x01, 0x02, 0x02, 0x39,
+ 0x06, 0x14, 0xC2, 0x2A, 0x03, 0x03, 0x85, 0x47, 0xB6, 0x02, 0x03, 0x78,
+ 0x2E, 0xA8, 0x02, 0x02, 0x06, 0x03, 0x26, 0x04, 0x01, 0x24, 0x9D, 0x00,
+ 0x00, 0xBA, 0x01, 0x10, 0x0F, 0x05, 0x02, 0x73, 0x2B, 0x00, 0x00, 0x9E,
+ 0xBA, 0x01, 0x14, 0x0E, 0x06, 0x02, 0x73, 0x2B, 0x85, 0x01, 0x0C, 0x08,
+ 0x01, 0x0C, 0xB6, 0x9D, 0x85, 0x2A, 0x01, 0x0C, 0x08, 0x01, 0x0C, 0x32,
+ 0x05, 0x02, 0x67, 0x2B, 0x00, 0x02, 0x03, 0x00, 0x03, 0x01, 0x02, 0x00,
+ 0x9A, 0x02, 0x01, 0x02, 0x00, 0x3C, 0x2A, 0x01, 0x00, 0x0F, 0x06, 0x02,
+ 0x65, 0x00, 0xD1, 0x04, 0x74, 0x00, 0xC0, 0x01, 0x01, 0x0E, 0x06, 0x02,
+ 0x68, 0x2B, 0xC2, 0x2A, 0x2A, 0x5F, 0x47, 0x01, 0x05, 0x11, 0x39, 0x06,
+ 0x02, 0x68, 0x2B, 0x01, 0x08, 0x08, 0x2A, 0x84, 0x30, 0x0B, 0x06, 0x0D,
+ 0x2A, 0x01, 0x01, 0x47, 0x0C, 0x3F, 0x2A, 0x84, 0x42, 0x86, 0x42, 0x04,
+ 0x01, 0x29, 0x00, 0x00, 0xC0, 0x8A, 0x30, 0x01, 0x00, 0x3A, 0x0F, 0x06,
+ 0x13, 0x29, 0x01, 0x01, 0x0F, 0x05, 0x02, 0x6B, 0x2B, 0xC2, 0x06, 0x02,
+ 0x6B, 0x2B, 0x01, 0x02, 0x8A, 0x42, 0x04, 0x28, 0x01, 0x02, 0x3A, 0x0F,
+ 0x06, 0x1F, 0x29, 0x01, 0x0D, 0x0F, 0x05, 0x02, 0x6B, 0x2B, 0xC2, 0x01,
+ 0x0C, 0x0F, 0x05, 0x02, 0x6B, 0x2B, 0x85, 0x01, 0x0C, 0xB6, 0x8B, 0x85,
+ 0x01, 0x0C, 0x32, 0x05, 0x02, 0x6B, 0x2B, 0x04, 0x03, 0x6B, 0x2B, 0x29,
+ 0x00, 0x00, 0xC0, 0xA7, 0xC0, 0xA7, 0x2A, 0x06, 0x1D, 0xC2, 0x06, 0x03,
+ 0xBC, 0x04, 0x15, 0xC0, 0x2A, 0x01, 0x81, 0x7F, 0x0D, 0x06, 0x0C, 0x2A,
+ 0x8D, 0x08, 0x01, 0x00, 0x47, 0x42, 0x8D, 0x47, 0xB6, 0x04, 0x01, 0xC9,
+ 0x04, 0x60, 0x9D, 0x9D, 0x00, 0x00, 0xBB, 0x2A, 0x5F, 0x06, 0x07, 0x29,
+ 0x06, 0x02, 0x69, 0x2B, 0x04, 0x74, 0x00, 0x00, 0xC3, 0x01, 0x03, 0xC1,
+ 0x47, 0x29, 0x47, 0x00, 0x00, 0xC0, 0xC9, 0x00, 0x03, 0x01, 0x00, 0x03,
+ 0x00, 0xC0, 0xA7, 0x2A, 0x06, 0x80, 0x50, 0xC2, 0x03, 0x01, 0xC2, 0x03,
+ 0x02, 0x02, 0x01, 0x01, 0x08, 0x0F, 0x06, 0x16, 0x02, 0x02, 0x01, 0x0F,
+ 0x0D, 0x06, 0x0D, 0x01, 0x01, 0x02, 0x02, 0x01, 0x10, 0x08, 0x0C, 0x02,
+ 0x00, 0x39, 0x03, 0x00, 0x04, 0x2A, 0x02, 0x01, 0x01, 0x02, 0x11, 0x02,
+ 0x01, 0x01, 0x06, 0x0D, 0x13, 0x02, 0x02, 0x01, 0x01, 0x0F, 0x02, 0x02,
+ 0x01, 0x03, 0x0F, 0x39, 0x13, 0x06, 0x11, 0x02, 0x00, 0x01, 0x01, 0x02,
+ 0x02, 0x62, 0x01, 0x02, 0x0C, 0x02, 0x01, 0x08, 0x0C, 0x39, 0x03, 0x00,
+ 0x04, 0xFF, 0x2C, 0x9D, 0x02, 0x00, 0x00, 0x00, 0xC0, 0xA7, 0xBD, 0x82,
+ 0x41, 0x9D, 0x00, 0x00, 0xC0, 0xA7, 0xC0, 0xA7, 0x01, 0x00, 0x7E, 0x41,
+ 0x2A, 0x06, 0x15, 0xC0, 0x2A, 0x01, 0x20, 0x0B, 0x06, 0x0B, 0x01, 0x01,
+ 0x47, 0x0C, 0x7E, 0x2F, 0x39, 0x7E, 0x41, 0x04, 0x01, 0x29, 0x04, 0x68,
+ 0x9D, 0x9D, 0x00, 0x00, 0x01, 0x02, 0x9A, 0xC3, 0x01, 0x08, 0x0C, 0xC3,
+ 0x08, 0x00, 0x00, 0x01, 0x03, 0x9A, 0xC3, 0x01, 0x08, 0x0C, 0xC3, 0x08,
+ 0x01, 0x08, 0x0C, 0xC3, 0x08, 0x00, 0x00, 0x01, 0x01, 0x9A, 0xC3, 0x00,
+ 0x00, 0x3D, 0x2A, 0x5D, 0x05, 0x01, 0x00, 0x29, 0xD1, 0x04, 0x76, 0x02,
+ 0x03, 0x00, 0x94, 0x30, 0x03, 0x01, 0x01, 0x00, 0x2A, 0x02, 0x01, 0x0B,
+ 0x06, 0x10, 0x2A, 0x01, 0x01, 0x0C, 0x93, 0x08, 0x2E, 0x02, 0x00, 0x0F,
+ 0x06, 0x01, 0x00, 0x61, 0x04, 0x6A, 0x29, 0x01, 0x7F, 0x00, 0x00, 0x2C,
+ 0x19, 0x38, 0x06, 0x04, 0xCF, 0x29, 0x04, 0x78, 0x01, 0x16, 0x89, 0x42,
+ 0x01, 0x00, 0xE2, 0x01, 0x00, 0xE1, 0x2C, 0x01, 0x17, 0x89, 0x42, 0x00,
+ 0x00, 0x01, 0x15, 0x89, 0x42, 0x47, 0x57, 0x29, 0x57, 0x29, 0x2C, 0x00,
+ 0x00, 0x01, 0x01, 0x47, 0xC6, 0x00, 0x00, 0xBB, 0x01, 0x01, 0x0F, 0x05,
+ 0x02, 0x73, 0x2B, 0x2A, 0xC9, 0x29, 0x00, 0x00, 0x47, 0x3A, 0x9A, 0x47,
+ 0x2A, 0x06, 0x05, 0xC3, 0x29, 0x62, 0x04, 0x78, 0x29, 0x00, 0x02, 0x03,
+ 0x00, 0x78, 0x2E, 0x9C, 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, 0x3A, 0x0F, 0x06, 0x10, 0x29, 0x01, 0x00,
+ 0x01, 0x18, 0x02, 0x00, 0x06, 0x03, 0x4C, 0x04, 0x01, 0x4D, 0x04, 0x81,
+ 0x0D, 0x01, 0x01, 0x3A, 0x0F, 0x06, 0x10, 0x29, 0x01, 0x01, 0x01, 0x10,
+ 0x02, 0x00, 0x06, 0x03, 0x4C, 0x04, 0x01, 0x4D, 0x04, 0x80, 0x77, 0x01,
+ 0x02, 0x3A, 0x0F, 0x06, 0x10, 0x29, 0x01, 0x01, 0x01, 0x20, 0x02, 0x00,
+ 0x06, 0x03, 0x4C, 0x04, 0x01, 0x4D, 0x04, 0x80, 0x61, 0x01, 0x03, 0x3A,
+ 0x0F, 0x06, 0x0F, 0x29, 0x29, 0x01, 0x10, 0x02, 0x00, 0x06, 0x03, 0x4A,
+ 0x04, 0x01, 0x4B, 0x04, 0x80, 0x4C, 0x01, 0x04, 0x3A, 0x0F, 0x06, 0x0E,
+ 0x29, 0x29, 0x01, 0x20, 0x02, 0x00, 0x06, 0x03, 0x4A, 0x04, 0x01, 0x4B,
+ 0x04, 0x38, 0x01, 0x05, 0x3A, 0x0F, 0x06, 0x0C, 0x29, 0x29, 0x02, 0x00,
+ 0x06, 0x03, 0x4E, 0x04, 0x01, 0x4F, 0x04, 0x26, 0x2A, 0x01, 0x09, 0x10,
+ 0x06, 0x02, 0x6A, 0x2B, 0x47, 0x29, 0x2A, 0x01, 0x01, 0x13, 0x01, 0x04,
+ 0x0C, 0x01, 0x10, 0x08, 0x47, 0x01, 0x08, 0x13, 0x01, 0x10, 0x47, 0x09,
+ 0x02, 0x00, 0x06, 0x03, 0x48, 0x04, 0x01, 0x49, 0x00, 0x29, 0x00, 0x00,
+ 0x9C, 0x01, 0x0C, 0x12, 0x01, 0x02, 0x10, 0x00, 0x00, 0x9C, 0x01, 0x0C,
+ 0x12, 0x2A, 0x60, 0x47, 0x01, 0x03, 0x0B, 0x13, 0x00, 0x00, 0x9C, 0x01,
+ 0x0C, 0x12, 0x01, 0x01, 0x0F, 0x00, 0x00, 0x9C, 0x01, 0x0C, 0x12, 0x5F,
+ 0x00, 0x00, 0x1B, 0x01, 0x00, 0x75, 0x30, 0x2A, 0x06, 0x22, 0x01, 0x01,
+ 0x3A, 0x0F, 0x06, 0x06, 0x29, 0x01, 0x00, 0xA0, 0x04, 0x14, 0x01, 0x02,
+ 0x3A, 0x0F, 0x06, 0x0D, 0x29, 0x77, 0x30, 0x01, 0x01, 0x0F, 0x06, 0x03,
+ 0x01, 0x10, 0x39, 0x04, 0x01, 0x29, 0x04, 0x01, 0x29, 0x7D, 0x30, 0x05,
+ 0x33, 0x31, 0x06, 0x30, 0x88, 0x30, 0x01, 0x14, 0x3A, 0x0F, 0x06, 0x06,
+ 0x29, 0x01, 0x02, 0x39, 0x04, 0x22, 0x01, 0x15, 0x3A, 0x0F, 0x06, 0x09,
+ 0x29, 0xAA, 0x06, 0x03, 0x01, 0x7F, 0xA0, 0x04, 0x13, 0x01, 0x16, 0x3A,
+ 0x0F, 0x06, 0x06, 0x29, 0x01, 0x01, 0x39, 0x04, 0x07, 0x29, 0x01, 0x04,
+ 0x39, 0x01, 0x00, 0x29, 0x19, 0x06, 0x03, 0x01, 0x08, 0x39, 0x00, 0x00,
+ 0x1B, 0x2A, 0x05, 0x13, 0x31, 0x06, 0x10, 0x88, 0x30, 0x01, 0x15, 0x0F,
+ 0x06, 0x08, 0x29, 0xAA, 0x01, 0x00, 0x77, 0x42, 0x04, 0x01, 0x23, 0x00,
+ 0x00, 0xCF, 0x01, 0x07, 0x13, 0x01, 0x01, 0x10, 0x06, 0x02, 0x73, 0x2B,
+ 0x00, 0x01, 0x03, 0x00, 0x2C, 0x19, 0x06, 0x05, 0x02, 0x00, 0x89, 0x42,
+ 0x00, 0xCF, 0x29, 0x04, 0x74, 0x00, 0x01, 0x14, 0xD2, 0x01, 0x01, 0xE2,
+ 0x2C, 0x2A, 0x01, 0x00, 0xCA, 0x01, 0x16, 0xD2, 0xD6, 0x2C, 0x00, 0x00,
+ 0x01, 0x0B, 0xE2, 0x52, 0x2A, 0x2A, 0x01, 0x03, 0x08, 0xE1, 0xE1, 0x14,
+ 0x2A, 0x5D, 0x06, 0x02, 0x29, 0x00, 0xE1, 0x1E, 0x2A, 0x06, 0x05, 0x85,
+ 0x47, 0xDA, 0x04, 0x77, 0x29, 0x04, 0x6C, 0x00, 0x01, 0x00, 0xDC, 0x95,
+ 0x2E, 0x01, 0x86, 0x03, 0x11, 0x06, 0x05, 0x63, 0x01, 0x00, 0xDD, 0x08,
+ 0x50, 0x08, 0x01, 0x03, 0x08, 0x01, 0x0D, 0xE2, 0xE1, 0x01, 0x00, 0xDC,
+ 0xE2, 0x01, 0x01, 0xDC, 0x29, 0x95, 0x2E, 0x01, 0x86, 0x03, 0x11, 0x06,
+ 0x08, 0x01, 0x00, 0xDD, 0xE0, 0x01, 0x01, 0xDD, 0x29, 0x50, 0xE0, 0x16,
+ 0x15, 0x2A, 0x5D, 0x06, 0x02, 0x29, 0x00, 0xE0, 0x1F, 0x2A, 0x06, 0x05,
+ 0x85, 0x47, 0xDA, 0x04, 0x77, 0x29, 0x04, 0x6C, 0x00, 0x9E, 0x01, 0x14,
+ 0xE2, 0x01, 0x0C, 0xE1, 0x85, 0x01, 0x0C, 0xDA, 0x00, 0x04, 0x03, 0x00,
+ 0x01, 0x02, 0xE2, 0x01, 0x80, 0x46, 0x8A, 0x30, 0x01, 0x02, 0x0F, 0x06,
+ 0x0C, 0x02, 0x00, 0x06, 0x04, 0x01, 0x05, 0x04, 0x02, 0x01, 0x1D, 0x04,
+ 0x02, 0x01, 0x00, 0x03, 0x01, 0x86, 0x30, 0x06, 0x04, 0x01, 0x05, 0x04,
+ 0x02, 0x01, 0x00, 0x03, 0x02, 0x8C, 0x2E, 0x2A, 0x06, 0x05, 0x62, 0x21,
+ 0x01, 0x07, 0x08, 0x03, 0x03, 0x02, 0x01, 0x02, 0x02, 0x08, 0x02, 0x03,
+ 0x08, 0x2A, 0x06, 0x03, 0x01, 0x02, 0x08, 0x08, 0xE1, 0x95, 0x2E, 0xE0,
+ 0x8E, 0x01, 0x04, 0x17, 0x8E, 0x01, 0x04, 0x08, 0x01, 0x1C, 0x34, 0x8E,
+ 0x01, 0x20, 0xDA, 0x01, 0x20, 0xE2, 0x8F, 0x01, 0x20, 0xDA, 0x78, 0x2E,
+ 0xE0, 0x01, 0x00, 0xE2, 0x02, 0x01, 0x02, 0x02, 0x08, 0x02, 0x03, 0x08,
+ 0x2A, 0x06, 0x80, 0x40, 0xE0, 0x02, 0x01, 0x2A, 0x06, 0x10, 0x01, 0x83,
+ 0xFE, 0x01, 0xE0, 0x01, 0x04, 0x09, 0x2A, 0xE0, 0x62, 0x8B, 0x47, 0xDB,
+ 0x04, 0x01, 0x29, 0x02, 0x02, 0x06, 0x0C, 0x01, 0x01, 0xE0, 0x01, 0x01,
+ 0xE0, 0x86, 0x30, 0x01, 0x08, 0x09, 0xE2, 0x02, 0x03, 0x2A, 0x06, 0x11,
+ 0x01, 0x10, 0xE0, 0x01, 0x04, 0x09, 0x2A, 0xE0, 0x64, 0x2A, 0xE0, 0x62,
+ 0x85, 0x47, 0xDB, 0x04, 0x01, 0x29, 0x04, 0x01, 0x29, 0x00, 0x00, 0x01,
+ 0x0E, 0xE2, 0x01, 0x00, 0xE1, 0x00, 0x03, 0x78, 0x2E, 0xCC, 0x05, 0x01,
+ 0x00, 0x7E, 0x2F, 0x2A, 0x01, 0x82, 0x80, 0x80, 0x80, 0x00, 0x13, 0x06,
+ 0x05, 0x29, 0x01, 0x1D, 0x04, 0x0E, 0x2A, 0x01, 0x83, 0xC0, 0x80, 0x80,
+ 0x00, 0x13, 0x2A, 0x06, 0x01, 0x47, 0x29, 0xA5, 0x03, 0x00, 0x02, 0x00,
+ 0x25, 0x2A, 0x5D, 0x06, 0x02, 0x37, 0x2B, 0x03, 0x01, 0x95, 0x2E, 0x01,
+ 0x86, 0x03, 0x11, 0x03, 0x02, 0x01, 0x0C, 0xE2, 0x02, 0x01, 0x80, 0x30,
+ 0x08, 0x02, 0x02, 0x01, 0x02, 0x13, 0x08, 0x01, 0x06, 0x08, 0xE1, 0x01,
+ 0x03, 0xE2, 0x02, 0x00, 0xE0, 0x7F, 0x80, 0x30, 0xDB, 0x02, 0x02, 0x06,
+ 0x1C, 0x92, 0x2E, 0x2A, 0x01, 0x83, 0xFE, 0x00, 0x0B, 0x06, 0x03, 0xE0,
+ 0x04, 0x0F, 0x01, 0x81, 0x7F, 0x13, 0xE2, 0x78, 0x2E, 0xCD, 0x01, 0x01,
+ 0x0C, 0x01, 0x03, 0x08, 0xE2, 0x02, 0x01, 0xE0, 0x85, 0x02, 0x01, 0xDA,
+ 0x00, 0x00, 0x56, 0x2A, 0x01, 0x00, 0x0F, 0x06, 0x02, 0x65, 0x00, 0xCF,
+ 0x29, 0x04, 0x73, 0x00, 0x2A, 0xE2, 0xDA, 0x00, 0x00, 0x01, 0x00, 0x78,
+ 0x2E, 0xCB, 0x06, 0x0C, 0x63, 0x3A, 0x06, 0x08, 0x01, 0x80, 0x41, 0xE2,
+ 0x01, 0x80, 0x42, 0xE2, 0x46, 0x06, 0x07, 0x61, 0x3A, 0x06, 0x03, 0x01,
+ 0x01, 0xE2, 0x45, 0x06, 0x08, 0x61, 0x3A, 0x06, 0x04, 0x01, 0x80, 0x40,
+ 0xE2, 0x47, 0x29, 0x00, 0x01, 0x01, 0x00, 0x03, 0x00, 0x46, 0x45, 0x39,
+ 0x05, 0x14, 0x01, 0x01, 0x01, 0x80, 0x7C, 0xDE, 0x03, 0x00, 0x01, 0x03,
+ 0x01, 0x80, 0x7C, 0xDE, 0x02, 0x00, 0x08, 0x47, 0x29, 0x00, 0x46, 0x06,
+ 0x07, 0x01, 0x01, 0x44, 0x29, 0xDE, 0x03, 0x00, 0x45, 0x06, 0x0A, 0x01,
+ 0x03, 0x44, 0x29, 0xDE, 0x02, 0x00, 0x08, 0x03, 0x00, 0x29, 0x02, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x01, 0x04, 0xDF, 0x01, 0x05, 0xDF, 0x01, 0x06,
+ 0xDF, 0x01, 0x03, 0xDF, 0x01, 0x02, 0xDF, 0x0A, 0x65, 0x00, 0x01, 0x03,
+ 0x00, 0x3A, 0x01, 0x01, 0x02, 0x00, 0x0C, 0x13, 0x05, 0x01, 0x00, 0x63,
+ 0x01, 0x03, 0x3B, 0x06, 0x07, 0x02, 0x00, 0xE2, 0x01, 0x02, 0x3B, 0xE2,
+ 0x00, 0x00, 0x2A, 0x01, 0x08, 0x54, 0xE2, 0xE2, 0x00, 0x00, 0x2A, 0x01,
+ 0x10, 0x54, 0xE2, 0xE0, 0x00, 0x00, 0x2A, 0x57, 0x06, 0x02, 0x29, 0x00,
+ 0xCF, 0x29, 0x04, 0x76
+};
+
+static const uint16_t t0_caddr[] = {
+ 0,
+ 5,
+ 10,
+ 15,
+ 20,
+ 25,
+ 30,
+ 35,
+ 40,
+ 44,
+ 48,
+ 52,
+ 56,
+ 60,
+ 64,
+ 68,
+ 72,
+ 76,
+ 80,
+ 84,
+ 88,
+ 92,
+ 96,
+ 100,
+ 104,
+ 109,
+ 114,
+ 119,
+ 124,
+ 129,
+ 134,
+ 139,
+ 144,
+ 149,
+ 154,
+ 159,
+ 164,
+ 169,
+ 174,
+ 180,
+ 185,
+ 190,
+ 195,
+ 200,
+ 205,
+ 210,
+ 215,
+ 220,
+ 225,
+ 230,
+ 235,
+ 240,
+ 245,
+ 250,
+ 255,
+ 260,
+ 265,
+ 270,
+ 275,
+ 280,
+ 285,
+ 290,
+ 299,
+ 303,
+ 328,
+ 334,
+ 353,
+ 364,
+ 405,
+ 516,
+ 520,
+ 553,
+ 563,
+ 587,
+ 669,
+ 683,
+ 689,
+ 748,
+ 767,
+ 789,
+ 838,
+ 887,
+ 963,
+ 1065,
+ 1076,
+ 1670,
+ 1674,
+ 1741,
+ 1751,
+ 1782,
+ 1806,
+ 1852,
+ 1922,
+ 1962,
+ 1976,
+ 1985,
+ 1989,
+ 2084,
+ 2092,
+ 2128,
+ 2139,
+ 2155,
+ 2161,
+ 2172,
+ 2207,
+ 2233,
+ 2245,
+ 2251,
+ 2264,
+ 2279,
+ 2472,
+ 2481,
+ 2494,
+ 2503,
+ 2510,
+ 2616,
+ 2641,
+ 2654,
+ 2670,
+ 2688,
+ 2720,
+ 2793,
+ 2806,
+ 2987,
+ 2995,
+ 3122,
+ 3136,
+ 3141,
+ 3185,
+ 3242,
+ 3263,
+ 3290,
+ 3298,
+ 3306
+};
+
+#define T0_INTERPRETED 93
+
+#define T0_ENTER(ip, rp, slot) do { \
+ const unsigned char *t0_newip; \
+ uint32_t t0_lnum; \
+ t0_newip = &t0_codeblock[t0_caddr[(slot) - T0_INTERPRETED]]; \
+ t0_lnum = t0_parse7E_unsigned(&t0_newip); \
+ (rp) += t0_lnum; \
+ *((rp) ++) = (uint32_t)((ip) - &t0_codeblock[0]) + (t0_lnum << 16); \
+ (ip) = t0_newip; \
+ } while (0)
+
+#define T0_DEFENTRY(name, slot) \
+void \
+name(void *ctx) \
+{ \
+ t0_context *t0ctx = ctx; \
+ t0ctx->ip = &t0_codeblock[0]; \
+ T0_ENTER(t0ctx->ip, t0ctx->rp, slot); \
+}
+
+T0_DEFENTRY(br_ssl_hs_server_init_main, 166)
+
+#define T0_NEXT(t0ipp) (*(*(t0ipp)) ++)
+
+void
+br_ssl_hs_server_run(void *t0ctx)
+{
+ uint32_t *dp, *rp;
+ const unsigned char *ip;
+
+#define T0_LOCAL(x) (*(rp - 2 - (x)))
+#define T0_POP() (*-- dp)
+#define T0_POPi() (*(int32_t *)(-- dp))
+#define T0_PEEK(x) (*(dp - 1 - (x)))
+#define T0_PEEKi(x) (*(int32_t *)(dp - 1 - (x)))
+#define T0_PUSH(v) do { *dp = (v); dp ++; } while (0)
+#define T0_PUSHi(v) do { *(int32_t *)dp = (v); dp ++; } while (0)
+#define T0_RPOP() (*-- rp)
+#define T0_RPOPi() (*(int32_t *)(-- rp))
+#define T0_RPUSH(v) do { *rp = (v); rp ++; } while (0)
+#define T0_RPUSHi(v) do { *(int32_t *)rp = (v); rp ++; } while (0)
+#define T0_ROLL(x) do { \
+ size_t t0len = (size_t)(x); \
+ uint32_t t0tmp = *(dp - 1 - t0len); \
+ memmove(dp - t0len - 1, dp - t0len, t0len * sizeof *dp); \
+ *(dp - 1) = t0tmp; \
+} while (0)
+#define T0_SWAP() do { \
+ uint32_t t0tmp = *(dp - 2); \
+ *(dp - 2) = *(dp - 1); \
+ *(dp - 1) = t0tmp; \
+} while (0)
+#define T0_ROT() do { \
+ uint32_t t0tmp = *(dp - 3); \
+ *(dp - 3) = *(dp - 2); \
+ *(dp - 2) = *(dp - 1); \
+ *(dp - 1) = t0tmp; \
+} while (0)
+#define T0_NROT() do { \
+ uint32_t t0tmp = *(dp - 1); \
+ *(dp - 1) = *(dp - 2); \
+ *(dp - 2) = *(dp - 3); \
+ *(dp - 3) = t0tmp; \
+} while (0)
+#define T0_PICK(x) do { \
+ uint32_t t0depth = (x); \
+ T0_PUSH(T0_PEEK(t0depth)); \
+} while (0)
+#define T0_CO() do { \
+ goto t0_exit; \
+} while (0)
+#define T0_RET() goto t0_next
+
+ dp = ((t0_context *)t0ctx)->dp;
+ rp = ((t0_context *)t0ctx)->rp;
+ ip = ((t0_context *)t0ctx)->ip;
+ goto t0_next;
+ for (;;) {
+ uint32_t t0x;
+
+ t0_next:
+ t0x = T0_NEXT(&ip);
+ if (t0x < T0_INTERPRETED) {
+ switch (t0x) {
+ int32_t t0off;
+
+ case 0: /* ret */
+ t0x = T0_RPOP();
+ rp -= (t0x >> 16);
+ t0x &= 0xFFFF;
+ if (t0x == 0) {
+ ip = NULL;
+ goto t0_exit;
+ }
+ ip = &t0_codeblock[t0x];
+ break;
+ case 1: /* literal constant */
+ T0_PUSHi(t0_parse7E_signed(&ip));
+ break;
+ case 2: /* read local */
+ T0_PUSH(T0_LOCAL(t0_parse7E_unsigned(&ip)));
+ break;
+ case 3: /* write local */
+ T0_LOCAL(t0_parse7E_unsigned(&ip)) = T0_POP();
+ break;
+ case 4: /* jump */
+ t0off = t0_parse7E_signed(&ip);
+ ip += t0off;
+ break;
+ case 5: /* jump if */
+ t0off = t0_parse7E_signed(&ip);
+ if (T0_POP()) {
+ ip += t0off;
+ }
+ break;
+ case 6: /* jump if not */
+ t0off = t0_parse7E_signed(&ip);
+ if (!T0_POP()) {
+ ip += t0off;
+ }
+ break;
+ case 7: {
+ /* * */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a * b);
+
+ }
+ break;
+ case 8: {
+ /* + */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a + b);
+
+ }
+ break;
+ case 9: {
+ /* - */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a - b);
+
+ }
+ break;
+ case 10: {
+ /* -rot */
+ T0_NROT();
+ }
+ break;
+ case 11: {
+ /* < */
+
+ int32_t b = T0_POPi();
+ int32_t a = T0_POPi();
+ T0_PUSH(-(uint32_t)(a < b));
+
+ }
+ break;
+ case 12: {
+ /* << */
+
+ int c = (int)T0_POPi();
+ uint32_t x = T0_POP();
+ T0_PUSH(x << c);
+
+ }
+ break;
+ case 13: {
+ /* <= */
+
+ int32_t b = T0_POPi();
+ int32_t a = T0_POPi();
+ T0_PUSH(-(uint32_t)(a <= b));
+
+ }
+ break;
+ case 14: {
+ /* <> */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(-(uint32_t)(a != b));
+
+ }
+ break;
+ case 15: {
+ /* = */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(-(uint32_t)(a == b));
+
+ }
+ break;
+ case 16: {
+ /* > */
+
+ int32_t b = T0_POPi();
+ int32_t a = T0_POPi();
+ T0_PUSH(-(uint32_t)(a > b));
+
+ }
+ break;
+ case 17: {
+ /* >= */
+
+ int32_t b = T0_POPi();
+ int32_t a = T0_POPi();
+ T0_PUSH(-(uint32_t)(a >= b));
+
+ }
+ break;
+ case 18: {
+ /* >> */
+
+ int c = (int)T0_POPi();
+ int32_t x = T0_POPi();
+ T0_PUSHi(x >> c);
+
+ }
+ break;
+ case 19: {
+ /* and */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a & b);
+
+ }
+ break;
+ case 20: {
+ /* 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 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();
+ void *addr = (unsigned char *)ENG + (size_t)T0_POP();
+ memset(addr, 0, len);
+
+ }
+ break;
+ case 24: {
+ /* call-policy-handler */
+
+ int x;
+ br_ssl_server_choices choices;
+
+ x = (*CTX->policy_vtable)->choose(
+ CTX->policy_vtable, CTX, &choices);
+ ENG->session.cipher_suite = choices.cipher_suite;
+ CTX->sign_hash_id = choices.algo_id;
+ ENG->chain = choices.chain;
+ ENG->chain_len = choices.chain_len;
+ T0_PUSHi(-(x != 0));
+
+ }
+ break;
+ case 25: {
+ /* can-output? */
+
+ T0_PUSHi(-(ENG->hlen_out > 0));
+
+ }
+ break;
+ case 26: {
+ /* check-resume */
+
+ if (ENG->session.session_id_len == 32
+ && CTX->cache_vtable != NULL && (*CTX->cache_vtable)->load(
+ CTX->cache_vtable, CTX, &ENG->session))
+ {
+ T0_PUSHi(-1);
+ } else {
+ T0_PUSH(0);
+ }
+
+ }
+ break;
+ case 27: {
+ /* co */
+ T0_CO();
+ }
+ break;
+ case 28: {
+ /* compute-Finished-inner */
+
+ int prf_id = T0_POP();
+ int from_client = T0_POPi();
+ unsigned char tmp[48];
+ br_tls_prf_seed_chunk seed;
+
+ br_tls_prf_impl prf = br_ssl_engine_get_PRF(ENG, prf_id);
+ seed.data = tmp;
+ if (ENG->session.version >= BR_TLS12) {
+ seed.len = br_multihash_out(&ENG->mhash, prf_id, tmp);
+ } else {
+ br_multihash_out(&ENG->mhash, br_md5_ID, tmp);
+ br_multihash_out(&ENG->mhash, br_sha1_ID, tmp + 16);
+ seed.len = 36;
+ }
+ prf(ENG->pad, 12, ENG->session.master_secret,
+ sizeof ENG->session.master_secret,
+ from_client ? "client finished" : "server finished",
+ 1, &seed);
+
+ }
+ break;
+ 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 = 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 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: {
+ /* copy-protocol-name */
+
+ size_t idx = T0_POP();
+ size_t len = strlen(ENG->protocol_names[idx]);
+ memcpy(ENG->pad, ENG->protocol_names[idx], len);
+ T0_PUSH(len);
+
+ }
+ break;
+ case 34: {
+ /* data-get8 */
+
+ size_t addr = T0_POP();
+ T0_PUSH(t0_datablock[addr]);
+
+ }
+ break;
+ case 35: {
+ /* discard-input */
+
+ ENG->hlen_in = 0;
+
+ }
+ break;
+ case 36: {
+ /* do-ecdh */
+
+ int prf_id = T0_POPi();
+ size_t len = T0_POP();
+ do_ecdh(CTX, prf_id, ENG->pad, len);
+
+ }
+ break;
+ case 37: {
+ /* do-ecdhe-part1 */
+
+ int curve = T0_POPi();
+ T0_PUSHi(do_ecdhe_part1(CTX, curve));
+
+ }
+ break;
+ case 38: {
+ /* do-ecdhe-part2 */
+
+ int prf_id = T0_POPi();
+ size_t len = T0_POP();
+ do_ecdhe_part2(CTX, prf_id, ENG->pad, len);
+
+ }
+ break;
+ case 39: {
+ /* do-rsa-decrypt */
+
+ int prf_id = T0_POPi();
+ size_t len = T0_POP();
+ do_rsa_decrypt(CTX, prf_id, ENG->pad, len);
+
+ }
+ break;
+ case 40: {
+ /* do-static-ecdh */
+
+ do_static_ecdh(CTX, T0_POP());
+
+ }
+ break;
+ case 41: {
+ /* drop */
+ (void)T0_POP();
+ }
+ break;
+ case 42: {
+ /* dup */
+ T0_PUSH(T0_PEEK(0));
+ }
+ break;
+ case 43: {
+ /* fail */
+
+ br_ssl_engine_fail(ENG, (int)T0_POPi());
+ T0_CO();
+
+ }
+ break;
+ case 44: {
+ /* flush-record */
+
+ br_ssl_engine_flush_record(ENG);
+
+ }
+ break;
+ case 45: {
+ /* 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 46: {
+ /* get16 */
+
+ size_t addr = (size_t)T0_POP();
+ T0_PUSH(*(uint16_t *)(void *)((unsigned char *)ENG + addr));
+
+ }
+ break;
+ case 47: {
+ /* get32 */
+
+ size_t addr = (size_t)T0_POP();
+ T0_PUSH(*(uint32_t *)(void *)((unsigned char *)ENG + addr));
+
+ }
+ break;
+ case 48: {
+ /* get8 */
+
+ size_t addr = (size_t)T0_POP();
+ T0_PUSH(*((unsigned char *)ENG + addr));
+
+ }
+ break;
+ case 49: {
+ /* has-input? */
+
+ T0_PUSHi(-(ENG->hlen_in != 0));
+
+ }
+ break;
+ case 50: {
+ /* memcmp */
+
+ size_t len = (size_t)T0_POP();
+ void *addr2 = (unsigned char *)ENG + (size_t)T0_POP();
+ void *addr1 = (unsigned char *)ENG + (size_t)T0_POP();
+ int x = memcmp(addr1, addr2, len);
+ T0_PUSH((uint32_t)-(x == 0));
+
+ }
+ break;
+ case 51: {
+ /* memcpy */
+
+ size_t len = (size_t)T0_POP();
+ void *src = (unsigned char *)ENG + (size_t)T0_POP();
+ void *dst = (unsigned char *)ENG + (size_t)T0_POP();
+ memcpy(dst, src, len);
+
+ }
+ break;
+ case 52: {
+ /* mkrand */
+
+ size_t len = (size_t)T0_POP();
+ void *addr = (unsigned char *)ENG + (size_t)T0_POP();
+ br_hmac_drbg_generate(&ENG->rng, addr, len);
+
+ }
+ break;
+ case 53: {
+ /* more-incoming-bytes? */
+
+ T0_PUSHi(ENG->hlen_in != 0 || !br_ssl_engine_recvrec_finished(ENG));
+
+ }
+ break;
+ case 54: {
+ /* multihash-init */
+
+ br_multihash_init(&ENG->mhash);
+
+ }
+ break;
+ case 55: {
+ /* neg */
+
+ uint32_t a = T0_POP();
+ T0_PUSH(-a);
+
+ }
+ break;
+ case 56: {
+ /* not */
+
+ uint32_t a = T0_POP();
+ T0_PUSH(~a);
+
+ }
+ break;
+ case 57: {
+ /* or */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a | b);
+
+ }
+ break;
+ case 58: {
+ /* over */
+ T0_PUSH(T0_PEEK(1));
+ }
+ break;
+ case 59: {
+ /* pick */
+ T0_PICK(T0_POP());
+ }
+ break;
+ case 60: {
+ /* read-chunk-native */
+
+ size_t clen = ENG->hlen_in;
+ if (clen > 0) {
+ uint32_t addr, len;
+
+ len = T0_POP();
+ addr = T0_POP();
+ if ((size_t)len < clen) {
+ clen = (size_t)len;
+ }
+ memcpy((unsigned char *)ENG + addr, ENG->hbuf_in, clen);
+ if (ENG->record_type_in == BR_SSL_HANDSHAKE) {
+ br_multihash_update(&ENG->mhash, ENG->hbuf_in, clen);
+ }
+ T0_PUSH(addr + (uint32_t)clen);
+ T0_PUSH(len - (uint32_t)clen);
+ ENG->hbuf_in += clen;
+ ENG->hlen_in -= clen;
+ }
+
+ }
+ break;
+ case 61: {
+ /* read8-native */
+
+ if (ENG->hlen_in > 0) {
+ unsigned char x;
+
+ x = *ENG->hbuf_in ++;
+ if (ENG->record_type_in == BR_SSL_HANDSHAKE) {
+ br_multihash_update(&ENG->mhash, &x, 1);
+ }
+ T0_PUSH(x);
+ ENG->hlen_in --;
+ } else {
+ T0_PUSHi(-1);
+ }
+
+ }
+ break;
+ case 62: {
+ /* save-session */
+
+ if (CTX->cache_vtable != NULL) {
+ (*CTX->cache_vtable)->save(
+ CTX->cache_vtable, CTX, &ENG->session);
+ }
+
+ }
+ break;
+ case 63: {
+ /* set-max-frag-len */
+
+ size_t max_frag_len = T0_POP();
+
+ br_ssl_engine_new_max_frag_len(ENG, max_frag_len);
+
+ /*
+ * We must adjust our own output limit. Since we call this only
+ * after receiving a ClientHello and before beginning to send
+ * the ServerHello, the next output record should be empty at
+ * that point, so we can use max_frag_len as a limit.
+ */
+ if (ENG->hlen_out > max_frag_len) {
+ ENG->hlen_out = max_frag_len;
+ }
+
+ }
+ break;
+ case 64: {
+ /* set16 */
+
+ size_t addr = (size_t)T0_POP();
+ *(uint16_t *)(void *)((unsigned char *)ENG + addr) = (uint16_t)T0_POP();
+
+ }
+ break;
+ case 65: {
+ /* set32 */
+
+ size_t addr = (size_t)T0_POP();
+ *(uint32_t *)(void *)((unsigned char *)ENG + addr) = (uint32_t)T0_POP();
+
+ }
+ break;
+ case 66: {
+ /* set8 */
+
+ size_t addr = (size_t)T0_POP();
+ *((unsigned char *)ENG + addr) = (unsigned char)T0_POP();
+
+ }
+ break;
+ case 67: {
+ /* supported-curves */
+
+ uint32_t x = ENG->iec == NULL ? 0 : ENG->iec->supported_curves;
+ T0_PUSH(x);
+
+ }
+ break;
+ case 68: {
+ /* supported-hash-functions */
+
+ int i;
+ unsigned x, num;
+
+ x = 0;
+ num = 0;
+ for (i = br_sha1_ID; i <= br_sha512_ID; i ++) {
+ if (br_multihash_getimpl(&ENG->mhash, i)) {
+ x |= 1U << i;
+ num ++;
+ }
+ }
+ T0_PUSH(x);
+ T0_PUSH(num);
+
+ }
+ break;
+ case 69: {
+ /* supports-ecdsa? */
+
+ T0_PUSHi(-(ENG->iecdsa != 0));
+
+ }
+ break;
+ case 70: {
+ /* supports-rsa-sign? */
+
+ T0_PUSHi(-(ENG->irsavrfy != 0));
+
+ }
+ break;
+ case 71: {
+ /* swap */
+ T0_SWAP();
+ }
+ break;
+ case 72: {
+ /* switch-aesccm-in */
+
+ int is_client, prf_id;
+ unsigned cipher_key_len, tag_len;
+
+ tag_len = T0_POP();
+ cipher_key_len = T0_POP();
+ prf_id = T0_POP();
+ is_client = T0_POP();
+ br_ssl_engine_switch_ccm_in(ENG, is_client, prf_id,
+ ENG->iaes_ctrcbc, cipher_key_len, tag_len);
+
+ }
+ break;
+ case 73: {
+ /* switch-aesccm-out */
+
+ int is_client, prf_id;
+ unsigned cipher_key_len, tag_len;
+
+ tag_len = T0_POP();
+ cipher_key_len = T0_POP();
+ prf_id = T0_POP();
+ is_client = T0_POP();
+ br_ssl_engine_switch_ccm_out(ENG, is_client, prf_id,
+ ENG->iaes_ctrcbc, cipher_key_len, tag_len);
+
+ }
+ break;
+ case 74: {
+ /* switch-aesgcm-in */
+
+ int is_client, prf_id;
+ unsigned cipher_key_len;
+
+ cipher_key_len = T0_POP();
+ prf_id = T0_POP();
+ is_client = T0_POP();
+ br_ssl_engine_switch_gcm_in(ENG, is_client, prf_id,
+ ENG->iaes_ctr, cipher_key_len);
+
+ }
+ break;
+ case 75: {
+ /* switch-aesgcm-out */
+
+ int is_client, prf_id;
+ unsigned cipher_key_len;
+
+ cipher_key_len = T0_POP();
+ prf_id = T0_POP();
+ is_client = T0_POP();
+ br_ssl_engine_switch_gcm_out(ENG, is_client, prf_id,
+ ENG->iaes_ctr, cipher_key_len);
+
+ }
+ break;
+ case 76: {
+ /* switch-cbc-in */
+
+ int is_client, prf_id, mac_id, aes;
+ unsigned cipher_key_len;
+
+ cipher_key_len = T0_POP();
+ aes = T0_POP();
+ mac_id = T0_POP();
+ prf_id = T0_POP();
+ is_client = T0_POP();
+ br_ssl_engine_switch_cbc_in(ENG, is_client, prf_id, mac_id,
+ aes ? ENG->iaes_cbcdec : ENG->ides_cbcdec, cipher_key_len);
+
+ }
+ break;
+ case 77: {
+ /* switch-cbc-out */
+
+ int is_client, prf_id, mac_id, aes;
+ unsigned cipher_key_len;
+
+ cipher_key_len = T0_POP();
+ aes = T0_POP();
+ mac_id = T0_POP();
+ prf_id = T0_POP();
+ is_client = T0_POP();
+ br_ssl_engine_switch_cbc_out(ENG, is_client, prf_id, mac_id,
+ aes ? ENG->iaes_cbcenc : ENG->ides_cbcenc, cipher_key_len);
+
+ }
+ break;
+ case 78: {
+ /* switch-chapol-in */
+
+ int is_client, prf_id;
+
+ prf_id = T0_POP();
+ is_client = T0_POP();
+ br_ssl_engine_switch_chapol_in(ENG, is_client, prf_id);
+
+ }
+ break;
+ case 79: {
+ /* switch-chapol-out */
+
+ int is_client, prf_id;
+
+ prf_id = T0_POP();
+ is_client = T0_POP();
+ br_ssl_engine_switch_chapol_out(ENG, is_client, prf_id);
+
+ }
+ break;
+ case 80: {
+ /* 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 81: {
+ /* test-protocol-name */
+
+ size_t len = T0_POP();
+ size_t u;
+
+ for (u = 0; u < ENG->protocol_names_num; u ++) {
+ const char *name;
+
+ name = ENG->protocol_names[u];
+ if (len == strlen(name) && memcmp(ENG->pad, name, len) == 0) {
+ T0_PUSH(u);
+ T0_RET();
+ }
+ }
+ T0_PUSHi(-1);
+
+ }
+ break;
+ case 82: {
+ /* 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 83: {
+ /* u< */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(-(uint32_t)(a < b));
+
+ }
+ break;
+ case 84: {
+ /* u>> */
+
+ int c = (int)T0_POPi();
+ uint32_t x = T0_POP();
+ T0_PUSH(x >> c);
+
+ }
+ break;
+ case 85: {
+ /* verify-CV-sig */
+
+ int err;
+
+ err = verify_CV_sig(CTX, T0_POP());
+ T0_PUSHi(err);
+
+ }
+ break;
+ case 86: {
+ /* write-blob-chunk */
+
+ size_t clen = ENG->hlen_out;
+ if (clen > 0) {
+ uint32_t addr, len;
+
+ len = T0_POP();
+ addr = T0_POP();
+ if ((size_t)len < clen) {
+ clen = (size_t)len;
+ }
+ memcpy(ENG->hbuf_out, (unsigned char *)ENG + addr, clen);
+ if (ENG->record_type_out == BR_SSL_HANDSHAKE) {
+ br_multihash_update(&ENG->mhash, ENG->hbuf_out, clen);
+ }
+ T0_PUSH(addr + (uint32_t)clen);
+ T0_PUSH(len - (uint32_t)clen);
+ ENG->hbuf_out += clen;
+ ENG->hlen_out -= clen;
+ }
+
+ }
+ break;
+ case 87: {
+ /* write8-native */
+
+ unsigned char x;
+
+ x = (unsigned char)T0_POP();
+ if (ENG->hlen_out > 0) {
+ if (ENG->record_type_out == BR_SSL_HANDSHAKE) {
+ br_multihash_update(&ENG->mhash, &x, 1);
+ }
+ *ENG->hbuf_out ++ = x;
+ ENG->hlen_out --;
+ T0_PUSHi(-1);
+ } else {
+ T0_PUSHi(0);
+ }
+
+ }
+ break;
+ case 88: {
+ /* 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 89: {
+ /* x509-end-cert */
+
+ const br_x509_class *xc;
+
+ xc = *(ENG->x509ctx);
+ xc->end_cert(ENG->x509ctx);
+
+ }
+ break;
+ case 90: {
+ /* x509-end-chain */
+
+ const br_x509_class *xc;
+
+ xc = *(ENG->x509ctx);
+ T0_PUSH(xc->end_chain(ENG->x509ctx));
+
+ }
+ break;
+ case 91: {
+ /* x509-start-cert */
+
+ const br_x509_class *xc;
+
+ xc = *(ENG->x509ctx);
+ xc->start_cert(ENG->x509ctx, T0_POP());
+
+ }
+ break;
+ case 92: {
+ /* 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;
+ }
+
+ } else {
+ T0_ENTER(ip, rp, t0x);
+ }
+ }
+t0_exit:
+ ((t0_context *)t0ctx)->dp = dp;
+ ((t0_context *)t0ctx)->rp = rp;
+ ((t0_context *)t0ctx)->ip = ip;
+}
diff --git a/test/monniaux/BearSSL/src/ssl/ssl_hs_server.t0 b/test/monniaux/BearSSL/src/ssl/ssl_hs_server.t0
new file mode 100644
index 00000000..9f6e934e
--- /dev/null
+++ b/test/monniaux/BearSSL/src/ssl/ssl_hs_server.t0
@@ -0,0 +1,1510 @@
+\ Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+\
+\ Permission is hereby granted, free of charge, to any person obtaining
+\ a copy of this software and associated documentation files (the
+\ "Software"), to deal in the Software without restriction, including
+\ without limitation the rights to use, copy, modify, merge, publish,
+\ distribute, sublicense, and/or sell copies of the Software, and to
+\ permit persons to whom the Software is furnished to do so, subject to
+\ the following conditions:
+\
+\ The above copyright notice and this permission notice shall be
+\ included in all copies or substantial portions of the Software.
+\
+\ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+\ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+\ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+\ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+\ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+\ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+\ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+\ SOFTWARE.
+
+\ ----------------------------------------------------------------------
+\ Handshake processing code, for the server.
+\ The common T0 code (ssl_hs_common.t0) shall be read first.
+
+preamble {
+
+/*
+ * This macro evaluates to a pointer to the server context, under that
+ * specific name. It must be noted that since the engine context is the
+ * first field of the br_ssl_server_context structure ('eng'), then
+ * pointers values of both types are interchangeable, modulo an
+ * appropriate cast. This also means that "addresses" computed as offsets
+ * within the structure work for both kinds of context.
+ */
+#define CTX ((br_ssl_server_context *)ENG)
+
+/*
+ * Decrypt the pre-master secret (RSA key exchange).
+ */
+static void
+do_rsa_decrypt(br_ssl_server_context *ctx, int prf_id,
+ unsigned char *epms, size_t len)
+{
+ uint32_t x;
+ unsigned char rpms[48];
+
+ /*
+ * Decrypt the PMS.
+ */
+ x = (*ctx->policy_vtable)->do_keyx(ctx->policy_vtable, epms, &len);
+
+ /*
+ * Set the first two bytes to the maximum supported client
+ * protocol version. These bytes are used for version rollback
+ * detection; forceing the two bytes will make the master secret
+ * wrong if the bytes are not correct. This process is
+ * recommended by RFC 5246 (section 7.4.7.1).
+ */
+ br_enc16be(epms, ctx->client_max_version);
+
+ /*
+ * Make a random PMS and copy it above the decrypted value if the
+ * decryption failed. Note that we use a constant-time conditional
+ * copy.
+ */
+ br_hmac_drbg_generate(&ctx->eng.rng, rpms, sizeof rpms);
+ br_ccopy(x ^ 1, epms, rpms, sizeof rpms);
+
+ /*
+ * Compute master secret.
+ */
+ br_ssl_engine_compute_master(&ctx->eng, prf_id, epms, 48);
+
+ /*
+ * Clear the pre-master secret from RAM: it is normally a buffer
+ * in the context, hence potentially long-lived.
+ */
+ memset(epms, 0, len);
+}
+
+/*
+ * Common part for ECDH and ECDHE.
+ */
+static void
+ecdh_common(br_ssl_server_context *ctx, int prf_id,
+ unsigned char *xcoor, size_t xcoor_len, uint32_t ctl)
+{
+ unsigned char rpms[80];
+
+ if (xcoor_len > sizeof rpms) {
+ xcoor_len = sizeof rpms;
+ ctl = 0;
+ }
+
+ /*
+ * Make a random PMS and copy it above the decrypted value if the
+ * decryption failed. Note that we use a constant-time conditional
+ * copy.
+ */
+ br_hmac_drbg_generate(&ctx->eng.rng, rpms, xcoor_len);
+ br_ccopy(ctl ^ 1, xcoor, rpms, xcoor_len);
+
+ /*
+ * Compute master secret.
+ */
+ br_ssl_engine_compute_master(&ctx->eng, prf_id, xcoor, xcoor_len);
+
+ /*
+ * Clear the pre-master secret from RAM: it is normally a buffer
+ * in the context, hence potentially long-lived.
+ */
+ memset(xcoor, 0, xcoor_len);
+}
+
+/*
+ * Do the ECDH key exchange (not ECDHE).
+ */
+static void
+do_ecdh(br_ssl_server_context *ctx, int prf_id,
+ unsigned char *cpoint, size_t cpoint_len)
+{
+ uint32_t x;
+
+ /*
+ * Finalise the key exchange.
+ */
+ x = (*ctx->policy_vtable)->do_keyx(ctx->policy_vtable,
+ cpoint, &cpoint_len);
+ 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);
+}
+
+static size_t
+hash_data(br_ssl_server_context *ctx,
+ void *dst, int hash_id, const void *src, size_t len)
+{
+ const br_hash_class *hf;
+ br_hash_compat_context hc;
+
+ if (hash_id == 0) {
+ unsigned char tmp[36];
+
+ hf = br_multihash_getimpl(&ctx->eng.mhash, br_md5_ID);
+ if (hf == NULL) {
+ return 0;
+ }
+ hf->init(&hc.vtable);
+ hf->update(&hc.vtable, src, len);
+ hf->out(&hc.vtable, tmp);
+ hf = br_multihash_getimpl(&ctx->eng.mhash, br_sha1_ID);
+ if (hf == NULL) {
+ return 0;
+ }
+ hf->init(&hc.vtable);
+ hf->update(&hc.vtable, src, len);
+ hf->out(&hc.vtable, tmp + 16);
+ memcpy(dst, tmp, 36);
+ return 36;
+ } else {
+ hf = br_multihash_getimpl(&ctx->eng.mhash, hash_id);
+ if (hf == NULL) {
+ return 0;
+ }
+ hf->init(&hc.vtable);
+ hf->update(&hc.vtable, src, len);
+ hf->out(&hc.vtable, dst);
+ return (hf->desc >> BR_HASHDESC_OUT_OFF) & BR_HASHDESC_OUT_MASK;
+ }
+}
+
+/*
+ * 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
+ * signature length (in bytes), or -x on error (with x being an error
+ * code). The encoded point is written in the ecdhe_point[] context buffer
+ * (length in ecdhe_point_len).
+ */
+static int
+do_ecdhe_part1(br_ssl_server_context *ctx, int curve)
+{
+ unsigned algo_id;
+ unsigned mask;
+ const unsigned char *order;
+ size_t olen, glen;
+ size_t hv_len, sig_len;
+
+ if (!((ctx->eng.iec->supported_curves >> curve) & 1)) {
+ return -BR_ERR_INVALID_ALGORITHM;
+ }
+ ctx->eng.ecdhe_curve = curve;
+
+ /*
+ * Generate our private key. We need a non-zero random value
+ * which is lower than the curve order, in a "large enough"
+ * range. We force the top bit to 0 and bottom bit to 1, which
+ * does the trick. Note that contrary to what happens in ECDSA,
+ * this is not a problem if we do not cover the full range of
+ * possible values.
+ */
+ order = ctx->eng.iec->order(curve, &olen);
+ mask = 0xFF;
+ while (mask >= order[0]) {
+ mask >>= 1;
+ }
+ br_hmac_drbg_generate(&ctx->eng.rng, ctx->ecdhe_key, olen);
+ ctx->ecdhe_key[0] &= mask;
+ ctx->ecdhe_key[olen - 1] |= 0x01;
+ ctx->ecdhe_key_len = olen;
+
+ /*
+ * Compute our ECDH point.
+ */
+ glen = ctx->eng.iec->mulgen(ctx->eng.ecdhe_point,
+ ctx->ecdhe_key, olen, curve);
+ ctx->eng.ecdhe_point_len = glen;
+
+ /*
+ * Assemble the message to be signed, and possibly hash it.
+ */
+ memcpy(ctx->eng.pad, ctx->eng.client_random, 32);
+ memcpy(ctx->eng.pad + 32, ctx->eng.server_random, 32);
+ ctx->eng.pad[64 + 0] = 0x03;
+ ctx->eng.pad[64 + 1] = 0x00;
+ ctx->eng.pad[64 + 2] = curve;
+ ctx->eng.pad[64 + 3] = ctx->eng.ecdhe_point_len;
+ memcpy(ctx->eng.pad + 64 + 4,
+ ctx->eng.ecdhe_point, ctx->eng.ecdhe_point_len);
+ hv_len = 64 + 4 + ctx->eng.ecdhe_point_len;
+ algo_id = ctx->sign_hash_id;
+ if (algo_id >= (unsigned)0xFF00) {
+ hv_len = hash_data(ctx, ctx->eng.pad, algo_id & 0xFF,
+ ctx->eng.pad, hv_len);
+ if (hv_len == 0) {
+ return -BR_ERR_INVALID_ALGORITHM;
+ }
+ }
+
+ sig_len = (*ctx->policy_vtable)->do_sign(ctx->policy_vtable,
+ algo_id, ctx->eng.pad, hv_len, sizeof ctx->eng.pad);
+ return sig_len ? (int)sig_len : -BR_ERR_INVALID_ALGORITHM;
+}
+
+/*
+ * Do the ECDHE key exchange (part 2: computation of the shared secret
+ * from the point sent by the client).
+ */
+static void
+do_ecdhe_part2(br_ssl_server_context *ctx, int prf_id,
+ unsigned char *cpoint, size_t cpoint_len)
+{
+ int curve;
+ uint32_t ctl;
+ size_t xoff, xlen;
+
+ curve = ctx->eng.ecdhe_curve;
+
+ /*
+ * Finalise the key exchange.
+ */
+ ctl = ctx->eng.iec->mul(cpoint, cpoint_len,
+ ctx->ecdhe_key, ctx->ecdhe_key_len, curve);
+ xoff = ctx->eng.iec->xoff(curve, &xlen);
+ ecdh_common(ctx, prf_id, cpoint + xoff, xlen, ctl);
+
+ /*
+ * Clear the ECDHE private key. Forward Secrecy is achieved insofar
+ * as that key does not get stolen, so we'd better destroy it
+ * as soon as it ceases to be useful.
+ */
+ 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;
+}
+
+}
+
+\ =======================================================================
+
+: addr-ctx:
+ next-word { field }
+ "addr-" field + 0 1 define-word
+ 0 8191 "offsetof(br_ssl_server_context, " field + ")" + make-CX
+ postpone literal postpone ; ;
+
+addr-ctx: client_max_version
+addr-ctx: client_suites
+addr-ctx: client_suites_num
+addr-ctx: hashes
+addr-ctx: curves
+addr-ctx: sign_hash_id
+
+\ Get address and length of the client_suites[] buffer. Length is expressed
+\ in bytes.
+: addr-len-client_suites ( -- addr len )
+ addr-client_suites
+ CX 0 1023 { BR_MAX_CIPHER_SUITES * sizeof(br_suite_translated) } ;
+
+\ Read the client SNI extension.
+: read-client-sni ( lim -- lim )
+ \ Open extension value.
+ read16 open-elt
+
+ \ Open ServerNameList.
+ read16 open-elt
+
+ \ Find if there is a name of type 0 (host_name) with a length
+ \ that fits in our dedicated buffer.
+ begin dup while
+ read8 if
+ read-ignore-16
+ else
+ read16
+ dup 255 <= if
+ dup addr-server_name + 0 swap set8
+ addr-server_name swap read-blob
+ else
+ skip-blob
+ then
+ then
+ repeat
+
+ \ Close ServerNameList.
+ close-elt
+
+ \ Close extension value.
+ close-elt ;
+
+\ Set the new maximum fragment length. BEWARE: this shall be called only
+\ after reading the ClientHello and before writing the ServerHello.
+cc: set-max-frag-len ( len -- ) {
+ size_t max_frag_len = T0_POP();
+
+ br_ssl_engine_new_max_frag_len(ENG, max_frag_len);
+
+ /*
+ * We must adjust our own output limit. Since we call this only
+ * after receiving a ClientHello and before beginning to send
+ * the ServerHello, the next output record should be empty at
+ * that point, so we can use max_frag_len as a limit.
+ */
+ if (ENG->hlen_out > max_frag_len) {
+ ENG->hlen_out = max_frag_len;
+ }
+}
+
+\ Read the client Max Frag Length extension.
+: read-client-frag ( lim -- lim )
+ \ Extension value must have length exactly 1 byte.
+ read16 1 <> if ERR_BAD_FRAGLEN fail then
+ read8
+
+ \ The byte value must be 1, 2, 3 or 4.
+ dup dup 0= swap 5 >= or if ERR_BAD_FRAGLEN fail then
+
+ \ If our own maximum fragment length is greater, then we reduce
+ \ our length.
+ 8 + dup addr-log_max_frag_len get8 < if
+ dup 1 swap << set-max-frag-len
+ dup addr-log_max_frag_len set8
+ addr-peer_log_max_frag_len set8
+ else
+ drop
+ then ;
+
+\ Read the Secure Renegotiation extension from the client.
+: read-client-reneg ( lim -- lim )
+ \ Get value length.
+ read16
+
+ \ The "reneg" value is one of:
+ \ 0 on first handshake, client support is unknown
+ \ 1 client does not support secure renegotiation
+ \ 2 client supports secure renegotiation
+ addr-reneg get8 case
+ 0 of
+ \ First handshake, value length shall be 1.
+ 1 = ifnot ERR_BAD_SECRENEG fail then
+ read8 if ERR_BAD_SECRENEG fail then
+ 2 addr-reneg set8
+ endof
+ 2 of
+ \ Renegotiation, value shall consist of 13 bytes
+ \ (header + copy of the saved client "Finished").
+ 13 = ifnot ERR_BAD_SECRENEG fail then
+ read8 12 = ifnot ERR_BAD_SECRENEG fail then
+ addr-pad 12 read-blob
+ addr-saved_finished addr-pad 12 memcmp ifnot
+ ERR_BAD_SECRENEG fail
+ then
+ endof
+
+ \ If "reneg" is 1 then the client is not supposed to support
+ \ the extension, and it sends it nonetheless, which means
+ \ foul play.
+ ERR_BAD_SECRENEG fail
+ endcase ;
+
+\ Read the Signature Algorithms extension.
+: read-signatures ( lim -- lim )
+ \ Open extension value.
+ read16 open-elt
+
+ read-list-sign-algos addr-hashes set32
+
+ \ Close extension value.
+ close-elt ;
+
+\ Read the Supported Curves extension.
+: read-supported-curves ( lim -- lim )
+ \ Open extension value.
+ read16 open-elt
+
+ \ Open list of curve identifiers.
+ read16 open-elt
+
+ \ Get all supported curves.
+ 0 addr-curves set32
+ begin dup while
+ read16 dup 32 < if
+ 1 swap << addr-curves get32 or addr-curves set32
+ else
+ drop
+ then
+ repeat
+ close-elt
+ close-elt ;
+
+\ Read the ALPN extension from client.
+: read-ALPN-from-client ( lim -- lim )
+ \ If we do not have configured names, then we just ignore the
+ \ extension.
+ addr-protocol_names_num get16 ifnot read-ignore-16 ret then
+
+ \ Open extension value.
+ read16 open-elt
+
+ \ Open list of protocol names.
+ read16 open-elt
+
+ \ Get all names and test for their support. We keep the one with
+ \ the lowest index (because we apply server's preferences, as
+ \ recommended by RFC 7301, section 3.2. We set the 'found' variable
+ \ to -2 and use an unsigned comparison, making -2 a huge value.
+ -2 { found }
+ begin dup while
+ read8 dup { len } addr-pad swap read-blob
+ len test-protocol-name dup found u< if
+ >found
+ else
+ drop
+ then
+ repeat
+
+ \ End of extension.
+ close-elt
+ close-elt
+
+ \ Write back found name index (or not). If no match was found,
+ \ then we write -1 (0xFFFF) in the index value, not 0, so that
+ \ the caller knows that we tried to match, and failed.
+ found 1+ addr-selected_protocol set16 ;
+
+\ Call policy handler to get cipher suite, hash function identifier and
+\ certificate chain. Returned value is 0 (false) on failure.
+cc: call-policy-handler ( -- bool ) {
+ int x;
+ br_ssl_server_choices choices;
+
+ x = (*CTX->policy_vtable)->choose(
+ CTX->policy_vtable, CTX, &choices);
+ ENG->session.cipher_suite = choices.cipher_suite;
+ CTX->sign_hash_id = choices.algo_id;
+ ENG->chain = choices.chain;
+ ENG->chain_len = choices.chain_len;
+ T0_PUSHi(-(x != 0));
+}
+
+\ Check for a remembered session.
+cc: check-resume ( -- bool ) {
+ if (ENG->session.session_id_len == 32
+ && CTX->cache_vtable != NULL && (*CTX->cache_vtable)->load(
+ CTX->cache_vtable, CTX, &ENG->session))
+ {
+ T0_PUSHi(-1);
+ } else {
+ T0_PUSH(0);
+ }
+}
+
+\ Save the current session.
+cc: save-session ( -- ) {
+ if (CTX->cache_vtable != NULL) {
+ (*CTX->cache_vtable)->save(
+ CTX->cache_vtable, CTX, &ENG->session);
+ }
+}
+
+\ Read and drop ClientHello. This is used when a client-triggered
+\ renegotiation attempt is rejected.
+: skip-ClientHello ( -- )
+ read-handshake-header-core
+ 1 = ifnot ERR_UNEXPECTED fail then
+ dup skip-blob drop ;
+
+\ Read ClientHello. If the session is resumed, then -1 is returned.
+: read-ClientHello ( -- resume )
+ \ Get header, and check message type.
+ read-handshake-header 1 = ifnot ERR_UNEXPECTED fail then
+
+ \ Get maximum protocol version from client.
+ read16 dup { client-version-max } addr-client_max_version set16
+
+ \ Client random.
+ addr-client_random 32 read-blob
+
+ \ Client session ID.
+ read8 dup 32 > if ERR_OVERSIZED_ID fail then
+ dup addr-session_id_len set8
+ addr-session_id swap read-blob
+
+ \ Lookup session for resumption. We should do that here because
+ \ we need to verify that the remembered cipher suite is still
+ \ matched by this ClientHello.
+ check-resume { resume }
+
+ \ Cipher suites. We read all cipher suites from client, each time
+ \ matching against our own list. We accumulate suites in the
+ \ client_suites[] context buffer: we keep suites that are
+ \ supported by both the client and the server (so the list size
+ \ cannot exceed that of the server list), and we keep them in
+ \ either client or server preference order (depending on the
+ \ relevant flag).
+ \
+ \ We also need to identify the pseudo cipher suite for secure
+ \ renegotiation here.
+ read16 open-elt
+ 0 { reneg-scsv }
+ 0 { resume-suite }
+ addr-len-client_suites dup2 bzero
+ over + { css-off css-max }
+ begin
+ dup while
+ read16 dup { suite }
+
+ \ Check that when resuming a session, the requested
+ \ suite is still valid.
+ resume if
+ dup addr-cipher_suite get16 = if
+ -1 >resume-suite
+ then
+ then
+
+ \ Special handling for TLS_EMPTY_RENEGOTIATION_INFO_SCSV.
+ \ This fake cipher suite may occur only in the first
+ \ handshake.
+ dup 0x00FF = if
+ addr-reneg get8 if ERR_BAD_SECRENEG fail then
+ -1 >reneg-scsv
+ then
+
+ \ Special handling for TLS_FALLBACK_SCSV. If the client
+ \ maximum version is less than our own maximum version,
+ \ then this is an undue downgrade. We mark it by setting
+ \ the client max version to 0x10000.
+ dup 0x5600 = if
+ client-version-max addr-version_min get16 >=
+ client-version-max addr-version_max get16 < and if
+ -1 >client-version-max
+ then
+ then
+
+ \ Test whether the suite is supported by the server.
+ scan-suite dup 0< if
+ \ We do not support this cipher suite. Note
+ \ that this also covers the case of pseudo
+ \ cipher suites.
+ drop
+ else
+ \ If we use server order, then we place the
+ \ suite at the computed offset; otherwise, we
+ \ append it to the list at the current place.
+ 0 flag? if
+ 2 << addr-client_suites + suite swap set16
+ else
+ drop
+ \ We need to test for list length because
+ \ the client list may have duplicates,
+ \ that we do not filter. Duplicates are
+ \ invalid so this is not a problem if we
+ \ reject such clients.
+ css-off css-max >= if
+ ERR_BAD_HANDSHAKE fail
+ then
+ suite css-off set16
+ css-off 4 + >css-off
+ then
+ then
+ repeat
+ drop
+
+ \ Compression methods. We need method 0 (no compression).
+ 0 { ok-compression }
+ read8 open-elt
+ begin dup while
+ read8 ifnot -1 >ok-compression then
+ repeat
+ close-elt
+
+ \ Set default values for parameters that may be affected by
+ \ extensions:
+ \ -- server name is empty
+ \ -- client is reputed to know RSA and ECDSA, both with SHA-1
+ \ -- the default elliptic curve is P-256 (secp256r1, id = 23)
+ 0 addr-server_name set8
+ 0x0404 addr-hashes set32
+ 0x800000 addr-curves set32
+
+ \ Process extensions, if any.
+ dup if
+ read16 open-elt
+ begin dup while
+ read16 case
+ \ Server Name Indication.
+ 0x0000 of
+ read-client-sni
+ endof
+ \ Max Frag Length.
+ 0x0001 of
+ read-client-frag
+ endof
+ \ Secure Renegotiation.
+ 0xFF01 of
+ read-client-reneg
+ endof
+ \ Signature Algorithms.
+ 0x000D of
+ read-signatures
+ endof
+ \ Supported Curves.
+ 0x000A of
+ read-supported-curves
+ endof
+ \ Supported Point Formats.
+ \ We only support "uncompressed", that all
+ \ implementations are supposed to support,
+ \ so we can simply ignore that extension.
+ \ 0x000B of
+ \ read-ignore-16
+ \ endof
+
+ \ ALPN
+ 0x0010 of
+ read-ALPN-from-client
+ endof
+
+ \ Other extensions are ignored.
+ drop read-ignore-16 0
+ endcase
+ repeat
+ close-elt
+ then
+
+ \ Close message.
+ close-elt
+
+ \ Cancel session resumption if the cipher suite was not found.
+ resume resume-suite and >resume
+
+ \ Now check the received data. Since the client is expecting an
+ \ answer, we can send an appropriate fatal alert on any error.
+
+ \ Compute protocol version as the minimum of our maximum version,
+ \ and the maximum version sent by the client. If that is less than
+ \ 0x0300 (SSL-3.0), then fail. Otherwise, we may at least send an
+ \ alert with that version. We still reject versions lower than our
+ \ configured minimum.
+ \ As a special case, in case of undue downgrade, we send a specific
+ \ alert (see RFC 7507). Note that this case may happen only if
+ \ we would otherwise accept the client's version.
+ client-version-max 0< if
+ addr-client_max_version get16 addr-version_out set16
+ 86 fail-alert
+ then
+ addr-version_max get16
+ dup client-version-max > if drop client-version-max then
+ dup 0x0300 < if ERR_BAD_VERSION fail then
+ client-version-max addr-version_min get16 < if
+ 70 fail-alert
+ then
+ \ If resuming the session, then enforce the previously negotiated
+ \ version (if still possible).
+ resume if
+ addr-version get16 client-version-max <= if
+ drop addr-version get16
+ else
+ 0 >resume
+ then
+ then
+ dup addr-version set16
+ dup addr-version_in set16
+ dup addr-version_out set16
+ 0x0303 >= { can-tls12 }
+
+ \ If the client sent TLS_EMPTY_RENEGOTIATION_INFO_SCSV, then
+ \ we should mark the client as "supporting secure renegotiation".
+ reneg-scsv if 2 addr-reneg set8 then
+
+ \ If, at that point, the 'reneg' value is still 0, then the client
+ \ did not send the extension or the SCSV, so we have to assume
+ \ that secure renegotiation is not supported by that client.
+ addr-reneg get8 ifnot 1 addr-reneg set8 then
+
+ \ Check compression.
+ ok-compression ifnot 40 fail-alert then
+
+ \ Filter hash function support by what the server also supports.
+ \ If no common hash function remains with RSA and/or ECDSA, then
+ \ the corresponding ECDHE suites are not possible.
+ supported-hash-functions drop 257 * 0xFFFF0000 or
+ addr-hashes get32 and dup addr-hashes set32
+ \ 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 12 << { can-ecdhe }
+
+ \ Filter supported curves. If there is no common curve between
+ \ client and us, then ECDHE suites cannot be used. Note that we
+ \ may still allow ECDH, depending on the EC key handler.
+ addr-curves get32 supported-curves and dup addr-curves set32
+ ifnot 0 >can-ecdhe then
+
+ \ If resuming a session, then the next steps are not necessary;
+ \ we won't invoke the policy handler.
+ 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
+
+ \ Translate common cipher suites, then squeeze out holes: there
+ \ may be holes because of the way we fill the list when the
+ \ 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 the relevant signature algorithm) or no common curve.
+ \ -- TLS-1.2-only suites are removed if the negotiated 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
+ dup 12 >> dup 1 = swap 2 = or if
+ dup can-ecdhe and ifnot
+ 2drop 0 dup
+ then
+ then
+ can-tls12 ifnot
+ \ Suites compatible with TLS-1.0 and TLS-1.1 are
+ \ exactly the ones that use HMAC/SHA-1.
+ dup 0xF0 and 0x20 <> if
+ 2drop 0 dup
+ then
+ then
+ dup if
+ css-off 2+ set16 css-off set16
+ css-off 4 + >css-off
+ else
+ 2drop
+ then
+ 4 +
+ repeat
+ drop
+ css-off addr-client_suites - 2 >>
+ dup ifnot
+ \ No common cipher suite: handshake failure.
+ 40 fail-alert
+ then
+ addr-client_suites_num set8
+
+ \ Check ALPN.
+ addr-selected_protocol get16 0xFFFF = if
+ 3 flag? if 120 fail-alert then
+ 0 addr-selected_protocol set16
+ then
+
+ \ Call policy handler to obtain the cipher suite and other
+ \ parameters.
+ call-policy-handler ifnot 40 fail-alert then
+
+ \ We are not resuming a session.
+ 0 ;
+
+\ Write ServerHello.
+: write-ServerHello ( initial -- )
+ { initial }
+ \ Compute ServerHello length.
+ 2 write8 70
+
+ \ Compute length of Secure Renegotiation extension.
+ addr-reneg get8 2 = if
+ initial if 5 else 29 then
+ else
+ 0
+ then
+ { ext-reneg-len }
+
+ \ Compute length of Max Fragment Length extension.
+ addr-peer_log_max_frag_len get8 if 5 else 0 then
+ { ext-max-frag-len }
+
+ \ Compute length of ALPN extension. This also copy the
+ \ selected protocol name into the pad.
+ addr-selected_protocol get16 dup if 1- copy-protocol-name 7 + then
+ { ext-ALPN-len }
+
+ \ Adjust ServerHello length to account for the extensions.
+ ext-reneg-len ext-max-frag-len + ext-ALPN-len + dup if 2 + then +
+ write24
+
+ \ Protocol version
+ addr-version get16 write16
+
+ \ Server random
+ addr-server_random 4 bzero
+ addr-server_random 4 + 28 mkrand
+ addr-server_random 32 write-blob
+
+ \ Session ID
+ \ TODO: if we have no session cache at all, we might send here
+ \ an empty session ID. This would save a bit of network
+ \ bandwidth.
+ 32 write8
+ addr-session_id 32 write-blob
+
+ \ Cipher suite
+ addr-cipher_suite get16 write16
+
+ \ Compression method
+ 0 write8
+
+ \ Extensions
+ ext-reneg-len ext-max-frag-len + ext-ALPN-len + dup if
+ write16
+ ext-reneg-len dup if
+ 0xFF01 write16
+ 4 - dup write16
+ 1- addr-saved_finished swap write-blob-head8
+ else
+ drop
+ then
+ ext-max-frag-len if
+ 0x0001 write16
+ 1 write16 addr-peer_log_max_frag_len get8 8 - write8
+ then
+ ext-ALPN-len dup if
+ \ Note: the selected protocol name was previously
+ \ copied into the pad.
+ 0x0010 write16
+ 4 - dup write16
+ 2- dup write16
+ 1- addr-pad swap write-blob-head8
+ else
+ drop
+ then
+ else
+ drop
+ then ;
+
+\ 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 ) {
+ int curve = T0_POPi();
+ T0_PUSHi(do_ecdhe_part1(CTX, curve));
+}
+
+\ Get index of first bit set to 1 (in low to high order).
+: lowest-1 ( bits -- n )
+ dup ifnot drop -1 ret then
+ 0 begin dup2 >> 1 and 0= while 1+ repeat
+ swap drop ;
+
+\ Write the Server Key Exchange message (if applicable).
+: write-ServerKeyExchange ( -- )
+ addr-cipher_suite get16 use-ecdhe? ifnot ret then
+
+ \ We must select an appropriate curve among the curves that
+ \ are supported both by us and the peer. Right now, we apply
+ \ a fixed preference order: Curve25519, P-256, P-384, P-521,
+ \ then the common curve with the lowest ID.
+ \ (TODO: add some option to make that behaviour configurable.)
+ \
+ \ This loop always terminates because previous processing made
+ \ sure that ECDHE suites are not selectable if there is no common
+ \ curve.
+ addr-curves get32
+ dup 0x20000000 and if
+ drop 29
+ else
+ dup 0x38000000 and dup if swap then
+ drop lowest-1
+ then
+ { curve-id }
+
+ \ Compute the signed curve point to send.
+ curve-id do-ecdhe-part1 dup 0< if neg fail then { sig-len }
+
+ \ If using TLS-1.2+, then the hash function and signature
+ \ algorithm are explicitly encoded in the message.
+ addr-version get16 0x0303 >= { tls1.2+ }
+
+ 12 write8
+ sig-len addr-ecdhe_point_len get8 + tls1.2+ 2 and + 6 + write24
+
+ \ Curve parameters: named curve with 16-bit ID.
+ 3 write8 curve-id write16
+
+ \ Public point.
+ addr-ecdhe_point addr-ecdhe_point_len get8 write-blob-head8
+
+ \ If TLS-1.2+, write hash and signature identifiers.
+ tls1.2+ if
+ \ sign_hash_id contains either a hash identifier,
+ \ or the complete 16-bit value to write.
+ addr-sign_hash_id get16
+ dup 0xFF00 < if
+ write16
+ else
+ 0xFF and write8
+ \ 'use-rsa-ecdhe?' returns -1 for RSA, 0 for
+ \ ECDSA. The byte on the wire shall be 1 for RSA,
+ \ 3 for ECDSA.
+ addr-cipher_suite get16 use-rsa-ecdhe? 1 << 3 + write8
+ then
+ then
+
+ \ Signature.
+ 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 ;
+
+\ Perform RSA decryption of the client-sent pre-master secret. The value
+\ is in the pad, and its length is provided as parameter.
+cc: do-rsa-decrypt ( len prf_id -- ) {
+ int prf_id = T0_POPi();
+ size_t len = T0_POP();
+ do_rsa_decrypt(CTX, prf_id, ENG->pad, len);
+}
+
+\ Perform ECDH (not ECDHE). The point from the client is in the pad, and
+\ its length is provided as parameter.
+cc: do-ecdh ( len prf_id -- ) {
+ int prf_id = T0_POPi();
+ size_t len = T0_POP();
+ do_ecdh(CTX, prf_id, ENG->pad, len);
+}
+
+\ Do the second part of ECDHE.
+cc: do-ecdhe-part2 ( len prf_id -- ) {
+ int prf_id = T0_POPi();
+ size_t len = T0_POP();
+ do_ecdhe_part2(CTX, prf_id, ENG->pad, len);
+}
+
+\ 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.
+ read16
+ dup 512 > if ERR_LIMIT_EXCEEDED fail then
+ dup { enc-rsa-len }
+ addr-pad swap read-blob
+ enc-rsa-len addr-cipher_suite get16 prf-id do-rsa-decrypt
+ then
+ addr-cipher_suite get16 dup use-ecdhe? swap use-ecdh? { ecdhe ecdh }
+ ecdh ecdhe or if
+ \ ECDH or ECDHE key exchange: we expect an EC point.
+ read8 dup { ec-point-len }
+ addr-pad swap read-blob
+ ec-point-len addr-cipher_suite get16 prf-id
+ ecdhe if do-ecdhe-part2 else do-ecdh then
+ 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
+ begin can-output? not while wait-co drop repeat
+ 22 addr-record_type_out set8
+ 0 write8 0 write24 flush-record
+ 23 addr-record_type_out set8 ;
+
+\ Make a handshake.
+: do-handshake ( initial -- )
+ 0 addr-application_data set8
+ 22 addr-record_type_out set8
+ 0 addr-selected_protocol set16
+ multihash-init
+ read-ClientHello
+ more-incoming-bytes? if ERR_UNEXPECTED fail then
+ if
+ \ Session resumption
+ write-ServerHello
+ 0 write-CCS-Finished
+ 0 read-CCS-Finished
+ else
+ \ Not a session resumption
+ write-ServerHello
+ write-Certificate drop
+ write-ServerKeyExchange
+ ta-names-total-length if
+ write-CertificateRequest
+ then
+ write-ServerHelloDone
+ flush-record
+
+ \ If we sent a CertificateRequest then we expect a
+ \ Certificate message.
+ ta-names-total-length if
+ \ Read client certificate.
+ 0 read-Certificate
+
+ choice
+ dup 0< uf
+ \ Client certificate validation failed.
+ 2 flag? ifnot neg fail then
+ drop
+ read-ClientKeyExchange
+ read-CertificateVerify-header
+ dup skip-blob drop
+ enduf
+ dup 0= uf
+ \ Client sent no certificate at all.
+ drop
+ 2 flag? ifnot
+ ERR_NO_CLIENT_AUTH fail
+ then
+ read-ClientKeyExchange
+ enduf
+
+ \ Client certificate was validated.
+ read-ClientKeyExchange-header
+ dup ifnot
+ \ Empty ClientKeyExchange.
+ drop
+ process-static-ECDH
+ else
+ read-ClientKeyExchange-contents
+ read-CertificateVerify
+ then
+ endchoice
+ else
+ \ No client certificate request, we just expect
+ \ a non-empty ClientKeyExchange.
+ read-ClientKeyExchange
+ then
+ 0 read-CCS-Finished
+ 0 write-CCS-Finished
+ save-session
+ then
+ 1 addr-application_data set8
+ 23 addr-record_type_out set8 ;
+
+\ Entry point.
+: main ( -- ! )
+ \ Perform initial handshake.
+ -1 do-handshake
+
+ begin
+ \ Wait for further invocation. At that point, we should
+ \ get either an explicit call for renegotiation, or
+ \ an incoming ClientHello handshake message.
+ wait-co
+ dup 0x07 and case
+ 0x00 of
+ 0x10 and if
+ \ The best we can do is ask for a
+ \ renegotiation, then wait for it
+ \ to happen.
+ 0 addr-application_data set8
+ send-HelloRequest
+ then
+ endof
+ 0x01 of
+ \ Reject renegotiations if the peer does not
+ \ support secure renegotiation, or if the
+ \ "no renegotiation" flag is set.
+ drop
+ addr-reneg get8 1 = 1 flag? or if
+ skip-ClientHello
+ flush-record
+ begin can-output? not while
+ wait-co drop
+ repeat
+ 100 send-warning
+ \ Put back connection in "application
+ \ data" state: it's not dead yet.
+ 1 addr-application_data set8
+ 23 addr-record_type_out set8
+ else
+ 0 do-handshake
+ then
+ endof
+ ERR_UNEXPECTED fail
+ endcase
+ again
+ ;
diff --git a/test/monniaux/BearSSL/src/ssl/ssl_io.c b/test/monniaux/BearSSL/src/ssl/ssl_io.c
new file mode 100644
index 00000000..19526159
--- /dev/null
+++ b/test/monniaux/BearSSL/src/ssl/ssl_io.c
@@ -0,0 +1,261 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_ssl.h */
+void
+br_sslio_init(br_sslio_context *ctx,
+ br_ssl_engine_context *engine,
+ int (*low_read)(void *read_context,
+ unsigned char *data, size_t len),
+ void *read_context,
+ int (*low_write)(void *write_context,
+ const unsigned char *data, size_t len),
+ void *write_context)
+{
+ ctx->engine = engine;
+ ctx->low_read = low_read;
+ ctx->read_context = read_context;
+ ctx->low_write = low_write;
+ ctx->write_context = write_context;
+}
+
+/*
+ * Run the engine, until the specified target state is achieved, or
+ * an error occurs. The target state is SENDAPP, RECVAPP, or the
+ * combination of both (the combination matches either). When a match is
+ * achieved, this function returns 0. On error, it returns -1.
+ */
+static int
+run_until(br_sslio_context *ctx, unsigned target)
+{
+ for (;;) {
+ unsigned state;
+
+ state = br_ssl_engine_current_state(ctx->engine);
+ if (state & BR_SSL_CLOSED) {
+ return -1;
+ }
+
+ /*
+ * If there is some record data to send, do it. This takes
+ * precedence over everything else.
+ */
+ if (state & BR_SSL_SENDREC) {
+ unsigned char *buf;
+ size_t len;
+ int wlen;
+
+ buf = br_ssl_engine_sendrec_buf(ctx->engine, &len);
+ wlen = ctx->low_write(ctx->write_context, buf, len);
+ if (wlen < 0) {
+ /*
+ * If we received a close_notify and we
+ * still send something, then we have our
+ * own response close_notify to send, and
+ * the peer is allowed by RFC 5246 not to
+ * wait for it.
+ */
+ if (!ctx->engine->shutdown_recv) {
+ br_ssl_engine_fail(
+ ctx->engine, BR_ERR_IO);
+ }
+ return -1;
+ }
+ if (wlen > 0) {
+ br_ssl_engine_sendrec_ack(ctx->engine, wlen);
+ }
+ continue;
+ }
+
+ /*
+ * If we reached our target, then we are finished.
+ */
+ if (state & target) {
+ return 0;
+ }
+
+ /*
+ * If some application data must be read, and we did not
+ * exit, then this means that we are trying to write data,
+ * and that's not possible until the application data is
+ * read. This may happen if using a shared in/out buffer,
+ * and the underlying protocol is not strictly half-duplex.
+ * This is unrecoverable here, so we report an error.
+ */
+ if (state & BR_SSL_RECVAPP) {
+ return -1;
+ }
+
+ /*
+ * If we reached that point, then either we are trying
+ * to read data and there is some, or the engine is stuck
+ * until a new record is obtained.
+ */
+ if (state & BR_SSL_RECVREC) {
+ unsigned char *buf;
+ size_t len;
+ int rlen;
+
+ buf = br_ssl_engine_recvrec_buf(ctx->engine, &len);
+ rlen = ctx->low_read(ctx->read_context, buf, len);
+ if (rlen < 0) {
+ br_ssl_engine_fail(ctx->engine, BR_ERR_IO);
+ return -1;
+ }
+ if (rlen > 0) {
+ br_ssl_engine_recvrec_ack(ctx->engine, rlen);
+ }
+ continue;
+ }
+
+ /*
+ * We can reach that point if the target RECVAPP, and
+ * the state contains SENDAPP only. This may happen with
+ * a shared in/out buffer. In that case, we must flush
+ * the buffered data to "make room" for a new incoming
+ * record.
+ */
+ br_ssl_engine_flush(ctx->engine, 0);
+ }
+}
+
+/* see bearssl_ssl.h */
+int
+br_sslio_read(br_sslio_context *ctx, void *dst, size_t len)
+{
+ unsigned char *buf;
+ size_t alen;
+
+ if (len == 0) {
+ return 0;
+ }
+ if (run_until(ctx, BR_SSL_RECVAPP) < 0) {
+ return -1;
+ }
+ buf = br_ssl_engine_recvapp_buf(ctx->engine, &alen);
+ if (alen > len) {
+ alen = len;
+ }
+ memcpy(dst, buf, alen);
+ br_ssl_engine_recvapp_ack(ctx->engine, alen);
+ return (int)alen;
+}
+
+/* see bearssl_ssl.h */
+int
+br_sslio_read_all(br_sslio_context *ctx, void *dst, size_t len)
+{
+ unsigned char *buf;
+
+ buf = dst;
+ while (len > 0) {
+ int rlen;
+
+ rlen = br_sslio_read(ctx, buf, len);
+ if (rlen < 0) {
+ return -1;
+ }
+ buf += rlen;
+ len -= (size_t)rlen;
+ }
+ return 0;
+}
+
+/* see bearssl_ssl.h */
+int
+br_sslio_write(br_sslio_context *ctx, const void *src, size_t len)
+{
+ unsigned char *buf;
+ size_t alen;
+
+ if (len == 0) {
+ return 0;
+ }
+ if (run_until(ctx, BR_SSL_SENDAPP) < 0) {
+ return -1;
+ }
+ buf = br_ssl_engine_sendapp_buf(ctx->engine, &alen);
+ if (alen > len) {
+ alen = len;
+ }
+ memcpy(buf, src, alen);
+ br_ssl_engine_sendapp_ack(ctx->engine, alen);
+ return (int)alen;
+}
+
+/* see bearssl_ssl.h */
+int
+br_sslio_write_all(br_sslio_context *ctx, const void *src, size_t len)
+{
+ const unsigned char *buf;
+
+ buf = src;
+ while (len > 0) {
+ int wlen;
+
+ wlen = br_sslio_write(ctx, buf, len);
+ if (wlen < 0) {
+ return -1;
+ }
+ buf += wlen;
+ len -= (size_t)wlen;
+ }
+ return 0;
+}
+
+/* see bearssl_ssl.h */
+int
+br_sslio_flush(br_sslio_context *ctx)
+{
+ /*
+ * We trigger a flush. We know the data is gone when there is
+ * no longer any record data to send, and we can either read
+ * or write application data. The call to run_until() does the
+ * job because it ensures that any assembled record data is
+ * first sent down the wire before considering anything else.
+ */
+ br_ssl_engine_flush(ctx->engine, 0);
+ return run_until(ctx, BR_SSL_SENDAPP | BR_SSL_RECVAPP);
+}
+
+/* see bearssl_ssl.h */
+int
+br_sslio_close(br_sslio_context *ctx)
+{
+ br_ssl_engine_close(ctx->engine);
+ while (br_ssl_engine_current_state(ctx->engine) != BR_SSL_CLOSED) {
+ /*
+ * Discard any incoming application data.
+ */
+ size_t len;
+
+ run_until(ctx, BR_SSL_RECVAPP);
+ if (br_ssl_engine_recvapp_buf(ctx->engine, &len) != NULL) {
+ br_ssl_engine_recvapp_ack(ctx->engine, len);
+ }
+ }
+ return br_ssl_engine_last_error(ctx->engine) == BR_ERR_OK;
+}
diff --git a/test/monniaux/BearSSL/src/ssl/ssl_keyexport.c b/test/monniaux/BearSSL/src/ssl/ssl_keyexport.c
new file mode 100644
index 00000000..58e6dc3c
--- /dev/null
+++ b/test/monniaux/BearSSL/src/ssl/ssl_keyexport.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/*
+ * Supported cipher suites that use SHA-384 for the PRF when selected
+ * for TLS 1.2. All other cipher suites are deemed to use SHA-256.
+ */
+static const uint16_t suites_sha384[] = {
+ BR_TLS_RSA_WITH_AES_256_GCM_SHA384,
+ BR_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
+ BR_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384,
+ BR_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
+ BR_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384,
+ BR_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+ BR_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384,
+ BR_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+ BR_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384
+};
+
+/* see bearssl_ssl.h */
+int
+br_ssl_key_export(br_ssl_engine_context *cc,
+ void *dst, size_t len, const char *label,
+ const void *context, size_t context_len)
+{
+ br_tls_prf_seed_chunk chunks[4];
+ br_tls_prf_impl iprf;
+ size_t num_chunks, u;
+ unsigned char tmp[2];
+ int prf_id;
+
+ if (cc->application_data != 1) {
+ return 0;
+ }
+ chunks[0].data = cc->client_random;
+ chunks[0].len = sizeof cc->client_random;
+ chunks[1].data = cc->server_random;
+ chunks[1].len = sizeof cc->server_random;
+ if (context != NULL) {
+ br_enc16be(tmp, (unsigned)context_len);
+ chunks[2].data = tmp;
+ chunks[2].len = 2;
+ chunks[3].data = context;
+ chunks[3].len = context_len;
+ num_chunks = 4;
+ } else {
+ num_chunks = 2;
+ }
+ prf_id = BR_SSLPRF_SHA256;
+ for (u = 0; u < (sizeof suites_sha384) / sizeof(uint16_t); u ++) {
+ if (suites_sha384[u] == cc->session.cipher_suite) {
+ prf_id = BR_SSLPRF_SHA384;
+ }
+ }
+ iprf = br_ssl_engine_get_PRF(cc, prf_id);
+ iprf(dst, len,
+ cc->session.master_secret, sizeof cc->session.master_secret,
+ label, num_chunks, chunks);
+ return 1;
+}
diff --git a/test/monniaux/BearSSL/src/ssl/ssl_lru.c b/test/monniaux/BearSSL/src/ssl/ssl_lru.c
new file mode 100644
index 00000000..4c71011f
--- /dev/null
+++ b/test/monniaux/BearSSL/src/ssl/ssl_lru.c
@@ -0,0 +1,537 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/*
+ * Each entry consists in a fixed number of bytes. Entries are concatenated
+ * in the store block. "Addresses" are really offsets in the block,
+ * expressed over 32 bits (so the cache may have size at most 4 GB, which
+ * "ought to be enough for everyone"). The "null address" is 0xFFFFFFFF.
+ * Note that since the storage block alignment is in no way guaranteed, we
+ * perform only accesses that can handle unaligned data.
+ *
+ * Two concurrent data structures are maintained:
+ *
+ * -- Entries are organised in a doubly-linked list; saved entries are added
+ * at the head, and loaded entries are moved to the head. Eviction uses
+ * the list tail (this is the LRU algorithm).
+ *
+ * -- Entries are indexed with a binary tree: all left descendants of a
+ * node have a lower session ID (in lexicographic order), while all
+ * right descendants have a higher session ID. The tree is heuristically
+ * balanced.
+ *
+ * Entry format:
+ *
+ * session ID 32 bytes
+ * master secret 48 bytes
+ * protocol version 2 bytes (big endian)
+ * cipher suite 2 bytes (big endian)
+ * list prev 4 bytes (big endian)
+ * list next 4 bytes (big endian)
+ * tree left child 4 bytes (big endian)
+ * tree right child 4 bytes (big endian)
+ *
+ * If an entry has a protocol version set to 0, then it is "disabled":
+ * it was a session pushed to the cache at some point, but it has
+ * been explicitly removed.
+ *
+ * We need to keep the tree balanced because an attacker could make
+ * handshakes, selecting some specific sessions (by reusing them) to
+ * try to make us make an imbalanced tree that makes lookups expensive
+ * (a denial-of-service attack that would persist as long as the cache
+ * remains, i.e. even after the attacker made all his connections).
+ * To do that, we replace the session ID (or the start of the session ID)
+ * with a HMAC value computed over the replaced part; the hash function
+ * implementation and the key are obtained from the server context upon
+ * first save() call.
+ *
+ * Theoretically, an attacker could use the exact timing of the lookup
+ * to infer the current tree topology, and try to revive entries to make
+ * it as unbalanced as possible. However, since the session ID are
+ * chosen randomly by the server, and the attacker cannot see the
+ * indexing values and must thus rely on blind selection, it should be
+ * exponentially difficult for the attacker to maintain a large
+ * imbalance.
+ */
+#define SESSION_ID_LEN 32
+#define MASTER_SECRET_LEN 48
+
+#define SESSION_ID_OFF 0
+#define MASTER_SECRET_OFF 32
+#define VERSION_OFF 80
+#define CIPHER_SUITE_OFF 82
+#define LIST_PREV_OFF 84
+#define LIST_NEXT_OFF 88
+#define TREE_LEFT_OFF 92
+#define TREE_RIGHT_OFF 96
+
+#define LRU_ENTRY_LEN 100
+
+#define ADDR_NULL ((uint32_t)-1)
+
+#define GETSET(name, off) \
+static inline uint32_t get_ ## name(br_ssl_session_cache_lru *cc, uint32_t x) \
+{ \
+ return br_dec32be(cc->store + x + (off)); \
+} \
+static inline void set_ ## name(br_ssl_session_cache_lru *cc, \
+ uint32_t x, uint32_t val) \
+{ \
+ br_enc32be(cc->store + x + (off), val); \
+}
+
+GETSET(prev, LIST_PREV_OFF)
+GETSET(next, LIST_NEXT_OFF)
+GETSET(left, TREE_LEFT_OFF)
+GETSET(right, TREE_RIGHT_OFF)
+
+/*
+ * Transform the session ID by replacing the first N bytes with a HMAC
+ * value computed over these bytes, using the random key K (the HMAC
+ * value is truncated if needed). HMAC will use the same hash function
+ * as the DRBG in the SSL server context, so with SHA-256, SHA-384,
+ * or SHA-1, depending on what is available.
+ *
+ * The risk of collision is considered too small to be a concern; and
+ * the impact of a collision is low (the handshake won't succeed). This
+ * risk is much lower than any transmission error, which would lead to
+ * the same consequences.
+ *
+ * Source and destination arrays msut be disjoint.
+ */
+static void
+mask_id(br_ssl_session_cache_lru *cc,
+ const unsigned char *src, unsigned char *dst)
+{
+ br_hmac_key_context hkc;
+ br_hmac_context hc;
+
+ memcpy(dst, src, SESSION_ID_LEN);
+ br_hmac_key_init(&hkc, cc->hash, cc->index_key, sizeof cc->index_key);
+ br_hmac_init(&hc, &hkc, SESSION_ID_LEN);
+ br_hmac_update(&hc, src, SESSION_ID_LEN);
+ br_hmac_out(&hc, dst);
+}
+
+/*
+ * Find a node by ID. Returned value is the node address, or ADDR_NULL if
+ * the node is not found.
+ *
+ * If addr_link is not NULL, then '*addr_link' is set to the address of the
+ * last followed link. If the found node is the root, or if the tree is
+ * empty, then '*addr_link' is set to ADDR_NULL.
+ */
+static uint32_t
+find_node(br_ssl_session_cache_lru *cc, const unsigned char *id,
+ uint32_t *addr_link)
+{
+ uint32_t x, y;
+
+ x = cc->root;
+ y = ADDR_NULL;
+ while (x != ADDR_NULL) {
+ int r;
+
+ r = memcmp(id, cc->store + x + SESSION_ID_OFF, SESSION_ID_LEN);
+ if (r < 0) {
+ y = x + TREE_LEFT_OFF;
+ x = get_left(cc, x);
+ } else if (r == 0) {
+ if (addr_link != NULL) {
+ *addr_link = y;
+ }
+ return x;
+ } else {
+ y = x + TREE_RIGHT_OFF;
+ x = get_right(cc, x);
+ }
+ }
+ if (addr_link != NULL) {
+ *addr_link = y;
+ }
+ return ADDR_NULL;
+}
+
+/*
+ * For node x, find its replacement upon removal.
+ *
+ * -- If node x has no child, then this returns ADDR_NULL.
+ * -- Otherwise, if node x has a left child, then the replacement is the
+ * rightmost left-descendent.
+ * -- Otherwise, the replacement is the leftmost right-descendent.
+ *
+ * If a node is returned, then '*al' is set to the address of the field
+ * that points to that node. Otherwise (node x has no child), '*al' is
+ * set to ADDR_NULL.
+ *
+ * Note that the replacement node, when found, is always a descendent
+ * of node 'x', so it cannot be the tree root. Thus, '*al' can be set
+ * to ADDR_NULL only when no node is found and ADDR_NULL is returned.
+ */
+static uint32_t
+find_replacement_node(br_ssl_session_cache_lru *cc, uint32_t x, uint32_t *al)
+{
+ uint32_t y1, y2;
+
+ y1 = get_left(cc, x);
+ if (y1 != ADDR_NULL) {
+ y2 = x + TREE_LEFT_OFF;
+ for (;;) {
+ uint32_t z;
+
+ z = get_right(cc, y1);
+ if (z == ADDR_NULL) {
+ *al = y2;
+ return y1;
+ }
+ y2 = y1 + TREE_RIGHT_OFF;
+ y1 = z;
+ }
+ }
+ y1 = get_right(cc, x);
+ if (y1 != ADDR_NULL) {
+ y2 = x + TREE_RIGHT_OFF;
+ for (;;) {
+ uint32_t z;
+
+ z = get_left(cc, y1);
+ if (z == ADDR_NULL) {
+ *al = y2;
+ return y1;
+ }
+ y2 = y1 + TREE_LEFT_OFF;
+ y1 = z;
+ }
+ }
+ *al = ADDR_NULL;
+ return ADDR_NULL;
+}
+
+/*
+ * Set the link at address 'alx' to point to node 'x'. If 'alx' is
+ * ADDR_NULL, then this sets the tree root to 'x'.
+ */
+static inline void
+set_link(br_ssl_session_cache_lru *cc, uint32_t alx, uint32_t x)
+{
+ if (alx == ADDR_NULL) {
+ cc->root = x;
+ } else {
+ br_enc32be(cc->store + alx, x);
+ }
+}
+
+/*
+ * Remove node 'x' from the tree. This function shall not be called if
+ * node 'x' is not part of the tree.
+ */
+static void
+remove_node(br_ssl_session_cache_lru *cc, uint32_t x)
+{
+ uint32_t alx, y, aly;
+
+ /*
+ * Removal algorithm:
+ * ------------------
+ *
+ * - If we remove the root, then the tree becomes empty.
+ *
+ * - If the removed node has no child, then we can simply remove
+ * it, with nothing else to do.
+ *
+ * - Otherwise, the removed node must be replaced by either its
+ * rightmost left-descendent, or its leftmost right-descendent.
+ * The replacement node itself must be removed from its current
+ * place. By definition, that replacement node has either no
+ * child, or at most a single child that will replace it in the
+ * tree.
+ */
+
+ /*
+ * Find node back and its ancestor link. If the node was the
+ * root, then alx is set to ADDR_NULL.
+ */
+ find_node(cc, cc->store + x + SESSION_ID_OFF, &alx);
+
+ /*
+ * Find replacement node 'y', and 'aly' is set to the address of
+ * the link to that replacement node. If the removed node has no
+ * child, then both 'y' and 'aly' are set to ADDR_NULL.
+ */
+ y = find_replacement_node(cc, x, &aly);
+
+ if (y != ADDR_NULL) {
+ uint32_t z;
+
+ /*
+ * The unlinked replacement node may have one child (but
+ * not two) that takes its place.
+ */
+ z = get_left(cc, y);
+ if (z == ADDR_NULL) {
+ z = get_right(cc, y);
+ }
+ set_link(cc, aly, z);
+
+ /*
+ * Link the replacement node in its new place, overwriting
+ * the current link to the node 'x' (which removes 'x').
+ */
+ set_link(cc, alx, y);
+
+ /*
+ * The replacement node adopts the left and right children
+ * of the removed node. Note that this also works even if
+ * the replacement node was a direct descendent of the
+ * removed node, since we unlinked it previously.
+ */
+ set_left(cc, y, get_left(cc, x));
+ set_right(cc, y, get_right(cc, x));
+ } else {
+ /*
+ * No replacement, we simply unlink the node 'x'.
+ */
+ set_link(cc, alx, ADDR_NULL);
+ }
+}
+
+static void
+lru_save(const br_ssl_session_cache_class **ctx,
+ br_ssl_server_context *server_ctx,
+ const br_ssl_session_parameters *params)
+{
+ br_ssl_session_cache_lru *cc;
+ unsigned char id[SESSION_ID_LEN];
+ uint32_t x, alx;
+
+ cc = (br_ssl_session_cache_lru *)ctx;
+
+ /*
+ * If the buffer is too small, we don't record anything. This
+ * test avoids problems in subsequent code.
+ */
+ if (cc->store_len < LRU_ENTRY_LEN) {
+ return;
+ }
+
+ /*
+ * Upon the first save in a session cache instance, we obtain
+ * a random key for our indexing.
+ */
+ if (!cc->init_done) {
+ br_hmac_drbg_generate(&server_ctx->eng.rng,
+ cc->index_key, sizeof cc->index_key);
+ cc->hash = br_hmac_drbg_get_hash(&server_ctx->eng.rng);
+ cc->init_done = 1;
+ }
+ mask_id(cc, params->session_id, id);
+
+ /*
+ * Look for the node in the tree. If the same ID is already used,
+ * then reject it. This is a collision event, which should be
+ * exceedingly rare.
+ * Note: we do NOT record the emplacement here, because the
+ * removal of an entry may change the tree topology.
+ */
+ if (find_node(cc, id, NULL) != ADDR_NULL) {
+ return;
+ }
+
+ /*
+ * Find some room for the new parameters. If the cache is not
+ * full yet, add it to the end of the area and bump the pointer up.
+ * Otherwise, evict the list tail entry. Note that we already
+ * filtered out the case of a ridiculously small buffer that
+ * cannot hold any entry at all; thus, if there is no room for an
+ * extra entry, then the cache cannot be empty.
+ */
+ if (cc->store_ptr > (cc->store_len - LRU_ENTRY_LEN)) {
+ /*
+ * Evict tail. If the buffer has room for a single entry,
+ * then this may also be the head.
+ */
+ x = cc->tail;
+ cc->tail = get_prev(cc, x);
+ if (cc->tail == ADDR_NULL) {
+ cc->head = ADDR_NULL;
+ } else {
+ set_next(cc, cc->tail, ADDR_NULL);
+ }
+
+ /*
+ * Remove the node from the tree.
+ */
+ remove_node(cc, x);
+ } else {
+ /*
+ * Allocate room for new node.
+ */
+ x = cc->store_ptr;
+ cc->store_ptr += LRU_ENTRY_LEN;
+ }
+
+ /*
+ * Find the emplacement for the new node, and link it.
+ */
+ find_node(cc, id, &alx);
+ set_link(cc, alx, x);
+ set_left(cc, x, ADDR_NULL);
+ set_right(cc, x, ADDR_NULL);
+
+ /*
+ * New entry becomes new list head. It may also become the list
+ * tail if the cache was empty at that point.
+ */
+ if (cc->head == ADDR_NULL) {
+ cc->tail = x;
+ } else {
+ set_prev(cc, cc->head, x);
+ }
+ set_prev(cc, x, ADDR_NULL);
+ set_next(cc, x, cc->head);
+ cc->head = x;
+
+ /*
+ * Fill data in the entry.
+ */
+ memcpy(cc->store + x + SESSION_ID_OFF, id, SESSION_ID_LEN);
+ memcpy(cc->store + x + MASTER_SECRET_OFF,
+ params->master_secret, MASTER_SECRET_LEN);
+ br_enc16be(cc->store + x + VERSION_OFF, params->version);
+ br_enc16be(cc->store + x + CIPHER_SUITE_OFF, params->cipher_suite);
+}
+
+static int
+lru_load(const br_ssl_session_cache_class **ctx,
+ br_ssl_server_context *server_ctx,
+ br_ssl_session_parameters *params)
+{
+ br_ssl_session_cache_lru *cc;
+ unsigned char id[SESSION_ID_LEN];
+ uint32_t x;
+
+ (void)server_ctx;
+ cc = (br_ssl_session_cache_lru *)ctx;
+ if (!cc->init_done) {
+ return 0;
+ }
+ mask_id(cc, params->session_id, id);
+ x = find_node(cc, id, NULL);
+ if (x != ADDR_NULL) {
+ unsigned version;
+
+ version = br_dec16be(cc->store + x + VERSION_OFF);
+ if (version == 0) {
+ /*
+ * Entry is disabled, we pretend we did not find it.
+ * Notably, we don't move it to the front of the
+ * LRU list.
+ */
+ return 0;
+ }
+ params->version = version;
+ params->cipher_suite = br_dec16be(
+ cc->store + x + CIPHER_SUITE_OFF);
+ memcpy(params->master_secret,
+ cc->store + x + MASTER_SECRET_OFF,
+ MASTER_SECRET_LEN);
+ if (x != cc->head) {
+ /*
+ * Found node is not at list head, so move
+ * it to the head.
+ */
+ uint32_t p, n;
+
+ p = get_prev(cc, x);
+ n = get_next(cc, x);
+ set_next(cc, p, n);
+ if (n == ADDR_NULL) {
+ cc->tail = p;
+ } else {
+ set_prev(cc, n, p);
+ }
+ set_prev(cc, cc->head, x);
+ set_next(cc, x, cc->head);
+ set_prev(cc, x, ADDR_NULL);
+ cc->head = x;
+ }
+ return 1;
+ }
+ return 0;
+}
+
+static const br_ssl_session_cache_class lru_class = {
+ sizeof(br_ssl_session_cache_lru),
+ &lru_save,
+ &lru_load
+};
+
+/* see inner.h */
+void
+br_ssl_session_cache_lru_init(br_ssl_session_cache_lru *cc,
+ unsigned char *store, size_t store_len)
+{
+ cc->vtable = &lru_class;
+ cc->store = store;
+ cc->store_len = store_len;
+ cc->store_ptr = 0;
+ cc->init_done = 0;
+ cc->head = ADDR_NULL;
+ cc->tail = ADDR_NULL;
+ cc->root = ADDR_NULL;
+}
+
+/* see bearssl_ssl.h */
+void br_ssl_session_cache_lru_forget(
+ br_ssl_session_cache_lru *cc, const unsigned char *id)
+{
+ unsigned char mid[SESSION_ID_LEN];
+ uint32_t addr;
+
+ /*
+ * If the cache is not initialised yet, then it is empty, and
+ * there is nothing to forget.
+ */
+ if (!cc->init_done) {
+ return;
+ }
+
+ /*
+ * Look for the node in the tree. If found, the entry is marked
+ * as "disabled"; it will be reused in due course, as it ages
+ * through the list.
+ *
+ * We do not go through the complex moves of actually releasing
+ * the entry right away because explicitly forgetting sessions
+ * should be a rare event, meant mostly for testing purposes,
+ * so this is not worth the extra code size.
+ */
+ mask_id(cc, id, mid);
+ addr = find_node(cc, mid, NULL);
+ if (addr != ADDR_NULL) {
+ br_enc16be(cc->store + addr + VERSION_OFF, 0);
+ }
+}
diff --git a/test/monniaux/BearSSL/src/ssl/ssl_rec_cbc.c b/test/monniaux/BearSSL/src/ssl/ssl_rec_cbc.c
new file mode 100644
index 00000000..c0806049
--- /dev/null
+++ b/test/monniaux/BearSSL/src/ssl/ssl_rec_cbc.c
@@ -0,0 +1,440 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+static void
+in_cbc_init(br_sslrec_in_cbc_context *cc,
+ const br_block_cbcdec_class *bc_impl,
+ const void *bc_key, size_t bc_key_len,
+ const br_hash_class *dig_impl,
+ const void *mac_key, size_t mac_key_len, size_t mac_out_len,
+ const void *iv)
+{
+ cc->vtable = &br_sslrec_in_cbc_vtable;
+ cc->seq = 0;
+ bc_impl->init(&cc->bc.vtable, bc_key, bc_key_len);
+ br_hmac_key_init(&cc->mac, dig_impl, mac_key, mac_key_len);
+ cc->mac_len = mac_out_len;
+ if (iv == NULL) {
+ memset(cc->iv, 0, sizeof cc->iv);
+ cc->explicit_IV = 1;
+ } else {
+ memcpy(cc->iv, iv, bc_impl->block_size);
+ cc->explicit_IV = 0;
+ }
+}
+
+static int
+cbc_check_length(const br_sslrec_in_cbc_context *cc, size_t rlen)
+{
+ /*
+ * Plaintext size: at most 16384 bytes
+ * Padding: at most 256 bytes
+ * MAC: mac_len extra bytes
+ * TLS 1.1+: each record has an explicit IV
+ *
+ * Minimum length includes at least one byte of padding, and the
+ * MAC.
+ *
+ * Total length must be a multiple of the block size.
+ */
+ size_t blen;
+ size_t min_len, max_len;
+
+ blen = cc->bc.vtable->block_size;
+ min_len = (blen + cc->mac_len) & ~(blen - 1);
+ max_len = (16384 + 256 + cc->mac_len) & ~(blen - 1);
+ if (cc->explicit_IV) {
+ min_len += blen;
+ max_len += blen;
+ }
+ return min_len <= rlen && rlen <= max_len;
+}
+
+/*
+ * Rotate array buf[] of length 'len' to the left (towards low indices)
+ * by 'num' bytes if ctl is 1; otherwise, leave it unchanged. This is
+ * constant-time. 'num' MUST be lower than 'len'. 'len' MUST be lower
+ * than or equal to 64.
+ */
+static void
+cond_rotate(uint32_t ctl, unsigned char *buf, size_t len, size_t num)
+{
+ unsigned char tmp[64];
+ size_t u, v;
+
+ for (u = 0, v = num; u < len; u ++) {
+ tmp[u] = MUX(ctl, buf[v], buf[u]);
+ if (++ v == len) {
+ v = 0;
+ }
+ }
+ memcpy(buf, tmp, len);
+}
+
+static unsigned char *
+cbc_decrypt(br_sslrec_in_cbc_context *cc,
+ int record_type, unsigned version, void *data, size_t *data_len)
+{
+ /*
+ * We represent all lengths on 32-bit integers, because:
+ * -- SSL record lengths always fit in 32 bits;
+ * -- our constant-time primitives operate on 32-bit integers.
+ */
+ unsigned char *buf;
+ uint32_t u, v, len, blen, min_len, max_len;
+ uint32_t good, pad_len, rot_count, len_withmac, len_nomac;
+ unsigned char tmp1[64], tmp2[64];
+ int i;
+ br_hmac_context hc;
+
+ buf = data;
+ len = *data_len;
+ blen = cc->bc.vtable->block_size;
+
+ /*
+ * Decrypt data, and skip the explicit IV (if applicable). Note
+ * that the total length is supposed to have been verified by
+ * the caller. If there is an explicit IV, then we actually
+ * "decrypt" it using the implicit IV (from previous record),
+ * which is useless but harmless.
+ */
+ cc->bc.vtable->run(&cc->bc.vtable, cc->iv, data, len);
+ if (cc->explicit_IV) {
+ buf += blen;
+ len -= blen;
+ }
+
+ /*
+ * Compute minimum and maximum length of plaintext + MAC. These
+ * lengths can be inferred from the outside: they are not secret.
+ */
+ min_len = (cc->mac_len + 256 < len) ? len - 256 : cc->mac_len;
+ max_len = len - 1;
+
+ /*
+ * Use the last decrypted byte to compute the actual payload
+ * length. Take care not to underflow (we use unsigned types).
+ */
+ pad_len = buf[max_len];
+ good = LE(pad_len, (uint32_t)(max_len - min_len));
+ len = MUX(good, (uint32_t)(max_len - pad_len), min_len);
+
+ /*
+ * Check padding contents: all padding bytes must be equal to
+ * the value of pad_len.
+ */
+ for (u = min_len; u < max_len; u ++) {
+ good &= LT(u, len) | EQ(buf[u], pad_len);
+ }
+
+ /*
+ * Extract the MAC value. This is done in one pass, but results
+ * in a "rotated" MAC value depending on where it actually
+ * occurs. The 'rot_count' value is set to the offset of the
+ * first MAC byte within tmp1[].
+ *
+ * min_len and max_len are also adjusted to the minimum and
+ * maximum lengths of the plaintext alone (without the MAC).
+ */
+ len_withmac = (uint32_t)len;
+ len_nomac = len_withmac - cc->mac_len;
+ min_len -= cc->mac_len;
+ rot_count = 0;
+ memset(tmp1, 0, cc->mac_len);
+ v = 0;
+ for (u = min_len; u < max_len; u ++) {
+ tmp1[v] |= MUX(GE(u, len_nomac) & LT(u, len_withmac),
+ buf[u], 0x00);
+ rot_count = MUX(EQ(u, len_nomac), v, rot_count);
+ if (++ v == cc->mac_len) {
+ v = 0;
+ }
+ }
+ max_len -= cc->mac_len;
+
+ /*
+ * Rotate back the MAC value. The loop below does the constant-time
+ * rotation in time n*log n for a MAC output of length n. We assume
+ * that the MAC output length is no more than 64 bytes, so the
+ * rotation count fits on 6 bits.
+ */
+ for (i = 5; i >= 0; i --) {
+ uint32_t rc;
+
+ rc = (uint32_t)1 << i;
+ cond_rotate(rot_count >> i, tmp1, cc->mac_len, rc);
+ rot_count &= ~rc;
+ }
+
+ /*
+ * Recompute the HMAC value. The input is the concatenation of
+ * the sequence number (8 bytes), the record header (5 bytes),
+ * and the payload.
+ *
+ * At that point, min_len is the minimum plaintext length, but
+ * max_len still includes the MAC length.
+ */
+ br_enc64be(tmp2, cc->seq ++);
+ tmp2[8] = (unsigned char)record_type;
+ br_enc16be(tmp2 + 9, version);
+ br_enc16be(tmp2 + 11, len_nomac);
+ br_hmac_init(&hc, &cc->mac, cc->mac_len);
+ br_hmac_update(&hc, tmp2, 13);
+ br_hmac_outCT(&hc, buf, len_nomac, min_len, max_len, tmp2);
+
+ /*
+ * Compare the extracted and recomputed MAC values.
+ */
+ for (u = 0; u < cc->mac_len; u ++) {
+ good &= EQ0(tmp1[u] ^ tmp2[u]);
+ }
+
+ /*
+ * Check that the plaintext length is valid. The previous
+ * check was on the encrypted length, but the padding may have
+ * turned shorter than expected.
+ *
+ * Once this final test is done, the critical "constant-time"
+ * section ends and we can make conditional jumps again.
+ */
+ good &= LE(len_nomac, 16384);
+
+ if (!good) {
+ return 0;
+ }
+ *data_len = len_nomac;
+ return buf;
+}
+
+/* see bearssl_ssl.h */
+const br_sslrec_in_cbc_class br_sslrec_in_cbc_vtable = {
+ {
+ sizeof(br_sslrec_in_cbc_context),
+ (int (*)(const br_sslrec_in_class *const *, size_t))
+ &cbc_check_length,
+ (unsigned char *(*)(const br_sslrec_in_class **,
+ int, unsigned, void *, size_t *))
+ &cbc_decrypt
+ },
+ (void (*)(const br_sslrec_in_cbc_class **,
+ const br_block_cbcdec_class *, const void *, size_t,
+ const br_hash_class *, const void *, size_t, size_t,
+ const void *))
+ &in_cbc_init
+};
+
+/*
+ * For CBC output:
+ *
+ * -- With TLS 1.1+, there is an explicit IV. Generation method uses
+ * HMAC, computed over the current sequence number, and the current MAC
+ * key. The resulting value is truncated to the size of a block, and
+ * added at the head of the plaintext; it will get encrypted along with
+ * the data. This custom generation mechanism is "safe" under the
+ * assumption that HMAC behaves like a random oracle; since the MAC for
+ * a record is computed over the concatenation of the sequence number,
+ * the record header and the plaintext, the HMAC-for-IV will not collide
+ * with the normal HMAC.
+ *
+ * -- With TLS 1.0, for application data, we want to enforce a 1/n-1
+ * split, as a countermeasure against chosen-plaintext attacks. We thus
+ * need to leave some room in the buffer for that extra record.
+ */
+
+static void
+out_cbc_init(br_sslrec_out_cbc_context *cc,
+ const br_block_cbcenc_class *bc_impl,
+ const void *bc_key, size_t bc_key_len,
+ const br_hash_class *dig_impl,
+ const void *mac_key, size_t mac_key_len, size_t mac_out_len,
+ const void *iv)
+{
+ cc->vtable = &br_sslrec_out_cbc_vtable;
+ cc->seq = 0;
+ bc_impl->init(&cc->bc.vtable, bc_key, bc_key_len);
+ br_hmac_key_init(&cc->mac, dig_impl, mac_key, mac_key_len);
+ cc->mac_len = mac_out_len;
+ if (iv == NULL) {
+ memset(cc->iv, 0, sizeof cc->iv);
+ cc->explicit_IV = 1;
+ } else {
+ memcpy(cc->iv, iv, bc_impl->block_size);
+ cc->explicit_IV = 0;
+ }
+}
+
+static void
+cbc_max_plaintext(const br_sslrec_out_cbc_context *cc,
+ size_t *start, size_t *end)
+{
+ size_t blen, len;
+
+ blen = cc->bc.vtable->block_size;
+ if (cc->explicit_IV) {
+ *start += blen;
+ } else {
+ *start += 4 + ((cc->mac_len + blen + 1) & ~(blen - 1));
+ }
+ len = (*end - *start) & ~(blen - 1);
+ len -= 1 + cc->mac_len;
+ if (len > 16384) {
+ len = 16384;
+ }
+ *end = *start + len;
+}
+
+static unsigned char *
+cbc_encrypt(br_sslrec_out_cbc_context *cc,
+ int record_type, unsigned version, void *data, size_t *data_len)
+{
+ unsigned char *buf, *rbuf;
+ size_t len, blen, plen;
+ unsigned char tmp[13];
+ br_hmac_context hc;
+
+ buf = data;
+ len = *data_len;
+ blen = cc->bc.vtable->block_size;
+
+ /*
+ * If using TLS 1.0, with more than one byte of plaintext, and
+ * the record is application data, then we need to compute
+ * a "split". We do not perform the split on other record types
+ * because it turned out that some existing, deployed
+ * implementations of SSL/TLS do not tolerate the splitting of
+ * some message types (in particular the Finished message).
+ *
+ * If using TLS 1.1+, then there is an explicit IV. We produce
+ * that IV by adding an extra initial plaintext block, whose
+ * value is computed with HMAC over the record sequence number.
+ */
+ if (cc->explicit_IV) {
+ /*
+ * We use here the fact that all the HMAC variants we
+ * support can produce at least 16 bytes, while all the
+ * block ciphers we support have blocks of no more than
+ * 16 bytes. Thus, we can always truncate the HMAC output
+ * down to the block size.
+ */
+ br_enc64be(tmp, cc->seq);
+ br_hmac_init(&hc, &cc->mac, blen);
+ br_hmac_update(&hc, tmp, 8);
+ br_hmac_out(&hc, buf - blen);
+ rbuf = buf - blen - 5;
+ } else {
+ if (len > 1 && record_type == BR_SSL_APPLICATION_DATA) {
+ /*
+ * To do the split, we use a recursive invocation;
+ * since we only give one byte to the inner call,
+ * the recursion stops there.
+ *
+ * We need to compute the exact size of the extra
+ * record, so that the two resulting records end up
+ * being sequential in RAM.
+ *
+ * We use here the fact that cbc_max_plaintext()
+ * adjusted the start offset to leave room for the
+ * initial fragment.
+ */
+ size_t xlen;
+
+ rbuf = buf - 4
+ - ((cc->mac_len + blen + 1) & ~(blen - 1));
+ rbuf[0] = buf[0];
+ xlen = 1;
+ rbuf = cbc_encrypt(cc, record_type,
+ version, rbuf, &xlen);
+ buf ++;
+ len --;
+ } else {
+ rbuf = buf - 5;
+ }
+ }
+
+ /*
+ * Compute MAC.
+ */
+ br_enc64be(tmp, cc->seq ++);
+ tmp[8] = record_type;
+ br_enc16be(tmp + 9, version);
+ br_enc16be(tmp + 11, len);
+ br_hmac_init(&hc, &cc->mac, cc->mac_len);
+ br_hmac_update(&hc, tmp, 13);
+ br_hmac_update(&hc, buf, len);
+ br_hmac_out(&hc, buf + len);
+ len += cc->mac_len;
+
+ /*
+ * Add padding.
+ */
+ plen = blen - (len & (blen - 1));
+ memset(buf + len, (unsigned)plen - 1, plen);
+ len += plen;
+
+ /*
+ * If an explicit IV is used, the corresponding extra block was
+ * already put in place earlier; we just have to account for it
+ * here.
+ */
+ if (cc->explicit_IV) {
+ buf -= blen;
+ len += blen;
+ }
+
+ /*
+ * Encrypt the whole thing. If there is an explicit IV, we also
+ * encrypt it, which is fine (encryption of a uniformly random
+ * block is still a uniformly random block).
+ */
+ cc->bc.vtable->run(&cc->bc.vtable, cc->iv, buf, len);
+
+ /*
+ * Add the header and return.
+ */
+ buf[-5] = record_type;
+ br_enc16be(buf - 4, version);
+ br_enc16be(buf - 2, len);
+ *data_len = (size_t)((buf + len) - rbuf);
+ return rbuf;
+}
+
+/* see bearssl_ssl.h */
+const br_sslrec_out_cbc_class br_sslrec_out_cbc_vtable = {
+ {
+ sizeof(br_sslrec_out_cbc_context),
+ (void (*)(const br_sslrec_out_class *const *,
+ size_t *, size_t *))
+ &cbc_max_plaintext,
+ (unsigned char *(*)(const br_sslrec_out_class **,
+ int, unsigned, void *, size_t *))
+ &cbc_encrypt
+ },
+ (void (*)(const br_sslrec_out_cbc_class **,
+ const br_block_cbcenc_class *, const void *, size_t,
+ const br_hash_class *, const void *, size_t, size_t,
+ const void *))
+ &out_cbc_init
+};
diff --git a/test/monniaux/BearSSL/src/ssl/ssl_rec_ccm.c b/test/monniaux/BearSSL/src/ssl/ssl_rec_ccm.c
new file mode 100644
index 00000000..92c32952
--- /dev/null
+++ b/test/monniaux/BearSSL/src/ssl/ssl_rec_ccm.c
@@ -0,0 +1,213 @@
+/*
+ * Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/*
+ * CCM initialisation. This does everything except setting the vtable,
+ * which depends on whether this is a context for encrypting or for
+ * decrypting.
+ */
+static void
+gen_ccm_init(br_sslrec_ccm_context *cc,
+ const br_block_ctrcbc_class *bc_impl,
+ const void *key, size_t key_len,
+ const void *iv, size_t tag_len)
+{
+ cc->seq = 0;
+ bc_impl->init(&cc->bc.vtable, key, key_len);
+ memcpy(cc->iv, iv, sizeof cc->iv);
+ cc->tag_len = tag_len;
+}
+
+static void
+in_ccm_init(br_sslrec_ccm_context *cc,
+ const br_block_ctrcbc_class *bc_impl,
+ const void *key, size_t key_len,
+ const void *iv, size_t tag_len)
+{
+ cc->vtable.in = &br_sslrec_in_ccm_vtable;
+ gen_ccm_init(cc, bc_impl, key, key_len, iv, tag_len);
+}
+
+static int
+ccm_check_length(const br_sslrec_ccm_context *cc, size_t rlen)
+{
+ /*
+ * CCM overhead is 8 bytes for nonce_explicit, and the tag
+ * (normally 8 or 16 bytes, depending on cipher suite).
+ */
+ size_t over;
+
+ over = 8 + cc->tag_len;
+ return rlen >= over && rlen <= (16384 + over);
+}
+
+static unsigned char *
+ccm_decrypt(br_sslrec_ccm_context *cc,
+ int record_type, unsigned version, void *data, size_t *data_len)
+{
+ br_ccm_context zc;
+ unsigned char *buf;
+ unsigned char nonce[12], header[13];
+ size_t len;
+
+ buf = (unsigned char *)data + 8;
+ len = *data_len - (8 + cc->tag_len);
+
+ /*
+ * Make nonce (implicit + explicit parts).
+ */
+ memcpy(nonce, cc->iv, sizeof cc->iv);
+ memcpy(nonce + 4, data, 8);
+
+ /*
+ * Assemble synthetic header for the AAD.
+ */
+ br_enc64be(header, cc->seq ++);
+ header[8] = (unsigned char)record_type;
+ br_enc16be(header + 9, version);
+ br_enc16be(header + 11, len);
+
+ /*
+ * Perform CCM decryption.
+ */
+ br_ccm_init(&zc, &cc->bc.vtable);
+ br_ccm_reset(&zc, nonce, sizeof nonce, sizeof header, len, cc->tag_len);
+ br_ccm_aad_inject(&zc, header, sizeof header);
+ br_ccm_flip(&zc);
+ br_ccm_run(&zc, 0, buf, len);
+ if (!br_ccm_check_tag(&zc, buf + len)) {
+ return NULL;
+ }
+ *data_len = len;
+ return buf;
+}
+
+/* see bearssl_ssl.h */
+const br_sslrec_in_ccm_class br_sslrec_in_ccm_vtable = {
+ {
+ sizeof(br_sslrec_ccm_context),
+ (int (*)(const br_sslrec_in_class *const *, size_t))
+ &ccm_check_length,
+ (unsigned char *(*)(const br_sslrec_in_class **,
+ int, unsigned, void *, size_t *))
+ &ccm_decrypt
+ },
+ (void (*)(const br_sslrec_in_ccm_class **,
+ const br_block_ctrcbc_class *, const void *, size_t,
+ const void *, size_t))
+ &in_ccm_init
+};
+
+static void
+out_ccm_init(br_sslrec_ccm_context *cc,
+ const br_block_ctrcbc_class *bc_impl,
+ const void *key, size_t key_len,
+ const void *iv, size_t tag_len)
+{
+ cc->vtable.out = &br_sslrec_out_ccm_vtable;
+ gen_ccm_init(cc, bc_impl, key, key_len, iv, tag_len);
+}
+
+static void
+ccm_max_plaintext(const br_sslrec_ccm_context *cc,
+ size_t *start, size_t *end)
+{
+ size_t len;
+
+ *start += 8;
+ len = *end - *start - cc->tag_len;
+ if (len > 16384) {
+ len = 16384;
+ }
+ *end = *start + len;
+}
+
+static unsigned char *
+ccm_encrypt(br_sslrec_ccm_context *cc,
+ int record_type, unsigned version, void *data, size_t *data_len)
+{
+ br_ccm_context zc;
+ unsigned char *buf;
+ unsigned char nonce[12], header[13];
+ size_t len;
+
+ buf = (unsigned char *)data;
+ len = *data_len;
+
+ /*
+ * Make nonce; the explicit part is an encoding of the sequence
+ * number.
+ */
+ memcpy(nonce, cc->iv, sizeof cc->iv);
+ br_enc64be(nonce + 4, cc->seq);
+
+ /*
+ * Assemble synthetic header for the AAD.
+ */
+ br_enc64be(header, cc->seq ++);
+ header[8] = (unsigned char)record_type;
+ br_enc16be(header + 9, version);
+ br_enc16be(header + 11, len);
+
+ /*
+ * Perform CCM encryption.
+ */
+ br_ccm_init(&zc, &cc->bc.vtable);
+ br_ccm_reset(&zc, nonce, sizeof nonce, sizeof header, len, cc->tag_len);
+ br_ccm_aad_inject(&zc, header, sizeof header);
+ br_ccm_flip(&zc);
+ br_ccm_run(&zc, 1, buf, len);
+ br_ccm_get_tag(&zc, buf + len);
+
+ /*
+ * Assemble header and adjust pointer/length.
+ */
+ len += 8 + cc->tag_len;
+ buf -= 13;
+ memcpy(buf + 5, nonce + 4, 8);
+ buf[0] = (unsigned char)record_type;
+ br_enc16be(buf + 1, version);
+ br_enc16be(buf + 3, len);
+ *data_len = len + 5;
+ return buf;
+}
+
+/* see bearssl_ssl.h */
+const br_sslrec_out_ccm_class br_sslrec_out_ccm_vtable = {
+ {
+ sizeof(br_sslrec_ccm_context),
+ (void (*)(const br_sslrec_out_class *const *,
+ size_t *, size_t *))
+ &ccm_max_plaintext,
+ (unsigned char *(*)(const br_sslrec_out_class **,
+ int, unsigned, void *, size_t *))
+ &ccm_encrypt
+ },
+ (void (*)(const br_sslrec_out_ccm_class **,
+ const br_block_ctrcbc_class *, const void *, size_t,
+ const void *, size_t))
+ &out_ccm_init
+};
diff --git a/test/monniaux/BearSSL/src/ssl/ssl_rec_chapol.c b/test/monniaux/BearSSL/src/ssl/ssl_rec_chapol.c
new file mode 100644
index 00000000..73b3c785
--- /dev/null
+++ b/test/monniaux/BearSSL/src/ssl/ssl_rec_chapol.c
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+static void
+gen_chapol_init(br_sslrec_chapol_context *cc,
+ br_chacha20_run ichacha, br_poly1305_run ipoly,
+ const void *key, const void *iv)
+{
+ cc->seq = 0;
+ cc->ichacha = ichacha;
+ cc->ipoly = ipoly;
+ memcpy(cc->key, key, sizeof cc->key);
+ memcpy(cc->iv, iv, sizeof cc->iv);
+}
+
+static void
+gen_chapol_process(br_sslrec_chapol_context *cc,
+ int record_type, unsigned version, void *data, size_t len,
+ void *tag, int encrypt)
+{
+ unsigned char header[13];
+ unsigned char nonce[12];
+ uint64_t seq;
+ size_t u;
+
+ seq = cc->seq ++;
+ br_enc64be(header, seq);
+ header[8] = (unsigned char)record_type;
+ br_enc16be(header + 9, version);
+ br_enc16be(header + 11, len);
+ memcpy(nonce, cc->iv, 12);
+ for (u = 0; u < 8; u ++) {
+ nonce[11 - u] ^= (unsigned char)seq;
+ seq >>= 8;
+ }
+ cc->ipoly(cc->key, nonce, data, len, header, sizeof header,
+ tag, cc->ichacha, encrypt);
+}
+
+static void
+in_chapol_init(br_sslrec_chapol_context *cc,
+ br_chacha20_run ichacha, br_poly1305_run ipoly,
+ const void *key, const void *iv)
+{
+ cc->vtable.in = &br_sslrec_in_chapol_vtable;
+ gen_chapol_init(cc, ichacha, ipoly, key, iv);
+}
+
+static int
+chapol_check_length(const br_sslrec_chapol_context *cc, size_t rlen)
+{
+ /*
+ * Overhead is just the authentication tag (16 bytes).
+ */
+ (void)cc;
+ return rlen >= 16 && rlen <= (16384 + 16);
+}
+
+static unsigned char *
+chapol_decrypt(br_sslrec_chapol_context *cc,
+ int record_type, unsigned version, void *data, size_t *data_len)
+{
+ unsigned char *buf;
+ size_t u, len;
+ unsigned char tag[16];
+ unsigned bad;
+
+ buf = data;
+ len = *data_len - 16;
+ gen_chapol_process(cc, record_type, version, buf, len, tag, 0);
+ bad = 0;
+ for (u = 0; u < 16; u ++) {
+ bad |= tag[u] ^ buf[len + u];
+ }
+ if (bad) {
+ return NULL;
+ }
+ *data_len = len;
+ return buf;
+}
+
+/* see bearssl_ssl.h */
+const br_sslrec_in_chapol_class br_sslrec_in_chapol_vtable = {
+ {
+ sizeof(br_sslrec_chapol_context),
+ (int (*)(const br_sslrec_in_class *const *, size_t))
+ &chapol_check_length,
+ (unsigned char *(*)(const br_sslrec_in_class **,
+ int, unsigned, void *, size_t *))
+ &chapol_decrypt
+ },
+ (void (*)(const br_sslrec_in_chapol_class **,
+ br_chacha20_run, br_poly1305_run,
+ const void *, const void *))
+ &in_chapol_init
+};
+
+static void
+out_chapol_init(br_sslrec_chapol_context *cc,
+ br_chacha20_run ichacha, br_poly1305_run ipoly,
+ const void *key, const void *iv)
+{
+ cc->vtable.out = &br_sslrec_out_chapol_vtable;
+ gen_chapol_init(cc, ichacha, ipoly, key, iv);
+}
+
+static void
+chapol_max_plaintext(const br_sslrec_chapol_context *cc,
+ size_t *start, size_t *end)
+{
+ size_t len;
+
+ (void)cc;
+ len = *end - *start - 16;
+ if (len > 16384) {
+ len = 16384;
+ }
+ *end = *start + len;
+}
+
+static unsigned char *
+chapol_encrypt(br_sslrec_chapol_context *cc,
+ int record_type, unsigned version, void *data, size_t *data_len)
+{
+ unsigned char *buf;
+ size_t len;
+
+ buf = data;
+ len = *data_len;
+ gen_chapol_process(cc, record_type, version, buf, len, buf + len, 1);
+ buf -= 5;
+ buf[0] = (unsigned char)record_type;
+ br_enc16be(buf + 1, version);
+ br_enc16be(buf + 3, len + 16);
+ *data_len = len + 21;
+ return buf;
+}
+
+/* see bearssl_ssl.h */
+const br_sslrec_out_chapol_class br_sslrec_out_chapol_vtable = {
+ {
+ sizeof(br_sslrec_chapol_context),
+ (void (*)(const br_sslrec_out_class *const *,
+ size_t *, size_t *))
+ &chapol_max_plaintext,
+ (unsigned char *(*)(const br_sslrec_out_class **,
+ int, unsigned, void *, size_t *))
+ &chapol_encrypt
+ },
+ (void (*)(const br_sslrec_out_chapol_class **,
+ br_chacha20_run, br_poly1305_run,
+ const void *, const void *))
+ &out_chapol_init
+};
diff --git a/test/monniaux/BearSSL/src/ssl/ssl_rec_gcm.c b/test/monniaux/BearSSL/src/ssl/ssl_rec_gcm.c
new file mode 100644
index 00000000..70df2777
--- /dev/null
+++ b/test/monniaux/BearSSL/src/ssl/ssl_rec_gcm.c
@@ -0,0 +1,235 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/*
+ * GCM initialisation. This does everything except setting the vtable,
+ * which depends on whether this is a context for encrypting or for
+ * decrypting.
+ */
+static void
+gen_gcm_init(br_sslrec_gcm_context *cc,
+ const br_block_ctr_class *bc_impl,
+ const void *key, size_t key_len,
+ br_ghash gh_impl,
+ const void *iv)
+{
+ unsigned char tmp[12];
+
+ cc->seq = 0;
+ bc_impl->init(&cc->bc.vtable, key, key_len);
+ cc->gh = gh_impl;
+ memcpy(cc->iv, iv, sizeof cc->iv);
+ memset(cc->h, 0, sizeof cc->h);
+ memset(tmp, 0, sizeof tmp);
+ bc_impl->run(&cc->bc.vtable, tmp, 0, cc->h, sizeof cc->h);
+}
+
+static void
+in_gcm_init(br_sslrec_gcm_context *cc,
+ const br_block_ctr_class *bc_impl,
+ const void *key, size_t key_len,
+ br_ghash gh_impl,
+ const void *iv)
+{
+ cc->vtable.in = &br_sslrec_in_gcm_vtable;
+ gen_gcm_init(cc, bc_impl, key, key_len, gh_impl, iv);
+}
+
+static int
+gcm_check_length(const br_sslrec_gcm_context *cc, size_t rlen)
+{
+ /*
+ * GCM adds a fixed overhead:
+ * 8 bytes for the nonce_explicit (before the ciphertext)
+ * 16 bytes for the authentication tag (after the ciphertext)
+ */
+ (void)cc;
+ return rlen >= 24 && rlen <= (16384 + 24);
+}
+
+/*
+ * Compute the authentication tag. The value written in 'tag' must still
+ * be CTR-encrypted.
+ */
+static void
+do_tag(br_sslrec_gcm_context *cc,
+ int record_type, unsigned version,
+ void *data, size_t len, void *tag)
+{
+ unsigned char header[13];
+ unsigned char footer[16];
+
+ /*
+ * Compute authentication tag. Three elements must be injected in
+ * sequence, each possibly 0-padded to reach a length multiple
+ * of the block size: the 13-byte header (sequence number, record
+ * type, protocol version, record length), the cipher text, and
+ * the word containing the encodings of the bit lengths of the two
+ * other elements.
+ */
+ br_enc64be(header, cc->seq ++);
+ header[8] = (unsigned char)record_type;
+ br_enc16be(header + 9, version);
+ br_enc16be(header + 11, len);
+ br_enc64be(footer, (uint64_t)(sizeof header) << 3);
+ br_enc64be(footer + 8, (uint64_t)len << 3);
+ memset(tag, 0, 16);
+ cc->gh(tag, cc->h, header, sizeof header);
+ cc->gh(tag, cc->h, data, len);
+ cc->gh(tag, cc->h, footer, sizeof footer);
+}
+
+/*
+ * Do CTR encryption. This also does CTR encryption of a single block at
+ * address 'xortag' with the counter value appropriate for the final
+ * processing of the authentication tag.
+ */
+static void
+do_ctr(br_sslrec_gcm_context *cc, const void *nonce, void *data, size_t len,
+ void *xortag)
+{
+ unsigned char iv[12];
+
+ memcpy(iv, cc->iv, 4);
+ memcpy(iv + 4, nonce, 8);
+ cc->bc.vtable->run(&cc->bc.vtable, iv, 2, data, len);
+ cc->bc.vtable->run(&cc->bc.vtable, iv, 1, xortag, 16);
+}
+
+static unsigned char *
+gcm_decrypt(br_sslrec_gcm_context *cc,
+ int record_type, unsigned version, void *data, size_t *data_len)
+{
+ unsigned char *buf;
+ size_t len, u;
+ uint32_t bad;
+ unsigned char tag[16];
+
+ buf = (unsigned char *)data + 8;
+ len = *data_len - 24;
+ do_tag(cc, record_type, version, buf, len, tag);
+ do_ctr(cc, data, buf, len, tag);
+
+ /*
+ * Compare the computed tag with the value from the record. It
+ * is possibly useless to do a constant-time comparison here,
+ * but it does not hurt.
+ */
+ bad = 0;
+ for (u = 0; u < 16; u ++) {
+ bad |= tag[u] ^ buf[len + u];
+ }
+ if (bad) {
+ return NULL;
+ }
+ *data_len = len;
+ return buf;
+}
+
+/* see bearssl_ssl.h */
+const br_sslrec_in_gcm_class br_sslrec_in_gcm_vtable = {
+ {
+ sizeof(br_sslrec_gcm_context),
+ (int (*)(const br_sslrec_in_class *const *, size_t))
+ &gcm_check_length,
+ (unsigned char *(*)(const br_sslrec_in_class **,
+ int, unsigned, void *, size_t *))
+ &gcm_decrypt
+ },
+ (void (*)(const br_sslrec_in_gcm_class **,
+ const br_block_ctr_class *, const void *, size_t,
+ br_ghash, const void *))
+ &in_gcm_init
+};
+
+static void
+out_gcm_init(br_sslrec_gcm_context *cc,
+ const br_block_ctr_class *bc_impl,
+ const void *key, size_t key_len,
+ br_ghash gh_impl,
+ const void *iv)
+{
+ cc->vtable.out = &br_sslrec_out_gcm_vtable;
+ gen_gcm_init(cc, bc_impl, key, key_len, gh_impl, iv);
+}
+
+static void
+gcm_max_plaintext(const br_sslrec_gcm_context *cc,
+ size_t *start, size_t *end)
+{
+ size_t len;
+
+ (void)cc;
+ *start += 8;
+ len = *end - *start - 16;
+ if (len > 16384) {
+ len = 16384;
+ }
+ *end = *start + len;
+}
+
+static unsigned char *
+gcm_encrypt(br_sslrec_gcm_context *cc,
+ int record_type, unsigned version, void *data, size_t *data_len)
+{
+ unsigned char *buf;
+ size_t u, len;
+ unsigned char tmp[16];
+
+ buf = (unsigned char *)data;
+ len = *data_len;
+ memset(tmp, 0, sizeof tmp);
+ br_enc64be(buf - 8, cc->seq);
+ do_ctr(cc, buf - 8, buf, len, tmp);
+ do_tag(cc, record_type, version, buf, len, buf + len);
+ for (u = 0; u < 16; u ++) {
+ buf[len + u] ^= tmp[u];
+ }
+ len += 24;
+ buf -= 13;
+ buf[0] = (unsigned char)record_type;
+ br_enc16be(buf + 1, version);
+ br_enc16be(buf + 3, len);
+ *data_len = len + 5;
+ return buf;
+}
+
+/* see bearssl_ssl.h */
+const br_sslrec_out_gcm_class br_sslrec_out_gcm_vtable = {
+ {
+ sizeof(br_sslrec_gcm_context),
+ (void (*)(const br_sslrec_out_class *const *,
+ size_t *, size_t *))
+ &gcm_max_plaintext,
+ (unsigned char *(*)(const br_sslrec_out_class **,
+ int, unsigned, void *, size_t *))
+ &gcm_encrypt
+ },
+ (void (*)(const br_sslrec_out_gcm_class **,
+ const br_block_ctr_class *, const void *, size_t,
+ br_ghash, const void *))
+ &out_gcm_init
+};
diff --git a/test/monniaux/BearSSL/src/ssl/ssl_scert_single_ec.c b/test/monniaux/BearSSL/src/ssl/ssl_scert_single_ec.c
new file mode 100644
index 00000000..ce8d7539
--- /dev/null
+++ b/test/monniaux/BearSSL/src/ssl/ssl_scert_single_ec.c
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+static int
+se_choose(const br_ssl_server_policy_class **pctx,
+ const br_ssl_server_context *cc,
+ br_ssl_server_choices *choices)
+{
+ br_ssl_server_policy_ec_context *pc;
+ const br_suite_translated *st;
+ size_t u, st_num;
+ unsigned hash_id;
+
+ 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) >> 8);
+ if (cc->eng.session.version < BR_TLS12) {
+ hash_id = br_sha1_ID;
+ }
+ choices->chain = pc->chain;
+ choices->chain_len = pc->chain_len;
+ for (u = 0; u < st_num; u ++) {
+ unsigned tt;
+
+ tt = st[u][1];
+ switch (tt >> 12) {
+ case BR_SSLKEYX_ECDH_RSA:
+ if ((pc->allowed_usages & BR_KEYTYPE_KEYX) != 0
+ && pc->cert_issuer_key_type == BR_KEYTYPE_RSA)
+ {
+ choices->cipher_suite = st[u][0];
+ return 1;
+ }
+ break;
+ case BR_SSLKEYX_ECDH_ECDSA:
+ if ((pc->allowed_usages & BR_KEYTYPE_KEYX) != 0
+ && pc->cert_issuer_key_type == BR_KEYTYPE_EC)
+ {
+ choices->cipher_suite = st[u][0];
+ return 1;
+ }
+ break;
+ case BR_SSLKEYX_ECDHE_ECDSA:
+ if ((pc->allowed_usages & BR_KEYTYPE_SIGN) != 0
+ && hash_id != 0)
+ {
+ choices->cipher_suite = st[u][0];
+ choices->algo_id = hash_id + 0xFF00;
+ return 1;
+ }
+ break;
+ }
+ }
+ return 0;
+}
+
+static uint32_t
+se_do_keyx(const br_ssl_server_policy_class **pctx,
+ unsigned char *data, size_t *len)
+{
+ br_ssl_server_policy_ec_context *pc;
+ uint32_t r;
+ size_t xoff, xlen;
+
+ pc = (br_ssl_server_policy_ec_context *)pctx;
+ r = pc->iec->mul(data, *len, pc->sk->x, pc->sk->xlen, pc->sk->curve);
+ xoff = pc->iec->xoff(pc->sk->curve, &xlen);
+ memmove(data, data + xoff, xlen);
+ *len = xlen;
+ return r;
+}
+
+static size_t
+se_do_sign(const br_ssl_server_policy_class **pctx,
+ unsigned algo_id, unsigned char *data, size_t hv_len, size_t len)
+{
+ br_ssl_server_policy_ec_context *pc;
+ unsigned char hv[64];
+ const br_hash_class *hc;
+
+ algo_id &= 0xFF;
+ pc = (br_ssl_server_policy_ec_context *)pctx;
+ hc = br_multihash_getimpl(pc->mhash, algo_id);
+ if (hc == NULL) {
+ return 0;
+ }
+ memcpy(hv, data, hv_len);
+ if (len < 139) {
+ return 0;
+ }
+ return pc->iecdsa(pc->iec, hc, hv, pc->sk, data);
+}
+
+static const br_ssl_server_policy_class se_policy_vtable = {
+ sizeof(br_ssl_server_policy_ec_context),
+ se_choose,
+ se_do_keyx,
+ se_do_sign
+};
+
+/* see bearssl_ssl.h */
+void
+br_ssl_server_set_single_ec(br_ssl_server_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->chain_handler.single_ec.vtable = &se_policy_vtable;
+ cc->chain_handler.single_ec.chain = chain;
+ cc->chain_handler.single_ec.chain_len = chain_len;
+ cc->chain_handler.single_ec.sk = sk;
+ cc->chain_handler.single_ec.allowed_usages = allowed_usages;
+ cc->chain_handler.single_ec.cert_issuer_key_type = cert_issuer_key_type;
+ cc->chain_handler.single_ec.mhash = &cc->eng.mhash;
+ cc->chain_handler.single_ec.iec = iec;
+ cc->chain_handler.single_ec.iecdsa = iecdsa;
+ cc->policy_vtable = &cc->chain_handler.single_ec.vtable;
+}
diff --git a/test/monniaux/BearSSL/src/ssl/ssl_scert_single_rsa.c b/test/monniaux/BearSSL/src/ssl/ssl_scert_single_rsa.c
new file mode 100644
index 00000000..b2c77679
--- /dev/null
+++ b/test/monniaux/BearSSL/src/ssl/ssl_scert_single_rsa.c
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+static int
+sr_choose(const br_ssl_server_policy_class **pctx,
+ const br_ssl_server_context *cc,
+ br_ssl_server_choices *choices)
+{
+ br_ssl_server_policy_rsa_context *pc;
+ const br_suite_translated *st;
+ size_t u, st_num;
+ unsigned hash_id;
+ int fh;
+
+ pc = (br_ssl_server_policy_rsa_context *)pctx;
+ st = br_ssl_server_get_client_suites(cc, &st_num);
+ if (cc->eng.session.version < BR_TLS12) {
+ hash_id = 0;
+ fh = 1;
+ } else {
+ hash_id = br_ssl_choose_hash(
+ br_ssl_server_get_client_hashes(cc));
+ fh = (hash_id != 0);
+ }
+ choices->chain = pc->chain;
+ choices->chain_len = pc->chain_len;
+ for (u = 0; u < st_num; u ++) {
+ unsigned tt;
+
+ tt = st[u][1];
+ switch (tt >> 12) {
+ case BR_SSLKEYX_RSA:
+ if ((pc->allowed_usages & BR_KEYTYPE_KEYX) != 0) {
+ choices->cipher_suite = st[u][0];
+ return 1;
+ }
+ break;
+ case BR_SSLKEYX_ECDHE_RSA:
+ if ((pc->allowed_usages & BR_KEYTYPE_SIGN) != 0 && fh) {
+ choices->cipher_suite = st[u][0];
+ choices->algo_id = hash_id + 0xFF00;
+ return 1;
+ }
+ break;
+ }
+ }
+ return 0;
+}
+
+static uint32_t
+sr_do_keyx(const br_ssl_server_policy_class **pctx,
+ unsigned char *data, size_t *len)
+{
+ br_ssl_server_policy_rsa_context *pc;
+
+ pc = (br_ssl_server_policy_rsa_context *)pctx;
+ return br_rsa_ssl_decrypt(pc->irsacore, pc->sk, data, *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
+sr_do_sign(const br_ssl_server_policy_class **pctx,
+ unsigned algo_id, unsigned char *data, size_t hv_len, size_t len)
+{
+ br_ssl_server_policy_rsa_context *pc;
+ unsigned char hv[64];
+ size_t sig_len;
+ const unsigned char *hash_oid;
+
+ pc = (br_ssl_server_policy_rsa_context *)pctx;
+ memcpy(hv, data, hv_len);
+ algo_id &= 0xFF;
+ if (algo_id == 0) {
+ hash_oid = NULL;
+ } else if (algo_id >= 2 && algo_id <= 6) {
+ hash_oid = HASH_OID[algo_id - 2];
+ } else {
+ return 0;
+ }
+ sig_len = (pc->sk->n_bitlen + 7) >> 3;
+ if (len < sig_len) {
+ return 0;
+ }
+ return pc->irsasign(hash_oid, hv, hv_len, pc->sk, data) ? sig_len : 0;
+}
+
+static const br_ssl_server_policy_class sr_policy_vtable = {
+ sizeof(br_ssl_server_policy_rsa_context),
+ sr_choose,
+ sr_do_keyx,
+ sr_do_sign
+};
+
+/* see bearssl_ssl.h */
+void
+br_ssl_server_set_single_rsa(br_ssl_server_context *cc,
+ const br_x509_certificate *chain, size_t chain_len,
+ const br_rsa_private_key *sk, unsigned allowed_usages,
+ br_rsa_private irsacore, br_rsa_pkcs1_sign irsasign)
+{
+ cc->chain_handler.single_rsa.vtable = &sr_policy_vtable;
+ cc->chain_handler.single_rsa.chain = chain;
+ cc->chain_handler.single_rsa.chain_len = chain_len;
+ cc->chain_handler.single_rsa.sk = sk;
+ cc->chain_handler.single_rsa.allowed_usages = allowed_usages;
+ cc->chain_handler.single_rsa.irsacore = irsacore;
+ cc->chain_handler.single_rsa.irsasign = irsasign;
+ cc->policy_vtable = &cc->chain_handler.single_rsa.vtable;
+}
diff --git a/test/monniaux/BearSSL/src/ssl/ssl_server.c b/test/monniaux/BearSSL/src/ssl/ssl_server.c
new file mode 100644
index 00000000..5578b630
--- /dev/null
+++ b/test/monniaux/BearSSL/src/ssl/ssl_server.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_ssl.h */
+void
+br_ssl_server_zero(br_ssl_server_context *cc)
+{
+ /*
+ * For really standard C, we should explicitly set to NULL all
+ * pointers, and 0 all other fields. However, on all our target
+ * architectures, a direct memset() will work, be faster, and
+ * use a lot less code.
+ */
+ memset(cc, 0, sizeof *cc);
+}
+
+/* see bearssl_ssl.h */
+int
+br_ssl_server_reset(br_ssl_server_context *cc)
+{
+ br_ssl_engine_set_buffer(&cc->eng, NULL, 0, 0);
+ if (!br_ssl_engine_init_rand(&cc->eng)) {
+ return 0;
+ }
+ cc->eng.reneg = 0;
+ br_ssl_engine_hs_reset(&cc->eng,
+ br_ssl_hs_server_init_main, br_ssl_hs_server_run);
+ return br_ssl_engine_last_error(&cc->eng) == BR_ERR_OK;
+}
diff --git a/test/monniaux/BearSSL/src/ssl/ssl_server_full_ec.c b/test/monniaux/BearSSL/src/ssl/ssl_server_full_ec.c
new file mode 100644
index 00000000..bccc0930
--- /dev/null
+++ b/test/monniaux/BearSSL/src/ssl/ssl_server_full_ec.c
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_ssl.h */
+void
+br_ssl_server_init_full_ec(br_ssl_server_context *cc,
+ const br_x509_certificate *chain, size_t chain_len,
+ unsigned cert_issuer_key_type, const br_ec_private_key *sk)
+{
+ /*
+ * The "full" profile supports all implemented cipher suites.
+ *
+ * Rationale for suite order, from most important to least
+ * important rule:
+ *
+ * -- Don't use 3DES if AES is available.
+ * -- Try to have Forward Secrecy (ECDHE suite) if possible.
+ * -- ChaCha20+Poly1305 is better than AES/GCM (faster, smaller).
+ * -- GCM is better than CCM and CBC. CCM is better than CBC.
+ * -- CCM is better than CCM_8.
+ * -- AES-128 is preferred over AES-256 (AES-128 is already
+ * strong enough, and AES-256 is 40% more expensive).
+ *
+ * Note that for ECDH suites, the list will be automatically
+ * filtered based on the issuing CA key type.
+ */
+ static const uint16_t suites[] = {
+ BR_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
+ BR_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ BR_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+ BR_TLS_ECDHE_ECDSA_WITH_AES_128_CCM,
+ BR_TLS_ECDHE_ECDSA_WITH_AES_256_CCM,
+ BR_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8,
+ BR_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8,
+ BR_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
+ BR_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
+ BR_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
+ BR_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
+ BR_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256,
+ BR_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256,
+ BR_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384,
+ BR_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384,
+ BR_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256,
+ BR_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256,
+ BR_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384,
+ BR_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384,
+ BR_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
+ BR_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,
+ BR_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,
+ BR_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,
+ BR_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
+ BR_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,
+ BR_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA
+ };
+
+ /*
+ * All hash functions are activated.
+ * Note: the X.509 validation engine will nonetheless refuse to
+ * validate signatures that use MD5 as hash function.
+ */
+ static const br_hash_class *hashes[] = {
+ &br_md5_vtable,
+ &br_sha1_vtable,
+ &br_sha224_vtable,
+ &br_sha256_vtable,
+ &br_sha384_vtable,
+ &br_sha512_vtable
+ };
+
+ int id;
+
+ /*
+ * Reset server context and set supported versions from TLS-1.0
+ * to TLS-1.2 (inclusive).
+ */
+ br_ssl_server_zero(cc);
+ br_ssl_engine_set_versions(&cc->eng, BR_TLS10, BR_TLS12);
+
+ /*
+ * Set suites and elliptic curve implementation (for ECDHE).
+ */
+ br_ssl_engine_set_suites(&cc->eng, suites,
+ (sizeof suites) / (sizeof suites[0]));
+ br_ssl_engine_set_default_ec(&cc->eng);
+
+ /*
+ * Set the "server policy": handler for the certificate chain
+ * and private key operations.
+ */
+ br_ssl_server_set_single_ec(cc, chain, chain_len, sk,
+ BR_KEYTYPE_KEYX | BR_KEYTYPE_SIGN,
+ cert_issuer_key_type,
+ br_ssl_engine_get_ec(&cc->eng),
+#if BR_LOMUL
+ br_ecdsa_i15_sign_asn1
+#else
+ br_ecdsa_i31_sign_asn1
+#endif
+ );
+
+ /*
+ * Set supported hash functions.
+ */
+ for (id = br_md5_ID; id <= br_sha512_ID; id ++) {
+ const br_hash_class *hc;
+
+ hc = hashes[id - 1];
+ br_ssl_engine_set_hash(&cc->eng, id, hc);
+ }
+
+ /*
+ * Set the PRF implementations.
+ */
+ br_ssl_engine_set_prf10(&cc->eng, &br_tls10_prf);
+ br_ssl_engine_set_prf_sha256(&cc->eng, &br_tls12_sha256_prf);
+ br_ssl_engine_set_prf_sha384(&cc->eng, &br_tls12_sha384_prf);
+
+ /*
+ * Symmetric encryption.
+ */
+ br_ssl_engine_set_default_aes_cbc(&cc->eng);
+ br_ssl_engine_set_default_aes_ccm(&cc->eng);
+ br_ssl_engine_set_default_aes_gcm(&cc->eng);
+ br_ssl_engine_set_default_des_cbc(&cc->eng);
+ br_ssl_engine_set_default_chapol(&cc->eng);
+}
diff --git a/test/monniaux/BearSSL/src/ssl/ssl_server_full_rsa.c b/test/monniaux/BearSSL/src/ssl/ssl_server_full_rsa.c
new file mode 100644
index 00000000..d67c0761
--- /dev/null
+++ b/test/monniaux/BearSSL/src/ssl/ssl_server_full_rsa.c
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_ssl.h */
+void
+br_ssl_server_init_full_rsa(br_ssl_server_context *cc,
+ const br_x509_certificate *chain, size_t chain_len,
+ const br_rsa_private_key *sk)
+{
+ /*
+ * The "full" profile supports all implemented cipher suites.
+ *
+ * Rationale for suite order, from most important to least
+ * important rule:
+ *
+ * -- Don't use 3DES if AES is available.
+ * -- Try to have Forward Secrecy (ECDHE suite) if possible.
+ * -- ChaCha20+Poly1305 is better than AES/GCM (faster, smaller).
+ * -- GCM is better than CBC.
+ * -- AES-128 is preferred over AES-256 (AES-128 is already
+ * strong enough, and AES-256 is 40% more expensive).
+ */
+ static const uint16_t suites[] = {
+ BR_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
+ BR_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ BR_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+ BR_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
+ BR_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
+ BR_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+ BR_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+ BR_TLS_RSA_WITH_AES_128_GCM_SHA256,
+ BR_TLS_RSA_WITH_AES_256_GCM_SHA384,
+ BR_TLS_RSA_WITH_AES_128_CCM,
+ BR_TLS_RSA_WITH_AES_256_CCM,
+ BR_TLS_RSA_WITH_AES_128_CCM_8,
+ BR_TLS_RSA_WITH_AES_256_CCM_8,
+ BR_TLS_RSA_WITH_AES_128_CBC_SHA256,
+ BR_TLS_RSA_WITH_AES_256_CBC_SHA256,
+ BR_TLS_RSA_WITH_AES_128_CBC_SHA,
+ BR_TLS_RSA_WITH_AES_256_CBC_SHA,
+ BR_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
+ BR_TLS_RSA_WITH_3DES_EDE_CBC_SHA
+ };
+
+ /*
+ * All hash functions are activated.
+ * Note: the X.509 validation engine will nonetheless refuse to
+ * validate signatures that use MD5 as hash function.
+ */
+ static const br_hash_class *hashes[] = {
+ &br_md5_vtable,
+ &br_sha1_vtable,
+ &br_sha224_vtable,
+ &br_sha256_vtable,
+ &br_sha384_vtable,
+ &br_sha512_vtable
+ };
+
+ int id;
+
+ /*
+ * Reset server context and set supported versions from TLS-1.0
+ * to TLS-1.2 (inclusive).
+ */
+ br_ssl_server_zero(cc);
+ br_ssl_engine_set_versions(&cc->eng, BR_TLS10, BR_TLS12);
+
+ /*
+ * Set suites and elliptic curve implementation (for ECDHE).
+ */
+ br_ssl_engine_set_suites(&cc->eng, suites,
+ (sizeof suites) / (sizeof suites[0]));
+ br_ssl_engine_set_default_ec(&cc->eng);
+
+ /*
+ * Set the "server policy": handler for the certificate chain
+ * and private key operations.
+ */
+ br_ssl_server_set_single_rsa(cc, chain, chain_len, sk,
+ BR_KEYTYPE_KEYX | BR_KEYTYPE_SIGN,
+ br_rsa_private_get_default(),
+ br_rsa_pkcs1_sign_get_default());
+
+ /*
+ * Set supported hash functions.
+ */
+ for (id = br_md5_ID; id <= br_sha512_ID; id ++) {
+ const br_hash_class *hc;
+
+ hc = hashes[id - 1];
+ br_ssl_engine_set_hash(&cc->eng, id, hc);
+ }
+
+ /*
+ * Set the PRF implementations.
+ */
+ br_ssl_engine_set_prf10(&cc->eng, &br_tls10_prf);
+ br_ssl_engine_set_prf_sha256(&cc->eng, &br_tls12_sha256_prf);
+ br_ssl_engine_set_prf_sha384(&cc->eng, &br_tls12_sha384_prf);
+
+ /*
+ * Symmetric encryption.
+ */
+ br_ssl_engine_set_default_aes_cbc(&cc->eng);
+ br_ssl_engine_set_default_aes_ccm(&cc->eng);
+ br_ssl_engine_set_default_aes_gcm(&cc->eng);
+ br_ssl_engine_set_default_des_cbc(&cc->eng);
+ br_ssl_engine_set_default_chapol(&cc->eng);
+}
diff --git a/test/monniaux/BearSSL/src/ssl/ssl_server_mine2c.c b/test/monniaux/BearSSL/src/ssl/ssl_server_mine2c.c
new file mode 100644
index 00000000..bf61b565
--- /dev/null
+++ b/test/monniaux/BearSSL/src/ssl/ssl_server_mine2c.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_ssl.h */
+void
+br_ssl_server_init_mine2c(br_ssl_server_context *cc,
+ const br_x509_certificate *chain, size_t chain_len,
+ const br_rsa_private_key *sk)
+{
+ static const uint16_t suites[] = {
+ BR_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
+ };
+
+ /*
+ * Reset server context and set supported versions to TLS-1.2 (only).
+ */
+ br_ssl_server_zero(cc);
+ br_ssl_engine_set_versions(&cc->eng, BR_TLS12, BR_TLS12);
+
+ /*
+ * Set suites and elliptic curve implementation (for ECDHE).
+ */
+ br_ssl_engine_set_suites(&cc->eng, suites,
+ (sizeof suites) / (sizeof suites[0]));
+ br_ssl_engine_set_ec(&cc->eng, &br_ec_all_m15);
+
+ /*
+ * Set the "server policy": handler for the certificate chain
+ * and private key operations.
+ */
+ br_ssl_server_set_single_rsa(cc, chain, chain_len, sk,
+ BR_KEYTYPE_SIGN, 0, br_rsa_i31_pkcs1_sign);
+
+ /*
+ * Set supported hash functions.
+ */
+ br_ssl_engine_set_hash(&cc->eng, br_sha256_ID, &br_sha256_vtable);
+
+ /*
+ * Set the PRF implementations.
+ */
+ br_ssl_engine_set_prf_sha256(&cc->eng, &br_tls12_sha256_prf);
+
+ /*
+ * Symmetric encryption.
+ */
+ br_ssl_engine_set_default_chapol(&cc->eng);
+}
diff --git a/test/monniaux/BearSSL/src/ssl/ssl_server_mine2g.c b/test/monniaux/BearSSL/src/ssl/ssl_server_mine2g.c
new file mode 100644
index 00000000..80fa5b11
--- /dev/null
+++ b/test/monniaux/BearSSL/src/ssl/ssl_server_mine2g.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_ssl.h */
+void
+br_ssl_server_init_mine2g(br_ssl_server_context *cc,
+ const br_x509_certificate *chain, size_t chain_len,
+ const br_rsa_private_key *sk)
+{
+ static const uint16_t suites[] = {
+ BR_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
+ };
+
+ /*
+ * Reset server context and set supported versions to TLS-1.2 (only).
+ */
+ br_ssl_server_zero(cc);
+ br_ssl_engine_set_versions(&cc->eng, BR_TLS12, BR_TLS12);
+
+ /*
+ * Set suites and elliptic curve implementation (for ECDHE).
+ */
+ br_ssl_engine_set_suites(&cc->eng, suites,
+ (sizeof suites) / (sizeof suites[0]));
+ br_ssl_engine_set_ec(&cc->eng, &br_ec_all_m15);
+
+ /*
+ * Set the "server policy": handler for the certificate chain
+ * and private key operations.
+ */
+ br_ssl_server_set_single_rsa(cc, chain, chain_len, sk,
+ BR_KEYTYPE_SIGN, 0, br_rsa_i31_pkcs1_sign);
+
+ /*
+ * Set supported hash functions.
+ */
+ br_ssl_engine_set_hash(&cc->eng, br_sha256_ID, &br_sha256_vtable);
+
+ /*
+ * Set the PRF implementations.
+ */
+ br_ssl_engine_set_prf_sha256(&cc->eng, &br_tls12_sha256_prf);
+
+ /*
+ * Symmetric encryption.
+ */
+ br_ssl_engine_set_default_aes_gcm(&cc->eng);
+}
diff --git a/test/monniaux/BearSSL/src/ssl/ssl_server_minf2c.c b/test/monniaux/BearSSL/src/ssl/ssl_server_minf2c.c
new file mode 100644
index 00000000..3f442369
--- /dev/null
+++ b/test/monniaux/BearSSL/src/ssl/ssl_server_minf2c.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_ssl.h */
+void
+br_ssl_server_init_minf2c(br_ssl_server_context *cc,
+ const br_x509_certificate *chain, size_t chain_len,
+ const br_ec_private_key *sk)
+{
+ static const uint16_t suites[] = {
+ BR_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
+ };
+
+ /*
+ * Reset server context and set supported versions to TLS-1.2 (only).
+ */
+ br_ssl_server_zero(cc);
+ br_ssl_engine_set_versions(&cc->eng, BR_TLS12, BR_TLS12);
+
+ /*
+ * Set suites and elliptic curve implementation (for ECDHE).
+ */
+ br_ssl_engine_set_suites(&cc->eng, suites,
+ (sizeof suites) / (sizeof suites[0]));
+ br_ssl_engine_set_ec(&cc->eng, &br_ec_all_m15);
+
+ /*
+ * Set the "server policy": handler for the certificate chain
+ * and private key operations.
+ */
+ br_ssl_server_set_single_ec(cc, chain, chain_len, sk,
+ BR_KEYTYPE_SIGN, 0, &br_ec_all_m15, br_ecdsa_i31_sign_asn1);
+
+ /*
+ * Set supported hash functions.
+ */
+ br_ssl_engine_set_hash(&cc->eng, br_sha256_ID, &br_sha256_vtable);
+
+ /*
+ * Set the PRF implementations.
+ */
+ br_ssl_engine_set_prf_sha256(&cc->eng, &br_tls12_sha256_prf);
+
+ /*
+ * Symmetric encryption.
+ */
+ br_ssl_engine_set_default_chapol(&cc->eng);
+}
diff --git a/test/monniaux/BearSSL/src/ssl/ssl_server_minf2g.c b/test/monniaux/BearSSL/src/ssl/ssl_server_minf2g.c
new file mode 100644
index 00000000..8613de1e
--- /dev/null
+++ b/test/monniaux/BearSSL/src/ssl/ssl_server_minf2g.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_ssl.h */
+void
+br_ssl_server_init_minf2g(br_ssl_server_context *cc,
+ const br_x509_certificate *chain, size_t chain_len,
+ const br_ec_private_key *sk)
+{
+ static const uint16_t suites[] = {
+ BR_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
+ };
+
+ /*
+ * Reset server context and set supported versions to TLS-1.2 (only).
+ */
+ br_ssl_server_zero(cc);
+ br_ssl_engine_set_versions(&cc->eng, BR_TLS12, BR_TLS12);
+
+ /*
+ * Set suites and elliptic curve implementation (for ECDHE).
+ */
+ br_ssl_engine_set_suites(&cc->eng, suites,
+ (sizeof suites) / (sizeof suites[0]));
+ br_ssl_engine_set_ec(&cc->eng, &br_ec_all_m15);
+
+ /*
+ * Set the "server policy": handler for the certificate chain
+ * and private key operations.
+ */
+ br_ssl_server_set_single_ec(cc, chain, chain_len, sk,
+ BR_KEYTYPE_SIGN, 0, &br_ec_all_m15, br_ecdsa_i31_sign_asn1);
+
+ /*
+ * Set supported hash functions.
+ */
+ br_ssl_engine_set_hash(&cc->eng, br_sha256_ID, &br_sha256_vtable);
+
+ /*
+ * Set the PRF implementations.
+ */
+ br_ssl_engine_set_prf_sha256(&cc->eng, &br_tls12_sha256_prf);
+
+ /*
+ * Symmetric encryption.
+ */
+ br_ssl_engine_set_default_aes_gcm(&cc->eng);
+}
diff --git a/test/monniaux/BearSSL/src/ssl/ssl_server_minr2g.c b/test/monniaux/BearSSL/src/ssl/ssl_server_minr2g.c
new file mode 100644
index 00000000..83c238b4
--- /dev/null
+++ b/test/monniaux/BearSSL/src/ssl/ssl_server_minr2g.c
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_ssl.h */
+void
+br_ssl_server_init_minr2g(br_ssl_server_context *cc,
+ const br_x509_certificate *chain, size_t chain_len,
+ const br_rsa_private_key *sk)
+{
+ static const uint16_t suites[] = {
+ BR_TLS_RSA_WITH_AES_128_GCM_SHA256
+ };
+
+ /*
+ * Reset server context and set supported versions to TLS-1.2 (only).
+ */
+ br_ssl_server_zero(cc);
+ br_ssl_engine_set_versions(&cc->eng, BR_TLS12, BR_TLS12);
+
+ /*
+ * Set suites.
+ */
+ br_ssl_engine_set_suites(&cc->eng, suites,
+ (sizeof suites) / (sizeof suites[0]));
+
+ /*
+ * Set the "server policy": handler for the certificate chain
+ * and private key operations.
+ */
+ br_ssl_server_set_single_rsa(cc, chain, chain_len, sk,
+ BR_KEYTYPE_KEYX, br_rsa_i31_private, 0);
+
+ /*
+ * Set supported hash functions.
+ */
+ br_ssl_engine_set_hash(&cc->eng, br_sha256_ID, &br_sha256_vtable);
+
+ /*
+ * Set the PRF implementations.
+ */
+ br_ssl_engine_set_prf_sha256(&cc->eng, &br_tls12_sha256_prf);
+
+ /*
+ * Symmetric encryption.
+ */
+ br_ssl_engine_set_default_aes_gcm(&cc->eng);
+}
diff --git a/test/monniaux/BearSSL/src/ssl/ssl_server_minu2g.c b/test/monniaux/BearSSL/src/ssl/ssl_server_minu2g.c
new file mode 100644
index 00000000..67213842
--- /dev/null
+++ b/test/monniaux/BearSSL/src/ssl/ssl_server_minu2g.c
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_ssl.h */
+void
+br_ssl_server_init_minu2g(br_ssl_server_context *cc,
+ const br_x509_certificate *chain, size_t chain_len,
+ const br_ec_private_key *sk)
+{
+ static const uint16_t suites[] = {
+ BR_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256
+ };
+
+ /*
+ * Reset server context and set supported versions to TLS-1.2 (only).
+ */
+ br_ssl_server_zero(cc);
+ br_ssl_engine_set_versions(&cc->eng, BR_TLS12, BR_TLS12);
+
+ /*
+ * Set suites.
+ */
+ br_ssl_engine_set_suites(&cc->eng, suites,
+ (sizeof suites) / (sizeof suites[0]));
+
+ /*
+ * Set the "server policy": handler for the certificate chain
+ * and private key operations.
+ */
+ br_ssl_server_set_single_ec(cc, chain, chain_len, sk,
+ BR_KEYTYPE_KEYX, BR_KEYTYPE_RSA, &br_ec_all_m15, 0);
+
+ /*
+ * Set supported hash functions.
+ */
+ br_ssl_engine_set_hash(&cc->eng, br_sha256_ID, &br_sha256_vtable);
+
+ /*
+ * Set the PRF implementations.
+ */
+ br_ssl_engine_set_prf_sha256(&cc->eng, &br_tls12_sha256_prf);
+
+ /*
+ * Symmetric encryption.
+ */
+ br_ssl_engine_set_default_aes_gcm(&cc->eng);
+}
diff --git a/test/monniaux/BearSSL/src/ssl/ssl_server_minv2g.c b/test/monniaux/BearSSL/src/ssl/ssl_server_minv2g.c
new file mode 100644
index 00000000..194e654e
--- /dev/null
+++ b/test/monniaux/BearSSL/src/ssl/ssl_server_minv2g.c
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_ssl.h */
+void
+br_ssl_server_init_minv2g(br_ssl_server_context *cc,
+ const br_x509_certificate *chain, size_t chain_len,
+ const br_ec_private_key *sk)
+{
+ static const uint16_t suites[] = {
+ BR_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256
+ };
+
+ /*
+ * Reset server context and set supported versions to TLS-1.2 (only).
+ */
+ br_ssl_server_zero(cc);
+ br_ssl_engine_set_versions(&cc->eng, BR_TLS12, BR_TLS12);
+
+ /*
+ * Set suites.
+ */
+ br_ssl_engine_set_suites(&cc->eng, suites,
+ (sizeof suites) / (sizeof suites[0]));
+
+ /*
+ * Set the "server policy": handler for the certificate chain
+ * and private key operations.
+ */
+ br_ssl_server_set_single_ec(cc, chain, chain_len, sk,
+ BR_KEYTYPE_KEYX, BR_KEYTYPE_EC, &br_ec_all_m15, 0);
+
+ /*
+ * Set supported hash functions.
+ */
+ br_ssl_engine_set_hash(&cc->eng, br_sha256_ID, &br_sha256_vtable);
+
+ /*
+ * Set the PRF implementations.
+ */
+ br_ssl_engine_set_prf_sha256(&cc->eng, &br_tls12_sha256_prf);
+
+ /*
+ * Symmetric encryption.
+ */
+ br_ssl_engine_set_default_aes_gcm(&cc->eng);
+}