From b50081a83bd1b55254c4ff10ac97bf5e00747628 Mon Sep 17 00:00:00 2001 From: Sergey Lyubka Date: Thu, 6 Feb 2025 13:07:53 +0000 Subject: [PATCH] TLS verification --- mongoose.c | 2380 ++++++++++++++++++++++-- mongoose.h | 104 +- src/drivers/phy.h | 2 +- src/sha256.c | 171 ++ src/sha256.h | 14 + src/tls_builtin.c | 624 +++++-- src/tls_chacha20.c | 2 + src/tls_rsa.c | 1579 ++++++++++++++++ src/tls_rsa.h | 7 + src/util.h | 6 + test/Makefile | 2 +- test/data/ca.pem | 134 ++ test/unit_test.c | 2 +- tutorials/http/http-client/packed_fs.c | 591 +++++- 14 files changed, 5281 insertions(+), 337 deletions(-) create mode 100644 src/tls_rsa.c create mode 100644 src/tls_rsa.h diff --git a/mongoose.c b/mongoose.c index 32772391..c13576dc 100644 --- a/mongoose.c +++ b/mongoose.c @@ -7630,6 +7630,13 @@ void mg_sha256_final(unsigned char digest[32], mg_sha256_ctx *ctx) { } } +void mg_sha256(uint8_t dst[32], uint8_t *data, size_t datasz) { + mg_sha256_ctx ctx; + mg_sha256_init(&ctx); + mg_sha256_update(&ctx, data, datasz); + mg_sha256_final(dst, &ctx); +} + void mg_hmac_sha256(uint8_t dst[32], uint8_t *key, size_t keysz, uint8_t *data, size_t datasz) { mg_sha256_ctx ctx; @@ -7659,6 +7666,170 @@ void mg_hmac_sha256(uint8_t dst[32], uint8_t *key, size_t keysz, uint8_t *data, mg_sha256_final(dst, &ctx); } +//===================================== +// TODO: rename macros +#define ROTR64(x, n) (((x) >> (n)) | ((x) << (64 - (n)))) +#define CH(x, y, z) (((x) & (y)) ^ (~(x) & (z))) +#define MAJ(x, y, z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) +#define EP0(x) (ROTR64(x, 28) ^ ROTR64(x, 34) ^ ROTR64(x, 39)) +#define EP1(x) (ROTR64(x, 14) ^ ROTR64(x, 18) ^ ROTR64(x, 41)) +#define SIG0(x) (ROTR64(x, 1) ^ ROTR64(x, 8) ^ ((x) >> 7)) +#define SIG1(x) (ROTR64(x, 19) ^ ROTR64(x, 61) ^ ((x) >> 6)) + +static const uint64_t mg_sha256_k2[80] = { + 0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, + 0xe9b5dba58189dbbc, 0x3956c25bf348b538, 0x59f111f1b605d019, + 0x923f82a4af194f9b, 0xab1c5ed5da6d8118, 0xd807aa98a3030242, + 0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2, + 0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235, + 0xc19bf174cf692694, 0xe49b69c19ef14ad2, 0xefbe4786384f25e3, + 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65, 0x2de92c6f592b0275, + 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5, + 0x983e5152ee66dfab, 0xa831c66d2db43210, 0xb00327c898fb213f, + 0xbf597fc7beef0ee4, 0xc6e00bf33da88fc2, 0xd5a79147930aa725, + 0x06ca6351e003826f, 0x142929670a0e6e70, 0x27b70a8546d22ffc, + 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df, + 0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, + 0x92722c851482353b, 0xa2bfe8a14cf10364, 0xa81a664bbc423001, + 0xc24b8b70d0f89791, 0xc76c51a30654be30, 0xd192e819d6ef5218, + 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8, + 0x19a4c116b8d2d0c8, 0x1e376c085141ab53, 0x2748774cdf8eeb99, + 0x34b0bcb5e19b48a8, 0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, + 0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3, 0x748f82ee5defb2fc, + 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec, + 0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, + 0xc67178f2e372532b, 0xca273eceea26619c, 0xd186b8c721c0c207, + 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178, 0x06f067aa72176fba, + 0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b, + 0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc, + 0x431d67c49c100d4c, 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, + 0x5fcb6fab3ad6faec, 0x6c44198c4a475817}; + +static void mg_sha384_transform(mg_sha384_ctx *ctx, const uint8_t data[]) { + uint64_t m[80]; + uint64_t a, b, c, d, e, f, g, h; + int i, j; + + for (i = 0, j = 0; i < 16; ++i, j += 8) + m[i] = ((uint64_t) data[j] << 56) | ((uint64_t) data[j + 1] << 48) | + ((uint64_t) data[j + 2] << 40) | ((uint64_t) data[j + 3] << 32) | + ((uint64_t) data[j + 4] << 24) | ((uint64_t) data[j + 5] << 16) | + ((uint64_t) data[j + 6] << 8) | ((uint64_t) data[j + 7]); + for (; i < 80; ++i) + m[i] = SIG1(m[i - 2]) + m[i - 7] + SIG0(m[i - 15]) + m[i - 16]; + + a = ctx->state[0]; + b = ctx->state[1]; + c = ctx->state[2]; + d = ctx->state[3]; + e = ctx->state[4]; + f = ctx->state[5]; + g = ctx->state[6]; + h = ctx->state[7]; + + for (i = 0; i < 80; ++i) { + uint64_t t1 = h + EP1(e) + CH(e, f, g) + mg_sha256_k2[i] + m[i]; + uint64_t t2 = EP0(a) + MAJ(a, b, c); + h = g; + g = f; + f = e; + e = d + t1; + d = c; + c = b; + b = a; + a = t1 + t2; + } + + ctx->state[0] += a; + ctx->state[1] += b; + ctx->state[2] += c; + ctx->state[3] += d; + ctx->state[4] += e; + ctx->state[5] += f; + ctx->state[6] += g; + ctx->state[7] += h; +} + +void mg_sha384_init(mg_sha384_ctx *ctx) { + ctx->datalen = 0; + ctx->bitlen[0] = 0; + ctx->bitlen[1] = 0; + ctx->state[0] = 0xcbbb9d5dc1059ed8; + ctx->state[1] = 0x629a292a367cd507; + ctx->state[2] = 0x9159015a3070dd17; + ctx->state[3] = 0x152fecd8f70e5939; + ctx->state[4] = 0x67332667ffc00b31; + ctx->state[5] = 0x8eb44a8768581511; + ctx->state[6] = 0xdb0c2e0d64f98fa7; + ctx->state[7] = 0x47b5481dbefa4fa4; +} + +void mg_sha384_update(mg_sha384_ctx *ctx, const uint8_t *data, size_t len) { + size_t i; + for (i = 0; i < len; ++i) { + ctx->buffer[ctx->datalen] = data[i]; + ctx->datalen++; + if (ctx->datalen == 128) { + mg_sha384_transform(ctx, ctx->buffer); + ctx->bitlen[1] += 1024; + if (ctx->bitlen[1] < 1024) ctx->bitlen[0]++; + ctx->datalen = 0; + } + } +} + +void mg_sha384_final(uint8_t hash[48], mg_sha384_ctx *ctx) { + size_t i = ctx->datalen; + + if (ctx->datalen < 112) { + ctx->buffer[i++] = 0x80; + while (i < 112) ctx->buffer[i++] = 0x00; + } else { + ctx->buffer[i++] = 0x80; + while (i < 128) ctx->buffer[i++] = 0x00; + mg_sha384_transform(ctx, ctx->buffer); + memset(ctx->buffer, 0, 112); + } + + ctx->bitlen[1] += ctx->datalen * 8; + if (ctx->bitlen[1] < ctx->datalen * 8) ctx->bitlen[0]++; + ctx->buffer[127] = (uint8_t) (ctx->bitlen[1]); + ctx->buffer[126] = (uint8_t) (ctx->bitlen[1] >> 8); + ctx->buffer[125] = (uint8_t) (ctx->bitlen[1] >> 16); + ctx->buffer[124] = (uint8_t) (ctx->bitlen[1] >> 24); + ctx->buffer[123] = (uint8_t) (ctx->bitlen[1] >> 32); + ctx->buffer[122] = (uint8_t) (ctx->bitlen[1] >> 40); + ctx->buffer[121] = (uint8_t) (ctx->bitlen[1] >> 48); + ctx->buffer[120] = (uint8_t) (ctx->bitlen[1] >> 56); + ctx->buffer[119] = (uint8_t) (ctx->bitlen[0]); + ctx->buffer[118] = (uint8_t) (ctx->bitlen[0] >> 8); + ctx->buffer[117] = (uint8_t) (ctx->bitlen[0] >> 16); + ctx->buffer[116] = (uint8_t) (ctx->bitlen[0] >> 24); + ctx->buffer[115] = (uint8_t) (ctx->bitlen[0] >> 32); + ctx->buffer[114] = (uint8_t) (ctx->bitlen[0] >> 40); + ctx->buffer[113] = (uint8_t) (ctx->bitlen[0] >> 48); + ctx->buffer[112] = (uint8_t) (ctx->bitlen[0] >> 56); + mg_sha384_transform(ctx, ctx->buffer); + + for (i = 0; i < 6; ++i) { + hash[i * 8] = (uint8_t) ((ctx->state[i] >> 56) & 0xff); + hash[i * 8 + 1] = (uint8_t) ((ctx->state[i] >> 48) & 0xff); + hash[i * 8 + 2] = (uint8_t) ((ctx->state[i] >> 40) & 0xff); + hash[i * 8 + 3] = (uint8_t) ((ctx->state[i] >> 32) & 0xff); + hash[i * 8 + 4] = (uint8_t) ((ctx->state[i] >> 24) & 0xff); + hash[i * 8 + 5] = (uint8_t) ((ctx->state[i] >> 16) & 0xff); + hash[i * 8 + 6] = (uint8_t) ((ctx->state[i] >> 8) & 0xff); + hash[i * 8 + 7] = (uint8_t) (ctx->state[i] & 0xff); + } +} + +void mg_sha384(uint8_t dst[48], uint8_t *data, size_t datasz) { + mg_sha384_ctx ctx; + mg_sha384_init(&ctx); + mg_sha384_update(&ctx, data, datasz); + mg_sha384_final(dst, &ctx); +} + #ifdef MG_ENABLE_LINES #line 1 "src/sntp.c" #endif @@ -9968,6 +10139,7 @@ int mg_aes_gcm_decrypt(unsigned char *output, const unsigned char *input, + #if MG_TLS == MG_TLS_BUILTIN #define CHACHA20 1 @@ -10040,12 +10212,15 @@ struct tls_data { int skip_verification; // perform checks on server certificate? int cert_requested; // client received a CertificateRequest? struct mg_str cert_der; // certificate in DER format + struct mg_str ca_der; // CA certificate uint8_t ec_key[32]; // EC private key char hostname[254]; // server hostname (client extension) - uint8_t certhash[32]; // certificate message hash - uint8_t pubkey[64]; // server EC public key to verify cert - uint8_t sighash[32]; // server EC public key to verify cert + int is_ec_pubkey; // EC or RSA? + uint8_t pubkey[512 + 16]; // server EC (64) or RSA (512+exp) public key to + // verify cert + size_t pubkeysz; // size of the server public key + uint8_t sighash[32]; // calculated signature verification hash struct tls_enc enc; }; @@ -10099,6 +10274,66 @@ struct mg_der_tlv { uint8_t *value; }; +static int mg_der_parse(uint8_t *der, size_t dersz, struct mg_der_tlv *tlv) { + size_t header_len = 2; + uint32_t len = dersz < 2 ? 0 : der[1]; + if (dersz < 2) return -1; // Invalid DER + tlv->type = der[0]; + if (len > 0x7F) { // long-form length + uint8_t len_bytes = len & 0x7F; + if (dersz < (size_t) (2 + len_bytes)) return -1; + len = 0; + for (uint8_t i = 0; i < len_bytes; i++) { + len = (len << 8) | der[2 + i]; + } + header_len += len_bytes; + } + if (dersz < header_len + len) return -1; + tlv->len = len; + tlv->value = der + header_len; + return (int) (header_len + len); +} + +static int mg_der_next(struct mg_der_tlv *parent, struct mg_der_tlv *child) { + if (parent->len == 0) return 0; + int consumed = mg_der_parse(parent->value, parent->len, child); + if (consumed < 0) return -1; + parent->value += consumed; + parent->len -= (uint32_t) consumed; + return 1; +} + +static int mg_der_find_oid(struct mg_der_tlv *tlv, const uint8_t *oid, + size_t oid_len, struct mg_der_tlv *found) { + struct mg_der_tlv parent, child; + parent = *tlv; + while (mg_der_next(&parent, &child) > 0) { + if (child.type == 0x06 && child.len == oid_len && + memcmp(child.value, oid, oid_len) == 0) { + return mg_der_next(&parent, found); + } else if (child.type & 0x20) { + struct mg_der_tlv sub_parent = child; + if (mg_der_find_oid(&sub_parent, oid, oid_len, found)) return 1; + } + } + return 0; +} + +#if 0 +static void mg_der_debug(struct mg_der_tlv *tlv, int depth) { + MG_DEBUG(("> %.*sd=%d Type: 0x%02X, Length: %u\n", depth * 4, " ", depth, + tlv->type, tlv->len)); + + if (tlv->type & 0x20) { // Constructed: recurse into children + struct mg_der_tlv child; + struct mg_der_tlv parent = *tlv; + while (mg_der_next(&parent, &child) > 0) { + mg_der_debug(&child, depth + 1); + } + } +} +#endif + // parse DER into a TLV record static int mg_der_to_tlv(uint8_t *der, size_t dersz, struct mg_der_tlv *tlv) { if (dersz < 2) { @@ -10121,31 +10356,6 @@ static int mg_der_to_tlv(uint8_t *der, size_t dersz, struct mg_der_tlv *tlv) { return 0; } -static int mg_der_find(uint8_t *der, size_t dersz, uint8_t *oid, size_t oidsz, - struct mg_der_tlv *tlv) { - uint8_t *p, *end; - struct mg_der_tlv child = {0, 0, NULL}; - if (mg_der_to_tlv(der, dersz, tlv) < 0) { - return -1; // invalid DER - } else if (tlv->type == 6) { // found OID, check value - return (tlv->len == oidsz && memcmp(tlv->value, oid, oidsz) == 0); - } else if ((tlv->type & 0x20) == 0) { - return 0; // Primitive, but not OID: not found - } - // Constructed object: scan children - p = tlv->value; - end = tlv->value + tlv->len; - while (end > p) { - int r; - mg_der_to_tlv(p, (size_t) (end - p), &child); - r = mg_der_find(p, (size_t) (end - p), oid, oidsz, tlv); - if (r < 0) return -1; // error - if (r > 0) return 1; // found OID! - p = child.value + child.len; - } - return 0; // not found -} - // Did we receive a full TLS record in the c->rtls buffer? static bool mg_tls_got_record(struct mg_connection *c) { return c->rtls.len >= (size_t) TLS_RECHDR_SIZE && @@ -10344,7 +10554,7 @@ static void mg_tls_encrypt(struct mg_connection *c, const uint8_t *msg, nonce[8] ^= (uint8_t) ((seq >> 24) & 255U); nonce[9] ^= (uint8_t) ((seq >> 16) & 255U); nonce[10] ^= (uint8_t) ((seq >> 8) & 255U); - nonce[11] ^= (uint8_t) ((seq) &255U); + nonce[11] ^= (uint8_t) ((seq) & 255U); mg_iobuf_add(wio, wio->len, hdr, sizeof(hdr)); mg_iobuf_resize(wio, wio->len + encsz); @@ -10423,8 +10633,7 @@ static int mg_tls_recv_record(struct mg_connection *c) { nonce[8] ^= (uint8_t) ((seq >> 24) & 255U); nonce[9] ^= (uint8_t) ((seq >> 16) & 255U); nonce[10] ^= (uint8_t) ((seq >> 8) & 255U); - nonce[11] ^= (uint8_t) ((seq) &255U); - + nonce[11] ^= (uint8_t) ((seq) & 255U); #if CHACHA20 { uint8_t *dec = (uint8_t *) calloc(1, msgsz); @@ -10512,15 +10721,14 @@ static int mg_tls_server_recv_hello(struct mg_connection *c) { uint16_t key_exchange_len; uint8_t *key_exchange; uint16_t n = MG_LOAD_BE16(ext + j + 2); - if (ext[j] != 0x00 || - ext[j + 1] != 0x33) { // not a key share extension, ignore + if (MG_LOAD_BE16(ext + j) != 0x0033) { // not a key share extension, ignore j += (uint16_t) (n + 4); continue; } key_exchange_len = MG_LOAD_BE16(ext + j + 4); key_exchange = ext + j + 6; if (key_exchange_len > - rio->len - (uint16_t) ((size_t) key_exchange - (size_t) rio->buf) - 2) + rio->len - (uint16_t) ((size_t) key_exchange - (size_t) rio->buf)) goto fail; for (k = 0; k < key_exchange_len;) { uint16_t m = MG_LOAD_BE16(key_exchange + k + 2); @@ -10574,7 +10782,7 @@ static void mg_tls_server_send_hello(struct mg_connection *c) { // calculate keyshare uint8_t x25519_pub[X25519_BYTES]; uint8_t x25519_prv[X25519_BYTES]; - if (!mg_random(x25519_prv, sizeof(x25519_prv))) mg_error(c, "RNG"); + if (!mg_random(x25519_prv, sizeof(x25519_prv))) mg_error(c, "RNG"); mg_tls_x25519(x25519_pub, x25519_prv, X25519_BASE_POINT, 1); mg_tls_x25519(tls->x25519_sec, x25519_prv, tls->x25519_cli, 1); mg_tls_hexdump("s x25519 sec", tls->x25519_sec, sizeof(tls->x25519_sec)); @@ -10603,28 +10811,30 @@ static void mg_tls_server_send_ext(struct mg_connection *c) { static void mg_tls_server_send_cert(struct mg_connection *c) { struct tls_data *tls = (struct tls_data *) c->tls; - // server DER certificate (empty) - size_t n = tls->cert_der.len; + int send_ca = !c->is_client && tls->ca_der.len > 0; + // server DER certificate + CA (optional) + size_t n = tls->cert_der.len + (send_ca ? tls->ca_der.len + 5 : 0); uint8_t *cert = (uint8_t *) calloc(1, 13 + n); if (cert == NULL) { mg_error(c, "tls cert oom"); return; } - cert[0] = 0x0b; // handshake header - cert[1] = (uint8_t) (((n + 9) >> 16) & 255U); // 3 bytes: payload length - cert[2] = (uint8_t) (((n + 9) >> 8) & 255U); - cert[3] = (uint8_t) ((n + 9) & 255U); - cert[4] = 0; // request context - cert[5] = (uint8_t) (((n + 5) >> 16) & 255U); // 3 bytes: cert (s) length - cert[6] = (uint8_t) (((n + 5) >> 8) & 255U); - cert[7] = (uint8_t) ((n + 5) & 255U); - cert[8] = - (uint8_t) (((n) >> 16) & 255U); // 3 bytes: first (and only) cert len - cert[9] = (uint8_t) (((n) >> 8) & 255U); - cert[10] = (uint8_t) (n & 255U); + cert[0] = 0x0b; // handshake header + MG_STORE_BE24(cert + 1, n + 9); + cert[4] = 0; // request context + MG_STORE_BE24(cert + 5, n + 5); // 3 bytes: cert (s) length + MG_STORE_BE24(cert + 8, tls->cert_der.len); // 3 bytes: first cert len // bytes 11+ are certificate in DER format - memmove(cert + 11, tls->cert_der.buf, n); - cert[11 + n] = cert[12 + n] = 0; // certificate extensions (none) + memmove(cert + 11, tls->cert_der.buf, tls->cert_der.len); + MG_STORE_BE16(cert + 11 + tls->cert_der.len, + 0); // certificate extensions (none) + if (send_ca) { + size_t offset = 13 + tls->cert_der.len; + MG_STORE_BE24(cert + offset, tls->ca_der.len); // 3 bytes: CA cert length + memmove(cert + offset + 3, tls->ca_der.buf, + tls->ca_der.len); // CA cert data + MG_STORE_BE16(cert + 11 + n, 0); // certificate extensions (none) + } mg_sha256_update(&tls->sha256, cert, 13 + n); mg_tls_encrypt(c, cert, 13 + n, MG_TLS_HANDSHAKE); free(cert); @@ -10733,9 +10943,10 @@ static void mg_tls_client_send_hello(struct mg_connection *c) { uint8_t x25519_pub[X25519_BYTES]; - // the only signature algorithm we actually support - uint8_t secp256r1_sig_algs[8] = { - 0x00, 0x0d, 0x00, 0x04, 0x00, 0x02, 0x04, 0x03, + // signature algorithms we actually support: + // rsa_pkcs1_sha256, rsa_pss_rsae_sha256 and ecdsa_secp256r1_sha256 + uint8_t secp256r1_sig_algs[12] = { + 0x00, 0x0d, 0x00, 0x08, 0x00, 0x06, 0x04, 0x03, 0x08, 0x04, 0x04, 0x01, }; // all popular signature algorithms (if we don't care about verification) uint8_t all_sig_algs[34] = { @@ -10906,106 +11117,351 @@ static int mg_tls_client_recv_ext(struct mg_connection *c) { return 0; } +struct mg_tls_cert { + int is_ec_pubkey; + struct mg_str sn; + struct mg_str pubkey; + struct mg_str sig; // signature + uint8_t tbshash[48]; // 32b for sha256/secp256, 48b for sha384/secp384 + size_t tbshashsz; // actual TBS hash size +}; + +static void mg_der_debug_cert_name(const char *name, struct mg_der_tlv *tlv) { + struct mg_der_tlv v; + struct mg_str cn, c, o, ou; + cn = c = o = ou = mg_str(""); + if (mg_der_find_oid(tlv, (uint8_t *) "\x55\x04\x03", 3, &v)) + cn = mg_str_n((const char *) v.value, v.len); + if (mg_der_find_oid(tlv, (uint8_t *) "\x55\x04\x06", 3, &v)) + c = mg_str_n((const char *) v.value, v.len); + if (mg_der_find_oid(tlv, (uint8_t *) "\x55\x04\x0a", 3, &v)) + o = mg_str_n((const char *) v.value, v.len); + if (mg_der_find_oid(tlv, (uint8_t *) "\x55\x04\x0b", 3, &v)) + ou = mg_str_n((const char *) v.value, v.len); + MG_VERBOSE(("%s: CN=%.*s, C=%.*s, O=%.*s, OU=%.*s", name, cn.len, cn.buf, + c.len, c.buf, o.len, o.buf, ou.len, ou.buf)); +} + +static int mg_tls_parse_cert_der(void *buf, size_t dersz, + struct mg_tls_cert *cert) { + uint8_t *tbs, *der = (uint8_t *) buf; + size_t tbssz; + struct mg_der_tlv root, tbs_cert, field, algo; // pubkey, signature; + struct mg_der_tlv pki, pki_algo, pki_key, pki_curve, raw_sig; + + // Parse outermost SEQUENCE + if (mg_der_parse(der, dersz, &root) <= 0 || root.type != 0x30) return -1; + + // Parse TBSCertificate SEQUENCE + tbs = root.value; + if (mg_der_next(&root, &tbs_cert) <= 0 || tbs_cert.type != 0x30) return -1; + tbssz = (size_t) (tbs_cert.value + tbs_cert.len - tbs); + + // Parse Version (optional field) + if (mg_der_next(&tbs_cert, &field) <= 0) return -1; + if (field.type == 0xa0) { // v3 + if (mg_der_parse(field.value, field.len, &field) <= 0 || field.len != 1 || + field.value[0] != 2) + return -1; + if (mg_der_next(&tbs_cert, &field) <= 0) return -1; + } + + // Parse Serial Number + if (field.type != 2) return -1; + cert->sn = mg_str_n((char *) field.value, field.len); + MG_VERBOSE(("cert s/n: %M", mg_print_hex, cert->sn.len, cert->sn.buf)); + + // Parse signature algorithm (first occurrence) + if (mg_der_next(&tbs_cert, &field) <= 0 || field.type != 0x30) return -1; + if (mg_der_next(&field, &algo) <= 0 || algo.type != 0x06) return -1; + + MG_VERBOSE(("sig algo (oid): %M", mg_print_hex, algo.len, algo.value)); + // Signature algorithm OID mapping + if (memcmp(algo.value, "\x2A\x86\x48\xCE\x3D\x04\x03\x02", algo.len) == 0) { + MG_VERBOSE(("sig algo: ECDSA with SHA256")); + mg_sha256(cert->tbshash, tbs, tbssz); + cert->tbshashsz = 32; + } else if (memcmp(algo.value, "\x2A\x86\x48\x86\xF7\x0D\x01\x01\x0B", + algo.len) == 0) { + MG_VERBOSE(("sig algo: RSA with SHA256")); + mg_sha256(cert->tbshash, tbs, tbssz); + cert->tbshashsz = 32; + } else if (memcmp(algo.value, "\x2A\x86\x48\xCE\x3D\x04\x03\x03", algo.len) == + 0) { + MG_VERBOSE(("sig algo: ECDSA with SHA384")); + mg_sha384(cert->tbshash, tbs, tbssz); + cert->tbshashsz = 48; + } else if (memcmp(algo.value, "\x2A\x86\x48\x86\xF7\x0D\x01\x01\x0C", + algo.len) == 0) { + MG_VERBOSE(("sig algo: RSA with SHA384")); + mg_sha384(cert->tbshash, tbs, tbssz); + cert->tbshashsz = 48; + } else { + MG_ERROR( + ("sig algo: unsupported OID: %M", mg_print_hex, algo.len, algo.value)); + return -1; + } + MG_VERBOSE(("tbs hash: %M", mg_print_hex, cert->tbshashsz, cert->tbshash)); + + // issuer + if (mg_der_next(&tbs_cert, &field) <= 0 || field.type != 0x30) return -1; + mg_der_debug_cert_name("issuer", &field); + + // validity dates (before/after) + if (mg_der_next(&tbs_cert, &field) <= 0 || field.type != 0x30) return -1; + if (1) { + struct mg_der_tlv before, after; + mg_der_next(&field, &before); + mg_der_next(&field, &after); + if (memcmp(after.value, "250101000000Z", after.len) < 0) { + MG_ERROR(("invalid validity dates: before=%M after=%M", mg_print_hex, + before.len, before.value, mg_print_hex, after.len, + after.value)); + return -1; + } + } + + // subject + if (mg_der_next(&tbs_cert, &field) <= 0 || field.type != 0x30) return -1; + mg_der_debug_cert_name("subject", &field); + + // subject public key info + if (mg_der_next(&tbs_cert, &field) <= 0 || field.type != 0x30) return -1; + + if (mg_der_next(&field, &pki) <= 0 || pki.type != 0x30) return -1; + if (mg_der_next(&pki, &pki_algo) <= 0 || pki_algo.type != 0x06) return -1; + + // public key algorithm + MG_VERBOSE(("pk algo (oid): %M", mg_print_hex, pki_algo.len, pki_algo.value)); + if (memcmp(pki_algo.value, "\x2A\x86\x48\xCE\x3D\x03\x01\x07", + pki_algo.len) == 0) { + cert->is_ec_pubkey = 1; + MG_VERBOSE(("pk algo: ECDSA secp256r1")); + } else if (memcmp(pki_algo.value, "\x2A\x86\x48\xCE\x3D\x03\x01\x08", + pki_algo.len) == 0) { + cert->is_ec_pubkey = 1; + MG_VERBOSE(("pk algo: ECDSA secp384r1")); + } else if (memcmp(pki_algo.value, "\x2A\x86\x48\xCE\x3D\x02\x01", + pki_algo.len) == 0) { + cert->is_ec_pubkey = 1; + MG_VERBOSE(("pk algo: EC public key")); + } else if (memcmp(pki_algo.value, "\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01", + pki_algo.len) == 0) { + cert->is_ec_pubkey = 0; + MG_VERBOSE(("pk algo: RSA")); + } else { + MG_ERROR(("unsupported pk algo: %M", mg_print_hex, pki_algo.len, + pki_algo.value)); + return -1; + } + + // Parse public key + if (cert->is_ec_pubkey) { + if (mg_der_next(&pki, &pki_curve) <= 0 || pki_curve.type != 0x06) return -1; + } + if (mg_der_next(&field, &pki_key) <= 0 || pki_key.type != 0x03) return -1; + + if (cert->is_ec_pubkey) { // Skip leading 0x00 and 0x04 (=uncompressed) + cert->pubkey = mg_str_n((char *) pki_key.value + 2, pki_key.len - 2); + } else { // Skip leading 0x00 byte + cert->pubkey = mg_str_n((char *) pki_key.value + 1, pki_key.len - 1); + } + + // Parse signature + if (mg_der_next(&root, &field) <= 0 || field.type != 0x30) return -1; + if (mg_der_next(&root, &raw_sig) <= 0 || raw_sig.type != 0x03) return -1; + if (raw_sig.len < 1 || raw_sig.value[0] != 0x00) return -1; + + cert->sig = mg_str_n((char *) raw_sig.value + 1, raw_sig.len - 1); + MG_VERBOSE(("sig: %M", mg_print_hex, cert->sig.len, cert->sig.buf)); + + return 0; +} + +static int mg_tls_verify_cert_san(const uint8_t *der, size_t dersz, + const char *server_name) { + struct mg_der_tlv root, field, name; + if (mg_der_parse((uint8_t *) der, dersz, &root) < 0 || + mg_der_find_oid(&root, (uint8_t *) "\x55\x1d\x11", 3, &field) < 0) { + MG_ERROR(("failed to parse certificate to extract SAN")); + return -1; + } + if (mg_der_parse(field.value, field.len, &field) < 0) { + MG_ERROR( + ("certificate subject alternative names is not a constructed object")); + return -1; + } + while (mg_der_next(&field, &name) > 0) { + if (mg_match(mg_str(server_name), + mg_str_n((const char *) name.value, name.len), NULL)) { + // Found SAN that matches the host name + return 1; + } + } + return -1; +} + +static int mg_tls_verify_cert_signature(const struct mg_tls_cert *cert, + const struct mg_tls_cert *issuer) { + if (issuer->is_ec_pubkey) { + uint8_t sig[128]; + struct mg_der_tlv seq = {0, 0, 0}, a = {0, 0, 0}, b = {0, 0, 0}; + mg_der_parse((uint8_t *) cert->sig.buf, cert->sig.len, &seq); + mg_der_next(&seq, &a); + mg_der_next(&seq, &b); + if (a.len == 0 || b.len == 0) { + MG_ERROR(("cert verification error")); + return 0; + } + if (issuer->pubkey.len == 64) { + const uint32_t N = 32; + if (a.len > N) a.value += (a.len - N), a.len = N; + if (b.len > N) b.value += (b.len - N), b.len = N; + memmove(sig, a.value, N); + memmove(sig + N, b.value, N); + return mg_uecc_verify((uint8_t *) issuer->pubkey.buf, cert->tbshash, + (unsigned) cert->tbshashsz, sig, + mg_uecc_secp256r1()); + } else if (issuer->pubkey.len == 96) { + MG_DEBUG(("ignore secp386 for now")); + return 1; + } else { + MG_ERROR(("unsupported public key length: %d", issuer->pubkey.len)); + return 0; + } + } else { + int r; + uint8_t sig2[256]; // 2048 bits + struct mg_der_tlv seq, modulus, exponent; + if (mg_der_parse((uint8_t *) issuer->pubkey.buf, issuer->pubkey.len, + &seq) <= 0 || + mg_der_next(&seq, &modulus) <= 0 || modulus.type != 2 || + mg_der_next(&seq, &exponent) <= 0 || exponent.type != 2) { + return -1; + } + mg_rsa_mod_pow(modulus.value, modulus.len, exponent.value, exponent.len, + (uint8_t *) cert->sig.buf, cert->sig.len, sig2, + sizeof(sig2)); + + r = memcmp(sig2 + sizeof(sig2) - cert->tbshashsz, cert->tbshash, + cert->tbshashsz); + return r == 0; + } +} + static int mg_tls_client_recv_cert(struct mg_connection *c) { - uint8_t *cert; - uint32_t certsz; - struct mg_der_tlv oid, pubkey, seq, subj; int subj_match = 0; struct tls_data *tls = (struct tls_data *) c->tls; unsigned char *recv_buf; + (void) subj_match; + if (mg_tls_recv_record(c) < 0) { return -1; } + recv_buf = &c->rtls.buf[tls->recv_offset]; + if (recv_buf[0] == MG_TLS_CERTIFICATE_REQUEST) { MG_VERBOSE(("got certificate request")); mg_tls_drop_message(c); tls->cert_requested = 1; return -1; } + if (recv_buf[0] != MG_TLS_CERTIFICATE) { mg_error(c, "expected server certificate but got msg 0x%02x", recv_buf[0]); return -1; } - if (tls->skip_verification) { - mg_tls_drop_message(c); - return 0; - } if (tls->recv_len < 11) { mg_error(c, "certificate list too short"); return -1; } - cert = recv_buf + 11; - certsz = MG_LOAD_BE24(recv_buf + 8); - if (certsz > tls->recv_len - 11) { - mg_error(c, "certificate too long: %d vs %d", certsz, tls->recv_len - 11); + uint32_t full_cert_chain_len = MG_LOAD_BE24(recv_buf + 1); + uint32_t cert_chain_len = MG_LOAD_BE24(recv_buf + 5); + if (cert_chain_len != full_cert_chain_len - 4) { + MG_ERROR(("full chain length: %d, chain length: %d", full_cert_chain_len, + cert_chain_len)); + mg_error(c, "certificate chain length mismatch"); return -1; } - do { - // secp256r1 public key - if (mg_der_find(cert, certsz, - (uint8_t *) "\x2A\x86\x48\xCE\x3D\x03\x01\x07", 8, - &oid) < 0) { - mg_error(c, "certificate secp256r1 public key OID not found"); + // Normally, there are 2-3 certs in a chain + struct mg_tls_cert certs[8]; + int certnum = 0; + uint8_t *p = recv_buf + 8; + //uint8_t *endp = recv_buf + tls->recv_len; + uint8_t *endp = recv_buf + cert_chain_len; + + int found_ca = 0; + struct mg_tls_cert ca; + + memset(certs, 0, sizeof(certs)); + memset(&ca, 0, sizeof(ca)); + + if (tls->ca_der.len > 0) { + if (mg_tls_parse_cert_der(tls->ca_der.buf, tls->ca_der.len, &ca) < 0) { + mg_error(c, "failed to parse CA certificate"); return -1; } - if (mg_der_to_tlv(oid.value + oid.len, - (size_t) (cert + certsz - (oid.value + oid.len)), - &pubkey) < 0) { - mg_error(c, "certificate secp256r1 public key not found"); + MG_VERBOSE(("CA serial: %M", mg_print_hex, ca.sn.len, ca.sn.buf)); + } + + while (p < endp) { + struct mg_tls_cert *ci = &certs[certnum++]; + uint32_t certsz = MG_LOAD_BE24(p); + uint8_t *cert = p + 3; + uint16_t certext = MG_LOAD_BE16(cert + certsz); + if (certext != 0) { + mg_error(c, "certificate extensions are not supported"); + return -1; + } + p = cert + certsz + 2; + + if (mg_tls_parse_cert_der(cert, certsz, ci) < 0) { + mg_error(c, "failed to parse certificate"); return -1; } - // expect BIT STRING, unpadded, uncompressed: [0]+[4]+32+32 content bytes - if (pubkey.type != 3 || pubkey.len != 66 || pubkey.value[0] != 0 || - pubkey.value[1] != 4) { - mg_error(c, "unsupported public key bitstring encoding"); - return -1; - } - memmove(tls->pubkey, pubkey.value + 2, pubkey.len - 2); - } while (0); - - // Subject Alternative Names - do { - if (mg_der_find(cert, certsz, (uint8_t *) "\x55\x1d\x11", 3, &oid) < 0) { - mg_error(c, "certificate does not contain subject alternative names"); - return -1; - } - if (mg_der_to_tlv(oid.value + oid.len, - (size_t) (cert + certsz - (oid.value + oid.len)), - &seq) < 0) { - mg_error(c, "certificate subject alternative names not found"); - return -1; - } - if (mg_der_to_tlv(seq.value, seq.len, &seq) < 0) { - mg_error( - c, - "certificate subject alternative names is not a constructed object"); - return -1; - } - MG_VERBOSE(("verify hostname %s", tls->hostname)); - while (seq.len > 0) { - if (mg_der_to_tlv(seq.value, seq.len, &subj) < 0) { - mg_error(c, "bad subject alternative name"); + if (ci == certs) { + // First certificate in the chain is peer cert, check SAN and store + // public key for further CertVerify step + if (mg_tls_verify_cert_san(cert, certsz, tls->hostname) <= 0) { + mg_error(c, "failed to verify hostname"); return -1; } - MG_VERBOSE(("subj=%.*s", subj.len, subj.value)); - if (mg_match(mg_str((const char *) tls->hostname), - mg_str_n((const char *) subj.value, subj.len), NULL)) { - subj_match = 1; - break; + memmove(tls->pubkey, ci->pubkey.buf, ci->pubkey.len); + tls->pubkeysz = ci->pubkey.len; + } else { + if (!mg_tls_verify_cert_signature(ci - 1, ci)) { + mg_error(c, "failed to verify certificate chain"); + return -1; } - seq.len = (uint32_t) (seq.value + seq.len - (subj.value + subj.len)); - seq.value = subj.value + subj.len; } - if (!subj_match) { - mg_error(c, "certificate did not match the hostname"); + + if (ca.pubkey.len == ci->pubkey.len && + memcmp(ca.pubkey.buf, ci->pubkey.buf, ca.pubkey.len) == 0) { + found_ca = 1; + break; + } + + if (certnum == sizeof(certs) / sizeof(certs[0]) - 1) { + mg_error(c, "too many certificates in the chain"); return -1; } - } while (0); + } + + if (!found_ca && tls->ca_der.len > 0) { + if (certnum < 1 || + !mg_tls_verify_cert_signature(&certs[certnum - 1], &ca)) { + mg_error(c, "failed to verify CA"); + return -1; + } else { + MG_VERBOSE( + ("CA was not in the chain, but verification with builtin CA passed")); + } + } mg_tls_drop_message(c); mg_tls_calc_cert_verify_hash(c, tls->sighash, 0); @@ -11020,51 +11476,94 @@ static int mg_tls_client_recv_cert_verify(struct mg_connection *c) { } recv_buf = &c->rtls.buf[tls->recv_offset]; if (recv_buf[0] != MG_TLS_CERTIFICATE_VERIFY) { - mg_error(c, "expected server certificate verify but got msg 0x%02x", recv_buf[0]); + mg_error(c, "expected server certificate verify but got msg 0x%02x", + recv_buf[0]); return -1; } + if (tls->recv_len < 8) { + mg_error(c, "server certificate verify is too short: %d bytes", + tls->recv_len); + return -1; + } + // Ignore CertificateVerify is strict checks are not required if (tls->skip_verification) { mg_tls_drop_message(c); return 0; } - // Extract certificate signature and verify it using pubkey and sighash - do { + uint16_t sigalg = MG_LOAD_BE16(recv_buf + 4); + uint16_t siglen = MG_LOAD_BE16(recv_buf + 6); + uint8_t *sigbuf = recv_buf + 8; + if (siglen > tls->recv_len - 8) { + mg_error(c, "invalid certverify signature length: %d, expected %d", siglen, + tls->recv_len - 8); + return -1; + } + MG_VERBOSE(("certificate verification, algo=%04x, siglen=%d", sigalg, siglen)); + + if (sigalg == 0x0804) { // rsa_pss_rsae_sha256 + uint8_t sig2[512]; // 2048 or 4096 bits + struct mg_der_tlv seq, modulus, exponent; + + if (mg_der_parse(tls->pubkey, tls->pubkeysz, &seq) <= 0 || + mg_der_next(&seq, &modulus) <= 0 || modulus.type != 2 || + mg_der_next(&seq, &exponent) <= 0 || exponent.type != 2) { + mg_error(c, "invalid public key"); + return -1; + } + + mg_rsa_mod_pow(modulus.value, modulus.len, exponent.value, exponent.len, + sigbuf, siglen, sig2, sizeof(sig2)); + + if (sig2[sizeof(sig2) - 1] != 0xbc) { + mg_error(c, "failed to verify RSA certificate (certverify)"); + return -1; + } + MG_DEBUG(("certificate verification successful (RSA)")); + } else if (sigalg == 0x0403) { // ecdsa_secp256r1_sha256 + // Extract certificate signature and verify it using pubkey and sighash uint8_t sig[64]; - struct mg_der_tlv seq, a, b; - if (mg_der_to_tlv(recv_buf + 8, tls->recv_len - 8, &seq) < 0) { + struct mg_der_tlv seq, r, s; + if (mg_der_to_tlv(sigbuf, siglen, &seq) < 0) { mg_error(c, "verification message is not an ASN.1 DER sequence"); return -1; } - if (mg_der_to_tlv(seq.value, seq.len, &a) < 0) { + if (mg_der_to_tlv(seq.value, seq.len, &r) < 0) { mg_error(c, "missing first part of the signature"); return -1; } - if (mg_der_to_tlv(a.value + a.len, seq.len - a.len, &b) < 0) { + if (mg_der_to_tlv(r.value + r.len, seq.len - r.len, &s) < 0) { mg_error(c, "missing second part of the signature"); return -1; } // Integers may be padded with zeroes - if (a.len > 32) { - a.value = a.value + (a.len - 32); - a.len = 32; - } - if (b.len > 32) { - b.value = b.value + (b.len - 32); - b.len = 32; - } + if (r.len > 32) r.value = r.value + (r.len - 32), r.len = 32; + if (s.len > 32) s.value = s.value + (s.len - 32), s.len = 32; - memmove(sig, a.value, a.len); - memmove(sig + 32, b.value, b.len); + memmove(sig, r.value, r.len); + memmove(sig + 32, s.value, s.len); if (mg_uecc_verify(tls->pubkey, tls->sighash, sizeof(tls->sighash), sig, mg_uecc_secp256r1()) != 1) { - mg_error(c, "failed to verify certificate"); + mg_error(c, "failed to verify EC certificate (certverify)"); return -1; } - } while (0); - + MG_DEBUG(("certificate verification successful (EC)")); + } else { + // From + // https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml: + // 0805 = rsa_pss_rsae_sha384 + // 0806 = rsa_pss_rsae_sha512 + // 0807 = ed25519 + // 0808 = ed448 + // 0809 = rsa_pss_pss_sha256 + // 080A = rsa_pss_pss_sha384 + // 080B = rsa_pss_pss_sha512 + MG_ERROR(("unsupported certverify signature scheme: %x of %d bytes", sigalg, + siglen)); + return -1; + } mg_tls_drop_message(c); return 0; } @@ -11154,9 +11653,7 @@ static void mg_tls_client_handshake(struct mg_connection *c) { c->is_tls_hs = 0; mg_call(c, MG_EV_TLS_HS, NULL); break; - default: - mg_error(c, "unexpected client state: %d", tls->state); - break; + default: mg_error(c, "unexpected client state: %d", tls->state); break; } } @@ -11183,9 +11680,7 @@ static void mg_tls_server_handshake(struct mg_connection *c) { tls->state = MG_TLS_STATE_SERVER_CONNECTED; c->is_tls_hs = 0; return; - default: - mg_error(c, "unexpected server state: %d", tls->state); - break; + default: mg_error(c, "unexpected server state: %d", tls->state); break; } } @@ -11242,7 +11737,7 @@ void mg_tls_init(struct mg_connection *c, const struct mg_tls_opts *opts) { c->is_client ? MG_TLS_STATE_CLIENT_START : MG_TLS_STATE_SERVER_START; tls->skip_verification = opts->skip_verification; - //tls->send.align = MG_IO_SIZE; + // tls->send.align = MG_IO_SIZE; c->tls = tls; c->is_tls = c->is_tls_hs = 1; @@ -11257,9 +11752,16 @@ void mg_tls_init(struct mg_connection *c, const struct mg_tls_opts *opts) { strncpy((char *) tls->hostname, opts->name.buf, sizeof(tls->hostname) - 1); tls->hostname[opts->name.len] = 0; } + // server CA certificate, store serial number + if (opts->ca.len > 0) { + if (mg_parse_pem(opts->ca, mg_str_s("CERTIFICATE"), &tls->ca_der) < 0) { + MG_ERROR(("Failed to load certificate")); + return; + } + } if (opts->cert.buf == NULL) { - MG_VERBOSE(("no certificate provided")); + MG_VERBOSE(("No certificate provided")); return; } @@ -11271,7 +11773,7 @@ void mg_tls_init(struct mg_connection *c, const struct mg_tls_opts *opts) { // parse PEM or DER EC key if (opts->key.buf == NULL) { - mg_error(c, "certificate provided without a private key"); + mg_error(c, "Certificate provided without a private key"); return; } @@ -11294,7 +11796,7 @@ void mg_tls_init(struct mg_connection *c, const struct mg_tls_opts *opts) { } else if (mg_parse_pem(opts->key, mg_str_s("PRIVATE KEY"), &key) == 0) { mg_error(c, "PKCS8 private key format is not supported"); } else { - mg_error(c, "expected EC PRIVATE KEY or PRIVATE KEY"); + mg_error(c, "Expected EC PRIVATE KEY or PRIVATE KEY"); } } @@ -11303,6 +11805,7 @@ void mg_tls_free(struct mg_connection *c) { if (tls != NULL) { mg_iobuf_free(&tls->send); free((void *) tls->cert_der.buf); + free((void *) tls->ca_der.buf); } free(c->tls); c->tls = NULL; @@ -11472,10 +11975,12 @@ static void initialize_state(uint32_t state[CHACHA20_STATE_WORDS], const uint8_t key[CHACHA20_KEY_SIZE], const uint8_t nonce[CHACHA20_NONCE_SIZE], uint32_t counter) { +#if 0 #ifdef static_assert static_assert(sizeof(uint32_t) == 4, "We don't support systems that do not conform to standard of " "uint32_t being exact 32bit wide"); +#endif #endif state[0] = 0x61707865; state[1] = 0x3320646e; @@ -13257,6 +13762,1589 @@ void mg_tls_ctx_free(struct mg_mgr *mgr) { } #endif +#ifdef MG_ENABLE_LINES +#line 1 "src/tls_rsa.c" +#endif + + +#if defined(MG_TLS) && MG_TLS == MG_TLS_BUILTIN + +#define NS_INTERNAL static +typedef struct _bigint bigint; /**< An alias for _bigint */ + +/* + * Copyright (c) 2007, Cameron Rich + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the axTLS project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* Maintain a number of precomputed variables when doing reduction */ +#define BIGINT_M_OFFSET 0 /**< Normal modulo offset. */ +#define BIGINT_P_OFFSET 1 /**< p modulo offset. */ +#define BIGINT_Q_OFFSET 2 /**< q module offset. */ +#define BIGINT_NUM_MODS 3 /**< The number of modulus constants used. */ + +/* Architecture specific functions for big ints */ +#if defined(CONFIG_INTEGER_8BIT) +#define COMP_RADIX 256U /**< Max component + 1 */ +#define COMP_MAX 0xFFFFU /**< (Max dbl comp -1) */ +#define COMP_BIT_SIZE 8 /**< Number of bits in a component. */ +#define COMP_BYTE_SIZE 1 /**< Number of bytes in a component. */ +#define COMP_NUM_NIBBLES 2 /**< Used For diagnostics only. */ +typedef uint8_t comp; /**< A single precision component. */ +typedef uint16_t long_comp; /**< A double precision component. */ +typedef int16_t slong_comp; /**< A signed double precision component. */ +#elif defined(CONFIG_INTEGER_16BIT) +#define COMP_RADIX 65536U /**< Max component + 1 */ +#define COMP_MAX 0xFFFFFFFFU /**< (Max dbl comp -1) */ +#define COMP_BIT_SIZE 16 /**< Number of bits in a component. */ +#define COMP_BYTE_SIZE 2 /**< Number of bytes in a component. */ +#define COMP_NUM_NIBBLES 4 /**< Used For diagnostics only. */ +typedef uint16_t comp; /**< A single precision component. */ +typedef uint32_t long_comp; /**< A double precision component. */ +typedef int32_t slong_comp; /**< A signed double precision component. */ +#else /* regular 32 bit */ +#ifdef WIN32 +#define COMP_RADIX 4294967296i64 +#define COMP_MAX 0xFFFFFFFFFFFFFFFFui64 +#else +#define COMP_RADIX 4294967296 /**< Max component + 1 */ +#define COMP_MAX 0xFFFFFFFFFFFFFFFF /**< (Max dbl comp -1) */ +#endif +#define COMP_BIT_SIZE 32 /**< Number of bits in a component. */ +#define COMP_BYTE_SIZE 4 /**< Number of bytes in a component. */ +#define COMP_NUM_NIBBLES 8 /**< Used For diagnostics only. */ +typedef uint32_t comp; /**< A single precision component. */ +typedef uint64_t long_comp; /**< A double precision component. */ +typedef int64_t slong_comp; /**< A signed double precision component. */ +#endif + +/** + * @struct _bigint + * @brief A big integer basic object + */ +struct _bigint { + struct _bigint *next; /**< The next bigint in the cache. */ + short size; /**< The number of components in this bigint. */ + short max_comps; /**< The heapsize allocated for this bigint */ + int refs; /**< An internal reference count. */ + comp *comps; /**< A ptr to the actual component data */ +}; + +/** + * Maintains the state of the cache, and a number of variables used in + * reduction. + */ +struct _BI_CTX /**< A big integer "session" context. */ + { + bigint *active_list; /**< Bigints currently used. */ + bigint *free_list; /**< Bigints not used. */ + bigint *bi_radix; /**< The radix used. */ + bigint *bi_mod[BIGINT_NUM_MODS]; /**< modulus */ + +#if defined(CONFIG_BIGINT_MONTGOMERY) + bigint *bi_RR_mod_m[BIGINT_NUM_MODS]; /**< R^2 mod m */ + bigint *bi_R_mod_m[BIGINT_NUM_MODS]; /**< R mod m */ + comp N0_dash[BIGINT_NUM_MODS]; +#elif defined(CONFIG_BIGINT_BARRETT) + bigint *bi_mu[BIGINT_NUM_MODS]; /**< Storage for mu */ +#endif + bigint *bi_normalised_mod[BIGINT_NUM_MODS]; /**< Normalised mod storage. */ + bigint **g; /**< Used by sliding-window. */ + int window; /**< The size of the sliding window */ + int active_count; /**< Number of active bigints. */ + int free_count; /**< Number of free bigints. */ + +#ifdef CONFIG_BIGINT_MONTGOMERY + uint8_t use_classical; /**< Use classical reduction. */ +#endif + uint8_t mod_offset; /**< The mod offset we are using */ +}; +typedef struct _BI_CTX BI_CTX; + +#if !defined(MAX) +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#endif + +#define PERMANENT 0x7FFF55AA /**< A magic number for permanents. */ + +/* + * Copyright (c) 2007, Cameron Rich + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the axTLS project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +NS_INTERNAL BI_CTX *bi_initialize(void); +//NS_INTERNAL void bi_terminate(BI_CTX *ctx); +NS_INTERNAL void bi_permanent(bigint *bi); +NS_INTERNAL void bi_depermanent(bigint *bi); +//NS_INTERNAL void bi_clear_cache(BI_CTX *ctx); +NS_INTERNAL void bi_free(BI_CTX *ctx, bigint *bi); +NS_INTERNAL bigint *bi_copy(bigint *bi); +NS_INTERNAL bigint *bi_clone(BI_CTX *ctx, const bigint *bi); +NS_INTERNAL void bi_export(BI_CTX *ctx, bigint *bi, uint8_t *data, int size); +NS_INTERNAL bigint *bi_import(BI_CTX *ctx, const uint8_t *data, int len); +NS_INTERNAL bigint *int_to_bi(BI_CTX *ctx, comp i); + +/* the functions that actually do something interesting */ +NS_INTERNAL bigint *bi_add(BI_CTX *ctx, bigint *bia, bigint *bib); +NS_INTERNAL bigint *bi_subtract(BI_CTX *ctx, bigint *bia, bigint *bib, + int *is_negative); +NS_INTERNAL bigint *bi_divide(BI_CTX *ctx, bigint *bia, bigint *bim, + int is_mod); +NS_INTERNAL bigint *bi_multiply(BI_CTX *ctx, bigint *bia, bigint *bib); +NS_INTERNAL bigint *bi_mod_power(BI_CTX *ctx, bigint *bi, bigint *biexp); +#if 0 +NS_INTERNAL bigint *bi_mod_power2(BI_CTX *ctx, bigint *bi, + bigint *bim, bigint *biexp); +#endif +NS_INTERNAL int bi_compare(bigint *bia, bigint *bib); +NS_INTERNAL void bi_set_mod(BI_CTX *ctx, bigint *bim, int mod_offset); +//NS_INTERNAL void bi_free_mod(BI_CTX *ctx, int mod_offset); + +#ifdef CONFIG_SSL_FULL_MODE +NS_INTERNAL void bi_print(const char *label, bigint *bi); +NS_INTERNAL bigint *bi_str_import(BI_CTX *ctx, const char *data); +#endif + +/** + * @def bi_mod + * Find the residue of B. bi_set_mod() must be called before hand. + */ +#define bi_mod(A, B) bi_divide(A, B, ctx->bi_mod[ctx->mod_offset], 1) + +/** + * bi_residue() is technically the same as bi_mod(), but it uses the + * appropriate reduction technique (which is bi_mod() when doing classical + * reduction). + */ +#if defined(CONFIG_BIGINT_MONTGOMERY) +#define bi_residue(A, B) bi_mont(A, B) +NS_INTERNAL bigint *bi_mont(BI_CTX *ctx, bigint *bixy); +#elif defined(CONFIG_BIGINT_BARRETT) +#define bi_residue(A, B) bi_barrett(A, B) +NS_INTERNAL bigint *bi_barrett(BI_CTX *ctx, bigint *bi); +#else /* if defined(CONFIG_BIGINT_CLASSICAL) */ +#define bi_residue(A, B) bi_mod(A, B) +#endif + +#ifdef CONFIG_BIGINT_SQUARE +NS_INTERNAL bigint *bi_square(BI_CTX *ctx, bigint *bi); +#else +#define bi_square(A, B) bi_multiply(A, bi_copy(B), B) +#endif + +//NS_INTERNAL bigint *bi_crt(BI_CTX *ctx, bigint *bi, bigint *dP, bigint *dQ, +// bigint *p, bigint *q, bigint *qInv); + +/* + * Copyright (c) 2007, Cameron Rich + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the axTLS project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @defgroup bigint_api Big Integer API + * @brief The bigint implementation as used by the axTLS project. + * + * The bigint library is for RSA encryption/decryption as well as signing. + * This code tries to minimise use of malloc/free by maintaining a small + * cache. A bigint context may maintain state by being made "permanent". + * It be be later released with a bi_depermanent() and bi_free() call. + * + * It supports the following reduction techniques: + * - Classical + * - Barrett + * - Montgomery + * + * It also implements the following: + * - Karatsuba multiplication + * - Squaring + * - Sliding window exponentiation + * - Chinese Remainder Theorem (implemented in rsa.c). + * + * All the algorithms used are pretty standard, and designed for different + * data bus sizes. Negative numbers are not dealt with at all, so a subtraction + * may need to be tested for negativity. + * + * This library steals some ideas from Jef Poskanzer + * + * and GMP . It gets most of its implementation + * detail from "The Handbook of Applied Cryptography" + * + * @{ + */ + +#define V1 v->comps[v->size - 1] /**< v1 for division */ +#define V2 v->comps[v->size - 2] /**< v2 for division */ +#define U(j) tmp_u->comps[tmp_u->size - j - 1] /**< uj for division */ +#define Q(j) quotient->comps[quotient->size - j - 1] /**< qj for division */ + +static bigint *bi_int_multiply(BI_CTX *ctx, bigint *bi, comp i); +static bigint *bi_int_divide(BI_CTX *ctx, bigint *biR, comp denom); +static bigint *alloc(BI_CTX *ctx, int size); +static bigint *trim(bigint *bi); +static void more_comps(bigint *bi, int n); +#if defined(CONFIG_BIGINT_KARATSUBA) || defined(CONFIG_BIGINT_BARRETT) || \ + defined(CONFIG_BIGINT_MONTGOMERY) +static bigint *comp_right_shift(bigint *biR, int num_shifts); +static bigint *comp_left_shift(bigint *biR, int num_shifts); +#endif + +#ifdef CONFIG_BIGINT_CHECK_ON +static void check(const bigint *bi); +#else +#define check(A) /**< disappears in normal production mode */ +#endif + +/** + * @brief Start a new bigint context. + * @return A bigint context. + */ +NS_INTERNAL BI_CTX *bi_initialize(void) { + /* calloc() sets everything to zero */ + BI_CTX *ctx = (BI_CTX *) calloc(1, sizeof(BI_CTX)); + + /* the radix */ + ctx->bi_radix = alloc(ctx, 2); + ctx->bi_radix->comps[0] = 0; + ctx->bi_radix->comps[1] = 1; + bi_permanent(ctx->bi_radix); + return ctx; +} + +#if 0 +/** + * @brief Close the bigint context and free any resources. + * + * Free up any used memory - a check is done if all objects were not + * properly freed. + * @param ctx [in] The bigint session context. + */ +NS_INTERNAL void bi_terminate(BI_CTX *ctx) { + bi_depermanent(ctx->bi_radix); + bi_free(ctx, ctx->bi_radix); + + if (ctx->active_count != 0) { +#ifdef CONFIG_SSL_FULL_MODE + printf("bi_terminate: there were %d un-freed bigints\n", ctx->active_count); +#endif + abort(); + } + + bi_clear_cache(ctx); + free(ctx); +} + +/** + *@brief Clear the memory cache. + */ +NS_INTERNAL void bi_clear_cache(BI_CTX *ctx) { + bigint *p, *pn; + + if (ctx->free_list == NULL) return; + + for (p = ctx->free_list; p != NULL; p = pn) { + pn = p->next; + free(p->comps); + free(p); + } + + ctx->free_count = 0; + ctx->free_list = NULL; +} +#endif + +/** + * @brief Increment the number of references to this object. + * It does not do a full copy. + * @param bi [in] The bigint to copy. + * @return A reference to the same bigint. + */ +NS_INTERNAL bigint *bi_copy(bigint *bi) { + check(bi); + if (bi->refs != PERMANENT) bi->refs++; + return bi; +} + +/** + * @brief Simply make a bigint object "unfreeable" if bi_free() is called on it. + * + * For this object to be freed, bi_depermanent() must be called. + * @param bi [in] The bigint to be made permanent. + */ +NS_INTERNAL void bi_permanent(bigint *bi) { + check(bi); + if (bi->refs != 1) { +#ifdef CONFIG_SSL_FULL_MODE + printf("bi_permanent: refs was not 1\n"); +#endif + abort(); + } + + bi->refs = PERMANENT; +} + +/** + * @brief Take a permanent object and make it eligible for freedom. + * @param bi [in] The bigint to be made back to temporary. + */ +NS_INTERNAL void bi_depermanent(bigint *bi) { + check(bi); + if (bi->refs != PERMANENT) { +#ifdef CONFIG_SSL_FULL_MODE + printf("bi_depermanent: bigint was not permanent\n"); +#endif + abort(); + } + + bi->refs = 1; +} + +/** + * @brief Free a bigint object so it can be used again. + * + * The memory itself it not actually freed, just tagged as being available + * @param ctx [in] The bigint session context. + * @param bi [in] The bigint to be freed. + */ +NS_INTERNAL void bi_free(BI_CTX *ctx, bigint *bi) { + check(bi); + if (bi->refs == PERMANENT) { + return; + } + + if (--bi->refs > 0) { + return; + } + + bi->next = ctx->free_list; + ctx->free_list = bi; + ctx->free_count++; + + if (--ctx->active_count < 0) { +#ifdef CONFIG_SSL_FULL_MODE + printf( + "bi_free: active_count went negative " + "- double-freed bigint?\n"); +#endif + abort(); + } +} + +/** + * @brief Convert an (unsigned) integer into a bigint. + * @param ctx [in] The bigint session context. + * @param i [in] The (unsigned) integer to be converted. + * + */ +NS_INTERNAL bigint *int_to_bi(BI_CTX *ctx, comp i) { + bigint *biR = alloc(ctx, 1); + biR->comps[0] = i; + return biR; +} + +/** + * @brief Do a full copy of the bigint object. + * @param ctx [in] The bigint session context. + * @param bi [in] The bigint object to be copied. + */ +NS_INTERNAL bigint *bi_clone(BI_CTX *ctx, const bigint *bi) { + bigint *biR = alloc(ctx, bi->size); + check(bi); + memcpy(biR->comps, bi->comps, (size_t) bi->size * COMP_BYTE_SIZE); + return biR; +} + +/** + * @brief Perform an addition operation between two bigints. + * @param ctx [in] The bigint session context. + * @param bia [in] A bigint. + * @param bib [in] Another bigint. + * @return The result of the addition. + */ +NS_INTERNAL bigint *bi_add(BI_CTX *ctx, bigint *bia, bigint *bib) { + int n; + comp carry = 0; + comp *pa, *pb; + + check(bia); + check(bib); + + n = MAX(bia->size, bib->size); + more_comps(bia, n + 1); + more_comps(bib, n); + pa = bia->comps; + pb = bib->comps; + + do { + comp sl, rl, cy1; + sl = *pa + *pb++; + rl = sl + carry; + cy1 = sl < *pa; + carry = cy1 | (rl < sl); + *pa++ = rl; + } while (--n != 0); + + *pa = carry; /* do overflow */ + bi_free(ctx, bib); + return trim(bia); +} + +/** + * @brief Perform a subtraction operation between two bigints. + * @param ctx [in] The bigint session context. + * @param bia [in] A bigint. + * @param bib [in] Another bigint. + * @param is_negative [out] If defined, indicates that the result was negative. + * is_negative may be null. + * @return The result of the subtraction. The result is always positive. + */ +NS_INTERNAL bigint *bi_subtract(BI_CTX *ctx, bigint *bia, bigint *bib, + int *is_negative) { + int n = bia->size; + comp *pa, *pb, carry = 0; + + check(bia); + check(bib); + + more_comps(bib, n); + pa = bia->comps; + pb = bib->comps; + + do { + comp sl, rl, cy1; + sl = *pa - *pb++; + rl = sl - carry; + cy1 = sl > *pa; + carry = cy1 | (rl > sl); + *pa++ = rl; + } while (--n != 0); + + if (is_negative) /* indicate a negative result */ + { + *is_negative = (int) carry; + } + + bi_free(ctx, trim(bib)); /* put bib back to the way it was */ + return trim(bia); +} + +/** + * Perform a multiply between a bigint an an (unsigned) integer + */ +static bigint *bi_int_multiply(BI_CTX *ctx, bigint *bia, comp b) { + int j = 0, n = bia->size; + bigint *biR = alloc(ctx, n + 1); + comp carry = 0; + comp *r = biR->comps; + comp *a = bia->comps; + + check(bia); + + /* clear things to start with */ + memset(r, 0, (size_t) ((n + 1) * COMP_BYTE_SIZE)); + + do { + long_comp tmp = *r + (long_comp) a[j] * b + carry; + *r++ = (comp) tmp; /* downsize */ + carry = (comp)(tmp >> COMP_BIT_SIZE); + } while (++j < n); + + *r = carry; + bi_free(ctx, bia); + return trim(biR); +} + +/** + * @brief Does both division and modulo calculations. + * + * Used extensively when doing classical reduction. + * @param ctx [in] The bigint session context. + * @param u [in] A bigint which is the numerator. + * @param v [in] Either the denominator or the modulus depending on the mode. + * @param is_mod [n] Determines if this is a normal division (0) or a reduction + * (1). + * @return The result of the division/reduction. + */ +NS_INTERNAL bigint *bi_divide(BI_CTX *ctx, bigint *u, bigint *v, int is_mod) { + int n = v->size, m = u->size - n; + int j = 0, orig_u_size = u->size; + uint8_t mod_offset = ctx->mod_offset; + comp d; + bigint *quotient, *tmp_u; + comp q_dash; + + check(u); + check(v); + + /* if doing reduction and we are < mod, then return mod */ + if (is_mod && bi_compare(v, u) > 0) { + bi_free(ctx, v); + return u; + } + + quotient = alloc(ctx, m + 1); + tmp_u = alloc(ctx, n + 1); + v = trim(v); /* make sure we have no leading 0's */ + d = (comp)((long_comp) COMP_RADIX / (V1 + 1)); + + /* clear things to start with */ + memset(quotient->comps, 0, (size_t) ((quotient->size) * COMP_BYTE_SIZE)); + + /* normalise */ + if (d > 1) { + u = bi_int_multiply(ctx, u, d); + + if (is_mod) { + v = ctx->bi_normalised_mod[mod_offset]; + } else { + v = bi_int_multiply(ctx, v, d); + } + } + + if (orig_u_size == u->size) /* new digit position u0 */ + { + more_comps(u, orig_u_size + 1); + } + + do { + /* get a temporary short version of u */ + memcpy(tmp_u->comps, &u->comps[u->size - n - 1 - j], + (size_t) (n + 1) * COMP_BYTE_SIZE); + + /* calculate q' */ + if (U(0) == V1) { + q_dash = COMP_RADIX - 1; + } else { + q_dash = (comp)(((long_comp) U(0) * COMP_RADIX + U(1)) / V1); + + if (v->size > 1 && V2) { + /* we are implementing the following: + if (V2*q_dash > (((U(0)*COMP_RADIX + U(1) - + q_dash*V1)*COMP_RADIX) + U(2))) ... */ + comp inner = (comp)((long_comp) COMP_RADIX * U(0) + U(1) - + (long_comp) q_dash * V1); + if ((long_comp) V2 * q_dash > (long_comp) inner * COMP_RADIX + U(2)) { + q_dash--; + } + } + } + + /* multiply and subtract */ + if (q_dash) { + int is_negative; + tmp_u = bi_subtract(ctx, tmp_u, bi_int_multiply(ctx, bi_copy(v), q_dash), + &is_negative); + more_comps(tmp_u, n + 1); + + Q(j) = q_dash; + + /* add back */ + if (is_negative) { + Q(j)--; + tmp_u = bi_add(ctx, tmp_u, bi_copy(v)); + + /* lop off the carry */ + tmp_u->size--; + v->size--; + } + } else { + Q(j) = 0; + } + + /* copy back to u */ + memcpy(&u->comps[u->size - n - 1 - j], tmp_u->comps, + (size_t) (n + 1) * COMP_BYTE_SIZE); + } while (++j <= m); + + bi_free(ctx, tmp_u); + bi_free(ctx, v); + + if (is_mod) /* get the remainder */ + { + bi_free(ctx, quotient); + return bi_int_divide(ctx, trim(u), d); + } else /* get the quotient */ + { + bi_free(ctx, u); + return trim(quotient); + } +} + +/* + * Perform an integer divide on a bigint. + */ +static bigint *bi_int_divide(BI_CTX *ctx, bigint *biR, comp denom) { + int i = biR->size - 1; + long_comp r = 0; + + (void) ctx; + check(biR); + + do { + r = (r << COMP_BIT_SIZE) + biR->comps[i]; + biR->comps[i] = (comp)(r / denom); + r %= denom; + } while (--i >= 0); + + return trim(biR); +} + +#ifdef CONFIG_BIGINT_MONTGOMERY +/** + * There is a need for the value of integer N' such that B^-1(B-1)-N^-1N'=1, + * where B^-1(B-1) mod N=1. Actually, only the least significant part of + * N' is needed, hence the definition N0'=N' mod b. We reproduce below the + * simple algorithm from an article by Dusse and Kaliski to efficiently + * find N0' from N0 and b */ +static comp modular_inverse(bigint *bim) { + int i; + comp t = 1; + comp two_2_i_minus_1 = 2; /* 2^(i-1) */ + long_comp two_2_i = 4; /* 2^i */ + comp N = bim->comps[0]; + + for (i = 2; i <= COMP_BIT_SIZE; i++) { + if ((long_comp) N * t % two_2_i >= two_2_i_minus_1) { + t += two_2_i_minus_1; + } + + two_2_i_minus_1 <<= 1; + two_2_i <<= 1; + } + + return (comp)(COMP_RADIX - t); +} +#endif + +#if defined(CONFIG_BIGINT_KARATSUBA) || defined(CONFIG_BIGINT_BARRETT) || \ + defined(CONFIG_BIGINT_MONTGOMERY) +/** + * Take each component and shift down (in terms of components) + */ +static bigint *comp_right_shift(bigint *biR, int num_shifts) { + int i = biR->size - num_shifts; + comp *x = biR->comps; + comp *y = &biR->comps[num_shifts]; + + check(biR); + + if (i <= 0) /* have we completely right shifted? */ + { + biR->comps[0] = 0; /* return 0 */ + biR->size = 1; + return biR; + } + + do { + *x++ = *y++; + } while (--i > 0); + + biR->size -= num_shifts; + return biR; +} + +/** + * Take each component and shift it up (in terms of components) + */ +static bigint *comp_left_shift(bigint *biR, int num_shifts) { + int i = biR->size - 1; + comp *x, *y; + + check(biR); + + if (num_shifts <= 0) { + return biR; + } + + more_comps(biR, biR->size + num_shifts); + + x = &biR->comps[i + num_shifts]; + y = &biR->comps[i]; + + do { + *x-- = *y--; + } while (i--); + + memset(biR->comps, 0, (size_t) (num_shifts * COMP_BYTE_SIZE)); /* zero LS comps */ + return biR; +} +#endif + +/** + * @brief Allow a binary sequence to be imported as a bigint. + * @param ctx [in] The bigint session context. + * @param data [in] The data to be converted. + * @param size [in] The number of bytes of data. + * @return A bigint representing this data. + */ +NS_INTERNAL bigint *bi_import(BI_CTX *ctx, const uint8_t *data, int size) { + bigint *biR = alloc(ctx, (size + COMP_BYTE_SIZE - 1) / COMP_BYTE_SIZE); + int i, j = 0, offset = 0; + + memset(biR->comps, 0, (size_t) (biR->size * COMP_BYTE_SIZE)); + + for (i = size - 1; i >= 0; i--) { + biR->comps[offset] += (comp) data[i] << (j * 8); + + if (++j == COMP_BYTE_SIZE) { + j = 0; + offset++; + } + } + + return trim(biR); +} + +#ifdef CONFIG_SSL_FULL_MODE +/** + * @brief The testharness uses this code to import text hex-streams and + * convert them into bigints. + * @param ctx [in] The bigint session context. + * @param data [in] A string consisting of hex characters. The characters must + * be in upper case. + * @return A bigint representing this data. + */ +NS_INTERNAL bigint *bi_str_import(BI_CTX *ctx, const char *data) { + int size = strlen(data); + bigint *biR = alloc(ctx, (size + COMP_NUM_NIBBLES - 1) / COMP_NUM_NIBBLES); + int i, j = 0, offset = 0; + memset(biR->comps, 0, (size_t) (biR->size * COMP_BYTE_SIZE)); + + for (i = size - 1; i >= 0; i--) { + int num = (data[i] <= '9') ? (data[i] - '0') : (data[i] - 'A' + 10); + biR->comps[offset] += num << (j * 4); + + if (++j == COMP_NUM_NIBBLES) { + j = 0; + offset++; + } + } + + return biR; +} + +NS_INTERNAL void bi_print(const char *label, bigint *x) { + int i, j; + + if (x == NULL) { + printf("%s: (null)\n", label); + return; + } + + printf("%s: (size %d)\n", label, x->size); + for (i = x->size - 1; i >= 0; i--) { + for (j = COMP_NUM_NIBBLES - 1; j >= 0; j--) { + comp mask = 0x0f << (j * 4); + comp num = (x->comps[i] & mask) >> (j * 4); + putc((num <= 9) ? (num + '0') : (num + 'A' - 10), stdout); + } + } + + printf("\n"); +} +#endif + +/** + * @brief Take a bigint and convert it into a byte sequence. + * + * This is useful after a decrypt operation. + * @param ctx [in] The bigint session context. + * @param x [in] The bigint to be converted. + * @param data [out] The converted data as a byte stream. + * @param size [in] The maximum size of the byte stream. Unused bytes will be + * zeroed. + */ +NS_INTERNAL void bi_export(BI_CTX *ctx, bigint *x, uint8_t *data, int size) { + int i, j, k = size - 1; + + check(x); + memset(data, 0, (size_t) size); /* ensure all leading 0's are cleared */ + + for (i = 0; i < x->size; i++) { + for (j = 0; j < COMP_BYTE_SIZE; j++) { + comp mask = (comp) 0xff << (j * 8); + int num = (int) (x->comps[i] & mask) >> (j * 8); + data[k--] = (uint8_t) num; + + if (k < 0) { + goto buf_done; + } + } + } +buf_done: + + bi_free(ctx, x); +} + +/** + * @brief Pre-calculate some of the expensive steps in reduction. + * + * This function should only be called once (normally when a session starts). + * When the session is over, bi_free_mod() should be called. bi_mod_power() + * relies on this function being called. + * @param ctx [in] The bigint session context. + * @param bim [in] The bigint modulus that will be used. + * @param mod_offset [in] There are three moduluii that can be stored - the + * standard modulus, and its two primes p and q. This offset refers to which + * modulus we are referring to. + * @see bi_free_mod(), bi_mod_power(). + */ +NS_INTERNAL void bi_set_mod(BI_CTX *ctx, bigint *bim, int mod_offset) { + int k = bim->size; + comp d = (comp)((long_comp) COMP_RADIX / (bim->comps[k - 1] + 1)); +#ifdef CONFIG_BIGINT_MONTGOMERY + bigint *R, *R2; +#endif + + ctx->bi_mod[mod_offset] = bim; + bi_permanent(ctx->bi_mod[mod_offset]); + ctx->bi_normalised_mod[mod_offset] = bi_int_multiply(ctx, bim, d); + bi_permanent(ctx->bi_normalised_mod[mod_offset]); + +#if defined(CONFIG_BIGINT_MONTGOMERY) + /* set montgomery variables */ + R = comp_left_shift(bi_clone(ctx, ctx->bi_radix), k - 1); /* R */ + R2 = comp_left_shift(bi_clone(ctx, ctx->bi_radix), k * 2 - 1); /* R^2 */ + ctx->bi_RR_mod_m[mod_offset] = bi_mod(ctx, R2); /* R^2 mod m */ + ctx->bi_R_mod_m[mod_offset] = bi_mod(ctx, R); /* R mod m */ + + bi_permanent(ctx->bi_RR_mod_m[mod_offset]); + bi_permanent(ctx->bi_R_mod_m[mod_offset]); + + ctx->N0_dash[mod_offset] = modular_inverse(ctx->bi_mod[mod_offset]); + +#elif defined(CONFIG_BIGINT_BARRETT) + ctx->bi_mu[mod_offset] = + bi_divide(ctx, comp_left_shift(bi_clone(ctx, ctx->bi_radix), k * 2 - 1), + ctx->bi_mod[mod_offset], 0); + bi_permanent(ctx->bi_mu[mod_offset]); +#endif +} + +#if 0 +/** + * @brief Used when cleaning various bigints at the end of a session. + * @param ctx [in] The bigint session context. + * @param mod_offset [in] The offset to use. + * @see bi_set_mod(). + */ +void bi_free_mod(BI_CTX *ctx, int mod_offset) { + bi_depermanent(ctx->bi_mod[mod_offset]); + bi_free(ctx, ctx->bi_mod[mod_offset]); +#if defined(CONFIG_BIGINT_MONTGOMERY) + bi_depermanent(ctx->bi_RR_mod_m[mod_offset]); + bi_depermanent(ctx->bi_R_mod_m[mod_offset]); + bi_free(ctx, ctx->bi_RR_mod_m[mod_offset]); + bi_free(ctx, ctx->bi_R_mod_m[mod_offset]); +#elif defined(CONFIG_BIGINT_BARRETT) + bi_depermanent(ctx->bi_mu[mod_offset]); + bi_free(ctx, ctx->bi_mu[mod_offset]); +#endif + bi_depermanent(ctx->bi_normalised_mod[mod_offset]); + bi_free(ctx, ctx->bi_normalised_mod[mod_offset]); +} +#endif + +/** + * Perform a standard multiplication between two bigints. + * + * Barrett reduction has no need for some parts of the product, so ignore bits + * of the multiply. This routine gives Barrett its big performance + * improvements over Classical/Montgomery reduction methods. + */ +static bigint *regular_multiply(BI_CTX *ctx, bigint *bia, bigint *bib, + int inner_partial, int outer_partial) { + int i = 0, j; + int n = bia->size; + int t = bib->size; + bigint *biR = alloc(ctx, n + t); + comp *sr = biR->comps; + comp *sa = bia->comps; + comp *sb = bib->comps; + + check(bia); + check(bib); + + /* clear things to start with */ + memset(biR->comps, 0, (size_t) ((n + t) * COMP_BYTE_SIZE)); + + do { + long_comp tmp; + comp carry = 0; + int r_index = i; + j = 0; + + if (outer_partial && outer_partial - i > 0 && outer_partial < n) { + r_index = outer_partial - 1; + j = outer_partial - i - 1; + } + + do { + if (inner_partial && r_index >= inner_partial) { + break; + } + + tmp = sr[r_index] + ((long_comp) sa[j]) * sb[i] + carry; + sr[r_index++] = (comp) tmp; /* downsize */ + carry = (comp) (tmp >> COMP_BIT_SIZE); + } while (++j < n); + + sr[r_index] = carry; + } while (++i < t); + + bi_free(ctx, bia); + bi_free(ctx, bib); + return trim(biR); +} + +#ifdef CONFIG_BIGINT_KARATSUBA +/* + * Karatsuba improves on regular multiplication due to only 3 multiplications + * being done instead of 4. The additional additions/subtractions are O(N) + * rather than O(N^2) and so for big numbers it saves on a few operations + */ +static bigint *karatsuba(BI_CTX *ctx, bigint *bia, bigint *bib, int is_square) { + bigint *x0, *x1; + bigint *p0, *p1, *p2; + int m; + + if (is_square) { + m = (bia->size + 1) / 2; + } else { + m = (MAX(bia->size, bib->size) + 1) / 2; + } + + x0 = bi_clone(ctx, bia); + x0->size = m; + x1 = bi_clone(ctx, bia); + comp_right_shift(x1, m); + bi_free(ctx, bia); + + /* work out the 3 partial products */ + if (is_square) { + p0 = bi_square(ctx, bi_copy(x0)); + p2 = bi_square(ctx, bi_copy(x1)); + p1 = bi_square(ctx, bi_add(ctx, x0, x1)); + } else /* normal multiply */ + { + bigint *y0, *y1; + y0 = bi_clone(ctx, bib); + y0->size = m; + y1 = bi_clone(ctx, bib); + comp_right_shift(y1, m); + bi_free(ctx, bib); + + p0 = bi_multiply(ctx, bi_copy(x0), bi_copy(y0)); + p2 = bi_multiply(ctx, bi_copy(x1), bi_copy(y1)); + p1 = bi_multiply(ctx, bi_add(ctx, x0, x1), bi_add(ctx, y0, y1)); + } + + p1 = bi_subtract(ctx, bi_subtract(ctx, p1, bi_copy(p2), NULL), bi_copy(p0), + NULL); + + comp_left_shift(p1, m); + comp_left_shift(p2, 2 * m); + return bi_add(ctx, p1, bi_add(ctx, p0, p2)); +} +#endif + +/** + * @brief Perform a multiplication operation between two bigints. + * @param ctx [in] The bigint session context. + * @param bia [in] A bigint. + * @param bib [in] Another bigint. + * @return The result of the multiplication. + */ +NS_INTERNAL bigint *bi_multiply(BI_CTX *ctx, bigint *bia, bigint *bib) { + check(bia); + check(bib); + +#ifdef CONFIG_BIGINT_KARATSUBA + if (MIN(bia->size, bib->size) < MUL_KARATSUBA_THRESH) { + return regular_multiply(ctx, bia, bib, 0, 0); + } + + return karatsuba(ctx, bia, bib, 0); +#else + return regular_multiply(ctx, bia, bib, 0, 0); +#endif +} + +#ifdef CONFIG_BIGINT_SQUARE +/* + * Perform the actual square operion. It takes into account overflow. + */ +static bigint *regular_square(BI_CTX *ctx, bigint *bi) { + int t = bi->size; + int i = 0, j; + bigint *biR = alloc(ctx, t * 2 + 1); + comp *w = biR->comps; + comp *x = bi->comps; + long_comp carry; + memset(w, 0, biR->size * COMP_BYTE_SIZE); + + do { + long_comp tmp = w[2 * i] + (long_comp) x[i] * x[i]; + w[2 * i] = (comp) tmp; + carry = tmp >> COMP_BIT_SIZE; + + for (j = i + 1; j < t; j++) { + uint8_t c = 0; + long_comp xx = (long_comp) x[i] * x[j]; + if ((COMP_MAX - xx) < xx) c = 1; + + tmp = (xx << 1); + + if ((COMP_MAX - tmp) < w[i + j]) c = 1; + + tmp += w[i + j]; + + if ((COMP_MAX - tmp) < carry) c = 1; + + tmp += carry; + w[i + j] = (comp) tmp; + carry = tmp >> COMP_BIT_SIZE; + + if (c) carry += COMP_RADIX; + } + + tmp = w[i + t] + carry; + w[i + t] = (comp) tmp; + w[i + t + 1] = tmp >> COMP_BIT_SIZE; + } while (++i < t); + + bi_free(ctx, bi); + return trim(biR); +} + +/** + * @brief Perform a square operation on a bigint. + * @param ctx [in] The bigint session context. + * @param bia [in] A bigint. + * @return The result of the multiplication. + */ +NS_INTERNAL bigint *bi_square(BI_CTX *ctx, bigint *bia) { + check(bia); + +#ifdef CONFIG_BIGINT_KARATSUBA + if (bia->size < SQU_KARATSUBA_THRESH) { + return regular_square(ctx, bia); + } + + return karatsuba(ctx, bia, NULL, 1); +#else + return regular_square(ctx, bia); +#endif +} +#endif + +/** + * @brief Compare two bigints. + * @param bia [in] A bigint. + * @param bib [in] Another bigint. + * @return -1 if smaller, 1 if larger and 0 if equal. + */ +NS_INTERNAL int bi_compare(bigint *bia, bigint *bib) { + int r, i; + + check(bia); + check(bib); + + if (bia->size > bib->size) + r = 1; + else if (bia->size < bib->size) + r = -1; + else { + comp *a = bia->comps; + comp *b = bib->comps; + + /* Same number of components. Compare starting from the high end + * and working down. */ + r = 0; + i = bia->size - 1; + + do { + if (a[i] > b[i]) { + r = 1; + break; + } else if (a[i] < b[i]) { + r = -1; + break; + } + } while (--i >= 0); + } + + return r; +} + +/* + * Allocate and zero more components. Does not consume bi. + */ +static void more_comps(bigint *bi, int n) { + if (n > bi->max_comps) { + int max = MAX(bi->max_comps * 2, n); + void *p = calloc(1, (size_t) max * COMP_BYTE_SIZE); + if (p != NULL && bi->size > 0) memcpy(p, bi->comps, (size_t) bi->max_comps * COMP_BYTE_SIZE); + free(bi->comps); + bi->max_comps = (short) max; + bi->comps = (comp *) p; + } + + if (n > bi->size) { + memset(&bi->comps[bi->size], 0, (size_t) (n - bi->size) * COMP_BYTE_SIZE); + } + + bi->size = (short) n; +} + +/* + * Make a new empty bigint. It may just use an old one if one is available. + * Otherwise get one off the heap. + */ +static bigint *alloc(BI_CTX *ctx, int size) { + bigint *biR; + + /* Can we recycle an old bigint? */ + if (ctx->free_list != NULL) { + biR = ctx->free_list; + ctx->free_list = biR->next; + ctx->free_count--; + + if (biR->refs != 0) { +#ifdef CONFIG_SSL_FULL_MODE + printf("alloc: refs was not 0\n"); +#endif + abort(); /* create a stack trace from a core dump */ + } + + more_comps(biR, size); + } else { + /* No free bigints available - create a new one. */ + biR = (bigint *) calloc(1, sizeof(bigint)); + biR->comps = (comp *) calloc(1, (size_t) size * COMP_BYTE_SIZE); + biR->max_comps = (short) size; /* give some space to spare */ + } + + biR->size = (short) size; + biR->refs = 1; + biR->next = NULL; + ctx->active_count++; + return biR; +} + +/* + * Work out the highest '1' bit in an exponent. Used when doing sliding-window + * exponentiation. + */ +static int find_max_exp_index(bigint *biexp) { + int i = COMP_BIT_SIZE - 1; + comp shift = COMP_RADIX / 2; + comp test = biexp->comps[biexp->size - 1]; /* assume no leading zeroes */ + + check(biexp); + + do { + if (test & shift) { + return i + (biexp->size - 1) * COMP_BIT_SIZE; + } + + shift >>= 1; + } while (i-- != 0); + + return -1; /* error - must have been a leading 0 */ +} + +/* + * Is a particular bit is an exponent 1 or 0? Used when doing sliding-window + * exponentiation. + */ +static int exp_bit_is_one(bigint *biexp, int offset) { + comp test = biexp->comps[offset / COMP_BIT_SIZE]; + int num_shifts = offset % COMP_BIT_SIZE; + comp shift = 1; + int i; + + check(biexp); + + for (i = 0; i < num_shifts; i++) { + shift <<= 1; + } + + return (test & shift) != 0; +} + +#ifdef CONFIG_BIGINT_CHECK_ON +/* + * Perform a sanity check on bi. + */ +static void check(const bigint *bi) { + if (bi->refs <= 0) { + printf("check: zero or negative refs in bigint\n"); + abort(); + } + + if (bi->next != NULL) { + printf( + "check: attempt to use a bigint from " + "the free list\n"); + abort(); + } +} +#endif + +/* + * Delete any leading 0's (and allow for 0). + */ +static bigint *trim(bigint *bi) { + check(bi); + + while (bi->comps[bi->size - 1] == 0 && bi->size > 1) { + bi->size--; + } + + return bi; +} + +#if defined(CONFIG_BIGINT_MONTGOMERY) +/** + * @brief Perform a single montgomery reduction. + * @param ctx [in] The bigint session context. + * @param bixy [in] A bigint. + * @return The result of the montgomery reduction. + */ +NS_INTERNAL bigint *bi_mont(BI_CTX *ctx, bigint *bixy) { + int i = 0, n; + uint8_t mod_offset = ctx->mod_offset; + bigint *bim = ctx->bi_mod[mod_offset]; + comp mod_inv = ctx->N0_dash[mod_offset]; + + check(bixy); + + if (ctx->use_classical) /* just use classical instead */ + { + return bi_mod(ctx, bixy); + } + + n = bim->size; + + do { + bixy = bi_add(ctx, bixy, + comp_left_shift( + bi_int_multiply(ctx, bim, bixy->comps[i] * mod_inv), i)); + } while (++i < n); + + comp_right_shift(bixy, n); + + if (bi_compare(bixy, bim) >= 0) { + bixy = bi_subtract(ctx, bixy, bim, NULL); + } + + return bixy; +} + +#elif defined(CONFIG_BIGINT_BARRETT) +/* + * Stomp on the most significant components to give the illusion of a "mod base + * radix" operation + */ +static bigint *comp_mod(bigint *bi, int mod) { + check(bi); + + if (bi->size > mod) { + bi->size = mod; + } + + return bi; +} + +/** + * @brief Perform a single Barrett reduction. + * @param ctx [in] The bigint session context. + * @param bi [in] A bigint. + * @return The result of the Barrett reduction. + */ +NS_INTERNAL bigint *bi_barrett(BI_CTX *ctx, bigint *bi) { + bigint *q1, *q2, *q3, *r1, *r2, *r; + uint8_t mod_offset = ctx->mod_offset; + bigint *bim = ctx->bi_mod[mod_offset]; + int k = bim->size; + + check(bi); + check(bim); + + /* use Classical method instead - Barrett cannot help here */ + if (bi->size > k * 2) { + return bi_mod(ctx, bi); + } + + q1 = comp_right_shift(bi_clone(ctx, bi), k - 1); + + /* do outer partial multiply */ + q2 = regular_multiply(ctx, q1, ctx->bi_mu[mod_offset], 0, k - 1); + q3 = comp_right_shift(q2, k + 1); + r1 = comp_mod(bi, k + 1); + + /* do inner partial multiply */ + r2 = comp_mod(regular_multiply(ctx, q3, bim, k + 1, 0), k + 1); + r = bi_subtract(ctx, r1, r2, NULL); + + /* if (r >= m) r = r - m; */ + if (bi_compare(r, bim) >= 0) { + r = bi_subtract(ctx, r, bim, NULL); + } + + return r; +} +#endif /* CONFIG_BIGINT_BARRETT */ + +#ifdef CONFIG_BIGINT_SLIDING_WINDOW +/* + * Work out g1, g3, g5, g7... etc for the sliding-window algorithm + */ +static void precompute_slide_window(BI_CTX *ctx, int window, bigint *g1) { + int k = 1, i; + bigint *g2; + + for (i = 0; i < window - 1; i++) /* compute 2^(window-1) */ + { + k <<= 1; + } + + ctx->g = (bigint **) calloc(1, k * sizeof(bigint *)); + ctx->g[0] = bi_clone(ctx, g1); + bi_permanent(ctx->g[0]); + g2 = bi_residue(ctx, bi_square(ctx, ctx->g[0])); /* g^2 */ + + for (i = 1; i < k; i++) { + ctx->g[i] = bi_residue(ctx, bi_multiply(ctx, ctx->g[i - 1], bi_copy(g2))); + bi_permanent(ctx->g[i]); + } + + bi_free(ctx, g2); + ctx->window = k; +} +#endif + +/** + * @brief Perform a modular exponentiation. + * + * This function requires bi_set_mod() to have been called previously. This is + * one of the optimisations used for performance. + * @param ctx [in] The bigint session context. + * @param bi [in] The bigint on which to perform the mod power operation. + * @param biexp [in] The bigint exponent. + * @return The result of the mod exponentiation operation + * @see bi_set_mod(). + */ +NS_INTERNAL bigint *bi_mod_power(BI_CTX *ctx, bigint *bi, bigint *biexp) { + int i = find_max_exp_index(biexp), j, window_size = 1; + bigint *biR = int_to_bi(ctx, 1); + +#if defined(CONFIG_BIGINT_MONTGOMERY) + uint8_t mod_offset = ctx->mod_offset; + if (!ctx->use_classical) { + /* preconvert */ + bi = bi_mont(ctx, + bi_multiply(ctx, bi, ctx->bi_RR_mod_m[mod_offset])); /* x' */ + bi_free(ctx, biR); + biR = ctx->bi_R_mod_m[mod_offset]; /* A */ + } +#endif + + check(bi); + check(biexp); + +#ifdef CONFIG_BIGINT_SLIDING_WINDOW + for (j = i; j > 32; j /= 5) /* work out an optimum size */ + window_size++; + + /* work out the slide constants */ + precompute_slide_window(ctx, window_size, bi); +#else /* just one constant */ + ctx->g = (bigint **) calloc(1, sizeof(bigint *)); + ctx->g[0] = bi_clone(ctx, bi); + ctx->window = 1; + bi_permanent(ctx->g[0]); +#endif + + /* if sliding-window is off, then only one bit will be done at a time and + * will reduce to standard left-to-right exponentiation */ + do { + if (exp_bit_is_one(biexp, i)) { + int l = i - window_size + 1; + int part_exp = 0; + + if (l < 0) /* LSB of exponent will always be 1 */ + l = 0; + else { + while (exp_bit_is_one(biexp, l) == 0) l++; /* go back up */ + } + + /* build up the section of the exponent */ + for (j = i; j >= l; j--) { + biR = bi_residue(ctx, bi_square(ctx, biR)); + if (exp_bit_is_one(biexp, j)) part_exp++; + + if (j != l) part_exp <<= 1; + } + + part_exp = (part_exp - 1) / 2; /* adjust for array */ + biR = bi_residue(ctx, bi_multiply(ctx, biR, ctx->g[part_exp])); + i = l - 1; + } else /* square it */ + { + biR = bi_residue(ctx, bi_square(ctx, biR)); + i--; + } + } while (i >= 0); + + /* cleanup */ + for (i = 0; i < ctx->window; i++) { + bi_depermanent(ctx->g[i]); + bi_free(ctx, ctx->g[i]); + } + + free(ctx->g); + bi_free(ctx, bi); + bi_free(ctx, biexp); +#if defined CONFIG_BIGINT_MONTGOMERY + return ctx->use_classical ? biR : bi_mont(ctx, biR); /* convert back */ +#else /* CONFIG_BIGINT_CLASSICAL or CONFIG_BIGINT_BARRETT */ + return biR; +#endif +} + +#if 0 +/** + * @brief Use the Chinese Remainder Theorem to quickly perform RSA decrypts. + * + * @param ctx [in] The bigint session context. + * @param bi [in] The bigint to perform the exp/mod. + * @param dP [in] CRT's dP bigint + * @param dQ [in] CRT's dQ bigint + * @param p [in] CRT's p bigint + * @param q [in] CRT's q bigint + * @param qInv [in] CRT's qInv bigint + * @return The result of the CRT operation + */ +NS_INTERNAL bigint *bi_crt(BI_CTX *ctx, bigint *bi, bigint *dP, bigint *dQ, + bigint *p, bigint *q, bigint *qInv) { + bigint *m1, *m2, *h; + +/* Montgomery has a condition the 0 < x, y < m and these products violate + * that condition. So disable Montgomery when using CRT */ +#if defined(CONFIG_BIGINT_MONTGOMERY) + ctx->use_classical = 1; +#endif + ctx->mod_offset = BIGINT_P_OFFSET; + m1 = bi_mod_power(ctx, bi_copy(bi), dP); + + ctx->mod_offset = BIGINT_Q_OFFSET; + m2 = bi_mod_power(ctx, bi, dQ); + + h = bi_subtract(ctx, bi_add(ctx, m1, p), bi_copy(m2), NULL); + h = bi_multiply(ctx, h, qInv); + ctx->mod_offset = BIGINT_P_OFFSET; + h = bi_residue(ctx, h); +#if defined(CONFIG_BIGINT_MONTGOMERY) + ctx->use_classical = 0; /* reset for any further operation */ +#endif + return bi_add(ctx, m2, bi_multiply(ctx, q, h)); +} +#endif + +int mg_rsa_mod_pow(const uint8_t *mod, size_t modsz, const uint8_t *exp, size_t expsz, const uint8_t *msg, size_t msgsz, uint8_t *out, size_t outsz) { + BI_CTX *bi_ctx = bi_initialize(); + bigint *n = bi_import(bi_ctx, mod, (int) modsz); + bigint *e = bi_import(bi_ctx, exp, (int) expsz); + bigint *h = bi_import(bi_ctx, msg, (int) msgsz); + bi_set_mod(bi_ctx, n, 0); + bigint *m1 = bi_mod_power(bi_ctx, h, e); + bi_export(bi_ctx, m1, out, (int) outsz); + bi_free(bi_ctx, n); + bi_free(bi_ctx, e); + bi_free(bi_ctx, h); + bi_free(bi_ctx, m1); + return 0; +} + +#endif /* MG_TLS == MG_TLS_BUILTIN */ + #ifdef MG_ENABLE_LINES #line 1 "src/tls_uecc.c" #endif diff --git a/mongoose.h b/mongoose.h index 62a807d8..dce5335b 100644 --- a/mongoose.h +++ b/mongoose.h @@ -1132,6 +1132,12 @@ bool mg_path_is_sane(const struct mg_str path); MG_U8P(p)[0] = ((n) >> 8U) & 255; \ MG_U8P(p)[1] = (n) &255; \ } while (0) +#define MG_STORE_BE24(p, n) \ + do { \ + MG_U8P(p)[0] = ((n) >> 16U) & 255; \ + MG_U8P(p)[1] = ((n) >> 8U) & 255; \ + MG_U8P(p)[2] = (n) &255; \ + } while (0) #define MG_REG(x) ((volatile uint32_t *) (x))[0] #define MG_BIT(x) (((uint32_t) 1U) << (x)) @@ -1260,11 +1266,25 @@ typedef struct { unsigned char buffer[64]; } mg_sha256_ctx; + void mg_sha256_init(mg_sha256_ctx *); void mg_sha256_update(mg_sha256_ctx *, const unsigned char *data, size_t len); void mg_sha256_final(unsigned char digest[32], mg_sha256_ctx *); +void mg_sha256(uint8_t dst[32], uint8_t *data, size_t datasz); void mg_hmac_sha256(uint8_t dst[32], uint8_t *key, size_t keysz, uint8_t *data, size_t datasz); + +typedef struct { + uint64_t state[8]; + uint8_t buffer[128]; + uint64_t bitlen[2]; + uint32_t datalen; +} mg_sha384_ctx; +void mg_sha384_init(mg_sha384_ctx *ctx); +void mg_sha384_update(mg_sha384_ctx *ctx, const uint8_t *data, size_t len); +void mg_sha384_final(uint8_t digest[48], mg_sha384_ctx *ctx); +void mg_sha384(uint8_t dst[48], uint8_t *data, size_t datasz); + #ifndef TLS_X15519_H #define TLS_X15519_H @@ -2108,6 +2128,13 @@ PORTABLE_8439_DECL size_t mg_chacha20_poly1305_decrypt( } #endif #endif +#ifndef TLS_RSA_H +#define TLS_RSA_H + + +int mg_rsa_mod_pow(const uint8_t *mod, size_t modsz, const uint8_t *exp, size_t expsz, const uint8_t *msg, size_t msgsz, uint8_t *out, size_t outsz); + +#endif // TLS_RSA_H struct mg_connection; @@ -2938,7 +2965,7 @@ enum { // Set if PHY LEDs are connected to ground MG_PHY_LEDS_ACTIVE_HIGH = (1 << 0), // Set when PHY clocks MAC. Otherwise, MAC clocks PHY - MG_PHY_CLOCKS_MAC = (1 << 1), + MG_PHY_CLOCKS_MAC = (1 << 1) }; enum { MG_PHY_SPEED_10M, MG_PHY_SPEED_100M, MG_PHY_SPEED_1000M }; @@ -3193,46 +3220,6 @@ struct mg_tcpip_driver_tms570_data { -#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_W5500) && MG_ENABLE_DRIVER_W5500 - -#endif - - -#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_XMC7) && MG_ENABLE_DRIVER_XMC7 - -struct mg_tcpip_driver_xmc7_data { - int mdc_cr; // Valid values: -1, 0, 1, 2, 3, 4, 5 - uint8_t phy_addr; -}; - -#ifndef MG_TCPIP_PHY_ADDR -#define MG_TCPIP_PHY_ADDR 0 -#endif - -#ifndef MG_DRIVER_MDC_CR -#define MG_DRIVER_MDC_CR 3 -#endif - -#define MG_TCPIP_DRIVER_INIT(mgr) \ - do { \ - static struct mg_tcpip_driver_xmc7_data driver_data_; \ - static struct mg_tcpip_if mif_; \ - driver_data_.mdc_cr = MG_DRIVER_MDC_CR; \ - driver_data_.phy_addr = MG_TCPIP_PHY_ADDR; \ - mif_.ip = MG_TCPIP_IP; \ - mif_.mask = MG_TCPIP_MASK; \ - mif_.gw = MG_TCPIP_GW; \ - mif_.driver = &mg_tcpip_driver_xmc7; \ - mif_.driver_data = &driver_data_; \ - MG_SET_MAC_ADDRESS(mif_.mac); \ - mg_tcpip_init(mgr, &mif_); \ - MG_INFO(("Driver: xmc7, MAC: %M", mg_print_mac, mif_.mac)); \ - } while (0) - -#endif - - - #if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_XMC) && MG_ENABLE_DRIVER_XMC struct mg_tcpip_driver_xmc_data { @@ -3279,6 +3266,41 @@ struct mg_tcpip_driver_xmc_data { #endif + +#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_XMC7) && MG_ENABLE_DRIVER_XMC7 + +struct mg_tcpip_driver_xmc7_data { + int mdc_cr; // Valid values: -1, 0, 1, 2, 3, 4, 5 + uint8_t phy_addr; +}; + +#ifndef MG_TCPIP_PHY_ADDR +#define MG_TCPIP_PHY_ADDR 0 +#endif + +#ifndef MG_DRIVER_MDC_CR +#define MG_DRIVER_MDC_CR 3 +#endif + +#define MG_TCPIP_DRIVER_INIT(mgr) \ + do { \ + static struct mg_tcpip_driver_xmc7_data driver_data_; \ + static struct mg_tcpip_if mif_; \ + driver_data_.mdc_cr = MG_DRIVER_MDC_CR; \ + driver_data_.phy_addr = MG_TCPIP_PHY_ADDR; \ + mif_.ip = MG_TCPIP_IP; \ + mif_.mask = MG_TCPIP_MASK; \ + mif_.gw = MG_TCPIP_GW; \ + mif_.driver = &mg_tcpip_driver_xmc7; \ + mif_.driver_data = &driver_data_; \ + MG_SET_MAC_ADDRESS(mif_.mac); \ + mg_tcpip_init(mgr, &mif_); \ + MG_INFO(("Driver: xmc7, MAC: %M", mg_print_mac, mif_.mac)); \ + } while (0) + +#endif + + #ifdef __cplusplus } #endif diff --git a/src/drivers/phy.h b/src/drivers/phy.h index 30ae6ba3..a7db06f0 100644 --- a/src/drivers/phy.h +++ b/src/drivers/phy.h @@ -12,7 +12,7 @@ enum { // Set if PHY LEDs are connected to ground MG_PHY_LEDS_ACTIVE_HIGH = (1 << 0), // Set when PHY clocks MAC. Otherwise, MAC clocks PHY - MG_PHY_CLOCKS_MAC = (1 << 1), + MG_PHY_CLOCKS_MAC = (1 << 1) }; enum { MG_PHY_SPEED_10M, MG_PHY_SPEED_100M, MG_PHY_SPEED_1000M }; diff --git a/src/sha256.c b/src/sha256.c index 999ceff5..418b9198 100644 --- a/src/sha256.c +++ b/src/sha256.c @@ -137,6 +137,13 @@ void mg_sha256_final(unsigned char digest[32], mg_sha256_ctx *ctx) { } } +void mg_sha256(uint8_t dst[32], uint8_t *data, size_t datasz) { + mg_sha256_ctx ctx; + mg_sha256_init(&ctx); + mg_sha256_update(&ctx, data, datasz); + mg_sha256_final(dst, &ctx); +} + void mg_hmac_sha256(uint8_t dst[32], uint8_t *key, size_t keysz, uint8_t *data, size_t datasz) { mg_sha256_ctx ctx; @@ -165,3 +172,167 @@ void mg_hmac_sha256(uint8_t dst[32], uint8_t *key, size_t keysz, uint8_t *data, mg_sha256_update(&ctx, dst, 32); mg_sha256_final(dst, &ctx); } + +//===================================== +// TODO: rename macros +#define ROTR64(x, n) (((x) >> (n)) | ((x) << (64 - (n)))) +#define CH(x, y, z) (((x) & (y)) ^ (~(x) & (z))) +#define MAJ(x, y, z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) +#define EP0(x) (ROTR64(x, 28) ^ ROTR64(x, 34) ^ ROTR64(x, 39)) +#define EP1(x) (ROTR64(x, 14) ^ ROTR64(x, 18) ^ ROTR64(x, 41)) +#define SIG0(x) (ROTR64(x, 1) ^ ROTR64(x, 8) ^ ((x) >> 7)) +#define SIG1(x) (ROTR64(x, 19) ^ ROTR64(x, 61) ^ ((x) >> 6)) + +static const uint64_t mg_sha256_k2[80] = { + 0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, + 0xe9b5dba58189dbbc, 0x3956c25bf348b538, 0x59f111f1b605d019, + 0x923f82a4af194f9b, 0xab1c5ed5da6d8118, 0xd807aa98a3030242, + 0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2, + 0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235, + 0xc19bf174cf692694, 0xe49b69c19ef14ad2, 0xefbe4786384f25e3, + 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65, 0x2de92c6f592b0275, + 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5, + 0x983e5152ee66dfab, 0xa831c66d2db43210, 0xb00327c898fb213f, + 0xbf597fc7beef0ee4, 0xc6e00bf33da88fc2, 0xd5a79147930aa725, + 0x06ca6351e003826f, 0x142929670a0e6e70, 0x27b70a8546d22ffc, + 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df, + 0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, + 0x92722c851482353b, 0xa2bfe8a14cf10364, 0xa81a664bbc423001, + 0xc24b8b70d0f89791, 0xc76c51a30654be30, 0xd192e819d6ef5218, + 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8, + 0x19a4c116b8d2d0c8, 0x1e376c085141ab53, 0x2748774cdf8eeb99, + 0x34b0bcb5e19b48a8, 0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, + 0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3, 0x748f82ee5defb2fc, + 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec, + 0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, + 0xc67178f2e372532b, 0xca273eceea26619c, 0xd186b8c721c0c207, + 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178, 0x06f067aa72176fba, + 0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b, + 0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc, + 0x431d67c49c100d4c, 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, + 0x5fcb6fab3ad6faec, 0x6c44198c4a475817}; + +static void mg_sha384_transform(mg_sha384_ctx *ctx, const uint8_t data[]) { + uint64_t m[80]; + uint64_t a, b, c, d, e, f, g, h; + int i, j; + + for (i = 0, j = 0; i < 16; ++i, j += 8) + m[i] = ((uint64_t) data[j] << 56) | ((uint64_t) data[j + 1] << 48) | + ((uint64_t) data[j + 2] << 40) | ((uint64_t) data[j + 3] << 32) | + ((uint64_t) data[j + 4] << 24) | ((uint64_t) data[j + 5] << 16) | + ((uint64_t) data[j + 6] << 8) | ((uint64_t) data[j + 7]); + for (; i < 80; ++i) + m[i] = SIG1(m[i - 2]) + m[i - 7] + SIG0(m[i - 15]) + m[i - 16]; + + a = ctx->state[0]; + b = ctx->state[1]; + c = ctx->state[2]; + d = ctx->state[3]; + e = ctx->state[4]; + f = ctx->state[5]; + g = ctx->state[6]; + h = ctx->state[7]; + + for (i = 0; i < 80; ++i) { + uint64_t t1 = h + EP1(e) + CH(e, f, g) + mg_sha256_k2[i] + m[i]; + uint64_t t2 = EP0(a) + MAJ(a, b, c); + h = g; + g = f; + f = e; + e = d + t1; + d = c; + c = b; + b = a; + a = t1 + t2; + } + + ctx->state[0] += a; + ctx->state[1] += b; + ctx->state[2] += c; + ctx->state[3] += d; + ctx->state[4] += e; + ctx->state[5] += f; + ctx->state[6] += g; + ctx->state[7] += h; +} + +void mg_sha384_init(mg_sha384_ctx *ctx) { + ctx->datalen = 0; + ctx->bitlen[0] = 0; + ctx->bitlen[1] = 0; + ctx->state[0] = 0xcbbb9d5dc1059ed8; + ctx->state[1] = 0x629a292a367cd507; + ctx->state[2] = 0x9159015a3070dd17; + ctx->state[3] = 0x152fecd8f70e5939; + ctx->state[4] = 0x67332667ffc00b31; + ctx->state[5] = 0x8eb44a8768581511; + ctx->state[6] = 0xdb0c2e0d64f98fa7; + ctx->state[7] = 0x47b5481dbefa4fa4; +} + +void mg_sha384_update(mg_sha384_ctx *ctx, const uint8_t *data, size_t len) { + size_t i; + for (i = 0; i < len; ++i) { + ctx->buffer[ctx->datalen] = data[i]; + ctx->datalen++; + if (ctx->datalen == 128) { + mg_sha384_transform(ctx, ctx->buffer); + ctx->bitlen[1] += 1024; + if (ctx->bitlen[1] < 1024) ctx->bitlen[0]++; + ctx->datalen = 0; + } + } +} + +void mg_sha384_final(uint8_t hash[48], mg_sha384_ctx *ctx) { + size_t i = ctx->datalen; + + if (ctx->datalen < 112) { + ctx->buffer[i++] = 0x80; + while (i < 112) ctx->buffer[i++] = 0x00; + } else { + ctx->buffer[i++] = 0x80; + while (i < 128) ctx->buffer[i++] = 0x00; + mg_sha384_transform(ctx, ctx->buffer); + memset(ctx->buffer, 0, 112); + } + + ctx->bitlen[1] += ctx->datalen * 8; + if (ctx->bitlen[1] < ctx->datalen * 8) ctx->bitlen[0]++; + ctx->buffer[127] = (uint8_t) (ctx->bitlen[1]); + ctx->buffer[126] = (uint8_t) (ctx->bitlen[1] >> 8); + ctx->buffer[125] = (uint8_t) (ctx->bitlen[1] >> 16); + ctx->buffer[124] = (uint8_t) (ctx->bitlen[1] >> 24); + ctx->buffer[123] = (uint8_t) (ctx->bitlen[1] >> 32); + ctx->buffer[122] = (uint8_t) (ctx->bitlen[1] >> 40); + ctx->buffer[121] = (uint8_t) (ctx->bitlen[1] >> 48); + ctx->buffer[120] = (uint8_t) (ctx->bitlen[1] >> 56); + ctx->buffer[119] = (uint8_t) (ctx->bitlen[0]); + ctx->buffer[118] = (uint8_t) (ctx->bitlen[0] >> 8); + ctx->buffer[117] = (uint8_t) (ctx->bitlen[0] >> 16); + ctx->buffer[116] = (uint8_t) (ctx->bitlen[0] >> 24); + ctx->buffer[115] = (uint8_t) (ctx->bitlen[0] >> 32); + ctx->buffer[114] = (uint8_t) (ctx->bitlen[0] >> 40); + ctx->buffer[113] = (uint8_t) (ctx->bitlen[0] >> 48); + ctx->buffer[112] = (uint8_t) (ctx->bitlen[0] >> 56); + mg_sha384_transform(ctx, ctx->buffer); + + for (i = 0; i < 6; ++i) { + hash[i * 8] = (uint8_t) ((ctx->state[i] >> 56) & 0xff); + hash[i * 8 + 1] = (uint8_t) ((ctx->state[i] >> 48) & 0xff); + hash[i * 8 + 2] = (uint8_t) ((ctx->state[i] >> 40) & 0xff); + hash[i * 8 + 3] = (uint8_t) ((ctx->state[i] >> 32) & 0xff); + hash[i * 8 + 4] = (uint8_t) ((ctx->state[i] >> 24) & 0xff); + hash[i * 8 + 5] = (uint8_t) ((ctx->state[i] >> 16) & 0xff); + hash[i * 8 + 6] = (uint8_t) ((ctx->state[i] >> 8) & 0xff); + hash[i * 8 + 7] = (uint8_t) (ctx->state[i] & 0xff); + } +} + +void mg_sha384(uint8_t dst[48], uint8_t *data, size_t datasz) { + mg_sha384_ctx ctx; + mg_sha384_init(&ctx); + mg_sha384_update(&ctx, data, datasz); + mg_sha384_final(dst, &ctx); +} diff --git a/src/sha256.h b/src/sha256.h index 71e8a6df..da98b50d 100644 --- a/src/sha256.h +++ b/src/sha256.h @@ -15,8 +15,22 @@ typedef struct { unsigned char buffer[64]; } mg_sha256_ctx; + void mg_sha256_init(mg_sha256_ctx *); void mg_sha256_update(mg_sha256_ctx *, const unsigned char *data, size_t len); void mg_sha256_final(unsigned char digest[32], mg_sha256_ctx *); +void mg_sha256(uint8_t dst[32], uint8_t *data, size_t datasz); void mg_hmac_sha256(uint8_t dst[32], uint8_t *key, size_t keysz, uint8_t *data, size_t datasz); + +typedef struct { + uint64_t state[8]; + uint8_t buffer[128]; + uint64_t bitlen[2]; + uint32_t datalen; +} mg_sha384_ctx; +void mg_sha384_init(mg_sha384_ctx *ctx); +void mg_sha384_update(mg_sha384_ctx *ctx, const uint8_t *data, size_t len); +void mg_sha384_final(uint8_t digest[48], mg_sha384_ctx *ctx); +void mg_sha384(uint8_t dst[48], uint8_t *data, size_t datasz); + diff --git a/src/tls_builtin.c b/src/tls_builtin.c index 992954bf..a7a587f7 100644 --- a/src/tls_builtin.c +++ b/src/tls_builtin.c @@ -5,6 +5,7 @@ #include "tls.h" #include "tls_aes128.h" #include "tls_chacha20.h" +#include "tls_rsa.h" #include "tls_uecc.h" #include "tls_x25519.h" #include "util.h" @@ -81,12 +82,15 @@ struct tls_data { int skip_verification; // perform checks on server certificate? int cert_requested; // client received a CertificateRequest? struct mg_str cert_der; // certificate in DER format + struct mg_str ca_der; // CA certificate uint8_t ec_key[32]; // EC private key char hostname[254]; // server hostname (client extension) - uint8_t certhash[32]; // certificate message hash - uint8_t pubkey[64]; // server EC public key to verify cert - uint8_t sighash[32]; // server EC public key to verify cert + int is_ec_pubkey; // EC or RSA? + uint8_t pubkey[512 + 16]; // server EC (64) or RSA (512+exp) public key to + // verify cert + size_t pubkeysz; // size of the server public key + uint8_t sighash[32]; // calculated signature verification hash struct tls_enc enc; }; @@ -140,6 +144,66 @@ struct mg_der_tlv { uint8_t *value; }; +static int mg_der_parse(uint8_t *der, size_t dersz, struct mg_der_tlv *tlv) { + size_t header_len = 2; + uint32_t len = dersz < 2 ? 0 : der[1]; + if (dersz < 2) return -1; // Invalid DER + tlv->type = der[0]; + if (len > 0x7F) { // long-form length + uint8_t len_bytes = len & 0x7F; + if (dersz < (size_t) (2 + len_bytes)) return -1; + len = 0; + for (uint8_t i = 0; i < len_bytes; i++) { + len = (len << 8) | der[2 + i]; + } + header_len += len_bytes; + } + if (dersz < header_len + len) return -1; + tlv->len = len; + tlv->value = der + header_len; + return (int) (header_len + len); +} + +static int mg_der_next(struct mg_der_tlv *parent, struct mg_der_tlv *child) { + if (parent->len == 0) return 0; + int consumed = mg_der_parse(parent->value, parent->len, child); + if (consumed < 0) return -1; + parent->value += consumed; + parent->len -= (uint32_t) consumed; + return 1; +} + +static int mg_der_find_oid(struct mg_der_tlv *tlv, const uint8_t *oid, + size_t oid_len, struct mg_der_tlv *found) { + struct mg_der_tlv parent, child; + parent = *tlv; + while (mg_der_next(&parent, &child) > 0) { + if (child.type == 0x06 && child.len == oid_len && + memcmp(child.value, oid, oid_len) == 0) { + return mg_der_next(&parent, found); + } else if (child.type & 0x20) { + struct mg_der_tlv sub_parent = child; + if (mg_der_find_oid(&sub_parent, oid, oid_len, found)) return 1; + } + } + return 0; +} + +#if 0 +static void mg_der_debug(struct mg_der_tlv *tlv, int depth) { + MG_DEBUG(("> %.*sd=%d Type: 0x%02X, Length: %u\n", depth * 4, " ", depth, + tlv->type, tlv->len)); + + if (tlv->type & 0x20) { // Constructed: recurse into children + struct mg_der_tlv child; + struct mg_der_tlv parent = *tlv; + while (mg_der_next(&parent, &child) > 0) { + mg_der_debug(&child, depth + 1); + } + } +} +#endif + // parse DER into a TLV record static int mg_der_to_tlv(uint8_t *der, size_t dersz, struct mg_der_tlv *tlv) { if (dersz < 2) { @@ -162,31 +226,6 @@ static int mg_der_to_tlv(uint8_t *der, size_t dersz, struct mg_der_tlv *tlv) { return 0; } -static int mg_der_find(uint8_t *der, size_t dersz, uint8_t *oid, size_t oidsz, - struct mg_der_tlv *tlv) { - uint8_t *p, *end; - struct mg_der_tlv child = {0, 0, NULL}; - if (mg_der_to_tlv(der, dersz, tlv) < 0) { - return -1; // invalid DER - } else if (tlv->type == 6) { // found OID, check value - return (tlv->len == oidsz && memcmp(tlv->value, oid, oidsz) == 0); - } else if ((tlv->type & 0x20) == 0) { - return 0; // Primitive, but not OID: not found - } - // Constructed object: scan children - p = tlv->value; - end = tlv->value + tlv->len; - while (end > p) { - int r; - mg_der_to_tlv(p, (size_t) (end - p), &child); - r = mg_der_find(p, (size_t) (end - p), oid, oidsz, tlv); - if (r < 0) return -1; // error - if (r > 0) return 1; // found OID! - p = child.value + child.len; - } - return 0; // not found -} - // Did we receive a full TLS record in the c->rtls buffer? static bool mg_tls_got_record(struct mg_connection *c) { return c->rtls.len >= (size_t) TLS_RECHDR_SIZE && @@ -385,7 +424,7 @@ static void mg_tls_encrypt(struct mg_connection *c, const uint8_t *msg, nonce[8] ^= (uint8_t) ((seq >> 24) & 255U); nonce[9] ^= (uint8_t) ((seq >> 16) & 255U); nonce[10] ^= (uint8_t) ((seq >> 8) & 255U); - nonce[11] ^= (uint8_t) ((seq) &255U); + nonce[11] ^= (uint8_t) ((seq) & 255U); mg_iobuf_add(wio, wio->len, hdr, sizeof(hdr)); mg_iobuf_resize(wio, wio->len + encsz); @@ -464,8 +503,7 @@ static int mg_tls_recv_record(struct mg_connection *c) { nonce[8] ^= (uint8_t) ((seq >> 24) & 255U); nonce[9] ^= (uint8_t) ((seq >> 16) & 255U); nonce[10] ^= (uint8_t) ((seq >> 8) & 255U); - nonce[11] ^= (uint8_t) ((seq) &255U); - + nonce[11] ^= (uint8_t) ((seq) & 255U); #if CHACHA20 { uint8_t *dec = (uint8_t *) calloc(1, msgsz); @@ -553,15 +591,14 @@ static int mg_tls_server_recv_hello(struct mg_connection *c) { uint16_t key_exchange_len; uint8_t *key_exchange; uint16_t n = MG_LOAD_BE16(ext + j + 2); - if (ext[j] != 0x00 || - ext[j + 1] != 0x33) { // not a key share extension, ignore + if (MG_LOAD_BE16(ext + j) != 0x0033) { // not a key share extension, ignore j += (uint16_t) (n + 4); continue; } key_exchange_len = MG_LOAD_BE16(ext + j + 4); key_exchange = ext + j + 6; if (key_exchange_len > - rio->len - (uint16_t) ((size_t) key_exchange - (size_t) rio->buf) - 2) + rio->len - (uint16_t) ((size_t) key_exchange - (size_t) rio->buf)) goto fail; for (k = 0; k < key_exchange_len;) { uint16_t m = MG_LOAD_BE16(key_exchange + k + 2); @@ -615,7 +652,7 @@ static void mg_tls_server_send_hello(struct mg_connection *c) { // calculate keyshare uint8_t x25519_pub[X25519_BYTES]; uint8_t x25519_prv[X25519_BYTES]; - if (!mg_random(x25519_prv, sizeof(x25519_prv))) mg_error(c, "RNG"); + if (!mg_random(x25519_prv, sizeof(x25519_prv))) mg_error(c, "RNG"); mg_tls_x25519(x25519_pub, x25519_prv, X25519_BASE_POINT, 1); mg_tls_x25519(tls->x25519_sec, x25519_prv, tls->x25519_cli, 1); mg_tls_hexdump("s x25519 sec", tls->x25519_sec, sizeof(tls->x25519_sec)); @@ -644,28 +681,30 @@ static void mg_tls_server_send_ext(struct mg_connection *c) { static void mg_tls_server_send_cert(struct mg_connection *c) { struct tls_data *tls = (struct tls_data *) c->tls; - // server DER certificate (empty) - size_t n = tls->cert_der.len; + int send_ca = !c->is_client && tls->ca_der.len > 0; + // server DER certificate + CA (optional) + size_t n = tls->cert_der.len + (send_ca ? tls->ca_der.len + 5 : 0); uint8_t *cert = (uint8_t *) calloc(1, 13 + n); if (cert == NULL) { mg_error(c, "tls cert oom"); return; } - cert[0] = 0x0b; // handshake header - cert[1] = (uint8_t) (((n + 9) >> 16) & 255U); // 3 bytes: payload length - cert[2] = (uint8_t) (((n + 9) >> 8) & 255U); - cert[3] = (uint8_t) ((n + 9) & 255U); - cert[4] = 0; // request context - cert[5] = (uint8_t) (((n + 5) >> 16) & 255U); // 3 bytes: cert (s) length - cert[6] = (uint8_t) (((n + 5) >> 8) & 255U); - cert[7] = (uint8_t) ((n + 5) & 255U); - cert[8] = - (uint8_t) (((n) >> 16) & 255U); // 3 bytes: first (and only) cert len - cert[9] = (uint8_t) (((n) >> 8) & 255U); - cert[10] = (uint8_t) (n & 255U); + cert[0] = 0x0b; // handshake header + MG_STORE_BE24(cert + 1, n + 9); + cert[4] = 0; // request context + MG_STORE_BE24(cert + 5, n + 5); // 3 bytes: cert (s) length + MG_STORE_BE24(cert + 8, tls->cert_der.len); // 3 bytes: first cert len // bytes 11+ are certificate in DER format - memmove(cert + 11, tls->cert_der.buf, n); - cert[11 + n] = cert[12 + n] = 0; // certificate extensions (none) + memmove(cert + 11, tls->cert_der.buf, tls->cert_der.len); + MG_STORE_BE16(cert + 11 + tls->cert_der.len, + 0); // certificate extensions (none) + if (send_ca) { + size_t offset = 13 + tls->cert_der.len; + MG_STORE_BE24(cert + offset, tls->ca_der.len); // 3 bytes: CA cert length + memmove(cert + offset + 3, tls->ca_der.buf, + tls->ca_der.len); // CA cert data + MG_STORE_BE16(cert + 11 + n, 0); // certificate extensions (none) + } mg_sha256_update(&tls->sha256, cert, 13 + n); mg_tls_encrypt(c, cert, 13 + n, MG_TLS_HANDSHAKE); free(cert); @@ -774,9 +813,10 @@ static void mg_tls_client_send_hello(struct mg_connection *c) { uint8_t x25519_pub[X25519_BYTES]; - // the only signature algorithm we actually support - uint8_t secp256r1_sig_algs[8] = { - 0x00, 0x0d, 0x00, 0x04, 0x00, 0x02, 0x04, 0x03, + // signature algorithms we actually support: + // rsa_pkcs1_sha256, rsa_pss_rsae_sha256 and ecdsa_secp256r1_sha256 + uint8_t secp256r1_sig_algs[12] = { + 0x00, 0x0d, 0x00, 0x08, 0x00, 0x06, 0x04, 0x03, 0x08, 0x04, 0x04, 0x01, }; // all popular signature algorithms (if we don't care about verification) uint8_t all_sig_algs[34] = { @@ -947,106 +987,351 @@ static int mg_tls_client_recv_ext(struct mg_connection *c) { return 0; } +struct mg_tls_cert { + int is_ec_pubkey; + struct mg_str sn; + struct mg_str pubkey; + struct mg_str sig; // signature + uint8_t tbshash[48]; // 32b for sha256/secp256, 48b for sha384/secp384 + size_t tbshashsz; // actual TBS hash size +}; + +static void mg_der_debug_cert_name(const char *name, struct mg_der_tlv *tlv) { + struct mg_der_tlv v; + struct mg_str cn, c, o, ou; + cn = c = o = ou = mg_str(""); + if (mg_der_find_oid(tlv, (uint8_t *) "\x55\x04\x03", 3, &v)) + cn = mg_str_n((const char *) v.value, v.len); + if (mg_der_find_oid(tlv, (uint8_t *) "\x55\x04\x06", 3, &v)) + c = mg_str_n((const char *) v.value, v.len); + if (mg_der_find_oid(tlv, (uint8_t *) "\x55\x04\x0a", 3, &v)) + o = mg_str_n((const char *) v.value, v.len); + if (mg_der_find_oid(tlv, (uint8_t *) "\x55\x04\x0b", 3, &v)) + ou = mg_str_n((const char *) v.value, v.len); + MG_VERBOSE(("%s: CN=%.*s, C=%.*s, O=%.*s, OU=%.*s", name, cn.len, cn.buf, + c.len, c.buf, o.len, o.buf, ou.len, ou.buf)); +} + +static int mg_tls_parse_cert_der(void *buf, size_t dersz, + struct mg_tls_cert *cert) { + uint8_t *tbs, *der = (uint8_t *) buf; + size_t tbssz; + struct mg_der_tlv root, tbs_cert, field, algo; // pubkey, signature; + struct mg_der_tlv pki, pki_algo, pki_key, pki_curve, raw_sig; + + // Parse outermost SEQUENCE + if (mg_der_parse(der, dersz, &root) <= 0 || root.type != 0x30) return -1; + + // Parse TBSCertificate SEQUENCE + tbs = root.value; + if (mg_der_next(&root, &tbs_cert) <= 0 || tbs_cert.type != 0x30) return -1; + tbssz = (size_t) (tbs_cert.value + tbs_cert.len - tbs); + + // Parse Version (optional field) + if (mg_der_next(&tbs_cert, &field) <= 0) return -1; + if (field.type == 0xa0) { // v3 + if (mg_der_parse(field.value, field.len, &field) <= 0 || field.len != 1 || + field.value[0] != 2) + return -1; + if (mg_der_next(&tbs_cert, &field) <= 0) return -1; + } + + // Parse Serial Number + if (field.type != 2) return -1; + cert->sn = mg_str_n((char *) field.value, field.len); + MG_VERBOSE(("cert s/n: %M", mg_print_hex, cert->sn.len, cert->sn.buf)); + + // Parse signature algorithm (first occurrence) + if (mg_der_next(&tbs_cert, &field) <= 0 || field.type != 0x30) return -1; + if (mg_der_next(&field, &algo) <= 0 || algo.type != 0x06) return -1; + + MG_VERBOSE(("sig algo (oid): %M", mg_print_hex, algo.len, algo.value)); + // Signature algorithm OID mapping + if (memcmp(algo.value, "\x2A\x86\x48\xCE\x3D\x04\x03\x02", algo.len) == 0) { + MG_VERBOSE(("sig algo: ECDSA with SHA256")); + mg_sha256(cert->tbshash, tbs, tbssz); + cert->tbshashsz = 32; + } else if (memcmp(algo.value, "\x2A\x86\x48\x86\xF7\x0D\x01\x01\x0B", + algo.len) == 0) { + MG_VERBOSE(("sig algo: RSA with SHA256")); + mg_sha256(cert->tbshash, tbs, tbssz); + cert->tbshashsz = 32; + } else if (memcmp(algo.value, "\x2A\x86\x48\xCE\x3D\x04\x03\x03", algo.len) == + 0) { + MG_VERBOSE(("sig algo: ECDSA with SHA384")); + mg_sha384(cert->tbshash, tbs, tbssz); + cert->tbshashsz = 48; + } else if (memcmp(algo.value, "\x2A\x86\x48\x86\xF7\x0D\x01\x01\x0C", + algo.len) == 0) { + MG_VERBOSE(("sig algo: RSA with SHA384")); + mg_sha384(cert->tbshash, tbs, tbssz); + cert->tbshashsz = 48; + } else { + MG_ERROR( + ("sig algo: unsupported OID: %M", mg_print_hex, algo.len, algo.value)); + return -1; + } + MG_VERBOSE(("tbs hash: %M", mg_print_hex, cert->tbshashsz, cert->tbshash)); + + // issuer + if (mg_der_next(&tbs_cert, &field) <= 0 || field.type != 0x30) return -1; + mg_der_debug_cert_name("issuer", &field); + + // validity dates (before/after) + if (mg_der_next(&tbs_cert, &field) <= 0 || field.type != 0x30) return -1; + if (1) { + struct mg_der_tlv before, after; + mg_der_next(&field, &before); + mg_der_next(&field, &after); + if (memcmp(after.value, "250101000000Z", after.len) < 0) { + MG_ERROR(("invalid validity dates: before=%M after=%M", mg_print_hex, + before.len, before.value, mg_print_hex, after.len, + after.value)); + return -1; + } + } + + // subject + if (mg_der_next(&tbs_cert, &field) <= 0 || field.type != 0x30) return -1; + mg_der_debug_cert_name("subject", &field); + + // subject public key info + if (mg_der_next(&tbs_cert, &field) <= 0 || field.type != 0x30) return -1; + + if (mg_der_next(&field, &pki) <= 0 || pki.type != 0x30) return -1; + if (mg_der_next(&pki, &pki_algo) <= 0 || pki_algo.type != 0x06) return -1; + + // public key algorithm + MG_VERBOSE(("pk algo (oid): %M", mg_print_hex, pki_algo.len, pki_algo.value)); + if (memcmp(pki_algo.value, "\x2A\x86\x48\xCE\x3D\x03\x01\x07", + pki_algo.len) == 0) { + cert->is_ec_pubkey = 1; + MG_VERBOSE(("pk algo: ECDSA secp256r1")); + } else if (memcmp(pki_algo.value, "\x2A\x86\x48\xCE\x3D\x03\x01\x08", + pki_algo.len) == 0) { + cert->is_ec_pubkey = 1; + MG_VERBOSE(("pk algo: ECDSA secp384r1")); + } else if (memcmp(pki_algo.value, "\x2A\x86\x48\xCE\x3D\x02\x01", + pki_algo.len) == 0) { + cert->is_ec_pubkey = 1; + MG_VERBOSE(("pk algo: EC public key")); + } else if (memcmp(pki_algo.value, "\x2A\x86\x48\x86\xF7\x0D\x01\x01\x01", + pki_algo.len) == 0) { + cert->is_ec_pubkey = 0; + MG_VERBOSE(("pk algo: RSA")); + } else { + MG_ERROR(("unsupported pk algo: %M", mg_print_hex, pki_algo.len, + pki_algo.value)); + return -1; + } + + // Parse public key + if (cert->is_ec_pubkey) { + if (mg_der_next(&pki, &pki_curve) <= 0 || pki_curve.type != 0x06) return -1; + } + if (mg_der_next(&field, &pki_key) <= 0 || pki_key.type != 0x03) return -1; + + if (cert->is_ec_pubkey) { // Skip leading 0x00 and 0x04 (=uncompressed) + cert->pubkey = mg_str_n((char *) pki_key.value + 2, pki_key.len - 2); + } else { // Skip leading 0x00 byte + cert->pubkey = mg_str_n((char *) pki_key.value + 1, pki_key.len - 1); + } + + // Parse signature + if (mg_der_next(&root, &field) <= 0 || field.type != 0x30) return -1; + if (mg_der_next(&root, &raw_sig) <= 0 || raw_sig.type != 0x03) return -1; + if (raw_sig.len < 1 || raw_sig.value[0] != 0x00) return -1; + + cert->sig = mg_str_n((char *) raw_sig.value + 1, raw_sig.len - 1); + MG_VERBOSE(("sig: %M", mg_print_hex, cert->sig.len, cert->sig.buf)); + + return 0; +} + +static int mg_tls_verify_cert_san(const uint8_t *der, size_t dersz, + const char *server_name) { + struct mg_der_tlv root, field, name; + if (mg_der_parse((uint8_t *) der, dersz, &root) < 0 || + mg_der_find_oid(&root, (uint8_t *) "\x55\x1d\x11", 3, &field) < 0) { + MG_ERROR(("failed to parse certificate to extract SAN")); + return -1; + } + if (mg_der_parse(field.value, field.len, &field) < 0) { + MG_ERROR( + ("certificate subject alternative names is not a constructed object")); + return -1; + } + while (mg_der_next(&field, &name) > 0) { + if (mg_match(mg_str(server_name), + mg_str_n((const char *) name.value, name.len), NULL)) { + // Found SAN that matches the host name + return 1; + } + } + return -1; +} + +static int mg_tls_verify_cert_signature(const struct mg_tls_cert *cert, + const struct mg_tls_cert *issuer) { + if (issuer->is_ec_pubkey) { + uint8_t sig[128]; + struct mg_der_tlv seq = {0, 0, 0}, a = {0, 0, 0}, b = {0, 0, 0}; + mg_der_parse((uint8_t *) cert->sig.buf, cert->sig.len, &seq); + mg_der_next(&seq, &a); + mg_der_next(&seq, &b); + if (a.len == 0 || b.len == 0) { + MG_ERROR(("cert verification error")); + return 0; + } + if (issuer->pubkey.len == 64) { + const uint32_t N = 32; + if (a.len > N) a.value += (a.len - N), a.len = N; + if (b.len > N) b.value += (b.len - N), b.len = N; + memmove(sig, a.value, N); + memmove(sig + N, b.value, N); + return mg_uecc_verify((uint8_t *) issuer->pubkey.buf, cert->tbshash, + (unsigned) cert->tbshashsz, sig, + mg_uecc_secp256r1()); + } else if (issuer->pubkey.len == 96) { + MG_DEBUG(("ignore secp386 for now")); + return 1; + } else { + MG_ERROR(("unsupported public key length: %d", issuer->pubkey.len)); + return 0; + } + } else { + int r; + uint8_t sig2[256]; // 2048 bits + struct mg_der_tlv seq, modulus, exponent; + if (mg_der_parse((uint8_t *) issuer->pubkey.buf, issuer->pubkey.len, + &seq) <= 0 || + mg_der_next(&seq, &modulus) <= 0 || modulus.type != 2 || + mg_der_next(&seq, &exponent) <= 0 || exponent.type != 2) { + return -1; + } + mg_rsa_mod_pow(modulus.value, modulus.len, exponent.value, exponent.len, + (uint8_t *) cert->sig.buf, cert->sig.len, sig2, + sizeof(sig2)); + + r = memcmp(sig2 + sizeof(sig2) - cert->tbshashsz, cert->tbshash, + cert->tbshashsz); + return r == 0; + } +} + static int mg_tls_client_recv_cert(struct mg_connection *c) { - uint8_t *cert; - uint32_t certsz; - struct mg_der_tlv oid, pubkey, seq, subj; int subj_match = 0; struct tls_data *tls = (struct tls_data *) c->tls; unsigned char *recv_buf; + (void) subj_match; + if (mg_tls_recv_record(c) < 0) { return -1; } + recv_buf = &c->rtls.buf[tls->recv_offset]; + if (recv_buf[0] == MG_TLS_CERTIFICATE_REQUEST) { MG_VERBOSE(("got certificate request")); mg_tls_drop_message(c); tls->cert_requested = 1; return -1; } + if (recv_buf[0] != MG_TLS_CERTIFICATE) { mg_error(c, "expected server certificate but got msg 0x%02x", recv_buf[0]); return -1; } - if (tls->skip_verification) { - mg_tls_drop_message(c); - return 0; - } if (tls->recv_len < 11) { mg_error(c, "certificate list too short"); return -1; } - cert = recv_buf + 11; - certsz = MG_LOAD_BE24(recv_buf + 8); - if (certsz > tls->recv_len - 11) { - mg_error(c, "certificate too long: %d vs %d", certsz, tls->recv_len - 11); + uint32_t full_cert_chain_len = MG_LOAD_BE24(recv_buf + 1); + uint32_t cert_chain_len = MG_LOAD_BE24(recv_buf + 5); + if (cert_chain_len != full_cert_chain_len - 4) { + MG_ERROR(("full chain length: %d, chain length: %d", full_cert_chain_len, + cert_chain_len)); + mg_error(c, "certificate chain length mismatch"); return -1; } - do { - // secp256r1 public key - if (mg_der_find(cert, certsz, - (uint8_t *) "\x2A\x86\x48\xCE\x3D\x03\x01\x07", 8, - &oid) < 0) { - mg_error(c, "certificate secp256r1 public key OID not found"); + // Normally, there are 2-3 certs in a chain + struct mg_tls_cert certs[8]; + int certnum = 0; + uint8_t *p = recv_buf + 8; + //uint8_t *endp = recv_buf + tls->recv_len; + uint8_t *endp = recv_buf + cert_chain_len; + + int found_ca = 0; + struct mg_tls_cert ca; + + memset(certs, 0, sizeof(certs)); + memset(&ca, 0, sizeof(ca)); + + if (tls->ca_der.len > 0) { + if (mg_tls_parse_cert_der(tls->ca_der.buf, tls->ca_der.len, &ca) < 0) { + mg_error(c, "failed to parse CA certificate"); return -1; } - if (mg_der_to_tlv(oid.value + oid.len, - (size_t) (cert + certsz - (oid.value + oid.len)), - &pubkey) < 0) { - mg_error(c, "certificate secp256r1 public key not found"); + MG_VERBOSE(("CA serial: %M", mg_print_hex, ca.sn.len, ca.sn.buf)); + } + + while (p < endp) { + struct mg_tls_cert *ci = &certs[certnum++]; + uint32_t certsz = MG_LOAD_BE24(p); + uint8_t *cert = p + 3; + uint16_t certext = MG_LOAD_BE16(cert + certsz); + if (certext != 0) { + mg_error(c, "certificate extensions are not supported"); + return -1; + } + p = cert + certsz + 2; + + if (mg_tls_parse_cert_der(cert, certsz, ci) < 0) { + mg_error(c, "failed to parse certificate"); return -1; } - // expect BIT STRING, unpadded, uncompressed: [0]+[4]+32+32 content bytes - if (pubkey.type != 3 || pubkey.len != 66 || pubkey.value[0] != 0 || - pubkey.value[1] != 4) { - mg_error(c, "unsupported public key bitstring encoding"); - return -1; - } - memmove(tls->pubkey, pubkey.value + 2, pubkey.len - 2); - } while (0); - - // Subject Alternative Names - do { - if (mg_der_find(cert, certsz, (uint8_t *) "\x55\x1d\x11", 3, &oid) < 0) { - mg_error(c, "certificate does not contain subject alternative names"); - return -1; - } - if (mg_der_to_tlv(oid.value + oid.len, - (size_t) (cert + certsz - (oid.value + oid.len)), - &seq) < 0) { - mg_error(c, "certificate subject alternative names not found"); - return -1; - } - if (mg_der_to_tlv(seq.value, seq.len, &seq) < 0) { - mg_error( - c, - "certificate subject alternative names is not a constructed object"); - return -1; - } - MG_VERBOSE(("verify hostname %s", tls->hostname)); - while (seq.len > 0) { - if (mg_der_to_tlv(seq.value, seq.len, &subj) < 0) { - mg_error(c, "bad subject alternative name"); + if (ci == certs) { + // First certificate in the chain is peer cert, check SAN and store + // public key for further CertVerify step + if (mg_tls_verify_cert_san(cert, certsz, tls->hostname) <= 0) { + mg_error(c, "failed to verify hostname"); return -1; } - MG_VERBOSE(("subj=%.*s", subj.len, subj.value)); - if (mg_match(mg_str((const char *) tls->hostname), - mg_str_n((const char *) subj.value, subj.len), NULL)) { - subj_match = 1; - break; + memmove(tls->pubkey, ci->pubkey.buf, ci->pubkey.len); + tls->pubkeysz = ci->pubkey.len; + } else { + if (!mg_tls_verify_cert_signature(ci - 1, ci)) { + mg_error(c, "failed to verify certificate chain"); + return -1; } - seq.len = (uint32_t) (seq.value + seq.len - (subj.value + subj.len)); - seq.value = subj.value + subj.len; } - if (!subj_match) { - mg_error(c, "certificate did not match the hostname"); + + if (ca.pubkey.len == ci->pubkey.len && + memcmp(ca.pubkey.buf, ci->pubkey.buf, ca.pubkey.len) == 0) { + found_ca = 1; + break; + } + + if (certnum == sizeof(certs) / sizeof(certs[0]) - 1) { + mg_error(c, "too many certificates in the chain"); return -1; } - } while (0); + } + + if (!found_ca && tls->ca_der.len > 0) { + if (certnum < 1 || + !mg_tls_verify_cert_signature(&certs[certnum - 1], &ca)) { + mg_error(c, "failed to verify CA"); + return -1; + } else { + MG_VERBOSE( + ("CA was not in the chain, but verification with builtin CA passed")); + } + } mg_tls_drop_message(c); mg_tls_calc_cert_verify_hash(c, tls->sighash, 0); @@ -1061,51 +1346,94 @@ static int mg_tls_client_recv_cert_verify(struct mg_connection *c) { } recv_buf = &c->rtls.buf[tls->recv_offset]; if (recv_buf[0] != MG_TLS_CERTIFICATE_VERIFY) { - mg_error(c, "expected server certificate verify but got msg 0x%02x", recv_buf[0]); + mg_error(c, "expected server certificate verify but got msg 0x%02x", + recv_buf[0]); return -1; } + if (tls->recv_len < 8) { + mg_error(c, "server certificate verify is too short: %d bytes", + tls->recv_len); + return -1; + } + // Ignore CertificateVerify is strict checks are not required if (tls->skip_verification) { mg_tls_drop_message(c); return 0; } - // Extract certificate signature and verify it using pubkey and sighash - do { + uint16_t sigalg = MG_LOAD_BE16(recv_buf + 4); + uint16_t siglen = MG_LOAD_BE16(recv_buf + 6); + uint8_t *sigbuf = recv_buf + 8; + if (siglen > tls->recv_len - 8) { + mg_error(c, "invalid certverify signature length: %d, expected %d", siglen, + tls->recv_len - 8); + return -1; + } + MG_VERBOSE(("certificate verification, algo=%04x, siglen=%d", sigalg, siglen)); + + if (sigalg == 0x0804) { // rsa_pss_rsae_sha256 + uint8_t sig2[512]; // 2048 or 4096 bits + struct mg_der_tlv seq, modulus, exponent; + + if (mg_der_parse(tls->pubkey, tls->pubkeysz, &seq) <= 0 || + mg_der_next(&seq, &modulus) <= 0 || modulus.type != 2 || + mg_der_next(&seq, &exponent) <= 0 || exponent.type != 2) { + mg_error(c, "invalid public key"); + return -1; + } + + mg_rsa_mod_pow(modulus.value, modulus.len, exponent.value, exponent.len, + sigbuf, siglen, sig2, sizeof(sig2)); + + if (sig2[sizeof(sig2) - 1] != 0xbc) { + mg_error(c, "failed to verify RSA certificate (certverify)"); + return -1; + } + MG_DEBUG(("certificate verification successful (RSA)")); + } else if (sigalg == 0x0403) { // ecdsa_secp256r1_sha256 + // Extract certificate signature and verify it using pubkey and sighash uint8_t sig[64]; - struct mg_der_tlv seq, a, b; - if (mg_der_to_tlv(recv_buf + 8, tls->recv_len - 8, &seq) < 0) { + struct mg_der_tlv seq, r, s; + if (mg_der_to_tlv(sigbuf, siglen, &seq) < 0) { mg_error(c, "verification message is not an ASN.1 DER sequence"); return -1; } - if (mg_der_to_tlv(seq.value, seq.len, &a) < 0) { + if (mg_der_to_tlv(seq.value, seq.len, &r) < 0) { mg_error(c, "missing first part of the signature"); return -1; } - if (mg_der_to_tlv(a.value + a.len, seq.len - a.len, &b) < 0) { + if (mg_der_to_tlv(r.value + r.len, seq.len - r.len, &s) < 0) { mg_error(c, "missing second part of the signature"); return -1; } // Integers may be padded with zeroes - if (a.len > 32) { - a.value = a.value + (a.len - 32); - a.len = 32; - } - if (b.len > 32) { - b.value = b.value + (b.len - 32); - b.len = 32; - } + if (r.len > 32) r.value = r.value + (r.len - 32), r.len = 32; + if (s.len > 32) s.value = s.value + (s.len - 32), s.len = 32; - memmove(sig, a.value, a.len); - memmove(sig + 32, b.value, b.len); + memmove(sig, r.value, r.len); + memmove(sig + 32, s.value, s.len); if (mg_uecc_verify(tls->pubkey, tls->sighash, sizeof(tls->sighash), sig, mg_uecc_secp256r1()) != 1) { - mg_error(c, "failed to verify certificate"); + mg_error(c, "failed to verify EC certificate (certverify)"); return -1; } - } while (0); - + MG_DEBUG(("certificate verification successful (EC)")); + } else { + // From + // https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml: + // 0805 = rsa_pss_rsae_sha384 + // 0806 = rsa_pss_rsae_sha512 + // 0807 = ed25519 + // 0808 = ed448 + // 0809 = rsa_pss_pss_sha256 + // 080A = rsa_pss_pss_sha384 + // 080B = rsa_pss_pss_sha512 + MG_ERROR(("unsupported certverify signature scheme: %x of %d bytes", sigalg, + siglen)); + return -1; + } mg_tls_drop_message(c); return 0; } @@ -1195,9 +1523,7 @@ static void mg_tls_client_handshake(struct mg_connection *c) { c->is_tls_hs = 0; mg_call(c, MG_EV_TLS_HS, NULL); break; - default: - mg_error(c, "unexpected client state: %d", tls->state); - break; + default: mg_error(c, "unexpected client state: %d", tls->state); break; } } @@ -1224,9 +1550,7 @@ static void mg_tls_server_handshake(struct mg_connection *c) { tls->state = MG_TLS_STATE_SERVER_CONNECTED; c->is_tls_hs = 0; return; - default: - mg_error(c, "unexpected server state: %d", tls->state); - break; + default: mg_error(c, "unexpected server state: %d", tls->state); break; } } @@ -1283,7 +1607,7 @@ void mg_tls_init(struct mg_connection *c, const struct mg_tls_opts *opts) { c->is_client ? MG_TLS_STATE_CLIENT_START : MG_TLS_STATE_SERVER_START; tls->skip_verification = opts->skip_verification; - //tls->send.align = MG_IO_SIZE; + // tls->send.align = MG_IO_SIZE; c->tls = tls; c->is_tls = c->is_tls_hs = 1; @@ -1298,9 +1622,16 @@ void mg_tls_init(struct mg_connection *c, const struct mg_tls_opts *opts) { strncpy((char *) tls->hostname, opts->name.buf, sizeof(tls->hostname) - 1); tls->hostname[opts->name.len] = 0; } + // server CA certificate, store serial number + if (opts->ca.len > 0) { + if (mg_parse_pem(opts->ca, mg_str_s("CERTIFICATE"), &tls->ca_der) < 0) { + MG_ERROR(("Failed to load certificate")); + return; + } + } if (opts->cert.buf == NULL) { - MG_VERBOSE(("no certificate provided")); + MG_VERBOSE(("No certificate provided")); return; } @@ -1312,7 +1643,7 @@ void mg_tls_init(struct mg_connection *c, const struct mg_tls_opts *opts) { // parse PEM or DER EC key if (opts->key.buf == NULL) { - mg_error(c, "certificate provided without a private key"); + mg_error(c, "Certificate provided without a private key"); return; } @@ -1335,7 +1666,7 @@ void mg_tls_init(struct mg_connection *c, const struct mg_tls_opts *opts) { } else if (mg_parse_pem(opts->key, mg_str_s("PRIVATE KEY"), &key) == 0) { mg_error(c, "PKCS8 private key format is not supported"); } else { - mg_error(c, "expected EC PRIVATE KEY or PRIVATE KEY"); + mg_error(c, "Expected EC PRIVATE KEY or PRIVATE KEY"); } } @@ -1344,6 +1675,7 @@ void mg_tls_free(struct mg_connection *c) { if (tls != NULL) { mg_iobuf_free(&tls->send); free((void *) tls->cert_der.buf); + free((void *) tls->ca_der.buf); } free(c->tls); c->tls = NULL; diff --git a/src/tls_chacha20.c b/src/tls_chacha20.c index 33524699..597022fa 100644 --- a/src/tls_chacha20.c +++ b/src/tls_chacha20.c @@ -104,10 +104,12 @@ static void initialize_state(uint32_t state[CHACHA20_STATE_WORDS], const uint8_t key[CHACHA20_KEY_SIZE], const uint8_t nonce[CHACHA20_NONCE_SIZE], uint32_t counter) { +#if 0 #ifdef static_assert static_assert(sizeof(uint32_t) == 4, "We don't support systems that do not conform to standard of " "uint32_t being exact 32bit wide"); +#endif #endif state[0] = 0x61707865; state[1] = 0x3320646e; diff --git a/src/tls_rsa.c b/src/tls_rsa.c new file mode 100644 index 00000000..47238b9f --- /dev/null +++ b/src/tls_rsa.c @@ -0,0 +1,1579 @@ +#include "tls_rsa.h" + +#if defined(MG_TLS) && MG_TLS == MG_TLS_BUILTIN + +#define NS_INTERNAL static +typedef struct _bigint bigint; /**< An alias for _bigint */ + +/* + * Copyright (c) 2007, Cameron Rich + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the axTLS project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* Maintain a number of precomputed variables when doing reduction */ +#define BIGINT_M_OFFSET 0 /**< Normal modulo offset. */ +#define BIGINT_P_OFFSET 1 /**< p modulo offset. */ +#define BIGINT_Q_OFFSET 2 /**< q module offset. */ +#define BIGINT_NUM_MODS 3 /**< The number of modulus constants used. */ + +/* Architecture specific functions for big ints */ +#if defined(CONFIG_INTEGER_8BIT) +#define COMP_RADIX 256U /**< Max component + 1 */ +#define COMP_MAX 0xFFFFU /**< (Max dbl comp -1) */ +#define COMP_BIT_SIZE 8 /**< Number of bits in a component. */ +#define COMP_BYTE_SIZE 1 /**< Number of bytes in a component. */ +#define COMP_NUM_NIBBLES 2 /**< Used For diagnostics only. */ +typedef uint8_t comp; /**< A single precision component. */ +typedef uint16_t long_comp; /**< A double precision component. */ +typedef int16_t slong_comp; /**< A signed double precision component. */ +#elif defined(CONFIG_INTEGER_16BIT) +#define COMP_RADIX 65536U /**< Max component + 1 */ +#define COMP_MAX 0xFFFFFFFFU /**< (Max dbl comp -1) */ +#define COMP_BIT_SIZE 16 /**< Number of bits in a component. */ +#define COMP_BYTE_SIZE 2 /**< Number of bytes in a component. */ +#define COMP_NUM_NIBBLES 4 /**< Used For diagnostics only. */ +typedef uint16_t comp; /**< A single precision component. */ +typedef uint32_t long_comp; /**< A double precision component. */ +typedef int32_t slong_comp; /**< A signed double precision component. */ +#else /* regular 32 bit */ +#ifdef WIN32 +#define COMP_RADIX 4294967296i64 +#define COMP_MAX 0xFFFFFFFFFFFFFFFFui64 +#else +#define COMP_RADIX 4294967296 /**< Max component + 1 */ +#define COMP_MAX 0xFFFFFFFFFFFFFFFF /**< (Max dbl comp -1) */ +#endif +#define COMP_BIT_SIZE 32 /**< Number of bits in a component. */ +#define COMP_BYTE_SIZE 4 /**< Number of bytes in a component. */ +#define COMP_NUM_NIBBLES 8 /**< Used For diagnostics only. */ +typedef uint32_t comp; /**< A single precision component. */ +typedef uint64_t long_comp; /**< A double precision component. */ +typedef int64_t slong_comp; /**< A signed double precision component. */ +#endif + +/** + * @struct _bigint + * @brief A big integer basic object + */ +struct _bigint { + struct _bigint *next; /**< The next bigint in the cache. */ + short size; /**< The number of components in this bigint. */ + short max_comps; /**< The heapsize allocated for this bigint */ + int refs; /**< An internal reference count. */ + comp *comps; /**< A ptr to the actual component data */ +}; + +/** + * Maintains the state of the cache, and a number of variables used in + * reduction. + */ +struct _BI_CTX /**< A big integer "session" context. */ + { + bigint *active_list; /**< Bigints currently used. */ + bigint *free_list; /**< Bigints not used. */ + bigint *bi_radix; /**< The radix used. */ + bigint *bi_mod[BIGINT_NUM_MODS]; /**< modulus */ + +#if defined(CONFIG_BIGINT_MONTGOMERY) + bigint *bi_RR_mod_m[BIGINT_NUM_MODS]; /**< R^2 mod m */ + bigint *bi_R_mod_m[BIGINT_NUM_MODS]; /**< R mod m */ + comp N0_dash[BIGINT_NUM_MODS]; +#elif defined(CONFIG_BIGINT_BARRETT) + bigint *bi_mu[BIGINT_NUM_MODS]; /**< Storage for mu */ +#endif + bigint *bi_normalised_mod[BIGINT_NUM_MODS]; /**< Normalised mod storage. */ + bigint **g; /**< Used by sliding-window. */ + int window; /**< The size of the sliding window */ + int active_count; /**< Number of active bigints. */ + int free_count; /**< Number of free bigints. */ + +#ifdef CONFIG_BIGINT_MONTGOMERY + uint8_t use_classical; /**< Use classical reduction. */ +#endif + uint8_t mod_offset; /**< The mod offset we are using */ +}; +typedef struct _BI_CTX BI_CTX; + +#if !defined(MAX) +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#endif + +#define PERMANENT 0x7FFF55AA /**< A magic number for permanents. */ + +/* + * Copyright (c) 2007, Cameron Rich + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the axTLS project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +NS_INTERNAL BI_CTX *bi_initialize(void); +//NS_INTERNAL void bi_terminate(BI_CTX *ctx); +NS_INTERNAL void bi_permanent(bigint *bi); +NS_INTERNAL void bi_depermanent(bigint *bi); +//NS_INTERNAL void bi_clear_cache(BI_CTX *ctx); +NS_INTERNAL void bi_free(BI_CTX *ctx, bigint *bi); +NS_INTERNAL bigint *bi_copy(bigint *bi); +NS_INTERNAL bigint *bi_clone(BI_CTX *ctx, const bigint *bi); +NS_INTERNAL void bi_export(BI_CTX *ctx, bigint *bi, uint8_t *data, int size); +NS_INTERNAL bigint *bi_import(BI_CTX *ctx, const uint8_t *data, int len); +NS_INTERNAL bigint *int_to_bi(BI_CTX *ctx, comp i); + +/* the functions that actually do something interesting */ +NS_INTERNAL bigint *bi_add(BI_CTX *ctx, bigint *bia, bigint *bib); +NS_INTERNAL bigint *bi_subtract(BI_CTX *ctx, bigint *bia, bigint *bib, + int *is_negative); +NS_INTERNAL bigint *bi_divide(BI_CTX *ctx, bigint *bia, bigint *bim, + int is_mod); +NS_INTERNAL bigint *bi_multiply(BI_CTX *ctx, bigint *bia, bigint *bib); +NS_INTERNAL bigint *bi_mod_power(BI_CTX *ctx, bigint *bi, bigint *biexp); +#if 0 +NS_INTERNAL bigint *bi_mod_power2(BI_CTX *ctx, bigint *bi, + bigint *bim, bigint *biexp); +#endif +NS_INTERNAL int bi_compare(bigint *bia, bigint *bib); +NS_INTERNAL void bi_set_mod(BI_CTX *ctx, bigint *bim, int mod_offset); +//NS_INTERNAL void bi_free_mod(BI_CTX *ctx, int mod_offset); + +#ifdef CONFIG_SSL_FULL_MODE +NS_INTERNAL void bi_print(const char *label, bigint *bi); +NS_INTERNAL bigint *bi_str_import(BI_CTX *ctx, const char *data); +#endif + +/** + * @def bi_mod + * Find the residue of B. bi_set_mod() must be called before hand. + */ +#define bi_mod(A, B) bi_divide(A, B, ctx->bi_mod[ctx->mod_offset], 1) + +/** + * bi_residue() is technically the same as bi_mod(), but it uses the + * appropriate reduction technique (which is bi_mod() when doing classical + * reduction). + */ +#if defined(CONFIG_BIGINT_MONTGOMERY) +#define bi_residue(A, B) bi_mont(A, B) +NS_INTERNAL bigint *bi_mont(BI_CTX *ctx, bigint *bixy); +#elif defined(CONFIG_BIGINT_BARRETT) +#define bi_residue(A, B) bi_barrett(A, B) +NS_INTERNAL bigint *bi_barrett(BI_CTX *ctx, bigint *bi); +#else /* if defined(CONFIG_BIGINT_CLASSICAL) */ +#define bi_residue(A, B) bi_mod(A, B) +#endif + +#ifdef CONFIG_BIGINT_SQUARE +NS_INTERNAL bigint *bi_square(BI_CTX *ctx, bigint *bi); +#else +#define bi_square(A, B) bi_multiply(A, bi_copy(B), B) +#endif + +//NS_INTERNAL bigint *bi_crt(BI_CTX *ctx, bigint *bi, bigint *dP, bigint *dQ, +// bigint *p, bigint *q, bigint *qInv); + +/* + * Copyright (c) 2007, Cameron Rich + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * * Neither the name of the axTLS project nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @defgroup bigint_api Big Integer API + * @brief The bigint implementation as used by the axTLS project. + * + * The bigint library is for RSA encryption/decryption as well as signing. + * This code tries to minimise use of malloc/free by maintaining a small + * cache. A bigint context may maintain state by being made "permanent". + * It be be later released with a bi_depermanent() and bi_free() call. + * + * It supports the following reduction techniques: + * - Classical + * - Barrett + * - Montgomery + * + * It also implements the following: + * - Karatsuba multiplication + * - Squaring + * - Sliding window exponentiation + * - Chinese Remainder Theorem (implemented in rsa.c). + * + * All the algorithms used are pretty standard, and designed for different + * data bus sizes. Negative numbers are not dealt with at all, so a subtraction + * may need to be tested for negativity. + * + * This library steals some ideas from Jef Poskanzer + * + * and GMP . It gets most of its implementation + * detail from "The Handbook of Applied Cryptography" + * + * @{ + */ + +#define V1 v->comps[v->size - 1] /**< v1 for division */ +#define V2 v->comps[v->size - 2] /**< v2 for division */ +#define U(j) tmp_u->comps[tmp_u->size - j - 1] /**< uj for division */ +#define Q(j) quotient->comps[quotient->size - j - 1] /**< qj for division */ + +static bigint *bi_int_multiply(BI_CTX *ctx, bigint *bi, comp i); +static bigint *bi_int_divide(BI_CTX *ctx, bigint *biR, comp denom); +static bigint *alloc(BI_CTX *ctx, int size); +static bigint *trim(bigint *bi); +static void more_comps(bigint *bi, int n); +#if defined(CONFIG_BIGINT_KARATSUBA) || defined(CONFIG_BIGINT_BARRETT) || \ + defined(CONFIG_BIGINT_MONTGOMERY) +static bigint *comp_right_shift(bigint *biR, int num_shifts); +static bigint *comp_left_shift(bigint *biR, int num_shifts); +#endif + +#ifdef CONFIG_BIGINT_CHECK_ON +static void check(const bigint *bi); +#else +#define check(A) /**< disappears in normal production mode */ +#endif + +/** + * @brief Start a new bigint context. + * @return A bigint context. + */ +NS_INTERNAL BI_CTX *bi_initialize(void) { + /* calloc() sets everything to zero */ + BI_CTX *ctx = (BI_CTX *) calloc(1, sizeof(BI_CTX)); + + /* the radix */ + ctx->bi_radix = alloc(ctx, 2); + ctx->bi_radix->comps[0] = 0; + ctx->bi_radix->comps[1] = 1; + bi_permanent(ctx->bi_radix); + return ctx; +} + +#if 0 +/** + * @brief Close the bigint context and free any resources. + * + * Free up any used memory - a check is done if all objects were not + * properly freed. + * @param ctx [in] The bigint session context. + */ +NS_INTERNAL void bi_terminate(BI_CTX *ctx) { + bi_depermanent(ctx->bi_radix); + bi_free(ctx, ctx->bi_radix); + + if (ctx->active_count != 0) { +#ifdef CONFIG_SSL_FULL_MODE + printf("bi_terminate: there were %d un-freed bigints\n", ctx->active_count); +#endif + abort(); + } + + bi_clear_cache(ctx); + free(ctx); +} + +/** + *@brief Clear the memory cache. + */ +NS_INTERNAL void bi_clear_cache(BI_CTX *ctx) { + bigint *p, *pn; + + if (ctx->free_list == NULL) return; + + for (p = ctx->free_list; p != NULL; p = pn) { + pn = p->next; + free(p->comps); + free(p); + } + + ctx->free_count = 0; + ctx->free_list = NULL; +} +#endif + +/** + * @brief Increment the number of references to this object. + * It does not do a full copy. + * @param bi [in] The bigint to copy. + * @return A reference to the same bigint. + */ +NS_INTERNAL bigint *bi_copy(bigint *bi) { + check(bi); + if (bi->refs != PERMANENT) bi->refs++; + return bi; +} + +/** + * @brief Simply make a bigint object "unfreeable" if bi_free() is called on it. + * + * For this object to be freed, bi_depermanent() must be called. + * @param bi [in] The bigint to be made permanent. + */ +NS_INTERNAL void bi_permanent(bigint *bi) { + check(bi); + if (bi->refs != 1) { +#ifdef CONFIG_SSL_FULL_MODE + printf("bi_permanent: refs was not 1\n"); +#endif + abort(); + } + + bi->refs = PERMANENT; +} + +/** + * @brief Take a permanent object and make it eligible for freedom. + * @param bi [in] The bigint to be made back to temporary. + */ +NS_INTERNAL void bi_depermanent(bigint *bi) { + check(bi); + if (bi->refs != PERMANENT) { +#ifdef CONFIG_SSL_FULL_MODE + printf("bi_depermanent: bigint was not permanent\n"); +#endif + abort(); + } + + bi->refs = 1; +} + +/** + * @brief Free a bigint object so it can be used again. + * + * The memory itself it not actually freed, just tagged as being available + * @param ctx [in] The bigint session context. + * @param bi [in] The bigint to be freed. + */ +NS_INTERNAL void bi_free(BI_CTX *ctx, bigint *bi) { + check(bi); + if (bi->refs == PERMANENT) { + return; + } + + if (--bi->refs > 0) { + return; + } + + bi->next = ctx->free_list; + ctx->free_list = bi; + ctx->free_count++; + + if (--ctx->active_count < 0) { +#ifdef CONFIG_SSL_FULL_MODE + printf( + "bi_free: active_count went negative " + "- double-freed bigint?\n"); +#endif + abort(); + } +} + +/** + * @brief Convert an (unsigned) integer into a bigint. + * @param ctx [in] The bigint session context. + * @param i [in] The (unsigned) integer to be converted. + * + */ +NS_INTERNAL bigint *int_to_bi(BI_CTX *ctx, comp i) { + bigint *biR = alloc(ctx, 1); + biR->comps[0] = i; + return biR; +} + +/** + * @brief Do a full copy of the bigint object. + * @param ctx [in] The bigint session context. + * @param bi [in] The bigint object to be copied. + */ +NS_INTERNAL bigint *bi_clone(BI_CTX *ctx, const bigint *bi) { + bigint *biR = alloc(ctx, bi->size); + check(bi); + memcpy(biR->comps, bi->comps, (size_t) bi->size * COMP_BYTE_SIZE); + return biR; +} + +/** + * @brief Perform an addition operation between two bigints. + * @param ctx [in] The bigint session context. + * @param bia [in] A bigint. + * @param bib [in] Another bigint. + * @return The result of the addition. + */ +NS_INTERNAL bigint *bi_add(BI_CTX *ctx, bigint *bia, bigint *bib) { + int n; + comp carry = 0; + comp *pa, *pb; + + check(bia); + check(bib); + + n = MAX(bia->size, bib->size); + more_comps(bia, n + 1); + more_comps(bib, n); + pa = bia->comps; + pb = bib->comps; + + do { + comp sl, rl, cy1; + sl = *pa + *pb++; + rl = sl + carry; + cy1 = sl < *pa; + carry = cy1 | (rl < sl); + *pa++ = rl; + } while (--n != 0); + + *pa = carry; /* do overflow */ + bi_free(ctx, bib); + return trim(bia); +} + +/** + * @brief Perform a subtraction operation between two bigints. + * @param ctx [in] The bigint session context. + * @param bia [in] A bigint. + * @param bib [in] Another bigint. + * @param is_negative [out] If defined, indicates that the result was negative. + * is_negative may be null. + * @return The result of the subtraction. The result is always positive. + */ +NS_INTERNAL bigint *bi_subtract(BI_CTX *ctx, bigint *bia, bigint *bib, + int *is_negative) { + int n = bia->size; + comp *pa, *pb, carry = 0; + + check(bia); + check(bib); + + more_comps(bib, n); + pa = bia->comps; + pb = bib->comps; + + do { + comp sl, rl, cy1; + sl = *pa - *pb++; + rl = sl - carry; + cy1 = sl > *pa; + carry = cy1 | (rl > sl); + *pa++ = rl; + } while (--n != 0); + + if (is_negative) /* indicate a negative result */ + { + *is_negative = (int) carry; + } + + bi_free(ctx, trim(bib)); /* put bib back to the way it was */ + return trim(bia); +} + +/** + * Perform a multiply between a bigint an an (unsigned) integer + */ +static bigint *bi_int_multiply(BI_CTX *ctx, bigint *bia, comp b) { + int j = 0, n = bia->size; + bigint *biR = alloc(ctx, n + 1); + comp carry = 0; + comp *r = biR->comps; + comp *a = bia->comps; + + check(bia); + + /* clear things to start with */ + memset(r, 0, (size_t) ((n + 1) * COMP_BYTE_SIZE)); + + do { + long_comp tmp = *r + (long_comp) a[j] * b + carry; + *r++ = (comp) tmp; /* downsize */ + carry = (comp)(tmp >> COMP_BIT_SIZE); + } while (++j < n); + + *r = carry; + bi_free(ctx, bia); + return trim(biR); +} + +/** + * @brief Does both division and modulo calculations. + * + * Used extensively when doing classical reduction. + * @param ctx [in] The bigint session context. + * @param u [in] A bigint which is the numerator. + * @param v [in] Either the denominator or the modulus depending on the mode. + * @param is_mod [n] Determines if this is a normal division (0) or a reduction + * (1). + * @return The result of the division/reduction. + */ +NS_INTERNAL bigint *bi_divide(BI_CTX *ctx, bigint *u, bigint *v, int is_mod) { + int n = v->size, m = u->size - n; + int j = 0, orig_u_size = u->size; + uint8_t mod_offset = ctx->mod_offset; + comp d; + bigint *quotient, *tmp_u; + comp q_dash; + + check(u); + check(v); + + /* if doing reduction and we are < mod, then return mod */ + if (is_mod && bi_compare(v, u) > 0) { + bi_free(ctx, v); + return u; + } + + quotient = alloc(ctx, m + 1); + tmp_u = alloc(ctx, n + 1); + v = trim(v); /* make sure we have no leading 0's */ + d = (comp)((long_comp) COMP_RADIX / (V1 + 1)); + + /* clear things to start with */ + memset(quotient->comps, 0, (size_t) ((quotient->size) * COMP_BYTE_SIZE)); + + /* normalise */ + if (d > 1) { + u = bi_int_multiply(ctx, u, d); + + if (is_mod) { + v = ctx->bi_normalised_mod[mod_offset]; + } else { + v = bi_int_multiply(ctx, v, d); + } + } + + if (orig_u_size == u->size) /* new digit position u0 */ + { + more_comps(u, orig_u_size + 1); + } + + do { + /* get a temporary short version of u */ + memcpy(tmp_u->comps, &u->comps[u->size - n - 1 - j], + (size_t) (n + 1) * COMP_BYTE_SIZE); + + /* calculate q' */ + if (U(0) == V1) { + q_dash = COMP_RADIX - 1; + } else { + q_dash = (comp)(((long_comp) U(0) * COMP_RADIX + U(1)) / V1); + + if (v->size > 1 && V2) { + /* we are implementing the following: + if (V2*q_dash > (((U(0)*COMP_RADIX + U(1) - + q_dash*V1)*COMP_RADIX) + U(2))) ... */ + comp inner = (comp)((long_comp) COMP_RADIX * U(0) + U(1) - + (long_comp) q_dash * V1); + if ((long_comp) V2 * q_dash > (long_comp) inner * COMP_RADIX + U(2)) { + q_dash--; + } + } + } + + /* multiply and subtract */ + if (q_dash) { + int is_negative; + tmp_u = bi_subtract(ctx, tmp_u, bi_int_multiply(ctx, bi_copy(v), q_dash), + &is_negative); + more_comps(tmp_u, n + 1); + + Q(j) = q_dash; + + /* add back */ + if (is_negative) { + Q(j)--; + tmp_u = bi_add(ctx, tmp_u, bi_copy(v)); + + /* lop off the carry */ + tmp_u->size--; + v->size--; + } + } else { + Q(j) = 0; + } + + /* copy back to u */ + memcpy(&u->comps[u->size - n - 1 - j], tmp_u->comps, + (size_t) (n + 1) * COMP_BYTE_SIZE); + } while (++j <= m); + + bi_free(ctx, tmp_u); + bi_free(ctx, v); + + if (is_mod) /* get the remainder */ + { + bi_free(ctx, quotient); + return bi_int_divide(ctx, trim(u), d); + } else /* get the quotient */ + { + bi_free(ctx, u); + return trim(quotient); + } +} + +/* + * Perform an integer divide on a bigint. + */ +static bigint *bi_int_divide(BI_CTX *ctx, bigint *biR, comp denom) { + int i = biR->size - 1; + long_comp r = 0; + + (void) ctx; + check(biR); + + do { + r = (r << COMP_BIT_SIZE) + biR->comps[i]; + biR->comps[i] = (comp)(r / denom); + r %= denom; + } while (--i >= 0); + + return trim(biR); +} + +#ifdef CONFIG_BIGINT_MONTGOMERY +/** + * There is a need for the value of integer N' such that B^-1(B-1)-N^-1N'=1, + * where B^-1(B-1) mod N=1. Actually, only the least significant part of + * N' is needed, hence the definition N0'=N' mod b. We reproduce below the + * simple algorithm from an article by Dusse and Kaliski to efficiently + * find N0' from N0 and b */ +static comp modular_inverse(bigint *bim) { + int i; + comp t = 1; + comp two_2_i_minus_1 = 2; /* 2^(i-1) */ + long_comp two_2_i = 4; /* 2^i */ + comp N = bim->comps[0]; + + for (i = 2; i <= COMP_BIT_SIZE; i++) { + if ((long_comp) N * t % two_2_i >= two_2_i_minus_1) { + t += two_2_i_minus_1; + } + + two_2_i_minus_1 <<= 1; + two_2_i <<= 1; + } + + return (comp)(COMP_RADIX - t); +} +#endif + +#if defined(CONFIG_BIGINT_KARATSUBA) || defined(CONFIG_BIGINT_BARRETT) || \ + defined(CONFIG_BIGINT_MONTGOMERY) +/** + * Take each component and shift down (in terms of components) + */ +static bigint *comp_right_shift(bigint *biR, int num_shifts) { + int i = biR->size - num_shifts; + comp *x = biR->comps; + comp *y = &biR->comps[num_shifts]; + + check(biR); + + if (i <= 0) /* have we completely right shifted? */ + { + biR->comps[0] = 0; /* return 0 */ + biR->size = 1; + return biR; + } + + do { + *x++ = *y++; + } while (--i > 0); + + biR->size -= num_shifts; + return biR; +} + +/** + * Take each component and shift it up (in terms of components) + */ +static bigint *comp_left_shift(bigint *biR, int num_shifts) { + int i = biR->size - 1; + comp *x, *y; + + check(biR); + + if (num_shifts <= 0) { + return biR; + } + + more_comps(biR, biR->size + num_shifts); + + x = &biR->comps[i + num_shifts]; + y = &biR->comps[i]; + + do { + *x-- = *y--; + } while (i--); + + memset(biR->comps, 0, (size_t) (num_shifts * COMP_BYTE_SIZE)); /* zero LS comps */ + return biR; +} +#endif + +/** + * @brief Allow a binary sequence to be imported as a bigint. + * @param ctx [in] The bigint session context. + * @param data [in] The data to be converted. + * @param size [in] The number of bytes of data. + * @return A bigint representing this data. + */ +NS_INTERNAL bigint *bi_import(BI_CTX *ctx, const uint8_t *data, int size) { + bigint *biR = alloc(ctx, (size + COMP_BYTE_SIZE - 1) / COMP_BYTE_SIZE); + int i, j = 0, offset = 0; + + memset(biR->comps, 0, (size_t) (biR->size * COMP_BYTE_SIZE)); + + for (i = size - 1; i >= 0; i--) { + biR->comps[offset] += (comp) data[i] << (j * 8); + + if (++j == COMP_BYTE_SIZE) { + j = 0; + offset++; + } + } + + return trim(biR); +} + +#ifdef CONFIG_SSL_FULL_MODE +/** + * @brief The testharness uses this code to import text hex-streams and + * convert them into bigints. + * @param ctx [in] The bigint session context. + * @param data [in] A string consisting of hex characters. The characters must + * be in upper case. + * @return A bigint representing this data. + */ +NS_INTERNAL bigint *bi_str_import(BI_CTX *ctx, const char *data) { + int size = strlen(data); + bigint *biR = alloc(ctx, (size + COMP_NUM_NIBBLES - 1) / COMP_NUM_NIBBLES); + int i, j = 0, offset = 0; + memset(biR->comps, 0, (size_t) (biR->size * COMP_BYTE_SIZE)); + + for (i = size - 1; i >= 0; i--) { + int num = (data[i] <= '9') ? (data[i] - '0') : (data[i] - 'A' + 10); + biR->comps[offset] += num << (j * 4); + + if (++j == COMP_NUM_NIBBLES) { + j = 0; + offset++; + } + } + + return biR; +} + +NS_INTERNAL void bi_print(const char *label, bigint *x) { + int i, j; + + if (x == NULL) { + printf("%s: (null)\n", label); + return; + } + + printf("%s: (size %d)\n", label, x->size); + for (i = x->size - 1; i >= 0; i--) { + for (j = COMP_NUM_NIBBLES - 1; j >= 0; j--) { + comp mask = 0x0f << (j * 4); + comp num = (x->comps[i] & mask) >> (j * 4); + putc((num <= 9) ? (num + '0') : (num + 'A' - 10), stdout); + } + } + + printf("\n"); +} +#endif + +/** + * @brief Take a bigint and convert it into a byte sequence. + * + * This is useful after a decrypt operation. + * @param ctx [in] The bigint session context. + * @param x [in] The bigint to be converted. + * @param data [out] The converted data as a byte stream. + * @param size [in] The maximum size of the byte stream. Unused bytes will be + * zeroed. + */ +NS_INTERNAL void bi_export(BI_CTX *ctx, bigint *x, uint8_t *data, int size) { + int i, j, k = size - 1; + + check(x); + memset(data, 0, (size_t) size); /* ensure all leading 0's are cleared */ + + for (i = 0; i < x->size; i++) { + for (j = 0; j < COMP_BYTE_SIZE; j++) { + comp mask = (comp) 0xff << (j * 8); + int num = (int) (x->comps[i] & mask) >> (j * 8); + data[k--] = (uint8_t) num; + + if (k < 0) { + goto buf_done; + } + } + } +buf_done: + + bi_free(ctx, x); +} + +/** + * @brief Pre-calculate some of the expensive steps in reduction. + * + * This function should only be called once (normally when a session starts). + * When the session is over, bi_free_mod() should be called. bi_mod_power() + * relies on this function being called. + * @param ctx [in] The bigint session context. + * @param bim [in] The bigint modulus that will be used. + * @param mod_offset [in] There are three moduluii that can be stored - the + * standard modulus, and its two primes p and q. This offset refers to which + * modulus we are referring to. + * @see bi_free_mod(), bi_mod_power(). + */ +NS_INTERNAL void bi_set_mod(BI_CTX *ctx, bigint *bim, int mod_offset) { + int k = bim->size; + comp d = (comp)((long_comp) COMP_RADIX / (bim->comps[k - 1] + 1)); +#ifdef CONFIG_BIGINT_MONTGOMERY + bigint *R, *R2; +#endif + + ctx->bi_mod[mod_offset] = bim; + bi_permanent(ctx->bi_mod[mod_offset]); + ctx->bi_normalised_mod[mod_offset] = bi_int_multiply(ctx, bim, d); + bi_permanent(ctx->bi_normalised_mod[mod_offset]); + +#if defined(CONFIG_BIGINT_MONTGOMERY) + /* set montgomery variables */ + R = comp_left_shift(bi_clone(ctx, ctx->bi_radix), k - 1); /* R */ + R2 = comp_left_shift(bi_clone(ctx, ctx->bi_radix), k * 2 - 1); /* R^2 */ + ctx->bi_RR_mod_m[mod_offset] = bi_mod(ctx, R2); /* R^2 mod m */ + ctx->bi_R_mod_m[mod_offset] = bi_mod(ctx, R); /* R mod m */ + + bi_permanent(ctx->bi_RR_mod_m[mod_offset]); + bi_permanent(ctx->bi_R_mod_m[mod_offset]); + + ctx->N0_dash[mod_offset] = modular_inverse(ctx->bi_mod[mod_offset]); + +#elif defined(CONFIG_BIGINT_BARRETT) + ctx->bi_mu[mod_offset] = + bi_divide(ctx, comp_left_shift(bi_clone(ctx, ctx->bi_radix), k * 2 - 1), + ctx->bi_mod[mod_offset], 0); + bi_permanent(ctx->bi_mu[mod_offset]); +#endif +} + +#if 0 +/** + * @brief Used when cleaning various bigints at the end of a session. + * @param ctx [in] The bigint session context. + * @param mod_offset [in] The offset to use. + * @see bi_set_mod(). + */ +void bi_free_mod(BI_CTX *ctx, int mod_offset) { + bi_depermanent(ctx->bi_mod[mod_offset]); + bi_free(ctx, ctx->bi_mod[mod_offset]); +#if defined(CONFIG_BIGINT_MONTGOMERY) + bi_depermanent(ctx->bi_RR_mod_m[mod_offset]); + bi_depermanent(ctx->bi_R_mod_m[mod_offset]); + bi_free(ctx, ctx->bi_RR_mod_m[mod_offset]); + bi_free(ctx, ctx->bi_R_mod_m[mod_offset]); +#elif defined(CONFIG_BIGINT_BARRETT) + bi_depermanent(ctx->bi_mu[mod_offset]); + bi_free(ctx, ctx->bi_mu[mod_offset]); +#endif + bi_depermanent(ctx->bi_normalised_mod[mod_offset]); + bi_free(ctx, ctx->bi_normalised_mod[mod_offset]); +} +#endif + +/** + * Perform a standard multiplication between two bigints. + * + * Barrett reduction has no need for some parts of the product, so ignore bits + * of the multiply. This routine gives Barrett its big performance + * improvements over Classical/Montgomery reduction methods. + */ +static bigint *regular_multiply(BI_CTX *ctx, bigint *bia, bigint *bib, + int inner_partial, int outer_partial) { + int i = 0, j; + int n = bia->size; + int t = bib->size; + bigint *biR = alloc(ctx, n + t); + comp *sr = biR->comps; + comp *sa = bia->comps; + comp *sb = bib->comps; + + check(bia); + check(bib); + + /* clear things to start with */ + memset(biR->comps, 0, (size_t) ((n + t) * COMP_BYTE_SIZE)); + + do { + long_comp tmp; + comp carry = 0; + int r_index = i; + j = 0; + + if (outer_partial && outer_partial - i > 0 && outer_partial < n) { + r_index = outer_partial - 1; + j = outer_partial - i - 1; + } + + do { + if (inner_partial && r_index >= inner_partial) { + break; + } + + tmp = sr[r_index] + ((long_comp) sa[j]) * sb[i] + carry; + sr[r_index++] = (comp) tmp; /* downsize */ + carry = (comp) (tmp >> COMP_BIT_SIZE); + } while (++j < n); + + sr[r_index] = carry; + } while (++i < t); + + bi_free(ctx, bia); + bi_free(ctx, bib); + return trim(biR); +} + +#ifdef CONFIG_BIGINT_KARATSUBA +/* + * Karatsuba improves on regular multiplication due to only 3 multiplications + * being done instead of 4. The additional additions/subtractions are O(N) + * rather than O(N^2) and so for big numbers it saves on a few operations + */ +static bigint *karatsuba(BI_CTX *ctx, bigint *bia, bigint *bib, int is_square) { + bigint *x0, *x1; + bigint *p0, *p1, *p2; + int m; + + if (is_square) { + m = (bia->size + 1) / 2; + } else { + m = (MAX(bia->size, bib->size) + 1) / 2; + } + + x0 = bi_clone(ctx, bia); + x0->size = m; + x1 = bi_clone(ctx, bia); + comp_right_shift(x1, m); + bi_free(ctx, bia); + + /* work out the 3 partial products */ + if (is_square) { + p0 = bi_square(ctx, bi_copy(x0)); + p2 = bi_square(ctx, bi_copy(x1)); + p1 = bi_square(ctx, bi_add(ctx, x0, x1)); + } else /* normal multiply */ + { + bigint *y0, *y1; + y0 = bi_clone(ctx, bib); + y0->size = m; + y1 = bi_clone(ctx, bib); + comp_right_shift(y1, m); + bi_free(ctx, bib); + + p0 = bi_multiply(ctx, bi_copy(x0), bi_copy(y0)); + p2 = bi_multiply(ctx, bi_copy(x1), bi_copy(y1)); + p1 = bi_multiply(ctx, bi_add(ctx, x0, x1), bi_add(ctx, y0, y1)); + } + + p1 = bi_subtract(ctx, bi_subtract(ctx, p1, bi_copy(p2), NULL), bi_copy(p0), + NULL); + + comp_left_shift(p1, m); + comp_left_shift(p2, 2 * m); + return bi_add(ctx, p1, bi_add(ctx, p0, p2)); +} +#endif + +/** + * @brief Perform a multiplication operation between two bigints. + * @param ctx [in] The bigint session context. + * @param bia [in] A bigint. + * @param bib [in] Another bigint. + * @return The result of the multiplication. + */ +NS_INTERNAL bigint *bi_multiply(BI_CTX *ctx, bigint *bia, bigint *bib) { + check(bia); + check(bib); + +#ifdef CONFIG_BIGINT_KARATSUBA + if (MIN(bia->size, bib->size) < MUL_KARATSUBA_THRESH) { + return regular_multiply(ctx, bia, bib, 0, 0); + } + + return karatsuba(ctx, bia, bib, 0); +#else + return regular_multiply(ctx, bia, bib, 0, 0); +#endif +} + +#ifdef CONFIG_BIGINT_SQUARE +/* + * Perform the actual square operion. It takes into account overflow. + */ +static bigint *regular_square(BI_CTX *ctx, bigint *bi) { + int t = bi->size; + int i = 0, j; + bigint *biR = alloc(ctx, t * 2 + 1); + comp *w = biR->comps; + comp *x = bi->comps; + long_comp carry; + memset(w, 0, biR->size * COMP_BYTE_SIZE); + + do { + long_comp tmp = w[2 * i] + (long_comp) x[i] * x[i]; + w[2 * i] = (comp) tmp; + carry = tmp >> COMP_BIT_SIZE; + + for (j = i + 1; j < t; j++) { + uint8_t c = 0; + long_comp xx = (long_comp) x[i] * x[j]; + if ((COMP_MAX - xx) < xx) c = 1; + + tmp = (xx << 1); + + if ((COMP_MAX - tmp) < w[i + j]) c = 1; + + tmp += w[i + j]; + + if ((COMP_MAX - tmp) < carry) c = 1; + + tmp += carry; + w[i + j] = (comp) tmp; + carry = tmp >> COMP_BIT_SIZE; + + if (c) carry += COMP_RADIX; + } + + tmp = w[i + t] + carry; + w[i + t] = (comp) tmp; + w[i + t + 1] = tmp >> COMP_BIT_SIZE; + } while (++i < t); + + bi_free(ctx, bi); + return trim(biR); +} + +/** + * @brief Perform a square operation on a bigint. + * @param ctx [in] The bigint session context. + * @param bia [in] A bigint. + * @return The result of the multiplication. + */ +NS_INTERNAL bigint *bi_square(BI_CTX *ctx, bigint *bia) { + check(bia); + +#ifdef CONFIG_BIGINT_KARATSUBA + if (bia->size < SQU_KARATSUBA_THRESH) { + return regular_square(ctx, bia); + } + + return karatsuba(ctx, bia, NULL, 1); +#else + return regular_square(ctx, bia); +#endif +} +#endif + +/** + * @brief Compare two bigints. + * @param bia [in] A bigint. + * @param bib [in] Another bigint. + * @return -1 if smaller, 1 if larger and 0 if equal. + */ +NS_INTERNAL int bi_compare(bigint *bia, bigint *bib) { + int r, i; + + check(bia); + check(bib); + + if (bia->size > bib->size) + r = 1; + else if (bia->size < bib->size) + r = -1; + else { + comp *a = bia->comps; + comp *b = bib->comps; + + /* Same number of components. Compare starting from the high end + * and working down. */ + r = 0; + i = bia->size - 1; + + do { + if (a[i] > b[i]) { + r = 1; + break; + } else if (a[i] < b[i]) { + r = -1; + break; + } + } while (--i >= 0); + } + + return r; +} + +/* + * Allocate and zero more components. Does not consume bi. + */ +static void more_comps(bigint *bi, int n) { + if (n > bi->max_comps) { + int max = MAX(bi->max_comps * 2, n); + void *p = calloc(1, (size_t) max * COMP_BYTE_SIZE); + if (p != NULL && bi->size > 0) memcpy(p, bi->comps, (size_t) bi->max_comps * COMP_BYTE_SIZE); + free(bi->comps); + bi->max_comps = (short) max; + bi->comps = (comp *) p; + } + + if (n > bi->size) { + memset(&bi->comps[bi->size], 0, (size_t) (n - bi->size) * COMP_BYTE_SIZE); + } + + bi->size = (short) n; +} + +/* + * Make a new empty bigint. It may just use an old one if one is available. + * Otherwise get one off the heap. + */ +static bigint *alloc(BI_CTX *ctx, int size) { + bigint *biR; + + /* Can we recycle an old bigint? */ + if (ctx->free_list != NULL) { + biR = ctx->free_list; + ctx->free_list = biR->next; + ctx->free_count--; + + if (biR->refs != 0) { +#ifdef CONFIG_SSL_FULL_MODE + printf("alloc: refs was not 0\n"); +#endif + abort(); /* create a stack trace from a core dump */ + } + + more_comps(biR, size); + } else { + /* No free bigints available - create a new one. */ + biR = (bigint *) calloc(1, sizeof(bigint)); + biR->comps = (comp *) calloc(1, (size_t) size * COMP_BYTE_SIZE); + biR->max_comps = (short) size; /* give some space to spare */ + } + + biR->size = (short) size; + biR->refs = 1; + biR->next = NULL; + ctx->active_count++; + return biR; +} + +/* + * Work out the highest '1' bit in an exponent. Used when doing sliding-window + * exponentiation. + */ +static int find_max_exp_index(bigint *biexp) { + int i = COMP_BIT_SIZE - 1; + comp shift = COMP_RADIX / 2; + comp test = biexp->comps[biexp->size - 1]; /* assume no leading zeroes */ + + check(biexp); + + do { + if (test & shift) { + return i + (biexp->size - 1) * COMP_BIT_SIZE; + } + + shift >>= 1; + } while (i-- != 0); + + return -1; /* error - must have been a leading 0 */ +} + +/* + * Is a particular bit is an exponent 1 or 0? Used when doing sliding-window + * exponentiation. + */ +static int exp_bit_is_one(bigint *biexp, int offset) { + comp test = biexp->comps[offset / COMP_BIT_SIZE]; + int num_shifts = offset % COMP_BIT_SIZE; + comp shift = 1; + int i; + + check(biexp); + + for (i = 0; i < num_shifts; i++) { + shift <<= 1; + } + + return (test & shift) != 0; +} + +#ifdef CONFIG_BIGINT_CHECK_ON +/* + * Perform a sanity check on bi. + */ +static void check(const bigint *bi) { + if (bi->refs <= 0) { + printf("check: zero or negative refs in bigint\n"); + abort(); + } + + if (bi->next != NULL) { + printf( + "check: attempt to use a bigint from " + "the free list\n"); + abort(); + } +} +#endif + +/* + * Delete any leading 0's (and allow for 0). + */ +static bigint *trim(bigint *bi) { + check(bi); + + while (bi->comps[bi->size - 1] == 0 && bi->size > 1) { + bi->size--; + } + + return bi; +} + +#if defined(CONFIG_BIGINT_MONTGOMERY) +/** + * @brief Perform a single montgomery reduction. + * @param ctx [in] The bigint session context. + * @param bixy [in] A bigint. + * @return The result of the montgomery reduction. + */ +NS_INTERNAL bigint *bi_mont(BI_CTX *ctx, bigint *bixy) { + int i = 0, n; + uint8_t mod_offset = ctx->mod_offset; + bigint *bim = ctx->bi_mod[mod_offset]; + comp mod_inv = ctx->N0_dash[mod_offset]; + + check(bixy); + + if (ctx->use_classical) /* just use classical instead */ + { + return bi_mod(ctx, bixy); + } + + n = bim->size; + + do { + bixy = bi_add(ctx, bixy, + comp_left_shift( + bi_int_multiply(ctx, bim, bixy->comps[i] * mod_inv), i)); + } while (++i < n); + + comp_right_shift(bixy, n); + + if (bi_compare(bixy, bim) >= 0) { + bixy = bi_subtract(ctx, bixy, bim, NULL); + } + + return bixy; +} + +#elif defined(CONFIG_BIGINT_BARRETT) +/* + * Stomp on the most significant components to give the illusion of a "mod base + * radix" operation + */ +static bigint *comp_mod(bigint *bi, int mod) { + check(bi); + + if (bi->size > mod) { + bi->size = mod; + } + + return bi; +} + +/** + * @brief Perform a single Barrett reduction. + * @param ctx [in] The bigint session context. + * @param bi [in] A bigint. + * @return The result of the Barrett reduction. + */ +NS_INTERNAL bigint *bi_barrett(BI_CTX *ctx, bigint *bi) { + bigint *q1, *q2, *q3, *r1, *r2, *r; + uint8_t mod_offset = ctx->mod_offset; + bigint *bim = ctx->bi_mod[mod_offset]; + int k = bim->size; + + check(bi); + check(bim); + + /* use Classical method instead - Barrett cannot help here */ + if (bi->size > k * 2) { + return bi_mod(ctx, bi); + } + + q1 = comp_right_shift(bi_clone(ctx, bi), k - 1); + + /* do outer partial multiply */ + q2 = regular_multiply(ctx, q1, ctx->bi_mu[mod_offset], 0, k - 1); + q3 = comp_right_shift(q2, k + 1); + r1 = comp_mod(bi, k + 1); + + /* do inner partial multiply */ + r2 = comp_mod(regular_multiply(ctx, q3, bim, k + 1, 0), k + 1); + r = bi_subtract(ctx, r1, r2, NULL); + + /* if (r >= m) r = r - m; */ + if (bi_compare(r, bim) >= 0) { + r = bi_subtract(ctx, r, bim, NULL); + } + + return r; +} +#endif /* CONFIG_BIGINT_BARRETT */ + +#ifdef CONFIG_BIGINT_SLIDING_WINDOW +/* + * Work out g1, g3, g5, g7... etc for the sliding-window algorithm + */ +static void precompute_slide_window(BI_CTX *ctx, int window, bigint *g1) { + int k = 1, i; + bigint *g2; + + for (i = 0; i < window - 1; i++) /* compute 2^(window-1) */ + { + k <<= 1; + } + + ctx->g = (bigint **) calloc(1, k * sizeof(bigint *)); + ctx->g[0] = bi_clone(ctx, g1); + bi_permanent(ctx->g[0]); + g2 = bi_residue(ctx, bi_square(ctx, ctx->g[0])); /* g^2 */ + + for (i = 1; i < k; i++) { + ctx->g[i] = bi_residue(ctx, bi_multiply(ctx, ctx->g[i - 1], bi_copy(g2))); + bi_permanent(ctx->g[i]); + } + + bi_free(ctx, g2); + ctx->window = k; +} +#endif + +/** + * @brief Perform a modular exponentiation. + * + * This function requires bi_set_mod() to have been called previously. This is + * one of the optimisations used for performance. + * @param ctx [in] The bigint session context. + * @param bi [in] The bigint on which to perform the mod power operation. + * @param biexp [in] The bigint exponent. + * @return The result of the mod exponentiation operation + * @see bi_set_mod(). + */ +NS_INTERNAL bigint *bi_mod_power(BI_CTX *ctx, bigint *bi, bigint *biexp) { + int i = find_max_exp_index(biexp), j, window_size = 1; + bigint *biR = int_to_bi(ctx, 1); + +#if defined(CONFIG_BIGINT_MONTGOMERY) + uint8_t mod_offset = ctx->mod_offset; + if (!ctx->use_classical) { + /* preconvert */ + bi = bi_mont(ctx, + bi_multiply(ctx, bi, ctx->bi_RR_mod_m[mod_offset])); /* x' */ + bi_free(ctx, biR); + biR = ctx->bi_R_mod_m[mod_offset]; /* A */ + } +#endif + + check(bi); + check(biexp); + +#ifdef CONFIG_BIGINT_SLIDING_WINDOW + for (j = i; j > 32; j /= 5) /* work out an optimum size */ + window_size++; + + /* work out the slide constants */ + precompute_slide_window(ctx, window_size, bi); +#else /* just one constant */ + ctx->g = (bigint **) calloc(1, sizeof(bigint *)); + ctx->g[0] = bi_clone(ctx, bi); + ctx->window = 1; + bi_permanent(ctx->g[0]); +#endif + + /* if sliding-window is off, then only one bit will be done at a time and + * will reduce to standard left-to-right exponentiation */ + do { + if (exp_bit_is_one(biexp, i)) { + int l = i - window_size + 1; + int part_exp = 0; + + if (l < 0) /* LSB of exponent will always be 1 */ + l = 0; + else { + while (exp_bit_is_one(biexp, l) == 0) l++; /* go back up */ + } + + /* build up the section of the exponent */ + for (j = i; j >= l; j--) { + biR = bi_residue(ctx, bi_square(ctx, biR)); + if (exp_bit_is_one(biexp, j)) part_exp++; + + if (j != l) part_exp <<= 1; + } + + part_exp = (part_exp - 1) / 2; /* adjust for array */ + biR = bi_residue(ctx, bi_multiply(ctx, biR, ctx->g[part_exp])); + i = l - 1; + } else /* square it */ + { + biR = bi_residue(ctx, bi_square(ctx, biR)); + i--; + } + } while (i >= 0); + + /* cleanup */ + for (i = 0; i < ctx->window; i++) { + bi_depermanent(ctx->g[i]); + bi_free(ctx, ctx->g[i]); + } + + free(ctx->g); + bi_free(ctx, bi); + bi_free(ctx, biexp); +#if defined CONFIG_BIGINT_MONTGOMERY + return ctx->use_classical ? biR : bi_mont(ctx, biR); /* convert back */ +#else /* CONFIG_BIGINT_CLASSICAL or CONFIG_BIGINT_BARRETT */ + return biR; +#endif +} + +#if 0 +/** + * @brief Use the Chinese Remainder Theorem to quickly perform RSA decrypts. + * + * @param ctx [in] The bigint session context. + * @param bi [in] The bigint to perform the exp/mod. + * @param dP [in] CRT's dP bigint + * @param dQ [in] CRT's dQ bigint + * @param p [in] CRT's p bigint + * @param q [in] CRT's q bigint + * @param qInv [in] CRT's qInv bigint + * @return The result of the CRT operation + */ +NS_INTERNAL bigint *bi_crt(BI_CTX *ctx, bigint *bi, bigint *dP, bigint *dQ, + bigint *p, bigint *q, bigint *qInv) { + bigint *m1, *m2, *h; + +/* Montgomery has a condition the 0 < x, y < m and these products violate + * that condition. So disable Montgomery when using CRT */ +#if defined(CONFIG_BIGINT_MONTGOMERY) + ctx->use_classical = 1; +#endif + ctx->mod_offset = BIGINT_P_OFFSET; + m1 = bi_mod_power(ctx, bi_copy(bi), dP); + + ctx->mod_offset = BIGINT_Q_OFFSET; + m2 = bi_mod_power(ctx, bi, dQ); + + h = bi_subtract(ctx, bi_add(ctx, m1, p), bi_copy(m2), NULL); + h = bi_multiply(ctx, h, qInv); + ctx->mod_offset = BIGINT_P_OFFSET; + h = bi_residue(ctx, h); +#if defined(CONFIG_BIGINT_MONTGOMERY) + ctx->use_classical = 0; /* reset for any further operation */ +#endif + return bi_add(ctx, m2, bi_multiply(ctx, q, h)); +} +#endif + +int mg_rsa_mod_pow(const uint8_t *mod, size_t modsz, const uint8_t *exp, size_t expsz, const uint8_t *msg, size_t msgsz, uint8_t *out, size_t outsz) { + BI_CTX *bi_ctx = bi_initialize(); + bigint *n = bi_import(bi_ctx, mod, (int) modsz); + bigint *e = bi_import(bi_ctx, exp, (int) expsz); + bigint *h = bi_import(bi_ctx, msg, (int) msgsz); + bi_set_mod(bi_ctx, n, 0); + bigint *m1 = bi_mod_power(bi_ctx, h, e); + bi_export(bi_ctx, m1, out, (int) outsz); + bi_free(bi_ctx, n); + bi_free(bi_ctx, e); + bi_free(bi_ctx, h); + bi_free(bi_ctx, m1); + return 0; +} + +#endif /* MG_TLS == MG_TLS_BUILTIN */ diff --git a/src/tls_rsa.h b/src/tls_rsa.h new file mode 100644 index 00000000..63ffdffc --- /dev/null +++ b/src/tls_rsa.h @@ -0,0 +1,7 @@ +#ifndef TLS_RSA_H +#define TLS_RSA_H + +#include "arch.h" +int mg_rsa_mod_pow(const uint8_t *mod, size_t modsz, const uint8_t *exp, size_t expsz, const uint8_t *msg, size_t msgsz, uint8_t *out, size_t outsz); + +#endif // TLS_RSA_H diff --git a/src/util.h b/src/util.h index 7ae6f1a7..fc3229b7 100644 --- a/src/util.h +++ b/src/util.h @@ -42,6 +42,12 @@ bool mg_path_is_sane(const struct mg_str path); MG_U8P(p)[0] = ((n) >> 8U) & 255; \ MG_U8P(p)[1] = (n) &255; \ } while (0) +#define MG_STORE_BE24(p, n) \ + do { \ + MG_U8P(p)[0] = ((n) >> 16U) & 255; \ + MG_U8P(p)[1] = ((n) >> 8U) & 255; \ + MG_U8P(p)[2] = (n) &255; \ + } while (0) #define MG_REG(x) ((volatile uint32_t *) (x))[0] #define MG_BIT(x) (((uint32_t) 1U) << (x)) diff --git a/test/Makefile b/test/Makefile index 9057f3cd..01f1ff58 100644 --- a/test/Makefile +++ b/test/Makefile @@ -209,7 +209,7 @@ mongoose.c: Makefile $(wildcard ../src/*.c) $(wildcard ../src/drivers/*.c) cd .. && (export LC_ALL=C ; cat src/license.h; echo; echo '#include "mongoose.h"' ; (for F in src/*.c src/drivers/*.c ; do echo; echo '#ifdef MG_ENABLE_LINES'; echo "#line 1 \"$$F\""; echo '#endif'; cat $$F | sed -e 's,#include ".*,,'; done))> $@ mongoose.h: $(HDRS) Makefile - cd .. && (cat src/license.h; echo; echo '#ifndef MONGOOSE_H'; echo '#define MONGOOSE_H'; echo; cat src/version.h ; echo; echo '#ifdef __cplusplus'; echo 'extern "C" {'; echo '#endif'; cat src/arch.h src/arch_*.h src/net_ft.h src/net_lwip.h src/net_rl.h src/config.h src/str.h src/queue.h src/fmt.h src/printf.h src/log.h src/timer.h src/fs.h src/util.h src/url.h src/iobuf.h src/base64.h src/md5.h src/sha1.h src/sha256.h src/tls_x25519.h src/tls_aes128.h src/tls_uecc.h src/tls_chacha20.h src/event.h src/net.h src/http.h src/ssi.h src/tls.h src/tls_mbed.h src/tls_openssl.h src/ws.h src/sntp.h src/mqtt.h src/dns.h src/json.h src/rpc.h src/ota.h src/flash.h src/net_builtin.h src/profile.h src/drivers/*.h | sed -e '/keep/! s,#include ".*,,' -e 's,^#pragma once,,'; echo; echo '#ifdef __cplusplus'; echo '}'; echo '#endif'; echo '#endif // MONGOOSE_H')> $@ + cd .. && (cat src/license.h; echo; echo '#ifndef MONGOOSE_H'; echo '#define MONGOOSE_H'; echo; cat src/version.h ; echo; echo '#ifdef __cplusplus'; echo 'extern "C" {'; echo '#endif'; cat src/arch.h src/arch_*.h src/net_ft.h src/net_lwip.h src/net_rl.h src/config.h src/str.h src/queue.h src/fmt.h src/printf.h src/log.h src/timer.h src/fs.h src/util.h src/url.h src/iobuf.h src/base64.h src/md5.h src/sha1.h src/sha256.h src/tls_x25519.h src/tls_aes128.h src/tls_uecc.h src/tls_chacha20.h src/tls_rsa.h src/event.h src/net.h src/http.h src/ssi.h src/tls.h src/tls_mbed.h src/tls_openssl.h src/ws.h src/sntp.h src/mqtt.h src/dns.h src/json.h src/rpc.h src/ota.h src/flash.h src/net_builtin.h src/profile.h src/drivers/*.h | sed -e '/keep/! s,#include ".*,,' -e 's,^#pragma once,,'; echo; echo '#ifdef __cplusplus'; echo '}'; echo '#endif'; echo '#endif // MONGOOSE_H')> $@ clean: clean_examples clean_refprojs clean_tutorials clean_examples_embedded diff --git a/test/data/ca.pem b/test/data/ca.pem index 9091ef92..8eb5c1c2 100644 --- a/test/data/ca.pem +++ b/test/data/ca.pem @@ -1,5 +1,139 @@ - Make sure your PEM file starts with a dash - + +Issuer: C=US, O=Internet Security Research Group, CN=ISRG Root X1 +Not Before: Mar 13 00:00:00 2024 GMT +Not After : Mar 12 23:59:59 2027 GMT +-----BEGIN CERTIFICATE----- +MIIEVzCCAj+gAwIBAgIRALBXPpFzlydw27SHyzpFKzgwDQYJKoZIhvcNAQELBQAw +TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh +cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMjQwMzEzMDAwMDAw +WhcNMjcwMzEyMjM1OTU5WjAyMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3Mg +RW5jcnlwdDELMAkGA1UEAxMCRTYwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAATZ8Z5G +h/ghcWCoJuuj+rnq2h25EqfUJtlRFLFhfHWWvyILOR/VvtEKRqotPEoJhC6+QJVV +6RlAN2Z17TJOdwRJ+HB7wxjnzvdxEP6sdNgA1O1tHHMWMxCcOrLqbGL0vbijgfgw +gfUwDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcD +ATASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBSTJ0aYA6lRaI6Y1sRCSNsj +v1iU0jAfBgNVHSMEGDAWgBR5tFnme7bl5AFzgAiIyBpY9umbbjAyBggrBgEFBQcB +AQQmMCQwIgYIKwYBBQUHMAKGFmh0dHA6Ly94MS5pLmxlbmNyLm9yZy8wEwYDVR0g +BAwwCjAIBgZngQwBAgEwJwYDVR0fBCAwHjAcoBqgGIYWaHR0cDovL3gxLmMubGVu +Y3Iub3JnLzANBgkqhkiG9w0BAQsFAAOCAgEAfYt7SiA1sgWGCIpunk46r4AExIRc +MxkKgUhNlrrv1B21hOaXN/5miE+LOTbrcmU/M9yvC6MVY730GNFoL8IhJ8j8vrOL +pMY22OP6baS1k9YMrtDTlwJHoGby04ThTUeBDksS9RiuHvicZqBedQdIF65pZuhp +eDcGBcLiYasQr/EO5gxxtLyTmgsHSOVSBcFOn9lgv7LECPq9i7mfH3mpxgrRKSxH +pOoZ0KXMcB+hHuvlklHntvcI0mMMQ0mhYj6qtMFStkF1RpCG3IPdIwpVCQqu8GV7 +s8ubknRzs+3C/Bm19RFOoiPpDkwvyNfvmQ14XkyqqKK5oZ8zhD32kFRQkxa8uZSu +h4aTImFxknu39waBxIRXE4jKxlAmQc4QjFZoq1KmQqQg0J/1JF8RlFvJas1VcjLv +YlvUB2t6npO6oQjB3l+PNf0DpQH7iUx3Wz5AjQCi6L25FjyE06q6BZ/QlmtYdl/8 +ZYao4SRqPEs/6cAiF+Qf5zg2UkaWtDphl1LKMuTNLotvsX99HP69V2faNyegodQ0 +LyTApr/vT01YPE46vNsDLgK+4cL6TrzC/a4WcmF5SRJ938zrv/duJHLXQIku5v0+ +EwOy59Hdm0PT/Er/84dDV0CSjdR/2XuZM3kpysSKLgD1cKiDA+IRguODCxfO9cyY +Ig46v9mFmBvyH04= +-----END CERTIFICATE----- + + +Issuer: C=US, O=Internet Security Research Group, CN=ISRG Root X1 +Not Before: Mar 13 00:00:00 2024 GMT +Not After : Mar 12 23:59:59 2027 GMT +-----BEGIN CERTIFICATE----- +MIIEVzCCAj+gAwIBAgIRAIOPbGPOsTmMYgZigxXJ/d4wDQYJKoZIhvcNAQELBQAw +TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh +cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMjQwMzEzMDAwMDAw +WhcNMjcwMzEyMjM1OTU5WjAyMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3Mg +RW5jcnlwdDELMAkGA1UEAxMCRTUwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQNCzqK +a2GOtu/cX1jnxkJFVKtj9mZhSAouWXW0gQI3ULc/FnncmOyhKJdyIBwsz9V8UiBO +VHhbhBRrwJCuhezAUUE8Wod/Bk3U/mDR+mwt4X2VEIiiCFQPmRpM5uoKrNijgfgw +gfUwDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcD +ATASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBSfK1/PPCFPnQS37SssxMZw +i9LXDTAfBgNVHSMEGDAWgBR5tFnme7bl5AFzgAiIyBpY9umbbjAyBggrBgEFBQcB +AQQmMCQwIgYIKwYBBQUHMAKGFmh0dHA6Ly94MS5pLmxlbmNyLm9yZy8wEwYDVR0g +BAwwCjAIBgZngQwBAgEwJwYDVR0fBCAwHjAcoBqgGIYWaHR0cDovL3gxLmMubGVu +Y3Iub3JnLzANBgkqhkiG9w0BAQsFAAOCAgEAH3KdNEVCQdqk0LKyuNImTKdRJY1C +2uw2SJajuhqkyGPY8C+zzsufZ+mgnhnq1A2KVQOSykOEnUbx1cy637rBAihx97r+ +bcwbZM6sTDIaEriR/PLk6LKs9Be0uoVxgOKDcpG9svD33J+G9Lcfv1K9luDmSTgG +6XNFIN5vfI5gs/lMPyojEMdIzK9blcl2/1vKxO8WGCcjvsQ1nJ/Pwt8LQZBfOFyV +XP8ubAp/au3dc4EKWG9MO5zcx1qT9+NXRGdVWxGvmBFRAajciMfXME1ZuGmk3/GO +koAM7ZkjZmleyokP1LGzmfJcUd9s7eeu1/9/eg5XlXd/55GtYjAM+C4DG5i7eaNq +cm2F+yxYIPt6cbbtYVNJCGfHWqHEQ4FYStUyFnv8sjyqU8ypgZaNJ9aVcWSICLOI +E1/Qv/7oKsnZCWJ926wU6RqG1OYPGOi1zuABhLw61cuPVDT28nQS/e6z95cJXq0e +K1BcaJ6fJZsmbjRgD5p3mvEf5vdQM7MCEvU0tHbsx2I5mHHJoABHb8KVBgWp/lcX +GWiWaeOyB7RP+OfDtvi2OsapxXiV7vNVs7fMlrRjY1joKaqmmycnBvAq14AEbtyL +sVfOS66B8apkeFX2NY4XPEYV4ZSCe8VHPrdrERk2wILG3T/EGmSIkCYVUMSnjmJd +VQD9F6Na/+zmXCc= +-----END CERTIFICATE----- + + +Issuer: C=US, O=Google Trust Services LLC, CN=GTS Root R1 +Not Before: Jun 22 00:00:00 2016 GMT +Not After : Jun 22 00:00:00 2036 GMT +-----BEGIN CERTIFICATE----- +MIIFVzCCAz+gAwIBAgINAgPlk28xsBNJiGuiFzANBgkqhkiG9w0BAQwFADBHMQsw +CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU +MBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw +MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp +Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwggIiMA0GCSqGSIb3DQEBAQUA +A4ICDwAwggIKAoICAQC2EQKLHuOhd5s73L+UPreVp0A8of2C+X0yBoJx9vaMf/vo +27xqLpeXo4xL+Sv2sfnOhB2x+cWX3u+58qPpvBKJXqeqUqv4IyfLpLGcY9vXmX7w +Cl7raKb0xlpHDU0QM+NOsROjyBhsS+z8CZDfnWQpJSMHobTSPS5g4M/SCYe7zUjw +TcLCeoiKu7rPWRnWr4+wB7CeMfGCwcDfLqZtbBkOtdh+JhpFAz2weaSUKK0Pfybl +qAj+lug8aJRT7oM6iCsVlgmy4HqMLnXWnOunVmSPlk9orj2XwoSPwLxAwAtcvfaH +szVsrBhQf4TgTM2S0yDpM7xSma8ytSmzJSq0SPly4cpk9+aCEI3oncKKiPo4Zor8 +Y/kB+Xj9e1x3+naH+uzfsQ55lVe0vSbv1gHR6xYKu44LtcXFilWr06zqkUspzBmk +MiVOKvFlRNACzqrOSbTqn3yDsEB750Orp2yjj32JgfpMpf/VjsPOS+C12LOORc92 +wO1AK/1TD7Cn1TsNsYqiA94xrcx36m97PtbfkSIS5r762DL8EGMUUXLeXdYWk70p +aDPvOmbsB4om3xPXV2V4J95eSRQAogB/mqghtqmxlbCluQ0WEdrHbEg8QOB+DVrN +VjzRlwW5y0vtOUucxD/SVRNuJLDWcfr0wbrM7Rv1/oFB2ACYPTrIrnqYNxgFlQID +AQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E +FgQU5K8rJnEaK0gnhS9SZizv8IkTcT4wDQYJKoZIhvcNAQEMBQADggIBAJ+qQibb +C5u+/x6Wki4+omVKapi6Ist9wTrYggoGxval3sBOh2Z5ofmmWJyq+bXmYOfg6LEe +QkEzCzc9zolwFcq1JKjPa7XSQCGYzyI0zzvFIoTgxQ6KfF2I5DUkzps+GlQebtuy +h6f88/qBVRRiClmpIgUxPoLW7ttXNLwzldMXG+gnoot7TiYaelpkttGsN/H9oPM4 +7HLwEXWdyzRSjeZ2axfG34arJ45JK3VmgRAhpuo+9K4l/3wV3s6MJT/KYnAK9y8J +ZgfIPxz88NtFMN9iiMG1D53Dn0reWVlHxYciNuaCp+0KueIHoI17eko8cdLiA6Ef +MgfdG+RCzgwARWGAtQsgWSl4vflVy2PFPEz0tv/bal8xa5meLMFrUKTX5hgUvYU/ +Z6tGn6D/Qqc6f1zLXbBwHSs09dR2CQzreExZBfMzQsNhFRAbd03OIozUhfJFfbdT +6u9AWpQKXCBfTkBdYiJ23//OYb2MI3jSNwLgjt7RETeJ9r/tSQdirpLsQBqvFAnZ +0E6yove+7u7Y/9waLd64NnHi/Hm3lCXRSHNboTXns5lndcEZOitHTtNCjv0xyBZm +2tIMPNuzjsmhDYAPexZ3FL//2wmUspO8IFgV6dtxQ/PeEMMA3KgqlbbC1j+Qa3bb +bP6MvPJwNQzcmRk13NfIRmPVNnGuV/u3gm3c +-----END CERTIFICATE----- + + +Issuer: OU=GlobalSign ECC Root CA - R4, O=GlobalSign, CN=GlobalSign +Not Before: Nov 13 00:00:00 2012 GMT +Not After : Jan 19 03:14:07 2038 GMT +-----BEGIN CERTIFICATE----- +MIIB3DCCAYOgAwIBAgINAgPlfvU/k/2lCSGypjAKBggqhkjOPQQDAjBQMSQwIgYD +VQQLExtHbG9iYWxTaWduIEVDQyBSb290IENBIC0gUjQxEzARBgNVBAoTCkdsb2Jh +bFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMTIxMTEzMDAwMDAwWhcNMzgw +MTE5MDMxNDA3WjBQMSQwIgYDVQQLExtHbG9iYWxTaWduIEVDQyBSb290IENBIC0g +UjQxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wWTAT +BgcqhkjOPQIBBggqhkjOPQMBBwNCAAS4xnnTj2wlDp8uORkcA6SumuU5BwkWymOx +uYb4ilfBV85C+nOh92VC/x7BALJucw7/xyHlGKSq2XE/qNS5zowdo0IwQDAOBgNV +HQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUVLB7rUW44kB/ ++wpu+74zyTyjhNUwCgYIKoZIzj0EAwIDRwAwRAIgIk90crlgr/HmnKAWBVBfw147 +bmF0774BxL4YSFlhgjICICadVGNA3jdgUM/I2O2dgq43mLyjj0xMqTQrbO/7lZsm +-----END CERTIFICATE----- + + +Issuer: C=US, O=Google Trust Services LLC, CN=GTS Root R4 +Not Before: Jun 22 00:00:00 2016 GMT +Not After : Jun 22 00:00:00 2036 GMT +-----BEGIN CERTIFICATE----- +MIICCTCCAY6gAwIBAgINAgPlwGjvYxqccpBQUjAKBggqhkjOPQQDAzBHMQswCQYD +VQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIG +A1UEAxMLR1RTIFJvb3QgUjQwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAw +WjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2Vz +IExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjQwdjAQBgcqhkjOPQIBBgUrgQQAIgNi +AATzdHOnaItgrkO4NcWBMHtLSZ37wWHO5t5GvWvVYRg1rkDdc/eJkTBa6zzuhXyi +QHY7qca4R9gq55KRanPpsXI5nymfopjTX15YhmUPoYRlBtHci8nHc8iMai/lxKvR +HYqjQjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW +BBSATNbrdP9JNqPV2Py1PsVq8JQdjDAKBggqhkjOPQQDAwNpADBmAjEA6ED/g94D +9J+uHXqnLrmvT/aDHQ4thQEd0dlq7A/Cr8deVl5c1RxYIigL9zC2L7F8AjEA8GE8 +p/SgguMh1YQdc4acLa/KNJvxn7kjNuK8YAOdgLOaVsjh4rsUecrNIdSUtUlD +-----END CERTIFICATE----- + + Issuer: C = US, O = Internet Security Research Group, CN = ISRG Root X1 Not Before: Jun 4 11:04:38 2015 GMT Not After : Jun 4 11:04:38 2035 GMT diff --git a/test/unit_test.c b/test/unit_test.c index 67ea5bb7..e1a00692 100644 --- a/test/unit_test.c +++ b/test/unit_test.c @@ -1327,7 +1327,7 @@ static void test_tls(void) { "Content-Length: %lu\n\n" "%s", data.len, data.buf) == 200); -#if MG_TLS == MG_TLS_BUILTIN +#if MG_TLS == MG_TLS_BUILTIN && defined(__linux__) // fire patched server, test multiple TLS records per TCP segment handling // skip other TLS stacks to avoid "bad client hello", we are 1.3 only { diff --git a/tutorials/http/http-client/packed_fs.c b/tutorials/http/http-client/packed_fs.c index a54b0a04..a0118d6e 100644 --- a/tutorials/http/http-client/packed_fs.c +++ b/tutorials/http/http-client/packed_fs.c @@ -16,6 +16,595 @@ static const unsigned char v1[] = { 121, 111, 117, 114, 32, 80, 69, 77, 32, 102, 105, 108, // your PEM fil 101, 32, 115, 116, 97, 114, 116, 115, 32, 119, 105, 116, // e starts wit 104, 32, 97, 32, 100, 97, 115, 104, 32, 45, 10, 10, // h a dash -.. + 10, 45, 45, 45, 45, 45, 66, 69, 71, 73, 78, 32, // .-----BEGIN + 67, 69, 82, 84, 73, 70, 73, 67, 65, 84, 69, 45, // CERTIFICATE- + 45, 45, 45, 45, 10, 77, 73, 73, 69, 86, 122, 67, // ----.MIIEVzC + 67, 65, 106, 43, 103, 65, 119, 73, 66, 65, 103, 73, // CAj+gAwIBAgI + 82, 65, 76, 66, 88, 80, 112, 70, 122, 108, 121, 100, // RALBXPpFzlyd + 119, 50, 55, 83, 72, 121, 122, 112, 70, 75, 122, 103, // w27SHyzpFKzg + 119, 68, 81, 89, 74, 75, 111, 90, 73, 104, 118, 99, // wDQYJKoZIhvc + 78, 65, 81, 69, 76, 66, 81, 65, 119, 10, 84, 122, // NAQELBQAw.Tz + 69, 76, 77, 65, 107, 71, 65, 49, 85, 69, 66, 104, // ELMAkGA1UEBh + 77, 67, 86, 86, 77, 120, 75, 84, 65, 110, 66, 103, // MCVVMxKTAnBg + 78, 86, 66, 65, 111, 84, 73, 69, 108, 117, 100, 71, // NVBAoTIEludG + 86, 121, 98, 109, 86, 48, 73, 70, 78, 108, 89, 51, // VybmV0IFNlY3 + 86, 121, 97, 88, 82, 53, 73, 70, 74, 108, 99, 50, // VyaXR5IFJlc2 + 86, 104, 10, 99, 109, 78, 111, 73, 69, 100, 121, 98, // Vh.cmNoIEdyb + 51, 86, 119, 77, 82, 85, 119, 69, 119, 89, 68, 86, // 3VwMRUwEwYDV + 81, 81, 68, 69, 119, 120, 74, 85, 49, 74, 72, 73, // QQDEwxJU1JHI + 70, 74, 118, 98, 51, 81, 103, 87, 68, 69, 119, 72, // FJvb3QgWDEwH + 104, 99, 78, 77, 106, 81, 119, 77, 122, 69, 122, 77, // hcNMjQwMzEzM + 68, 65, 119, 77, 68, 65, 119, 10, 87, 104, 99, 78, // DAwMDAw.WhcN + 77, 106, 99, 119, 77, 122, 69, 121, 77, 106, 77, 49, // MjcwMzEyMjM1 + 79, 84, 85, 53, 87, 106, 65, 121, 77, 81, 115, 119, // OTU5WjAyMQsw + 67, 81, 89, 68, 86, 81, 81, 71, 69, 119, 74, 86, // CQYDVQQGEwJV + 85, 122, 69, 87, 77, 66, 81, 71, 65, 49, 85, 69, // UzEWMBQGA1UE + 67, 104, 77, 78, 84, 71, 86, 48, 74, 51, 77, 103, // ChMNTGV0J3Mg + 10, 82, 87, 53, 106, 99, 110, 108, 119, 100, 68, 69, // .RW5jcnlwdDE + 76, 77, 65, 107, 71, 65, 49, 85, 69, 65, 120, 77, // LMAkGA1UEAxM + 67, 82, 84, 89, 119, 100, 106, 65, 81, 66, 103, 99, // CRTYwdjAQBgc + 113, 104, 107, 106, 79, 80, 81, 73, 66, 66, 103, 85, // qhkjOPQIBBgU + 114, 103, 81, 81, 65, 73, 103, 78, 105, 65, 65, 84, // rgQQAIgNiAAT + 90, 56, 90, 53, 71, 10, 104, 47, 103, 104, 99, 87, // Z8Z5G.h/ghcW + 67, 111, 74, 117, 117, 106, 43, 114, 110, 113, 50, 104, // CoJuuj+rnq2h + 50, 53, 69, 113, 102, 85, 74, 116, 108, 82, 70, 76, // 25EqfUJtlRFL + 70, 104, 102, 72, 87, 87, 118, 121, 73, 76, 79, 82, // FhfHWWvyILOR + 47, 86, 118, 116, 69, 75, 82, 113, 111, 116, 80, 69, // /VvtEKRqotPE + 111, 74, 104, 67, 54, 43, 81, 74, 86, 86, 10, 54, // oJhC6+QJVV.6 + 82, 108, 65, 78, 50, 90, 49, 55, 84, 74, 79, 100, // RlAN2Z17TJOd + 119, 82, 74, 43, 72, 66, 55, 119, 120, 106, 110, 122, // wRJ+HB7wxjnz + 118, 100, 120, 69, 80, 54, 115, 100, 78, 103, 65, 49, // vdxEP6sdNgA1 + 79, 49, 116, 72, 72, 77, 87, 77, 120, 67, 99, 79, // O1tHHMWMxCcO + 114, 76, 113, 98, 71, 76, 48, 118, 98, 105, 106, 103, // rLqbGL0vbijg + 102, 103, 119, 10, 103, 102, 85, 119, 68, 103, 89, 68, // fgw.gfUwDgYD + 86, 82, 48, 80, 65, 81, 72, 47, 66, 65, 81, 68, // VR0PAQH/BAQD + 65, 103, 71, 71, 77, 66, 48, 71, 65, 49, 85, 100, // AgGGMB0GA1Ud + 74, 81, 81, 87, 77, 66, 81, 71, 67, 67, 115, 71, // JQQWMBQGCCsG + 65, 81, 85, 70, 66, 119, 77, 67, 66, 103, 103, 114, // AQUFBwMCBggr + 66, 103, 69, 70, 66, 81, 99, 68, 10, 65, 84, 65, // BgEFBQcD.ATA + 83, 66, 103, 78, 86, 72, 82, 77, 66, 65, 102, 56, // SBgNVHRMBAf8 + 69, 67, 68, 65, 71, 65, 81, 72, 47, 65, 103, 69, // ECDAGAQH/AgE + 65, 77, 66, 48, 71, 65, 49, 85, 100, 68, 103, 81, // AMB0GA1UdDgQ + 87, 66, 66, 83, 84, 74, 48, 97, 89, 65, 54, 108, // WBBSTJ0aYA6l + 82, 97, 73, 54, 89, 49, 115, 82, 67, 83, 78, 115, // RaI6Y1sRCSNs + 106, 10, 118, 49, 105, 85, 48, 106, 65, 102, 66, 103, // j.v1iU0jAfBg + 78, 86, 72, 83, 77, 69, 71, 68, 65, 87, 103, 66, // NVHSMEGDAWgB + 82, 53, 116, 70, 110, 109, 101, 55, 98, 108, 53, 65, // R5tFnme7bl5A + 70, 122, 103, 65, 105, 73, 121, 66, 112, 89, 57, 117, // FzgAiIyBpY9u + 109, 98, 98, 106, 65, 121, 66, 103, 103, 114, 66, 103, // mbbjAyBggrBg + 69, 70, 66, 81, 99, 66, 10, 65, 81, 81, 109, 77, // EFBQcB.AQQmM + 67, 81, 119, 73, 103, 89, 73, 75, 119, 89, 66, 66, // CQwIgYIKwYBB + 81, 85, 72, 77, 65, 75, 71, 70, 109, 104, 48, 100, // QUHMAKGFmh0d + 72, 65, 54, 76, 121, 57, 52, 77, 83, 53, 112, 76, // HA6Ly94MS5pL + 109, 120, 108, 98, 109, 78, 121, 76, 109, 57, 121, 90, // mxlbmNyLm9yZ + 121, 56, 119, 69, 119, 89, 68, 86, 82, 48, 103, 10, // y8wEwYDVR0g. + 66, 65, 119, 119, 67, 106, 65, 73, 66, 103, 90, 110, // BAwwCjAIBgZn + 103, 81, 119, 66, 65, 103, 69, 119, 74, 119, 89, 68, // gQwBAgEwJwYD + 86, 82, 48, 102, 66, 67, 65, 119, 72, 106, 65, 99, // VR0fBCAwHjAc + 111, 66, 113, 103, 71, 73, 89, 87, 97, 72, 82, 48, // oBqgGIYWaHR0 + 99, 68, 111, 118, 76, 51, 103, 120, 76, 109, 77, 117, // cDovL3gxLmMu + 98, 71, 86, 117, 10, 89, 51, 73, 117, 98, 51, 74, // bGVu.Y3Iub3J + 110, 76, 122, 65, 78, 66, 103, 107, 113, 104, 107, 105, // nLzANBgkqhki + 71, 57, 119, 48, 66, 65, 81, 115, 70, 65, 65, 79, // G9w0BAQsFAAO + 67, 65, 103, 69, 65, 102, 89, 116, 55, 83, 105, 65, // CAgEAfYt7SiA + 49, 115, 103, 87, 71, 67, 73, 112, 117, 110, 107, 52, // 1sgWGCIpunk4 + 54, 114, 52, 65, 69, 120, 73, 82, 99, 10, 77, 120, // 6r4AExIRc.Mx + 107, 75, 103, 85, 104, 78, 108, 114, 114, 118, 49, 66, // kKgUhNlrrv1B + 50, 49, 104, 79, 97, 88, 78, 47, 53, 109, 105, 69, // 21hOaXN/5miE + 43, 76, 79, 84, 98, 114, 99, 109, 85, 47, 77, 57, // +LOTbrcmU/M9 + 121, 118, 67, 54, 77, 86, 89, 55, 51, 48, 71, 78, // yvC6MVY730GN + 70, 111, 76, 56, 73, 104, 74, 56, 106, 56, 118, 114, // FoL8IhJ8j8vr + 79, 76, 10, 112, 77, 89, 50, 50, 79, 80, 54, 98, // OL.pMY22OP6b + 97, 83, 49, 107, 57, 89, 77, 114, 116, 68, 84, 108, // aS1k9YMrtDTl + 119, 74, 72, 111, 71, 98, 121, 48, 52, 84, 104, 84, // wJHoGby04ThT + 85, 101, 66, 68, 107, 115, 83, 57, 82, 105, 117, 72, // UeBDksS9RiuH + 118, 105, 99, 90, 113, 66, 101, 100, 81, 100, 73, 70, // vicZqBedQdIF + 54, 53, 112, 90, 117, 104, 112, 10, 101, 68, 99, 71, // 65pZuhp.eDcG + 66, 99, 76, 105, 89, 97, 115, 81, 114, 47, 69, 79, // BcLiYasQr/EO + 53, 103, 120, 120, 116, 76, 121, 84, 109, 103, 115, 72, // 5gxxtLyTmgsH + 83, 79, 86, 83, 66, 99, 70, 79, 110, 57, 108, 103, // SOVSBcFOn9lg + 118, 55, 76, 69, 67, 80, 113, 57, 105, 55, 109, 102, // v7LECPq9i7mf + 72, 51, 109, 112, 120, 103, 114, 82, 75, 83, 120, 72, // H3mpxgrRKSxH + 10, 112, 79, 111, 90, 48, 75, 88, 77, 99, 66, 43, // .pOoZ0KXMcB+ + 104, 72, 117, 118, 108, 107, 108, 72, 110, 116, 118, 99, // hHuvlklHntvc + 73, 48, 109, 77, 77, 81, 48, 109, 104, 89, 106, 54, // I0mMMQ0mhYj6 + 113, 116, 77, 70, 83, 116, 107, 70, 49, 82, 112, 67, // qtMFStkF1RpC + 71, 51, 73, 80, 100, 73, 119, 112, 86, 67, 81, 113, // G3IPdIwpVCQq + 117, 56, 71, 86, 55, 10, 115, 56, 117, 98, 107, 110, // u8GV7.s8ubkn + 82, 122, 115, 43, 51, 67, 47, 66, 109, 49, 57, 82, // Rzs+3C/Bm19R + 70, 79, 111, 105, 80, 112, 68, 107, 119, 118, 121, 78, // FOoiPpDkwvyN + 102, 118, 109, 81, 49, 52, 88, 107, 121, 113, 113, 75, // fvmQ14XkyqqK + 75, 53, 111, 90, 56, 122, 104, 68, 51, 50, 107, 70, // K5oZ8zhD32kF + 82, 81, 107, 120, 97, 56, 117, 90, 83, 117, 10, 104, // RQkxa8uZSu.h + 52, 97, 84, 73, 109, 70, 120, 107, 110, 117, 51, 57, // 4aTImFxknu39 + 119, 97, 66, 120, 73, 82, 88, 69, 52, 106, 75, 120, // waBxIRXE4jKx + 108, 65, 109, 81, 99, 52, 81, 106, 70, 90, 111, 113, // lAmQc4QjFZoq + 49, 75, 109, 81, 113, 81, 103, 48, 74, 47, 49, 74, // 1KmQqQg0J/1J + 70, 56, 82, 108, 70, 118, 74, 97, 115, 49, 86, 99, // F8RlFvJas1Vc + 106, 76, 118, 10, 89, 108, 118, 85, 66, 50, 116, 54, // jLv.YlvUB2t6 + 110, 112, 79, 54, 111, 81, 106, 66, 51, 108, 43, 80, // npO6oQjB3l+P + 78, 102, 48, 68, 112, 81, 72, 55, 105, 85, 120, 51, // Nf0DpQH7iUx3 + 87, 122, 53, 65, 106, 81, 67, 105, 54, 76, 50, 53, // Wz5AjQCi6L25 + 70, 106, 121, 69, 48, 54, 113, 54, 66, 90, 47, 81, // FjyE06q6BZ/Q + 108, 109, 116, 89, 100, 108, 47, 56, 10, 90, 89, 97, // lmtYdl/8.ZYa + 111, 52, 83, 82, 113, 80, 69, 115, 47, 54, 99, 65, // o4SRqPEs/6cA + 105, 70, 43, 81, 102, 53, 122, 103, 50, 85, 107, 97, // iF+Qf5zg2Uka + 87, 116, 68, 112, 104, 108, 49, 76, 75, 77, 117, 84, // WtDphl1LKMuT + 78, 76, 111, 116, 118, 115, 88, 57, 57, 72, 80, 54, // NLotvsX99HP6 + 57, 86, 50, 102, 97, 78, 121, 101, 103, 111, 100, 81, // 9V2faNyegodQ + 48, 10, 76, 121, 84, 65, 112, 114, 47, 118, 84, 48, // 0.LyTApr/vT0 + 49, 89, 80, 69, 52, 54, 118, 78, 115, 68, 76, 103, // 1YPE46vNsDLg + 75, 43, 52, 99, 76, 54, 84, 114, 122, 67, 47, 97, // K+4cL6TrzC/a + 52, 87, 99, 109, 70, 53, 83, 82, 74, 57, 51, 56, // 4WcmF5SRJ938 + 122, 114, 118, 47, 100, 117, 74, 72, 76, 88, 81, 73, // zrv/duJHLXQI + 107, 117, 53, 118, 48, 43, 10, 69, 119, 79, 121, 53, // ku5v0+.EwOy5 + 57, 72, 100, 109, 48, 80, 84, 47, 69, 114, 47, 56, // 9Hdm0PT/Er/8 + 52, 100, 68, 86, 48, 67, 83, 106, 100, 82, 47, 50, // 4dDV0CSjdR/2 + 88, 117, 90, 77, 51, 107, 112, 121, 115, 83, 75, 76, // XuZM3kpysSKL + 103, 68, 49, 99, 75, 105, 68, 65, 43, 73, 82, 103, // gD1cKiDA+IRg + 117, 79, 68, 67, 120, 102, 79, 57, 99, 121, 89, 10, // uODCxfO9cyY. + 73, 103, 52, 54, 118, 57, 109, 70, 109, 66, 118, 121, // Ig46v9mFmBvy + 72, 48, 52, 61, 10, 45, 45, 45, 45, 45, 69, 78, // H04=.-----EN + 68, 32, 67, 69, 82, 84, 73, 70, 73, 67, 65, 84, // D CERTIFICAT + 69, 45, 45, 45, 45, 45, 10, 10, 73, 115, 115, 117, // E-----..Issu + 101, 114, 58, 32, 67, 61, 85, 83, 44, 32, 79, 61, // er: C=US, O= + 73, 110, 116, 101, 114, 110, 101, 116, 32, 83, 101, 99, // Internet Sec + 117, 114, 105, 116, 121, 32, 82, 101, 115, 101, 97, 114, // urity Resear + 99, 104, 32, 71, 114, 111, 117, 112, 44, 32, 67, 78, // ch Group, CN + 61, 73, 83, 82, 71, 32, 82, 111, 111, 116, 32, 88, // =ISRG Root X + 49, 10, 78, 111, 116, 32, 66, 101, 102, 111, 114, 101, // 1.Not Before + 58, 32, 77, 97, 114, 32, 49, 51, 32, 48, 48, 58, // : Mar 13 00: + 48, 48, 58, 48, 48, 32, 50, 48, 50, 52, 32, 71, // 00:00 2024 G + 77, 84, 10, 78, 111, 116, 32, 65, 102, 116, 101, 114, // MT.Not After + 32, 58, 32, 77, 97, 114, 32, 49, 50, 32, 50, 51, // : Mar 12 23 + 58, 53, 57, 58, 53, 57, 32, 50, 48, 50, 55, 32, // :59:59 2027 + 71, 77, 84, 10, 45, 45, 45, 45, 45, 66, 69, 71, // GMT.-----BEG + 73, 78, 32, 67, 69, 82, 84, 73, 70, 73, 67, 65, // IN CERTIFICA + 84, 69, 45, 45, 45, 45, 45, 10, 77, 73, 73, 69, // TE-----.MIIE + 86, 122, 67, 67, 65, 106, 43, 103, 65, 119, 73, 66, // VzCCAj+gAwIB + 65, 103, 73, 82, 65, 73, 79, 80, 98, 71, 80, 79, // AgIRAIOPbGPO + 115, 84, 109, 77, 89, 103, 90, 105, 103, 120, 88, 74, // sTmMYgZigxXJ + 47, 100, 52, 119, 68, 81, 89, 74, 75, 111, 90, 73, // /d4wDQYJKoZI + 104, 118, 99, 78, 65, 81, 69, 76, 66, 81, 65, 119, // hvcNAQELBQAw + 10, 84, 122, 69, 76, 77, 65, 107, 71, 65, 49, 85, // .TzELMAkGA1U + 69, 66, 104, 77, 67, 86, 86, 77, 120, 75, 84, 65, // EBhMCVVMxKTA + 110, 66, 103, 78, 86, 66, 65, 111, 84, 73, 69, 108, // nBgNVBAoTIEl + 117, 100, 71, 86, 121, 98, 109, 86, 48, 73, 70, 78, // udGVybmV0IFN + 108, 89, 51, 86, 121, 97, 88, 82, 53, 73, 70, 74, // lY3VyaXR5IFJ + 108, 99, 50, 86, 104, 10, 99, 109, 78, 111, 73, 69, // lc2Vh.cmNoIE + 100, 121, 98, 51, 86, 119, 77, 82, 85, 119, 69, 119, // dyb3VwMRUwEw + 89, 68, 86, 81, 81, 68, 69, 119, 120, 74, 85, 49, // YDVQQDEwxJU1 + 74, 72, 73, 70, 74, 118, 98, 51, 81, 103, 87, 68, // JHIFJvb3QgWD + 69, 119, 72, 104, 99, 78, 77, 106, 81, 119, 77, 122, // EwHhcNMjQwMz + 69, 122, 77, 68, 65, 119, 77, 68, 65, 119, 10, 87, // EzMDAwMDAw.W + 104, 99, 78, 77, 106, 99, 119, 77, 122, 69, 121, 77, // hcNMjcwMzEyM + 106, 77, 49, 79, 84, 85, 53, 87, 106, 65, 121, 77, // jM1OTU5WjAyM + 81, 115, 119, 67, 81, 89, 68, 86, 81, 81, 71, 69, // QswCQYDVQQGE + 119, 74, 86, 85, 122, 69, 87, 77, 66, 81, 71, 65, // wJVUzEWMBQGA + 49, 85, 69, 67, 104, 77, 78, 84, 71, 86, 48, 74, // 1UEChMNTGV0J + 51, 77, 103, 10, 82, 87, 53, 106, 99, 110, 108, 119, // 3Mg.RW5jcnlw + 100, 68, 69, 76, 77, 65, 107, 71, 65, 49, 85, 69, // dDELMAkGA1UE + 65, 120, 77, 67, 82, 84, 85, 119, 100, 106, 65, 81, // AxMCRTUwdjAQ + 66, 103, 99, 113, 104, 107, 106, 79, 80, 81, 73, 66, // BgcqhkjOPQIB + 66, 103, 85, 114, 103, 81, 81, 65, 73, 103, 78, 105, // BgUrgQQAIgNi + 65, 65, 81, 78, 67, 122, 113, 75, 10, 97, 50, 71, // AAQNCzqK.a2G + 79, 116, 117, 47, 99, 88, 49, 106, 110, 120, 107, 74, // Otu/cX1jnxkJ + 70, 86, 75, 116, 106, 57, 109, 90, 104, 83, 65, 111, // FVKtj9mZhSAo + 117, 87, 88, 87, 48, 103, 81, 73, 51, 85, 76, 99, // uWXW0gQI3ULc + 47, 70, 110, 110, 99, 109, 79, 121, 104, 75, 74, 100, // /FnncmOyhKJd + 121, 73, 66, 119, 115, 122, 57, 86, 56, 85, 105, 66, // yIBwsz9V8UiB + 79, 10, 86, 72, 104, 98, 104, 66, 82, 114, 119, 74, // O.VHhbhBRrwJ + 67, 117, 104, 101, 122, 65, 85, 85, 69, 56, 87, 111, // CuhezAUUE8Wo + 100, 47, 66, 107, 51, 85, 47, 109, 68, 82, 43, 109, // d/Bk3U/mDR+m + 119, 116, 52, 88, 50, 86, 69, 73, 105, 105, 67, 70, // wt4X2VEIiiCF + 81, 80, 109, 82, 112, 77, 53, 117, 111, 75, 114, 78, // QPmRpM5uoKrN + 105, 106, 103, 102, 103, 119, 10, 103, 102, 85, 119, 68, // ijgfgw.gfUwD + 103, 89, 68, 86, 82, 48, 80, 65, 81, 72, 47, 66, // gYDVR0PAQH/B + 65, 81, 68, 65, 103, 71, 71, 77, 66, 48, 71, 65, // AQDAgGGMB0GA + 49, 85, 100, 74, 81, 81, 87, 77, 66, 81, 71, 67, // 1UdJQQWMBQGC + 67, 115, 71, 65, 81, 85, 70, 66, 119, 77, 67, 66, // CsGAQUFBwMCB + 103, 103, 114, 66, 103, 69, 70, 66, 81, 99, 68, 10, // ggrBgEFBQcD. + 65, 84, 65, 83, 66, 103, 78, 86, 72, 82, 77, 66, // ATASBgNVHRMB + 65, 102, 56, 69, 67, 68, 65, 71, 65, 81, 72, 47, // Af8ECDAGAQH/ + 65, 103, 69, 65, 77, 66, 48, 71, 65, 49, 85, 100, // AgEAMB0GA1Ud + 68, 103, 81, 87, 66, 66, 83, 102, 75, 49, 47, 80, // DgQWBBSfK1/P + 80, 67, 70, 80, 110, 81, 83, 51, 55, 83, 115, 115, // PCFPnQS37Sss + 120, 77, 90, 119, 10, 105, 57, 76, 88, 68, 84, 65, // xMZw.i9LXDTA + 102, 66, 103, 78, 86, 72, 83, 77, 69, 71, 68, 65, // fBgNVHSMEGDA + 87, 103, 66, 82, 53, 116, 70, 110, 109, 101, 55, 98, // WgBR5tFnme7b + 108, 53, 65, 70, 122, 103, 65, 105, 73, 121, 66, 112, // l5AFzgAiIyBp + 89, 57, 117, 109, 98, 98, 106, 65, 121, 66, 103, 103, // Y9umbbjAyBgg + 114, 66, 103, 69, 70, 66, 81, 99, 66, 10, 65, 81, // rBgEFBQcB.AQ + 81, 109, 77, 67, 81, 119, 73, 103, 89, 73, 75, 119, // QmMCQwIgYIKw + 89, 66, 66, 81, 85, 72, 77, 65, 75, 71, 70, 109, // YBBQUHMAKGFm + 104, 48, 100, 72, 65, 54, 76, 121, 57, 52, 77, 83, // h0dHA6Ly94MS + 53, 112, 76, 109, 120, 108, 98, 109, 78, 121, 76, 109, // 5pLmxlbmNyLm + 57, 121, 90, 121, 56, 119, 69, 119, 89, 68, 86, 82, // 9yZy8wEwYDVR + 48, 103, 10, 66, 65, 119, 119, 67, 106, 65, 73, 66, // 0g.BAwwCjAIB + 103, 90, 110, 103, 81, 119, 66, 65, 103, 69, 119, 74, // gZngQwBAgEwJ + 119, 89, 68, 86, 82, 48, 102, 66, 67, 65, 119, 72, // wYDVR0fBCAwH + 106, 65, 99, 111, 66, 113, 103, 71, 73, 89, 87, 97, // jAcoBqgGIYWa + 72, 82, 48, 99, 68, 111, 118, 76, 51, 103, 120, 76, // HR0cDovL3gxL + 109, 77, 117, 98, 71, 86, 117, 10, 89, 51, 73, 117, // mMubGVu.Y3Iu + 98, 51, 74, 110, 76, 122, 65, 78, 66, 103, 107, 113, // b3JnLzANBgkq + 104, 107, 105, 71, 57, 119, 48, 66, 65, 81, 115, 70, // hkiG9w0BAQsF + 65, 65, 79, 67, 65, 103, 69, 65, 72, 51, 75, 100, // AAOCAgEAH3Kd + 78, 69, 86, 67, 81, 100, 113, 107, 48, 76, 75, 121, // NEVCQdqk0LKy + 117, 78, 73, 109, 84, 75, 100, 82, 74, 89, 49, 67, // uNImTKdRJY1C + 10, 50, 117, 119, 50, 83, 74, 97, 106, 117, 104, 113, // .2uw2SJajuhq + 107, 121, 71, 80, 89, 56, 67, 43, 122, 122, 115, 117, // kyGPY8C+zzsu + 102, 90, 43, 109, 103, 110, 104, 110, 113, 49, 65, 50, // fZ+mgnhnq1A2 + 75, 86, 81, 79, 83, 121, 107, 79, 69, 110, 85, 98, // KVQOSykOEnUb + 120, 49, 99, 121, 54, 51, 55, 114, 66, 65, 105, 104, // x1cy637rBAih + 120, 57, 55, 114, 43, 10, 98, 99, 119, 98, 90, 77, // x97r+.bcwbZM + 54, 115, 84, 68, 73, 97, 69, 114, 105, 82, 47, 80, // 6sTDIaEriR/P + 76, 107, 54, 76, 75, 115, 57, 66, 101, 48, 117, 111, // Lk6LKs9Be0uo + 86, 120, 103, 79, 75, 68, 99, 112, 71, 57, 115, 118, // VxgOKDcpG9sv + 68, 51, 51, 74, 43, 71, 57, 76, 99, 102, 118, 49, // D33J+G9Lcfv1 + 75, 57, 108, 117, 68, 109, 83, 84, 103, 71, 10, 54, // K9luDmSTgG.6 + 88, 78, 70, 73, 78, 53, 118, 102, 73, 53, 103, 115, // XNFIN5vfI5gs + 47, 108, 77, 80, 121, 111, 106, 69, 77, 100, 73, 122, // /lMPyojEMdIz + 75, 57, 98, 108, 99, 108, 50, 47, 49, 118, 75, 120, // K9blcl2/1vKx + 79, 56, 87, 71, 67, 99, 106, 118, 115, 81, 49, 110, // O8WGCcjvsQ1n + 74, 47, 80, 119, 116, 56, 76, 81, 90, 66, 102, 79, // J/Pwt8LQZBfO + 70, 121, 86, 10, 88, 80, 56, 117, 98, 65, 112, 47, // FyV.XP8ubAp/ + 97, 117, 51, 100, 99, 52, 69, 75, 87, 71, 57, 77, // au3dc4EKWG9M + 79, 53, 122, 99, 120, 49, 113, 84, 57, 43, 78, 88, // O5zcx1qT9+NX + 82, 71, 100, 86, 87, 120, 71, 118, 109, 66, 70, 82, // RGdVWxGvmBFR + 65, 97, 106, 99, 105, 77, 102, 88, 77, 69, 49, 90, // AajciMfXME1Z + 117, 71, 109, 107, 51, 47, 71, 79, 10, 107, 111, 65, // uGmk3/GO.koA + 77, 55, 90, 107, 106, 90, 109, 108, 101, 121, 111, 107, // M7ZkjZmleyok + 80, 49, 76, 71, 122, 109, 102, 74, 99, 85, 100, 57, // P1LGzmfJcUd9 + 115, 55, 101, 101, 117, 49, 47, 57, 47, 101, 103, 53, // s7eeu1/9/eg5 + 88, 108, 88, 100, 47, 53, 53, 71, 116, 89, 106, 65, // XlXd/55GtYjA + 77, 43, 67, 52, 68, 71, 53, 105, 55, 101, 97, 78, // M+C4DG5i7eaN + 113, 10, 99, 109, 50, 70, 43, 121, 120, 89, 73, 80, // q.cm2F+yxYIP + 116, 54, 99, 98, 98, 116, 89, 86, 78, 74, 67, 71, // t6cbbtYVNJCG + 102, 72, 87, 113, 72, 69, 81, 52, 70, 89, 83, 116, // fHWqHEQ4FYSt + 85, 121, 70, 110, 118, 56, 115, 106, 121, 113, 85, 56, // UyFnv8sjyqU8 + 121, 112, 103, 90, 97, 78, 74, 57, 97, 86, 99, 87, // ypgZaNJ9aVcW + 83, 73, 67, 76, 79, 73, 10, 69, 49, 47, 81, 118, // SICLOI.E1/Qv + 47, 55, 111, 75, 115, 110, 90, 67, 87, 74, 57, 50, // /7oKsnZCWJ92 + 54, 119, 85, 54, 82, 113, 71, 49, 79, 89, 80, 71, // 6wU6RqG1OYPG + 79, 105, 49, 122, 117, 65, 66, 104, 76, 119, 54, 49, // Oi1zuABhLw61 + 99, 117, 80, 86, 68, 84, 50, 56, 110, 81, 83, 47, // cuPVDT28nQS/ + 101, 54, 122, 57, 53, 99, 74, 88, 113, 48, 101, 10, // e6z95cJXq0e. + 75, 49, 66, 99, 97, 74, 54, 102, 74, 90, 115, 109, // K1BcaJ6fJZsm + 98, 106, 82, 103, 68, 53, 112, 51, 109, 118, 69, 102, // bjRgD5p3mvEf + 53, 118, 100, 81, 77, 55, 77, 67, 69, 118, 85, 48, // 5vdQM7MCEvU0 + 116, 72, 98, 115, 120, 50, 73, 53, 109, 72, 72, 74, // tHbsx2I5mHHJ + 111, 65, 66, 72, 98, 56, 75, 86, 66, 103, 87, 112, // oABHb8KVBgWp + 47, 108, 99, 88, 10, 71, 87, 105, 87, 97, 101, 79, // /lcX.GWiWaeO + 121, 66, 55, 82, 80, 43, 79, 102, 68, 116, 118, 105, // yB7RP+OfDtvi + 50, 79, 115, 97, 112, 120, 88, 105, 86, 55, 118, 78, // 2OsapxXiV7vN + 86, 115, 55, 102, 77, 108, 114, 82, 106, 89, 49, 106, // Vs7fMlrRjY1j + 111, 75, 97, 113, 109, 109, 121, 99, 110, 66, 118, 65, // oKaqmmycnBvA + 113, 49, 52, 65, 69, 98, 116, 121, 76, 10, 115, 86, // q14AEbtyL.sV + 102, 79, 83, 54, 54, 66, 56, 97, 112, 107, 101, 70, // fOS66B8apkeF + 88, 50, 78, 89, 52, 88, 80, 69, 89, 86, 52, 90, // X2NY4XPEYV4Z + 83, 67, 101, 56, 86, 72, 80, 114, 100, 114, 69, 82, // SCe8VHPrdrER + 107, 50, 119, 73, 76, 71, 51, 84, 47, 69, 71, 109, // k2wILG3T/EGm + 83, 73, 107, 67, 89, 86, 85, 77, 83, 110, 106, 109, // SIkCYVUMSnjm + 74, 100, 10, 86, 81, 68, 57, 70, 54, 78, 97, 47, // Jd.VQD9F6Na/ + 43, 122, 109, 88, 67, 99, 61, 10, 45, 45, 45, 45, // +zmXCc=.---- + 45, 69, 78, 68, 32, 67, 69, 82, 84, 73, 70, 73, // -END CERTIFI + 67, 65, 84, 69, 45, 45, 45, 45, 45, 10, 10, 10, // CATE-----... + 73, 115, 115, 117, 101, 114, 58, 32, 67, 61, 85, 83, // Issuer: C=US + 44, 32, 79, 61, 71, 111, 111, 103, 108, 101, 32, 84, // , O=Google T + 114, 117, 115, 116, 32, 83, 101, 114, 118, 105, 99, 101, // rust Service + 115, 32, 76, 76, 67, 44, 32, 67, 78, 61, 71, 84, // s LLC, CN=GT + 83, 32, 82, 111, 111, 116, 32, 82, 49, 10, 78, 111, // S Root R1.No + 116, 32, 66, 101, 102, 111, 114, 101, 58, 32, 74, 117, // t Before: Ju + 110, 32, 50, 50, 32, 48, 48, 58, 48, 48, 58, 48, // n 22 00:00:0 + 48, 32, 50, 48, 49, 54, 32, 71, 77, 84, 10, 78, // 0 2016 GMT.N + 111, 116, 32, 65, 102, 116, 101, 114, 32, 58, 32, 74, // ot After : J + 117, 110, 32, 50, 50, 32, 48, 48, 58, 48, 48, 58, // un 22 00:00: + 48, 48, 32, 50, 48, 51, 54, 32, 71, 77, 84, 10, // 00 2036 GMT. + 45, 45, 45, 45, 45, 66, 69, 71, 73, 78, 32, 67, // -----BEGIN C + 69, 82, 84, 73, 70, 73, 67, 65, 84, 69, 45, 45, // ERTIFICATE-- + 45, 45, 45, 10, 77, 73, 73, 70, 86, 122, 67, 67, // ---.MIIFVzCC + 65, 122, 43, 103, 65, 119, 73, 66, 65, 103, 73, 78, // Az+gAwIBAgIN + 65, 103, 80, 108, 107, 50, 56, 120, 115, 66, 78, 74, // AgPlk28xsBNJ + 105, 71, 117, 105, 70, 122, 65, 78, 66, 103, 107, 113, // iGuiFzANBgkq + 104, 107, 105, 71, 57, 119, 48, 66, 65, 81, 119, 70, // hkiG9w0BAQwF + 65, 68, 66, 72, 77, 81, 115, 119, 10, 67, 81, 89, // ADBHMQsw.CQY + 68, 86, 81, 81, 71, 69, 119, 74, 86, 85, 122, 69, // DVQQGEwJVUzE + 105, 77, 67, 65, 71, 65, 49, 85, 69, 67, 104, 77, // iMCAGA1UEChM + 90, 82, 50, 57, 118, 90, 50, 120, 108, 73, 70, 82, // ZR29vZ2xlIFR + 121, 100, 88, 78, 48, 73, 70, 78, 108, 99, 110, 90, // ydXN0IFNlcnZ + 112, 89, 50, 86, 122, 73, 69, 120, 77, 81, 122, 69, // pY2VzIExMQzE + 85, 10, 77, 66, 73, 71, 65, 49, 85, 69, 65, 120, // U.MBIGA1UEAx + 77, 76, 82, 49, 82, 84, 73, 70, 74, 118, 98, 51, // MLR1RTIFJvb3 + 81, 103, 85, 106, 69, 119, 72, 104, 99, 78, 77, 84, // QgUjEwHhcNMT + 89, 119, 78, 106, 73, 121, 77, 68, 65, 119, 77, 68, // YwNjIyMDAwMD + 65, 119, 87, 104, 99, 78, 77, 122, 89, 119, 78, 106, // AwWhcNMzYwNj + 73, 121, 77, 68, 65, 119, 10, 77, 68, 65, 119, 87, // IyMDAw.MDAwW + 106, 66, 72, 77, 81, 115, 119, 67, 81, 89, 68, 86, // jBHMQswCQYDV + 81, 81, 71, 69, 119, 74, 86, 85, 122, 69, 105, 77, // QQGEwJVUzEiM + 67, 65, 71, 65, 49, 85, 69, 67, 104, 77, 90, 82, // CAGA1UEChMZR + 50, 57, 118, 90, 50, 120, 108, 73, 70, 82, 121, 100, // 29vZ2xlIFRyd + 88, 78, 48, 73, 70, 78, 108, 99, 110, 90, 112, 10, // XN0IFNlcnZp. + 89, 50, 86, 122, 73, 69, 120, 77, 81, 122, 69, 85, // Y2VzIExMQzEU + 77, 66, 73, 71, 65, 49, 85, 69, 65, 120, 77, 76, // MBIGA1UEAxML + 82, 49, 82, 84, 73, 70, 74, 118, 98, 51, 81, 103, // R1RTIFJvb3Qg + 85, 106, 69, 119, 103, 103, 73, 105, 77, 65, 48, 71, // UjEwggIiMA0G + 67, 83, 113, 71, 83, 73, 98, 51, 68, 81, 69, 66, // CSqGSIb3DQEB + 65, 81, 85, 65, 10, 65, 52, 73, 67, 68, 119, 65, // AQUA.A4ICDwA + 119, 103, 103, 73, 75, 65, 111, 73, 67, 65, 81, 67, // wggIKAoICAQC + 50, 69, 81, 75, 76, 72, 117, 79, 104, 100, 53, 115, // 2EQKLHuOhd5s + 55, 51, 76, 43, 85, 80, 114, 101, 86, 112, 48, 65, // 73L+UPreVp0A + 56, 111, 102, 50, 67, 43, 88, 48, 121, 66, 111, 74, // 8of2C+X0yBoJ + 120, 57, 118, 97, 77, 102, 47, 118, 111, 10, 50, 55, // x9vaMf/vo.27 + 120, 113, 76, 112, 101, 88, 111, 52, 120, 76, 43, 83, // xqLpeXo4xL+S + 118, 50, 115, 102, 110, 79, 104, 66, 50, 120, 43, 99, // v2sfnOhB2x+c + 87, 88, 51, 117, 43, 53, 56, 113, 80, 112, 118, 66, // WX3u+58qPpvB + 75, 74, 88, 113, 101, 113, 85, 113, 118, 52, 73, 121, // KJXqeqUqv4Iy + 102, 76, 112, 76, 71, 99, 89, 57, 118, 88, 109, 88, // fLpLGcY9vXmX + 55, 119, 10, 67, 108, 55, 114, 97, 75, 98, 48, 120, // 7w.Cl7raKb0x + 108, 112, 72, 68, 85, 48, 81, 77, 43, 78, 79, 115, // lpHDU0QM+NOs + 82, 79, 106, 121, 66, 104, 115, 83, 43, 122, 56, 67, // ROjyBhsS+z8C + 90, 68, 102, 110, 87, 81, 112, 74, 83, 77, 72, 111, // ZDfnWQpJSMHo + 98, 84, 83, 80, 83, 53, 103, 52, 77, 47, 83, 67, // bTSPS5g4M/SC + 89, 101, 55, 122, 85, 106, 119, 10, 84, 99, 76, 67, // Ye7zUjw.TcLC + 101, 111, 105, 75, 117, 55, 114, 80, 87, 82, 110, 87, // eoiKu7rPWRnW + 114, 52, 43, 119, 66, 55, 67, 101, 77, 102, 71, 67, // r4+wB7CeMfGC + 119, 99, 68, 102, 76, 113, 90, 116, 98, 66, 107, 79, // wcDfLqZtbBkO + 116, 100, 104, 43, 74, 104, 112, 70, 65, 122, 50, 119, // tdh+JhpFAz2w + 101, 97, 83, 85, 75, 75, 48, 80, 102, 121, 98, 108, // eaSUKK0Pfybl + 10, 113, 65, 106, 43, 108, 117, 103, 56, 97, 74, 82, // .qAj+lug8aJR + 84, 55, 111, 77, 54, 105, 67, 115, 86, 108, 103, 109, // T7oM6iCsVlgm + 121, 52, 72, 113, 77, 76, 110, 88, 87, 110, 79, 117, // y4HqMLnXWnOu + 110, 86, 109, 83, 80, 108, 107, 57, 111, 114, 106, 50, // nVmSPlk9orj2 + 88, 119, 111, 83, 80, 119, 76, 120, 65, 119, 65, 116, // XwoSPwLxAwAt + 99, 118, 102, 97, 72, 10, 115, 122, 86, 115, 114, 66, // cvfaH.szVsrB + 104, 81, 102, 52, 84, 103, 84, 77, 50, 83, 48, 121, // hQf4TgTM2S0y + 68, 112, 77, 55, 120, 83, 109, 97, 56, 121, 116, 83, // DpM7xSma8ytS + 109, 122, 74, 83, 113, 48, 83, 80, 108, 121, 52, 99, // mzJSq0SPly4c + 112, 107, 57, 43, 97, 67, 69, 73, 51, 111, 110, 99, // pk9+aCEI3onc + 75, 75, 105, 80, 111, 52, 90, 111, 114, 56, 10, 89, // KKiPo4Zor8.Y + 47, 107, 66, 43, 88, 106, 57, 101, 49, 120, 51, 43, // /kB+Xj9e1x3+ + 110, 97, 72, 43, 117, 122, 102, 115, 81, 53, 53, 108, // naH+uzfsQ55l + 86, 101, 48, 118, 83, 98, 118, 49, 103, 72, 82, 54, // Ve0vSbv1gHR6 + 120, 89, 75, 117, 52, 52, 76, 116, 99, 88, 70, 105, // xYKu44LtcXFi + 108, 87, 114, 48, 54, 122, 113, 107, 85, 115, 112, 122, // lWr06zqkUspz + 66, 109, 107, 10, 77, 105, 86, 79, 75, 118, 70, 108, // Bmk.MiVOKvFl + 82, 78, 65, 67, 122, 113, 114, 79, 83, 98, 84, 113, // RNACzqrOSbTq + 110, 51, 121, 68, 115, 69, 66, 55, 53, 48, 79, 114, // n3yDsEB750Or + 112, 50, 121, 106, 106, 51, 50, 74, 103, 102, 112, 77, // p2yjj32JgfpM + 112, 102, 47, 86, 106, 115, 80, 79, 83, 43, 67, 49, // pf/VjsPOS+C1 + 50, 76, 79, 79, 82, 99, 57, 50, 10, 119, 79, 49, // 2LOORc92.wO1 + 65, 75, 47, 49, 84, 68, 55, 67, 110, 49, 84, 115, // AK/1TD7Cn1Ts + 78, 115, 89, 113, 105, 65, 57, 52, 120, 114, 99, 120, // NsYqiA94xrcx + 51, 54, 109, 57, 55, 80, 116, 98, 102, 107, 83, 73, // 36m97PtbfkSI + 83, 53, 114, 55, 54, 50, 68, 76, 56, 69, 71, 77, // S5r762DL8EGM + 85, 85, 88, 76, 101, 88, 100, 89, 87, 107, 55, 48, // UUXLeXdYWk70 + 112, 10, 97, 68, 80, 118, 79, 109, 98, 115, 66, 52, // p.aDPvOmbsB4 + 111, 109, 51, 120, 80, 88, 86, 50, 86, 52, 74, 57, // om3xPXV2V4J9 + 53, 101, 83, 82, 81, 65, 111, 103, 66, 47, 109, 113, // 5eSRQAogB/mq + 103, 104, 116, 113, 109, 120, 108, 98, 67, 108, 117, 81, // ghtqmxlbCluQ + 48, 87, 69, 100, 114, 72, 98, 69, 103, 56, 81, 79, // 0WEdrHbEg8QO + 66, 43, 68, 86, 114, 78, 10, 86, 106, 122, 82, 108, // B+DVrN.VjzRl + 119, 87, 53, 121, 48, 118, 116, 79, 85, 117, 99, 120, // wW5y0vtOUucx + 68, 47, 83, 86, 82, 78, 117, 74, 76, 68, 87, 99, // D/SVRNuJLDWc + 102, 114, 48, 119, 98, 114, 77, 55, 82, 118, 49, 47, // fr0wbrM7Rv1/ + 111, 70, 66, 50, 65, 67, 89, 80, 84, 114, 73, 114, // oFB2ACYPTrIr + 110, 113, 89, 78, 120, 103, 70, 108, 81, 73, 68, 10, // nqYNxgFlQID. + 65, 81, 65, 66, 111, 48, 73, 119, 81, 68, 65, 79, // AQABo0IwQDAO + 66, 103, 78, 86, 72, 81, 56, 66, 65, 102, 56, 69, // BgNVHQ8BAf8E + 66, 65, 77, 67, 65, 89, 89, 119, 68, 119, 89, 68, // BAMCAYYwDwYD + 86, 82, 48, 84, 65, 81, 72, 47, 66, 65, 85, 119, // VR0TAQH/BAUw + 65, 119, 69, 66, 47, 122, 65, 100, 66, 103, 78, 86, // AwEB/zAdBgNV + 72, 81, 52, 69, 10, 70, 103, 81, 85, 53, 75, 56, // HQ4E.FgQU5K8 + 114, 74, 110, 69, 97, 75, 48, 103, 110, 104, 83, 57, // rJnEaK0gnhS9 + 83, 90, 105, 122, 118, 56, 73, 107, 84, 99, 84, 52, // SZizv8IkTcT4 + 119, 68, 81, 89, 74, 75, 111, 90, 73, 104, 118, 99, // wDQYJKoZIhvc + 78, 65, 81, 69, 77, 66, 81, 65, 68, 103, 103, 73, // NAQEMBQADggI + 66, 65, 74, 43, 113, 81, 105, 98, 98, 10, 67, 53, // BAJ+qQibb.C5 + 117, 43, 47, 120, 54, 87, 107, 105, 52, 43, 111, 109, // u+/x6Wki4+om + 86, 75, 97, 112, 105, 54, 73, 115, 116, 57, 119, 84, // VKapi6Ist9wT + 114, 89, 103, 103, 111, 71, 120, 118, 97, 108, 51, 115, // rYggoGxval3s + 66, 79, 104, 50, 90, 53, 111, 102, 109, 109, 87, 74, // BOh2Z5ofmmWJ + 121, 113, 43, 98, 88, 109, 89, 79, 102, 103, 54, 76, // yq+bXmYOfg6L + 69, 101, 10, 81, 107, 69, 122, 67, 122, 99, 57, 122, // Ee.QkEzCzc9z + 111, 108, 119, 70, 99, 113, 49, 74, 75, 106, 80, 97, // olwFcq1JKjPa + 55, 88, 83, 81, 67, 71, 89, 122, 121, 73, 48, 122, // 7XSQCGYzyI0z + 122, 118, 70, 73, 111, 84, 103, 120, 81, 54, 75, 102, // zvFIoTgxQ6Kf + 70, 50, 73, 53, 68, 85, 107, 122, 112, 115, 43, 71, // F2I5DUkzps+G + 108, 81, 101, 98, 116, 117, 121, 10, 104, 54, 102, 56, // lQebtuy.h6f8 + 56, 47, 113, 66, 86, 82, 82, 105, 67, 108, 109, 112, // 8/qBVRRiClmp + 73, 103, 85, 120, 80, 111, 76, 87, 55, 116, 116, 88, // IgUxPoLW7ttX + 78, 76, 119, 122, 108, 100, 77, 88, 71, 43, 103, 110, // NLwzldMXG+gn + 111, 111, 116, 55, 84, 105, 89, 97, 101, 108, 112, 107, // oot7TiYaelpk + 116, 116, 71, 115, 78, 47, 72, 57, 111, 80, 77, 52, // ttGsN/H9oPM4 + 10, 55, 72, 76, 119, 69, 88, 87, 100, 121, 122, 82, // .7HLwEXWdyzR + 83, 106, 101, 90, 50, 97, 120, 102, 71, 51, 52, 97, // SjeZ2axfG34a + 114, 74, 52, 53, 74, 75, 51, 86, 109, 103, 82, 65, // rJ45JK3VmgRA + 104, 112, 117, 111, 43, 57, 75, 52, 108, 47, 51, 119, // hpuo+9K4l/3w + 86, 51, 115, 54, 77, 74, 84, 47, 75, 89, 110, 65, // V3s6MJT/KYnA + 75, 57, 121, 56, 74, 10, 90, 103, 102, 73, 80, 120, // K9y8J.ZgfIPx + 122, 56, 56, 78, 116, 70, 77, 78, 57, 105, 105, 77, // z88NtFMN9iiM + 71, 49, 68, 53, 51, 68, 110, 48, 114, 101, 87, 86, // G1D53Dn0reWV + 108, 72, 120, 89, 99, 105, 78, 117, 97, 67, 112, 43, // lHxYciNuaCp+ + 48, 75, 117, 101, 73, 72, 111, 73, 49, 55, 101, 107, // 0KueIHoI17ek + 111, 56, 99, 100, 76, 105, 65, 54, 69, 102, 10, 77, // o8cdLiA6Ef.M + 103, 102, 100, 71, 43, 82, 67, 122, 103, 119, 65, 82, // gfdG+RCzgwAR + 87, 71, 65, 116, 81, 115, 103, 87, 83, 108, 52, 118, // WGAtQsgWSl4v + 102, 108, 86, 121, 50, 80, 70, 80, 69, 122, 48, 116, // flVy2PFPEz0t + 118, 47, 98, 97, 108, 56, 120, 97, 53, 109, 101, 76, // v/bal8xa5meL + 77, 70, 114, 85, 75, 84, 88, 53, 104, 103, 85, 118, // MFrUKTX5hgUv + 89, 85, 47, 10, 90, 54, 116, 71, 110, 54, 68, 47, // YU/.Z6tGn6D/ + 81, 113, 99, 54, 102, 49, 122, 76, 88, 98, 66, 119, // Qqc6f1zLXbBw + 72, 83, 115, 48, 57, 100, 82, 50, 67, 81, 122, 114, // HSs09dR2CQzr + 101, 69, 120, 90, 66, 102, 77, 122, 81, 115, 78, 104, // eExZBfMzQsNh + 70, 82, 65, 98, 100, 48, 51, 79, 73, 111, 122, 85, // FRAbd03OIozU + 104, 102, 74, 70, 102, 98, 100, 84, 10, 54, 117, 57, // hfJFfbdT.6u9 + 65, 87, 112, 81, 75, 88, 67, 66, 102, 84, 107, 66, // AWpQKXCBfTkB + 100, 89, 105, 74, 50, 51, 47, 47, 79, 89, 98, 50, // dYiJ23//OYb2 + 77, 73, 51, 106, 83, 78, 119, 76, 103, 106, 116, 55, // MI3jSNwLgjt7 + 82, 69, 84, 101, 74, 57, 114, 47, 116, 83, 81, 100, // RETeJ9r/tSQd + 105, 114, 112, 76, 115, 81, 66, 113, 118, 70, 65, 110, // irpLsQBqvFAn + 90, 10, 48, 69, 54, 121, 111, 118, 101, 43, 55, 117, // Z.0E6yove+7u + 55, 89, 47, 57, 119, 97, 76, 100, 54, 52, 78, 110, // 7Y/9waLd64Nn + 72, 105, 47, 72, 109, 51, 108, 67, 88, 82, 83, 72, // Hi/Hm3lCXRSH + 78, 98, 111, 84, 88, 110, 115, 53, 108, 110, 100, 99, // NboTXns5lndc + 69, 90, 79, 105, 116, 72, 84, 116, 78, 67, 106, 118, // EZOitHTtNCjv + 48, 120, 121, 66, 90, 109, 10, 50, 116, 73, 77, 80, // 0xyBZm.2tIMP + 78, 117, 122, 106, 115, 109, 104, 68, 89, 65, 80, 101, // NuzjsmhDYAPe + 120, 90, 51, 70, 76, 47, 47, 50, 119, 109, 85, 115, // xZ3FL//2wmUs + 112, 79, 56, 73, 70, 103, 86, 54, 100, 116, 120, 81, // pO8IFgV6dtxQ + 47, 80, 101, 69, 77, 77, 65, 51, 75, 103, 113, 108, // /PeEMMA3Kgql + 98, 98, 67, 49, 106, 43, 81, 97, 51, 98, 98, 10, // bbC1j+Qa3bb. + 98, 80, 54, 77, 118, 80, 74, 119, 78, 81, 122, 99, // bP6MvPJwNQzc + 109, 82, 107, 49, 51, 78, 102, 73, 82, 109, 80, 86, // mRk13NfIRmPV + 78, 110, 71, 117, 86, 47, 117, 51, 103, 109, 51, 99, // NnGuV/u3gm3c + 10, 45, 45, 45, 45, 45, 69, 78, 68, 32, 67, 69, // .-----END CE + 82, 84, 73, 70, 73, 67, 65, 84, 69, 45, 45, 45, // RTIFICATE--- + 45, 45, 10, 10, 10, 73, 115, 115, 117, 101, 114, 58, // --...Issuer: + 32, 79, 85, 61, 71, 108, 111, 98, 97, 108, 83, 105, // OU=GlobalSi + 103, 110, 32, 69, 67, 67, 32, 82, 111, 111, 116, 32, // gn ECC Root + 67, 65, 32, 45, 32, 82, 52, 44, 32, 79, 61, 71, // CA - R4, O=G + 108, 111, 98, 97, 108, 83, 105, 103, 110, 44, 32, 67, // lobalSign, C + 78, 61, 71, 108, 111, 98, 97, 108, 83, 105, 103, 110, // N=GlobalSign + 10, 78, 111, 116, 32, 66, 101, 102, 111, 114, 101, 58, // .Not Before: + 32, 78, 111, 118, 32, 49, 51, 32, 48, 48, 58, 48, // Nov 13 00:0 + 48, 58, 48, 48, 32, 50, 48, 49, 50, 32, 71, 77, // 0:00 2012 GM + 84, 10, 78, 111, 116, 32, 65, 102, 116, 101, 114, 32, // T.Not After + 58, 32, 74, 97, 110, 32, 49, 57, 32, 48, 51, 58, // : Jan 19 03: + 49, 52, 58, 48, 55, 32, 50, 48, 51, 56, 32, 71, // 14:07 2038 G + 77, 84, 10, 45, 45, 45, 45, 45, 66, 69, 71, 73, // MT.-----BEGI + 78, 32, 67, 69, 82, 84, 73, 70, 73, 67, 65, 84, // N CERTIFICAT + 69, 45, 45, 45, 45, 45, 10, 77, 73, 73, 66, 51, // E-----.MIIB3 + 68, 67, 67, 65, 89, 79, 103, 65, 119, 73, 66, 65, // DCCAYOgAwIBA + 103, 73, 78, 65, 103, 80, 108, 102, 118, 85, 47, 107, // gINAgPlfvU/k + 47, 50, 108, 67, 83, 71, 121, 112, 106, 65, 75, 66, // /2lCSGypjAKB + 103, 103, 113, 104, 107, 106, 79, 80, 81, 81, 68, 65, // ggqhkjOPQQDA + 106, 66, 81, 77, 83, 81, 119, 73, 103, 89, 68, 10, // jBQMSQwIgYD. + 86, 81, 81, 76, 69, 120, 116, 72, 98, 71, 57, 105, // VQQLExtHbG9i + 89, 87, 120, 84, 97, 87, 100, 117, 73, 69, 86, 68, // YWxTaWduIEVD + 81, 121, 66, 83, 98, 50, 57, 48, 73, 69, 78, 66, // QyBSb290IENB + 73, 67, 48, 103, 85, 106, 81, 120, 69, 122, 65, 82, // IC0gUjQxEzAR + 66, 103, 78, 86, 66, 65, 111, 84, 67, 107, 100, 115, // BgNVBAoTCkds + 98, 50, 74, 104, 10, 98, 70, 78, 112, 90, 50, 52, // b2Jh.bFNpZ24 + 120, 69, 122, 65, 82, 66, 103, 78, 86, 66, 65, 77, // xEzARBgNVBAM + 84, 67, 107, 100, 115, 98, 50, 74, 104, 98, 70, 78, // TCkdsb2JhbFN + 112, 90, 50, 52, 119, 72, 104, 99, 78, 77, 84, 73, // pZ24wHhcNMTI + 120, 77, 84, 69, 122, 77, 68, 65, 119, 77, 68, 65, // xMTEzMDAwMDA + 119, 87, 104, 99, 78, 77, 122, 103, 119, 10, 77, 84, // wWhcNMzgw.MT + 69, 53, 77, 68, 77, 120, 78, 68, 65, 51, 87, 106, // E5MDMxNDA3Wj + 66, 81, 77, 83, 81, 119, 73, 103, 89, 68, 86, 81, // BQMSQwIgYDVQ + 81, 76, 69, 120, 116, 72, 98, 71, 57, 105, 89, 87, // QLExtHbG9iYW + 120, 84, 97, 87, 100, 117, 73, 69, 86, 68, 81, 121, // xTaWduIEVDQy + 66, 83, 98, 50, 57, 48, 73, 69, 78, 66, 73, 67, // BSb290IENBIC + 48, 103, 10, 85, 106, 81, 120, 69, 122, 65, 82, 66, // 0g.UjQxEzARB + 103, 78, 86, 66, 65, 111, 84, 67, 107, 100, 115, 98, // gNVBAoTCkdsb + 50, 74, 104, 98, 70, 78, 112, 90, 50, 52, 120, 69, // 2JhbFNpZ24xE + 122, 65, 82, 66, 103, 78, 86, 66, 65, 77, 84, 67, // zARBgNVBAMTC + 107, 100, 115, 98, 50, 74, 104, 98, 70, 78, 112, 90, // kdsb2JhbFNpZ + 50, 52, 119, 87, 84, 65, 84, 10, 66, 103, 99, 113, // 24wWTAT.Bgcq + 104, 107, 106, 79, 80, 81, 73, 66, 66, 103, 103, 113, // hkjOPQIBBggq + 104, 107, 106, 79, 80, 81, 77, 66, 66, 119, 78, 67, // hkjOPQMBBwNC + 65, 65, 83, 52, 120, 110, 110, 84, 106, 50, 119, 108, // AAS4xnnTj2wl + 68, 112, 56, 117, 79, 82, 107, 99, 65, 54, 83, 117, // Dp8uORkcA6Su + 109, 117, 85, 53, 66, 119, 107, 87, 121, 109, 79, 120, // muU5BwkWymOx + 10, 117, 89, 98, 52, 105, 108, 102, 66, 86, 56, 53, // .uYb4ilfBV85 + 67, 43, 110, 79, 104, 57, 50, 86, 67, 47, 120, 55, // C+nOh92VC/x7 + 66, 65, 76, 74, 117, 99, 119, 55, 47, 120, 121, 72, // BALJucw7/xyH + 108, 71, 75, 83, 113, 50, 88, 69, 47, 113, 78, 83, // lGKSq2XE/qNS + 53, 122, 111, 119, 100, 111, 48, 73, 119, 81, 68, 65, // 5zowdo0IwQDA + 79, 66, 103, 78, 86, 10, 72, 81, 56, 66, 65, 102, // OBgNV.HQ8BAf + 56, 69, 66, 65, 77, 67, 65, 89, 89, 119, 68, 119, // 8EBAMCAYYwDw + 89, 68, 86, 82, 48, 84, 65, 81, 72, 47, 66, 65, // YDVR0TAQH/BA + 85, 119, 65, 119, 69, 66, 47, 122, 65, 100, 66, 103, // UwAwEB/zAdBg + 78, 86, 72, 81, 52, 69, 70, 103, 81, 85, 86, 76, // NVHQ4EFgQUVL + 66, 55, 114, 85, 87, 52, 52, 107, 66, 47, 10, 43, // B7rUW44kB/.+ + 119, 112, 117, 43, 55, 52, 122, 121, 84, 121, 106, 104, // wpu+74zyTyjh + 78, 85, 119, 67, 103, 89, 73, 75, 111, 90, 73, 122, // NUwCgYIKoZIz + 106, 48, 69, 65, 119, 73, 68, 82, 119, 65, 119, 82, // j0EAwIDRwAwR + 65, 73, 103, 73, 107, 57, 48, 99, 114, 108, 103, 114, // AIgIk90crlgr + 47, 72, 109, 110, 75, 65, 87, 66, 86, 66, 102, 119, // /HmnKAWBVBfw + 49, 52, 55, 10, 98, 109, 70, 48, 55, 55, 52, 66, // 147.bmF0774B + 120, 76, 52, 89, 83, 70, 108, 104, 103, 106, 73, 67, // xL4YSFlhgjIC + 73, 67, 97, 100, 86, 71, 78, 65, 51, 106, 100, 103, // ICadVGNA3jdg + 85, 77, 47, 73, 50, 79, 50, 100, 103, 113, 52, 51, // UM/I2O2dgq43 + 109, 76, 121, 106, 106, 48, 120, 77, 113, 84, 81, 114, // mLyjj0xMqTQr + 98, 79, 47, 55, 108, 90, 115, 109, 10, 45, 45, 45, // bO/7lZsm.--- + 45, 45, 69, 78, 68, 32, 67, 69, 82, 84, 73, 70, // --END CERTIF + 73, 67, 65, 84, 69, 45, 45, 45, 45, 45, 10, 10, // ICATE-----.. + 10, 73, 115, 115, 117, 101, 114, 58, 32, 67, 61, 85, // .Issuer: C=U + 83, 44, 32, 79, 61, 71, 111, 111, 103, 108, 101, 32, // S, O=Google + 84, 114, 117, 115, 116, 32, 83, 101, 114, 118, 105, 99, // Trust Servic + 101, 115, 32, 76, 76, 67, 44, 32, 67, 78, 61, 71, // es LLC, CN=G + 84, 83, 32, 82, 111, 111, 116, 32, 82, 52, 10, 78, // TS Root R4.N + 111, 116, 32, 66, 101, 102, 111, 114, 101, 58, 32, 74, // ot Before: J + 117, 110, 32, 50, 50, 32, 48, 48, 58, 48, 48, 58, // un 22 00:00: + 48, 48, 32, 50, 48, 49, 54, 32, 71, 77, 84, 10, // 00 2016 GMT. + 78, 111, 116, 32, 65, 102, 116, 101, 114, 32, 58, 32, // Not After : + 74, 117, 110, 32, 50, 50, 32, 48, 48, 58, 48, 48, // Jun 22 00:00 + 58, 48, 48, 32, 50, 48, 51, 54, 32, 71, 77, 84, // :00 2036 GMT + 10, 45, 45, 45, 45, 45, 66, 69, 71, 73, 78, 32, // .-----BEGIN + 67, 69, 82, 84, 73, 70, 73, 67, 65, 84, 69, 45, // CERTIFICATE- + 45, 45, 45, 45, 10, 77, 73, 73, 67, 67, 84, 67, // ----.MIICCTC + 67, 65, 89, 54, 103, 65, 119, 73, 66, 65, 103, 73, // CAY6gAwIBAgI + 78, 65, 103, 80, 108, 119, 71, 106, 118, 89, 120, 113, // NAgPlwGjvYxq + 99, 99, 112, 66, 81, 85, 106, 65, 75, 66, 103, 103, // ccpBQUjAKBgg + 113, 104, 107, 106, 79, 80, 81, 81, 68, 65, 122, 66, // qhkjOPQQDAzB + 72, 77, 81, 115, 119, 67, 81, 89, 68, 10, 86, 81, // HMQswCQYD.VQ + 81, 71, 69, 119, 74, 86, 85, 122, 69, 105, 77, 67, // QGEwJVUzEiMC + 65, 71, 65, 49, 85, 69, 67, 104, 77, 90, 82, 50, // AGA1UEChMZR2 + 57, 118, 90, 50, 120, 108, 73, 70, 82, 121, 100, 88, // 9vZ2xlIFRydX + 78, 48, 73, 70, 78, 108, 99, 110, 90, 112, 89, 50, // N0IFNlcnZpY2 + 86, 122, 73, 69, 120, 77, 81, 122, 69, 85, 77, 66, // VzIExMQzEUMB + 73, 71, 10, 65, 49, 85, 69, 65, 120, 77, 76, 82, // IG.A1UEAxMLR + 49, 82, 84, 73, 70, 74, 118, 98, 51, 81, 103, 85, // 1RTIFJvb3QgU + 106, 81, 119, 72, 104, 99, 78, 77, 84, 89, 119, 78, // jQwHhcNMTYwN + 106, 73, 121, 77, 68, 65, 119, 77, 68, 65, 119, 87, // jIyMDAwMDAwW + 104, 99, 78, 77, 122, 89, 119, 78, 106, 73, 121, 77, // hcNMzYwNjIyM + 68, 65, 119, 77, 68, 65, 119, 10, 87, 106, 66, 72, // DAwMDAw.WjBH + 77, 81, 115, 119, 67, 81, 89, 68, 86, 81, 81, 71, // MQswCQYDVQQG + 69, 119, 74, 86, 85, 122, 69, 105, 77, 67, 65, 71, // EwJVUzEiMCAG + 65, 49, 85, 69, 67, 104, 77, 90, 82, 50, 57, 118, // A1UEChMZR29v + 90, 50, 120, 108, 73, 70, 82, 121, 100, 88, 78, 48, // Z2xlIFRydXN0 + 73, 70, 78, 108, 99, 110, 90, 112, 89, 50, 86, 122, // IFNlcnZpY2Vz + 10, 73, 69, 120, 77, 81, 122, 69, 85, 77, 66, 73, // .IExMQzEUMBI + 71, 65, 49, 85, 69, 65, 120, 77, 76, 82, 49, 82, // GA1UEAxMLR1R + 84, 73, 70, 74, 118, 98, 51, 81, 103, 85, 106, 81, // TIFJvb3QgUjQ + 119, 100, 106, 65, 81, 66, 103, 99, 113, 104, 107, 106, // wdjAQBgcqhkj + 79, 80, 81, 73, 66, 66, 103, 85, 114, 103, 81, 81, // OPQIBBgUrgQQ + 65, 73, 103, 78, 105, 10, 65, 65, 84, 122, 100, 72, // AIgNi.AATzdH + 79, 110, 97, 73, 116, 103, 114, 107, 79, 52, 78, 99, // OnaItgrkO4Nc + 87, 66, 77, 72, 116, 76, 83, 90, 51, 55, 119, 87, // WBMHtLSZ37wW + 72, 79, 53, 116, 53, 71, 118, 87, 118, 86, 89, 82, // HO5t5GvWvVYR + 103, 49, 114, 107, 68, 100, 99, 47, 101, 74, 107, 84, // g1rkDdc/eJkT + 66, 97, 54, 122, 122, 117, 104, 88, 121, 105, 10, 81, // Ba6zzuhXyi.Q + 72, 89, 55, 113, 99, 97, 52, 82, 57, 103, 113, 53, // HY7qca4R9gq5 + 53, 75, 82, 97, 110, 80, 112, 115, 88, 73, 53, 110, // 5KRanPpsXI5n + 121, 109, 102, 111, 112, 106, 84, 88, 49, 53, 89, 104, // ymfopjTX15Yh + 109, 85, 80, 111, 89, 82, 108, 66, 116, 72, 99, 105, // mUPoYRlBtHci + 56, 110, 72, 99, 56, 105, 77, 97, 105, 47, 108, 120, // 8nHc8iMai/lx + 75, 118, 82, 10, 72, 89, 113, 106, 81, 106, 66, 65, // KvR.HYqjQjBA + 77, 65, 52, 71, 65, 49, 85, 100, 68, 119, 69, 66, // MA4GA1UdDwEB + 47, 119, 81, 69, 65, 119, 73, 66, 104, 106, 65, 80, // /wQEAwIBhjAP + 66, 103, 78, 86, 72, 82, 77, 66, 65, 102, 56, 69, // BgNVHRMBAf8E + 66, 84, 65, 68, 65, 81, 72, 47, 77, 66, 48, 71, // BTADAQH/MB0G + 65, 49, 85, 100, 68, 103, 81, 87, 10, 66, 66, 83, // A1UdDgQW.BBS + 65, 84, 78, 98, 114, 100, 80, 57, 74, 78, 113, 80, // ATNbrdP9JNqP + 86, 50, 80, 121, 49, 80, 115, 86, 113, 56, 74, 81, // V2Py1PsVq8JQ + 100, 106, 68, 65, 75, 66, 103, 103, 113, 104, 107, 106, // djDAKBggqhkj + 79, 80, 81, 81, 68, 65, 119, 78, 112, 65, 68, 66, // OPQQDAwNpADB + 109, 65, 106, 69, 65, 54, 69, 68, 47, 103, 57, 52, // mAjEA6ED/g94 + 68, 10, 57, 74, 43, 117, 72, 88, 113, 110, 76, 114, // D.9J+uHXqnLr + 109, 118, 84, 47, 97, 68, 72, 81, 52, 116, 104, 81, // mvT/aDHQ4thQ + 69, 100, 48, 100, 108, 113, 55, 65, 47, 67, 114, 56, // Ed0dlq7A/Cr8 + 100, 101, 86, 108, 53, 99, 49, 82, 120, 89, 73, 105, // deVl5c1RxYIi + 103, 76, 57, 122, 67, 50, 76, 55, 70, 56, 65, 106, // gL9zC2L7F8Aj + 69, 65, 56, 71, 69, 56, 10, 112, 47, 83, 103, 103, // EA8GE8.p/Sgg + 117, 77, 104, 49, 89, 81, 100, 99, 52, 97, 99, 76, // uMh1YQdc4acL + 97, 47, 75, 78, 74, 118, 120, 110, 55, 107, 106, 78, // a/KNJvxn7kjN + 117, 75, 56, 89, 65, 79, 100, 103, 76, 79, 97, 86, // uK8YAOdgLOaV + 115, 106, 104, 52, 114, 115, 85, 101, 99, 114, 78, 73, // sjh4rsUecrNI + 100, 83, 85, 116, 85, 108, 68, 10, 45, 45, 45, 45, // dSUtUlD.---- + 45, 69, 78, 68, 32, 67, 69, 82, 84, 73, 70, 73, // -END CERTIFI + 67, 65, 84, 69, 45, 45, 45, 45, 45, 10, 10, 10, // CATE-----... 73, 115, 115, 117, 101, 114, 58, 32, 67, 32, 61, 32, // Issuer: C = 85, 83, 44, 32, 79, 32, 61, 32, 73, 110, 116, 101, // US, O = Inte 114, 110, 101, 116, 32, 83, 101, 99, 117, 114, 105, 116, // rnet Securit @@ -2556,7 +3145,7 @@ static const struct packed_file { size_t size; time_t mtime; } packed_files[] = { - {"/certs/ca.pem", v1, sizeof(v1), 1696845443}, + {"/certs/ca.pem", v1, sizeof(v1), 1739200860}, {NULL, NULL, 0, 0} };