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