1*0957b409SSimon J. Gerraty\ Copyright (c) 2016 Thomas Pornin <pornin@bolet.org> 2*0957b409SSimon J. Gerraty\ 3*0957b409SSimon J. Gerraty\ Permission is hereby granted, free of charge, to any person obtaining 4*0957b409SSimon J. Gerraty\ a copy of this software and associated documentation files (the 5*0957b409SSimon J. Gerraty\ "Software"), to deal in the Software without restriction, including 6*0957b409SSimon J. Gerraty\ without limitation the rights to use, copy, modify, merge, publish, 7*0957b409SSimon J. Gerraty\ distribute, sublicense, and/or sell copies of the Software, and to 8*0957b409SSimon J. Gerraty\ permit persons to whom the Software is furnished to do so, subject to 9*0957b409SSimon J. Gerraty\ the following conditions: 10*0957b409SSimon J. Gerraty\ 11*0957b409SSimon J. Gerraty\ The above copyright notice and this permission notice shall be 12*0957b409SSimon J. Gerraty\ included in all copies or substantial portions of the Software. 13*0957b409SSimon J. Gerraty\ 14*0957b409SSimon J. Gerraty\ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15*0957b409SSimon J. Gerraty\ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16*0957b409SSimon J. Gerraty\ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17*0957b409SSimon J. Gerraty\ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 18*0957b409SSimon J. Gerraty\ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 19*0957b409SSimon J. Gerraty\ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20*0957b409SSimon J. Gerraty\ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21*0957b409SSimon J. Gerraty\ SOFTWARE. 22*0957b409SSimon J. Gerraty 23*0957b409SSimon J. Gerraty\ ---------------------------------------------------------------------- 24*0957b409SSimon J. Gerraty\ Handshake processing code, for the client. 25*0957b409SSimon J. Gerraty\ The common T0 code (ssl_hs_common.t0) shall be read first. 26*0957b409SSimon J. Gerraty 27*0957b409SSimon J. Gerratypreamble { 28*0957b409SSimon J. Gerraty 29*0957b409SSimon J. Gerraty/* 30*0957b409SSimon J. Gerraty * This macro evaluates to a pointer to the client context, under that 31*0957b409SSimon J. Gerraty * specific name. It must be noted that since the engine context is the 32*0957b409SSimon J. Gerraty * first field of the br_ssl_client_context structure ('eng'), then 33*0957b409SSimon J. Gerraty * pointers values of both types are interchangeable, modulo an 34*0957b409SSimon J. Gerraty * appropriate cast. This also means that "addresses" computed as offsets 35*0957b409SSimon J. Gerraty * within the structure work for both kinds of context. 36*0957b409SSimon J. Gerraty */ 37*0957b409SSimon J. Gerraty#define CTX ((br_ssl_client_context *)ENG) 38*0957b409SSimon J. Gerraty 39*0957b409SSimon J. Gerraty/* 40*0957b409SSimon J. Gerraty * Generate the pre-master secret for RSA key exchange, and encrypt it 41*0957b409SSimon J. Gerraty * with the server's public key. Returned value is either the encrypted 42*0957b409SSimon J. Gerraty * data length (in bytes), or -x on error, with 'x' being an error code. 43*0957b409SSimon J. Gerraty * 44*0957b409SSimon J. Gerraty * This code assumes that the public key has been already verified (it 45*0957b409SSimon J. Gerraty * was properly obtained by the X.509 engine, and it has the right type, 46*0957b409SSimon J. Gerraty * i.e. it is of type RSA and suitable for encryption). 47*0957b409SSimon J. Gerraty */ 48*0957b409SSimon J. Gerratystatic int 49*0957b409SSimon J. Gerratymake_pms_rsa(br_ssl_client_context *ctx, int prf_id) 50*0957b409SSimon J. Gerraty{ 51*0957b409SSimon J. Gerraty const br_x509_class **xc; 52*0957b409SSimon J. Gerraty const br_x509_pkey *pk; 53*0957b409SSimon J. Gerraty const unsigned char *n; 54*0957b409SSimon J. Gerraty unsigned char *pms; 55*0957b409SSimon J. Gerraty size_t nlen, u; 56*0957b409SSimon J. Gerraty 57*0957b409SSimon J. Gerraty xc = ctx->eng.x509ctx; 58*0957b409SSimon J. Gerraty pk = (*xc)->get_pkey(xc, NULL); 59*0957b409SSimon J. Gerraty 60*0957b409SSimon J. Gerraty /* 61*0957b409SSimon J. Gerraty * Compute actual RSA key length, in case there are leading zeros. 62*0957b409SSimon J. Gerraty */ 63*0957b409SSimon J. Gerraty n = pk->key.rsa.n; 64*0957b409SSimon J. Gerraty nlen = pk->key.rsa.nlen; 65*0957b409SSimon J. Gerraty while (nlen > 0 && *n == 0) { 66*0957b409SSimon J. Gerraty n ++; 67*0957b409SSimon J. Gerraty nlen --; 68*0957b409SSimon J. Gerraty } 69*0957b409SSimon J. Gerraty 70*0957b409SSimon J. Gerraty /* 71*0957b409SSimon J. Gerraty * We need at least 59 bytes (48 bytes for pre-master secret, and 72*0957b409SSimon J. Gerraty * 11 bytes for the PKCS#1 type 2 padding). Note that the X.509 73*0957b409SSimon J. Gerraty * minimal engine normally blocks RSA keys shorter than 128 bytes, 74*0957b409SSimon J. Gerraty * so this is mostly for public keys provided explicitly by the 75*0957b409SSimon J. Gerraty * caller. 76*0957b409SSimon J. Gerraty */ 77*0957b409SSimon J. Gerraty if (nlen < 59) { 78*0957b409SSimon J. Gerraty return -BR_ERR_X509_WEAK_PUBLIC_KEY; 79*0957b409SSimon J. Gerraty } 80*0957b409SSimon J. Gerraty if (nlen > sizeof ctx->eng.pad) { 81*0957b409SSimon J. Gerraty return -BR_ERR_LIMIT_EXCEEDED; 82*0957b409SSimon J. Gerraty } 83*0957b409SSimon J. Gerraty 84*0957b409SSimon J. Gerraty /* 85*0957b409SSimon J. Gerraty * Make PMS. 86*0957b409SSimon J. Gerraty */ 87*0957b409SSimon J. Gerraty pms = ctx->eng.pad + nlen - 48; 88*0957b409SSimon J. Gerraty br_enc16be(pms, ctx->eng.version_max); 89*0957b409SSimon J. Gerraty br_hmac_drbg_generate(&ctx->eng.rng, pms + 2, 46); 90*0957b409SSimon J. Gerraty br_ssl_engine_compute_master(&ctx->eng, prf_id, pms, 48); 91*0957b409SSimon J. Gerraty 92*0957b409SSimon J. Gerraty /* 93*0957b409SSimon J. Gerraty * Apply PKCS#1 type 2 padding. 94*0957b409SSimon J. Gerraty */ 95*0957b409SSimon J. Gerraty ctx->eng.pad[0] = 0x00; 96*0957b409SSimon J. Gerraty ctx->eng.pad[1] = 0x02; 97*0957b409SSimon J. Gerraty ctx->eng.pad[nlen - 49] = 0x00; 98*0957b409SSimon J. Gerraty br_hmac_drbg_generate(&ctx->eng.rng, ctx->eng.pad + 2, nlen - 51); 99*0957b409SSimon J. Gerraty for (u = 2; u < nlen - 49; u ++) { 100*0957b409SSimon J. Gerraty while (ctx->eng.pad[u] == 0) { 101*0957b409SSimon J. Gerraty br_hmac_drbg_generate(&ctx->eng.rng, 102*0957b409SSimon J. Gerraty &ctx->eng.pad[u], 1); 103*0957b409SSimon J. Gerraty } 104*0957b409SSimon J. Gerraty } 105*0957b409SSimon J. Gerraty 106*0957b409SSimon J. Gerraty /* 107*0957b409SSimon J. Gerraty * Compute RSA encryption. 108*0957b409SSimon J. Gerraty */ 109*0957b409SSimon J. Gerraty if (!ctx->irsapub(ctx->eng.pad, nlen, &pk->key.rsa)) { 110*0957b409SSimon J. Gerraty return -BR_ERR_LIMIT_EXCEEDED; 111*0957b409SSimon J. Gerraty } 112*0957b409SSimon J. Gerraty return (int)nlen; 113*0957b409SSimon J. Gerraty} 114*0957b409SSimon J. Gerraty 115*0957b409SSimon J. Gerraty/* 116*0957b409SSimon J. Gerraty * OID for hash functions in RSA signatures. 117*0957b409SSimon J. Gerraty */ 118*0957b409SSimon J. Gerratystatic const unsigned char *HASH_OID[] = { 119*0957b409SSimon J. Gerraty BR_HASH_OID_SHA1, 120*0957b409SSimon J. Gerraty BR_HASH_OID_SHA224, 121*0957b409SSimon J. Gerraty BR_HASH_OID_SHA256, 122*0957b409SSimon J. Gerraty BR_HASH_OID_SHA384, 123*0957b409SSimon J. Gerraty BR_HASH_OID_SHA512 124*0957b409SSimon J. Gerraty}; 125*0957b409SSimon J. Gerraty 126*0957b409SSimon J. Gerraty/* 127*0957b409SSimon J. Gerraty * Check the RSA signature on the ServerKeyExchange message. 128*0957b409SSimon J. Gerraty * 129*0957b409SSimon J. Gerraty * hash hash function ID (2 to 6), or 0 for MD5+SHA-1 (with RSA only) 130*0957b409SSimon J. Gerraty * use_rsa non-zero for RSA signature, zero for ECDSA 131*0957b409SSimon J. Gerraty * sig_len signature length (in bytes); signature value is in the pad 132*0957b409SSimon J. Gerraty * 133*0957b409SSimon J. Gerraty * Returned value is 0 on success, or an error code. 134*0957b409SSimon J. Gerraty */ 135*0957b409SSimon J. Gerratystatic int 136*0957b409SSimon J. Gerratyverify_SKE_sig(br_ssl_client_context *ctx, 137*0957b409SSimon J. Gerraty int hash, int use_rsa, size_t sig_len) 138*0957b409SSimon J. Gerraty{ 139*0957b409SSimon J. Gerraty const br_x509_class **xc; 140*0957b409SSimon J. Gerraty const br_x509_pkey *pk; 141*0957b409SSimon J. Gerraty br_multihash_context mhc; 142*0957b409SSimon J. Gerraty unsigned char hv[64], head[4]; 143*0957b409SSimon J. Gerraty size_t hv_len; 144*0957b409SSimon J. Gerraty 145*0957b409SSimon J. Gerraty xc = ctx->eng.x509ctx; 146*0957b409SSimon J. Gerraty pk = (*xc)->get_pkey(xc, NULL); 147*0957b409SSimon J. Gerraty br_multihash_zero(&mhc); 148*0957b409SSimon J. Gerraty br_multihash_copyimpl(&mhc, &ctx->eng.mhash); 149*0957b409SSimon J. Gerraty br_multihash_init(&mhc); 150*0957b409SSimon J. Gerraty br_multihash_update(&mhc, 151*0957b409SSimon J. Gerraty ctx->eng.client_random, sizeof ctx->eng.client_random); 152*0957b409SSimon J. Gerraty br_multihash_update(&mhc, 153*0957b409SSimon J. Gerraty ctx->eng.server_random, sizeof ctx->eng.server_random); 154*0957b409SSimon J. Gerraty head[0] = 3; 155*0957b409SSimon J. Gerraty head[1] = 0; 156*0957b409SSimon J. Gerraty head[2] = ctx->eng.ecdhe_curve; 157*0957b409SSimon J. Gerraty head[3] = ctx->eng.ecdhe_point_len; 158*0957b409SSimon J. Gerraty br_multihash_update(&mhc, head, sizeof head); 159*0957b409SSimon J. Gerraty br_multihash_update(&mhc, 160*0957b409SSimon J. Gerraty ctx->eng.ecdhe_point, ctx->eng.ecdhe_point_len); 161*0957b409SSimon J. Gerraty if (hash) { 162*0957b409SSimon J. Gerraty hv_len = br_multihash_out(&mhc, hash, hv); 163*0957b409SSimon J. Gerraty if (hv_len == 0) { 164*0957b409SSimon J. Gerraty return BR_ERR_INVALID_ALGORITHM; 165*0957b409SSimon J. Gerraty } 166*0957b409SSimon J. Gerraty } else { 167*0957b409SSimon J. Gerraty if (!br_multihash_out(&mhc, br_md5_ID, hv) 168*0957b409SSimon J. Gerraty || !br_multihash_out(&mhc, br_sha1_ID, hv + 16)) 169*0957b409SSimon J. Gerraty { 170*0957b409SSimon J. Gerraty return BR_ERR_INVALID_ALGORITHM; 171*0957b409SSimon J. Gerraty } 172*0957b409SSimon J. Gerraty hv_len = 36; 173*0957b409SSimon J. Gerraty } 174*0957b409SSimon J. Gerraty if (use_rsa) { 175*0957b409SSimon J. Gerraty unsigned char tmp[64]; 176*0957b409SSimon J. Gerraty const unsigned char *hash_oid; 177*0957b409SSimon J. Gerraty 178*0957b409SSimon J. Gerraty if (hash) { 179*0957b409SSimon J. Gerraty hash_oid = HASH_OID[hash - 2]; 180*0957b409SSimon J. Gerraty } else { 181*0957b409SSimon J. Gerraty hash_oid = NULL; 182*0957b409SSimon J. Gerraty } 183*0957b409SSimon J. Gerraty if (!ctx->eng.irsavrfy(ctx->eng.pad, sig_len, 184*0957b409SSimon J. Gerraty hash_oid, hv_len, &pk->key.rsa, tmp) 185*0957b409SSimon J. Gerraty || memcmp(tmp, hv, hv_len) != 0) 186*0957b409SSimon J. Gerraty { 187*0957b409SSimon J. Gerraty return BR_ERR_BAD_SIGNATURE; 188*0957b409SSimon J. Gerraty } 189*0957b409SSimon J. Gerraty } else { 190*0957b409SSimon J. Gerraty if (!ctx->eng.iecdsa(ctx->eng.iec, hv, hv_len, &pk->key.ec, 191*0957b409SSimon J. Gerraty ctx->eng.pad, sig_len)) 192*0957b409SSimon J. Gerraty { 193*0957b409SSimon J. Gerraty return BR_ERR_BAD_SIGNATURE; 194*0957b409SSimon J. Gerraty } 195*0957b409SSimon J. Gerraty } 196*0957b409SSimon J. Gerraty return 0; 197*0957b409SSimon J. Gerraty} 198*0957b409SSimon J. Gerraty 199*0957b409SSimon J. Gerraty/* 200*0957b409SSimon J. Gerraty * Perform client-side ECDH (or ECDHE). The point that should be sent to 201*0957b409SSimon J. Gerraty * the server is written in the pad; returned value is either the point 202*0957b409SSimon J. Gerraty * length (in bytes), or -x on error, with 'x' being an error code. 203*0957b409SSimon J. Gerraty * 204*0957b409SSimon J. Gerraty * The point _from_ the server is taken from ecdhe_point[] if 'ecdhe' 205*0957b409SSimon J. Gerraty * is non-zero, or from the X.509 engine context if 'ecdhe' is zero 206*0957b409SSimon J. Gerraty * (for static ECDH). 207*0957b409SSimon J. Gerraty */ 208*0957b409SSimon J. Gerratystatic int 209*0957b409SSimon J. Gerratymake_pms_ecdh(br_ssl_client_context *ctx, unsigned ecdhe, int prf_id) 210*0957b409SSimon J. Gerraty{ 211*0957b409SSimon J. Gerraty int curve; 212*0957b409SSimon J. Gerraty unsigned char key[66], point[133]; 213*0957b409SSimon J. Gerraty const unsigned char *order, *point_src; 214*0957b409SSimon J. Gerraty size_t glen, olen, point_len, xoff, xlen; 215*0957b409SSimon J. Gerraty unsigned char mask; 216*0957b409SSimon J. Gerraty 217*0957b409SSimon J. Gerraty if (ecdhe) { 218*0957b409SSimon J. Gerraty curve = ctx->eng.ecdhe_curve; 219*0957b409SSimon J. Gerraty point_src = ctx->eng.ecdhe_point; 220*0957b409SSimon J. Gerraty point_len = ctx->eng.ecdhe_point_len; 221*0957b409SSimon J. Gerraty } else { 222*0957b409SSimon J. Gerraty const br_x509_class **xc; 223*0957b409SSimon J. Gerraty const br_x509_pkey *pk; 224*0957b409SSimon J. Gerraty 225*0957b409SSimon J. Gerraty xc = ctx->eng.x509ctx; 226*0957b409SSimon J. Gerraty pk = (*xc)->get_pkey(xc, NULL); 227*0957b409SSimon J. Gerraty curve = pk->key.ec.curve; 228*0957b409SSimon J. Gerraty point_src = pk->key.ec.q; 229*0957b409SSimon J. Gerraty point_len = pk->key.ec.qlen; 230*0957b409SSimon J. Gerraty } 231*0957b409SSimon J. Gerraty if ((ctx->eng.iec->supported_curves & ((uint32_t)1 << curve)) == 0) { 232*0957b409SSimon J. Gerraty return -BR_ERR_INVALID_ALGORITHM; 233*0957b409SSimon J. Gerraty } 234*0957b409SSimon J. Gerraty 235*0957b409SSimon J. Gerraty /* 236*0957b409SSimon J. Gerraty * We need to generate our key, as a non-zero random value which 237*0957b409SSimon J. Gerraty * is lower than the curve order, in a "large enough" range. We 238*0957b409SSimon J. Gerraty * force top bit to 0 and bottom bit to 1, which guarantees that 239*0957b409SSimon J. Gerraty * the value is in the proper range. 240*0957b409SSimon J. Gerraty */ 241*0957b409SSimon J. Gerraty order = ctx->eng.iec->order(curve, &olen); 242*0957b409SSimon J. Gerraty mask = 0xFF; 243*0957b409SSimon J. Gerraty while (mask >= order[0]) { 244*0957b409SSimon J. Gerraty mask >>= 1; 245*0957b409SSimon J. Gerraty } 246*0957b409SSimon J. Gerraty br_hmac_drbg_generate(&ctx->eng.rng, key, olen); 247*0957b409SSimon J. Gerraty key[0] &= mask; 248*0957b409SSimon J. Gerraty key[olen - 1] |= 0x01; 249*0957b409SSimon J. Gerraty 250*0957b409SSimon J. Gerraty /* 251*0957b409SSimon J. Gerraty * Compute the common ECDH point, whose X coordinate is the 252*0957b409SSimon J. Gerraty * pre-master secret. 253*0957b409SSimon J. Gerraty */ 254*0957b409SSimon J. Gerraty ctx->eng.iec->generator(curve, &glen); 255*0957b409SSimon J. Gerraty if (glen != point_len) { 256*0957b409SSimon J. Gerraty return -BR_ERR_INVALID_ALGORITHM; 257*0957b409SSimon J. Gerraty } 258*0957b409SSimon J. Gerraty 259*0957b409SSimon J. Gerraty memcpy(point, point_src, glen); 260*0957b409SSimon J. Gerraty if (!ctx->eng.iec->mul(point, glen, key, olen, curve)) { 261*0957b409SSimon J. Gerraty return -BR_ERR_INVALID_ALGORITHM; 262*0957b409SSimon J. Gerraty } 263*0957b409SSimon J. Gerraty 264*0957b409SSimon J. Gerraty /* 265*0957b409SSimon J. Gerraty * The pre-master secret is the X coordinate. 266*0957b409SSimon J. Gerraty */ 267*0957b409SSimon J. Gerraty xoff = ctx->eng.iec->xoff(curve, &xlen); 268*0957b409SSimon J. Gerraty br_ssl_engine_compute_master(&ctx->eng, prf_id, point + xoff, xlen); 269*0957b409SSimon J. Gerraty 270*0957b409SSimon J. Gerraty ctx->eng.iec->mulgen(point, key, olen, curve); 271*0957b409SSimon J. Gerraty memcpy(ctx->eng.pad, point, glen); 272*0957b409SSimon J. Gerraty return (int)glen; 273*0957b409SSimon J. Gerraty} 274*0957b409SSimon J. Gerraty 275*0957b409SSimon J. Gerraty/* 276*0957b409SSimon J. Gerraty * Perform full static ECDH. This occurs only in the context of client 277*0957b409SSimon J. Gerraty * authentication with certificates: the server uses an EC public key, 278*0957b409SSimon J. Gerraty * the cipher suite is of type ECDH (not ECDHE), the server requested a 279*0957b409SSimon J. Gerraty * client certificate and accepts static ECDH, the client has a 280*0957b409SSimon J. Gerraty * certificate with an EC public key in the same curve, and accepts 281*0957b409SSimon J. Gerraty * static ECDH as well. 282*0957b409SSimon J. Gerraty * 283*0957b409SSimon J. Gerraty * Returned value is 0 on success, -1 on error. 284*0957b409SSimon J. Gerraty */ 285*0957b409SSimon J. Gerratystatic int 286*0957b409SSimon J. Gerratymake_pms_static_ecdh(br_ssl_client_context *ctx, int prf_id) 287*0957b409SSimon J. Gerraty{ 288*0957b409SSimon J. Gerraty unsigned char point[133]; 289*0957b409SSimon J. Gerraty size_t point_len; 290*0957b409SSimon J. Gerraty const br_x509_class **xc; 291*0957b409SSimon J. Gerraty const br_x509_pkey *pk; 292*0957b409SSimon J. Gerraty 293*0957b409SSimon J. Gerraty xc = ctx->eng.x509ctx; 294*0957b409SSimon J. Gerraty pk = (*xc)->get_pkey(xc, NULL); 295*0957b409SSimon J. Gerraty point_len = pk->key.ec.qlen; 296*0957b409SSimon J. Gerraty if (point_len > sizeof point) { 297*0957b409SSimon J. Gerraty return -1; 298*0957b409SSimon J. Gerraty } 299*0957b409SSimon J. Gerraty memcpy(point, pk->key.ec.q, point_len); 300*0957b409SSimon J. Gerraty if (!(*ctx->client_auth_vtable)->do_keyx( 301*0957b409SSimon J. Gerraty ctx->client_auth_vtable, point, &point_len)) 302*0957b409SSimon J. Gerraty { 303*0957b409SSimon J. Gerraty return -1; 304*0957b409SSimon J. Gerraty } 305*0957b409SSimon J. Gerraty br_ssl_engine_compute_master(&ctx->eng, 306*0957b409SSimon J. Gerraty prf_id, point, point_len); 307*0957b409SSimon J. Gerraty return 0; 308*0957b409SSimon J. Gerraty} 309*0957b409SSimon J. Gerraty 310*0957b409SSimon J. Gerraty/* 311*0957b409SSimon J. Gerraty * Compute the client-side signature. This is invoked only when a 312*0957b409SSimon J. Gerraty * signature-based client authentication was selected. The computed 313*0957b409SSimon J. Gerraty * signature is in the pad; its length (in bytes) is returned. On 314*0957b409SSimon J. Gerraty * error, 0 is returned. 315*0957b409SSimon J. Gerraty */ 316*0957b409SSimon J. Gerratystatic size_t 317*0957b409SSimon J. Gerratymake_client_sign(br_ssl_client_context *ctx) 318*0957b409SSimon J. Gerraty{ 319*0957b409SSimon J. Gerraty size_t hv_len; 320*0957b409SSimon J. Gerraty 321*0957b409SSimon J. Gerraty /* 322*0957b409SSimon J. Gerraty * Compute hash of handshake messages so far. This "cannot" fail 323*0957b409SSimon J. Gerraty * because the list of supported hash functions provided to the 324*0957b409SSimon J. Gerraty * client certificate handler was trimmed to include only the 325*0957b409SSimon J. Gerraty * hash functions that the multi-hasher supports. 326*0957b409SSimon J. Gerraty */ 327*0957b409SSimon J. Gerraty if (ctx->hash_id) { 328*0957b409SSimon J. Gerraty hv_len = br_multihash_out(&ctx->eng.mhash, 329*0957b409SSimon J. Gerraty ctx->hash_id, ctx->eng.pad); 330*0957b409SSimon J. Gerraty } else { 331*0957b409SSimon J. Gerraty br_multihash_out(&ctx->eng.mhash, 332*0957b409SSimon J. Gerraty br_md5_ID, ctx->eng.pad); 333*0957b409SSimon J. Gerraty br_multihash_out(&ctx->eng.mhash, 334*0957b409SSimon J. Gerraty br_sha1_ID, ctx->eng.pad + 16); 335*0957b409SSimon J. Gerraty hv_len = 36; 336*0957b409SSimon J. Gerraty } 337*0957b409SSimon J. Gerraty return (*ctx->client_auth_vtable)->do_sign( 338*0957b409SSimon J. Gerraty ctx->client_auth_vtable, ctx->hash_id, hv_len, 339*0957b409SSimon J. Gerraty ctx->eng.pad, sizeof ctx->eng.pad); 340*0957b409SSimon J. Gerraty} 341*0957b409SSimon J. Gerraty 342*0957b409SSimon J. Gerraty} 343*0957b409SSimon J. Gerraty 344*0957b409SSimon J. Gerraty\ ======================================================================= 345*0957b409SSimon J. Gerraty 346*0957b409SSimon J. Gerraty: addr-ctx: 347*0957b409SSimon J. Gerraty next-word { field } 348*0957b409SSimon J. Gerraty "addr-" field + 0 1 define-word 349*0957b409SSimon J. Gerraty 0 8191 "offsetof(br_ssl_client_context, " field + ")" + make-CX 350*0957b409SSimon J. Gerraty postpone literal postpone ; ; 351*0957b409SSimon J. Gerraty 352*0957b409SSimon J. Gerratyaddr-ctx: min_clienthello_len 353*0957b409SSimon J. Gerratyaddr-ctx: hashes 354*0957b409SSimon J. Gerratyaddr-ctx: auth_type 355*0957b409SSimon J. Gerratyaddr-ctx: hash_id 356*0957b409SSimon J. Gerraty 357*0957b409SSimon J. Gerraty\ Length of the Secure Renegotiation extension. This is 5 for the 358*0957b409SSimon J. Gerraty\ first handshake, 17 for a renegotiation (if the server supports the 359*0957b409SSimon J. Gerraty\ extension), or 0 if we know that the server does not support the 360*0957b409SSimon J. Gerraty\ extension. 361*0957b409SSimon J. Gerraty: ext-reneg-length ( -- n ) 362*0957b409SSimon J. Gerraty addr-reneg get8 dup if 1 - 17 * else drop 5 then ; 363*0957b409SSimon J. Gerraty 364*0957b409SSimon J. Gerraty\ Length of SNI extension. 365*0957b409SSimon J. Gerraty: ext-sni-length ( -- len ) 366*0957b409SSimon J. Gerraty addr-server_name strlen dup if 9 + then ; 367*0957b409SSimon J. Gerraty 368*0957b409SSimon J. Gerraty\ Length of Maximum Fragment Length extension. 369*0957b409SSimon J. Gerraty: ext-frag-length ( -- len ) 370*0957b409SSimon J. Gerraty addr-log_max_frag_len get8 14 = if 0 else 5 then ; 371*0957b409SSimon J. Gerraty 372*0957b409SSimon J. Gerraty\ Length of Signatures extension. 373*0957b409SSimon J. Gerraty: ext-signatures-length ( -- len ) 374*0957b409SSimon J. Gerraty supported-hash-functions { num } drop 0 375*0957b409SSimon J. Gerraty supports-rsa-sign? if num + then 376*0957b409SSimon J. Gerraty supports-ecdsa? if num + then 377*0957b409SSimon J. Gerraty dup if 1 << 6 + then ; 378*0957b409SSimon J. Gerraty 379*0957b409SSimon J. Gerraty\ Write supported hash functions ( sign -- ) 380*0957b409SSimon J. Gerraty: write-hashes 381*0957b409SSimon J. Gerraty { sign } 382*0957b409SSimon J. Gerraty supported-hash-functions drop 383*0957b409SSimon J. Gerraty \ We advertise hash functions in the following preference order: 384*0957b409SSimon J. Gerraty \ SHA-256 SHA-224 SHA-384 SHA-512 SHA-1 385*0957b409SSimon J. Gerraty \ Rationale: 386*0957b409SSimon J. Gerraty \ -- SHA-256 and SHA-224 are more efficient on 32-bit architectures 387*0957b409SSimon J. Gerraty \ -- SHA-1 is less than ideally collision-resistant 388*0957b409SSimon J. Gerraty dup 0x10 and if 4 write8 sign write8 then 389*0957b409SSimon J. Gerraty dup 0x08 and if 3 write8 sign write8 then 390*0957b409SSimon J. Gerraty dup 0x20 and if 5 write8 sign write8 then 391*0957b409SSimon J. Gerraty dup 0x40 and if 6 write8 sign write8 then 392*0957b409SSimon J. Gerraty 0x04 and if 2 write8 sign write8 then ; 393*0957b409SSimon J. Gerraty 394*0957b409SSimon J. Gerraty\ Length of Supported Curves extension. 395*0957b409SSimon J. Gerraty: ext-supported-curves-length ( -- len ) 396*0957b409SSimon J. Gerraty supported-curves dup if 397*0957b409SSimon J. Gerraty 0 { x } 398*0957b409SSimon J. Gerraty begin dup while 399*0957b409SSimon J. Gerraty dup 1 and x + >x 400*0957b409SSimon J. Gerraty 1 >> 401*0957b409SSimon J. Gerraty repeat 402*0957b409SSimon J. Gerraty drop x 1 << 6 + 403*0957b409SSimon J. Gerraty then ; 404*0957b409SSimon J. Gerraty 405*0957b409SSimon J. Gerraty\ Length of Supported Point Formats extension. 406*0957b409SSimon J. Gerraty: ext-point-format-length ( -- len ) 407*0957b409SSimon J. Gerraty supported-curves if 6 else 0 then ; 408*0957b409SSimon J. Gerraty 409*0957b409SSimon J. Gerraty\ Length of ALPN extension. 410*0957b409SSimon J. Gerratycc: ext-ALPN-length ( -- len ) { 411*0957b409SSimon J. Gerraty size_t u, len; 412*0957b409SSimon J. Gerraty 413*0957b409SSimon J. Gerraty if (ENG->protocol_names_num == 0) { 414*0957b409SSimon J. Gerraty T0_PUSH(0); 415*0957b409SSimon J. Gerraty T0_RET(); 416*0957b409SSimon J. Gerraty } 417*0957b409SSimon J. Gerraty len = 6; 418*0957b409SSimon J. Gerraty for (u = 0; u < ENG->protocol_names_num; u ++) { 419*0957b409SSimon J. Gerraty len += 1 + strlen(ENG->protocol_names[u]); 420*0957b409SSimon J. Gerraty } 421*0957b409SSimon J. Gerraty T0_PUSH(len); 422*0957b409SSimon J. Gerraty} 423*0957b409SSimon J. Gerraty 424*0957b409SSimon J. Gerraty\ Write handshake message: ClientHello 425*0957b409SSimon J. Gerraty: write-ClientHello ( -- ) 426*0957b409SSimon J. Gerraty { ; total-ext-length } 427*0957b409SSimon J. Gerraty 428*0957b409SSimon J. Gerraty \ Compute length for extensions (without the general two-byte header). 429*0957b409SSimon J. Gerraty \ This does not take padding extension into account. 430*0957b409SSimon J. Gerraty ext-reneg-length ext-sni-length + ext-frag-length + 431*0957b409SSimon J. Gerraty ext-signatures-length + 432*0957b409SSimon J. Gerraty ext-supported-curves-length + ext-point-format-length + 433*0957b409SSimon J. Gerraty ext-ALPN-length + 434*0957b409SSimon J. Gerraty >total-ext-length 435*0957b409SSimon J. Gerraty 436*0957b409SSimon J. Gerraty \ ClientHello type 437*0957b409SSimon J. Gerraty 1 write8 438*0957b409SSimon J. Gerraty 439*0957b409SSimon J. Gerraty \ Compute and write length 440*0957b409SSimon J. Gerraty 39 addr-session_id_len get8 + addr-suites_num get8 1 << + 441*0957b409SSimon J. Gerraty total-ext-length if 2+ total-ext-length + then 442*0957b409SSimon J. Gerraty \ Compute padding (if requested). 443*0957b409SSimon J. Gerraty addr-min_clienthello_len get16 over - dup 0> if 444*0957b409SSimon J. Gerraty \ We well add a Pad ClientHello extension, which has its 445*0957b409SSimon J. Gerraty \ own header (4 bytes) and might be the only extension 446*0957b409SSimon J. Gerraty \ (2 extra bytes for the extension list header). 447*0957b409SSimon J. Gerraty total-ext-length ifnot swap 2+ swap 2- then 448*0957b409SSimon J. Gerraty \ Account for the extension header. 449*0957b409SSimon J. Gerraty 4 - dup 0< if drop 0 then 450*0957b409SSimon J. Gerraty \ Adjust total extension length. 451*0957b409SSimon J. Gerraty dup 4 + total-ext-length + >total-ext-length 452*0957b409SSimon J. Gerraty \ Adjust ClientHello length. 453*0957b409SSimon J. Gerraty swap 4 + over + swap 454*0957b409SSimon J. Gerraty else 455*0957b409SSimon J. Gerraty drop 456*0957b409SSimon J. Gerraty -1 457*0957b409SSimon J. Gerraty then 458*0957b409SSimon J. Gerraty { ext-padding-amount } 459*0957b409SSimon J. Gerraty write24 460*0957b409SSimon J. Gerraty 461*0957b409SSimon J. Gerraty \ Protocol version 462*0957b409SSimon J. Gerraty addr-version_max get16 write16 463*0957b409SSimon J. Gerraty 464*0957b409SSimon J. Gerraty \ Client random 465*0957b409SSimon J. Gerraty addr-client_random 4 bzero 466*0957b409SSimon J. Gerraty addr-client_random 4 + 28 mkrand 467*0957b409SSimon J. Gerraty addr-client_random 32 write-blob 468*0957b409SSimon J. Gerraty 469*0957b409SSimon J. Gerraty \ Session ID 470*0957b409SSimon J. Gerraty addr-session_id addr-session_id_len get8 write-blob-head8 471*0957b409SSimon J. Gerraty 472*0957b409SSimon J. Gerraty \ Supported cipher suites. We also check here that we indeed 473*0957b409SSimon J. Gerraty \ support all these suites. 474*0957b409SSimon J. Gerraty addr-suites_num get8 dup 1 << write16 475*0957b409SSimon J. Gerraty addr-suites_buf swap 476*0957b409SSimon J. Gerraty begin 477*0957b409SSimon J. Gerraty dup while 1- 478*0957b409SSimon J. Gerraty over get16 479*0957b409SSimon J. Gerraty dup suite-supported? ifnot ERR_BAD_CIPHER_SUITE fail then 480*0957b409SSimon J. Gerraty write16 481*0957b409SSimon J. Gerraty swap 2+ swap 482*0957b409SSimon J. Gerraty repeat 483*0957b409SSimon J. Gerraty 2drop 484*0957b409SSimon J. Gerraty 485*0957b409SSimon J. Gerraty \ Compression methods (only "null" compression) 486*0957b409SSimon J. Gerraty 1 write8 0 write8 487*0957b409SSimon J. Gerraty 488*0957b409SSimon J. Gerraty \ Extensions 489*0957b409SSimon J. Gerraty total-ext-length if 490*0957b409SSimon J. Gerraty total-ext-length write16 491*0957b409SSimon J. Gerraty ext-reneg-length if 492*0957b409SSimon J. Gerraty 0xFF01 write16 \ extension type (0xFF01) 493*0957b409SSimon J. Gerraty addr-saved_finished 494*0957b409SSimon J. Gerraty ext-reneg-length 4 - dup write16 \ extension length 495*0957b409SSimon J. Gerraty 1- write-blob-head8 \ verify data 496*0957b409SSimon J. Gerraty then 497*0957b409SSimon J. Gerraty ext-sni-length if 498*0957b409SSimon J. Gerraty 0x0000 write16 \ extension type (0) 499*0957b409SSimon J. Gerraty addr-server_name 500*0957b409SSimon J. Gerraty ext-sni-length 4 - dup write16 \ extension length 501*0957b409SSimon J. Gerraty 2 - dup write16 \ ServerNameList length 502*0957b409SSimon J. Gerraty 0 write8 \ name type: host_name 503*0957b409SSimon J. Gerraty 3 - write-blob-head16 \ the name itself 504*0957b409SSimon J. Gerraty then 505*0957b409SSimon J. Gerraty ext-frag-length if 506*0957b409SSimon J. Gerraty 0x0001 write16 \ extension type (1) 507*0957b409SSimon J. Gerraty 0x0001 write16 \ extension length 508*0957b409SSimon J. Gerraty addr-log_max_frag_len get8 8 - write8 509*0957b409SSimon J. Gerraty then 510*0957b409SSimon J. Gerraty ext-signatures-length if 511*0957b409SSimon J. Gerraty 0x000D write16 \ extension type (13) 512*0957b409SSimon J. Gerraty ext-signatures-length 4 - dup write16 \ extension length 513*0957b409SSimon J. Gerraty 2 - write16 \ list length 514*0957b409SSimon J. Gerraty supports-ecdsa? if 3 write-hashes then 515*0957b409SSimon J. Gerraty supports-rsa-sign? if 1 write-hashes then 516*0957b409SSimon J. Gerraty then 517*0957b409SSimon J. Gerraty \ TODO: add an API to specify preference order for curves. 518*0957b409SSimon J. Gerraty \ Right now we send Curve25519 first, then other curves in 519*0957b409SSimon J. Gerraty \ increasing ID values (hence P-256 in second). 520*0957b409SSimon J. Gerraty ext-supported-curves-length dup if 521*0957b409SSimon J. Gerraty 0x000A write16 \ extension type (10) 522*0957b409SSimon J. Gerraty 4 - dup write16 \ extension length 523*0957b409SSimon J. Gerraty 2- write16 \ list length 524*0957b409SSimon J. Gerraty supported-curves 0 525*0957b409SSimon J. Gerraty dup 0x20000000 and if 526*0957b409SSimon J. Gerraty 0xDFFFFFFF and 29 write16 527*0957b409SSimon J. Gerraty then 528*0957b409SSimon J. Gerraty begin dup 32 < while 529*0957b409SSimon J. Gerraty dup2 >> 1 and if dup write16 then 530*0957b409SSimon J. Gerraty 1+ 531*0957b409SSimon J. Gerraty repeat 532*0957b409SSimon J. Gerraty 2drop 533*0957b409SSimon J. Gerraty else 534*0957b409SSimon J. Gerraty drop 535*0957b409SSimon J. Gerraty then 536*0957b409SSimon J. Gerraty ext-point-format-length if 537*0957b409SSimon J. Gerraty 0x000B write16 \ extension type (11) 538*0957b409SSimon J. Gerraty 0x0002 write16 \ extension length 539*0957b409SSimon J. Gerraty 0x0100 write16 \ value: 1 format: uncompressed 540*0957b409SSimon J. Gerraty then 541*0957b409SSimon J. Gerraty ext-ALPN-length dup if 542*0957b409SSimon J. Gerraty 0x0010 write16 \ extension type (16) 543*0957b409SSimon J. Gerraty 4 - dup write16 \ extension length 544*0957b409SSimon J. Gerraty 2- write16 \ list length 545*0957b409SSimon J. Gerraty addr-protocol_names_num get16 0 546*0957b409SSimon J. Gerraty begin 547*0957b409SSimon J. Gerraty dup2 > while 548*0957b409SSimon J. Gerraty dup copy-protocol-name 549*0957b409SSimon J. Gerraty dup write8 addr-pad swap write-blob 550*0957b409SSimon J. Gerraty 1+ 551*0957b409SSimon J. Gerraty repeat 552*0957b409SSimon J. Gerraty 2drop 553*0957b409SSimon J. Gerraty else 554*0957b409SSimon J. Gerraty drop 555*0957b409SSimon J. Gerraty then 556*0957b409SSimon J. Gerraty ext-padding-amount 0< ifnot 557*0957b409SSimon J. Gerraty 0x0015 write16 \ extension value (21) 558*0957b409SSimon J. Gerraty ext-padding-amount 559*0957b409SSimon J. Gerraty dup write16 \ extension length 560*0957b409SSimon J. Gerraty begin dup while 561*0957b409SSimon J. Gerraty 1- 0 write8 repeat \ value (only zeros) 562*0957b409SSimon J. Gerraty drop 563*0957b409SSimon J. Gerraty then 564*0957b409SSimon J. Gerraty then 565*0957b409SSimon J. Gerraty ; 566*0957b409SSimon J. Gerraty 567*0957b409SSimon J. Gerraty\ ======================================================================= 568*0957b409SSimon J. Gerraty 569*0957b409SSimon J. Gerraty\ Parse server SNI extension. If present, then it should be empty. 570*0957b409SSimon J. Gerraty: read-server-sni ( lim -- lim ) 571*0957b409SSimon J. Gerraty read16 if ERR_BAD_SNI fail then ; 572*0957b409SSimon J. Gerraty 573*0957b409SSimon J. Gerraty\ Parse server Max Fragment Length extension. If present, then it should 574*0957b409SSimon J. Gerraty\ advertise the same length as the client. Note that whether the server 575*0957b409SSimon J. Gerraty\ sends it or not changes nothing for us: we won't send any record larger 576*0957b409SSimon J. Gerraty\ than the advertised value anyway, and we will accept incoming records 577*0957b409SSimon J. Gerraty\ up to our input buffer length. 578*0957b409SSimon J. Gerraty: read-server-frag ( lim -- lim ) 579*0957b409SSimon J. Gerraty read16 1 = ifnot ERR_BAD_FRAGLEN fail then 580*0957b409SSimon J. Gerraty read8 8 + addr-log_max_frag_len get8 = ifnot ERR_BAD_FRAGLEN fail then ; 581*0957b409SSimon J. Gerraty 582*0957b409SSimon J. Gerraty\ Parse server Secure Renegotiation extension. This is called only if 583*0957b409SSimon J. Gerraty\ the client sent that extension, so we only have two cases to 584*0957b409SSimon J. Gerraty\ distinguish: first handshake, and renegotiation; in the latter case, 585*0957b409SSimon J. Gerraty\ we know that the server supports the extension, otherwise the client 586*0957b409SSimon J. Gerraty\ would not have sent it. 587*0957b409SSimon J. Gerraty: read-server-reneg ( lim -- lim ) 588*0957b409SSimon J. Gerraty read16 589*0957b409SSimon J. Gerraty addr-reneg get8 ifnot 590*0957b409SSimon J. Gerraty \ "reneg" is 0, so this is a first handshake. The server's 591*0957b409SSimon J. Gerraty \ extension MUST be empty. We also learn that the server 592*0957b409SSimon J. Gerraty \ supports the extension. 593*0957b409SSimon J. Gerraty 1 = ifnot ERR_BAD_SECRENEG fail then 594*0957b409SSimon J. Gerraty read8 0 = ifnot ERR_BAD_SECRENEG fail then 595*0957b409SSimon J. Gerraty 2 addr-reneg set8 596*0957b409SSimon J. Gerraty else 597*0957b409SSimon J. Gerraty \ "reneg" is non-zero, and we sent an extension, so it must 598*0957b409SSimon J. Gerraty \ be 2 and this is a renegotiation. We must verify that 599*0957b409SSimon J. Gerraty \ the extension contents have length exactly 24 bytes and 600*0957b409SSimon J. Gerraty \ match the saved client and server "Finished". 601*0957b409SSimon J. Gerraty 25 = ifnot ERR_BAD_SECRENEG fail then 602*0957b409SSimon J. Gerraty read8 24 = ifnot ERR_BAD_SECRENEG fail then 603*0957b409SSimon J. Gerraty addr-pad 24 read-blob 604*0957b409SSimon J. Gerraty addr-saved_finished addr-pad 24 memcmp ifnot 605*0957b409SSimon J. Gerraty ERR_BAD_SECRENEG fail 606*0957b409SSimon J. Gerraty then 607*0957b409SSimon J. Gerraty then ; 608*0957b409SSimon J. Gerraty 609*0957b409SSimon J. Gerraty\ Read the ALPN extension from the server. It must contain a single name, 610*0957b409SSimon J. Gerraty\ and that name must match one of our names. 611*0957b409SSimon J. Gerraty: read-ALPN-from-server ( lim -- lim ) 612*0957b409SSimon J. Gerraty \ Extension contents length. 613*0957b409SSimon J. Gerraty read16 open-elt 614*0957b409SSimon J. Gerraty \ Length of list of names. 615*0957b409SSimon J. Gerraty read16 open-elt 616*0957b409SSimon J. Gerraty \ There should be a single name. 617*0957b409SSimon J. Gerraty read8 addr-pad swap dup { len } read-blob 618*0957b409SSimon J. Gerraty close-elt 619*0957b409SSimon J. Gerraty close-elt 620*0957b409SSimon J. Gerraty len test-protocol-name dup 0< if 621*0957b409SSimon J. Gerraty 3 flag? if ERR_UNEXPECTED fail then 622*0957b409SSimon J. Gerraty drop 623*0957b409SSimon J. Gerraty else 624*0957b409SSimon J. Gerraty 1+ addr-selected_protocol set16 625*0957b409SSimon J. Gerraty then ; 626*0957b409SSimon J. Gerraty 627*0957b409SSimon J. Gerraty\ Save a value in a 16-bit field, or check it in case of session resumption. 628*0957b409SSimon J. Gerraty: check-resume ( val addr resume -- ) 629*0957b409SSimon J. Gerraty if get16 = ifnot ERR_RESUME_MISMATCH fail then else set16 then ; 630*0957b409SSimon J. Gerraty 631*0957b409SSimon J. Gerratycc: DEBUG-BLOB ( addr len -- ) { 632*0957b409SSimon J. Gerraty extern int printf(const char *fmt, ...); 633*0957b409SSimon J. Gerraty 634*0957b409SSimon J. Gerraty size_t len = T0_POP(); 635*0957b409SSimon J. Gerraty unsigned char *buf = (unsigned char *)CTX + T0_POP(); 636*0957b409SSimon J. Gerraty size_t u; 637*0957b409SSimon J. Gerraty 638*0957b409SSimon J. Gerraty printf("BLOB:"); 639*0957b409SSimon J. Gerraty for (u = 0; u < len; u ++) { 640*0957b409SSimon J. Gerraty if (u % 16 == 0) { 641*0957b409SSimon J. Gerraty printf("\n "); 642*0957b409SSimon J. Gerraty } 643*0957b409SSimon J. Gerraty printf(" %02x", buf[u]); 644*0957b409SSimon J. Gerraty } 645*0957b409SSimon J. Gerraty printf("\n"); 646*0957b409SSimon J. Gerraty} 647*0957b409SSimon J. Gerraty 648*0957b409SSimon J. Gerraty\ Parse incoming ServerHello. Returned value is true (-1) on session 649*0957b409SSimon J. Gerraty\ resumption. 650*0957b409SSimon J. Gerraty: read-ServerHello ( -- bool ) 651*0957b409SSimon J. Gerraty \ Get header, and check message type. 652*0957b409SSimon J. Gerraty read-handshake-header 2 = ifnot ERR_UNEXPECTED fail then 653*0957b409SSimon J. Gerraty 654*0957b409SSimon J. Gerraty \ Get protocol version. 655*0957b409SSimon J. Gerraty read16 { version } 656*0957b409SSimon J. Gerraty version addr-version_min get16 < version addr-version_max get16 > or if 657*0957b409SSimon J. Gerraty ERR_UNSUPPORTED_VERSION fail 658*0957b409SSimon J. Gerraty then 659*0957b409SSimon J. Gerraty 660*0957b409SSimon J. Gerraty \ Enforce chosen version for subsequent records in both directions. 661*0957b409SSimon J. Gerraty version addr-version_in get16 <> if ERR_BAD_VERSION fail then 662*0957b409SSimon J. Gerraty version addr-version_out set16 663*0957b409SSimon J. Gerraty 664*0957b409SSimon J. Gerraty \ Server random. 665*0957b409SSimon J. Gerraty addr-server_random 32 read-blob 666*0957b409SSimon J. Gerraty 667*0957b409SSimon J. Gerraty \ The "session resumption" flag. 668*0957b409SSimon J. Gerraty 0 { resume } 669*0957b409SSimon J. Gerraty 670*0957b409SSimon J. Gerraty \ Session ID. 671*0957b409SSimon J. Gerraty read8 { idlen } 672*0957b409SSimon J. Gerraty idlen 32 > if ERR_OVERSIZED_ID fail then 673*0957b409SSimon J. Gerraty addr-pad idlen read-blob 674*0957b409SSimon J. Gerraty idlen addr-session_id_len get8 = idlen 0 > and if 675*0957b409SSimon J. Gerraty addr-session_id addr-pad idlen memcmp if 676*0957b409SSimon J. Gerraty \ Server session ID is non-empty and matches what 677*0957b409SSimon J. Gerraty \ we sent, so this is a session resumption. 678*0957b409SSimon J. Gerraty -1 >resume 679*0957b409SSimon J. Gerraty then 680*0957b409SSimon J. Gerraty then 681*0957b409SSimon J. Gerraty addr-session_id addr-pad idlen memcpy 682*0957b409SSimon J. Gerraty idlen addr-session_id_len set8 683*0957b409SSimon J. Gerraty 684*0957b409SSimon J. Gerraty \ Record version. 685*0957b409SSimon J. Gerraty version addr-version resume check-resume 686*0957b409SSimon J. Gerraty 687*0957b409SSimon J. Gerraty \ Cipher suite. We check that it is part of the list of cipher 688*0957b409SSimon J. Gerraty \ suites that we advertised. 689*0957b409SSimon J. Gerraty read16 690*0957b409SSimon J. Gerraty dup scan-suite 0< if ERR_BAD_CIPHER_SUITE fail then 691*0957b409SSimon J. Gerraty \ Also check that the cipher suite is compatible with the 692*0957b409SSimon J. Gerraty \ announced version: suites that don't use HMAC/SHA-1 are 693*0957b409SSimon J. Gerraty \ for TLS-1.2 only, not older versions. 694*0957b409SSimon J. Gerraty dup use-tls12? version 0x0303 < and if ERR_BAD_CIPHER_SUITE fail then 695*0957b409SSimon J. Gerraty addr-cipher_suite resume check-resume 696*0957b409SSimon J. Gerraty 697*0957b409SSimon J. Gerraty \ Compression method. Should be 0 (no compression). 698*0957b409SSimon J. Gerraty read8 if ERR_BAD_COMPRESSION fail then 699*0957b409SSimon J. Gerraty 700*0957b409SSimon J. Gerraty \ Parse extensions (if any). If there is no extension, then the 701*0957b409SSimon J. Gerraty \ read limit (on the TOS) should be 0 at that point. 702*0957b409SSimon J. Gerraty dup if 703*0957b409SSimon J. Gerraty \ Length of extension list. 704*0957b409SSimon J. Gerraty \ message size. 705*0957b409SSimon J. Gerraty read16 open-elt 706*0957b409SSimon J. Gerraty 707*0957b409SSimon J. Gerraty \ Enumerate extensions. For each of them, check that we 708*0957b409SSimon J. Gerraty \ sent an extension of that type, and did not see it 709*0957b409SSimon J. Gerraty \ yet; and then process it. 710*0957b409SSimon J. Gerraty ext-sni-length { ok-sni } 711*0957b409SSimon J. Gerraty ext-reneg-length { ok-reneg } 712*0957b409SSimon J. Gerraty ext-frag-length { ok-frag } 713*0957b409SSimon J. Gerraty ext-signatures-length { ok-signatures } 714*0957b409SSimon J. Gerraty ext-supported-curves-length { ok-curves } 715*0957b409SSimon J. Gerraty ext-point-format-length { ok-points } 716*0957b409SSimon J. Gerraty ext-ALPN-length { ok-ALPN } 717*0957b409SSimon J. Gerraty begin dup while 718*0957b409SSimon J. Gerraty read16 719*0957b409SSimon J. Gerraty case 720*0957b409SSimon J. Gerraty \ Server Name Indication. The server may 721*0957b409SSimon J. Gerraty \ send such an extension if it uses the SNI 722*0957b409SSimon J. Gerraty \ from the client, but that "response 723*0957b409SSimon J. Gerraty \ extension" is supposed to be empty. 724*0957b409SSimon J. Gerraty 0x0000 of 725*0957b409SSimon J. Gerraty ok-sni ifnot 726*0957b409SSimon J. Gerraty ERR_EXTRA_EXTENSION fail 727*0957b409SSimon J. Gerraty then 728*0957b409SSimon J. Gerraty 0 >ok-sni 729*0957b409SSimon J. Gerraty read-server-sni 730*0957b409SSimon J. Gerraty endof 731*0957b409SSimon J. Gerraty 732*0957b409SSimon J. Gerraty \ Max Frag Length. The contents shall be 733*0957b409SSimon J. Gerraty \ a single byte whose value matches the one 734*0957b409SSimon J. Gerraty \ sent by the client. 735*0957b409SSimon J. Gerraty 0x0001 of 736*0957b409SSimon J. Gerraty ok-frag ifnot 737*0957b409SSimon J. Gerraty ERR_EXTRA_EXTENSION fail 738*0957b409SSimon J. Gerraty then 739*0957b409SSimon J. Gerraty 0 >ok-frag 740*0957b409SSimon J. Gerraty read-server-frag 741*0957b409SSimon J. Gerraty endof 742*0957b409SSimon J. Gerraty 743*0957b409SSimon J. Gerraty \ Secure Renegotiation. 744*0957b409SSimon J. Gerraty 0xFF01 of 745*0957b409SSimon J. Gerraty ok-reneg ifnot 746*0957b409SSimon J. Gerraty ERR_EXTRA_EXTENSION fail 747*0957b409SSimon J. Gerraty then 748*0957b409SSimon J. Gerraty 0 >ok-reneg 749*0957b409SSimon J. Gerraty read-server-reneg 750*0957b409SSimon J. Gerraty endof 751*0957b409SSimon J. Gerraty 752*0957b409SSimon J. Gerraty \ Signature Algorithms. 753*0957b409SSimon J. Gerraty \ Normally, the server should never send this 754*0957b409SSimon J. Gerraty \ extension (so says RFC 5246 #7.4.1.4.1), 755*0957b409SSimon J. Gerraty \ but some existing servers do. 756*0957b409SSimon J. Gerraty 0x000D of 757*0957b409SSimon J. Gerraty ok-signatures ifnot 758*0957b409SSimon J. Gerraty ERR_EXTRA_EXTENSION fail 759*0957b409SSimon J. Gerraty then 760*0957b409SSimon J. Gerraty 0 >ok-signatures 761*0957b409SSimon J. Gerraty read-ignore-16 762*0957b409SSimon J. Gerraty endof 763*0957b409SSimon J. Gerraty 764*0957b409SSimon J. Gerraty \ Supported Curves. 765*0957b409SSimon J. Gerraty 0x000A of 766*0957b409SSimon J. Gerraty ok-curves ifnot 767*0957b409SSimon J. Gerraty ERR_EXTRA_EXTENSION fail 768*0957b409SSimon J. Gerraty then 769*0957b409SSimon J. Gerraty 0 >ok-curves 770*0957b409SSimon J. Gerraty read-ignore-16 771*0957b409SSimon J. Gerraty endof 772*0957b409SSimon J. Gerraty 773*0957b409SSimon J. Gerraty \ Supported Point Formats. 774*0957b409SSimon J. Gerraty 0x000B of 775*0957b409SSimon J. Gerraty ok-points ifnot 776*0957b409SSimon J. Gerraty ERR_EXTRA_EXTENSION fail 777*0957b409SSimon J. Gerraty then 778*0957b409SSimon J. Gerraty 0 >ok-points 779*0957b409SSimon J. Gerraty read-ignore-16 780*0957b409SSimon J. Gerraty endof 781*0957b409SSimon J. Gerraty 782*0957b409SSimon J. Gerraty \ ALPN. 783*0957b409SSimon J. Gerraty 0x0010 of 784*0957b409SSimon J. Gerraty ok-ALPN ifnot 785*0957b409SSimon J. Gerraty ERR_EXTRA_EXTENSION fail 786*0957b409SSimon J. Gerraty then 787*0957b409SSimon J. Gerraty 0 >ok-ALPN 788*0957b409SSimon J. Gerraty read-ALPN-from-server 789*0957b409SSimon J. Gerraty endof 790*0957b409SSimon J. Gerraty 791*0957b409SSimon J. Gerraty ERR_EXTRA_EXTENSION fail 792*0957b409SSimon J. Gerraty endcase 793*0957b409SSimon J. Gerraty repeat 794*0957b409SSimon J. Gerraty 795*0957b409SSimon J. Gerraty \ If we sent a secure renegotiation extension but did not 796*0957b409SSimon J. Gerraty \ receive a response, then the server does not support 797*0957b409SSimon J. Gerraty \ secure renegotiation. This is a hard failure if this 798*0957b409SSimon J. Gerraty \ is a renegotiation. 799*0957b409SSimon J. Gerraty ok-reneg if 800*0957b409SSimon J. Gerraty ok-reneg 5 > if ERR_BAD_SECRENEG fail then 801*0957b409SSimon J. Gerraty 1 addr-reneg set8 802*0957b409SSimon J. Gerraty then 803*0957b409SSimon J. Gerraty close-elt 804*0957b409SSimon J. Gerraty else 805*0957b409SSimon J. Gerraty \ No extension received at all, so the server does not 806*0957b409SSimon J. Gerraty \ support secure renegotiation. This is a hard failure 807*0957b409SSimon J. Gerraty \ if the server was previously known to support it (i.e. 808*0957b409SSimon J. Gerraty \ this is a renegotiation). 809*0957b409SSimon J. Gerraty ext-reneg-length 5 > if ERR_BAD_SECRENEG fail then 810*0957b409SSimon J. Gerraty 1 addr-reneg set8 811*0957b409SSimon J. Gerraty then 812*0957b409SSimon J. Gerraty close-elt 813*0957b409SSimon J. Gerraty resume 814*0957b409SSimon J. Gerraty ; 815*0957b409SSimon J. Gerraty 816*0957b409SSimon J. Gerratycc: set-server-curve ( -- ) { 817*0957b409SSimon J. Gerraty const br_x509_class *xc; 818*0957b409SSimon J. Gerraty const br_x509_pkey *pk; 819*0957b409SSimon J. Gerraty 820*0957b409SSimon J. Gerraty xc = *(ENG->x509ctx); 821*0957b409SSimon J. Gerraty pk = xc->get_pkey(ENG->x509ctx, NULL); 822*0957b409SSimon J. Gerraty CTX->server_curve = 823*0957b409SSimon J. Gerraty (pk->key_type == BR_KEYTYPE_EC) ? pk->key.ec.curve : 0; 824*0957b409SSimon J. Gerraty} 825*0957b409SSimon J. Gerraty 826*0957b409SSimon J. Gerraty\ Read Certificate message from server. 827*0957b409SSimon J. Gerraty: read-Certificate-from-server ( -- ) 828*0957b409SSimon J. Gerraty addr-cipher_suite get16 expected-key-type 829*0957b409SSimon J. Gerraty -1 read-Certificate 830*0957b409SSimon J. Gerraty dup 0< if neg fail then 831*0957b409SSimon J. Gerraty dup ifnot ERR_UNEXPECTED fail then 832*0957b409SSimon J. Gerraty over and <> if ERR_WRONG_KEY_USAGE fail then 833*0957b409SSimon J. Gerraty 834*0957b409SSimon J. Gerraty \ Set server curve (used for static ECDH). 835*0957b409SSimon J. Gerraty set-server-curve ; 836*0957b409SSimon J. Gerraty 837*0957b409SSimon J. Gerraty\ Verify signature on ECDHE point sent by the server. 838*0957b409SSimon J. Gerraty\ 'hash' is the hash function to use (1 to 6, or 0 for RSA with MD5+SHA-1) 839*0957b409SSimon J. Gerraty\ 'use-rsa' is 0 for ECDSA, -1 for for RSA 840*0957b409SSimon J. Gerraty\ 'sig-len' is the signature length (in bytes) 841*0957b409SSimon J. Gerraty\ The signature itself is in the pad. 842*0957b409SSimon J. Gerratycc: verify-SKE-sig ( hash use-rsa sig-len -- err ) { 843*0957b409SSimon J. Gerraty size_t sig_len = T0_POP(); 844*0957b409SSimon J. Gerraty int use_rsa = T0_POPi(); 845*0957b409SSimon J. Gerraty int hash = T0_POPi(); 846*0957b409SSimon J. Gerraty 847*0957b409SSimon J. Gerraty T0_PUSH(verify_SKE_sig(CTX, hash, use_rsa, sig_len)); 848*0957b409SSimon J. Gerraty} 849*0957b409SSimon J. Gerraty 850*0957b409SSimon J. Gerraty\ Parse ServerKeyExchange 851*0957b409SSimon J. Gerraty: read-ServerKeyExchange ( -- ) 852*0957b409SSimon J. Gerraty \ Get header, and check message type. 853*0957b409SSimon J. Gerraty read-handshake-header 12 = ifnot ERR_UNEXPECTED fail then 854*0957b409SSimon J. Gerraty 855*0957b409SSimon J. Gerraty \ We expect a named curve, and we must support it. 856*0957b409SSimon J. Gerraty read8 3 = ifnot ERR_INVALID_ALGORITHM fail then 857*0957b409SSimon J. Gerraty read16 dup addr-ecdhe_curve set8 858*0957b409SSimon J. Gerraty dup 32 >= if ERR_INVALID_ALGORITHM fail then 859*0957b409SSimon J. Gerraty supported-curves swap >> 1 and ifnot ERR_INVALID_ALGORITHM fail then 860*0957b409SSimon J. Gerraty 861*0957b409SSimon J. Gerraty \ Read the server point. 862*0957b409SSimon J. Gerraty read8 863*0957b409SSimon J. Gerraty dup 133 > if ERR_INVALID_ALGORITHM fail then 864*0957b409SSimon J. Gerraty dup addr-ecdhe_point_len set8 865*0957b409SSimon J. Gerraty addr-ecdhe_point swap read-blob 866*0957b409SSimon J. Gerraty 867*0957b409SSimon J. Gerraty \ If using TLS-1.2+, then the hash function and signature algorithm 868*0957b409SSimon J. Gerraty \ are explicitly provided; the signature algorithm must match what 869*0957b409SSimon J. Gerraty \ the cipher suite specifies. With TLS-1.0 and 1.1, the signature 870*0957b409SSimon J. Gerraty \ algorithm is inferred from the cipher suite, and the hash is 871*0957b409SSimon J. Gerraty \ either MD5+SHA-1 (for RSA signatures) or SHA-1 (for ECDSA). 872*0957b409SSimon J. Gerraty addr-version get16 0x0303 >= { tls1.2+ } 873*0957b409SSimon J. Gerraty addr-cipher_suite get16 use-rsa-ecdhe? { use-rsa } 874*0957b409SSimon J. Gerraty 2 { hash } 875*0957b409SSimon J. Gerraty tls1.2+ if 876*0957b409SSimon J. Gerraty \ Read hash function; accept only the SHA-* identifiers 877*0957b409SSimon J. Gerraty \ (from SHA-1 to SHA-512, no MD5 here). 878*0957b409SSimon J. Gerraty read8 879*0957b409SSimon J. Gerraty dup dup 2 < swap 6 > or if ERR_INVALID_ALGORITHM fail then 880*0957b409SSimon J. Gerraty >hash 881*0957b409SSimon J. Gerraty read8 882*0957b409SSimon J. Gerraty \ Get expected signature algorithm and compare with what 883*0957b409SSimon J. Gerraty \ the server just sent. Expected value is 1 for RSA, 3 884*0957b409SSimon J. Gerraty \ for ECDSA. Note that 'use-rsa' evaluates to -1 for RSA, 885*0957b409SSimon J. Gerraty \ 0 for ECDSA. 886*0957b409SSimon J. Gerraty use-rsa 1 << 3 + = ifnot ERR_INVALID_ALGORITHM fail then 887*0957b409SSimon J. Gerraty else 888*0957b409SSimon J. Gerraty \ For MD5+SHA-1, we set 'hash' to 0. 889*0957b409SSimon J. Gerraty use-rsa if 0 >hash then 890*0957b409SSimon J. Gerraty then 891*0957b409SSimon J. Gerraty 892*0957b409SSimon J. Gerraty \ Read signature into the pad. 893*0957b409SSimon J. Gerraty read16 dup { sig-len } 894*0957b409SSimon J. Gerraty 895*0957b409SSimon J. Gerraty dup 512 > if ERR_LIMIT_EXCEEDED fail then 896*0957b409SSimon J. Gerraty addr-pad swap read-blob 897*0957b409SSimon J. Gerraty 898*0957b409SSimon J. Gerraty \ Verify signature. 899*0957b409SSimon J. Gerraty hash use-rsa sig-len verify-SKE-sig 900*0957b409SSimon J. Gerraty dup if fail then drop 901*0957b409SSimon J. Gerraty 902*0957b409SSimon J. Gerraty close-elt ; 903*0957b409SSimon J. Gerraty 904*0957b409SSimon J. Gerraty\ Client certificate: start processing of anchor names. 905*0957b409SSimon J. Gerratycc: anchor-dn-start-name-list ( -- ) { 906*0957b409SSimon J. Gerraty if (CTX->client_auth_vtable != NULL) { 907*0957b409SSimon J. Gerraty (*CTX->client_auth_vtable)->start_name_list( 908*0957b409SSimon J. Gerraty CTX->client_auth_vtable); 909*0957b409SSimon J. Gerraty } 910*0957b409SSimon J. Gerraty} 911*0957b409SSimon J. Gerraty 912*0957b409SSimon J. Gerraty\ Client certificate: start a new anchor DN (length is 16-bit). 913*0957b409SSimon J. Gerratycc: anchor-dn-start-name ( length -- ) { 914*0957b409SSimon J. Gerraty size_t len; 915*0957b409SSimon J. Gerraty 916*0957b409SSimon J. Gerraty len = T0_POP(); 917*0957b409SSimon J. Gerraty if (CTX->client_auth_vtable != NULL) { 918*0957b409SSimon J. Gerraty (*CTX->client_auth_vtable)->start_name( 919*0957b409SSimon J. Gerraty CTX->client_auth_vtable, len); 920*0957b409SSimon J. Gerraty } 921*0957b409SSimon J. Gerraty} 922*0957b409SSimon J. Gerraty 923*0957b409SSimon J. Gerraty\ Client certificate: push some data for current anchor DN. 924*0957b409SSimon J. Gerratycc: anchor-dn-append-name ( length -- ) { 925*0957b409SSimon J. Gerraty size_t len; 926*0957b409SSimon J. Gerraty 927*0957b409SSimon J. Gerraty len = T0_POP(); 928*0957b409SSimon J. Gerraty if (CTX->client_auth_vtable != NULL) { 929*0957b409SSimon J. Gerraty (*CTX->client_auth_vtable)->append_name( 930*0957b409SSimon J. Gerraty CTX->client_auth_vtable, ENG->pad, len); 931*0957b409SSimon J. Gerraty } 932*0957b409SSimon J. Gerraty} 933*0957b409SSimon J. Gerraty 934*0957b409SSimon J. Gerraty\ Client certificate: end current anchor DN. 935*0957b409SSimon J. Gerratycc: anchor-dn-end-name ( -- ) { 936*0957b409SSimon J. Gerraty if (CTX->client_auth_vtable != NULL) { 937*0957b409SSimon J. Gerraty (*CTX->client_auth_vtable)->end_name( 938*0957b409SSimon J. Gerraty CTX->client_auth_vtable); 939*0957b409SSimon J. Gerraty } 940*0957b409SSimon J. Gerraty} 941*0957b409SSimon J. Gerraty 942*0957b409SSimon J. Gerraty\ Client certificate: end list of anchor DN. 943*0957b409SSimon J. Gerratycc: anchor-dn-end-name-list ( -- ) { 944*0957b409SSimon J. Gerraty if (CTX->client_auth_vtable != NULL) { 945*0957b409SSimon J. Gerraty (*CTX->client_auth_vtable)->end_name_list( 946*0957b409SSimon J. Gerraty CTX->client_auth_vtable); 947*0957b409SSimon J. Gerraty } 948*0957b409SSimon J. Gerraty} 949*0957b409SSimon J. Gerraty 950*0957b409SSimon J. Gerraty\ Client certificate: obtain the client certificate chain. 951*0957b409SSimon J. Gerratycc: get-client-chain ( auth_types -- ) { 952*0957b409SSimon J. Gerraty uint32_t auth_types; 953*0957b409SSimon J. Gerraty 954*0957b409SSimon J. Gerraty auth_types = T0_POP(); 955*0957b409SSimon J. Gerraty if (CTX->client_auth_vtable != NULL) { 956*0957b409SSimon J. Gerraty br_ssl_client_certificate ux; 957*0957b409SSimon J. Gerraty 958*0957b409SSimon J. Gerraty (*CTX->client_auth_vtable)->choose(CTX->client_auth_vtable, 959*0957b409SSimon J. Gerraty CTX, auth_types, &ux); 960*0957b409SSimon J. Gerraty CTX->auth_type = (unsigned char)ux.auth_type; 961*0957b409SSimon J. Gerraty CTX->hash_id = (unsigned char)ux.hash_id; 962*0957b409SSimon J. Gerraty ENG->chain = ux.chain; 963*0957b409SSimon J. Gerraty ENG->chain_len = ux.chain_len; 964*0957b409SSimon J. Gerraty } else { 965*0957b409SSimon J. Gerraty CTX->hash_id = 0; 966*0957b409SSimon J. Gerraty ENG->chain_len = 0; 967*0957b409SSimon J. Gerraty } 968*0957b409SSimon J. Gerraty} 969*0957b409SSimon J. Gerraty 970*0957b409SSimon J. Gerraty\ Parse CertificateRequest. Header has already been read. 971*0957b409SSimon J. Gerraty: read-contents-CertificateRequest ( lim -- ) 972*0957b409SSimon J. Gerraty \ Read supported client authentication types. We keep only 973*0957b409SSimon J. Gerraty \ RSA, ECDSA, and ECDH. 974*0957b409SSimon J. Gerraty 0 { auth_types } 975*0957b409SSimon J. Gerraty read8 open-elt 976*0957b409SSimon J. Gerraty begin dup while 977*0957b409SSimon J. Gerraty read8 case 978*0957b409SSimon J. Gerraty 1 of 0x0000FF endof 979*0957b409SSimon J. Gerraty 64 of 0x00FF00 endof 980*0957b409SSimon J. Gerraty 65 of 0x010000 endof 981*0957b409SSimon J. Gerraty 66 of 0x020000 endof 982*0957b409SSimon J. Gerraty 0 swap 983*0957b409SSimon J. Gerraty endcase 984*0957b409SSimon J. Gerraty auth_types or >auth_types 985*0957b409SSimon J. Gerraty repeat 986*0957b409SSimon J. Gerraty close-elt 987*0957b409SSimon J. Gerraty 988*0957b409SSimon J. Gerraty \ Full static ECDH is allowed only if the cipher suite is ECDH 989*0957b409SSimon J. Gerraty \ (not ECDHE). It would be theoretically feasible to use static 990*0957b409SSimon J. Gerraty \ ECDH on the client side with an ephemeral key pair from the 991*0957b409SSimon J. Gerraty \ server, but RFC 4492 (section 3) forbids it because ECDHE suites 992*0957b409SSimon J. Gerraty \ are supposed to provide forward secrecy, and static ECDH would 993*0957b409SSimon J. Gerraty \ negate that property. 994*0957b409SSimon J. Gerraty addr-cipher_suite get16 use-ecdh? ifnot 995*0957b409SSimon J. Gerraty auth_types 0xFFFF and >auth_types 996*0957b409SSimon J. Gerraty then 997*0957b409SSimon J. Gerraty 998*0957b409SSimon J. Gerraty \ Note: if the cipher suite is ECDH, then the X.509 validation 999*0957b409SSimon J. Gerraty \ engine was invoked with the BR_KEYTYPE_EC | BR_KEYTYPE_KEYX 1000*0957b409SSimon J. Gerraty \ combination, so the server's public key has already been 1001*0957b409SSimon J. Gerraty \ checked to be fit for a key exchange. 1002*0957b409SSimon J. Gerraty 1003*0957b409SSimon J. Gerraty \ With TLS 1.2: 1004*0957b409SSimon J. Gerraty \ - rsa_fixed_ecdh and ecdsa_fixed_ecdh are synoymous. 1005*0957b409SSimon J. Gerraty \ - There is an explicit list of supported sign+hash. 1006*0957b409SSimon J. Gerraty \ With TLS 1.0, 1007*0957b409SSimon J. Gerraty addr-version get16 0x0303 >= if 1008*0957b409SSimon J. Gerraty \ With TLS 1.2: 1009*0957b409SSimon J. Gerraty \ - There is an explicit list of supported sign+hash. 1010*0957b409SSimon J. Gerraty \ - The ECDH flags must be adjusted for RSA/ECDSA 1011*0957b409SSimon J. Gerraty \ support. 1012*0957b409SSimon J. Gerraty read-list-sign-algos dup addr-hashes set32 1013*0957b409SSimon J. Gerraty 1014*0957b409SSimon J. Gerraty \ Trim down the list depending on what hash functions 1015*0957b409SSimon J. Gerraty \ we support (since the hashing itself is done by the SSL 1016*0957b409SSimon J. Gerraty \ engine, not by the certificate handler). 1017*0957b409SSimon J. Gerraty supported-hash-functions drop dup 8 << or 0x030000 or and 1018*0957b409SSimon J. Gerraty 1019*0957b409SSimon J. Gerraty auth_types and 1020*0957b409SSimon J. Gerraty auth_types 0x030000 and if 1021*0957b409SSimon J. Gerraty dup 0x0000FF and if 0x010000 or then 1022*0957b409SSimon J. Gerraty dup 0x00FF00 and if 0x020000 or then 1023*0957b409SSimon J. Gerraty then 1024*0957b409SSimon J. Gerraty >auth_types 1025*0957b409SSimon J. Gerraty else 1026*0957b409SSimon J. Gerraty \ TLS 1.0 or 1.1. The hash function is fixed for signatures 1027*0957b409SSimon J. Gerraty \ (MD5+SHA-1 for RSA, SHA-1 for ECDSA). 1028*0957b409SSimon J. Gerraty auth_types 0x030401 and >auth_types 1029*0957b409SSimon J. Gerraty then 1030*0957b409SSimon J. Gerraty 1031*0957b409SSimon J. Gerraty \ Parse list of anchor DN. 1032*0957b409SSimon J. Gerraty anchor-dn-start-name-list 1033*0957b409SSimon J. Gerraty read16 open-elt 1034*0957b409SSimon J. Gerraty begin dup while 1035*0957b409SSimon J. Gerraty read16 open-elt 1036*0957b409SSimon J. Gerraty dup anchor-dn-start-name 1037*0957b409SSimon J. Gerraty 1038*0957b409SSimon J. Gerraty \ We read the DN by chunks through the pad, so 1039*0957b409SSimon J. Gerraty \ as to use the existing reading function (read-blob) 1040*0957b409SSimon J. Gerraty \ that also ensures proper hashing. 1041*0957b409SSimon J. Gerraty begin 1042*0957b409SSimon J. Gerraty dup while 1043*0957b409SSimon J. Gerraty dup 256 > if 256 else dup then { len } 1044*0957b409SSimon J. Gerraty addr-pad len read-blob 1045*0957b409SSimon J. Gerraty len anchor-dn-append-name 1046*0957b409SSimon J. Gerraty repeat 1047*0957b409SSimon J. Gerraty close-elt 1048*0957b409SSimon J. Gerraty anchor-dn-end-name 1049*0957b409SSimon J. Gerraty repeat 1050*0957b409SSimon J. Gerraty close-elt 1051*0957b409SSimon J. Gerraty anchor-dn-end-name-list 1052*0957b409SSimon J. Gerraty 1053*0957b409SSimon J. Gerraty \ We should have reached the message end. 1054*0957b409SSimon J. Gerraty close-elt 1055*0957b409SSimon J. Gerraty 1056*0957b409SSimon J. Gerraty \ Obtain the client chain. 1057*0957b409SSimon J. Gerraty auth_types get-client-chain 1058*0957b409SSimon J. Gerraty ; 1059*0957b409SSimon J. Gerraty 1060*0957b409SSimon J. Gerraty\ (obsolete) 1061*0957b409SSimon J. Gerraty\ Write an empty Certificate message. 1062*0957b409SSimon J. Gerraty\ : write-empty-Certificate ( -- ) 1063*0957b409SSimon J. Gerraty\ 11 write8 3 write24 0 write24 ; 1064*0957b409SSimon J. Gerraty 1065*0957b409SSimon J. Gerratycc: do-rsa-encrypt ( prf_id -- nlen ) { 1066*0957b409SSimon J. Gerraty int x; 1067*0957b409SSimon J. Gerraty 1068*0957b409SSimon J. Gerraty x = make_pms_rsa(CTX, T0_POP()); 1069*0957b409SSimon J. Gerraty if (x < 0) { 1070*0957b409SSimon J. Gerraty br_ssl_engine_fail(ENG, -x); 1071*0957b409SSimon J. Gerraty T0_CO(); 1072*0957b409SSimon J. Gerraty } else { 1073*0957b409SSimon J. Gerraty T0_PUSH(x); 1074*0957b409SSimon J. Gerraty } 1075*0957b409SSimon J. Gerraty} 1076*0957b409SSimon J. Gerraty 1077*0957b409SSimon J. Gerratycc: do-ecdh ( echde prf_id -- ulen ) { 1078*0957b409SSimon J. Gerraty unsigned prf_id = T0_POP(); 1079*0957b409SSimon J. Gerraty unsigned ecdhe = T0_POP(); 1080*0957b409SSimon J. Gerraty int x; 1081*0957b409SSimon J. Gerraty 1082*0957b409SSimon J. Gerraty x = make_pms_ecdh(CTX, ecdhe, prf_id); 1083*0957b409SSimon J. Gerraty if (x < 0) { 1084*0957b409SSimon J. Gerraty br_ssl_engine_fail(ENG, -x); 1085*0957b409SSimon J. Gerraty T0_CO(); 1086*0957b409SSimon J. Gerraty } else { 1087*0957b409SSimon J. Gerraty T0_PUSH(x); 1088*0957b409SSimon J. Gerraty } 1089*0957b409SSimon J. Gerraty} 1090*0957b409SSimon J. Gerraty 1091*0957b409SSimon J. Gerratycc: do-static-ecdh ( prf-id -- ) { 1092*0957b409SSimon J. Gerraty unsigned prf_id = T0_POP(); 1093*0957b409SSimon J. Gerraty 1094*0957b409SSimon J. Gerraty if (make_pms_static_ecdh(CTX, prf_id) < 0) { 1095*0957b409SSimon J. Gerraty br_ssl_engine_fail(ENG, BR_ERR_INVALID_ALGORITHM); 1096*0957b409SSimon J. Gerraty T0_CO(); 1097*0957b409SSimon J. Gerraty } 1098*0957b409SSimon J. Gerraty} 1099*0957b409SSimon J. Gerraty 1100*0957b409SSimon J. Gerratycc: do-client-sign ( -- sig_len ) { 1101*0957b409SSimon J. Gerraty size_t sig_len; 1102*0957b409SSimon J. Gerraty 1103*0957b409SSimon J. Gerraty sig_len = make_client_sign(CTX); 1104*0957b409SSimon J. Gerraty if (sig_len == 0) { 1105*0957b409SSimon J. Gerraty br_ssl_engine_fail(ENG, BR_ERR_INVALID_ALGORITHM); 1106*0957b409SSimon J. Gerraty T0_CO(); 1107*0957b409SSimon J. Gerraty } 1108*0957b409SSimon J. Gerraty T0_PUSH(sig_len); 1109*0957b409SSimon J. Gerraty} 1110*0957b409SSimon J. Gerraty 1111*0957b409SSimon J. Gerraty\ Write ClientKeyExchange. 1112*0957b409SSimon J. Gerraty: write-ClientKeyExchange ( -- ) 1113*0957b409SSimon J. Gerraty 16 write8 1114*0957b409SSimon J. Gerraty addr-cipher_suite get16 1115*0957b409SSimon J. Gerraty dup use-rsa-keyx? if 1116*0957b409SSimon J. Gerraty prf-id do-rsa-encrypt 1117*0957b409SSimon J. Gerraty dup 2+ write24 1118*0957b409SSimon J. Gerraty dup write16 1119*0957b409SSimon J. Gerraty addr-pad swap write-blob 1120*0957b409SSimon J. Gerraty else 1121*0957b409SSimon J. Gerraty dup use-ecdhe? swap prf-id do-ecdh 1122*0957b409SSimon J. Gerraty dup 1+ write24 1123*0957b409SSimon J. Gerraty dup write8 1124*0957b409SSimon J. Gerraty addr-pad swap write-blob 1125*0957b409SSimon J. Gerraty then ; 1126*0957b409SSimon J. Gerraty 1127*0957b409SSimon J. Gerraty\ Write CertificateVerify. This is invoked only if a client certificate 1128*0957b409SSimon J. Gerraty\ was requested and sent, and the authentication is not full static ECDH. 1129*0957b409SSimon J. Gerraty: write-CertificateVerify ( -- ) 1130*0957b409SSimon J. Gerraty do-client-sign 1131*0957b409SSimon J. Gerraty 15 write8 dup 1132*0957b409SSimon J. Gerraty addr-version get16 0x0303 >= if 1133*0957b409SSimon J. Gerraty 4 + write24 1134*0957b409SSimon J. Gerraty addr-hash_id get8 write8 1135*0957b409SSimon J. Gerraty addr-auth_type get8 write8 1136*0957b409SSimon J. Gerraty else 1137*0957b409SSimon J. Gerraty 2+ write24 1138*0957b409SSimon J. Gerraty then 1139*0957b409SSimon J. Gerraty dup write16 addr-pad swap write-blob ; 1140*0957b409SSimon J. Gerraty 1141*0957b409SSimon J. Gerraty\ ======================================================================= 1142*0957b409SSimon J. Gerraty 1143*0957b409SSimon J. Gerraty\ Perform a handshake. 1144*0957b409SSimon J. Gerraty: do-handshake ( -- ) 1145*0957b409SSimon J. Gerraty 0 addr-application_data set8 1146*0957b409SSimon J. Gerraty 22 addr-record_type_out set8 1147*0957b409SSimon J. Gerraty 0 addr-selected_protocol set16 1148*0957b409SSimon J. Gerraty multihash-init 1149*0957b409SSimon J. Gerraty 1150*0957b409SSimon J. Gerraty write-ClientHello 1151*0957b409SSimon J. Gerraty flush-record 1152*0957b409SSimon J. Gerraty read-ServerHello 1153*0957b409SSimon J. Gerraty 1154*0957b409SSimon J. Gerraty if 1155*0957b409SSimon J. Gerraty \ Session resumption. 1156*0957b409SSimon J. Gerraty -1 read-CCS-Finished 1157*0957b409SSimon J. Gerraty -1 write-CCS-Finished 1158*0957b409SSimon J. Gerraty 1159*0957b409SSimon J. Gerraty else 1160*0957b409SSimon J. Gerraty 1161*0957b409SSimon J. Gerraty \ Not a session resumption. 1162*0957b409SSimon J. Gerraty 1163*0957b409SSimon J. Gerraty \ Read certificate; then check key type and usages against 1164*0957b409SSimon J. Gerraty \ cipher suite. 1165*0957b409SSimon J. Gerraty read-Certificate-from-server 1166*0957b409SSimon J. Gerraty 1167*0957b409SSimon J. Gerraty \ Depending on cipher suite, we may now expect a 1168*0957b409SSimon J. Gerraty \ ServerKeyExchange. 1169*0957b409SSimon J. Gerraty addr-cipher_suite get16 expected-key-type 1170*0957b409SSimon J. Gerraty CX 0 63 { BR_KEYTYPE_SIGN } and if 1171*0957b409SSimon J. Gerraty read-ServerKeyExchange 1172*0957b409SSimon J. Gerraty then 1173*0957b409SSimon J. Gerraty 1174*0957b409SSimon J. Gerraty \ Get next header. 1175*0957b409SSimon J. Gerraty read-handshake-header 1176*0957b409SSimon J. Gerraty 1177*0957b409SSimon J. Gerraty \ If this is a CertificateRequest, parse it, then read 1178*0957b409SSimon J. Gerraty \ next header. 1179*0957b409SSimon J. Gerraty dup 13 = if 1180*0957b409SSimon J. Gerraty drop read-contents-CertificateRequest 1181*0957b409SSimon J. Gerraty read-handshake-header 1182*0957b409SSimon J. Gerraty -1 1183*0957b409SSimon J. Gerraty else 1184*0957b409SSimon J. Gerraty 0 1185*0957b409SSimon J. Gerraty then 1186*0957b409SSimon J. Gerraty { seen-CR } 1187*0957b409SSimon J. Gerraty 1188*0957b409SSimon J. Gerraty \ At that point, we should have a ServerHelloDone, 1189*0957b409SSimon J. Gerraty \ whose length must be 0. 1190*0957b409SSimon J. Gerraty 14 = ifnot ERR_UNEXPECTED fail then 1191*0957b409SSimon J. Gerraty if ERR_BAD_HELLO_DONE fail then 1192*0957b409SSimon J. Gerraty 1193*0957b409SSimon J. Gerraty \ There should not be more bytes in the record at that point. 1194*0957b409SSimon J. Gerraty more-incoming-bytes? if ERR_UNEXPECTED fail then 1195*0957b409SSimon J. Gerraty 1196*0957b409SSimon J. Gerraty seen-CR if 1197*0957b409SSimon J. Gerraty \ If the server requested a client certificate, then 1198*0957b409SSimon J. Gerraty \ we must write a Certificate message (it may be 1199*0957b409SSimon J. Gerraty \ empty). 1200*0957b409SSimon J. Gerraty write-Certificate 1201*0957b409SSimon J. Gerraty 1202*0957b409SSimon J. Gerraty \ If using static ECDH, then the ClientKeyExchange 1203*0957b409SSimon J. Gerraty \ is empty, and there is no CertificateVerify. 1204*0957b409SSimon J. Gerraty \ Otherwise, there is a ClientKeyExchange; there 1205*0957b409SSimon J. Gerraty \ will then be a CertificateVerify if a client chain 1206*0957b409SSimon J. Gerraty \ was indeed sent. 1207*0957b409SSimon J. Gerraty addr-hash_id get8 0xFF = if 1208*0957b409SSimon J. Gerraty drop 1209*0957b409SSimon J. Gerraty 16 write8 0 write24 1210*0957b409SSimon J. Gerraty addr-cipher_suite get16 prf-id do-static-ecdh 1211*0957b409SSimon J. Gerraty else 1212*0957b409SSimon J. Gerraty write-ClientKeyExchange 1213*0957b409SSimon J. Gerraty if write-CertificateVerify then 1214*0957b409SSimon J. Gerraty then 1215*0957b409SSimon J. Gerraty else 1216*0957b409SSimon J. Gerraty write-ClientKeyExchange 1217*0957b409SSimon J. Gerraty then 1218*0957b409SSimon J. Gerraty 1219*0957b409SSimon J. Gerraty -1 write-CCS-Finished 1220*0957b409SSimon J. Gerraty -1 read-CCS-Finished 1221*0957b409SSimon J. Gerraty then 1222*0957b409SSimon J. Gerraty 1223*0957b409SSimon J. Gerraty \ Now we should be invoked only in case of renegotiation. 1224*0957b409SSimon J. Gerraty 1 addr-application_data set8 1225*0957b409SSimon J. Gerraty 23 addr-record_type_out set8 ; 1226*0957b409SSimon J. Gerraty 1227*0957b409SSimon J. Gerraty\ Read a HelloRequest message. 1228*0957b409SSimon J. Gerraty: read-HelloRequest ( -- ) 1229*0957b409SSimon J. Gerraty \ A HelloRequest has length 0 and type 0. 1230*0957b409SSimon J. Gerraty read-handshake-header-core 1231*0957b409SSimon J. Gerraty if ERR_UNEXPECTED fail then 1232*0957b409SSimon J. Gerraty if ERR_BAD_HANDSHAKE fail then ; 1233*0957b409SSimon J. Gerraty 1234*0957b409SSimon J. Gerraty\ Entry point. 1235*0957b409SSimon J. Gerraty: main ( -- ! ) 1236*0957b409SSimon J. Gerraty \ Perform initial handshake. 1237*0957b409SSimon J. Gerraty do-handshake 1238*0957b409SSimon J. Gerraty 1239*0957b409SSimon J. Gerraty begin 1240*0957b409SSimon J. Gerraty \ Wait for further invocation. At that point, we should 1241*0957b409SSimon J. Gerraty \ get either an explicit call for renegotiation, or 1242*0957b409SSimon J. Gerraty \ an incoming HelloRequest handshake message. 1243*0957b409SSimon J. Gerraty wait-co 1244*0957b409SSimon J. Gerraty dup 0x07 and case 1245*0957b409SSimon J. Gerraty 0x00 of 1246*0957b409SSimon J. Gerraty 0x10 and if 1247*0957b409SSimon J. Gerraty do-handshake 1248*0957b409SSimon J. Gerraty then 1249*0957b409SSimon J. Gerraty endof 1250*0957b409SSimon J. Gerraty 0x01 of 1251*0957b409SSimon J. Gerraty drop 1252*0957b409SSimon J. Gerraty 0 addr-application_data set8 1253*0957b409SSimon J. Gerraty read-HelloRequest 1254*0957b409SSimon J. Gerraty \ Reject renegotiations if the peer does not 1255*0957b409SSimon J. Gerraty \ support secure renegotiation, or if the 1256*0957b409SSimon J. Gerraty \ "no renegotiation" flag is set. 1257*0957b409SSimon J. Gerraty addr-reneg get8 1 = 1 flag? or if 1258*0957b409SSimon J. Gerraty flush-record 1259*0957b409SSimon J. Gerraty begin can-output? not while 1260*0957b409SSimon J. Gerraty wait-co drop 1261*0957b409SSimon J. Gerraty repeat 1262*0957b409SSimon J. Gerraty 100 send-warning 1263*0957b409SSimon J. Gerraty \ We rejected the renegotiation, 1264*0957b409SSimon J. Gerraty \ but the connection is not dead. 1265*0957b409SSimon J. Gerraty \ We must set back things into 1266*0957b409SSimon J. Gerraty \ working "application data" state. 1267*0957b409SSimon J. Gerraty 1 addr-application_data set8 1268*0957b409SSimon J. Gerraty 23 addr-record_type_out set8 1269*0957b409SSimon J. Gerraty else 1270*0957b409SSimon J. Gerraty do-handshake 1271*0957b409SSimon J. Gerraty then 1272*0957b409SSimon J. Gerraty endof 1273*0957b409SSimon J. Gerraty ERR_UNEXPECTED fail 1274*0957b409SSimon J. Gerraty endcase 1275*0957b409SSimon J. Gerraty again 1276*0957b409SSimon J. Gerraty ; 1277