OLD | NEW |
| (Empty) |
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@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 */ | |
OLD | NEW |