Thu, 22 Jan 2015 13:21:57 +0100
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, ¶ms, 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, ¶m, 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 |