2 * Platform specific crypto wrappers
4 * ***** BEGIN LICENSE BLOCK *****
5 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
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/
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
17 * The Original Code is the Netscape security libraries.
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.
25 * Ryan Sleevi <ryan.sleevi@gmail.com>
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.
39 * ***** END LICENSE BLOCK ***** */
51 #ifdef NSS_PLATFORM_CLIENT_AUTH
57 #ifdef NSS_PLATFORM_CLIENT_AUTH
59 hack_NewCertificateListFromCertList(CERTCertList
* list
)
61 CERTCertificateList
* chain
= NULL
;
62 PLArenaPool
* arena
= NULL
;
63 CERTCertListNode
* node
;
66 if (CERT_LIST_EMPTY(list
))
69 arena
= PORT_NewArena(4096);
73 for (len
= 0, node
= CERT_LIST_HEAD(list
); !CERT_LIST_END(node
, list
);
74 len
++, node
= CERT_LIST_NEXT(node
)) {
77 chain
= PORT_ArenaNew(arena
, CERTCertificateList
);
81 chain
->certs
= PORT_ArenaNewArray(arena
, SECItem
, len
);
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
) {
96 SECITEM_CopyItem(arena
, &chain
->certs
[len
], &node
->cert
->derCert
);
104 PORT_FreeArena(arena
, PR_FALSE
);
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 */);
121 static PRCallOnceType cngFunctionsInitOnce
;
122 static const PRCallOnceType pristineCallOnce
;
124 static PRLibrary
*ncrypt_library
= NULL
;
125 static NCryptFreeObjectFunc pNCryptFreeObject
= NULL
;
126 static NCryptSignHashFunc pNCryptSignHash
= NULL
;
129 ssl_ShutdownCngFunctions(void *appData
, void *nssData
)
131 pNCryptSignHash
= NULL
;
132 pNCryptFreeObject
= NULL
;
133 if (ncrypt_library
) {
134 PR_UnloadLibrary(ncrypt_library
);
135 ncrypt_library
= NULL
;
138 cngFunctionsInitOnce
= pristineCallOnce
;
144 ssl_InitCngFunctions(void)
148 ncrypt_library
= PR_LoadLibrary("ncrypt.dll");
149 if (ncrypt_library
== NULL
)
152 pNCryptFreeObject
= (NCryptFreeObjectFunc
)PR_FindFunctionSymbol(
153 ncrypt_library
, "NCryptFreeObject");
154 if (pNCryptFreeObject
== NULL
)
157 pNCryptSignHash
= (NCryptSignHashFunc
)PR_FindFunctionSymbol(
158 ncrypt_library
, "NCryptSignHash");
159 if (pNCryptSignHash
== NULL
)
162 rv
= NSS_RegisterShutdown(ssl_ShutdownCngFunctions
, NULL
);
163 if (rv
!= SECSuccess
)
169 pNCryptSignHash
= NULL
;
170 pNCryptFreeObject
= NULL
;
171 if (ncrypt_library
) {
172 PR_UnloadLibrary(ncrypt_library
);
173 ncrypt_library
= NULL
;
182 if (PR_CallOnce(&cngFunctionsInitOnce
, ssl_InitCngFunctions
) != PR_SUCCESS
)
188 ssl_FreePlatformKey(PlatformKey key
)
193 if (key
->dwKeySpec
== CERT_NCRYPT_KEY_SPEC
) {
194 if (ssl_InitCng() == SECSuccess
) {
195 (*pNCryptFreeObject
)(key
->hNCryptKey
);
198 CryptReleaseContext(key
->hCryptProv
, 0);
204 ssl3_CngPlatformSignHashes(SSL3Hashes
*hash
, PlatformKey key
, SECItem
*buf
,
205 PRBool isTLS
, KeyType keyType
)
207 SECStatus rv
= SECFailure
;
208 SECURITY_STATUS ncrypt_status
;
209 PRBool doDerEncode
= PR_FALSE
;
211 DWORD signatureLen
= 0;
213 VOID
*pPaddingInfo
= NULL
;
215 /* Always encode using PKCS#1 block type. */
216 BCRYPT_PKCS1_PADDING_INFO rsaPaddingInfo
;
218 if (key
->dwKeySpec
!= CERT_NCRYPT_KEY_SPEC
) {
219 PR_SetError(SEC_ERROR_LIBRARY_FAILURE
, 0);
222 if (ssl_InitCng() != SECSuccess
) {
223 PR_SetError(SEC_ERROR_LIBRARY_FAILURE
, 0);
229 switch (hash
->hashAlg
) {
230 case SEC_OID_UNKNOWN
:
231 /* No OID/encoded DigestInfo. */
232 rsaPaddingInfo
.pszAlgId
= NULL
;
235 rsaPaddingInfo
.pszAlgId
= BCRYPT_SHA1_ALGORITHM
;
238 rsaPaddingInfo
.pszAlgId
= BCRYPT_SHA256_ALGORITHM
;
241 rsaPaddingInfo
.pszAlgId
= BCRYPT_SHA384_ALGORITHM
;
244 rsaPaddingInfo
.pszAlgId
= BCRYPT_SHA512_ALGORITHM
;
247 PORT_SetError(SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM
);
250 hashItem
.data
= hash
->u
.raw
;
251 hashItem
.len
= hash
->len
;
252 dwFlags
= BCRYPT_PAD_PKCS1
;
253 pPaddingInfo
= &rsaPaddingInfo
;
257 if (keyType
== ecKey
) {
258 doDerEncode
= PR_TRUE
;
262 if (hash
->hashAlg
== SEC_OID_UNKNOWN
) {
263 hashItem
.data
= hash
->u
.s
.sha
;
264 hashItem
.len
= sizeof(hash
->u
.s
.sha
);
266 hashItem
.data
= hash
->u
.raw
;
267 hashItem
.len
= hash
->len
;
271 PORT_SetError(SEC_ERROR_INVALID_KEY
);
274 PRINT_BUF(60, (NULL
, "hash(es) to be signed", hashItem
.data
, hashItem
.len
));
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
);
284 buf
->data
= (unsigned char *)PORT_Alloc(signatureLen
);
286 goto done
; /* error code was set. */
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
);
298 buf
->len
= signatureLen
;
301 SECItem derSig
= {siBuffer
, NULL
, 0};
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
);
315 PRINT_BUF(60, (NULL
, "signed hashes", buf
->data
, buf
->len
));
318 if (rv
!= SECSuccess
&& buf
->data
) {
319 PORT_Free(buf
->data
);
328 ssl3_CAPIPlatformSignHashes(SSL3Hashes
*hash
, PlatformKey key
, SECItem
*buf
,
329 PRBool isTLS
, KeyType keyType
)
331 SECStatus rv
= SECFailure
;
332 PRBool doDerEncode
= PR_FALSE
;
335 DWORD signatureLen
= 0;
337 HCRYPTHASH hHash
= 0;
343 switch (hash
->hashAlg
) {
344 case SEC_OID_UNKNOWN
:
351 hashAlg
= CALG_SHA_256
;
354 hashAlg
= CALG_SHA_384
;
357 hashAlg
= CALG_SHA_512
;
360 PORT_SetError(SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM
);
367 hashAlg
= CALG_SSL3_SHAMD5
;
369 hashItem
.data
= hash
->u
.raw
;
370 hashItem
.len
= hash
->len
;
374 if (keyType
== ecKey
) {
375 doDerEncode
= PR_TRUE
;
381 hashItem
.data
= hash
->u
.s
.sha
;
382 hashItem
.len
= sizeof(hash
->u
.s
.sha
);
384 hashItem
.data
= hash
->u
.raw
;
385 hashItem
.len
= hash
->len
;
389 PORT_SetError(SEC_ERROR_INVALID_KEY
);
392 PRINT_BUF(60, (NULL
, "hash(es) to be signed", hashItem
.data
, hashItem
.len
));
394 if (!CryptCreateHash(key
->hCryptProv
, hashAlg
, 0, 0, &hHash
)) {
395 PR_SetError(SSL_ERROR_SIGN_HASHES_FAILURE
, GetLastError());
398 argLen
= sizeof(hashLen
);
399 if (!CryptGetHashParam(hHash
, HP_HASHSIZE
, (BYTE
*)&hashLen
, &argLen
, 0)) {
400 PR_SetError(SSL_ERROR_SIGN_HASHES_FAILURE
, GetLastError());
403 if (hashLen
!= hashItem
.len
) {
404 PR_SetError(SSL_ERROR_SIGN_HASHES_FAILURE
, 0);
407 if (!CryptSetHashParam(hHash
, HP_HASHVAL
, (BYTE
*)hashItem
.data
, 0)) {
408 PR_SetError(SSL_ERROR_SIGN_HASHES_FAILURE
, GetLastError());
411 if (!CryptSignHash(hHash
, key
->dwKeySpec
, NULL
, 0,
412 NULL
, &signatureLen
) || signatureLen
== 0) {
413 PR_SetError(SSL_ERROR_SIGN_HASHES_FAILURE
, GetLastError());
416 buf
->data
= (unsigned char *)PORT_Alloc(signatureLen
);
418 goto done
; /* error code was set. */
420 if (!CryptSignHash(hHash
, key
->dwKeySpec
, NULL
, 0,
421 (BYTE
*)buf
->data
, &signatureLen
)) {
422 PR_SetError(SSL_ERROR_SIGN_HASHES_FAILURE
, GetLastError());
425 buf
->len
= signatureLen
;
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
;
434 SECItem derSig
= {siBuffer
, NULL
, 0};
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
);
448 PRINT_BUF(60, (NULL
, "signed hashes", buf
->data
, buf
->len
));
451 CryptDestroyHash(hHash
);
452 if (rv
!= SECSuccess
&& buf
->data
) {
453 PORT_Free(buf
->data
);
460 ssl3_PlatformSignHashes(SSL3Hashes
*hash
, PlatformKey key
, SECItem
*buf
,
461 PRBool isTLS
, KeyType keyType
)
463 if (key
->dwKeySpec
== CERT_NCRYPT_KEY_SPEC
) {
464 return ssl3_CngPlatformSignHashes(hash
, key
, buf
, isTLS
, keyType
);
466 return ssl3_CAPIPlatformSignHashes(hash
, key
, buf
, isTLS
, keyType
);
469 #elif defined(XP_MACOSX)
470 #include <Security/cssm.h>
473 ssl_FreePlatformKey(PlatformKey key
)
478 #define SSL_MAX_DIGEST_INFO_PREFIX 20
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. */
486 ssl3_GetDigestInfoPrefix(SECOidTag hashAlg
,
487 const SSL3Opaque
** out
, unsigned int *out_len
)
489 /* These are the DER encoding of ASN.1 DigestInfo structures:
490 * DigestInfo ::= SEQUENCE {
491 * digestAlgorithm AlgorithmIdentifier,
492 * digest OCTET STRING
494 * See PKCS #1 v2.2 Section 9.2, Note 1.
496 static const unsigned char kSHA1
[] = {
497 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e,
498 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14
500 static const unsigned char kSHA224
[] = {
501 0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
502 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, 0x05,
505 static const unsigned char kSHA256
[] = {
506 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
507 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05,
510 static const unsigned char kSHA384
[] = {
511 0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
512 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05,
515 static const unsigned char kSHA512
[] = {
516 0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
517 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05,
522 case SEC_OID_UNKNOWN
:
527 *out_len
= sizeof(kSHA1
);
531 *out_len
= sizeof(kSHA224
);
535 *out_len
= sizeof(kSHA256
);
539 *out_len
= sizeof(kSHA384
);
543 *out_len
= sizeof(kSHA512
);
546 PORT_SetError(SSL_ERROR_UNSUPPORTED_HASH_ALGORITHM
);
554 ssl3_PlatformSignHashes(SSL3Hashes
*hash
, PlatformKey key
, SECItem
*buf
,
555 PRBool isTLS
, KeyType keyType
)
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
;
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
];
576 status
= SecKeyGetCSPHandle(key
, &cspHandle
);
577 if (status
!= noErr
) {
578 PORT_SetError(SEC_ERROR_INVALID_KEY
);
582 status
= SecKeyGetCSSMKey(key
, &cssmKey
);
583 if (status
!= noErr
|| !cssmKey
) {
584 PORT_SetError(SEC_ERROR_NO_KEY
);
588 /* SecKeyGetBlockSize wasn't addeded until OS X 10.6 - but the
589 * needed information is readily available on the key itself.
591 signatureLen
= (cssmKey
->KeyHeader
.LogicalKeySizeInBits
+ 7) / 8;
593 if (signatureLen
== 0) {
594 PORT_SetError(SEC_ERROR_INVALID_KEY
);
598 buf
->data
= (unsigned char *)PORT_Alloc(signatureLen
);
600 goto done
; /* error code was set. */
602 sigAlg
= cssmKey
->KeyHeader
.AlgorithmId
;
603 digestAlg
= CSSM_ALGID_NONE
;
607 PORT_Assert(sigAlg
== CSSM_ALGID_RSA
);
608 if (ssl3_GetDigestInfoPrefix(hash
->hashAlg
, &prefix
, &prefixLen
) !=
612 if (prefixLen
+ hash
->len
> sizeof(prefixAndHash
)) {
613 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE
);
616 memcpy(prefixAndHash
, prefix
, prefixLen
);
617 memcpy(prefixAndHash
+ prefixLen
, hash
->u
.raw
, hash
->len
);
618 hashData
.Data
= prefixAndHash
;
619 hashData
.Length
= prefixLen
+ hash
->len
;
623 if (keyType
== ecKey
) {
624 PORT_Assert(sigAlg
== CSSM_ALGID_ECDSA
);
625 doDerEncode
= PR_TRUE
;
627 PORT_Assert(sigAlg
== CSSM_ALGID_DSA
);
630 if (hash
->hashAlg
== SEC_OID_UNKNOWN
) {
631 hashData
.Data
= hash
->u
.s
.sha
;
632 hashData
.Length
= sizeof(hash
->u
.s
.sha
);
634 hashData
.Data
= hash
->u
.raw
;
635 hashData
.Length
= hash
->len
;
639 PORT_SetError(SEC_ERROR_INVALID_KEY
);
642 PRINT_BUF(60, (NULL
, "hash(es) to be signed", hashData
.Data
, hashData
.Length
));
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?
648 status
= SecKeyGetCredentials(key
, CSSM_ACL_AUTHORIZATION_SIGN
,
649 kSecCredentialTypeDefault
, &cssmCreds
);
650 if (status
!= noErr
) {
651 PR_SetError(SSL_ERROR_SIGN_HASHES_FAILURE
, status
);
655 signatureData
.Length
= signatureLen
;
656 signatureData
.Data
= (uint8
*)buf
->data
;
658 cssmRv
= CSSM_CSP_CreateSignatureContext(cspHandle
, sigAlg
, cssmCreds
,
659 cssmKey
, &cssmSignature
);
661 PR_SetError(SSL_ERROR_SIGN_HASHES_FAILURE
, cssmRv
);
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
);
674 PR_SetError(SSL_ERROR_SIGN_HASHES_FAILURE
, cssmRv
);
679 cssmRv
= CSSM_SignData(cssmSignature
, &hashData
, 1, digestAlg
,
682 PR_SetError(SSL_ERROR_SIGN_HASHES_FAILURE
, cssmRv
);
685 buf
->len
= signatureData
.Length
;
688 SECItem derSig
= {siBuffer
, NULL
, 0};
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
);
702 PRINT_BUF(60, (NULL
, "signed hashes", buf
->data
, buf
->len
));
704 /* cspHandle, cssmKey, and cssmCreds are owned by the SecKeyRef and
705 * should not be freed. When the PlatformKey is freed, they will be
709 CSSM_DeleteContext(cssmSignature
);
711 if (rv
!= SECSuccess
&& buf
->data
) {
712 PORT_Free(buf
->data
);
719 ssl_FreePlatformKey(PlatformKey key
)
724 ssl3_PlatformSignHashes(SSL3Hashes
*hash
, PlatformKey key
, SECItem
*buf
,
725 PRBool isTLS
, KeyType keyType
)
727 PORT_SetError(PR_NOT_IMPLEMENTED_ERROR
);
732 #endif /* NSS_PLATFORM_CLIENT_AUTH */