1 /* 2 * Platform specific crypto wrappers 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-2000 22 * the Initial Developer. All Rights Reserved. 23 * 24 * Contributor(s): 25 * Ryan Sleevi <ryan.sleevi (at) gmail.com> 26 * 27 * Alternatively, the contents of this file may be used under the terms of 28 * either the GNU General Public License Version 2 or later (the "GPL"), or 29 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), 30 * in which case the provisions of the GPL or the LGPL are applicable instead 31 * of those above. If you wish to allow use of your version of this file only 32 * under the terms of either the GPL or the LGPL, and not to allow others to 33 * use your version of this file under the terms of the MPL, indicate your 34 * decision by deleting the provisions above and replace them with the notice 35 * and other provisions required by the GPL or the LGPL. If you do not delete 36 * the provisions above, a recipient may use your version of this file under 37 * the terms of any one of the MPL, the GPL or the LGPL. 38 * 39 * ***** END LICENSE BLOCK ***** */ 40 /* $Id$ */ 41 #include "certt.h" 42 #include "cryptohi.h" 43 #include "keythi.h" 44 #include "nss.h" 45 #include "secitem.h" 46 #include "ssl.h" 47 #include "sslimpl.h" 48 #include "prerror.h" 49 #include "prinit.h" 50 51 #ifdef NSS_PLATFORM_CLIENT_AUTH 52 #ifdef XP_WIN32 53 #include <NCrypt.h> 54 #endif 55 #endif 56 57 #ifdef NSS_PLATFORM_CLIENT_AUTH 58 CERTCertificateList* 59 hack_NewCertificateListFromCertList(CERTCertList* list) 60 { 61 CERTCertificateList * chain = NULL; 62 PLArenaPool * arena = NULL; 63 CERTCertListNode * node; 64 int len; 65 66 if (CERT_LIST_EMPTY(list)) 67 goto loser; 68 69 arena = PORT_NewArena(4096); 70 if (arena == NULL) 71 goto loser; 72 73 for (len = 0, node = CERT_LIST_HEAD(list); !CERT_LIST_END(node, list); 74 len++, node = CERT_LIST_NEXT(node)) { 75 } 76 77 chain = PORT_ArenaNew(arena, CERTCertificateList); 78 if (chain == NULL) 79 goto loser; 80 81 chain->certs = PORT_ArenaNewArray(arena, SECItem, len); 82 if (!chain->certs) 83 goto loser; 84 chain->len = len; 85 86 for (len = 0, node = CERT_LIST_HEAD(list); !CERT_LIST_END(node, list); 87 len++, node = CERT_LIST_NEXT(node)) { 88 // Check to see if the last cert to be sent is a self-signed cert, 89 // and if so, omit it from the list of certificates. However, if 90 // there is only one cert (len == 0), include the cert, as it means 91 // the EE cert is self-signed. 92 if (len > 0 && (len == chain->len - 1) && node->cert->isRoot) { 93 chain->len = len; 94 break; 95 } 96 SECITEM_CopyItem(arena, &chain->certs[len], &node->cert->derCert); 97 } 98 99 chain->arena = arena; 100 return chain; 101 102 loser: 103 if (arena) { 104 PORT_FreeArena(arena, PR_FALSE); 105 } 106 return NULL; 107 } 108 109 #if defined(XP_WIN32) 110 typedef SECURITY_STATUS (WINAPI *NCryptFreeObjectFunc)(NCRYPT_HANDLE); 111 typedef SECURITY_STATUS (WINAPI *NCryptSignHashFunc)( 112 NCRYPT_KEY_HANDLE /* hKey */, 113 VOID* /* pPaddingInfo */, 114 PBYTE /* pbHashValue */, 115 DWORD /* cbHashValue */, 116 PBYTE /* pbSignature */, 117 DWORD /* cbSignature */, 118 DWORD* /* pcbResult */, 119 DWORD /* dwFlags */); 120 121 static PRCallOnceType cngFunctionsInitOnce; 122 static const PRCallOnceType pristineCallOnce; 123 124 static PRLibrary *ncrypt_library = NULL; 125 static NCryptFreeObjectFunc pNCryptFreeObject = NULL; 126 static NCryptSignHashFunc pNCryptSignHash = NULL; 127 128 static SECStatus 129 ssl_ShutdownCngFunctions(void *appData, void *nssData) 130 { 131 pNCryptSignHash = NULL; 132 pNCryptFreeObject = NULL; 133 if (ncrypt_library) { 134 PR_UnloadLibrary(ncrypt_library); 135 ncrypt_library = NULL; 136 } 137 138 cngFunctionsInitOnce = pristineCallOnce; 139 140 return SECSuccess; 141 } 142 143 static PRStatus 144 ssl_InitCngFunctions(void) 145 { 146 SECStatus rv; 147 148 ncrypt_library = PR_LoadLibrary("ncrypt.dll"); 149 if (ncrypt_library == NULL) 150 goto loser; 151 152 pNCryptFreeObject = (NCryptFreeObjectFunc)PR_FindFunctionSymbol( 153 ncrypt_library, "NCryptFreeObject"); 154 if (pNCryptFreeObject == NULL) 155 goto loser; 156 157 pNCryptSignHash = (NCryptSignHashFunc)PR_FindFunctionSymbol( 158 ncrypt_library, "NCryptSignHash"); 159 if (pNCryptSignHash == NULL) 160 goto loser; 161 162 rv = NSS_RegisterShutdown(ssl_ShutdownCngFunctions, NULL); 163 if (rv != SECSuccess) 164 goto loser; 165 166 return PR_SUCCESS; 167 168 loser: 169 pNCryptSignHash = NULL; 170 pNCryptFreeObject = NULL; 171 if (ncrypt_library) { 172 PR_UnloadLibrary(ncrypt_library); 173 ncrypt_library = NULL; 174 } 175 176 return PR_FAILURE; 177 } 178 179 static SECStatus 180 ssl_InitCng(void) 181 { 182 if (PR_CallOnce(&cngFunctionsInitOnce, ssl_InitCngFunctions) != PR_SUCCESS) 183 return SECFailure; 184 return SECSuccess; 185 } 186 187 void 188 ssl_FreePlatformKey(PlatformKey key) 189 { 190 if (!key) 191 return; 192 193 if (key->dwKeySpec == CERT_NCRYPT_KEY_SPEC) { 194 if (ssl_InitCng() == SECSuccess) { 195 (*pNCryptFreeObject)(key->hNCryptKey); 196 } 197 } else { 198 CryptReleaseContext(key->hCryptProv, 0); 199 } 200 PORT_Free(key); 201 } 202 203 static SECStatus 204 ssl3_CngPlatformSignHashes(SSL3Hashes *hash, PlatformKey key, SECItem *buf, 205 PRBool isTLS, KeyType keyType) 206 { 207 SECStatus rv = SECFailure; 208 SECURITY_STATUS ncrypt_status; 209 PRBool doDerEncode = PR_FALSE; 210 SECItem hashItem; 211 DWORD signatureLen = 0; 212 DWORD dwFlags = 0; 213 VOID *pPaddingInfo = NULL; 214 215 /* Always encode using PKCS#1 block type. */ 216 BCRYPT_PKCS1_PADDING_INFO rsaPaddingInfo; 217 218 if (key->dwKeySpec != CERT_NCRYPT_KEY_SPEC) { 219 PR_SetError(SEC_ERROR_LIBRARY_FAILURE, 0); 220 return SECFailure; 221 } 222 if (ssl_InitCng() != SECSuccess) { 223 PR_SetError(SEC_ERROR_LIBRARY_FAILURE, 0); 224 return SECFailure; 225 } 226 227 switch (keyType) { 228 case rsaKey: 229 switch (hash->hashAlg) { 230 case SEC_OID_UNKNOWN: 231 /* No OID/encoded DigestInfo. */ 232 rsaPaddingInfo.pszAlgId = NULL; 233 break; 234 case SEC_OID_SHA1: 235 rsaPaddingInfo.pszAlgId = BCRYPT_SHA1_ALGORITHM; 236 break; 237 case SEC_OID_SHA256: 238 rsaPaddingInfo.pszAlgId = BCRYPT_SHA256_ALGORITHM; 239 break; 240 case SEC_OID_SHA384: 241 rsaPaddingInfo.pszAlgId = BCRYPT_SHA384_ALGORITHM; 242 break; 243 case SEC_OID_SHA512: 244 rsaPaddingInfo.pszAlgId = BCRYPT_SHA512_ALGORITHM; 245 break; 246 default: 247 PORT_SetError(SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM); 248 return SECFailure; 249 } 250 hashItem.data = hash->u.raw; 251 hashItem.len = hash->len; 252 dwFlags = BCRYPT_PAD_PKCS1; 253 pPaddingInfo = &rsaPaddingInfo; 254 break; 255 case dsaKey: 256 case ecKey: 257 if (keyType == ecKey) { 258 doDerEncode = PR_TRUE; 259 } else { 260 doDerEncode = isTLS; 261 } 262 if (hash->hashAlg == SEC_OID_UNKNOWN) { 263 hashItem.data = hash->u.s.sha; 264 hashItem.len = sizeof(hash->u.s.sha); 265 } else { 266 hashItem.data = hash->u.raw; 267 hashItem.len = hash->len; 268 } 269 break; 270 default: 271 PORT_SetError(SEC_ERROR_INVALID_KEY); 272 goto done; 273 } 274 PRINT_BUF(60, (NULL, "hash(es) to be signed", hashItem.data, hashItem.len)); 275 276 ncrypt_status = (*pNCryptSignHash)(key->hNCryptKey, pPaddingInfo, 277 (PBYTE)hashItem.data, hashItem.len, 278 NULL, 0, &signatureLen, dwFlags); 279 if (FAILED(ncrypt_status) || signatureLen == 0) { 280 PR_SetError(SSL_ERROR_SIGN_HASHES_FAILURE, ncrypt_status); 281 goto done; 282 } 283 284 buf->data = (unsigned char *)PORT_Alloc(signatureLen); 285 if (!buf->data) { 286 goto done; /* error code was set. */ 287 } 288 289 ncrypt_status = (*pNCryptSignHash)(key->hNCryptKey, pPaddingInfo, 290 (PBYTE)hashItem.data, hashItem.len, 291 (PBYTE)buf->data, signatureLen, 292 &signatureLen, dwFlags); 293 if (FAILED(ncrypt_status) || signatureLen == 0) { 294 PR_SetError(SSL_ERROR_SIGN_HASHES_FAILURE, ncrypt_status); 295 goto done; 296 } 297 298 buf->len = signatureLen; 299 300 if (doDerEncode) { 301 SECItem derSig = {siBuffer, NULL, 0}; 302 303 /* This also works for an ECDSA signature */ 304 rv = DSAU_EncodeDerSigWithLen(&derSig, buf, buf->len); 305 if (rv == SECSuccess) { 306 PORT_Free(buf->data); /* discard unencoded signature. */ 307 *buf = derSig; /* give caller encoded signature. */ 308 } else if (derSig.data) { 309 PORT_Free(derSig.data); 310 } 311 } else { 312 rv = SECSuccess; 313 } 314 315 PRINT_BUF(60, (NULL, "signed hashes", buf->data, buf->len)); 316 317 done: 318 if (rv != SECSuccess && buf->data) { 319 PORT_Free(buf->data); 320 buf->data = NULL; 321 buf->len = 0; 322 } 323 324 return rv; 325 } 326 327 static SECStatus 328 ssl3_CAPIPlatformSignHashes(SSL3Hashes *hash, PlatformKey key, SECItem *buf, 329 PRBool isTLS, KeyType keyType) 330 { 331 SECStatus rv = SECFailure; 332 PRBool doDerEncode = PR_FALSE; 333 SECItem hashItem; 334 DWORD argLen = 0; 335 DWORD signatureLen = 0; 336 ALG_ID hashAlg = 0; 337 HCRYPTHASH hHash = 0; 338 DWORD hashLen = 0; 339 unsigned int i = 0; 340 341 buf->data = NULL; 342 343 switch (hash->hashAlg) { 344 case SEC_OID_UNKNOWN: 345 hashAlg = 0; 346 break; 347 case SEC_OID_SHA1: 348 hashAlg = CALG_SHA1; 349 break; 350 case SEC_OID_SHA256: 351 hashAlg = CALG_SHA_256; 352 break; 353 case SEC_OID_SHA384: 354 hashAlg = CALG_SHA_384; 355 break; 356 case SEC_OID_SHA512: 357 hashAlg = CALG_SHA_512; 358 break; 359 default: 360 PORT_SetError(SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM); 361 return SECFailure; 362 } 363 364 switch (keyType) { 365 case rsaKey: 366 if (hashAlg == 0) { 367 hashAlg = CALG_SSL3_SHAMD5; 368 } 369 hashItem.data = hash->u.raw; 370 hashItem.len = hash->len; 371 break; 372 case dsaKey: 373 case ecKey: 374 if (keyType == ecKey) { 375 doDerEncode = PR_TRUE; 376 } else { 377 doDerEncode = isTLS; 378 } 379 if (hashAlg == 0) { 380 hashAlg = CALG_SHA1; 381 hashItem.data = hash->u.s.sha; 382 hashItem.len = sizeof(hash->u.s.sha); 383 } else { 384 hashItem.data = hash->u.raw; 385 hashItem.len = hash->len; 386 } 387 break; 388 default: 389 PORT_SetError(SEC_ERROR_INVALID_KEY); 390 goto done; 391 } 392 PRINT_BUF(60, (NULL, "hash(es) to be signed", hashItem.data, hashItem.len)); 393 394 if (!CryptCreateHash(key->hCryptProv, hashAlg, 0, 0, &hHash)) { 395 PR_SetError(SSL_ERROR_SIGN_HASHES_FAILURE, GetLastError()); 396 goto done; 397 } 398 argLen = sizeof(hashLen); 399 if (!CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE*)&hashLen, &argLen, 0)) { 400 PR_SetError(SSL_ERROR_SIGN_HASHES_FAILURE, GetLastError()); 401 goto done; 402 } 403 if (hashLen != hashItem.len) { 404 PR_SetError(SSL_ERROR_SIGN_HASHES_FAILURE, 0); 405 goto done; 406 } 407 if (!CryptSetHashParam(hHash, HP_HASHVAL, (BYTE*)hashItem.data, 0)) { 408 PR_SetError(SSL_ERROR_SIGN_HASHES_FAILURE, GetLastError()); 409 goto done; 410 } 411 if (!CryptSignHash(hHash, key->dwKeySpec, NULL, 0, 412 NULL, &signatureLen) || signatureLen == 0) { 413 PR_SetError(SSL_ERROR_SIGN_HASHES_FAILURE, GetLastError()); 414 goto done; 415 } 416 buf->data = (unsigned char *)PORT_Alloc(signatureLen); 417 if (!buf->data) 418 goto done; /* error code was set. */ 419 420 if (!CryptSignHash(hHash, key->dwKeySpec, NULL, 0, 421 (BYTE*)buf->data, &signatureLen)) { 422 PR_SetError(SSL_ERROR_SIGN_HASHES_FAILURE, GetLastError()); 423 goto done; 424 } 425 buf->len = signatureLen; 426 427 /* CryptoAPI signs in little-endian, so reverse */ 428 for (i = 0; i < buf->len / 2; ++i) { 429 unsigned char tmp = buf->data[i]; 430 buf->data[i] = buf->data[buf->len - 1 - i]; 431 buf->data[buf->len - 1 - i] = tmp; 432 } 433 if (doDerEncode) { 434 SECItem derSig = {siBuffer, NULL, 0}; 435 436 /* This also works for an ECDSA signature */ 437 rv = DSAU_EncodeDerSigWithLen(&derSig, buf, buf->len); 438 if (rv == SECSuccess) { 439 PORT_Free(buf->data); /* discard unencoded signature. */ 440 *buf = derSig; /* give caller encoded signature. */ 441 } else if (derSig.data) { 442 PORT_Free(derSig.data); 443 } 444 } else { 445 rv = SECSuccess; 446 } 447 448 PRINT_BUF(60, (NULL, "signed hashes", buf->data, buf->len)); 449 done: 450 if (hHash) 451 CryptDestroyHash(hHash); 452 if (rv != SECSuccess && buf->data) { 453 PORT_Free(buf->data); 454 buf->data = NULL; 455 } 456 return rv; 457 } 458 459 SECStatus 460 ssl3_PlatformSignHashes(SSL3Hashes *hash, PlatformKey key, SECItem *buf, 461 PRBool isTLS, KeyType keyType) 462 { 463 if (key->dwKeySpec == CERT_NCRYPT_KEY_SPEC) { 464 return ssl3_CngPlatformSignHashes(hash, key, buf, isTLS, keyType); 465 } 466 return ssl3_CAPIPlatformSignHashes(hash, key, buf, isTLS, keyType); 467 } 468 469 #elif defined(XP_MACOSX) 470 #include <Security/cssm.h> 471 472 void 473 ssl_FreePlatformKey(PlatformKey key) 474 { 475 CFRelease(key); 476 } 477 478 #define SSL_MAX_DIGEST_INFO_PREFIX 20 479 480 /* ssl3_GetDigestInfoPrefix sets |out| and |out_len| to point to a buffer that 481 * contains ASN.1 data that should be prepended to a hash of the given type in 482 * order to create a DigestInfo structure that is valid for use in a PKCS #1 483 * v1.5 RSA signature. |out_len| will not be set to a value greater than 484 * SSL_MAX_DIGEST_INFO_PREFIX. */ 485 static SECStatus 486 ssl3_GetDigestInfoPrefix(SECOidTag hashAlg, 487 const SSL3Opaque** out, unsigned int *out_len) 488 { 489 /* These are the DER encoding of ASN.1 DigestInfo structures: 490 * DigestInfo ::= SEQUENCE { 491 * digestAlgorithm AlgorithmIdentifier, 492 * digest OCTET STRING 493 * } 494 * See PKCS #1 v2.2 Section 9.2, Note 1. 495 */ 496 static const unsigned char kSHA1[] = { 497 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 498 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14 499 }; 500 static const unsigned char kSHA224[] = { 501 0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 502 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, 0x05, 503 0x00, 0x04, 0x1c 504 }; 505 static const unsigned char kSHA256[] = { 506 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 507 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 508 0x00, 0x04, 0x20 509 }; 510 static const unsigned char kSHA384[] = { 511 0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 512 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, 513 0x00, 0x04, 0x30 514 }; 515 static const unsigned char kSHA512[] = { 516 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 517 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 518 0x00, 0x04, 0x40 519 }; 520 521 switch (hashAlg) { 522 case SEC_OID_UNKNOWN: 523 *out_len = 0; 524 break; 525 case SEC_OID_SHA1: 526 *out = kSHA1; 527 *out_len = sizeof(kSHA1); 528 break; 529 case SEC_OID_SHA224: 530 *out = kSHA224; 531 *out_len = sizeof(kSHA224); 532 break; 533 case SEC_OID_SHA256: 534 *out = kSHA256; 535 *out_len = sizeof(kSHA256); 536 break; 537 case SEC_OID_SHA384: 538 *out = kSHA384; 539 *out_len = sizeof(kSHA384); 540 break; 541 case SEC_OID_SHA512: 542 *out = kSHA512; 543 *out_len = sizeof(kSHA512); 544 break; 545 default: 546 PORT_SetError(SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM); 547 return SECFailure; 548 } 549 550 return SECSuccess; 551 } 552 553 /* Given the length of a raw DSA signature (consisting of two integers 554 * r and s), returns the maximum length of the DER encoding of the 555 * following structure: 556 * 557 * Dss-Sig-Value ::= SEQUENCE { 558 * r INTEGER, 559 * s INTEGER 560 * } 561 */ 562 static unsigned int 563 ssl3_DSAMaxDerEncodedLength(unsigned int rawDsaLen) 564 { 565 /* The length of one INTEGER. */ 566 unsigned int integerDerLen = rawDsaLen/2 + /* the integer itself */ 567 1 + /* additional zero byte if high bit is 1 */ 568 SEC_ASN1LengthLength(rawDsaLen/2 + 1) + /* length */ 569 1; /* INTEGER tag */ 570 571 /* The length of two INTEGERs in a SEQUENCE */ 572 return 2 * integerDerLen + /* two INTEGERs */ 573 SEC_ASN1LengthLength(2 * integerDerLen) + /* length */ 574 1; /* SEQUENCE tag */ 575 } 576 577 SECStatus 578 ssl3_PlatformSignHashes(SSL3Hashes *hash, PlatformKey key, SECItem *buf, 579 PRBool isTLS, KeyType keyType) 580 { 581 SECStatus rv = SECFailure; 582 PRBool doDerDecode = PR_FALSE; 583 unsigned int rawDsaLen; 584 unsigned int signatureLen; 585 OSStatus status = noErr; 586 CSSM_CSP_HANDLE cspHandle = 0; 587 const CSSM_KEY *cssmKey = NULL; 588 CSSM_ALGORITHMS sigAlg; 589 CSSM_ALGORITHMS digestAlg; 590 const CSSM_ACCESS_CREDENTIALS * cssmCreds = NULL; 591 CSSM_RETURN cssmRv; 592 CSSM_DATA hashData; 593 CSSM_DATA signatureData; 594 CSSM_CC_HANDLE cssmSignature = 0; 595 const SSL3Opaque* prefix; 596 unsigned int prefixLen; 597 SSL3Opaque prefixAndHash[SSL_MAX_DIGEST_INFO_PREFIX + HASH_LENGTH_MAX]; 598 599 buf->data = NULL; 600 601 status = SecKeyGetCSPHandle(key, &cspHandle); 602 if (status != noErr) { 603 PORT_SetError(SEC_ERROR_INVALID_KEY); 604 goto done; 605 } 606 607 status = SecKeyGetCSSMKey(key, &cssmKey); 608 if (status != noErr || !cssmKey) { 609 PORT_SetError(SEC_ERROR_NO_KEY); 610 goto done; 611 } 612 613 sigAlg = cssmKey->KeyHeader.AlgorithmId; 614 digestAlg = CSSM_ALGID_NONE; 615 616 switch (keyType) { 617 case rsaKey: 618 PORT_Assert(sigAlg == CSSM_ALGID_RSA); 619 signatureLen = (cssmKey->KeyHeader.LogicalKeySizeInBits + 7) / 8; 620 if (ssl3_GetDigestInfoPrefix(hash->hashAlg, &prefix, &prefixLen) != 621 SECSuccess) { 622 goto done; 623 } 624 if (prefixLen + hash->len > sizeof(prefixAndHash)) { 625 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 626 goto done; 627 } 628 memcpy(prefixAndHash, prefix, prefixLen); 629 memcpy(prefixAndHash + prefixLen, hash->u.raw, hash->len); 630 hashData.Data = prefixAndHash; 631 hashData.Length = prefixLen + hash->len; 632 break; 633 case dsaKey: 634 case ecKey: 635 /* SSL3 DSA signatures are raw, not DER-encoded. CSSM gives back 636 * DER-encoded signatures, so they must be decoded. */ 637 doDerDecode = (keyType == dsaKey) && !isTLS; 638 639 /* Compute the maximum size of a DER-encoded signature: */ 640 if (keyType == ecKey) { 641 PORT_Assert(sigAlg == CSSM_ALGID_ECDSA); 642 /* LogicalKeySizeInBits is the size of an EC public key. But an 643 * ECDSA signature length depends on the size of the base 644 * point's order. For P-256, P-384, and P-521, these two sizes 645 * are the same. */ 646 rawDsaLen = 647 (cssmKey->KeyHeader.LogicalKeySizeInBits + 7) / 8 * 2; 648 } else { 649 /* TODO(davidben): Get the size of the subprime out of CSSM. For 650 * now, assume 160; Apple's implementation hardcodes it. */ 651 PORT_Assert(sigAlg == CSSM_ALGID_DSA); 652 rawDsaLen = 2 * (160 / 8); 653 } 654 signatureLen = ssl3_DSAMaxDerEncodedLength(rawDsaLen); 655 656 /* SEC_OID_UNKNOWN is used to specify the MD5/SHA1 concatenated 657 * hash. In that case, we use just the SHA1 part. */ 658 if (hash->hashAlg == SEC_OID_UNKNOWN) { 659 hashData.Data = hash->u.s.sha; 660 hashData.Length = sizeof(hash->u.s.sha); 661 } else { 662 hashData.Data = hash->u.raw; 663 hashData.Length = hash->len; 664 } 665 break; 666 default: 667 PORT_SetError(SEC_ERROR_INVALID_KEY); 668 goto done; 669 } 670 PRINT_BUF(60, (NULL, "hash(es) to be signed", hashData.Data, hashData.Length)); 671 672 if (signatureLen == 0) { 673 PORT_SetError(SEC_ERROR_INVALID_KEY); 674 goto done; 675 } 676 677 buf->data = (unsigned char *)PORT_Alloc(signatureLen); 678 if (!buf->data) 679 goto done; /* error code was set. */ 680 681 /* TODO(rsleevi): Should it be kSecCredentialTypeNoUI? In Win32, at least, 682 * you can prevent the UI by setting the provider handle on the 683 * certificate to be opened with CRYPT_SILENT, but is there an equivalent? 684 */ 685 status = SecKeyGetCredentials(key, CSSM_ACL_AUTHORIZATION_SIGN, 686 kSecCredentialTypeDefault, &cssmCreds); 687 if (status != noErr) { 688 PR_SetError(SSL_ERROR_SIGN_HASHES_FAILURE, status); 689 goto done; 690 } 691 692 signatureData.Length = signatureLen; 693 signatureData.Data = (uint8*)buf->data; 694 695 cssmRv = CSSM_CSP_CreateSignatureContext(cspHandle, sigAlg, cssmCreds, 696 cssmKey, &cssmSignature); 697 if (cssmRv) { 698 PR_SetError(SSL_ERROR_SIGN_HASHES_FAILURE, cssmRv); 699 goto done; 700 } 701 702 /* See "Apple Cryptographic Service Provider Functional Specification" */ 703 if (cssmKey->KeyHeader.AlgorithmId == CSSM_ALGID_RSA) { 704 /* To set RSA blinding for RSA keys */ 705 CSSM_CONTEXT_ATTRIBUTE blindingAttr; 706 blindingAttr.AttributeType = CSSM_ATTRIBUTE_RSA_BLINDING; 707 blindingAttr.AttributeLength = sizeof(uint32); 708 blindingAttr.Attribute.Uint32 = 1; 709 cssmRv = CSSM_UpdateContextAttributes(cssmSignature, 1, &blindingAttr); 710 if (cssmRv) { 711 PR_SetError(SSL_ERROR_SIGN_HASHES_FAILURE, cssmRv); 712 goto done; 713 } 714 } 715 716 cssmRv = CSSM_SignData(cssmSignature, &hashData, 1, digestAlg, 717 &signatureData); 718 if (cssmRv) { 719 PR_SetError(SSL_ERROR_SIGN_HASHES_FAILURE, cssmRv); 720 goto done; 721 } 722 buf->len = signatureData.Length; 723 724 if (doDerDecode) { 725 SECItem* rawSig = DSAU_DecodeDerSigToLen(buf, rawDsaLen); 726 if (rawSig != NULL) { 727 PORT_Free(buf->data); /* discard encoded signature. */ 728 *buf = *rawSig; /* give caller unencoded signature. */ 729 PORT_Free(rawSig); 730 rv = SECSuccess; 731 } 732 } else { 733 rv = SECSuccess; 734 } 735 736 PRINT_BUF(60, (NULL, "signed hashes", buf->data, buf->len)); 737 done: 738 /* cspHandle, cssmKey, and cssmCreds are owned by the SecKeyRef and 739 * should not be freed. When the PlatformKey is freed, they will be 740 * released. 741 */ 742 if (cssmSignature) 743 CSSM_DeleteContext(cssmSignature); 744 745 if (rv != SECSuccess && buf->data) { 746 PORT_Free(buf->data); 747 buf->data = NULL; 748 } 749 return rv; 750 } 751 #else 752 void 753 ssl_FreePlatformKey(PlatformKey key) 754 { 755 } 756 757 SECStatus 758 ssl3_PlatformSignHashes(SSL3Hashes *hash, PlatformKey key, SECItem *buf, 759 PRBool isTLS, KeyType keyType) 760 { 761 PORT_SetError(PR_NOT_IMPLEMENTED_ERROR); 762 return SECFailure; 763 } 764 #endif 765 766 #endif /* NSS_PLATFORM_CLIENT_AUTH */ 767