Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(325)

Side by Side Diff: net/third_party/nss/ssl/sslplatf.c

Issue 3455019: Support for using OS-native certificates for SSL client auth.... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Upload before checkin Created 10 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « net/third_party/nss/ssl/sslnonce.c ('k') | net/third_party/nss/ssl/sslsnce.c » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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 "ssl.h"
42 #include "certt.h"
43 #include "keythi.h"
44 #include "sslimpl.h"
45 #include "cryptohi.h"
46 #include "secitem.h"
47
48 #ifdef NSS_PLATFORM_CLIENT_AUTH
49 CERTCertificateList*
50 hack_NewCertificateListFromCertList(CERTCertList* list)
51 {
52 CERTCertificateList * chain = NULL;
53 PRArenaPool * arena = NULL;
54 CERTCertListNode * node;
55 int len;
56
57 if (CERT_LIST_EMPTY(list))
58 goto loser;
59
60 arena = PORT_NewArena(4096);
61 if (arena == NULL)
62 goto loser;
63
64 for (len = 0, node = CERT_LIST_HEAD(list); !CERT_LIST_END(node, list);
65 len++, node = CERT_LIST_NEXT(node)) {
66 }
67
68 chain = PORT_ArenaNew(arena, CERTCertificateList);
69 if (chain == NULL)
70 goto loser;
71
72 chain->certs = PORT_ArenaNewArray(arena, SECItem, len);
73 if (!chain->certs)
74 goto loser;
75 chain->len = len;
76
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) {
84 chain->len = len;
85 break;
86 }
87 SECITEM_CopyItem(arena, &chain->certs[len], &node->cert->derCert);
88 }
89
90 chain->arena = arena;
91 return chain;
92
93 loser:
94 if (arena) {
95 PORT_FreeArena(arena, PR_FALSE);
96 }
97 return NULL;
98 }
99
100 #if defined(XP_WIN32)
101 void
102 ssl_FreePlatformKey(PlatformKey key)
103 {
104 CryptReleaseContext(key, 0);
105 }
106
107 void
108 ssl_FreePlatformAuthInfo(PlatformAuthInfo* info)
109 {
110 if (info->provider != NULL) {
111 PORT_Free(info->provider);
112 info->provider = NULL;
113 }
114 if (info->container != NULL) {
115 PORT_Free(info->container);
116 info->container = NULL;
117 }
118 info->provType = 0;
119 }
120
121 void
122 ssl_InitPlatformAuthInfo(PlatformAuthInfo* info)
123 {
124 info->provider = NULL;
125 info->container = NULL;
126 info->provType = 0;
127 }
128
129 PRBool
130 ssl_PlatformAuthTokenPresent(PlatformAuthInfo *info)
131 {
132 HCRYPTPROV prov = 0;
133
134 if (!info || !info->provider || !info->container)
135 return PR_FALSE;
136
137 if (!CryptAcquireContextA(&prov, info->container, info->provider,
138 info->provType, 0))
139 return PR_FALSE;
140
141 CryptReleaseContext(prov, 0);
142 return PR_TRUE;
143 }
144
145 void
146 ssl_GetPlatformAuthInfoForKey(PlatformKey key,
147 PlatformAuthInfo *info)
148 {
149 DWORD bytesNeeded = 0;
150 ssl_InitPlatformAuthInfo(info);
151 bytesNeeded = sizeof(info->provType);
152 if (!CryptGetProvParam(key, PP_PROVTYPE, (BYTE*)&info->provType,
153 &bytesNeeded, 0))
154 goto error;
155
156 bytesNeeded = 0;
157 if (!CryptGetProvParam(key, PP_CONTAINER, NULL, &bytesNeeded, 0))
158 goto error;
159 info->container = (char*)PORT_Alloc(bytesNeeded);
160 if (info->container == NULL)
161 goto error;
162 if (!CryptGetProvParam(key, PP_CONTAINER, (BYTE*)info->container,
163 &bytesNeeded, 0))
164 goto error;
165
166 bytesNeeded = 0;
167 if (!CryptGetProvParam(key, PP_NAME, NULL, &bytesNeeded, 0))
168 goto error;
169 info->provider = (char*)PORT_Alloc(bytesNeeded);
170 if (info->provider == NULL)
171 goto error;
172 if (!CryptGetProvParam(key, PP_NAME, (BYTE*)info->provider,
173 &bytesNeeded, 0))
174 goto error;
175
176 goto done;
177 error:
178 ssl_FreePlatformAuthInfo(info);
179
180 done:
181 return;
182 }
183
184 SECStatus
185 ssl3_PlatformSignHashes(SSL3Hashes *hash, PlatformKey key, SECItem *buf,
186 PRBool isTLS)
187 {
188 SECStatus rv = SECFailure;
189 PRBool doDerEncode = PR_FALSE;
190 SECItem hashItem;
191 /* TODO(rsleevi): Should AT_SIGNATURE also be checked if doing client
192 * auth?
193 */
194 DWORD keySpec = AT_KEYEXCHANGE;
195 HCRYPTKEY hKey = 0;
196 DWORD argLen = 0;
197 ALG_ID keyAlg = 0;
198 DWORD signatureLen = 0;
199 ALG_ID hashAlg = 0;
200 HCRYPTHASH hHash = 0;
201 DWORD hashLen = 0;
202 unsigned int i = 0;
203
204 buf->data = NULL;
205 if (!CryptGetUserKey(key, keySpec, &hKey)) {
206 PORT_SetError(SEC_ERROR_INVALID_KEY);
207 goto done;
208 }
209
210 argLen = sizeof(keyAlg);
211 if (!CryptGetKeyParam(hKey, KP_ALGID, (BYTE*)&keyAlg, &argLen, 0)) {
212 PORT_SetError(SEC_ERROR_INVALID_KEY);
213 goto done;
214 }
215
216 switch (keyAlg) {
217 case CALG_RSA_KEYX:
218 case CALG_RSA_SIGN:
219 hashAlg = CALG_SSL3_SHAMD5;
220 hashItem.data = hash->md5;
221 hashItem.len = sizeof(SSL3Hashes);
222 break;
223 case CALG_DSS_SIGN:
224 /* TODO: Support CALG_ECDSA once tested */
225 case CALG_ECDSA:
226 if (keyAlg == CALG_ECDSA) {
227 doDerEncode = PR_TRUE;
228 } else {
229 doDerEncode = isTLS;
230 }
231 hashAlg = CALG_SHA1;
232 hashItem.data = hash->sha;
233 hashItem.len = sizeof(hash->sha);
234 break;
235 default:
236 PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG);
237 goto done;
238 }
239 PRINT_BUF(60, (NULL, "hash(es) to be signed", hashItem.data, hashItem.len));
240
241 if (!CryptCreateHash(key, hashAlg, 0, 0, &hHash)) {
242 ssl_MapLowLevelError(SSL_ERROR_SIGN_HASHES_FAILURE);
243 goto done;
244 }
245 argLen = sizeof(hashLen);
246 if (!CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE*)&hashLen, &argLen, 0)) {
247 ssl_MapLowLevelError(SSL_ERROR_SIGN_HASHES_FAILURE);
248 goto done;
249 }
250 if (hashLen != hashItem.len) {
251 ssl_MapLowLevelError(SSL_ERROR_SIGN_HASHES_FAILURE);
252 goto done;
253 }
254 if (!CryptSetHashParam(hHash, HP_HASHVAL, (BYTE*)hashItem.data, 0)) {
255 ssl_MapLowLevelError(SSL_ERROR_SIGN_HASHES_FAILURE);
256 goto done;
257 }
258 if (!CryptSignHash(hHash, keySpec, NULL, CRYPT_NOHASHOID,
259 NULL, &signatureLen) || signatureLen == 0) {
260 ssl_MapLowLevelError(SSL_ERROR_SIGN_HASHES_FAILURE);
261 goto done;
262 }
263 buf->len = signatureLen;
264 buf->data = (unsigned char *)PORT_Alloc(signatureLen);
265 if (!buf->data)
266 goto done; /* error code was set. */
267
268 if (!CryptSignHash(hHash, keySpec, NULL, CRYPT_NOHASHOID,
269 (BYTE*)buf->data, &signatureLen)) {
270 ssl_MapLowLevelError(SSL_ERROR_SIGN_HASHES_FAILURE);
271 goto done;
272 }
273
274 /* CryptoAPI signs in little-endian, so reverse */
275 for (i = 0; i < buf->len / 2; ++i) {
276 unsigned char tmp = buf->data[i];
277 buf->data[i] = buf->data[buf->len - 1 - i];
278 buf->data[buf->len - 1 - i] = tmp;
279 }
280 if (doDerEncode) {
281 SECItem derSig = {siBuffer, NULL, 0};
282
283 /* This also works for an ECDSA signature */
284 rv = DSAU_EncodeDerSigWithLen(&derSig, buf, buf->len);
285 if (rv == SECSuccess) {
286 PORT_Free(buf->data); /* discard unencoded signature. */
287 *buf = derSig; /* give caller encoded signature. */
288 } else if (derSig.data) {
289 PORT_Free(derSig.data);
290 }
291 }
292
293 PRINT_BUF(60, (NULL, "signed hashes", buf->data, buf->len));
294 rv = SECSuccess;
295 done:
296 if (hHash)
297 CryptDestroyHash(hHash);
298 if (hKey)
299 CryptDestroyKey(hKey);
300 if (rv != SECSuccess && buf->data) {
301 PORT_Free(buf->data);
302 buf->data = NULL;
303 }
304 return rv;
305 }
306
307 #elif defined(XP_MACOSX)
308 #include <Security/cssm.h>
309
310 /*
311 * In Mac OS X 10.5, these two functions are private but implemented, and
312 * in Mac OS X 10.6, these are exposed publicly. To compile with the 10.5
313 * SDK, we declare them here.
314 */
315 OSStatus SecKeychainItemCreatePersistentReference(SecKeychainItemRef itemRef, CF DataRef *persistentItemRef);
316 OSStatus SecKeychainItemCopyFromPersistentReference(CFDataRef persistentItemRef, SecKeychainItemRef *itemRef);
317
318 void
319 ssl_FreePlatformKey(PlatformKey key)
320 {
321 CFRelease(key);
322 }
323
324 void
325 ssl_FreePlatformAuthInfo(PlatformAuthInfo* info)
326 {
327 if (info->keychain != NULL) {
328 CFRelease(info->keychain);
329 info->keychain = NULL;
330 }
331 if (info->persistentKey != NULL) {
332 CFRelease(info->persistentKey);
333 info->persistentKey = NULL;
334 }
335 }
336
337 void
338 ssl_InitPlatformAuthInfo(PlatformAuthInfo* info)
339 {
340 info->keychain = NULL;
341 info->persistentKey = NULL;
342 }
343
344 PRBool
345 ssl_PlatformAuthTokenPresent(PlatformAuthInfo* info)
346 {
347 if (!info || !info->keychain || !info->persistentKey)
348 return PR_FALSE;
349
350 // Not actually interested in the status, but it can be used to make sure
351 // that the keychain still exists (as smart card ejection will remove
352 // the keychain)
353 SecKeychainStatus keychainStatus;
354 OSStatus rv = SecKeychainGetStatus(info->keychain, &keychainStatus);
355 if (rv != noErr)
356 return PR_FALSE;
357
358 // Make sure the individual key still exists within the keychain, if
359 // the keychain is present
360 SecKeychainItemRef keychainItem;
361 rv = SecKeychainItemCopyFromPersistentReference(info->persistentKey,
362 &keychainItem);
363 if (rv != noErr)
364 return PR_FALSE;
365
366 CFRelease(keychainItem);
367 return PR_TRUE;
368 }
369
370 void
371 ssl_GetPlatformAuthInfoForKey(PlatformKey key,
372 PlatformAuthInfo *info)
373 {
374 SecKeychainItemRef keychainItem = (SecKeychainItemRef)key;
375 OSStatus rv = SecKeychainItemCopyKeychain(keychainItem, &info->keychain);
376 if (rv == noErr) {
377 rv = SecKeychainItemCreatePersistentReference(keychainItem,
378 &info->persistentKey);
379 }
380 if (rv != noErr) {
381 ssl_FreePlatformAuthInfo(info);
382 }
383 return;
384 }
385
386 SECStatus
387 ssl3_PlatformSignHashes(SSL3Hashes *hash, PlatformKey key, SECItem *buf,
388 PRBool isTLS)
389 {
390 SECStatus rv = SECFailure;
391 PRBool doDerEncode = PR_FALSE;
392 unsigned int signatureLen;
393 OSStatus status = noErr;
394 CSSM_CSP_HANDLE cspHandle = 0;
395 const CSSM_KEY *cssmKey = NULL;
396 CSSM_ALGORITHMS sigAlg;
397 const CSSM_ACCESS_CREDENTIALS * cssmCreds = NULL;
398 CSSM_RETURN cssmRv;
399 CSSM_DATA hashData;
400 CSSM_DATA signatureData;
401 CSSM_CC_HANDLE cssmSignature = 0;
402
403 buf->data = NULL;
404
405 status = SecKeyGetCSPHandle(key, &cspHandle);
406 if (status != noErr) {
407 PORT_SetError(SEC_ERROR_INVALID_KEY);
408 goto done;
409 }
410
411 status = SecKeyGetCSSMKey(key, &cssmKey);
412 if (status != noErr || !cssmKey) {
413 PORT_SetError(SEC_ERROR_INVALID_KEY);
414 goto done;
415 }
416
417 /* SecKeyGetBlockSize wasn't addeded until OS X 10.6 - but the
418 * needed information is readily available on the key itself.
419 */
420 signatureLen = (cssmKey->KeyHeader.LogicalKeySizeInBits + 7) / 8;
421
422 if (signatureLen == 0) {
423 PORT_SetError(SEC_ERROR_INVALID_KEY);
424 goto done;
425 }
426
427 buf->len = signatureLen;
428 buf->data = (unsigned char *)PORT_Alloc(signatureLen);
429 if (!buf->data)
430 goto done; /* error code was set. */
431
432 sigAlg = cssmKey->KeyHeader.AlgorithmId;
433 switch (sigAlg) {
434 case CSSM_ALGID_RSA:
435 hashData.Data = hash->md5;
436 hashData.Length = sizeof(SSL3Hashes);
437 break;
438 case CSSM_ALGID_ECDSA:
439 case CSSM_ALGID_DSA:
440 if (sigAlg == CSSM_ALGID_ECDSA) {
441 doDerEncode = PR_TRUE;
442 } else {
443 doDerEncode = isTLS;
444 }
445 hashData.Data = hash->sha;
446 hashData.Length = sizeof(hash->sha);
447 break;
448 default:
449 PORT_SetError(SEC_ERROR_INVALID_KEY);
450 goto done;
451 }
452 PRINT_BUF(60, (NULL, "hash(es) to be signed", hashData.Data, hashData.Length ));
453
454 /* TODO(rsleevi): Should it be kSecCredentialTypeNoUI? In Win32, at least,
455 * you can prevent the UI by setting the provider handle on the
456 * certificate to be opened with CRYPT_SILENT, but is there an equivalent?
457 */
458 status = SecKeyGetCredentials(key, CSSM_ACL_AUTHORIZATION_SIGN,
459 kSecCredentialTypeDefault, &cssmCreds);
460 if (status != noErr) {
461 ssl_MapLowLevelError(SSL_ERROR_SIGN_HASHES_FAILURE);
462 goto done;
463 }
464
465 signatureData.Length = buf->len;
466 signatureData.Data = (uint8*)buf->data;
467
468 cssmRv = CSSM_CSP_CreateSignatureContext(cspHandle, sigAlg, cssmCreds,
469 cssmKey, &cssmSignature);
470 if (cssmRv) {
471 ssl_MapLowLevelError(SSL_ERROR_SIGN_HASHES_FAILURE);
472 goto done;
473 }
474
475 /* See "Apple Cryptographic Service Provider Functional Specification" */
476 if (cssmKey->KeyHeader.AlgorithmId == CSSM_ALGID_RSA) {
477 /* To set RSA blinding for RSA keys */
478 CSSM_CONTEXT_ATTRIBUTE blindingAttr;
479 blindingAttr.AttributeType = CSSM_ATTRIBUTE_RSA_BLINDING;
480 blindingAttr.AttributeLength = sizeof(uint32);
481 blindingAttr.Attribute.Uint32 = 1;
482 cssmRv = CSSM_UpdateContextAttributes(cssmSignature, 1, &blindingAttr);
483 if (cssmRv) {
484 ssl_MapLowLevelError(SSL_ERROR_SIGN_HASHES_FAILURE);
485 goto done;
486 }
487 }
488
489 cssmRv = CSSM_SignData(cssmSignature, &hashData, 1, CSSM_ALGID_NONE,
490 &signatureData);
491 if (cssmRv) {
492 ssl_MapLowLevelError(SSL_ERROR_SIGN_HASHES_FAILURE);
493 goto done;
494 }
495
496 if (doDerEncode) {
497 SECItem derSig = {siBuffer, NULL, 0};
498
499 /* This also works for an ECDSA signature */
500 rv = DSAU_EncodeDerSigWithLen(&derSig, buf, buf->len);
501 if (rv == SECSuccess) {
502 PORT_Free(buf->data); /* discard unencoded signature. */
503 *buf = derSig; /* give caller encoded signature. */
504 } else if (derSig.data) {
505 PORT_Free(derSig.data);
506 }
507 }
508
509 PRINT_BUF(60, (NULL, "signed hashes", buf->data, buf->len));
510 rv = SECSuccess;
511 done:
512 /* cspHandle, cssmKey, and cssmCreds are owned by the SecKeyRef and
513 * should not be freed. When the PlatformKey is freed, they will be
514 * released.
515 */
516 if (cssmSignature)
517 CSSM_DeleteContext(cssmSignature);
518
519 if (rv != SECSuccess && buf->data) {
520 PORT_Free(buf->data);
521 buf->data = NULL;
522 }
523 return rv;
524 }
525 #else
526 void
527 ssl_FreePlatformKey(PlatformKey key)
528 {
529 }
530
531 void
532 ssl_FreePlatformAuthInfo(PlatformAuthInfo *info)
533 {
534 }
535
536 void
537 ssl_InitPlatformAuthInfo(PlatformAuthInfo *info)
538 {
539 }
540
541 PRBool
542 ssl_PlatformAuthTokenPresent(PlatformAuthInfo *info)
543 {
544 return PR_FALSE;
545 }
546
547 void
548 ssl_GetPlatformAuthInfoForKey(PlatformKey key, PlatformAuthInfo *info)
549 {
550 }
551
552 SECStatus
553 ssl3_PlatformSignHashes(SSL3Hashes *hash, PlatformKey key, SECItem *buf,
554 PRBool isTLS)
555 {
556 PORT_SetError(PR_NOT_IMPLEMENTED_ERROR);
557 return SECFailure;
558 }
559 #endif
560
561 #endif /* NSS_PLATFORM_CLIENT_AUTH */
OLDNEW
« no previous file with comments | « net/third_party/nss/ssl/sslnonce.c ('k') | net/third_party/nss/ssl/sslsnce.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698