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 server. 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 server 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_server_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_server_context *)ENG) 38*0957b409SSimon J. Gerraty 39*0957b409SSimon J. Gerraty/* 40*0957b409SSimon J. Gerraty * Decrypt the pre-master secret (RSA key exchange). 41*0957b409SSimon J. Gerraty */ 42*0957b409SSimon J. Gerratystatic void 43*0957b409SSimon J. Gerratydo_rsa_decrypt(br_ssl_server_context *ctx, int prf_id, 44*0957b409SSimon J. Gerraty unsigned char *epms, size_t len) 45*0957b409SSimon J. Gerraty{ 46*0957b409SSimon J. Gerraty uint32_t x; 47*0957b409SSimon J. Gerraty unsigned char rpms[48]; 48*0957b409SSimon J. Gerraty 49*0957b409SSimon J. Gerraty /* 50*0957b409SSimon J. Gerraty * Decrypt the PMS. 51*0957b409SSimon J. Gerraty */ 52*0957b409SSimon J. Gerraty x = (*ctx->policy_vtable)->do_keyx(ctx->policy_vtable, epms, &len); 53*0957b409SSimon J. Gerraty 54*0957b409SSimon J. Gerraty /* 55*0957b409SSimon J. Gerraty * Set the first two bytes to the maximum supported client 56*0957b409SSimon J. Gerraty * protocol version. These bytes are used for version rollback 57*0957b409SSimon J. Gerraty * detection; forceing the two bytes will make the master secret 58*0957b409SSimon J. Gerraty * wrong if the bytes are not correct. This process is 59*0957b409SSimon J. Gerraty * recommended by RFC 5246 (section 7.4.7.1). 60*0957b409SSimon J. Gerraty */ 61*0957b409SSimon J. Gerraty br_enc16be(epms, ctx->client_max_version); 62*0957b409SSimon J. Gerraty 63*0957b409SSimon J. Gerraty /* 64*0957b409SSimon J. Gerraty * Make a random PMS and copy it above the decrypted value if the 65*0957b409SSimon J. Gerraty * decryption failed. Note that we use a constant-time conditional 66*0957b409SSimon J. Gerraty * copy. 67*0957b409SSimon J. Gerraty */ 68*0957b409SSimon J. Gerraty br_hmac_drbg_generate(&ctx->eng.rng, rpms, sizeof rpms); 69*0957b409SSimon J. Gerraty br_ccopy(x ^ 1, epms, rpms, sizeof rpms); 70*0957b409SSimon J. Gerraty 71*0957b409SSimon J. Gerraty /* 72*0957b409SSimon J. Gerraty * Compute master secret. 73*0957b409SSimon J. Gerraty */ 74*0957b409SSimon J. Gerraty br_ssl_engine_compute_master(&ctx->eng, prf_id, epms, 48); 75*0957b409SSimon J. Gerraty 76*0957b409SSimon J. Gerraty /* 77*0957b409SSimon J. Gerraty * Clear the pre-master secret from RAM: it is normally a buffer 78*0957b409SSimon J. Gerraty * in the context, hence potentially long-lived. 79*0957b409SSimon J. Gerraty */ 80*0957b409SSimon J. Gerraty memset(epms, 0, len); 81*0957b409SSimon J. Gerraty} 82*0957b409SSimon J. Gerraty 83*0957b409SSimon J. Gerraty/* 84*0957b409SSimon J. Gerraty * Common part for ECDH and ECDHE. 85*0957b409SSimon J. Gerraty */ 86*0957b409SSimon J. Gerratystatic void 87*0957b409SSimon J. Gerratyecdh_common(br_ssl_server_context *ctx, int prf_id, 88*0957b409SSimon J. Gerraty unsigned char *xcoor, size_t xcoor_len, uint32_t ctl) 89*0957b409SSimon J. Gerraty{ 90*0957b409SSimon J. Gerraty unsigned char rpms[80]; 91*0957b409SSimon J. Gerraty 92*0957b409SSimon J. Gerraty if (xcoor_len > sizeof rpms) { 93*0957b409SSimon J. Gerraty xcoor_len = sizeof rpms; 94*0957b409SSimon J. Gerraty ctl = 0; 95*0957b409SSimon J. Gerraty } 96*0957b409SSimon J. Gerraty 97*0957b409SSimon J. Gerraty /* 98*0957b409SSimon J. Gerraty * Make a random PMS and copy it above the decrypted value if the 99*0957b409SSimon J. Gerraty * decryption failed. Note that we use a constant-time conditional 100*0957b409SSimon J. Gerraty * copy. 101*0957b409SSimon J. Gerraty */ 102*0957b409SSimon J. Gerraty br_hmac_drbg_generate(&ctx->eng.rng, rpms, xcoor_len); 103*0957b409SSimon J. Gerraty br_ccopy(ctl ^ 1, xcoor, rpms, xcoor_len); 104*0957b409SSimon J. Gerraty 105*0957b409SSimon J. Gerraty /* 106*0957b409SSimon J. Gerraty * Compute master secret. 107*0957b409SSimon J. Gerraty */ 108*0957b409SSimon J. Gerraty br_ssl_engine_compute_master(&ctx->eng, prf_id, xcoor, xcoor_len); 109*0957b409SSimon J. Gerraty 110*0957b409SSimon J. Gerraty /* 111*0957b409SSimon J. Gerraty * Clear the pre-master secret from RAM: it is normally a buffer 112*0957b409SSimon J. Gerraty * in the context, hence potentially long-lived. 113*0957b409SSimon J. Gerraty */ 114*0957b409SSimon J. Gerraty memset(xcoor, 0, xcoor_len); 115*0957b409SSimon J. Gerraty} 116*0957b409SSimon J. Gerraty 117*0957b409SSimon J. Gerraty/* 118*0957b409SSimon J. Gerraty * Do the ECDH key exchange (not ECDHE). 119*0957b409SSimon J. Gerraty */ 120*0957b409SSimon J. Gerratystatic void 121*0957b409SSimon J. Gerratydo_ecdh(br_ssl_server_context *ctx, int prf_id, 122*0957b409SSimon J. Gerraty unsigned char *cpoint, size_t cpoint_len) 123*0957b409SSimon J. Gerraty{ 124*0957b409SSimon J. Gerraty uint32_t x; 125*0957b409SSimon J. Gerraty 126*0957b409SSimon J. Gerraty /* 127*0957b409SSimon J. Gerraty * Finalise the key exchange. 128*0957b409SSimon J. Gerraty */ 129*0957b409SSimon J. Gerraty x = (*ctx->policy_vtable)->do_keyx(ctx->policy_vtable, 130*0957b409SSimon J. Gerraty cpoint, &cpoint_len); 131*0957b409SSimon J. Gerraty ecdh_common(ctx, prf_id, cpoint, cpoint_len, x); 132*0957b409SSimon J. Gerraty} 133*0957b409SSimon J. Gerraty 134*0957b409SSimon J. Gerraty/* 135*0957b409SSimon J. Gerraty * Do the full static ECDH key exchange. When this function is called, 136*0957b409SSimon J. Gerraty * it has already been verified that the cipher suite uses ECDH (not ECDHE), 137*0957b409SSimon J. Gerraty * and the client's public key (from its certificate) has type EC and is 138*0957b409SSimon J. Gerraty * apt for key exchange. 139*0957b409SSimon J. Gerraty */ 140*0957b409SSimon J. Gerratystatic void 141*0957b409SSimon J. Gerratydo_static_ecdh(br_ssl_server_context *ctx, int prf_id) 142*0957b409SSimon J. Gerraty{ 143*0957b409SSimon J. Gerraty unsigned char cpoint[133]; 144*0957b409SSimon J. Gerraty size_t cpoint_len; 145*0957b409SSimon J. Gerraty const br_x509_class **xc; 146*0957b409SSimon J. Gerraty const br_x509_pkey *pk; 147*0957b409SSimon J. Gerraty 148*0957b409SSimon J. Gerraty xc = ctx->eng.x509ctx; 149*0957b409SSimon J. Gerraty pk = (*xc)->get_pkey(xc, NULL); 150*0957b409SSimon J. Gerraty cpoint_len = pk->key.ec.qlen; 151*0957b409SSimon J. Gerraty if (cpoint_len > sizeof cpoint) { 152*0957b409SSimon J. Gerraty /* 153*0957b409SSimon J. Gerraty * If the point is larger than our buffer then we need to 154*0957b409SSimon J. Gerraty * restrict it. Length 2 is not a valid point length, so 155*0957b409SSimon J. Gerraty * the ECDH will fail. 156*0957b409SSimon J. Gerraty */ 157*0957b409SSimon J. Gerraty cpoint_len = 2; 158*0957b409SSimon J. Gerraty } 159*0957b409SSimon J. Gerraty memcpy(cpoint, pk->key.ec.q, cpoint_len); 160*0957b409SSimon J. Gerraty do_ecdh(ctx, prf_id, cpoint, cpoint_len); 161*0957b409SSimon J. Gerraty} 162*0957b409SSimon J. Gerraty 163*0957b409SSimon J. Gerratystatic size_t 164*0957b409SSimon J. Gerratyhash_data(br_ssl_server_context *ctx, 165*0957b409SSimon J. Gerraty void *dst, int hash_id, const void *src, size_t len) 166*0957b409SSimon J. Gerraty{ 167*0957b409SSimon J. Gerraty const br_hash_class *hf; 168*0957b409SSimon J. Gerraty br_hash_compat_context hc; 169*0957b409SSimon J. Gerraty 170*0957b409SSimon J. Gerraty if (hash_id == 0) { 171*0957b409SSimon J. Gerraty unsigned char tmp[36]; 172*0957b409SSimon J. Gerraty 173*0957b409SSimon J. Gerraty hf = br_multihash_getimpl(&ctx->eng.mhash, br_md5_ID); 174*0957b409SSimon J. Gerraty if (hf == NULL) { 175*0957b409SSimon J. Gerraty return 0; 176*0957b409SSimon J. Gerraty } 177*0957b409SSimon J. Gerraty hf->init(&hc.vtable); 178*0957b409SSimon J. Gerraty hf->update(&hc.vtable, src, len); 179*0957b409SSimon J. Gerraty hf->out(&hc.vtable, tmp); 180*0957b409SSimon J. Gerraty hf = br_multihash_getimpl(&ctx->eng.mhash, br_sha1_ID); 181*0957b409SSimon J. Gerraty if (hf == NULL) { 182*0957b409SSimon J. Gerraty return 0; 183*0957b409SSimon J. Gerraty } 184*0957b409SSimon J. Gerraty hf->init(&hc.vtable); 185*0957b409SSimon J. Gerraty hf->update(&hc.vtable, src, len); 186*0957b409SSimon J. Gerraty hf->out(&hc.vtable, tmp + 16); 187*0957b409SSimon J. Gerraty memcpy(dst, tmp, 36); 188*0957b409SSimon J. Gerraty return 36; 189*0957b409SSimon J. Gerraty } else { 190*0957b409SSimon J. Gerraty hf = br_multihash_getimpl(&ctx->eng.mhash, hash_id); 191*0957b409SSimon J. Gerraty if (hf == NULL) { 192*0957b409SSimon J. Gerraty return 0; 193*0957b409SSimon J. Gerraty } 194*0957b409SSimon J. Gerraty hf->init(&hc.vtable); 195*0957b409SSimon J. Gerraty hf->update(&hc.vtable, src, len); 196*0957b409SSimon J. Gerraty hf->out(&hc.vtable, dst); 197*0957b409SSimon J. Gerraty return (hf->desc >> BR_HASHDESC_OUT_OFF) & BR_HASHDESC_OUT_MASK; 198*0957b409SSimon J. Gerraty } 199*0957b409SSimon J. Gerraty} 200*0957b409SSimon J. Gerraty 201*0957b409SSimon J. Gerraty/* 202*0957b409SSimon J. Gerraty * Do the ECDHE key exchange (part 1: generation of transient key, and 203*0957b409SSimon J. Gerraty * computing of the point to send to the client). Returned value is the 204*0957b409SSimon J. Gerraty * signature length (in bytes), or -x on error (with x being an error 205*0957b409SSimon J. Gerraty * code). The encoded point is written in the ecdhe_point[] context buffer 206*0957b409SSimon J. Gerraty * (length in ecdhe_point_len). 207*0957b409SSimon J. Gerraty */ 208*0957b409SSimon J. Gerratystatic int 209*0957b409SSimon J. Gerratydo_ecdhe_part1(br_ssl_server_context *ctx, int curve) 210*0957b409SSimon J. Gerraty{ 211*0957b409SSimon J. Gerraty unsigned algo_id; 212*0957b409SSimon J. Gerraty unsigned mask; 213*0957b409SSimon J. Gerraty const unsigned char *order; 214*0957b409SSimon J. Gerraty size_t olen, glen; 215*0957b409SSimon J. Gerraty size_t hv_len, sig_len; 216*0957b409SSimon J. Gerraty 217*0957b409SSimon J. Gerraty if (!((ctx->eng.iec->supported_curves >> curve) & 1)) { 218*0957b409SSimon J. Gerraty return -BR_ERR_INVALID_ALGORITHM; 219*0957b409SSimon J. Gerraty } 220*0957b409SSimon J. Gerraty ctx->eng.ecdhe_curve = curve; 221*0957b409SSimon J. Gerraty 222*0957b409SSimon J. Gerraty /* 223*0957b409SSimon J. Gerraty * Generate our private key. We need a non-zero random value 224*0957b409SSimon J. Gerraty * which is lower than the curve order, in a "large enough" 225*0957b409SSimon J. Gerraty * range. We force the top bit to 0 and bottom bit to 1, which 226*0957b409SSimon J. Gerraty * does the trick. Note that contrary to what happens in ECDSA, 227*0957b409SSimon J. Gerraty * this is not a problem if we do not cover the full range of 228*0957b409SSimon J. Gerraty * possible values. 229*0957b409SSimon J. Gerraty */ 230*0957b409SSimon J. Gerraty order = ctx->eng.iec->order(curve, &olen); 231*0957b409SSimon J. Gerraty mask = 0xFF; 232*0957b409SSimon J. Gerraty while (mask >= order[0]) { 233*0957b409SSimon J. Gerraty mask >>= 1; 234*0957b409SSimon J. Gerraty } 235*0957b409SSimon J. Gerraty br_hmac_drbg_generate(&ctx->eng.rng, ctx->ecdhe_key, olen); 236*0957b409SSimon J. Gerraty ctx->ecdhe_key[0] &= mask; 237*0957b409SSimon J. Gerraty ctx->ecdhe_key[olen - 1] |= 0x01; 238*0957b409SSimon J. Gerraty ctx->ecdhe_key_len = olen; 239*0957b409SSimon J. Gerraty 240*0957b409SSimon J. Gerraty /* 241*0957b409SSimon J. Gerraty * Compute our ECDH point. 242*0957b409SSimon J. Gerraty */ 243*0957b409SSimon J. Gerraty glen = ctx->eng.iec->mulgen(ctx->eng.ecdhe_point, 244*0957b409SSimon J. Gerraty ctx->ecdhe_key, olen, curve); 245*0957b409SSimon J. Gerraty ctx->eng.ecdhe_point_len = glen; 246*0957b409SSimon J. Gerraty 247*0957b409SSimon J. Gerraty /* 248*0957b409SSimon J. Gerraty * Assemble the message to be signed, and possibly hash it. 249*0957b409SSimon J. Gerraty */ 250*0957b409SSimon J. Gerraty memcpy(ctx->eng.pad, ctx->eng.client_random, 32); 251*0957b409SSimon J. Gerraty memcpy(ctx->eng.pad + 32, ctx->eng.server_random, 32); 252*0957b409SSimon J. Gerraty ctx->eng.pad[64 + 0] = 0x03; 253*0957b409SSimon J. Gerraty ctx->eng.pad[64 + 1] = 0x00; 254*0957b409SSimon J. Gerraty ctx->eng.pad[64 + 2] = curve; 255*0957b409SSimon J. Gerraty ctx->eng.pad[64 + 3] = ctx->eng.ecdhe_point_len; 256*0957b409SSimon J. Gerraty memcpy(ctx->eng.pad + 64 + 4, 257*0957b409SSimon J. Gerraty ctx->eng.ecdhe_point, ctx->eng.ecdhe_point_len); 258*0957b409SSimon J. Gerraty hv_len = 64 + 4 + ctx->eng.ecdhe_point_len; 259*0957b409SSimon J. Gerraty algo_id = ctx->sign_hash_id; 260*0957b409SSimon J. Gerraty if (algo_id >= (unsigned)0xFF00) { 261*0957b409SSimon J. Gerraty hv_len = hash_data(ctx, ctx->eng.pad, algo_id & 0xFF, 262*0957b409SSimon J. Gerraty ctx->eng.pad, hv_len); 263*0957b409SSimon J. Gerraty if (hv_len == 0) { 264*0957b409SSimon J. Gerraty return -BR_ERR_INVALID_ALGORITHM; 265*0957b409SSimon J. Gerraty } 266*0957b409SSimon J. Gerraty } 267*0957b409SSimon J. Gerraty 268*0957b409SSimon J. Gerraty sig_len = (*ctx->policy_vtable)->do_sign(ctx->policy_vtable, 269*0957b409SSimon J. Gerraty algo_id, ctx->eng.pad, hv_len, sizeof ctx->eng.pad); 270*0957b409SSimon J. Gerraty return sig_len ? (int)sig_len : -BR_ERR_INVALID_ALGORITHM; 271*0957b409SSimon J. Gerraty} 272*0957b409SSimon J. Gerraty 273*0957b409SSimon J. Gerraty/* 274*0957b409SSimon J. Gerraty * Do the ECDHE key exchange (part 2: computation of the shared secret 275*0957b409SSimon J. Gerraty * from the point sent by the client). 276*0957b409SSimon J. Gerraty */ 277*0957b409SSimon J. Gerratystatic void 278*0957b409SSimon J. Gerratydo_ecdhe_part2(br_ssl_server_context *ctx, int prf_id, 279*0957b409SSimon J. Gerraty unsigned char *cpoint, size_t cpoint_len) 280*0957b409SSimon J. Gerraty{ 281*0957b409SSimon J. Gerraty int curve; 282*0957b409SSimon J. Gerraty uint32_t ctl; 283*0957b409SSimon J. Gerraty size_t xoff, xlen; 284*0957b409SSimon J. Gerraty 285*0957b409SSimon J. Gerraty curve = ctx->eng.ecdhe_curve; 286*0957b409SSimon J. Gerraty 287*0957b409SSimon J. Gerraty /* 288*0957b409SSimon J. Gerraty * Finalise the key exchange. 289*0957b409SSimon J. Gerraty */ 290*0957b409SSimon J. Gerraty ctl = ctx->eng.iec->mul(cpoint, cpoint_len, 291*0957b409SSimon J. Gerraty ctx->ecdhe_key, ctx->ecdhe_key_len, curve); 292*0957b409SSimon J. Gerraty xoff = ctx->eng.iec->xoff(curve, &xlen); 293*0957b409SSimon J. Gerraty ecdh_common(ctx, prf_id, cpoint + xoff, xlen, ctl); 294*0957b409SSimon J. Gerraty 295*0957b409SSimon J. Gerraty /* 296*0957b409SSimon J. Gerraty * Clear the ECDHE private key. Forward Secrecy is achieved insofar 297*0957b409SSimon J. Gerraty * as that key does not get stolen, so we'd better destroy it 298*0957b409SSimon J. Gerraty * as soon as it ceases to be useful. 299*0957b409SSimon J. Gerraty */ 300*0957b409SSimon J. Gerraty memset(ctx->ecdhe_key, 0, ctx->ecdhe_key_len); 301*0957b409SSimon J. Gerraty} 302*0957b409SSimon J. Gerraty 303*0957b409SSimon J. Gerraty/* 304*0957b409SSimon J. Gerraty * Offset for hash value within the pad (when obtaining all hash values, 305*0957b409SSimon J. Gerraty * in preparation for verification of the CertificateVerify message). 306*0957b409SSimon J. Gerraty * Order is MD5, SHA-1, SHA-224, SHA-256, SHA-384, SHA-512; last value 307*0957b409SSimon J. Gerraty * is used to get the total length. 308*0957b409SSimon J. Gerraty */ 309*0957b409SSimon J. Gerratystatic const unsigned char HASH_PAD_OFF[] = { 0, 16, 36, 64, 96, 144, 208 }; 310*0957b409SSimon J. Gerraty 311*0957b409SSimon J. Gerraty/* 312*0957b409SSimon J. Gerraty * OID for hash functions in RSA signatures. 313*0957b409SSimon J. Gerraty */ 314*0957b409SSimon J. Gerratystatic const unsigned char HASH_OID_SHA1[] = { 315*0957b409SSimon J. Gerraty 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A 316*0957b409SSimon J. Gerraty}; 317*0957b409SSimon J. Gerraty 318*0957b409SSimon J. Gerratystatic const unsigned char HASH_OID_SHA224[] = { 319*0957b409SSimon J. Gerraty 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04 320*0957b409SSimon J. Gerraty}; 321*0957b409SSimon J. Gerraty 322*0957b409SSimon J. Gerratystatic const unsigned char HASH_OID_SHA256[] = { 323*0957b409SSimon J. Gerraty 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01 324*0957b409SSimon J. Gerraty}; 325*0957b409SSimon J. Gerraty 326*0957b409SSimon J. Gerratystatic const unsigned char HASH_OID_SHA384[] = { 327*0957b409SSimon J. Gerraty 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02 328*0957b409SSimon J. Gerraty}; 329*0957b409SSimon J. Gerraty 330*0957b409SSimon J. Gerratystatic const unsigned char HASH_OID_SHA512[] = { 331*0957b409SSimon J. Gerraty 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03 332*0957b409SSimon J. Gerraty}; 333*0957b409SSimon J. Gerraty 334*0957b409SSimon J. Gerratystatic const unsigned char *HASH_OID[] = { 335*0957b409SSimon J. Gerraty HASH_OID_SHA1, 336*0957b409SSimon J. Gerraty HASH_OID_SHA224, 337*0957b409SSimon J. Gerraty HASH_OID_SHA256, 338*0957b409SSimon J. Gerraty HASH_OID_SHA384, 339*0957b409SSimon J. Gerraty HASH_OID_SHA512 340*0957b409SSimon J. Gerraty}; 341*0957b409SSimon J. Gerraty 342*0957b409SSimon J. Gerraty/* 343*0957b409SSimon J. Gerraty * Verify the signature in CertificateVerify. Returned value is 0 on 344*0957b409SSimon J. Gerraty * success, or a non-zero error code. Lack of implementation of the 345*0957b409SSimon J. Gerraty * designated signature algorithm is reported as a "bad signature" 346*0957b409SSimon J. Gerraty * error (because it means that the peer did not honour our advertised 347*0957b409SSimon J. Gerraty * set of supported signature algorithms). 348*0957b409SSimon J. Gerraty */ 349*0957b409SSimon J. Gerratystatic int 350*0957b409SSimon J. Gerratyverify_CV_sig(br_ssl_server_context *ctx, size_t sig_len) 351*0957b409SSimon J. Gerraty{ 352*0957b409SSimon J. Gerraty const br_x509_class **xc; 353*0957b409SSimon J. Gerraty const br_x509_pkey *pk; 354*0957b409SSimon J. Gerraty int id; 355*0957b409SSimon J. Gerraty 356*0957b409SSimon J. Gerraty id = ctx->hash_CV_id; 357*0957b409SSimon J. Gerraty xc = ctx->eng.x509ctx; 358*0957b409SSimon J. Gerraty pk = (*xc)->get_pkey(xc, NULL); 359*0957b409SSimon J. Gerraty if (pk->key_type == BR_KEYTYPE_RSA) { 360*0957b409SSimon J. Gerraty unsigned char tmp[64]; 361*0957b409SSimon J. Gerraty const unsigned char *hash_oid; 362*0957b409SSimon J. Gerraty 363*0957b409SSimon J. Gerraty if (id == 0) { 364*0957b409SSimon J. Gerraty hash_oid = NULL; 365*0957b409SSimon J. Gerraty } else { 366*0957b409SSimon J. Gerraty hash_oid = HASH_OID[id - 2]; 367*0957b409SSimon J. Gerraty } 368*0957b409SSimon J. Gerraty if (ctx->eng.irsavrfy == 0) { 369*0957b409SSimon J. Gerraty return BR_ERR_BAD_SIGNATURE; 370*0957b409SSimon J. Gerraty } 371*0957b409SSimon J. Gerraty if (!ctx->eng.irsavrfy(ctx->eng.pad, sig_len, 372*0957b409SSimon J. Gerraty hash_oid, ctx->hash_CV_len, &pk->key.rsa, tmp) 373*0957b409SSimon J. Gerraty || memcmp(tmp, ctx->hash_CV, ctx->hash_CV_len) != 0) 374*0957b409SSimon J. Gerraty { 375*0957b409SSimon J. Gerraty return BR_ERR_BAD_SIGNATURE; 376*0957b409SSimon J. Gerraty } 377*0957b409SSimon J. Gerraty } else { 378*0957b409SSimon J. Gerraty if (ctx->eng.iecdsa == 0) { 379*0957b409SSimon J. Gerraty return BR_ERR_BAD_SIGNATURE; 380*0957b409SSimon J. Gerraty } 381*0957b409SSimon J. Gerraty if (!ctx->eng.iecdsa(ctx->eng.iec, 382*0957b409SSimon J. Gerraty ctx->hash_CV, ctx->hash_CV_len, 383*0957b409SSimon J. Gerraty &pk->key.ec, ctx->eng.pad, sig_len)) 384*0957b409SSimon J. Gerraty { 385*0957b409SSimon J. Gerraty return BR_ERR_BAD_SIGNATURE; 386*0957b409SSimon J. Gerraty } 387*0957b409SSimon J. Gerraty } 388*0957b409SSimon J. Gerraty return 0; 389*0957b409SSimon J. Gerraty} 390*0957b409SSimon J. Gerraty 391*0957b409SSimon J. Gerraty} 392*0957b409SSimon J. Gerraty 393*0957b409SSimon J. Gerraty\ ======================================================================= 394*0957b409SSimon J. Gerraty 395*0957b409SSimon J. Gerraty: addr-ctx: 396*0957b409SSimon J. Gerraty next-word { field } 397*0957b409SSimon J. Gerraty "addr-" field + 0 1 define-word 398*0957b409SSimon J. Gerraty 0 8191 "offsetof(br_ssl_server_context, " field + ")" + make-CX 399*0957b409SSimon J. Gerraty postpone literal postpone ; ; 400*0957b409SSimon J. Gerraty 401*0957b409SSimon J. Gerratyaddr-ctx: client_max_version 402*0957b409SSimon J. Gerratyaddr-ctx: client_suites 403*0957b409SSimon J. Gerratyaddr-ctx: client_suites_num 404*0957b409SSimon J. Gerratyaddr-ctx: hashes 405*0957b409SSimon J. Gerratyaddr-ctx: curves 406*0957b409SSimon J. Gerratyaddr-ctx: sign_hash_id 407*0957b409SSimon J. Gerraty 408*0957b409SSimon J. Gerraty\ Get address and length of the client_suites[] buffer. Length is expressed 409*0957b409SSimon J. Gerraty\ in bytes. 410*0957b409SSimon J. Gerraty: addr-len-client_suites ( -- addr len ) 411*0957b409SSimon J. Gerraty addr-client_suites 412*0957b409SSimon J. Gerraty CX 0 1023 { BR_MAX_CIPHER_SUITES * sizeof(br_suite_translated) } ; 413*0957b409SSimon J. Gerraty 414*0957b409SSimon J. Gerraty\ Read the client SNI extension. 415*0957b409SSimon J. Gerraty: read-client-sni ( lim -- lim ) 416*0957b409SSimon J. Gerraty \ Open extension value. 417*0957b409SSimon J. Gerraty read16 open-elt 418*0957b409SSimon J. Gerraty 419*0957b409SSimon J. Gerraty \ Open ServerNameList. 420*0957b409SSimon J. Gerraty read16 open-elt 421*0957b409SSimon J. Gerraty 422*0957b409SSimon J. Gerraty \ Find if there is a name of type 0 (host_name) with a length 423*0957b409SSimon J. Gerraty \ that fits in our dedicated buffer. 424*0957b409SSimon J. Gerraty begin dup while 425*0957b409SSimon J. Gerraty read8 if 426*0957b409SSimon J. Gerraty read-ignore-16 427*0957b409SSimon J. Gerraty else 428*0957b409SSimon J. Gerraty read16 429*0957b409SSimon J. Gerraty dup 255 <= if 430*0957b409SSimon J. Gerraty dup addr-server_name + 0 swap set8 431*0957b409SSimon J. Gerraty addr-server_name swap read-blob 432*0957b409SSimon J. Gerraty else 433*0957b409SSimon J. Gerraty skip-blob 434*0957b409SSimon J. Gerraty then 435*0957b409SSimon J. Gerraty then 436*0957b409SSimon J. Gerraty repeat 437*0957b409SSimon J. Gerraty 438*0957b409SSimon J. Gerraty \ Close ServerNameList. 439*0957b409SSimon J. Gerraty close-elt 440*0957b409SSimon J. Gerraty 441*0957b409SSimon J. Gerraty \ Close extension value. 442*0957b409SSimon J. Gerraty close-elt ; 443*0957b409SSimon J. Gerraty 444*0957b409SSimon J. Gerraty\ Set the new maximum fragment length. BEWARE: this shall be called only 445*0957b409SSimon J. Gerraty\ after reading the ClientHello and before writing the ServerHello. 446*0957b409SSimon J. Gerratycc: set-max-frag-len ( len -- ) { 447*0957b409SSimon J. Gerraty size_t max_frag_len = T0_POP(); 448*0957b409SSimon J. Gerraty 449*0957b409SSimon J. Gerraty br_ssl_engine_new_max_frag_len(ENG, max_frag_len); 450*0957b409SSimon J. Gerraty 451*0957b409SSimon J. Gerraty /* 452*0957b409SSimon J. Gerraty * We must adjust our own output limit. Since we call this only 453*0957b409SSimon J. Gerraty * after receiving a ClientHello and before beginning to send 454*0957b409SSimon J. Gerraty * the ServerHello, the next output record should be empty at 455*0957b409SSimon J. Gerraty * that point, so we can use max_frag_len as a limit. 456*0957b409SSimon J. Gerraty */ 457*0957b409SSimon J. Gerraty if (ENG->hlen_out > max_frag_len) { 458*0957b409SSimon J. Gerraty ENG->hlen_out = max_frag_len; 459*0957b409SSimon J. Gerraty } 460*0957b409SSimon J. Gerraty} 461*0957b409SSimon J. Gerraty 462*0957b409SSimon J. Gerraty\ Read the client Max Frag Length extension. 463*0957b409SSimon J. Gerraty: read-client-frag ( lim -- lim ) 464*0957b409SSimon J. Gerraty \ Extension value must have length exactly 1 byte. 465*0957b409SSimon J. Gerraty read16 1 <> if ERR_BAD_FRAGLEN fail then 466*0957b409SSimon J. Gerraty read8 467*0957b409SSimon J. Gerraty 468*0957b409SSimon J. Gerraty \ The byte value must be 1, 2, 3 or 4. 469*0957b409SSimon J. Gerraty dup dup 0= swap 5 >= or if ERR_BAD_FRAGLEN fail then 470*0957b409SSimon J. Gerraty 471*0957b409SSimon J. Gerraty \ If our own maximum fragment length is greater, then we reduce 472*0957b409SSimon J. Gerraty \ our length. 473*0957b409SSimon J. Gerraty 8 + dup addr-log_max_frag_len get8 < if 474*0957b409SSimon J. Gerraty dup 1 swap << set-max-frag-len 475*0957b409SSimon J. Gerraty dup addr-log_max_frag_len set8 476*0957b409SSimon J. Gerraty addr-peer_log_max_frag_len set8 477*0957b409SSimon J. Gerraty else 478*0957b409SSimon J. Gerraty drop 479*0957b409SSimon J. Gerraty then ; 480*0957b409SSimon J. Gerraty 481*0957b409SSimon J. Gerraty\ Read the Secure Renegotiation extension from the client. 482*0957b409SSimon J. Gerraty: read-client-reneg ( lim -- lim ) 483*0957b409SSimon J. Gerraty \ Get value length. 484*0957b409SSimon J. Gerraty read16 485*0957b409SSimon J. Gerraty 486*0957b409SSimon J. Gerraty \ The "reneg" value is one of: 487*0957b409SSimon J. Gerraty \ 0 on first handshake, client support is unknown 488*0957b409SSimon J. Gerraty \ 1 client does not support secure renegotiation 489*0957b409SSimon J. Gerraty \ 2 client supports secure renegotiation 490*0957b409SSimon J. Gerraty addr-reneg get8 case 491*0957b409SSimon J. Gerraty 0 of 492*0957b409SSimon J. Gerraty \ First handshake, value length shall be 1. 493*0957b409SSimon J. Gerraty 1 = ifnot ERR_BAD_SECRENEG fail then 494*0957b409SSimon J. Gerraty read8 if ERR_BAD_SECRENEG fail then 495*0957b409SSimon J. Gerraty 2 addr-reneg set8 496*0957b409SSimon J. Gerraty endof 497*0957b409SSimon J. Gerraty 2 of 498*0957b409SSimon J. Gerraty \ Renegotiation, value shall consist of 13 bytes 499*0957b409SSimon J. Gerraty \ (header + copy of the saved client "Finished"). 500*0957b409SSimon J. Gerraty 13 = ifnot ERR_BAD_SECRENEG fail then 501*0957b409SSimon J. Gerraty read8 12 = ifnot ERR_BAD_SECRENEG fail then 502*0957b409SSimon J. Gerraty addr-pad 12 read-blob 503*0957b409SSimon J. Gerraty addr-saved_finished addr-pad 12 memcmp ifnot 504*0957b409SSimon J. Gerraty ERR_BAD_SECRENEG fail 505*0957b409SSimon J. Gerraty then 506*0957b409SSimon J. Gerraty endof 507*0957b409SSimon J. Gerraty 508*0957b409SSimon J. Gerraty \ If "reneg" is 1 then the client is not supposed to support 509*0957b409SSimon J. Gerraty \ the extension, and it sends it nonetheless, which means 510*0957b409SSimon J. Gerraty \ foul play. 511*0957b409SSimon J. Gerraty ERR_BAD_SECRENEG fail 512*0957b409SSimon J. Gerraty endcase ; 513*0957b409SSimon J. Gerraty 514*0957b409SSimon J. Gerraty\ Read the Signature Algorithms extension. 515*0957b409SSimon J. Gerraty: read-signatures ( lim -- lim ) 516*0957b409SSimon J. Gerraty \ Open extension value. 517*0957b409SSimon J. Gerraty read16 open-elt 518*0957b409SSimon J. Gerraty 519*0957b409SSimon J. Gerraty read-list-sign-algos addr-hashes set32 520*0957b409SSimon J. Gerraty 521*0957b409SSimon J. Gerraty \ Close extension value. 522*0957b409SSimon J. Gerraty close-elt ; 523*0957b409SSimon J. Gerraty 524*0957b409SSimon J. Gerraty\ Read the Supported Curves extension. 525*0957b409SSimon J. Gerraty: read-supported-curves ( lim -- lim ) 526*0957b409SSimon J. Gerraty \ Open extension value. 527*0957b409SSimon J. Gerraty read16 open-elt 528*0957b409SSimon J. Gerraty 529*0957b409SSimon J. Gerraty \ Open list of curve identifiers. 530*0957b409SSimon J. Gerraty read16 open-elt 531*0957b409SSimon J. Gerraty 532*0957b409SSimon J. Gerraty \ Get all supported curves. 533*0957b409SSimon J. Gerraty 0 addr-curves set32 534*0957b409SSimon J. Gerraty begin dup while 535*0957b409SSimon J. Gerraty read16 dup 32 < if 536*0957b409SSimon J. Gerraty 1 swap << addr-curves get32 or addr-curves set32 537*0957b409SSimon J. Gerraty else 538*0957b409SSimon J. Gerraty drop 539*0957b409SSimon J. Gerraty then 540*0957b409SSimon J. Gerraty repeat 541*0957b409SSimon J. Gerraty close-elt 542*0957b409SSimon J. Gerraty close-elt ; 543*0957b409SSimon J. Gerraty 544*0957b409SSimon J. Gerraty\ Read the ALPN extension from client. 545*0957b409SSimon J. Gerraty: read-ALPN-from-client ( lim -- lim ) 546*0957b409SSimon J. Gerraty \ If we do not have configured names, then we just ignore the 547*0957b409SSimon J. Gerraty \ extension. 548*0957b409SSimon J. Gerraty addr-protocol_names_num get16 ifnot read-ignore-16 ret then 549*0957b409SSimon J. Gerraty 550*0957b409SSimon J. Gerraty \ Open extension value. 551*0957b409SSimon J. Gerraty read16 open-elt 552*0957b409SSimon J. Gerraty 553*0957b409SSimon J. Gerraty \ Open list of protocol names. 554*0957b409SSimon J. Gerraty read16 open-elt 555*0957b409SSimon J. Gerraty 556*0957b409SSimon J. Gerraty \ Get all names and test for their support. We keep the one with 557*0957b409SSimon J. Gerraty \ the lowest index (because we apply server's preferences, as 558*0957b409SSimon J. Gerraty \ recommended by RFC 7301, section 3.2. We set the 'found' variable 559*0957b409SSimon J. Gerraty \ to -2 and use an unsigned comparison, making -2 a huge value. 560*0957b409SSimon J. Gerraty -2 { found } 561*0957b409SSimon J. Gerraty begin dup while 562*0957b409SSimon J. Gerraty read8 dup { len } addr-pad swap read-blob 563*0957b409SSimon J. Gerraty len test-protocol-name dup found u< if 564*0957b409SSimon J. Gerraty >found 565*0957b409SSimon J. Gerraty else 566*0957b409SSimon J. Gerraty drop 567*0957b409SSimon J. Gerraty then 568*0957b409SSimon J. Gerraty repeat 569*0957b409SSimon J. Gerraty 570*0957b409SSimon J. Gerraty \ End of extension. 571*0957b409SSimon J. Gerraty close-elt 572*0957b409SSimon J. Gerraty close-elt 573*0957b409SSimon J. Gerraty 574*0957b409SSimon J. Gerraty \ Write back found name index (or not). If no match was found, 575*0957b409SSimon J. Gerraty \ then we write -1 (0xFFFF) in the index value, not 0, so that 576*0957b409SSimon J. Gerraty \ the caller knows that we tried to match, and failed. 577*0957b409SSimon J. Gerraty found 1+ addr-selected_protocol set16 ; 578*0957b409SSimon J. Gerraty 579*0957b409SSimon J. Gerraty\ Call policy handler to get cipher suite, hash function identifier and 580*0957b409SSimon J. Gerraty\ certificate chain. Returned value is 0 (false) on failure. 581*0957b409SSimon J. Gerratycc: call-policy-handler ( -- bool ) { 582*0957b409SSimon J. Gerraty int x; 583*0957b409SSimon J. Gerraty br_ssl_server_choices choices; 584*0957b409SSimon J. Gerraty 585*0957b409SSimon J. Gerraty x = (*CTX->policy_vtable)->choose( 586*0957b409SSimon J. Gerraty CTX->policy_vtable, CTX, &choices); 587*0957b409SSimon J. Gerraty ENG->session.cipher_suite = choices.cipher_suite; 588*0957b409SSimon J. Gerraty CTX->sign_hash_id = choices.algo_id; 589*0957b409SSimon J. Gerraty ENG->chain = choices.chain; 590*0957b409SSimon J. Gerraty ENG->chain_len = choices.chain_len; 591*0957b409SSimon J. Gerraty T0_PUSHi(-(x != 0)); 592*0957b409SSimon J. Gerraty} 593*0957b409SSimon J. Gerraty 594*0957b409SSimon J. Gerraty\ Check for a remembered session. 595*0957b409SSimon J. Gerratycc: check-resume ( -- bool ) { 596*0957b409SSimon J. Gerraty if (ENG->session.session_id_len == 32 597*0957b409SSimon J. Gerraty && CTX->cache_vtable != NULL && (*CTX->cache_vtable)->load( 598*0957b409SSimon J. Gerraty CTX->cache_vtable, CTX, &ENG->session)) 599*0957b409SSimon J. Gerraty { 600*0957b409SSimon J. Gerraty T0_PUSHi(-1); 601*0957b409SSimon J. Gerraty } else { 602*0957b409SSimon J. Gerraty T0_PUSH(0); 603*0957b409SSimon J. Gerraty } 604*0957b409SSimon J. Gerraty} 605*0957b409SSimon J. Gerraty 606*0957b409SSimon J. Gerraty\ Save the current session. 607*0957b409SSimon J. Gerratycc: save-session ( -- ) { 608*0957b409SSimon J. Gerraty if (CTX->cache_vtable != NULL) { 609*0957b409SSimon J. Gerraty (*CTX->cache_vtable)->save( 610*0957b409SSimon J. Gerraty CTX->cache_vtable, CTX, &ENG->session); 611*0957b409SSimon J. Gerraty } 612*0957b409SSimon J. Gerraty} 613*0957b409SSimon J. Gerraty 614*0957b409SSimon J. Gerraty\ Read and drop ClientHello. This is used when a client-triggered 615*0957b409SSimon J. Gerraty\ renegotiation attempt is rejected. 616*0957b409SSimon J. Gerraty: skip-ClientHello ( -- ) 617*0957b409SSimon J. Gerraty read-handshake-header-core 618*0957b409SSimon J. Gerraty 1 = ifnot ERR_UNEXPECTED fail then 619*0957b409SSimon J. Gerraty dup skip-blob drop ; 620*0957b409SSimon J. Gerraty 621*0957b409SSimon J. Gerraty\ Read ClientHello. If the session is resumed, then -1 is returned. 622*0957b409SSimon J. Gerraty: read-ClientHello ( -- resume ) 623*0957b409SSimon J. Gerraty \ Get header, and check message type. 624*0957b409SSimon J. Gerraty read-handshake-header 1 = ifnot ERR_UNEXPECTED fail then 625*0957b409SSimon J. Gerraty 626*0957b409SSimon J. Gerraty \ Get maximum protocol version from client. 627*0957b409SSimon J. Gerraty read16 dup { client-version-max } addr-client_max_version set16 628*0957b409SSimon J. Gerraty 629*0957b409SSimon J. Gerraty \ Client random. 630*0957b409SSimon J. Gerraty addr-client_random 32 read-blob 631*0957b409SSimon J. Gerraty 632*0957b409SSimon J. Gerraty \ Client session ID. 633*0957b409SSimon J. Gerraty read8 dup 32 > if ERR_OVERSIZED_ID fail then 634*0957b409SSimon J. Gerraty dup addr-session_id_len set8 635*0957b409SSimon J. Gerraty addr-session_id swap read-blob 636*0957b409SSimon J. Gerraty 637*0957b409SSimon J. Gerraty \ Lookup session for resumption. We should do that here because 638*0957b409SSimon J. Gerraty \ we need to verify that the remembered cipher suite is still 639*0957b409SSimon J. Gerraty \ matched by this ClientHello. 640*0957b409SSimon J. Gerraty check-resume { resume } 641*0957b409SSimon J. Gerraty 642*0957b409SSimon J. Gerraty \ Cipher suites. We read all cipher suites from client, each time 643*0957b409SSimon J. Gerraty \ matching against our own list. We accumulate suites in the 644*0957b409SSimon J. Gerraty \ client_suites[] context buffer: we keep suites that are 645*0957b409SSimon J. Gerraty \ supported by both the client and the server (so the list size 646*0957b409SSimon J. Gerraty \ cannot exceed that of the server list), and we keep them in 647*0957b409SSimon J. Gerraty \ either client or server preference order (depending on the 648*0957b409SSimon J. Gerraty \ relevant flag). 649*0957b409SSimon J. Gerraty \ 650*0957b409SSimon J. Gerraty \ We also need to identify the pseudo cipher suite for secure 651*0957b409SSimon J. Gerraty \ renegotiation here. 652*0957b409SSimon J. Gerraty read16 open-elt 653*0957b409SSimon J. Gerraty 0 { reneg-scsv } 654*0957b409SSimon J. Gerraty 0 { resume-suite } 655*0957b409SSimon J. Gerraty addr-len-client_suites dup2 bzero 656*0957b409SSimon J. Gerraty over + { css-off css-max } 657*0957b409SSimon J. Gerraty begin 658*0957b409SSimon J. Gerraty dup while 659*0957b409SSimon J. Gerraty read16 dup { suite } 660*0957b409SSimon J. Gerraty 661*0957b409SSimon J. Gerraty \ Check that when resuming a session, the requested 662*0957b409SSimon J. Gerraty \ suite is still valid. 663*0957b409SSimon J. Gerraty resume if 664*0957b409SSimon J. Gerraty dup addr-cipher_suite get16 = if 665*0957b409SSimon J. Gerraty -1 >resume-suite 666*0957b409SSimon J. Gerraty then 667*0957b409SSimon J. Gerraty then 668*0957b409SSimon J. Gerraty 669*0957b409SSimon J. Gerraty \ Special handling for TLS_EMPTY_RENEGOTIATION_INFO_SCSV. 670*0957b409SSimon J. Gerraty \ This fake cipher suite may occur only in the first 671*0957b409SSimon J. Gerraty \ handshake. 672*0957b409SSimon J. Gerraty dup 0x00FF = if 673*0957b409SSimon J. Gerraty addr-reneg get8 if ERR_BAD_SECRENEG fail then 674*0957b409SSimon J. Gerraty -1 >reneg-scsv 675*0957b409SSimon J. Gerraty then 676*0957b409SSimon J. Gerraty 677*0957b409SSimon J. Gerraty \ Special handling for TLS_FALLBACK_SCSV. If the client 678*0957b409SSimon J. Gerraty \ maximum version is less than our own maximum version, 679*0957b409SSimon J. Gerraty \ then this is an undue downgrade. We mark it by setting 680*0957b409SSimon J. Gerraty \ the client max version to 0x10000. 681*0957b409SSimon J. Gerraty dup 0x5600 = if 682*0957b409SSimon J. Gerraty client-version-max addr-version_min get16 >= 683*0957b409SSimon J. Gerraty client-version-max addr-version_max get16 < and if 684*0957b409SSimon J. Gerraty -1 >client-version-max 685*0957b409SSimon J. Gerraty then 686*0957b409SSimon J. Gerraty then 687*0957b409SSimon J. Gerraty 688*0957b409SSimon J. Gerraty \ Test whether the suite is supported by the server. 689*0957b409SSimon J. Gerraty scan-suite dup 0< if 690*0957b409SSimon J. Gerraty \ We do not support this cipher suite. Note 691*0957b409SSimon J. Gerraty \ that this also covers the case of pseudo 692*0957b409SSimon J. Gerraty \ cipher suites. 693*0957b409SSimon J. Gerraty drop 694*0957b409SSimon J. Gerraty else 695*0957b409SSimon J. Gerraty \ If we use server order, then we place the 696*0957b409SSimon J. Gerraty \ suite at the computed offset; otherwise, we 697*0957b409SSimon J. Gerraty \ append it to the list at the current place. 698*0957b409SSimon J. Gerraty 0 flag? if 699*0957b409SSimon J. Gerraty 2 << addr-client_suites + suite swap set16 700*0957b409SSimon J. Gerraty else 701*0957b409SSimon J. Gerraty drop 702*0957b409SSimon J. Gerraty \ We need to test for list length because 703*0957b409SSimon J. Gerraty \ the client list may have duplicates, 704*0957b409SSimon J. Gerraty \ that we do not filter. Duplicates are 705*0957b409SSimon J. Gerraty \ invalid so this is not a problem if we 706*0957b409SSimon J. Gerraty \ reject such clients. 707*0957b409SSimon J. Gerraty css-off css-max >= if 708*0957b409SSimon J. Gerraty ERR_BAD_HANDSHAKE fail 709*0957b409SSimon J. Gerraty then 710*0957b409SSimon J. Gerraty suite css-off set16 711*0957b409SSimon J. Gerraty css-off 4 + >css-off 712*0957b409SSimon J. Gerraty then 713*0957b409SSimon J. Gerraty then 714*0957b409SSimon J. Gerraty repeat 715*0957b409SSimon J. Gerraty drop 716*0957b409SSimon J. Gerraty 717*0957b409SSimon J. Gerraty \ Compression methods. We need method 0 (no compression). 718*0957b409SSimon J. Gerraty 0 { ok-compression } 719*0957b409SSimon J. Gerraty read8 open-elt 720*0957b409SSimon J. Gerraty begin dup while 721*0957b409SSimon J. Gerraty read8 ifnot -1 >ok-compression then 722*0957b409SSimon J. Gerraty repeat 723*0957b409SSimon J. Gerraty close-elt 724*0957b409SSimon J. Gerraty 725*0957b409SSimon J. Gerraty \ Set default values for parameters that may be affected by 726*0957b409SSimon J. Gerraty \ extensions: 727*0957b409SSimon J. Gerraty \ -- server name is empty 728*0957b409SSimon J. Gerraty \ -- client is reputed to know RSA and ECDSA, both with SHA-1 729*0957b409SSimon J. Gerraty \ -- the default elliptic curve is P-256 (secp256r1, id = 23) 730*0957b409SSimon J. Gerraty 0 addr-server_name set8 731*0957b409SSimon J. Gerraty 0x0404 addr-hashes set32 732*0957b409SSimon J. Gerraty 0x800000 addr-curves set32 733*0957b409SSimon J. Gerraty 734*0957b409SSimon J. Gerraty \ Process extensions, if any. 735*0957b409SSimon J. Gerraty dup if 736*0957b409SSimon J. Gerraty read16 open-elt 737*0957b409SSimon J. Gerraty begin dup while 738*0957b409SSimon J. Gerraty read16 case 739*0957b409SSimon J. Gerraty \ Server Name Indication. 740*0957b409SSimon J. Gerraty 0x0000 of 741*0957b409SSimon J. Gerraty read-client-sni 742*0957b409SSimon J. Gerraty endof 743*0957b409SSimon J. Gerraty \ Max Frag Length. 744*0957b409SSimon J. Gerraty 0x0001 of 745*0957b409SSimon J. Gerraty read-client-frag 746*0957b409SSimon J. Gerraty endof 747*0957b409SSimon J. Gerraty \ Secure Renegotiation. 748*0957b409SSimon J. Gerraty 0xFF01 of 749*0957b409SSimon J. Gerraty read-client-reneg 750*0957b409SSimon J. Gerraty endof 751*0957b409SSimon J. Gerraty \ Signature Algorithms. 752*0957b409SSimon J. Gerraty 0x000D of 753*0957b409SSimon J. Gerraty read-signatures 754*0957b409SSimon J. Gerraty endof 755*0957b409SSimon J. Gerraty \ Supported Curves. 756*0957b409SSimon J. Gerraty 0x000A of 757*0957b409SSimon J. Gerraty read-supported-curves 758*0957b409SSimon J. Gerraty endof 759*0957b409SSimon J. Gerraty \ Supported Point Formats. 760*0957b409SSimon J. Gerraty \ We only support "uncompressed", that all 761*0957b409SSimon J. Gerraty \ implementations are supposed to support, 762*0957b409SSimon J. Gerraty \ so we can simply ignore that extension. 763*0957b409SSimon J. Gerraty \ 0x000B of 764*0957b409SSimon J. Gerraty \ read-ignore-16 765*0957b409SSimon J. Gerraty \ endof 766*0957b409SSimon J. Gerraty 767*0957b409SSimon J. Gerraty \ ALPN 768*0957b409SSimon J. Gerraty 0x0010 of 769*0957b409SSimon J. Gerraty read-ALPN-from-client 770*0957b409SSimon J. Gerraty endof 771*0957b409SSimon J. Gerraty 772*0957b409SSimon J. Gerraty \ Other extensions are ignored. 773*0957b409SSimon J. Gerraty drop read-ignore-16 0 774*0957b409SSimon J. Gerraty endcase 775*0957b409SSimon J. Gerraty repeat 776*0957b409SSimon J. Gerraty close-elt 777*0957b409SSimon J. Gerraty then 778*0957b409SSimon J. Gerraty 779*0957b409SSimon J. Gerraty \ Close message. 780*0957b409SSimon J. Gerraty close-elt 781*0957b409SSimon J. Gerraty 782*0957b409SSimon J. Gerraty \ Cancel session resumption if the cipher suite was not found. 783*0957b409SSimon J. Gerraty resume resume-suite and >resume 784*0957b409SSimon J. Gerraty 785*0957b409SSimon J. Gerraty \ Now check the received data. Since the client is expecting an 786*0957b409SSimon J. Gerraty \ answer, we can send an appropriate fatal alert on any error. 787*0957b409SSimon J. Gerraty 788*0957b409SSimon J. Gerraty \ Compute protocol version as the minimum of our maximum version, 789*0957b409SSimon J. Gerraty \ and the maximum version sent by the client. If that is less than 790*0957b409SSimon J. Gerraty \ 0x0300 (SSL-3.0), then fail. Otherwise, we may at least send an 791*0957b409SSimon J. Gerraty \ alert with that version. We still reject versions lower than our 792*0957b409SSimon J. Gerraty \ configured minimum. 793*0957b409SSimon J. Gerraty \ As a special case, in case of undue downgrade, we send a specific 794*0957b409SSimon J. Gerraty \ alert (see RFC 7507). Note that this case may happen only if 795*0957b409SSimon J. Gerraty \ we would otherwise accept the client's version. 796*0957b409SSimon J. Gerraty client-version-max 0< if 797*0957b409SSimon J. Gerraty addr-client_max_version get16 addr-version_out set16 798*0957b409SSimon J. Gerraty 86 fail-alert 799*0957b409SSimon J. Gerraty then 800*0957b409SSimon J. Gerraty addr-version_max get16 801*0957b409SSimon J. Gerraty dup client-version-max > if drop client-version-max then 802*0957b409SSimon J. Gerraty dup 0x0300 < if ERR_BAD_VERSION fail then 803*0957b409SSimon J. Gerraty client-version-max addr-version_min get16 < if 804*0957b409SSimon J. Gerraty 70 fail-alert 805*0957b409SSimon J. Gerraty then 806*0957b409SSimon J. Gerraty \ If resuming the session, then enforce the previously negotiated 807*0957b409SSimon J. Gerraty \ version (if still possible). 808*0957b409SSimon J. Gerraty resume if 809*0957b409SSimon J. Gerraty addr-version get16 client-version-max <= if 810*0957b409SSimon J. Gerraty drop addr-version get16 811*0957b409SSimon J. Gerraty else 812*0957b409SSimon J. Gerraty 0 >resume 813*0957b409SSimon J. Gerraty then 814*0957b409SSimon J. Gerraty then 815*0957b409SSimon J. Gerraty dup addr-version set16 816*0957b409SSimon J. Gerraty dup addr-version_in set16 817*0957b409SSimon J. Gerraty dup addr-version_out set16 818*0957b409SSimon J. Gerraty 0x0303 >= { can-tls12 } 819*0957b409SSimon J. Gerraty 820*0957b409SSimon J. Gerraty \ If the client sent TLS_EMPTY_RENEGOTIATION_INFO_SCSV, then 821*0957b409SSimon J. Gerraty \ we should mark the client as "supporting secure renegotiation". 822*0957b409SSimon J. Gerraty reneg-scsv if 2 addr-reneg set8 then 823*0957b409SSimon J. Gerraty 824*0957b409SSimon J. Gerraty \ If, at that point, the 'reneg' value is still 0, then the client 825*0957b409SSimon J. Gerraty \ did not send the extension or the SCSV, so we have to assume 826*0957b409SSimon J. Gerraty \ that secure renegotiation is not supported by that client. 827*0957b409SSimon J. Gerraty addr-reneg get8 ifnot 1 addr-reneg set8 then 828*0957b409SSimon J. Gerraty 829*0957b409SSimon J. Gerraty \ Check compression. 830*0957b409SSimon J. Gerraty ok-compression ifnot 40 fail-alert then 831*0957b409SSimon J. Gerraty 832*0957b409SSimon J. Gerraty \ Filter hash function support by what the server also supports. 833*0957b409SSimon J. Gerraty \ If no common hash function remains with RSA and/or ECDSA, then 834*0957b409SSimon J. Gerraty \ the corresponding ECDHE suites are not possible. 835*0957b409SSimon J. Gerraty supported-hash-functions drop 257 * 0xFFFF0000 or 836*0957b409SSimon J. Gerraty addr-hashes get32 and dup addr-hashes set32 837*0957b409SSimon J. Gerraty \ In 'can-ecdhe', bit 12 is set if ECDHE_RSA is possible, bit 13 is 838*0957b409SSimon J. Gerraty \ set if ECDHE_ECDSA is possible. 839*0957b409SSimon J. Gerraty dup 0xFF and 0<> neg 840*0957b409SSimon J. Gerraty swap 8 >> 0<> 2 and or 12 << { can-ecdhe } 841*0957b409SSimon J. Gerraty 842*0957b409SSimon J. Gerraty \ Filter supported curves. If there is no common curve between 843*0957b409SSimon J. Gerraty \ client and us, then ECDHE suites cannot be used. Note that we 844*0957b409SSimon J. Gerraty \ may still allow ECDH, depending on the EC key handler. 845*0957b409SSimon J. Gerraty addr-curves get32 supported-curves and dup addr-curves set32 846*0957b409SSimon J. Gerraty ifnot 0 >can-ecdhe then 847*0957b409SSimon J. Gerraty 848*0957b409SSimon J. Gerraty \ If resuming a session, then the next steps are not necessary; 849*0957b409SSimon J. Gerraty \ we won't invoke the policy handler. 850*0957b409SSimon J. Gerraty resume if -1 ret then 851*0957b409SSimon J. Gerraty 852*0957b409SSimon J. Gerraty \ We are not resuming, so a new session ID should be generated. 853*0957b409SSimon J. Gerraty \ We don't check that the new ID is distinct from the one sent 854*0957b409SSimon J. Gerraty \ by the client because probability of such an event is 2^(-256), 855*0957b409SSimon J. Gerraty \ i.e. much (much) lower than that of an undetected transmission 856*0957b409SSimon J. Gerraty \ error or hardware miscomputation, and with similar consequences 857*0957b409SSimon J. Gerraty \ (handshake simply fails). 858*0957b409SSimon J. Gerraty addr-session_id 32 mkrand 859*0957b409SSimon J. Gerraty 32 addr-session_id_len set8 860*0957b409SSimon J. Gerraty 861*0957b409SSimon J. Gerraty \ Translate common cipher suites, then squeeze out holes: there 862*0957b409SSimon J. Gerraty \ may be holes because of the way we fill the list when the 863*0957b409SSimon J. Gerraty \ server preference order is enforced, and also in case some 864*0957b409SSimon J. Gerraty \ suites are filtered out. In particular: 865*0957b409SSimon J. Gerraty \ -- ECDHE suites are removed if there is no common hash function 866*0957b409SSimon J. Gerraty \ (for the relevant signature algorithm) or no common curve. 867*0957b409SSimon J. Gerraty \ -- TLS-1.2-only suites are removed if the negotiated version is 868*0957b409SSimon J. Gerraty \ TLS-1.1 or lower. 869*0957b409SSimon J. Gerraty addr-client_suites dup >css-off 870*0957b409SSimon J. Gerraty begin dup css-max < while 871*0957b409SSimon J. Gerraty dup get16 dup cipher-suite-to-elements 872*0957b409SSimon J. Gerraty dup 12 >> dup 1 = swap 2 = or if 873*0957b409SSimon J. Gerraty dup can-ecdhe and ifnot 874*0957b409SSimon J. Gerraty 2drop 0 dup 875*0957b409SSimon J. Gerraty then 876*0957b409SSimon J. Gerraty then 877*0957b409SSimon J. Gerraty can-tls12 ifnot 878*0957b409SSimon J. Gerraty \ Suites compatible with TLS-1.0 and TLS-1.1 are 879*0957b409SSimon J. Gerraty \ exactly the ones that use HMAC/SHA-1. 880*0957b409SSimon J. Gerraty dup 0xF0 and 0x20 <> if 881*0957b409SSimon J. Gerraty 2drop 0 dup 882*0957b409SSimon J. Gerraty then 883*0957b409SSimon J. Gerraty then 884*0957b409SSimon J. Gerraty dup if 885*0957b409SSimon J. Gerraty css-off 2+ set16 css-off set16 886*0957b409SSimon J. Gerraty css-off 4 + >css-off 887*0957b409SSimon J. Gerraty else 888*0957b409SSimon J. Gerraty 2drop 889*0957b409SSimon J. Gerraty then 890*0957b409SSimon J. Gerraty 4 + 891*0957b409SSimon J. Gerraty repeat 892*0957b409SSimon J. Gerraty drop 893*0957b409SSimon J. Gerraty css-off addr-client_suites - 2 >> 894*0957b409SSimon J. Gerraty dup ifnot 895*0957b409SSimon J. Gerraty \ No common cipher suite: handshake failure. 896*0957b409SSimon J. Gerraty 40 fail-alert 897*0957b409SSimon J. Gerraty then 898*0957b409SSimon J. Gerraty addr-client_suites_num set8 899*0957b409SSimon J. Gerraty 900*0957b409SSimon J. Gerraty \ Check ALPN. 901*0957b409SSimon J. Gerraty addr-selected_protocol get16 0xFFFF = if 902*0957b409SSimon J. Gerraty 3 flag? if 120 fail-alert then 903*0957b409SSimon J. Gerraty 0 addr-selected_protocol set16 904*0957b409SSimon J. Gerraty then 905*0957b409SSimon J. Gerraty 906*0957b409SSimon J. Gerraty \ Call policy handler to obtain the cipher suite and other 907*0957b409SSimon J. Gerraty \ parameters. 908*0957b409SSimon J. Gerraty call-policy-handler ifnot 40 fail-alert then 909*0957b409SSimon J. Gerraty 910*0957b409SSimon J. Gerraty \ We are not resuming a session. 911*0957b409SSimon J. Gerraty 0 ; 912*0957b409SSimon J. Gerraty 913*0957b409SSimon J. Gerraty\ Write ServerHello. 914*0957b409SSimon J. Gerraty: write-ServerHello ( initial -- ) 915*0957b409SSimon J. Gerraty { initial } 916*0957b409SSimon J. Gerraty \ Compute ServerHello length. 917*0957b409SSimon J. Gerraty 2 write8 70 918*0957b409SSimon J. Gerraty 919*0957b409SSimon J. Gerraty \ Compute length of Secure Renegotiation extension. 920*0957b409SSimon J. Gerraty addr-reneg get8 2 = if 921*0957b409SSimon J. Gerraty initial if 5 else 29 then 922*0957b409SSimon J. Gerraty else 923*0957b409SSimon J. Gerraty 0 924*0957b409SSimon J. Gerraty then 925*0957b409SSimon J. Gerraty { ext-reneg-len } 926*0957b409SSimon J. Gerraty 927*0957b409SSimon J. Gerraty \ Compute length of Max Fragment Length extension. 928*0957b409SSimon J. Gerraty addr-peer_log_max_frag_len get8 if 5 else 0 then 929*0957b409SSimon J. Gerraty { ext-max-frag-len } 930*0957b409SSimon J. Gerraty 931*0957b409SSimon J. Gerraty \ Compute length of ALPN extension. This also copy the 932*0957b409SSimon J. Gerraty \ selected protocol name into the pad. 933*0957b409SSimon J. Gerraty addr-selected_protocol get16 dup if 1- copy-protocol-name 7 + then 934*0957b409SSimon J. Gerraty { ext-ALPN-len } 935*0957b409SSimon J. Gerraty 936*0957b409SSimon J. Gerraty \ Adjust ServerHello length to account for the extensions. 937*0957b409SSimon J. Gerraty ext-reneg-len ext-max-frag-len + ext-ALPN-len + dup if 2 + then + 938*0957b409SSimon J. Gerraty write24 939*0957b409SSimon J. Gerraty 940*0957b409SSimon J. Gerraty \ Protocol version 941*0957b409SSimon J. Gerraty addr-version get16 write16 942*0957b409SSimon J. Gerraty 943*0957b409SSimon J. Gerraty \ Server random 944*0957b409SSimon J. Gerraty addr-server_random 4 bzero 945*0957b409SSimon J. Gerraty addr-server_random 4 + 28 mkrand 946*0957b409SSimon J. Gerraty addr-server_random 32 write-blob 947*0957b409SSimon J. Gerraty 948*0957b409SSimon J. Gerraty \ Session ID 949*0957b409SSimon J. Gerraty \ TODO: if we have no session cache at all, we might send here 950*0957b409SSimon J. Gerraty \ an empty session ID. This would save a bit of network 951*0957b409SSimon J. Gerraty \ bandwidth. 952*0957b409SSimon J. Gerraty 32 write8 953*0957b409SSimon J. Gerraty addr-session_id 32 write-blob 954*0957b409SSimon J. Gerraty 955*0957b409SSimon J. Gerraty \ Cipher suite 956*0957b409SSimon J. Gerraty addr-cipher_suite get16 write16 957*0957b409SSimon J. Gerraty 958*0957b409SSimon J. Gerraty \ Compression method 959*0957b409SSimon J. Gerraty 0 write8 960*0957b409SSimon J. Gerraty 961*0957b409SSimon J. Gerraty \ Extensions 962*0957b409SSimon J. Gerraty ext-reneg-len ext-max-frag-len + ext-ALPN-len + dup if 963*0957b409SSimon J. Gerraty write16 964*0957b409SSimon J. Gerraty ext-reneg-len dup if 965*0957b409SSimon J. Gerraty 0xFF01 write16 966*0957b409SSimon J. Gerraty 4 - dup write16 967*0957b409SSimon J. Gerraty 1- addr-saved_finished swap write-blob-head8 968*0957b409SSimon J. Gerraty else 969*0957b409SSimon J. Gerraty drop 970*0957b409SSimon J. Gerraty then 971*0957b409SSimon J. Gerraty ext-max-frag-len if 972*0957b409SSimon J. Gerraty 0x0001 write16 973*0957b409SSimon J. Gerraty 1 write16 addr-peer_log_max_frag_len get8 8 - write8 974*0957b409SSimon J. Gerraty then 975*0957b409SSimon J. Gerraty ext-ALPN-len dup if 976*0957b409SSimon J. Gerraty \ Note: the selected protocol name was previously 977*0957b409SSimon J. Gerraty \ copied into the pad. 978*0957b409SSimon J. Gerraty 0x0010 write16 979*0957b409SSimon J. Gerraty 4 - dup write16 980*0957b409SSimon J. Gerraty 2- dup write16 981*0957b409SSimon J. Gerraty 1- addr-pad swap write-blob-head8 982*0957b409SSimon J. Gerraty else 983*0957b409SSimon J. Gerraty drop 984*0957b409SSimon J. Gerraty then 985*0957b409SSimon J. Gerraty else 986*0957b409SSimon J. Gerraty drop 987*0957b409SSimon J. Gerraty then ; 988*0957b409SSimon J. Gerraty 989*0957b409SSimon J. Gerraty\ Do the first part of ECDHE. Returned value is the computed signature 990*0957b409SSimon J. Gerraty\ length, or a negative error code on error. 991*0957b409SSimon J. Gerratycc: do-ecdhe-part1 ( curve -- len ) { 992*0957b409SSimon J. Gerraty int curve = T0_POPi(); 993*0957b409SSimon J. Gerraty T0_PUSHi(do_ecdhe_part1(CTX, curve)); 994*0957b409SSimon J. Gerraty} 995*0957b409SSimon J. Gerraty 996*0957b409SSimon J. Gerraty\ Get index of first bit set to 1 (in low to high order). 997*0957b409SSimon J. Gerraty: lowest-1 ( bits -- n ) 998*0957b409SSimon J. Gerraty dup ifnot drop -1 ret then 999*0957b409SSimon J. Gerraty 0 begin dup2 >> 1 and 0= while 1+ repeat 1000*0957b409SSimon J. Gerraty swap drop ; 1001*0957b409SSimon J. Gerraty 1002*0957b409SSimon J. Gerraty\ Write the Server Key Exchange message (if applicable). 1003*0957b409SSimon J. Gerraty: write-ServerKeyExchange ( -- ) 1004*0957b409SSimon J. Gerraty addr-cipher_suite get16 use-ecdhe? ifnot ret then 1005*0957b409SSimon J. Gerraty 1006*0957b409SSimon J. Gerraty \ We must select an appropriate curve among the curves that 1007*0957b409SSimon J. Gerraty \ are supported both by us and the peer. Right now, we apply 1008*0957b409SSimon J. Gerraty \ a fixed preference order: Curve25519, P-256, P-384, P-521, 1009*0957b409SSimon J. Gerraty \ then the common curve with the lowest ID. 1010*0957b409SSimon J. Gerraty \ (TODO: add some option to make that behaviour configurable.) 1011*0957b409SSimon J. Gerraty \ 1012*0957b409SSimon J. Gerraty \ This loop always terminates because previous processing made 1013*0957b409SSimon J. Gerraty \ sure that ECDHE suites are not selectable if there is no common 1014*0957b409SSimon J. Gerraty \ curve. 1015*0957b409SSimon J. Gerraty addr-curves get32 1016*0957b409SSimon J. Gerraty dup 0x20000000 and if 1017*0957b409SSimon J. Gerraty drop 29 1018*0957b409SSimon J. Gerraty else 1019*0957b409SSimon J. Gerraty dup 0x38000000 and dup if swap then 1020*0957b409SSimon J. Gerraty drop lowest-1 1021*0957b409SSimon J. Gerraty then 1022*0957b409SSimon J. Gerraty { curve-id } 1023*0957b409SSimon J. Gerraty 1024*0957b409SSimon J. Gerraty \ Compute the signed curve point to send. 1025*0957b409SSimon J. Gerraty curve-id do-ecdhe-part1 dup 0< if neg fail then { sig-len } 1026*0957b409SSimon J. Gerraty 1027*0957b409SSimon J. Gerraty \ If using TLS-1.2+, then the hash function and signature 1028*0957b409SSimon J. Gerraty \ algorithm are explicitly encoded in the message. 1029*0957b409SSimon J. Gerraty addr-version get16 0x0303 >= { tls1.2+ } 1030*0957b409SSimon J. Gerraty 1031*0957b409SSimon J. Gerraty 12 write8 1032*0957b409SSimon J. Gerraty sig-len addr-ecdhe_point_len get8 + tls1.2+ 2 and + 6 + write24 1033*0957b409SSimon J. Gerraty 1034*0957b409SSimon J. Gerraty \ Curve parameters: named curve with 16-bit ID. 1035*0957b409SSimon J. Gerraty 3 write8 curve-id write16 1036*0957b409SSimon J. Gerraty 1037*0957b409SSimon J. Gerraty \ Public point. 1038*0957b409SSimon J. Gerraty addr-ecdhe_point addr-ecdhe_point_len get8 write-blob-head8 1039*0957b409SSimon J. Gerraty 1040*0957b409SSimon J. Gerraty \ If TLS-1.2+, write hash and signature identifiers. 1041*0957b409SSimon J. Gerraty tls1.2+ if 1042*0957b409SSimon J. Gerraty \ sign_hash_id contains either a hash identifier, 1043*0957b409SSimon J. Gerraty \ or the complete 16-bit value to write. 1044*0957b409SSimon J. Gerraty addr-sign_hash_id get16 1045*0957b409SSimon J. Gerraty dup 0xFF00 < if 1046*0957b409SSimon J. Gerraty write16 1047*0957b409SSimon J. Gerraty else 1048*0957b409SSimon J. Gerraty 0xFF and write8 1049*0957b409SSimon J. Gerraty \ 'use-rsa-ecdhe?' returns -1 for RSA, 0 for 1050*0957b409SSimon J. Gerraty \ ECDSA. The byte on the wire shall be 1 for RSA, 1051*0957b409SSimon J. Gerraty \ 3 for ECDSA. 1052*0957b409SSimon J. Gerraty addr-cipher_suite get16 use-rsa-ecdhe? 1 << 3 + write8 1053*0957b409SSimon J. Gerraty then 1054*0957b409SSimon J. Gerraty then 1055*0957b409SSimon J. Gerraty 1056*0957b409SSimon J. Gerraty \ Signature. 1057*0957b409SSimon J. Gerraty sig-len write16 1058*0957b409SSimon J. Gerraty addr-pad sig-len write-blob ; 1059*0957b409SSimon J. Gerraty 1060*0957b409SSimon J. Gerraty\ Get length of the list of anchor names to send to the client. The length 1061*0957b409SSimon J. Gerraty\ includes the per-name 2-byte header, but _not_ the 2-byte header for 1062*0957b409SSimon J. Gerraty\ the list itself. If no client certificate is requested, then this 1063*0957b409SSimon J. Gerraty\ returns 0. 1064*0957b409SSimon J. Gerratycc: ta-names-total-length ( -- len ) { 1065*0957b409SSimon J. Gerraty size_t u, len; 1066*0957b409SSimon J. Gerraty 1067*0957b409SSimon J. Gerraty len = 0; 1068*0957b409SSimon J. Gerraty if (CTX->ta_names != NULL) { 1069*0957b409SSimon J. Gerraty for (u = 0; u < CTX->num_tas; u ++) { 1070*0957b409SSimon J. Gerraty len += CTX->ta_names[u].len + 2; 1071*0957b409SSimon J. Gerraty } 1072*0957b409SSimon J. Gerraty } else if (CTX->tas != NULL) { 1073*0957b409SSimon J. Gerraty for (u = 0; u < CTX->num_tas; u ++) { 1074*0957b409SSimon J. Gerraty len += CTX->tas[u].dn.len + 2; 1075*0957b409SSimon J. Gerraty } 1076*0957b409SSimon J. Gerraty } 1077*0957b409SSimon J. Gerraty T0_PUSH(len); 1078*0957b409SSimon J. Gerraty} 1079*0957b409SSimon J. Gerraty 1080*0957b409SSimon J. Gerraty\ Compute length and optionally write the contents of the list of 1081*0957b409SSimon J. Gerraty\ supported client authentication methods. 1082*0957b409SSimon J. Gerraty: write-list-auth ( do_write -- len ) 1083*0957b409SSimon J. Gerraty 0 1084*0957b409SSimon J. Gerraty addr-cipher_suite get16 use-ecdh? if 1085*0957b409SSimon J. Gerraty 2+ over if 65 write8 66 write8 then 1086*0957b409SSimon J. Gerraty then 1087*0957b409SSimon J. Gerraty supports-rsa-sign? if 1+ over if 1 write8 then then 1088*0957b409SSimon J. Gerraty supports-ecdsa? if 1+ over if 64 write8 then then 1089*0957b409SSimon J. Gerraty swap drop ; 1090*0957b409SSimon J. Gerraty 1091*0957b409SSimon J. Gerraty: write-signhash-inner2 ( dow algo hashes len id -- dow algo hashes len ) 1092*0957b409SSimon J. Gerraty { id } 1093*0957b409SSimon J. Gerraty over 1 id << and ifnot ret then 1094*0957b409SSimon J. Gerraty 2+ 1095*0957b409SSimon J. Gerraty 3 pick if id write8 2 pick write8 then ; 1096*0957b409SSimon J. Gerraty 1097*0957b409SSimon J. Gerraty: write-signhash-inner1 ( dow algo hashes -- dow len ) 1098*0957b409SSimon J. Gerraty 0 1099*0957b409SSimon J. Gerraty 4 write-signhash-inner2 1100*0957b409SSimon J. Gerraty 5 write-signhash-inner2 1101*0957b409SSimon J. Gerraty 6 write-signhash-inner2 1102*0957b409SSimon J. Gerraty 3 write-signhash-inner2 1103*0957b409SSimon J. Gerraty 2 write-signhash-inner2 1104*0957b409SSimon J. Gerraty -rot 2drop ; 1105*0957b409SSimon J. Gerraty 1106*0957b409SSimon J. Gerraty\ Compute length and optionally write the contents of the list of 1107*0957b409SSimon J. Gerraty\ supported sign+hash algorithms. 1108*0957b409SSimon J. Gerraty: write-list-signhash ( do_write -- len ) 1109*0957b409SSimon J. Gerraty 0 { len } 1110*0957b409SSimon J. Gerraty \ If supporting neither RSA nor ECDSA in the engine, then we 1111*0957b409SSimon J. Gerraty \ will do only static ECDH, and thus we claim support for 1112*0957b409SSimon J. Gerraty \ everything (for the X.509 validator). 1113*0957b409SSimon J. Gerraty supports-rsa-sign? supports-ecdsa? or ifnot 1114*0957b409SSimon J. Gerraty 1 0x7C write-signhash-inner1 >len 1115*0957b409SSimon J. Gerraty 3 0x7C write-signhash-inner1 len + 1116*0957b409SSimon J. Gerraty swap drop ret 1117*0957b409SSimon J. Gerraty then 1118*0957b409SSimon J. Gerraty supports-rsa-sign? if 1119*0957b409SSimon J. Gerraty 1 supported-hash-functions drop 1120*0957b409SSimon J. Gerraty write-signhash-inner1 >len 1121*0957b409SSimon J. Gerraty then 1122*0957b409SSimon J. Gerraty supports-ecdsa? if 1123*0957b409SSimon J. Gerraty 3 supported-hash-functions drop 1124*0957b409SSimon J. Gerraty write-signhash-inner1 len + >len 1125*0957b409SSimon J. Gerraty then 1126*0957b409SSimon J. Gerraty drop len ; 1127*0957b409SSimon J. Gerraty 1128*0957b409SSimon J. Gerraty\ Initialise index for sending the list of anchor DN. 1129*0957b409SSimon J. Gerratycc: begin-ta-name-list ( -- ) { 1130*0957b409SSimon J. Gerraty CTX->cur_dn_index = 0; 1131*0957b409SSimon J. Gerraty} 1132*0957b409SSimon J. Gerraty 1133*0957b409SSimon J. Gerraty\ Switch to next DN in the list. Returned value is the DN length, or -1 1134*0957b409SSimon J. Gerraty\ if the end of the list was reached. 1135*0957b409SSimon J. Gerratycc: begin-ta-name ( -- len ) { 1136*0957b409SSimon J. Gerraty const br_x500_name *dn; 1137*0957b409SSimon J. Gerraty if (CTX->cur_dn_index >= CTX->num_tas) { 1138*0957b409SSimon J. Gerraty T0_PUSHi(-1); 1139*0957b409SSimon J. Gerraty } else { 1140*0957b409SSimon J. Gerraty if (CTX->ta_names == NULL) { 1141*0957b409SSimon J. Gerraty dn = &CTX->tas[CTX->cur_dn_index].dn; 1142*0957b409SSimon J. Gerraty } else { 1143*0957b409SSimon J. Gerraty dn = &CTX->ta_names[CTX->cur_dn_index]; 1144*0957b409SSimon J. Gerraty } 1145*0957b409SSimon J. Gerraty CTX->cur_dn_index ++; 1146*0957b409SSimon J. Gerraty CTX->cur_dn = dn->data; 1147*0957b409SSimon J. Gerraty CTX->cur_dn_len = dn->len; 1148*0957b409SSimon J. Gerraty T0_PUSH(CTX->cur_dn_len); 1149*0957b409SSimon J. Gerraty } 1150*0957b409SSimon J. Gerraty} 1151*0957b409SSimon J. Gerraty 1152*0957b409SSimon J. Gerraty\ Copy a chunk of the current DN into the pad. Returned value is the 1153*0957b409SSimon J. Gerraty\ chunk length; this is 0 when the end of the current DN is reached. 1154*0957b409SSimon J. Gerratycc: copy-dn-chunk ( -- len ) { 1155*0957b409SSimon J. Gerraty size_t clen; 1156*0957b409SSimon J. Gerraty 1157*0957b409SSimon J. Gerraty clen = CTX->cur_dn_len; 1158*0957b409SSimon J. Gerraty if (clen > sizeof ENG->pad) { 1159*0957b409SSimon J. Gerraty clen = sizeof ENG->pad; 1160*0957b409SSimon J. Gerraty } 1161*0957b409SSimon J. Gerraty memcpy(ENG->pad, CTX->cur_dn, clen); 1162*0957b409SSimon J. Gerraty CTX->cur_dn += clen; 1163*0957b409SSimon J. Gerraty CTX->cur_dn_len -= clen; 1164*0957b409SSimon J. Gerraty T0_PUSH(clen); 1165*0957b409SSimon J. Gerraty} 1166*0957b409SSimon J. Gerraty 1167*0957b409SSimon J. Gerraty\ Write a CertificateRequest message. 1168*0957b409SSimon J. Gerraty: write-CertificateRequest ( -- ) 1169*0957b409SSimon J. Gerraty \ The list of client authentication types includes: 1170*0957b409SSimon J. Gerraty \ rsa_sign (1) 1171*0957b409SSimon J. Gerraty \ ecdsa_sign (64) 1172*0957b409SSimon J. Gerraty \ rsa_fixed_ecdh (65) 1173*0957b409SSimon J. Gerraty \ ecdsa_fixed_ecdh (66) 1174*0957b409SSimon J. Gerraty \ rsa_sign and ecdsa_sign require, respectively, RSA and ECDSA 1175*0957b409SSimon J. Gerraty \ support. Static ECDH requires that the cipher suite is ECDH. 1176*0957b409SSimon J. Gerraty \ When we ask for static ECDH, we always send both rsa_fixed_ecdh 1177*0957b409SSimon J. Gerraty \ and ecdsa_fixed_ecdh because what matters there is what the 1178*0957b409SSimon J. Gerraty \ X.509 engine may support, and we do not control that. 1179*0957b409SSimon J. Gerraty \ 1180*0957b409SSimon J. Gerraty \ With TLS 1.2, we must also send a list of supported signature 1181*0957b409SSimon J. Gerraty \ and hash algorithms. That list is supposed to qualify both 1182*0957b409SSimon J. Gerraty \ the engine itself, and the X.509 validator, which are separate 1183*0957b409SSimon J. Gerraty \ in BearSSL. There again, we use the engine capabilities in that 1184*0957b409SSimon J. Gerraty \ list, and resort to a generic all-support list if only 1185*0957b409SSimon J. Gerraty \ static ECDH is accepted. 1186*0957b409SSimon J. Gerraty \ 1187*0957b409SSimon J. Gerraty \ (In practice, client implementations tend to have at most one 1188*0957b409SSimon J. Gerraty \ or two certificates, and send the chain regardless of what 1189*0957b409SSimon J. Gerraty \ algorithms are used in it.) 1190*0957b409SSimon J. Gerraty 1191*0957b409SSimon J. Gerraty 0 write-list-auth 1192*0957b409SSimon J. Gerraty addr-version get16 0x0303 >= if 1193*0957b409SSimon J. Gerraty 2+ 0 write-list-signhash + 1194*0957b409SSimon J. Gerraty then 1195*0957b409SSimon J. Gerraty ta-names-total-length + 3 + 1196*0957b409SSimon J. Gerraty 1197*0957b409SSimon J. Gerraty \ Message header 1198*0957b409SSimon J. Gerraty 13 write8 write24 1199*0957b409SSimon J. Gerraty 1200*0957b409SSimon J. Gerraty \ List of authentication methods 1201*0957b409SSimon J. Gerraty 0 write-list-auth write8 1 write-list-auth drop 1202*0957b409SSimon J. Gerraty 1203*0957b409SSimon J. Gerraty \ For TLS 1.2+, list of sign+hash 1204*0957b409SSimon J. Gerraty addr-version get16 0x0303 >= if 1205*0957b409SSimon J. Gerraty 0 write-list-signhash write16 1 write-list-signhash drop 1206*0957b409SSimon J. Gerraty then 1207*0957b409SSimon J. Gerraty 1208*0957b409SSimon J. Gerraty \ Trust anchor names 1209*0957b409SSimon J. Gerraty ta-names-total-length write16 1210*0957b409SSimon J. Gerraty begin-ta-name-list 1211*0957b409SSimon J. Gerraty begin 1212*0957b409SSimon J. Gerraty begin-ta-name 1213*0957b409SSimon J. Gerraty dup 0< if drop ret then write16 1214*0957b409SSimon J. Gerraty begin copy-dn-chunk dup while 1215*0957b409SSimon J. Gerraty addr-pad swap write-blob 1216*0957b409SSimon J. Gerraty repeat 1217*0957b409SSimon J. Gerraty drop 1218*0957b409SSimon J. Gerraty again ; 1219*0957b409SSimon J. Gerraty 1220*0957b409SSimon J. Gerraty\ Write the Server Hello Done message. 1221*0957b409SSimon J. Gerraty: write-ServerHelloDone ( -- ) 1222*0957b409SSimon J. Gerraty 14 write8 0 write24 ; 1223*0957b409SSimon J. Gerraty 1224*0957b409SSimon J. Gerraty\ Perform RSA decryption of the client-sent pre-master secret. The value 1225*0957b409SSimon J. Gerraty\ is in the pad, and its length is provided as parameter. 1226*0957b409SSimon J. Gerratycc: do-rsa-decrypt ( len prf_id -- ) { 1227*0957b409SSimon J. Gerraty int prf_id = T0_POPi(); 1228*0957b409SSimon J. Gerraty size_t len = T0_POP(); 1229*0957b409SSimon J. Gerraty do_rsa_decrypt(CTX, prf_id, ENG->pad, len); 1230*0957b409SSimon J. Gerraty} 1231*0957b409SSimon J. Gerraty 1232*0957b409SSimon J. Gerraty\ Perform ECDH (not ECDHE). The point from the client is in the pad, and 1233*0957b409SSimon J. Gerraty\ its length is provided as parameter. 1234*0957b409SSimon J. Gerratycc: do-ecdh ( len prf_id -- ) { 1235*0957b409SSimon J. Gerraty int prf_id = T0_POPi(); 1236*0957b409SSimon J. Gerraty size_t len = T0_POP(); 1237*0957b409SSimon J. Gerraty do_ecdh(CTX, prf_id, ENG->pad, len); 1238*0957b409SSimon J. Gerraty} 1239*0957b409SSimon J. Gerraty 1240*0957b409SSimon J. Gerraty\ Do the second part of ECDHE. 1241*0957b409SSimon J. Gerratycc: do-ecdhe-part2 ( len prf_id -- ) { 1242*0957b409SSimon J. Gerraty int prf_id = T0_POPi(); 1243*0957b409SSimon J. Gerraty size_t len = T0_POP(); 1244*0957b409SSimon J. Gerraty do_ecdhe_part2(CTX, prf_id, ENG->pad, len); 1245*0957b409SSimon J. Gerraty} 1246*0957b409SSimon J. Gerraty 1247*0957b409SSimon J. Gerraty\ Perform static ECDH. The point from the client is the public key 1248*0957b409SSimon J. Gerraty\ extracted from its certificate. 1249*0957b409SSimon J. Gerratycc: do-static-ecdh ( prf_id -- ) { 1250*0957b409SSimon J. Gerraty do_static_ecdh(CTX, T0_POP()); 1251*0957b409SSimon J. Gerraty} 1252*0957b409SSimon J. Gerraty 1253*0957b409SSimon J. Gerraty\ Read a ClientKeyExchange header. 1254*0957b409SSimon J. Gerraty: read-ClientKeyExchange-header ( -- len ) 1255*0957b409SSimon J. Gerraty read-handshake-header 16 = ifnot ERR_UNEXPECTED fail then ; 1256*0957b409SSimon J. Gerraty 1257*0957b409SSimon J. Gerraty\ Read the Client Key Exchange contents (non-empty case). 1258*0957b409SSimon J. Gerraty: read-ClientKeyExchange-contents ( lim -- ) 1259*0957b409SSimon J. Gerraty \ What we should get depends on the cipher suite. 1260*0957b409SSimon J. Gerraty addr-cipher_suite get16 use-rsa-keyx? if 1261*0957b409SSimon J. Gerraty \ RSA key exchange: we expect a RSA-encrypted value. 1262*0957b409SSimon J. Gerraty read16 1263*0957b409SSimon J. Gerraty dup 512 > if ERR_LIMIT_EXCEEDED fail then 1264*0957b409SSimon J. Gerraty dup { enc-rsa-len } 1265*0957b409SSimon J. Gerraty addr-pad swap read-blob 1266*0957b409SSimon J. Gerraty enc-rsa-len addr-cipher_suite get16 prf-id do-rsa-decrypt 1267*0957b409SSimon J. Gerraty then 1268*0957b409SSimon J. Gerraty addr-cipher_suite get16 dup use-ecdhe? swap use-ecdh? { ecdhe ecdh } 1269*0957b409SSimon J. Gerraty ecdh ecdhe or if 1270*0957b409SSimon J. Gerraty \ ECDH or ECDHE key exchange: we expect an EC point. 1271*0957b409SSimon J. Gerraty read8 dup { ec-point-len } 1272*0957b409SSimon J. Gerraty addr-pad swap read-blob 1273*0957b409SSimon J. Gerraty ec-point-len addr-cipher_suite get16 prf-id 1274*0957b409SSimon J. Gerraty ecdhe if do-ecdhe-part2 else do-ecdh then 1275*0957b409SSimon J. Gerraty then 1276*0957b409SSimon J. Gerraty close-elt ; 1277*0957b409SSimon J. Gerraty 1278*0957b409SSimon J. Gerraty\ Read the Client Key Exchange (normal case). 1279*0957b409SSimon J. Gerraty: read-ClientKeyExchange ( -- ) 1280*0957b409SSimon J. Gerraty read-ClientKeyExchange-header 1281*0957b409SSimon J. Gerraty read-ClientKeyExchange-contents ; 1282*0957b409SSimon J. Gerraty 1283*0957b409SSimon J. Gerraty\ Obtain all possible hash values for handshake messages so far. This 1284*0957b409SSimon J. Gerraty\ is done because we need the hash value for the CertificateVerify 1285*0957b409SSimon J. Gerraty\ _before_ knowing which hash function will actually be used, as this 1286*0957b409SSimon J. Gerraty\ information is obtained from decoding the message header itself. 1287*0957b409SSimon J. Gerraty\ All hash values are stored in the pad (208 bytes in total). 1288*0957b409SSimon J. Gerratycc: compute-hash-CV ( -- ) { 1289*0957b409SSimon J. Gerraty int i; 1290*0957b409SSimon J. Gerraty 1291*0957b409SSimon J. Gerraty for (i = 1; i <= 6; i ++) { 1292*0957b409SSimon J. Gerraty br_multihash_out(&ENG->mhash, i, 1293*0957b409SSimon J. Gerraty ENG->pad + HASH_PAD_OFF[i - 1]); 1294*0957b409SSimon J. Gerraty } 1295*0957b409SSimon J. Gerraty} 1296*0957b409SSimon J. Gerraty 1297*0957b409SSimon J. Gerraty\ Copy the proper hash value from the pad into the dedicated buffer. 1298*0957b409SSimon J. Gerraty\ Returned value is true (-1) on success, false (0) on error (error 1299*0957b409SSimon J. Gerraty\ being an unimplemented hash function). The id has already been verified 1300*0957b409SSimon J. Gerraty\ to be either 0 (for MD5+SHA-1) or one of the SHA-* functions. 1301*0957b409SSimon J. Gerratycc: copy-hash-CV ( hash_id -- bool ) { 1302*0957b409SSimon J. Gerraty int id = T0_POP(); 1303*0957b409SSimon J. Gerraty size_t off, len; 1304*0957b409SSimon J. Gerraty 1305*0957b409SSimon J. Gerraty if (id == 0) { 1306*0957b409SSimon J. Gerraty off = 0; 1307*0957b409SSimon J. Gerraty len = 36; 1308*0957b409SSimon J. Gerraty } else { 1309*0957b409SSimon J. Gerraty if (br_multihash_getimpl(&ENG->mhash, id) == 0) { 1310*0957b409SSimon J. Gerraty T0_PUSH(0); 1311*0957b409SSimon J. Gerraty T0_RET(); 1312*0957b409SSimon J. Gerraty } 1313*0957b409SSimon J. Gerraty off = HASH_PAD_OFF[id - 1]; 1314*0957b409SSimon J. Gerraty len = HASH_PAD_OFF[id] - off; 1315*0957b409SSimon J. Gerraty } 1316*0957b409SSimon J. Gerraty memcpy(CTX->hash_CV, ENG->pad + off, len); 1317*0957b409SSimon J. Gerraty CTX->hash_CV_len = len; 1318*0957b409SSimon J. Gerraty CTX->hash_CV_id = id; 1319*0957b409SSimon J. Gerraty T0_PUSHi(-1); 1320*0957b409SSimon J. Gerraty} 1321*0957b409SSimon J. Gerraty 1322*0957b409SSimon J. Gerraty\ Verify signature in CertificateVerify. Output is 0 on success, or a 1323*0957b409SSimon J. Gerraty\ non-zero error code. 1324*0957b409SSimon J. Gerratycc: verify-CV-sig ( sig-len -- err ) { 1325*0957b409SSimon J. Gerraty int err; 1326*0957b409SSimon J. Gerraty 1327*0957b409SSimon J. Gerraty err = verify_CV_sig(CTX, T0_POP()); 1328*0957b409SSimon J. Gerraty T0_PUSHi(err); 1329*0957b409SSimon J. Gerraty} 1330*0957b409SSimon J. Gerraty 1331*0957b409SSimon J. Gerraty\ Process static ECDH. 1332*0957b409SSimon J. Gerraty: process-static-ECDH ( ktu -- ) 1333*0957b409SSimon J. Gerraty \ Static ECDH is allowed only if the cipher suite uses ECDH, and 1334*0957b409SSimon J. Gerraty \ the client's public key has type EC and allows key exchange. 1335*0957b409SSimon J. Gerraty \ BR_KEYTYPE_KEYX is 0x10, and BR_KEYTYPE_EC is 2. 1336*0957b409SSimon J. Gerraty 0x1F and 0x12 = ifnot ERR_WRONG_KEY_USAGE fail then 1337*0957b409SSimon J. Gerraty addr-cipher_suite get16 1338*0957b409SSimon J. Gerraty dup use-ecdh? ifnot ERR_UNEXPECTED fail then 1339*0957b409SSimon J. Gerraty prf-id 1340*0957b409SSimon J. Gerraty do-static-ecdh ; 1341*0957b409SSimon J. Gerraty 1342*0957b409SSimon J. Gerraty\ Read CertificateVerify header. 1343*0957b409SSimon J. Gerraty: read-CertificateVerify-header ( -- lim ) 1344*0957b409SSimon J. Gerraty compute-hash-CV 1345*0957b409SSimon J. Gerraty read-handshake-header 15 = ifnot ERR_UNEXPECTED fail then ; 1346*0957b409SSimon J. Gerraty 1347*0957b409SSimon J. Gerraty\ Read CertificateVerify. The client key type + usage is expected on the 1348*0957b409SSimon J. Gerraty\ stack. 1349*0957b409SSimon J. Gerraty: read-CertificateVerify ( ktu -- ) 1350*0957b409SSimon J. Gerraty \ Check that the key allows for signatures. 1351*0957b409SSimon J. Gerraty dup 0x20 and ifnot ERR_WRONG_KEY_USAGE fail then 1352*0957b409SSimon J. Gerraty 0x0F and { key-type } 1353*0957b409SSimon J. Gerraty 1354*0957b409SSimon J. Gerraty \ Get header. 1355*0957b409SSimon J. Gerraty read-CertificateVerify-header 1356*0957b409SSimon J. Gerraty 1357*0957b409SSimon J. Gerraty \ With TLS 1.2+, there is an explicit hash + signature indication, 1358*0957b409SSimon J. Gerraty \ which must be compatible with the key type. 1359*0957b409SSimon J. Gerraty addr-version get16 0x0303 >= if 1360*0957b409SSimon J. Gerraty \ Get hash function, then signature algorithm. The 1361*0957b409SSimon J. Gerraty \ signature algorithm is 1 (RSA) or 3 (ECDSA) while our 1362*0957b409SSimon J. Gerraty \ symbolic constants for key types are 1 (RSA) or 2 (EC). 1363*0957b409SSimon J. Gerraty read16 1364*0957b409SSimon J. Gerraty dup 0xFF and 1+ 1 >> key-type = ifnot 1365*0957b409SSimon J. Gerraty ERR_BAD_SIGNATURE fail 1366*0957b409SSimon J. Gerraty then 1367*0957b409SSimon J. Gerraty 8 >> 1368*0957b409SSimon J. Gerraty 1369*0957b409SSimon J. Gerraty \ We support only SHA-1, SHA-224, SHA-256, SHA-384 1370*0957b409SSimon J. Gerraty \ and SHA-512. We explicitly reject MD5. 1371*0957b409SSimon J. Gerraty dup 2 < over 6 > or if ERR_INVALID_ALGORITHM fail then 1372*0957b409SSimon J. Gerraty else 1373*0957b409SSimon J. Gerraty \ With TLS 1.0 and 1.1, hash is MD5+SHA-1 (0) for RSA, 1374*0957b409SSimon J. Gerraty \ SHA-1 (2) for ECDSA. 1375*0957b409SSimon J. Gerraty key-type 0x01 = if 0 else 2 then 1376*0957b409SSimon J. Gerraty then 1377*0957b409SSimon J. Gerraty copy-hash-CV ifnot ERR_INVALID_ALGORITHM fail then 1378*0957b409SSimon J. Gerraty 1379*0957b409SSimon J. Gerraty \ Read signature. 1380*0957b409SSimon J. Gerraty read16 dup { sig-len } 1381*0957b409SSimon J. Gerraty dup 512 > if ERR_LIMIT_EXCEEDED fail then 1382*0957b409SSimon J. Gerraty addr-pad swap read-blob 1383*0957b409SSimon J. Gerraty sig-len verify-CV-sig 1384*0957b409SSimon J. Gerraty dup if fail then drop 1385*0957b409SSimon J. Gerraty 1386*0957b409SSimon J. Gerraty close-elt ; 1387*0957b409SSimon J. Gerraty 1388*0957b409SSimon J. Gerraty\ Send a HelloRequest. 1389*0957b409SSimon J. Gerraty: send-HelloRequest ( -- ) 1390*0957b409SSimon J. Gerraty flush-record 1391*0957b409SSimon J. Gerraty begin can-output? not while wait-co drop repeat 1392*0957b409SSimon J. Gerraty 22 addr-record_type_out set8 1393*0957b409SSimon J. Gerraty 0 write8 0 write24 flush-record 1394*0957b409SSimon J. Gerraty 23 addr-record_type_out set8 ; 1395*0957b409SSimon J. Gerraty 1396*0957b409SSimon J. Gerraty\ Make a handshake. 1397*0957b409SSimon J. Gerraty: do-handshake ( initial -- ) 1398*0957b409SSimon J. Gerraty 0 addr-application_data set8 1399*0957b409SSimon J. Gerraty 22 addr-record_type_out set8 1400*0957b409SSimon J. Gerraty 0 addr-selected_protocol set16 1401*0957b409SSimon J. Gerraty multihash-init 1402*0957b409SSimon J. Gerraty read-ClientHello 1403*0957b409SSimon J. Gerraty more-incoming-bytes? if ERR_UNEXPECTED fail then 1404*0957b409SSimon J. Gerraty if 1405*0957b409SSimon J. Gerraty \ Session resumption 1406*0957b409SSimon J. Gerraty write-ServerHello 1407*0957b409SSimon J. Gerraty 0 write-CCS-Finished 1408*0957b409SSimon J. Gerraty 0 read-CCS-Finished 1409*0957b409SSimon J. Gerraty else 1410*0957b409SSimon J. Gerraty \ Not a session resumption 1411*0957b409SSimon J. Gerraty write-ServerHello 1412*0957b409SSimon J. Gerraty write-Certificate drop 1413*0957b409SSimon J. Gerraty write-ServerKeyExchange 1414*0957b409SSimon J. Gerraty ta-names-total-length if 1415*0957b409SSimon J. Gerraty write-CertificateRequest 1416*0957b409SSimon J. Gerraty then 1417*0957b409SSimon J. Gerraty write-ServerHelloDone 1418*0957b409SSimon J. Gerraty flush-record 1419*0957b409SSimon J. Gerraty 1420*0957b409SSimon J. Gerraty \ If we sent a CertificateRequest then we expect a 1421*0957b409SSimon J. Gerraty \ Certificate message. 1422*0957b409SSimon J. Gerraty ta-names-total-length if 1423*0957b409SSimon J. Gerraty \ Read client certificate. 1424*0957b409SSimon J. Gerraty 0 read-Certificate 1425*0957b409SSimon J. Gerraty 1426*0957b409SSimon J. Gerraty choice 1427*0957b409SSimon J. Gerraty dup 0< uf 1428*0957b409SSimon J. Gerraty \ Client certificate validation failed. 1429*0957b409SSimon J. Gerraty 2 flag? ifnot neg fail then 1430*0957b409SSimon J. Gerraty drop 1431*0957b409SSimon J. Gerraty read-ClientKeyExchange 1432*0957b409SSimon J. Gerraty read-CertificateVerify-header 1433*0957b409SSimon J. Gerraty dup skip-blob drop 1434*0957b409SSimon J. Gerraty enduf 1435*0957b409SSimon J. Gerraty dup 0= uf 1436*0957b409SSimon J. Gerraty \ Client sent no certificate at all. 1437*0957b409SSimon J. Gerraty drop 1438*0957b409SSimon J. Gerraty 2 flag? ifnot 1439*0957b409SSimon J. Gerraty ERR_NO_CLIENT_AUTH fail 1440*0957b409SSimon J. Gerraty then 1441*0957b409SSimon J. Gerraty read-ClientKeyExchange 1442*0957b409SSimon J. Gerraty enduf 1443*0957b409SSimon J. Gerraty 1444*0957b409SSimon J. Gerraty \ Client certificate was validated. 1445*0957b409SSimon J. Gerraty read-ClientKeyExchange-header 1446*0957b409SSimon J. Gerraty dup ifnot 1447*0957b409SSimon J. Gerraty \ Empty ClientKeyExchange. 1448*0957b409SSimon J. Gerraty drop 1449*0957b409SSimon J. Gerraty process-static-ECDH 1450*0957b409SSimon J. Gerraty else 1451*0957b409SSimon J. Gerraty read-ClientKeyExchange-contents 1452*0957b409SSimon J. Gerraty read-CertificateVerify 1453*0957b409SSimon J. Gerraty then 1454*0957b409SSimon J. Gerraty endchoice 1455*0957b409SSimon J. Gerraty else 1456*0957b409SSimon J. Gerraty \ No client certificate request, we just expect 1457*0957b409SSimon J. Gerraty \ a non-empty ClientKeyExchange. 1458*0957b409SSimon J. Gerraty read-ClientKeyExchange 1459*0957b409SSimon J. Gerraty then 1460*0957b409SSimon J. Gerraty 0 read-CCS-Finished 1461*0957b409SSimon J. Gerraty 0 write-CCS-Finished 1462*0957b409SSimon J. Gerraty save-session 1463*0957b409SSimon J. Gerraty then 1464*0957b409SSimon J. Gerraty 1 addr-application_data set8 1465*0957b409SSimon J. Gerraty 23 addr-record_type_out set8 ; 1466*0957b409SSimon J. Gerraty 1467*0957b409SSimon J. Gerraty\ Entry point. 1468*0957b409SSimon J. Gerraty: main ( -- ! ) 1469*0957b409SSimon J. Gerraty \ Perform initial handshake. 1470*0957b409SSimon J. Gerraty -1 do-handshake 1471*0957b409SSimon J. Gerraty 1472*0957b409SSimon J. Gerraty begin 1473*0957b409SSimon J. Gerraty \ Wait for further invocation. At that point, we should 1474*0957b409SSimon J. Gerraty \ get either an explicit call for renegotiation, or 1475*0957b409SSimon J. Gerraty \ an incoming ClientHello handshake message. 1476*0957b409SSimon J. Gerraty wait-co 1477*0957b409SSimon J. Gerraty dup 0x07 and case 1478*0957b409SSimon J. Gerraty 0x00 of 1479*0957b409SSimon J. Gerraty 0x10 and if 1480*0957b409SSimon J. Gerraty \ The best we can do is ask for a 1481*0957b409SSimon J. Gerraty \ renegotiation, then wait for it 1482*0957b409SSimon J. Gerraty \ to happen. 1483*0957b409SSimon J. Gerraty 0 addr-application_data set8 1484*0957b409SSimon J. Gerraty send-HelloRequest 1485*0957b409SSimon J. Gerraty then 1486*0957b409SSimon J. Gerraty endof 1487*0957b409SSimon J. Gerraty 0x01 of 1488*0957b409SSimon J. Gerraty \ Reject renegotiations if the peer does not 1489*0957b409SSimon J. Gerraty \ support secure renegotiation, or if the 1490*0957b409SSimon J. Gerraty \ "no renegotiation" flag is set. 1491*0957b409SSimon J. Gerraty drop 1492*0957b409SSimon J. Gerraty addr-reneg get8 1 = 1 flag? or if 1493*0957b409SSimon J. Gerraty skip-ClientHello 1494*0957b409SSimon J. Gerraty flush-record 1495*0957b409SSimon J. Gerraty begin can-output? not while 1496*0957b409SSimon J. Gerraty wait-co drop 1497*0957b409SSimon J. Gerraty repeat 1498*0957b409SSimon J. Gerraty 100 send-warning 1499*0957b409SSimon J. Gerraty \ Put back connection in "application 1500*0957b409SSimon J. Gerraty \ data" state: it's not dead yet. 1501*0957b409SSimon J. Gerraty 1 addr-application_data set8 1502*0957b409SSimon J. Gerraty 23 addr-record_type_out set8 1503*0957b409SSimon J. Gerraty else 1504*0957b409SSimon J. Gerraty 0 do-handshake 1505*0957b409SSimon J. Gerraty then 1506*0957b409SSimon J. Gerraty endof 1507*0957b409SSimon J. Gerraty ERR_UNEXPECTED fail 1508*0957b409SSimon J. Gerraty endcase 1509*0957b409SSimon J. Gerraty again 1510*0957b409SSimon J. Gerraty ; 1511