security/nss/lib/ssl/derive.c

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /*
michael@0 2 * Key Derivation that doesn't use PKCS11
michael@0 3 *
michael@0 4 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 5 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 7
michael@0 8 #include "ssl.h" /* prereq to sslimpl.h */
michael@0 9 #include "certt.h" /* prereq to sslimpl.h */
michael@0 10 #include "keythi.h" /* prereq to sslimpl.h */
michael@0 11 #include "sslimpl.h"
michael@0 12 #ifndef NO_PKCS11_BYPASS
michael@0 13 #include "blapi.h"
michael@0 14 #endif
michael@0 15
michael@0 16 #include "keyhi.h"
michael@0 17 #include "pk11func.h"
michael@0 18 #include "secasn1.h"
michael@0 19 #include "cert.h"
michael@0 20 #include "secmodt.h"
michael@0 21
michael@0 22 #include "sslproto.h"
michael@0 23 #include "sslerr.h"
michael@0 24
michael@0 25 #ifndef NO_PKCS11_BYPASS
michael@0 26 /* make this a macro! */
michael@0 27 #ifdef NOT_A_MACRO
michael@0 28 static void
michael@0 29 buildSSLKey(unsigned char * keyBlock, unsigned int keyLen, SECItem * result,
michael@0 30 const char * label)
michael@0 31 {
michael@0 32 result->type = siBuffer;
michael@0 33 result->data = keyBlock;
michael@0 34 result->len = keyLen;
michael@0 35 PRINT_BUF(100, (NULL, label, keyBlock, keyLen));
michael@0 36 }
michael@0 37 #else
michael@0 38 #define buildSSLKey(keyBlock, keyLen, result, label) \
michael@0 39 { \
michael@0 40 (result)->type = siBuffer; \
michael@0 41 (result)->data = keyBlock; \
michael@0 42 (result)->len = keyLen; \
michael@0 43 PRINT_BUF(100, (NULL, label, keyBlock, keyLen)); \
michael@0 44 }
michael@0 45 #endif
michael@0 46
michael@0 47 /*
michael@0 48 * SSL Key generation given pre master secret
michael@0 49 */
michael@0 50 #ifndef NUM_MIXERS
michael@0 51 #define NUM_MIXERS 9
michael@0 52 #endif
michael@0 53 static const char * const mixers[NUM_MIXERS] = {
michael@0 54 "A",
michael@0 55 "BB",
michael@0 56 "CCC",
michael@0 57 "DDDD",
michael@0 58 "EEEEE",
michael@0 59 "FFFFFF",
michael@0 60 "GGGGGGG",
michael@0 61 "HHHHHHHH",
michael@0 62 "IIIIIIIII"
michael@0 63 };
michael@0 64
michael@0 65
michael@0 66 SECStatus
michael@0 67 ssl3_KeyAndMacDeriveBypass(
michael@0 68 ssl3CipherSpec * pwSpec,
michael@0 69 const unsigned char * cr,
michael@0 70 const unsigned char * sr,
michael@0 71 PRBool isTLS,
michael@0 72 PRBool isExport)
michael@0 73 {
michael@0 74 const ssl3BulkCipherDef *cipher_def = pwSpec->cipher_def;
michael@0 75 unsigned char * key_block = pwSpec->key_block;
michael@0 76 unsigned char * key_block2 = NULL;
michael@0 77 unsigned int block_bytes = 0;
michael@0 78 unsigned int block_needed = 0;
michael@0 79 unsigned int i;
michael@0 80 unsigned int keySize; /* actual size of cipher keys */
michael@0 81 unsigned int effKeySize; /* effective size of cipher keys */
michael@0 82 unsigned int macSize; /* size of MAC secret */
michael@0 83 unsigned int IVSize; /* size of IV */
michael@0 84 PRBool explicitIV = PR_FALSE;
michael@0 85 SECStatus rv = SECFailure;
michael@0 86 SECStatus status = SECSuccess;
michael@0 87 PRBool isFIPS = PR_FALSE;
michael@0 88 PRBool isTLS12 = pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2;
michael@0 89
michael@0 90 SECItem srcr;
michael@0 91 SECItem crsr;
michael@0 92
michael@0 93 unsigned char srcrdata[SSL3_RANDOM_LENGTH * 2];
michael@0 94 unsigned char crsrdata[SSL3_RANDOM_LENGTH * 2];
michael@0 95 PRUint64 md5buf[22];
michael@0 96 PRUint64 shabuf[40];
michael@0 97
michael@0 98 #define md5Ctx ((MD5Context *)md5buf)
michael@0 99 #define shaCtx ((SHA1Context *)shabuf)
michael@0 100
michael@0 101 static const SECItem zed = { siBuffer, NULL, 0 };
michael@0 102
michael@0 103 if (pwSpec->msItem.data == NULL ||
michael@0 104 pwSpec->msItem.len != SSL3_MASTER_SECRET_LENGTH) {
michael@0 105 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 106 return rv;
michael@0 107 }
michael@0 108
michael@0 109 PRINT_BUF(100, (NULL, "Master Secret", pwSpec->msItem.data,
michael@0 110 pwSpec->msItem.len));
michael@0 111
michael@0 112 /* figure out how much is needed */
michael@0 113 macSize = pwSpec->mac_size;
michael@0 114 keySize = cipher_def->key_size;
michael@0 115 effKeySize = cipher_def->secret_key_size;
michael@0 116 IVSize = cipher_def->iv_size;
michael@0 117 if (keySize == 0) {
michael@0 118 effKeySize = IVSize = 0; /* only MACing */
michael@0 119 }
michael@0 120 if (cipher_def->type == type_block &&
michael@0 121 pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_1) {
michael@0 122 /* Block ciphers in >= TLS 1.1 use a per-record, explicit IV. */
michael@0 123 explicitIV = PR_TRUE;
michael@0 124 }
michael@0 125 block_needed =
michael@0 126 2 * (macSize + effKeySize + ((!isExport && !explicitIV) * IVSize));
michael@0 127
michael@0 128 /*
michael@0 129 * clear out our returned keys so we can recover on failure
michael@0 130 */
michael@0 131 pwSpec->client.write_key_item = zed;
michael@0 132 pwSpec->client.write_mac_key_item = zed;
michael@0 133 pwSpec->server.write_key_item = zed;
michael@0 134 pwSpec->server.write_mac_key_item = zed;
michael@0 135
michael@0 136 /* initialize the server random, client random block */
michael@0 137 srcr.type = siBuffer;
michael@0 138 srcr.data = srcrdata;
michael@0 139 srcr.len = sizeof srcrdata;
michael@0 140 PORT_Memcpy(srcrdata, sr, SSL3_RANDOM_LENGTH);
michael@0 141 PORT_Memcpy(srcrdata + SSL3_RANDOM_LENGTH, cr, SSL3_RANDOM_LENGTH);
michael@0 142
michael@0 143 /* initialize the client random, server random block */
michael@0 144 crsr.type = siBuffer;
michael@0 145 crsr.data = crsrdata;
michael@0 146 crsr.len = sizeof crsrdata;
michael@0 147 PORT_Memcpy(crsrdata, cr, SSL3_RANDOM_LENGTH);
michael@0 148 PORT_Memcpy(crsrdata + SSL3_RANDOM_LENGTH, sr, SSL3_RANDOM_LENGTH);
michael@0 149 PRINT_BUF(100, (NULL, "Key & MAC CRSR", crsr.data, crsr.len));
michael@0 150
michael@0 151 /*
michael@0 152 * generate the key material:
michael@0 153 */
michael@0 154 if (isTLS) {
michael@0 155 SECItem keyblk;
michael@0 156
michael@0 157 keyblk.type = siBuffer;
michael@0 158 keyblk.data = key_block;
michael@0 159 keyblk.len = block_needed;
michael@0 160
michael@0 161 if (isTLS12) {
michael@0 162 status = TLS_P_hash(HASH_AlgSHA256, &pwSpec->msItem,
michael@0 163 "key expansion", &srcr, &keyblk, isFIPS);
michael@0 164 } else {
michael@0 165 status = TLS_PRF(&pwSpec->msItem, "key expansion", &srcr, &keyblk,
michael@0 166 isFIPS);
michael@0 167 }
michael@0 168 if (status != SECSuccess) {
michael@0 169 goto key_and_mac_derive_fail;
michael@0 170 }
michael@0 171 block_bytes = keyblk.len;
michael@0 172 } else {
michael@0 173 /* key_block =
michael@0 174 * MD5(master_secret + SHA('A' + master_secret +
michael@0 175 * ServerHello.random + ClientHello.random)) +
michael@0 176 * MD5(master_secret + SHA('BB' + master_secret +
michael@0 177 * ServerHello.random + ClientHello.random)) +
michael@0 178 * MD5(master_secret + SHA('CCC' + master_secret +
michael@0 179 * ServerHello.random + ClientHello.random)) +
michael@0 180 * [...];
michael@0 181 */
michael@0 182 unsigned int made = 0;
michael@0 183 for (i = 0; made < block_needed && i < NUM_MIXERS; ++i) {
michael@0 184 unsigned int outLen;
michael@0 185 unsigned char sha_out[SHA1_LENGTH];
michael@0 186
michael@0 187 SHA1_Begin(shaCtx);
michael@0 188 SHA1_Update(shaCtx, (unsigned char*)(mixers[i]), i+1);
michael@0 189 SHA1_Update(shaCtx, pwSpec->msItem.data, pwSpec->msItem.len);
michael@0 190 SHA1_Update(shaCtx, srcr.data, srcr.len);
michael@0 191 SHA1_End(shaCtx, sha_out, &outLen, SHA1_LENGTH);
michael@0 192 PORT_Assert(outLen == SHA1_LENGTH);
michael@0 193
michael@0 194 MD5_Begin(md5Ctx);
michael@0 195 MD5_Update(md5Ctx, pwSpec->msItem.data, pwSpec->msItem.len);
michael@0 196 MD5_Update(md5Ctx, sha_out, outLen);
michael@0 197 MD5_End(md5Ctx, key_block + made, &outLen, MD5_LENGTH);
michael@0 198 PORT_Assert(outLen == MD5_LENGTH);
michael@0 199 made += MD5_LENGTH;
michael@0 200 }
michael@0 201 block_bytes = made;
michael@0 202 }
michael@0 203 PORT_Assert(block_bytes >= block_needed);
michael@0 204 PORT_Assert(block_bytes <= sizeof pwSpec->key_block);
michael@0 205 PRINT_BUF(100, (NULL, "key block", key_block, block_bytes));
michael@0 206
michael@0 207 /*
michael@0 208 * Put the key material where it goes.
michael@0 209 */
michael@0 210 key_block2 = key_block + block_bytes;
michael@0 211 i = 0; /* now shows how much consumed */
michael@0 212
michael@0 213 /*
michael@0 214 * The key_block is partitioned as follows:
michael@0 215 * client_write_MAC_secret[CipherSpec.hash_size]
michael@0 216 */
michael@0 217 buildSSLKey(&key_block[i],macSize, &pwSpec->client.write_mac_key_item, \
michael@0 218 "Client Write MAC Secret");
michael@0 219 i += macSize;
michael@0 220
michael@0 221 /*
michael@0 222 * server_write_MAC_secret[CipherSpec.hash_size]
michael@0 223 */
michael@0 224 buildSSLKey(&key_block[i],macSize, &pwSpec->server.write_mac_key_item, \
michael@0 225 "Server Write MAC Secret");
michael@0 226 i += macSize;
michael@0 227
michael@0 228 if (!keySize) {
michael@0 229 /* only MACing */
michael@0 230 buildSSLKey(NULL, 0, &pwSpec->client.write_key_item, \
michael@0 231 "Client Write Key (MAC only)");
michael@0 232 buildSSLKey(NULL, 0, &pwSpec->server.write_key_item, \
michael@0 233 "Server Write Key (MAC only)");
michael@0 234 buildSSLKey(NULL, 0, &pwSpec->client.write_iv_item, \
michael@0 235 "Client Write IV (MAC only)");
michael@0 236 buildSSLKey(NULL, 0, &pwSpec->server.write_iv_item, \
michael@0 237 "Server Write IV (MAC only)");
michael@0 238 } else if (!isExport) {
michael@0 239 /*
michael@0 240 ** Generate Domestic write keys and IVs.
michael@0 241 ** client_write_key[CipherSpec.key_material]
michael@0 242 */
michael@0 243 buildSSLKey(&key_block[i], keySize, &pwSpec->client.write_key_item, \
michael@0 244 "Domestic Client Write Key");
michael@0 245 i += keySize;
michael@0 246
michael@0 247 /*
michael@0 248 ** server_write_key[CipherSpec.key_material]
michael@0 249 */
michael@0 250 buildSSLKey(&key_block[i], keySize, &pwSpec->server.write_key_item, \
michael@0 251 "Domestic Server Write Key");
michael@0 252 i += keySize;
michael@0 253
michael@0 254 if (IVSize > 0) {
michael@0 255 if (explicitIV) {
michael@0 256 static unsigned char zero_block[32];
michael@0 257 PORT_Assert(IVSize <= sizeof zero_block);
michael@0 258 buildSSLKey(&zero_block[0], IVSize, \
michael@0 259 &pwSpec->client.write_iv_item, \
michael@0 260 "Domestic Client Write IV");
michael@0 261 buildSSLKey(&zero_block[0], IVSize, \
michael@0 262 &pwSpec->server.write_iv_item, \
michael@0 263 "Domestic Server Write IV");
michael@0 264 } else {
michael@0 265 /*
michael@0 266 ** client_write_IV[CipherSpec.IV_size]
michael@0 267 */
michael@0 268 buildSSLKey(&key_block[i], IVSize, \
michael@0 269 &pwSpec->client.write_iv_item, \
michael@0 270 "Domestic Client Write IV");
michael@0 271 i += IVSize;
michael@0 272
michael@0 273 /*
michael@0 274 ** server_write_IV[CipherSpec.IV_size]
michael@0 275 */
michael@0 276 buildSSLKey(&key_block[i], IVSize, \
michael@0 277 &pwSpec->server.write_iv_item, \
michael@0 278 "Domestic Server Write IV");
michael@0 279 i += IVSize;
michael@0 280 }
michael@0 281 }
michael@0 282 PORT_Assert(i <= block_bytes);
michael@0 283 } else if (!isTLS) {
michael@0 284 /*
michael@0 285 ** Generate SSL3 Export write keys and IVs.
michael@0 286 */
michael@0 287 unsigned int outLen;
michael@0 288
michael@0 289 /*
michael@0 290 ** client_write_key[CipherSpec.key_material]
michael@0 291 ** final_client_write_key = MD5(client_write_key +
michael@0 292 ** ClientHello.random + ServerHello.random);
michael@0 293 */
michael@0 294 MD5_Begin(md5Ctx);
michael@0 295 MD5_Update(md5Ctx, &key_block[i], effKeySize);
michael@0 296 MD5_Update(md5Ctx, crsr.data, crsr.len);
michael@0 297 MD5_End(md5Ctx, key_block2, &outLen, MD5_LENGTH);
michael@0 298 i += effKeySize;
michael@0 299 buildSSLKey(key_block2, keySize, &pwSpec->client.write_key_item, \
michael@0 300 "SSL3 Export Client Write Key");
michael@0 301 key_block2 += keySize;
michael@0 302
michael@0 303 /*
michael@0 304 ** server_write_key[CipherSpec.key_material]
michael@0 305 ** final_server_write_key = MD5(server_write_key +
michael@0 306 ** ServerHello.random + ClientHello.random);
michael@0 307 */
michael@0 308 MD5_Begin(md5Ctx);
michael@0 309 MD5_Update(md5Ctx, &key_block[i], effKeySize);
michael@0 310 MD5_Update(md5Ctx, srcr.data, srcr.len);
michael@0 311 MD5_End(md5Ctx, key_block2, &outLen, MD5_LENGTH);
michael@0 312 i += effKeySize;
michael@0 313 buildSSLKey(key_block2, keySize, &pwSpec->server.write_key_item, \
michael@0 314 "SSL3 Export Server Write Key");
michael@0 315 key_block2 += keySize;
michael@0 316 PORT_Assert(i <= block_bytes);
michael@0 317
michael@0 318 if (IVSize) {
michael@0 319 /*
michael@0 320 ** client_write_IV =
michael@0 321 ** MD5(ClientHello.random + ServerHello.random);
michael@0 322 */
michael@0 323 MD5_Begin(md5Ctx);
michael@0 324 MD5_Update(md5Ctx, crsr.data, crsr.len);
michael@0 325 MD5_End(md5Ctx, key_block2, &outLen, MD5_LENGTH);
michael@0 326 buildSSLKey(key_block2, IVSize, &pwSpec->client.write_iv_item, \
michael@0 327 "SSL3 Export Client Write IV");
michael@0 328 key_block2 += IVSize;
michael@0 329
michael@0 330 /*
michael@0 331 ** server_write_IV =
michael@0 332 ** MD5(ServerHello.random + ClientHello.random);
michael@0 333 */
michael@0 334 MD5_Begin(md5Ctx);
michael@0 335 MD5_Update(md5Ctx, srcr.data, srcr.len);
michael@0 336 MD5_End(md5Ctx, key_block2, &outLen, MD5_LENGTH);
michael@0 337 buildSSLKey(key_block2, IVSize, &pwSpec->server.write_iv_item, \
michael@0 338 "SSL3 Export Server Write IV");
michael@0 339 key_block2 += IVSize;
michael@0 340 }
michael@0 341
michael@0 342 PORT_Assert(key_block2 - key_block <= sizeof pwSpec->key_block);
michael@0 343 } else {
michael@0 344 /*
michael@0 345 ** Generate TLS Export write keys and IVs.
michael@0 346 */
michael@0 347 SECItem secret ;
michael@0 348 SECItem keyblk ;
michael@0 349
michael@0 350 secret.type = siBuffer;
michael@0 351 keyblk.type = siBuffer;
michael@0 352 /*
michael@0 353 ** client_write_key[CipherSpec.key_material]
michael@0 354 ** final_client_write_key = PRF(client_write_key,
michael@0 355 ** "client write key",
michael@0 356 ** client_random + server_random);
michael@0 357 */
michael@0 358 secret.data = &key_block[i];
michael@0 359 secret.len = effKeySize;
michael@0 360 i += effKeySize;
michael@0 361 keyblk.data = key_block2;
michael@0 362 keyblk.len = keySize;
michael@0 363 status = TLS_PRF(&secret, "client write key", &crsr, &keyblk, isFIPS);
michael@0 364 if (status != SECSuccess) {
michael@0 365 goto key_and_mac_derive_fail;
michael@0 366 }
michael@0 367 buildSSLKey(key_block2, keySize, &pwSpec->client.write_key_item, \
michael@0 368 "TLS Export Client Write Key");
michael@0 369 key_block2 += keySize;
michael@0 370
michael@0 371 /*
michael@0 372 ** server_write_key[CipherSpec.key_material]
michael@0 373 ** final_server_write_key = PRF(server_write_key,
michael@0 374 ** "server write key",
michael@0 375 ** client_random + server_random);
michael@0 376 */
michael@0 377 secret.data = &key_block[i];
michael@0 378 secret.len = effKeySize;
michael@0 379 i += effKeySize;
michael@0 380 keyblk.data = key_block2;
michael@0 381 keyblk.len = keySize;
michael@0 382 status = TLS_PRF(&secret, "server write key", &crsr, &keyblk, isFIPS);
michael@0 383 if (status != SECSuccess) {
michael@0 384 goto key_and_mac_derive_fail;
michael@0 385 }
michael@0 386 buildSSLKey(key_block2, keySize, &pwSpec->server.write_key_item, \
michael@0 387 "TLS Export Server Write Key");
michael@0 388 key_block2 += keySize;
michael@0 389
michael@0 390 /*
michael@0 391 ** iv_block = PRF("", "IV block", client_random + server_random);
michael@0 392 ** client_write_IV[SecurityParameters.IV_size]
michael@0 393 ** server_write_IV[SecurityParameters.IV_size]
michael@0 394 */
michael@0 395 if (IVSize) {
michael@0 396 secret.data = NULL;
michael@0 397 secret.len = 0;
michael@0 398 keyblk.data = key_block2;
michael@0 399 keyblk.len = 2 * IVSize;
michael@0 400 status = TLS_PRF(&secret, "IV block", &crsr, &keyblk, isFIPS);
michael@0 401 if (status != SECSuccess) {
michael@0 402 goto key_and_mac_derive_fail;
michael@0 403 }
michael@0 404 buildSSLKey(key_block2, IVSize, \
michael@0 405 &pwSpec->client.write_iv_item, \
michael@0 406 "TLS Export Client Write IV");
michael@0 407 buildSSLKey(key_block2 + IVSize, IVSize, \
michael@0 408 &pwSpec->server.write_iv_item, \
michael@0 409 "TLS Export Server Write IV");
michael@0 410 key_block2 += 2 * IVSize;
michael@0 411 }
michael@0 412 PORT_Assert(key_block2 - key_block <= sizeof pwSpec->key_block);
michael@0 413 }
michael@0 414 rv = SECSuccess;
michael@0 415
michael@0 416 key_and_mac_derive_fail:
michael@0 417
michael@0 418 MD5_DestroyContext(md5Ctx, PR_FALSE);
michael@0 419 SHA1_DestroyContext(shaCtx, PR_FALSE);
michael@0 420
michael@0 421 if (rv != SECSuccess) {
michael@0 422 PORT_SetError(SSL_ERROR_SESSION_KEY_GEN_FAILURE);
michael@0 423 }
michael@0 424
michael@0 425 return rv;
michael@0 426 }
michael@0 427
michael@0 428
michael@0 429 /* derive the Master Secret from the PMS */
michael@0 430 /* Presently, this is only done wtih RSA PMS, and only on the server side,
michael@0 431 * so isRSA is always true.
michael@0 432 */
michael@0 433 SECStatus
michael@0 434 ssl3_MasterKeyDeriveBypass(
michael@0 435 ssl3CipherSpec * pwSpec,
michael@0 436 const unsigned char * cr,
michael@0 437 const unsigned char * sr,
michael@0 438 const SECItem * pms,
michael@0 439 PRBool isTLS,
michael@0 440 PRBool isRSA)
michael@0 441 {
michael@0 442 unsigned char * key_block = pwSpec->key_block;
michael@0 443 SECStatus rv = SECSuccess;
michael@0 444 PRBool isFIPS = PR_FALSE;
michael@0 445 PRBool isTLS12 = pwSpec->version >= SSL_LIBRARY_VERSION_TLS_1_2;
michael@0 446
michael@0 447 SECItem crsr;
michael@0 448
michael@0 449 unsigned char crsrdata[SSL3_RANDOM_LENGTH * 2];
michael@0 450 PRUint64 md5buf[22];
michael@0 451 PRUint64 shabuf[40];
michael@0 452
michael@0 453 #define md5Ctx ((MD5Context *)md5buf)
michael@0 454 #define shaCtx ((SHA1Context *)shabuf)
michael@0 455
michael@0 456 /* first do the consistancy checks */
michael@0 457 if (isRSA) {
michael@0 458 PORT_Assert(pms->len == SSL3_RSA_PMS_LENGTH);
michael@0 459 if (pms->len != SSL3_RSA_PMS_LENGTH) {
michael@0 460 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 461 return SECFailure;
michael@0 462 }
michael@0 463 /* caller must test PMS version for rollback */
michael@0 464 }
michael@0 465
michael@0 466 /* initialize the client random, server random block */
michael@0 467 crsr.type = siBuffer;
michael@0 468 crsr.data = crsrdata;
michael@0 469 crsr.len = sizeof crsrdata;
michael@0 470 PORT_Memcpy(crsrdata, cr, SSL3_RANDOM_LENGTH);
michael@0 471 PORT_Memcpy(crsrdata + SSL3_RANDOM_LENGTH, sr, SSL3_RANDOM_LENGTH);
michael@0 472 PRINT_BUF(100, (NULL, "Master Secret CRSR", crsr.data, crsr.len));
michael@0 473
michael@0 474 /* finally do the key gen */
michael@0 475 if (isTLS) {
michael@0 476 SECItem master = { siBuffer, NULL, 0 };
michael@0 477
michael@0 478 master.data = key_block;
michael@0 479 master.len = SSL3_MASTER_SECRET_LENGTH;
michael@0 480
michael@0 481 if (isTLS12) {
michael@0 482 rv = TLS_P_hash(HASH_AlgSHA256, pms, "master secret", &crsr,
michael@0 483 &master, isFIPS);
michael@0 484 } else {
michael@0 485 rv = TLS_PRF(pms, "master secret", &crsr, &master, isFIPS);
michael@0 486 }
michael@0 487 if (rv != SECSuccess) {
michael@0 488 PORT_SetError(SSL_ERROR_SESSION_KEY_GEN_FAILURE);
michael@0 489 }
michael@0 490 } else {
michael@0 491 int i;
michael@0 492 unsigned int made = 0;
michael@0 493 for (i = 0; i < 3; i++) {
michael@0 494 unsigned int outLen;
michael@0 495 unsigned char sha_out[SHA1_LENGTH];
michael@0 496
michael@0 497 SHA1_Begin(shaCtx);
michael@0 498 SHA1_Update(shaCtx, (unsigned char*) mixers[i], i+1);
michael@0 499 SHA1_Update(shaCtx, pms->data, pms->len);
michael@0 500 SHA1_Update(shaCtx, crsr.data, crsr.len);
michael@0 501 SHA1_End(shaCtx, sha_out, &outLen, SHA1_LENGTH);
michael@0 502 PORT_Assert(outLen == SHA1_LENGTH);
michael@0 503
michael@0 504 MD5_Begin(md5Ctx);
michael@0 505 MD5_Update(md5Ctx, pms->data, pms->len);
michael@0 506 MD5_Update(md5Ctx, sha_out, outLen);
michael@0 507 MD5_End(md5Ctx, key_block + made, &outLen, MD5_LENGTH);
michael@0 508 PORT_Assert(outLen == MD5_LENGTH);
michael@0 509 made += outLen;
michael@0 510 }
michael@0 511 }
michael@0 512
michael@0 513 /* store the results */
michael@0 514 PORT_Memcpy(pwSpec->raw_master_secret, key_block,
michael@0 515 SSL3_MASTER_SECRET_LENGTH);
michael@0 516 pwSpec->msItem.data = pwSpec->raw_master_secret;
michael@0 517 pwSpec->msItem.len = SSL3_MASTER_SECRET_LENGTH;
michael@0 518 PRINT_BUF(100, (NULL, "Master Secret", pwSpec->msItem.data,
michael@0 519 pwSpec->msItem.len));
michael@0 520
michael@0 521 return rv;
michael@0 522 }
michael@0 523
michael@0 524 static SECStatus
michael@0 525 ssl_canExtractMS(PK11SymKey *pms, PRBool isTLS, PRBool isDH, PRBool *pcbp)
michael@0 526 { SECStatus rv;
michael@0 527 PK11SymKey * ms = NULL;
michael@0 528 SECItem params = {siBuffer, NULL, 0};
michael@0 529 CK_SSL3_MASTER_KEY_DERIVE_PARAMS master_params;
michael@0 530 unsigned char rand[SSL3_RANDOM_LENGTH];
michael@0 531 CK_VERSION pms_version;
michael@0 532 CK_MECHANISM_TYPE master_derive;
michael@0 533 CK_MECHANISM_TYPE key_derive;
michael@0 534 CK_FLAGS keyFlags;
michael@0 535
michael@0 536 if (pms == NULL)
michael@0 537 return(SECFailure);
michael@0 538
michael@0 539 PORT_Memset(rand, 0, SSL3_RANDOM_LENGTH);
michael@0 540
michael@0 541 if (isTLS) {
michael@0 542 if(isDH) master_derive = CKM_TLS_MASTER_KEY_DERIVE_DH;
michael@0 543 else master_derive = CKM_TLS_MASTER_KEY_DERIVE;
michael@0 544 key_derive = CKM_TLS_KEY_AND_MAC_DERIVE;
michael@0 545 keyFlags = CKF_SIGN | CKF_VERIFY;
michael@0 546 } else {
michael@0 547 if (isDH) master_derive = CKM_SSL3_MASTER_KEY_DERIVE_DH;
michael@0 548 else master_derive = CKM_SSL3_MASTER_KEY_DERIVE;
michael@0 549 key_derive = CKM_SSL3_KEY_AND_MAC_DERIVE;
michael@0 550 keyFlags = 0;
michael@0 551 }
michael@0 552
michael@0 553 master_params.pVersion = &pms_version;
michael@0 554 master_params.RandomInfo.pClientRandom = rand;
michael@0 555 master_params.RandomInfo.ulClientRandomLen = SSL3_RANDOM_LENGTH;
michael@0 556 master_params.RandomInfo.pServerRandom = rand;
michael@0 557 master_params.RandomInfo.ulServerRandomLen = SSL3_RANDOM_LENGTH;
michael@0 558
michael@0 559 params.data = (unsigned char *) &master_params;
michael@0 560 params.len = sizeof master_params;
michael@0 561
michael@0 562 ms = PK11_DeriveWithFlags(pms, master_derive, &params, key_derive,
michael@0 563 CKA_DERIVE, 0, keyFlags);
michael@0 564 if (ms == NULL)
michael@0 565 return(SECFailure);
michael@0 566
michael@0 567 rv = PK11_ExtractKeyValue(ms);
michael@0 568 *pcbp = (rv == SECSuccess);
michael@0 569 PK11_FreeSymKey(ms);
michael@0 570
michael@0 571 return(rv);
michael@0 572
michael@0 573 }
michael@0 574 #endif /* !NO_PKCS11_BYPASS */
michael@0 575
michael@0 576 /* Check the key exchange algorithm for each cipher in the list to see if
michael@0 577 * a master secret key can be extracted. If the KEA will use keys from the
michael@0 578 * specified cert make sure the extract operation is attempted from the slot
michael@0 579 * where the private key resides.
michael@0 580 * If MS can be extracted for all ciphers, (*pcanbypass) is set to TRUE and
michael@0 581 * SECSuccess is returned. In all other cases but one (*pcanbypass) is
michael@0 582 * set to FALSE and SECFailure is returned.
michael@0 583 * In that last case Derive() has been called successfully but the MS is null,
michael@0 584 * CanBypass sets (*pcanbypass) to FALSE and returns SECSuccess indicating the
michael@0 585 * arguments were all valid but the slot cannot be bypassed.
michael@0 586 */
michael@0 587
michael@0 588 /* XXX Add SSL_CBP_TLS1_1 and test it in protocolmask when setting isTLS. */
michael@0 589
michael@0 590 SECStatus
michael@0 591 SSL_CanBypass(CERTCertificate *cert, SECKEYPrivateKey *srvPrivkey,
michael@0 592 PRUint32 protocolmask, PRUint16 *ciphersuites, int nsuites,
michael@0 593 PRBool *pcanbypass, void *pwArg)
michael@0 594 {
michael@0 595 #ifdef NO_PKCS11_BYPASS
michael@0 596 if (!pcanbypass) {
michael@0 597 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 598 return SECFailure;
michael@0 599 }
michael@0 600 *pcanbypass = PR_FALSE;
michael@0 601 return SECSuccess;
michael@0 602 #else
michael@0 603 SECStatus rv;
michael@0 604 int i;
michael@0 605 PRUint16 suite;
michael@0 606 PK11SymKey * pms = NULL;
michael@0 607 SECKEYPublicKey * srvPubkey = NULL;
michael@0 608 KeyType privKeytype;
michael@0 609 PK11SlotInfo * slot = NULL;
michael@0 610 SECItem param;
michael@0 611 CK_VERSION version;
michael@0 612 CK_MECHANISM_TYPE mechanism_array[2];
michael@0 613 SECItem enc_pms = {siBuffer, NULL, 0};
michael@0 614 PRBool isTLS = PR_FALSE;
michael@0 615 SSLCipherSuiteInfo csdef;
michael@0 616 PRBool testrsa = PR_FALSE;
michael@0 617 PRBool testrsa_export = PR_FALSE;
michael@0 618 PRBool testecdh = PR_FALSE;
michael@0 619 PRBool testecdhe = PR_FALSE;
michael@0 620 #ifndef NSS_DISABLE_ECC
michael@0 621 SECKEYECParams ecParams = { siBuffer, NULL, 0 };
michael@0 622 #endif
michael@0 623
michael@0 624 if (!cert || !srvPrivkey || !ciphersuites || !pcanbypass) {
michael@0 625 PORT_SetError(SEC_ERROR_INVALID_ARGS);
michael@0 626 return SECFailure;
michael@0 627 }
michael@0 628
michael@0 629 srvPubkey = CERT_ExtractPublicKey(cert);
michael@0 630 if (!srvPubkey)
michael@0 631 return SECFailure;
michael@0 632
michael@0 633 *pcanbypass = PR_TRUE;
michael@0 634 rv = SECFailure;
michael@0 635
michael@0 636 /* determine which KEAs to test */
michael@0 637 /* 0 (TLS_NULL_WITH_NULL_NULL) is used as a list terminator because
michael@0 638 * SSL3 and TLS specs forbid negotiating that cipher suite number.
michael@0 639 */
michael@0 640 for (i=0; i < nsuites && (suite = *ciphersuites++) != 0; i++) {
michael@0 641 /* skip SSL2 cipher suites and ones NSS doesn't support */
michael@0 642 if (SSL_GetCipherSuiteInfo(suite, &csdef, sizeof(csdef)) != SECSuccess
michael@0 643 || SSL_IS_SSL2_CIPHER(suite) )
michael@0 644 continue;
michael@0 645 switch (csdef.keaType) {
michael@0 646 case ssl_kea_rsa:
michael@0 647 switch (csdef.cipherSuite) {
michael@0 648 case TLS_RSA_EXPORT1024_WITH_RC4_56_SHA:
michael@0 649 case TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA:
michael@0 650 case TLS_RSA_EXPORT_WITH_RC4_40_MD5:
michael@0 651 case TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5:
michael@0 652 testrsa_export = PR_TRUE;
michael@0 653 }
michael@0 654 if (!testrsa_export)
michael@0 655 testrsa = PR_TRUE;
michael@0 656 break;
michael@0 657 case ssl_kea_ecdh:
michael@0 658 if (strcmp(csdef.keaTypeName, "ECDHE") == 0) /* ephemeral? */
michael@0 659 testecdhe = PR_TRUE;
michael@0 660 else
michael@0 661 testecdh = PR_TRUE;
michael@0 662 break;
michael@0 663 case ssl_kea_dh:
michael@0 664 /* this is actually DHE */
michael@0 665 default:
michael@0 666 continue;
michael@0 667 }
michael@0 668 }
michael@0 669
michael@0 670 /* For each protocol try to derive and extract an MS.
michael@0 671 * Failure of function any function except MS extract means
michael@0 672 * continue with the next cipher test. Stop testing when the list is
michael@0 673 * exhausted or when the first MS extract--not derive--fails.
michael@0 674 */
michael@0 675 privKeytype = SECKEY_GetPrivateKeyType(srvPrivkey);
michael@0 676 protocolmask &= SSL_CBP_SSL3|SSL_CBP_TLS1_0;
michael@0 677 while (protocolmask) {
michael@0 678 if (protocolmask & SSL_CBP_SSL3) {
michael@0 679 isTLS = PR_FALSE;
michael@0 680 protocolmask ^= SSL_CBP_SSL3;
michael@0 681 } else {
michael@0 682 isTLS = PR_TRUE;
michael@0 683 protocolmask ^= SSL_CBP_TLS1_0;
michael@0 684 }
michael@0 685
michael@0 686 if (privKeytype == rsaKey && testrsa_export) {
michael@0 687 if (PK11_GetPrivateModulusLen(srvPrivkey) > EXPORT_RSA_KEY_LENGTH) {
michael@0 688 *pcanbypass = PR_FALSE;
michael@0 689 rv = SECSuccess;
michael@0 690 break;
michael@0 691 } else
michael@0 692 testrsa = PR_TRUE;
michael@0 693 }
michael@0 694 for (; privKeytype == rsaKey && testrsa; ) {
michael@0 695 /* TLS_RSA */
michael@0 696 unsigned char rsaPmsBuf[SSL3_RSA_PMS_LENGTH];
michael@0 697 unsigned int outLen = 0;
michael@0 698 CK_MECHANISM_TYPE target;
michael@0 699 SECStatus irv;
michael@0 700
michael@0 701 mechanism_array[0] = CKM_SSL3_PRE_MASTER_KEY_GEN;
michael@0 702 mechanism_array[1] = CKM_RSA_PKCS;
michael@0 703
michael@0 704 slot = PK11_GetBestSlotMultiple(mechanism_array, 2, pwArg);
michael@0 705 if (slot == NULL) {
michael@0 706 PORT_SetError(SSL_ERROR_TOKEN_SLOT_NOT_FOUND);
michael@0 707 break;
michael@0 708 }
michael@0 709
michael@0 710 /* Generate the pre-master secret ... (client side) */
michael@0 711 version.major = 3 /*MSB(clientHelloVersion)*/;
michael@0 712 version.minor = 0 /*LSB(clientHelloVersion)*/;
michael@0 713 param.data = (unsigned char *)&version;
michael@0 714 param.len = sizeof version;
michael@0 715 pms = PK11_KeyGen(slot, CKM_SSL3_PRE_MASTER_KEY_GEN, &param, 0, pwArg);
michael@0 716 PK11_FreeSlot(slot);
michael@0 717 if (!pms)
michael@0 718 break;
michael@0 719 /* now wrap it */
michael@0 720 enc_pms.len = SECKEY_PublicKeyStrength(srvPubkey);
michael@0 721 enc_pms.data = (unsigned char*)PORT_Alloc(enc_pms.len);
michael@0 722 if (enc_pms.data == NULL) {
michael@0 723 PORT_SetError(PR_OUT_OF_MEMORY_ERROR);
michael@0 724 break;
michael@0 725 }
michael@0 726 irv = PK11_PubWrapSymKey(CKM_RSA_PKCS, srvPubkey, pms, &enc_pms);
michael@0 727 if (irv != SECSuccess)
michael@0 728 break;
michael@0 729 PK11_FreeSymKey(pms);
michael@0 730 pms = NULL;
michael@0 731 /* now do the server side--check the triple bypass first */
michael@0 732 rv = PK11_PrivDecryptPKCS1(srvPrivkey, rsaPmsBuf, &outLen,
michael@0 733 sizeof rsaPmsBuf,
michael@0 734 (unsigned char *)enc_pms.data,
michael@0 735 enc_pms.len);
michael@0 736 /* if decrypt worked we're done with the RSA test */
michael@0 737 if (rv == SECSuccess) {
michael@0 738 *pcanbypass = PR_TRUE;
michael@0 739 break;
michael@0 740 }
michael@0 741 /* check for fallback to double bypass */
michael@0 742 target = isTLS ? CKM_TLS_MASTER_KEY_DERIVE
michael@0 743 : CKM_SSL3_MASTER_KEY_DERIVE;
michael@0 744 pms = PK11_PubUnwrapSymKey(srvPrivkey, &enc_pms,
michael@0 745 target, CKA_DERIVE, 0);
michael@0 746 rv = ssl_canExtractMS(pms, isTLS, PR_FALSE, pcanbypass);
michael@0 747 if (rv == SECSuccess && *pcanbypass == PR_FALSE)
michael@0 748 goto done;
michael@0 749 break;
michael@0 750 }
michael@0 751
michael@0 752 /* Check for NULL to avoid double free.
michael@0 753 * SECItem_FreeItem sets data NULL in secitem.c#265
michael@0 754 */
michael@0 755 if (enc_pms.data != NULL) {
michael@0 756 SECITEM_FreeItem(&enc_pms, PR_FALSE);
michael@0 757 }
michael@0 758 #ifndef NSS_DISABLE_ECC
michael@0 759 for (; (privKeytype == ecKey && ( testecdh || testecdhe)) ||
michael@0 760 (privKeytype == rsaKey && testecdhe); ) {
michael@0 761 CK_MECHANISM_TYPE target;
michael@0 762 SECKEYPublicKey *keapub = NULL;
michael@0 763 SECKEYPrivateKey *keapriv;
michael@0 764 SECKEYPublicKey *cpub = NULL; /* client's ephemeral ECDH keys */
michael@0 765 SECKEYPrivateKey *cpriv = NULL;
michael@0 766 SECKEYECParams *pecParams = NULL;
michael@0 767
michael@0 768 if (privKeytype == ecKey && testecdhe) {
michael@0 769 /* TLS_ECDHE_ECDSA */
michael@0 770 pecParams = &srvPubkey->u.ec.DEREncodedParams;
michael@0 771 } else if (privKeytype == rsaKey && testecdhe) {
michael@0 772 /* TLS_ECDHE_RSA */
michael@0 773 ECName ec_curve;
michael@0 774 int serverKeyStrengthInBits;
michael@0 775 int signatureKeyStrength;
michael@0 776 int requiredECCbits;
michael@0 777
michael@0 778 /* find a curve of equivalent strength to the RSA key's */
michael@0 779 requiredECCbits = PK11_GetPrivateModulusLen(srvPrivkey);
michael@0 780 if (requiredECCbits < 0)
michael@0 781 break;
michael@0 782 requiredECCbits *= BPB;
michael@0 783 serverKeyStrengthInBits = srvPubkey->u.rsa.modulus.len;
michael@0 784 if (srvPubkey->u.rsa.modulus.data[0] == 0) {
michael@0 785 serverKeyStrengthInBits--;
michael@0 786 }
michael@0 787 /* convert to strength in bits */
michael@0 788 serverKeyStrengthInBits *= BPB;
michael@0 789
michael@0 790 signatureKeyStrength =
michael@0 791 SSL_RSASTRENGTH_TO_ECSTRENGTH(serverKeyStrengthInBits);
michael@0 792
michael@0 793 if ( requiredECCbits > signatureKeyStrength )
michael@0 794 requiredECCbits = signatureKeyStrength;
michael@0 795
michael@0 796 ec_curve =
michael@0 797 ssl3_GetCurveWithECKeyStrength(
michael@0 798 ssl3_GetSupportedECCurveMask(NULL),
michael@0 799 requiredECCbits);
michael@0 800 rv = ssl3_ECName2Params(NULL, ec_curve, &ecParams);
michael@0 801 if (rv == SECFailure) {
michael@0 802 break;
michael@0 803 }
michael@0 804 pecParams = &ecParams;
michael@0 805 }
michael@0 806
michael@0 807 if (testecdhe) {
michael@0 808 /* generate server's ephemeral keys */
michael@0 809 keapriv = SECKEY_CreateECPrivateKey(pecParams, &keapub, NULL);
michael@0 810 if (!keapriv || !keapub) {
michael@0 811 if (keapriv)
michael@0 812 SECKEY_DestroyPrivateKey(keapriv);
michael@0 813 if (keapub)
michael@0 814 SECKEY_DestroyPublicKey(keapub);
michael@0 815 PORT_SetError(SEC_ERROR_KEYGEN_FAIL);
michael@0 816 rv = SECFailure;
michael@0 817 break;
michael@0 818 }
michael@0 819 } else {
michael@0 820 /* TLS_ECDH_ECDSA */
michael@0 821 keapub = srvPubkey;
michael@0 822 keapriv = srvPrivkey;
michael@0 823 pecParams = &srvPubkey->u.ec.DEREncodedParams;
michael@0 824 }
michael@0 825
michael@0 826 /* perform client side ops */
michael@0 827 /* generate a pair of ephemeral keys using server's parms */
michael@0 828 cpriv = SECKEY_CreateECPrivateKey(pecParams, &cpub, NULL);
michael@0 829 if (!cpriv || !cpub) {
michael@0 830 if (testecdhe) {
michael@0 831 SECKEY_DestroyPrivateKey(keapriv);
michael@0 832 SECKEY_DestroyPublicKey(keapub);
michael@0 833 }
michael@0 834 PORT_SetError(SEC_ERROR_KEYGEN_FAIL);
michael@0 835 rv = SECFailure;
michael@0 836 break;
michael@0 837 }
michael@0 838 /* now do the server side */
michael@0 839 /* determine the PMS using client's public value */
michael@0 840 target = isTLS ? CKM_TLS_MASTER_KEY_DERIVE_DH
michael@0 841 : CKM_SSL3_MASTER_KEY_DERIVE_DH;
michael@0 842 pms = PK11_PubDeriveWithKDF(keapriv, cpub, PR_FALSE, NULL, NULL,
michael@0 843 CKM_ECDH1_DERIVE,
michael@0 844 target,
michael@0 845 CKA_DERIVE, 0, CKD_NULL, NULL, NULL);
michael@0 846 rv = ssl_canExtractMS(pms, isTLS, PR_TRUE, pcanbypass);
michael@0 847 SECKEY_DestroyPrivateKey(cpriv);
michael@0 848 SECKEY_DestroyPublicKey(cpub);
michael@0 849 if (testecdhe) {
michael@0 850 SECKEY_DestroyPrivateKey(keapriv);
michael@0 851 SECKEY_DestroyPublicKey(keapub);
michael@0 852 }
michael@0 853 if (rv == SECSuccess && *pcanbypass == PR_FALSE)
michael@0 854 goto done;
michael@0 855 break;
michael@0 856 }
michael@0 857 /* Check for NULL to avoid double free. */
michael@0 858 if (ecParams.data != NULL) {
michael@0 859 PORT_Free(ecParams.data);
michael@0 860 ecParams.data = NULL;
michael@0 861 }
michael@0 862 #endif /* NSS_DISABLE_ECC */
michael@0 863 if (pms)
michael@0 864 PK11_FreeSymKey(pms);
michael@0 865 }
michael@0 866
michael@0 867 /* *pcanbypass has been set */
michael@0 868 rv = SECSuccess;
michael@0 869
michael@0 870 done:
michael@0 871 if (pms)
michael@0 872 PK11_FreeSymKey(pms);
michael@0 873
michael@0 874 /* Check for NULL to avoid double free.
michael@0 875 * SECItem_FreeItem sets data NULL in secitem.c#265
michael@0 876 */
michael@0 877 if (enc_pms.data != NULL) {
michael@0 878 SECITEM_FreeItem(&enc_pms, PR_FALSE);
michael@0 879 }
michael@0 880 #ifndef NSS_DISABLE_ECC
michael@0 881 if (ecParams.data != NULL) {
michael@0 882 PORT_Free(ecParams.data);
michael@0 883 ecParams.data = NULL;
michael@0 884 }
michael@0 885 #endif /* NSS_DISABLE_ECC */
michael@0 886
michael@0 887 if (srvPubkey) {
michael@0 888 SECKEY_DestroyPublicKey(srvPubkey);
michael@0 889 srvPubkey = NULL;
michael@0 890 }
michael@0 891
michael@0 892
michael@0 893 return rv;
michael@0 894 #endif /* NO_PKCS11_BYPASS */
michael@0 895 }
michael@0 896

mercurial