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 ***** */
48 #ifdef NSS_PLATFORM_CLIENT_AUTH
50 hack_NewCertificateListFromCertList(CERTCertList
* list
)
52 CERTCertificateList
* chain
= NULL
;
53 PRArenaPool
* arena
= NULL
;
54 CERTCertListNode
* node
;
57 if (CERT_LIST_EMPTY(list
))
60 arena
= PORT_NewArena(4096);
64 for (len
= 0, node
= CERT_LIST_HEAD(list
); !CERT_LIST_END(node
, list
);
65 len
++, node
= CERT_LIST_NEXT(node
)) {
68 chain
= PORT_ArenaNew(arena
, CERTCertificateList
);
72 chain
->certs
= PORT_ArenaNewArray(arena
, SECItem
, len
);
77 for (len
= 0, node
= CERT_LIST_HEAD(list
); !CERT_LIST_END(node
, list
);
78 len
++, node
= CERT_LIST_NEXT(node
)) {
79 // Check to see if the last cert to be sent is a self-signed cert,
80 // and if so, omit it from the list of certificates. However, if
81 // there is only one cert (len == 0), include the cert, as it means
82 // the EE cert is self-signed.
83 if (len
> 0 && (len
== chain
->len
- 1) && node
->cert
->isRoot
) {
87 SECITEM_CopyItem(arena
, &chain
->certs
[len
], &node
->cert
->derCert
);
95 PORT_FreeArena(arena
, PR_FALSE
);
100 #if defined(XP_WIN32)
102 ssl_FreePlatformKey(PlatformKey key
)
105 if (key
->dwKeySpec
!= CERT_NCRYPT_KEY_SPEC
)
106 CryptReleaseContext(key
->hCryptProv
, 0);
107 /* FIXME(rsleevi): Close CNG keys. */
113 ssl3_PlatformSignHashes(SSL3Hashes
*hash
, PlatformKey key
, SECItem
*buf
,
116 SECStatus rv
= SECFailure
;
117 PRBool doDerEncode
= PR_FALSE
;
122 DWORD signatureLen
= 0;
124 HCRYPTHASH hHash
= 0;
129 if (!CryptGetUserKey(key
->hCryptProv
, key
->dwKeySpec
, &hKey
)) {
130 if (GetLastError() == NTE_NO_KEY
) {
131 PORT_SetError(SEC_ERROR_NO_KEY
);
133 PORT_SetError(SEC_ERROR_INVALID_KEY
);
138 argLen
= sizeof(keyAlg
);
139 if (!CryptGetKeyParam(hKey
, KP_ALGID
, (BYTE
*)&keyAlg
, &argLen
, 0)) {
140 PORT_SetError(SEC_ERROR_INVALID_KEY
);
147 hashAlg
= CALG_SSL3_SHAMD5
;
148 hashItem
.data
= hash
->md5
;
149 hashItem
.len
= sizeof(SSL3Hashes
);
153 if (keyAlg
== CALG_ECDSA
) {
154 doDerEncode
= PR_TRUE
;
159 hashItem
.data
= hash
->sha
;
160 hashItem
.len
= sizeof(hash
->sha
);
163 PORT_SetError(SEC_ERROR_INVALID_KEY
);
166 PRINT_BUF(60, (NULL
, "hash(es) to be signed", hashItem
.data
, hashItem
.len
));
168 if (!CryptCreateHash(key
->hCryptProv
, hashAlg
, 0, 0, &hHash
)) {
169 PORT_SetError(SSL_ERROR_SIGN_HASHES_FAILURE
);
172 argLen
= sizeof(hashLen
);
173 if (!CryptGetHashParam(hHash
, HP_HASHSIZE
, (BYTE
*)&hashLen
, &argLen
, 0)) {
174 PORT_SetError(SSL_ERROR_SIGN_HASHES_FAILURE
);
177 if (hashLen
!= hashItem
.len
) {
178 PORT_SetError(SSL_ERROR_SIGN_HASHES_FAILURE
);
181 if (!CryptSetHashParam(hHash
, HP_HASHVAL
, (BYTE
*)hashItem
.data
, 0)) {
182 PORT_SetError(SSL_ERROR_SIGN_HASHES_FAILURE
);
185 if (!CryptSignHash(hHash
, key
->dwKeySpec
, NULL
, 0,
186 NULL
, &signatureLen
) || signatureLen
== 0) {
187 PORT_SetError(SSL_ERROR_SIGN_HASHES_FAILURE
);
190 buf
->data
= (unsigned char *)PORT_Alloc(signatureLen
);
192 goto done
; /* error code was set. */
194 if (!CryptSignHash(hHash
, key
->dwKeySpec
, NULL
, 0,
195 (BYTE
*)buf
->data
, &signatureLen
)) {
196 PORT_SetError(SSL_ERROR_SIGN_HASHES_FAILURE
);
199 buf
->len
= signatureLen
;
201 /* CryptoAPI signs in little-endian, so reverse */
202 for (i
= 0; i
< buf
->len
/ 2; ++i
) {
203 unsigned char tmp
= buf
->data
[i
];
204 buf
->data
[i
] = buf
->data
[buf
->len
- 1 - i
];
205 buf
->data
[buf
->len
- 1 - i
] = tmp
;
208 SECItem derSig
= {siBuffer
, NULL
, 0};
210 /* This also works for an ECDSA signature */
211 rv
= DSAU_EncodeDerSigWithLen(&derSig
, buf
, buf
->len
);
212 if (rv
== SECSuccess
) {
213 PORT_Free(buf
->data
); /* discard unencoded signature. */
214 *buf
= derSig
; /* give caller encoded signature. */
215 } else if (derSig
.data
) {
216 PORT_Free(derSig
.data
);
222 PRINT_BUF(60, (NULL
, "signed hashes", buf
->data
, buf
->len
));
225 CryptDestroyHash(hHash
);
227 CryptDestroyKey(hKey
);
228 if (rv
!= SECSuccess
&& buf
->data
) {
229 PORT_Free(buf
->data
);
235 #elif defined(XP_MACOSX)
236 #include <Security/cssm.h>
239 ssl_FreePlatformKey(PlatformKey key
)
245 ssl3_PlatformSignHashes(SSL3Hashes
*hash
, PlatformKey key
, SECItem
*buf
,
248 SECStatus rv
= SECFailure
;
249 PRBool doDerEncode
= PR_FALSE
;
250 unsigned int signatureLen
;
251 OSStatus status
= noErr
;
252 CSSM_CSP_HANDLE cspHandle
= 0;
253 const CSSM_KEY
*cssmKey
= NULL
;
254 CSSM_ALGORITHMS sigAlg
;
255 const CSSM_ACCESS_CREDENTIALS
* cssmCreds
= NULL
;
258 CSSM_DATA signatureData
;
259 CSSM_CC_HANDLE cssmSignature
= 0;
263 status
= SecKeyGetCSPHandle(key
, &cspHandle
);
264 if (status
!= noErr
) {
265 PORT_SetError(SEC_ERROR_INVALID_KEY
);
269 status
= SecKeyGetCSSMKey(key
, &cssmKey
);
270 if (status
!= noErr
|| !cssmKey
) {
271 PORT_SetError(SEC_ERROR_NO_KEY
);
275 /* SecKeyGetBlockSize wasn't addeded until OS X 10.6 - but the
276 * needed information is readily available on the key itself.
278 signatureLen
= (cssmKey
->KeyHeader
.LogicalKeySizeInBits
+ 7) / 8;
280 if (signatureLen
== 0) {
281 PORT_SetError(SEC_ERROR_INVALID_KEY
);
285 buf
->data
= (unsigned char *)PORT_Alloc(signatureLen
);
287 goto done
; /* error code was set. */
289 sigAlg
= cssmKey
->KeyHeader
.AlgorithmId
;
292 hashData
.Data
= hash
->md5
;
293 hashData
.Length
= sizeof(SSL3Hashes
);
295 case CSSM_ALGID_ECDSA
:
297 if (sigAlg
== CSSM_ALGID_ECDSA
) {
298 doDerEncode
= PR_TRUE
;
302 hashData
.Data
= hash
->sha
;
303 hashData
.Length
= sizeof(hash
->sha
);
306 PORT_SetError(SEC_ERROR_INVALID_KEY
);
309 PRINT_BUF(60, (NULL
, "hash(es) to be signed", hashData
.Data
, hashData
.Length
));
311 /* TODO(rsleevi): Should it be kSecCredentialTypeNoUI? In Win32, at least,
312 * you can prevent the UI by setting the provider handle on the
313 * certificate to be opened with CRYPT_SILENT, but is there an equivalent?
315 status
= SecKeyGetCredentials(key
, CSSM_ACL_AUTHORIZATION_SIGN
,
316 kSecCredentialTypeDefault
, &cssmCreds
);
317 if (status
!= noErr
) {
318 PORT_SetError(SSL_ERROR_SIGN_HASHES_FAILURE
);
322 signatureData
.Length
= signatureLen
;
323 signatureData
.Data
= (uint8
*)buf
->data
;
325 cssmRv
= CSSM_CSP_CreateSignatureContext(cspHandle
, sigAlg
, cssmCreds
,
326 cssmKey
, &cssmSignature
);
328 PORT_SetError(SSL_ERROR_SIGN_HASHES_FAILURE
);
332 /* See "Apple Cryptographic Service Provider Functional Specification" */
333 if (cssmKey
->KeyHeader
.AlgorithmId
== CSSM_ALGID_RSA
) {
334 /* To set RSA blinding for RSA keys */
335 CSSM_CONTEXT_ATTRIBUTE blindingAttr
;
336 blindingAttr
.AttributeType
= CSSM_ATTRIBUTE_RSA_BLINDING
;
337 blindingAttr
.AttributeLength
= sizeof(uint32
);
338 blindingAttr
.Attribute
.Uint32
= 1;
339 cssmRv
= CSSM_UpdateContextAttributes(cssmSignature
, 1, &blindingAttr
);
341 PORT_SetError(SSL_ERROR_SIGN_HASHES_FAILURE
);
346 cssmRv
= CSSM_SignData(cssmSignature
, &hashData
, 1, CSSM_ALGID_NONE
,
349 PORT_SetError(SSL_ERROR_SIGN_HASHES_FAILURE
);
352 buf
->len
= signatureData
.Length
;
355 SECItem derSig
= {siBuffer
, NULL
, 0};
357 /* This also works for an ECDSA signature */
358 rv
= DSAU_EncodeDerSigWithLen(&derSig
, buf
, buf
->len
);
359 if (rv
== SECSuccess
) {
360 PORT_Free(buf
->data
); /* discard unencoded signature. */
361 *buf
= derSig
; /* give caller encoded signature. */
362 } else if (derSig
.data
) {
363 PORT_Free(derSig
.data
);
369 PRINT_BUF(60, (NULL
, "signed hashes", buf
->data
, buf
->len
));
371 /* cspHandle, cssmKey, and cssmCreds are owned by the SecKeyRef and
372 * should not be freed. When the PlatformKey is freed, they will be
376 CSSM_DeleteContext(cssmSignature
);
378 if (rv
!= SECSuccess
&& buf
->data
) {
379 PORT_Free(buf
->data
);
386 ssl_FreePlatformKey(PlatformKey key
)
391 ssl3_PlatformSignHashes(SSL3Hashes
*hash
, PlatformKey key
, SECItem
*buf
,
394 PORT_SetError(PR_NOT_IMPLEMENTED_ERROR
);
399 #endif /* NSS_PLATFORM_CLIENT_AUTH */