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 SECStatus 554 ssl3_PlatformSignHashes(SSL3Hashes *hash, PlatformKey key, SECItem *buf, 555 PRBool isTLS, KeyType keyType) 556 { 557 SECStatus rv = SECFailure; 558 PRBool doDerEncode = PR_FALSE; 559 unsigned int signatureLen; 560 OSStatus status = noErr; 561 CSSM_CSP_HANDLE cspHandle = 0; 562 const CSSM_KEY *cssmKey = NULL; 563 CSSM_ALGORITHMS sigAlg; 564 CSSM_ALGORITHMS digestAlg; 565 const CSSM_ACCESS_CREDENTIALS * cssmCreds = NULL; 566 CSSM_RETURN cssmRv; 567 CSSM_DATA hashData; 568 CSSM_DATA signatureData; 569 CSSM_CC_HANDLE cssmSignature = 0; 570 const SSL3Opaque* prefix; 571 unsigned int prefixLen; 572 SSL3Opaque prefixAndHash[SSL_MAX_DIGEST_INFO_PREFIX + HASH_LENGTH_MAX]; 573 574 buf->data = NULL; 575 576 status = SecKeyGetCSPHandle(key, &cspHandle); 577 if (status != noErr) { 578 PORT_SetError(SEC_ERROR_INVALID_KEY); 579 goto done; 580 } 581 582 status = SecKeyGetCSSMKey(key, &cssmKey); 583 if (status != noErr || !cssmKey) { 584 PORT_SetError(SEC_ERROR_NO_KEY); 585 goto done; 586 } 587 588 /* SecKeyGetBlockSize wasn't addeded until OS X 10.6 - but the 589 * needed information is readily available on the key itself. 590 */ 591 signatureLen = (cssmKey->KeyHeader.LogicalKeySizeInBits + 7) / 8; 592 593 if (signatureLen == 0) { 594 PORT_SetError(SEC_ERROR_INVALID_KEY); 595 goto done; 596 } 597 598 buf->data = (unsigned char *)PORT_Alloc(signatureLen); 599 if (!buf->data) 600 goto done; /* error code was set. */ 601 602 sigAlg = cssmKey->KeyHeader.AlgorithmId; 603 digestAlg = CSSM_ALGID_NONE; 604 605 switch (keyType) { 606 case rsaKey: 607 PORT_Assert(sigAlg == CSSM_ALGID_RSA); 608 if (ssl3_GetDigestInfoPrefix(hash->hashAlg, &prefix, &prefixLen) != 609 SECSuccess) { 610 goto done; 611 } 612 if (prefixLen + hash->len > sizeof(prefixAndHash)) { 613 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 614 goto done; 615 } 616 memcpy(prefixAndHash, prefix, prefixLen); 617 memcpy(prefixAndHash + prefixLen, hash->u.raw, hash->len); 618 hashData.Data = prefixAndHash; 619 hashData.Length = prefixLen + hash->len; 620 break; 621 case dsaKey: 622 case ecKey: 623 if (keyType == ecKey) { 624 PORT_Assert(sigAlg == CSSM_ALGID_ECDSA); 625 doDerEncode = PR_TRUE; 626 } else { 627 PORT_Assert(sigAlg == CSSM_ALGID_DSA); 628 doDerEncode = isTLS; 629 } 630 if (hash->hashAlg == SEC_OID_UNKNOWN) { 631 hashData.Data = hash->u.s.sha; 632 hashData.Length = sizeof(hash->u.s.sha); 633 } else { 634 hashData.Data = hash->u.raw; 635 hashData.Length = hash->len; 636 } 637 break; 638 default: 639 PORT_SetError(SEC_ERROR_INVALID_KEY); 640 goto done; 641 } 642 PRINT_BUF(60, (NULL, "hash(es) to be signed", hashData.Data, hashData.Length)); 643 644 /* TODO(rsleevi): Should it be kSecCredentialTypeNoUI? In Win32, at least, 645 * you can prevent the UI by setting the provider handle on the 646 * certificate to be opened with CRYPT_SILENT, but is there an equivalent? 647 */ 648 status = SecKeyGetCredentials(key, CSSM_ACL_AUTHORIZATION_SIGN, 649 kSecCredentialTypeDefault, &cssmCreds); 650 if (status != noErr) { 651 PR_SetError(SSL_ERROR_SIGN_HASHES_FAILURE, status); 652 goto done; 653 } 654 655 signatureData.Length = signatureLen; 656 signatureData.Data = (uint8*)buf->data; 657 658 cssmRv = CSSM_CSP_CreateSignatureContext(cspHandle, sigAlg, cssmCreds, 659 cssmKey, &cssmSignature); 660 if (cssmRv) { 661 PR_SetError(SSL_ERROR_SIGN_HASHES_FAILURE, cssmRv); 662 goto done; 663 } 664 665 /* See "Apple Cryptographic Service Provider Functional Specification" */ 666 if (cssmKey->KeyHeader.AlgorithmId == CSSM_ALGID_RSA) { 667 /* To set RSA blinding for RSA keys */ 668 CSSM_CONTEXT_ATTRIBUTE blindingAttr; 669 blindingAttr.AttributeType = CSSM_ATTRIBUTE_RSA_BLINDING; 670 blindingAttr.AttributeLength = sizeof(uint32); 671 blindingAttr.Attribute.Uint32 = 1; 672 cssmRv = CSSM_UpdateContextAttributes(cssmSignature, 1, &blindingAttr); 673 if (cssmRv) { 674 PR_SetError(SSL_ERROR_SIGN_HASHES_FAILURE, cssmRv); 675 goto done; 676 } 677 } 678 679 cssmRv = CSSM_SignData(cssmSignature, &hashData, 1, digestAlg, 680 &signatureData); 681 if (cssmRv) { 682 PR_SetError(SSL_ERROR_SIGN_HASHES_FAILURE, cssmRv); 683 goto done; 684 } 685 buf->len = signatureData.Length; 686 687 if (doDerEncode) { 688 SECItem derSig = {siBuffer, NULL, 0}; 689 690 /* This also works for an ECDSA signature */ 691 rv = DSAU_EncodeDerSigWithLen(&derSig, buf, buf->len); 692 if (rv == SECSuccess) { 693 PORT_Free(buf->data); /* discard unencoded signature. */ 694 *buf = derSig; /* give caller encoded signature. */ 695 } else if (derSig.data) { 696 PORT_Free(derSig.data); 697 } 698 } else { 699 rv = SECSuccess; 700 } 701 702 PRINT_BUF(60, (NULL, "signed hashes", buf->data, buf->len)); 703 done: 704 /* cspHandle, cssmKey, and cssmCreds are owned by the SecKeyRef and 705 * should not be freed. When the PlatformKey is freed, they will be 706 * released. 707 */ 708 if (cssmSignature) 709 CSSM_DeleteContext(cssmSignature); 710 711 if (rv != SECSuccess && buf->data) { 712 PORT_Free(buf->data); 713 buf->data = NULL; 714 } 715 return rv; 716 } 717 #else 718 void 719 ssl_FreePlatformKey(PlatformKey key) 720 { 721 } 722 723 SECStatus 724 ssl3_PlatformSignHashes(SSL3Hashes *hash, PlatformKey key, SECItem *buf, 725 PRBool isTLS, KeyType keyType) 726 { 727 PORT_SetError(PR_NOT_IMPLEMENTED_ERROR); 728 return SECFailure; 729 } 730 #endif 731 732 #endif /* NSS_PLATFORM_CLIENT_AUTH */ 733