]> git.saurik.com Git - apple/security.git/blob - libsecurity_ssl/lib/appleCdsa.c
Security-55471.14.tar.gz
[apple/security.git] / libsecurity_ssl / lib / appleCdsa.c
1 /*
2 * Copyright (c) 2000-2001,2005-2008,2010-2012 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /*
25 * appleCdsa.c - CDSA based implementation of sslCrypto.h interfaces.
26 */
27
28 #include "ssl.h"
29 #if USE_CDSA_CRYPTO
30
31 #include "appleCdsa.h"
32 #include "sslCrypto.h"
33
34 #include "CipherSuite.h"
35 #include "sslContext.h"
36 #include "sslMemory.h"
37 #include "sslUtils.h"
38 #include "sslDebug.h"
39 #include "sslBER.h"
40 #include "ModuleAttacher.h"
41
42 #ifndef _SSL_KEYCHAIN_H_
43 #include "sslKeychain.h"
44 #endif
45
46 #include <string.h>
47 #include <stdlib.h>
48 #include <assert.h>
49
50 #include <Security/cssm.h>
51 #include <Security/cssmapple.h>
52 #include <Security/Security.h>
53 #include <Security/SecTrustPriv.h>
54 #include <Security/SecPolicyPriv.h>
55 #include <Security/SecKeyPriv.h>
56
57 /* X.509 includes, from cssmapi */
58 #include <Security/x509defs.h> /* x.509 function and type defs */
59 #include <Security/oidsalg.h>
60 #include <Security/oidscert.h>
61
62 // MARK: -
63 // MARK: Utilities
64
65 /*
66 * Set up a Raw symmetric key with specified algorithm and key bits.
67 */
68 OSStatus sslSetUpSymmKey(
69 CSSM_KEY_PTR symKey,
70 CSSM_ALGORITHMS alg,
71 CSSM_KEYUSE keyUse, // CSSM_KEYUSE_ENCRYPT, etc.
72 CSSM_BOOL copyKey, // true: copy keyData false: set by reference
73 uint8 *keyData,
74 size_t keyDataLen) // in bytes
75 {
76 OSStatus serr;
77 CSSM_KEYHEADER *hdr;
78
79 memset(symKey, 0, sizeof(CSSM_KEY));
80 if(copyKey) {
81 serr = stSetUpCssmData(&symKey->KeyData, keyDataLen);
82 if(serr) {
83 return serr;
84 }
85 memmove(symKey->KeyData.Data, keyData, keyDataLen);
86 }
87 else {
88 symKey->KeyData.Data = keyData;
89 symKey->KeyData.Length = keyDataLen;
90 }
91
92 /* set up the header */
93 hdr = &symKey->KeyHeader;
94 hdr->BlobType = CSSM_KEYBLOB_RAW;
95 hdr->Format = CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING;
96 hdr->AlgorithmId = alg;
97 hdr->KeyClass = CSSM_KEYCLASS_SESSION_KEY;
98 hdr->LogicalKeySizeInBits = keyDataLen * 8;
99 hdr->KeyAttr = CSSM_KEYATTR_MODIFIABLE | CSSM_KEYATTR_EXTRACTABLE;
100 hdr->KeyUsage = keyUse;
101 hdr->WrapAlgorithmId = CSSM_ALGID_NONE;
102 return errSecSuccess;
103 }
104
105 /*
106 * Free a CSSM_KEY - its CSP resources, KCItemRef, and the key itself.
107 */
108 OSStatus sslFreeKey(
109 CSSM_CSP_HANDLE cspHand,
110 CSSM_KEY_PTR *key, /* so we can null it out */
111 #if ST_KC_KEYS_NEED_REF
112 SecKeychainRef *kcItem)
113 #else
114 void *kcItem)
115 #endif
116 {
117 assert(key != NULL);
118
119 if(*key != NULL) {
120 if(cspHand != 0) {
121 CSSM_FreeKey(cspHand, NULL, *key, CSSM_FALSE);
122 }
123 stAppFree(*key, NULL); // key mallocd by CL using our callback
124 *key = NULL;
125 }
126 #if ST_KC_KEYS_NEED_REF
127 if((kcItem != NULL) && (*kcItem != NULL)) {
128 KCReleaseItem(kcItem); /* does this NULL the referent? */
129 *kcItem = NULL;
130 }
131 #endif
132 return errSecSuccess;
133 }
134
135 /*
136 * Standard app-level memory functions required by CDSA.
137 */
138 void * stAppMalloc (size_t size, void *allocRef) {
139 return( malloc(size) );
140 }
141 void stAppFree (void *mem_ptr, void *allocRef) {
142 free(mem_ptr);
143 return;
144 }
145 void * stAppRealloc (void *ptr, size_t size, void *allocRef) {
146 return( realloc( ptr, size ) );
147 }
148 void * stAppCalloc (uint32_t num, size_t size, void *allocRef) {
149 return( calloc( num, size ) );
150 }
151
152 /*
153 * Ensure there's a connection to ctx->cspHand. If there
154 * already is one, fine.
155 * Note that as of 12/18/00, we assume we're connected to
156 * all modules all the time (since we do an attachToAll() in
157 * SSLNewContext()).
158 */
159 OSStatus attachToCsp(SSLContext *ctx)
160 {
161 assert(ctx != NULL);
162 if(ctx->cspHand != 0) {
163 return errSecSuccess;
164 }
165 else {
166 return errSSLModuleAttach;
167 }
168 }
169
170 /*
171 * Connect to TP, CL; reusable.
172 */
173 OSStatus attachToCl(SSLContext *ctx)
174 {
175 assert(ctx != NULL);
176 if(ctx->clHand != 0) {
177 return errSecSuccess;
178 }
179 else {
180 return errSSLModuleAttach;
181 }
182 }
183
184 OSStatus attachToTp(SSLContext *ctx)
185 {
186 assert(ctx != NULL);
187 if(ctx->tpHand != 0) {
188 return errSecSuccess;
189 }
190 else {
191 return errSSLModuleAttach;
192 }
193 }
194
195 /*
196 * Convenience function - attach to CSP, CL, TP. Reusable.
197 */
198 OSStatus attachToAll(SSLContext *ctx)
199 {
200 CSSM_RETURN crtn;
201
202 assert(ctx != NULL);
203 crtn = attachToModules(&ctx->cspHand, &ctx->clHand, &ctx->tpHand);
204 if(crtn) {
205 return errSSLModuleAttach;
206 }
207 else {
208 return errSecSuccess;
209 }
210 }
211
212 OSStatus detachFromAll(SSLContext *ctx)
213 {
214 #if 0
215 /* No more, attachments are kept on a global basis */
216 assert(ctx != NULL);
217 if(ctx->cspHand != 0) {
218 CSSM_ModuleDetach(ctx->cspHand);
219 ctx->cspHand = 0;
220 }
221 if(ctx->tpHand != 0) {
222 CSSM_ModuleDetach(ctx->tpHand);
223 ctx->tpHand = 0;
224 }
225 if(ctx->clHand != 0) {
226 CSSM_ModuleDetach(ctx->clHand);
227 ctx->clHand = 0;
228 }
229 #endif /* 0 */
230 return errSecSuccess;
231 }
232
233 /*
234 * Add a CSSM_ATTRIBUTE_RSA_BLINDING attribute to
235 * specified crypto context.
236 */
237 static CSSM_RETURN sslAddBlindingAttr(
238 CSSM_CC_HANDLE ccHand)
239 {
240 CSSM_CONTEXT_ATTRIBUTE newAttr;
241 CSSM_RETURN crtn;
242
243 newAttr.AttributeType = CSSM_ATTRIBUTE_RSA_BLINDING;
244 newAttr.AttributeLength = sizeof(uint32_t);
245 newAttr.Attribute.Uint32 = 1;
246 crtn = CSSM_UpdateContextAttributes(ccHand, 1, &newAttr);
247 if(crtn) {
248 stPrintCdsaError("CSSM_UpdateContextAttributes", crtn);
249 }
250 return crtn;
251 }
252
253 /* Get CSP, key in CSSM format from a SecKeyRef */
254 static OSStatus sslGetKeyParts(
255 SecKeyRef keyRef,
256 const CSSM_KEY **cssmKey,
257 CSSM_CSP_HANDLE *cspHand)
258 {
259 OSStatus ortn = SecKeyGetCSSMKey(keyRef, cssmKey);
260 if(ortn) {
261 sslErrorLog("sslGetKeyParts: SecKeyGetCSSMKey err %d\n",
262 (int)ortn);
263 return ortn;
264 }
265 ortn = SecKeyGetCSPHandle(keyRef, cspHand);
266 if(ortn) {
267 sslErrorLog("sslGetKeyParts: SecKeyGetCSPHandle err %d\n",
268 (int)ortn);
269 }
270 return ortn;
271 }
272
273 /* Return the first certificate reference from the supplied array
274 * whose data matches the given certificate, or NULL if none match.
275 */
276 static SecCertificateRef sslGetMatchingCertInArray(
277 SecCertificateRef certRef,
278 CFArrayRef certArray)
279 {
280 CSSM_DATA certData;
281 OSStatus ortn;
282 int idx, count;
283
284 if(certRef == NULL || certArray == NULL) {
285 return NULL;
286 }
287 ortn = SecCertificateGetData(certRef, &certData);
288 if(!ortn) {
289 count = CFArrayGetCount(certArray);
290 for(idx=0; idx<count; idx++) {
291 CSSM_DATA aData = { 0, NULL };
292 SecCertificateRef aCert = (SecCertificateRef)CFArrayGetValueAtIndex(certArray, idx);
293 ortn = SecCertificateGetData(aCert, &aData);
294 if (!ortn && aData.Length == certData.Length &&
295 !memcmp(aData.Data, certData.Data, certData.Length)) {
296 return aCert;
297 }
298 }
299 }
300 return NULL;
301 }
302
303 // MARK: -
304 // MARK: CSSM_DATA routines
305
306 CSSM_DATA_PTR stMallocCssmData(
307 size_t size)
308 {
309 CSSM_DATA_PTR rtn = (CSSM_DATA_PTR)stAppMalloc(sizeof(CSSM_DATA), NULL);
310
311 if(rtn == NULL) {
312 return NULL;
313 }
314 rtn->Length = size;
315 if(size == 0) {
316 rtn->Data = NULL;
317 }
318 else {
319 rtn->Data = (uint8 *)stAppMalloc(size, NULL);
320 }
321 return rtn;
322 }
323
324 void stFreeCssmData(
325 CSSM_DATA_PTR data,
326 CSSM_BOOL freeStruct)
327 {
328 if(data == NULL) {
329 return;
330 }
331 if(data->Data != NULL) {
332 stAppFree(data->Data, NULL);
333 data->Data = NULL;
334 }
335 data->Length = 0;
336 if(freeStruct) {
337 stAppFree(data, NULL);
338 }
339 }
340
341 /*
342 * Ensure that indicated CSSM_DATA_PTR can handle 'length' bytes of data.
343 * Malloc the Data ptr if necessary.
344 */
345 OSStatus stSetUpCssmData(
346 CSSM_DATA_PTR data,
347 size_t length)
348 {
349 assert(data != NULL);
350 if(data->Length == 0) {
351 data->Data = (uint8 *)stAppMalloc(length, NULL);
352 if(data->Data == NULL) {
353 return errSecAllocate;
354 }
355 }
356 else if(data->Length < length) {
357 sslErrorLog("stSetUpCssmData: length too small\n");
358 return errSecAllocate;
359 }
360 data->Length = length;
361 return errSecSuccess;
362 }
363
364 /* All signature ops are "raw", with digest step done by us */
365 static OSStatus sslKeyToSigAlg(
366 const CSSM_KEY *cssmKey,
367 CSSM_ALGORITHMS *sigAlg) /* RETURNED */
368
369 {
370 OSStatus ortn = errSecSuccess;
371 switch(cssmKey->KeyHeader.AlgorithmId) {
372 case CSSM_ALGID_RSA:
373 *sigAlg = CSSM_ALGID_RSA;
374 break;
375 case CSSM_ALGID_DSA:
376 *sigAlg = CSSM_ALGID_DSA;
377 break;
378 case CSSM_ALGID_ECDSA:
379 *sigAlg = CSSM_ALGID_ECDSA;
380 break;
381 default:
382 ortn = errSSLBadConfiguration;
383 break;
384 }
385 return ortn;
386 }
387
388 // MARK: -
389 // MARK: Public CSP Functions
390
391 /*
392 * Raw RSA/DSA sign/verify.
393 */
394 OSStatus sslRawSign(
395 SSLContext *ctx,
396 SecKeyRef privKeyRef,
397 const UInt8 *plainText,
398 size_t plainTextLen,
399 UInt8 *sig, // mallocd by caller; RETURNED
400 size_t sigLen, // available
401 size_t *actualBytes) // RETURNED
402 {
403 CSSM_CC_HANDLE sigHand = 0;
404 CSSM_RETURN crtn;
405 OSStatus serr;
406 CSSM_DATA sigData;
407 CSSM_DATA ptextData;
408 CSSM_CSP_HANDLE cspHand;
409 const CSSM_KEY *privKey;
410 const CSSM_ACCESS_CREDENTIALS *creds;
411
412 assert(ctx != NULL);
413 if((privKeyRef == NULL) ||
414 (plainText == NULL) ||
415 (sig == NULL) ||
416 (actualBytes == NULL)) {
417 sslErrorLog("sslRsaRawSign: bad arguments\n");
418 return errSSLInternal;
419 }
420 *actualBytes = 0;
421
422 /* Get CSP, signing key in CSSM format */
423 serr = sslGetKeyParts(privKeyRef, &privKey, &cspHand);
424 if(serr) {
425 return serr;
426 }
427 assert(privKey->KeyHeader.KeyClass == CSSM_KEYCLASS_PRIVATE_KEY);
428
429 CSSM_ALGORITHMS sigAlg;
430 serr = sslKeyToSigAlg(privKey, &sigAlg);
431 if(serr) {
432 return serr;
433 }
434
435 /*
436 * Get default creds
437 * FIXME: per 3420180, this needs to allow app-specified creds via
438 * an new API
439 */
440 serr = SecKeyGetCredentials(privKeyRef,
441 CSSM_ACL_AUTHORIZATION_SIGN,
442 kSecCredentialTypeDefault,
443 &creds);
444 if(serr) {
445 sslErrorLog("sslRawSign: SecKeyGetCredentials err %lu\n", (unsigned long)serr);
446 return serr;
447 }
448
449 crtn = CSSM_CSP_CreateSignatureContext(cspHand,
450 sigAlg,
451 creds,
452 privKey,
453 &sigHand);
454 if(crtn) {
455 stPrintCdsaError("CSSM_CSP_CreateSignatureContext (1)", crtn);
456 return errSSLCrypto;
457 }
458
459 if((ctx->rsaBlindingEnable) &&
460 (privKey->KeyHeader.AlgorithmId == CSSM_ALGID_RSA)) {
461 /*
462 * Turn on RSA blinding to defeat timing attacks
463 */
464 crtn = sslAddBlindingAttr(sigHand);
465 if(crtn) {
466 return crtn;
467 }
468 }
469
470 ptextData.Data = (uint8 *)plainText;
471 ptextData.Length = plainTextLen;
472
473 /* caller better get this right, or the SignData will fail */
474 sigData.Data = sig;
475 sigData.Length = sigLen;
476
477 crtn = CSSM_SignData(sigHand,
478 &ptextData,
479 1,
480 CSSM_ALGID_NONE, // digestAlg for raw sign
481 &sigData);
482 if(crtn) {
483 stPrintCdsaError("CSSM_SignData", crtn);
484 serr = errSSLCrypto;
485 }
486 else {
487 *actualBytes = sigData.Length;
488 serr = errSecSuccess;
489 }
490 if(sigHand != 0) {
491 CSSM_DeleteContext(sigHand);
492 }
493 return serr;
494 }
495
496 OSStatus sslRawVerify(
497 SSLContext *ctx,
498 const SSLPubKey *sslPubKey,
499 const UInt8 *plainText,
500 size_t plainTextLen,
501 const UInt8 *sig,
502 size_t sigLen)
503 {
504 CSSM_CC_HANDLE sigHand = 0;
505 CSSM_RETURN crtn;
506 OSStatus serr;
507 CSSM_DATA sigData;
508 CSSM_DATA ptextData;
509 const CSSM_KEY *pubKey;
510 CSSM_CSP_HANDLE cspHand;
511
512 assert(ctx != NULL);
513 if((sslPubKey == NULL) ||
514 (sslPubKey->key == NULL) ||
515 (sslPubKey->csp == 0) ||
516 (plainText == NULL) ||
517 (sig == NULL)) {
518 sslErrorLog("sslRawVerify: bad arguments\n");
519 return errSSLInternal;
520 }
521
522 pubKey = &sslPubKey->key;
523 cspHand = sslPubKey->csp;
524
525 CSSM_ALGORITHMS sigAlg;
526 serr = sslKeyToSigAlg(pubKey, &sigAlg);
527 if(serr) {
528 return serr;
529 }
530 crtn = CSSM_CSP_CreateSignatureContext(cspHand,
531 sigAlg,
532 NULL, // passPhrase
533 pubKey,
534 &sigHand);
535 if(sigHand == 0) {
536 stPrintCdsaError("CSSM_CSP_CreateSignatureContext (2)", crtn);
537 return errSSLCrypto;
538 }
539
540 ptextData.Data = (uint8 *)plainText;
541 ptextData.Length = plainTextLen;
542 sigData.Data = (uint8 *)sig;
543 sigData.Length = sigLen;
544
545 crtn = CSSM_VerifyData(sigHand,
546 &ptextData,
547 1,
548 CSSM_ALGID_NONE, // digestAlg
549 &sigData);
550 if(crtn) {
551 stPrintCdsaError("CSSM_VerifyData", crtn);
552 serr = errSSLCrypto;
553 }
554 else {
555 serr = errSecSuccess;
556 }
557 if(sigHand != 0) {
558 CSSM_DeleteContext(sigHand);
559 }
560 return serr;
561 }
562
563 /*
564 * Encrypt/Decrypt
565 */
566 OSStatus sslRsaEncrypt(
567 SSLContext *ctx,
568 const CSSM_KEY *pubKey,
569 CSSM_CSP_HANDLE cspHand,
570 CSSM_PADDING padding, // CSSM_PADDING_PKCS1, CSSM_PADDING_APPLE_SSLv2
571 const UInt8 *plainText,
572 size_t plainTextLen,
573 UInt8 *cipherText, // mallocd by caller; RETURNED
574 size_t cipherTextLen, // available
575 size_t *actualBytes) // RETURNED
576 {
577 CSSM_DATA ctextData = {0, NULL};
578 CSSM_DATA ptextData;
579 CSSM_DATA remData = {0, NULL};
580 CSSM_CC_HANDLE cryptHand = 0;
581 OSStatus serr = errSSLInternal;
582 CSSM_RETURN crtn;
583 size_t bytesMoved = 0;
584 CSSM_ACCESS_CREDENTIALS creds;
585
586 assert(ctx != NULL);
587 assert(actualBytes != NULL);
588 *actualBytes = 0;
589
590 if((pubKey == NULL) || (cspHand == 0)) {
591 sslErrorLog("sslRsaEncrypt: bad pubKey/cspHand\n");
592 return errSSLInternal;
593 }
594 assert(pubKey->KeyHeader.KeyClass == CSSM_KEYCLASS_PUBLIC_KEY);
595
596 #if RSA_PUB_KEY_USAGE_HACK
597 ((CSSM_KEY_PTR)pubKey)->KeyHeader.KeyUsage |= CSSM_KEYUSE_ENCRYPT;
598 #endif
599 memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
600
601 crtn = CSSM_CSP_CreateAsymmetricContext(cspHand,
602 CSSM_ALGID_RSA,
603 &creds,
604 pubKey,
605 padding,
606 &cryptHand);
607 if(crtn) {
608 stPrintCdsaError("CSSM_CSP_CreateAsymmetricContext", crtn);
609 return errSSLCrypto;
610 }
611 ptextData.Data = (uint8 *)plainText;
612 ptextData.Length = plainTextLen;
613
614 /*
615 * Have CSP malloc ciphertext
616 */
617 crtn = CSSM_EncryptData(cryptHand,
618 &ptextData,
619 1,
620 &ctextData,
621 1,
622 &bytesMoved,
623 &remData);
624 if(crtn == CSSM_OK) {
625 /*
626 * ciphertext in both ctextData and remData; ensure it'll fit
627 * in caller's buf & copy
628 */
629 if(bytesMoved > cipherTextLen) {
630 sslErrorLog("sslRsaEncrypt overflow; cipherTextLen %lu bytesMoved %lu\n",
631 cipherTextLen, bytesMoved);
632 serr = errSSLCrypto;
633 }
634 else {
635 size_t toMoveCtext;
636 size_t toMoveRem;
637
638 *actualBytes = bytesMoved;
639 /*
640 * Snag valid data from ctextData - its length or bytesMoved,
641 * whichever is less
642 */
643 if(ctextData.Length > bytesMoved) {
644 /* everything's in ctext */
645 toMoveCtext = bytesMoved;
646 toMoveRem = 0;
647 }
648 else {
649 /* must be some in remData too */
650 toMoveCtext = ctextData.Length;
651 toMoveRem = bytesMoved - toMoveCtext; // remainder
652 }
653 if(toMoveCtext) {
654 memmove(cipherText, ctextData.Data, toMoveCtext);
655 }
656 if(toMoveRem) {
657 memmove(cipherText + toMoveCtext, remData.Data,
658 toMoveRem);
659 }
660 serr = errSecSuccess;
661 }
662 }
663 else {
664 stPrintCdsaError("CSSM_EncryptData", crtn);
665 serr = errSSLCrypto;
666 }
667 if(cryptHand != 0) {
668 CSSM_DeleteContext(cryptHand);
669 }
670
671 /* free data mallocd by CSP */
672 stFreeCssmData(&ctextData, CSSM_FALSE);
673 stFreeCssmData(&remData, CSSM_FALSE);
674 return serr;
675 }
676
677 OSStatus sslRsaDecrypt(
678 SSLContext *ctx,
679 SecKeyRef privKeyRef,
680 CSSM_PADDING padding, // CSSM_PADDING_PKCS1, CSSM_PADDING_APPLE_SSLv2
681 const UInt8 *cipherText,
682 size_t cipherTextLen,
683 UInt8 *plainText, // mallocd by caller; RETURNED
684 size_t plainTextLen, // available
685 size_t *actualBytes) // RETURNED
686 {
687 CSSM_DATA ptextData = {0, NULL};
688 CSSM_DATA ctextData;
689 CSSM_DATA remData = {0, NULL};
690 CSSM_CC_HANDLE cryptHand = 0;
691 OSStatus serr = errSSLInternal;
692 CSSM_RETURN crtn;
693 size_t bytesMoved = 0;
694 CSSM_CSP_HANDLE cspHand;
695 const CSSM_KEY *privKey;
696 const CSSM_ACCESS_CREDENTIALS *creds;
697
698 assert(ctx != NULL);
699 assert(actualBytes != NULL);
700 *actualBytes = 0;
701
702 if(privKeyRef == NULL) {
703 sslErrorLog("sslRsaDecrypt: bad privKey\n");
704 return errSSLInternal;
705 }
706
707 /* Get CSP, signing key in CSSM format */
708 serr = sslGetKeyParts(privKeyRef, &privKey, &cspHand);
709 if(serr) {
710 return serr;
711 }
712 assert(privKey->KeyHeader.KeyClass == CSSM_KEYCLASS_PRIVATE_KEY);
713
714 /*
715 * Get default creds
716 * FIXME: per 3420180, this needs to allow app-specified creds via
717 * an new API
718 */
719 serr = SecKeyGetCredentials(privKeyRef,
720 CSSM_ACL_AUTHORIZATION_DECRYPT,
721 kSecCredentialTypeDefault,
722 &creds);
723 if(serr) {
724 sslErrorLog("sslRsaDecrypt: SecKeyGetCredentials err %lu\n", (unsigned long)serr);
725 return serr;
726 }
727 crtn = CSSM_CSP_CreateAsymmetricContext(cspHand,
728 CSSM_ALGID_RSA,
729 creds,
730 privKey,
731 padding,
732 &cryptHand);
733 if(crtn) {
734 stPrintCdsaError("CSSM_CSP_CreateAsymmetricContext", crtn);
735 return errSSLCrypto;
736 }
737 ctextData.Data = (uint8 *)cipherText;
738 ctextData.Length = cipherTextLen;
739
740 if((ctx->rsaBlindingEnable) &&
741 (privKey->KeyHeader.AlgorithmId == CSSM_ALGID_RSA)) {
742 /*
743 * Turn on RSA blinding to defeat timing attacks
744 */
745 crtn = sslAddBlindingAttr(cryptHand);
746 if(crtn) {
747 return crtn;
748 }
749 }
750
751 /*
752 * Have CSP malloc plaintext
753 */
754 crtn = CSSM_DecryptData(cryptHand,
755 &ctextData,
756 1,
757 &ptextData,
758 1,
759 &bytesMoved,
760 &remData);
761 if(crtn == CSSM_OK) {
762 /*
763 * plaintext in both ptextData and remData; ensure it'll fit
764 * in caller's buf & copy
765 */
766 if(bytesMoved > plainTextLen) {
767 sslErrorLog("sslRsaDecrypt overflow; plainTextLen %lu bytesMoved %lu\n",
768 plainTextLen, bytesMoved);
769 serr = errSSLCrypto;
770 }
771 else {
772 size_t toMovePtext;
773 size_t toMoveRem;
774
775 *actualBytes = bytesMoved;
776 /*
777 * Snag valid data from ptextData - its length or bytesMoved,
778 * whichever is less
779 */
780 if(ptextData.Length > bytesMoved) {
781 /* everything's in ptext */
782 toMovePtext = bytesMoved;
783 toMoveRem = 0;
784 }
785 else {
786 /* must be some in remData too */
787 toMovePtext = ptextData.Length;
788 toMoveRem = bytesMoved - toMovePtext; // remainder
789 }
790 if(toMovePtext) {
791 memmove(plainText, ptextData.Data, toMovePtext);
792 }
793 if(toMoveRem) {
794 memmove(plainText + toMovePtext, remData.Data,
795 toMoveRem);
796 }
797 serr = errSecSuccess;
798 }
799 }
800 else {
801 stPrintCdsaError("CSSM_DecryptData", crtn);
802 serr = errSSLCrypto;
803 }
804 if(cryptHand != 0) {
805 CSSM_DeleteContext(cryptHand);
806 }
807
808 /* free data mallocd by CSP */
809 stFreeCssmData(&ptextData, CSSM_FALSE);
810 stFreeCssmData(&remData, CSSM_FALSE);
811 return serr;
812 }
813
814 /*
815 * Obtain size of key in bytes.
816 */
817 uint32_t sslPrivKeyLengthInBytes(const SSLPrivKey *sslKey)
818 {
819 const CSSM_KEY *cssmKey;
820
821 assert(sslKey != NULL);
822 assert(sslKey->key != NULL);
823 err = SecKeyGetCSSMKey(sslKey->key, &cssmKey);
824 if(err) {
825 sslErrorLog("sslKeyLengthInBytes: SecKeyGetCSSMKey err %d\n", (int)err);
826 return 0;
827 }
828
829 return (((cssmKey->KeyHeader.LogicalKeySizeInBits) + 7) / 8);
830 }
831
832 /*
833 * Obtain size of key in bytes.
834 */
835 uint32_t sslPubKeyLengthInBytes(const SSLPubKey *sslKey)
836 {
837 const CSSM_KEY *cssmKey;
838
839 assert(sslKey != NULL);
840 assert(sslKey->key != NULL);
841
842 return (((sslKey->key.KeyHeader.LogicalKeySizeInBits) + 7) / 8);
843 }
844
845
846 /*
847 * Obtain maximum size of signature in bytes. A bit of a kludge; we could
848 * ask the CSP to do this but that would be kind of expensive.
849 */
850 OSStatus sslGetMaxSigSize(
851 const CSSM_KEY *privKey,
852 uint32_t *maxSigSize)
853 {
854 OSStatus ortn = errSecSuccess;
855 assert(privKey != NULL);
856 assert(privKey->KeyHeader.KeyClass == CSSM_KEYCLASS_PRIVATE_KEY);
857 switch(privKey->KeyHeader.AlgorithmId) {
858 case CSSM_ALGID_RSA:
859 *maxSigSize = sslPrivKeyLengthInBytes(privKey);
860 break;
861 case CSSM_ALGID_DSA:
862 {
863 /* DSA sig is DER sequence of two 160-bit integers */
864 uint32_t sizeOfOneInt;
865 sizeOfOneInt = (160 / 8) + // the raw contents
866 1 + // possible leading zero
867 2; // tag + length (assume DER, not BER)
868 *maxSigSize = (2 * sizeOfOneInt) + 5;
869 break;
870 }
871 default:
872 ortn = errSSLBadConfiguration;
873 break;
874 }
875 return ortn;
876 }
877 /*
878 * Get raw key bits from an RSA public key.
879 */
880 OSStatus sslGetPubKeyBits(
881 SSLContext *ctx,
882 const CSSM_KEY *pubKey,
883 CSSM_CSP_HANDLE cspHand,
884 SSLBuffer *modulus, // data mallocd and RETURNED
885 SSLBuffer *exponent) // data mallocd and RETURNED
886 {
887 CSSM_KEY wrappedKey;
888 CSSM_BOOL didWrap = CSSM_FALSE;
889 const CSSM_KEYHEADER *hdr;
890 SSLBuffer pubKeyBlob;
891 OSStatus srtn;
892
893 assert(ctx != NULL);
894 assert(modulus != NULL);
895 assert(exponent != NULL);
896 assert(pubKey != NULL);
897
898 hdr = &pubKey->KeyHeader;
899 if(hdr->KeyClass != CSSM_KEYCLASS_PUBLIC_KEY) {
900 sslErrorLog("sslGetPubKeyBits: bad keyClass (%ld)\n", (long)hdr->KeyClass);
901 return errSSLInternal;
902 }
903 if(hdr->AlgorithmId != CSSM_ALGID_RSA) {
904 sslErrorLog("sslGetPubKeyBits: bad AlgorithmId (%ld)\n", (long)hdr->AlgorithmId);
905 return errSSLInternal;
906 }
907
908 /* Note currently ALL public keys are raw, obtained from the CL... */
909 assert(hdr->BlobType == CSSM_KEYBLOB_RAW);
910
911 /*
912 * Handle possible reference format - I think it should be in
913 * blob form since it came from the DL, but conversion is
914 * simple.
915 */
916 switch(hdr->BlobType) {
917 case CSSM_KEYBLOB_RAW:
918 /* easy case */
919 CSSM_TO_SSLBUF(&pubKey->KeyData, &pubKeyBlob);
920 break;
921
922 case CSSM_KEYBLOB_REFERENCE:
923
924 sslErrorLog("sslGetPubKeyBits: bad BlobType (%ld)\n",
925 (long)hdr->BlobType);
926 return errSSLInternal;
927
928 #if 0
929 /*
930 * Convert to a blob via "NULL wrap"; no wrapping key,
931 * ALGID_NONE
932 */
933 srtn = attachToCsp(ctx);
934 if(srtn) {
935 return srtn;
936 }
937 memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
938 crtn = CSSM_CSP_CreateSymmetricContext(ctx->cspHand,
939 CSSM_ALGID_NONE,
940 CSSM_ALGMODE_NONE,
941 &creds, // creds
942 pubKey,
943 NULL, // InitVector
944 CSSM_PADDING_NONE,
945 0, // reserved
946 &ccHand);
947 if(crtn) {
948 stPrintCdsaError("sslGetPubKeyBits: CreateSymmetricContext failure", crtn);
949 return errSSLCrypto;
950 }
951 memset(&wrappedKey, 0, sizeof(CSSM_KEY));
952 crtn = CSSM_WrapKey(ccHand,
953 &creds,
954 pubKey,
955 NULL, // descriptiveData
956 &wrappedKey);
957 CSSM_DeleteContext(ccHand);
958 if(crtn) {
959 stPrintCdsaError("CSSM_WrapKey", crtn);
960 return errSSLCrypto;
961 }
962 hdr = &wrappedKey.KeyHeader;
963 if(hdr->BlobType != CSSM_KEYBLOB_RAW) {
964 sslErrorLog("sslGetPubKeyBits: bad BlobType (%ld) after WrapKey\n",
965 hdr->BlobType);
966 return errSSLCrypto;
967 }
968 didWrap = CSSM_TRUE;
969 CSSM_TO_SSLBUF(&wrappedKey.KeyData, &pubKeyBlob);
970 break;
971 #endif /* 0 */
972
973 default:
974 sslErrorLog("sslGetPubKeyBits: bad BlobType (%ld)\n",
975 (long)hdr->BlobType);
976 return errSSLInternal;
977
978 } /* switch BlobType */
979
980 assert(hdr->BlobType == CSSM_KEYBLOB_RAW);
981 srtn = sslDecodeRsaBlob(&pubKeyBlob, modulus, exponent);
982 if(didWrap) {
983 CSSM_FreeKey(ctx->cspHand, NULL, &wrappedKey, CSSM_FALSE);
984 }
985 return srtn;
986 }
987
988 /*
989 * Given raw RSA key bits, cook up a CSSM_KEY_PTR. Used in
990 * Server-initiated key exchange.
991 */
992 OSStatus sslGetPubKeyFromBits(
993 SSLContext *ctx,
994 const SSLBuffer *modulus,
995 const SSLBuffer *exponent,
996 CSSM_KEY_PTR *pubKey, // mallocd and RETURNED
997 CSSM_CSP_HANDLE *cspHand) // RETURNED
998 {
999 CSSM_KEY_PTR key = NULL;
1000 OSStatus serr;
1001 SSLBuffer blob;
1002 CSSM_KEYHEADER_PTR hdr;
1003 CSSM_KEY_SIZE keySize;
1004 CSSM_RETURN crtn;
1005
1006 assert((ctx != NULL) && (modulus != NULL) && (exponent != NULL));
1007 assert((pubKey != NULL) && (cspHand != NULL));
1008
1009 *pubKey = NULL;
1010 *cspHand = 0;
1011
1012 serr = attachToCsp(ctx);
1013 if(serr) {
1014 return serr;
1015 }
1016 serr = sslEncodeRsaBlob(modulus, exponent, &blob);
1017 if(serr) {
1018 return serr;
1019 }
1020
1021 /* the rest is boilerplate, cook up a good-looking public key */
1022 key = (CSSM_KEY_PTR)sslMalloc(sizeof(CSSM_KEY));
1023 if(key == NULL) {
1024 return errSecAllocate;
1025 }
1026 memset(key, 0, sizeof(CSSM_KEY));
1027 hdr = &key->KeyHeader;
1028
1029 hdr->HeaderVersion = CSSM_KEYHEADER_VERSION;
1030 /* key_ptr->KeyHeader.CspId is unknown (remains 0) */
1031 hdr->BlobType = CSSM_KEYBLOB_RAW;
1032 hdr->AlgorithmId = CSSM_ALGID_RSA;
1033 hdr->Format = CSSM_KEYBLOB_RAW_FORMAT_PKCS1;
1034 hdr->KeyClass = CSSM_KEYCLASS_PUBLIC_KEY;
1035 /* comply with ASA requirements */
1036 hdr->KeyUsage = CSSM_KEYUSE_VERIFY;
1037 hdr->KeyAttr = CSSM_KEYATTR_EXTRACTABLE;
1038 /* key_ptr->KeyHeader.StartDate is unknown (remains 0) */
1039 /* key_ptr->KeyHeader.EndDate is unknown (remains 0) */
1040 hdr->WrapAlgorithmId = CSSM_ALGID_NONE;
1041 hdr->WrapMode = CSSM_ALGMODE_NONE;
1042
1043 /* blob->data was mallocd by sslEncodeRsaBlob, pass it over to
1044 * actual key */
1045 SSLBUF_TO_CSSM(&blob, &key->KeyData);
1046
1047 /*
1048 * Get keySizeInBits. This also serves to validate the key blob
1049 * we just cooked up.
1050 */
1051 crtn = CSSM_QueryKeySizeInBits(ctx->cspHand, CSSM_INVALID_HANDLE, key, &keySize);
1052 if(crtn) {
1053 stPrintCdsaError("sslGetPubKeyFromBits: QueryKeySizeInBits\n", crtn);
1054 serr = errSSLCrypto;
1055 goto abort;
1056 }
1057
1058 /* success */
1059 hdr->LogicalKeySizeInBits = keySize.EffectiveKeySizeInBits;
1060 *pubKey = key;
1061 *cspHand = ctx->cspHand;
1062 return errSecSuccess;
1063
1064 abort:
1065 /* note this frees the blob */
1066 sslFreeKey(ctx->cspHand, &key, NULL);
1067 return serr;
1068 }
1069
1070 #ifdef UNUSED_FUNCTIONS
1071 /*
1072 * NULL-unwrap a raw key to a ref key. Caller must free the returned key.
1073 */
1074 static OSStatus sslNullUnwrapKey(
1075 CSSM_CSP_HANDLE cspHand,
1076 CSSM_KEY_PTR rawKey,
1077 CSSM_KEY_PTR refKey)
1078 {
1079 CSSM_DATA descData = {0, 0};
1080 CSSM_RETURN crtn;
1081 CSSM_CC_HANDLE ccHand;
1082 CSSM_ACCESS_CREDENTIALS creds;
1083 CSSM_DATA labelData = {4, (uint8 *)"none"};
1084 uint32 keyAttr;
1085 OSStatus ortn = errSecSuccess;
1086
1087 memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
1088 memset(refKey, 0, sizeof(CSSM_KEY));
1089
1090 crtn = CSSM_CSP_CreateSymmetricContext(cspHand,
1091 CSSM_ALGID_NONE,
1092 CSSM_ALGMODE_NONE,
1093 &creds,
1094 NULL, // unwrappingKey
1095 NULL, // initVector
1096 CSSM_PADDING_NONE,
1097 0, // Params
1098 &ccHand);
1099 if(crtn) {
1100 stPrintCdsaError("sslNullUnwrapKey: CSSM_CSP_CreateSymmetricContext\n", crtn);
1101 return errSSLCrypto;
1102 }
1103
1104 keyAttr = rawKey->KeyHeader.KeyAttr;
1105 keyAttr &= ~(CSSM_KEYATTR_ALWAYS_SENSITIVE | CSSM_KEYATTR_NEVER_EXTRACTABLE |
1106 CSSM_KEYATTR_MODIFIABLE);
1107 keyAttr |= CSSM_KEYATTR_RETURN_REF;
1108 if(rawKey->KeyHeader.KeyClass == CSSM_KEYCLASS_PUBLIC_KEY) {
1109 /* CSP policy */
1110 keyAttr |= CSSM_KEYATTR_EXTRACTABLE;
1111 }
1112 crtn = CSSM_UnwrapKey(ccHand,
1113 NULL, // PublicKey
1114 rawKey,
1115 rawKey->KeyHeader.KeyUsage,
1116 keyAttr,
1117 &labelData,
1118 NULL, // CredAndAclEntry
1119 refKey,
1120 &descData); // required
1121 if(crtn != CSSM_OK) {
1122 stPrintCdsaError("sslNullUnwrapKey: CSSM_UnwrapKey\n", crtn);
1123 ortn = errSSLCrypto;
1124 }
1125 if(CSSM_DeleteContext(ccHand)) {
1126 printf("CSSM_DeleteContext failure\n");
1127 }
1128 return crtn;
1129 }
1130 #endif
1131
1132 /*
1133 * NULL-wrap a ref key to a raw key. Caller must free the returned key.
1134 */
1135 static OSStatus sslNullWrapKey(
1136 CSSM_CSP_HANDLE cspHand,
1137 CSSM_KEY_PTR refKey,
1138 CSSM_KEY_PTR rawKey)
1139 {
1140 CSSM_DATA descData = {0, 0};
1141 CSSM_RETURN crtn;
1142 CSSM_CC_HANDLE ccHand;
1143 CSSM_ACCESS_CREDENTIALS creds;
1144 uint32 keyAttr;
1145 OSStatus ortn = errSecSuccess;
1146
1147 memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
1148 memset(rawKey, 0, sizeof(CSSM_KEY));
1149
1150 crtn = CSSM_CSP_CreateSymmetricContext(cspHand,
1151 CSSM_ALGID_NONE,
1152 CSSM_ALGMODE_NONE,
1153 &creds,
1154 NULL, // unwrappingKey
1155 NULL, // initVector
1156 CSSM_PADDING_NONE,
1157 0, // Params
1158 &ccHand);
1159 if(crtn) {
1160 stPrintCdsaError("sslNullWrapKey: CSSM_CSP_CreateSymmetricContext\n", crtn);
1161 return errSSLCrypto;
1162 }
1163
1164 keyAttr = rawKey->KeyHeader.KeyAttr;
1165 keyAttr &= ~(CSSM_KEYATTR_ALWAYS_SENSITIVE | CSSM_KEYATTR_NEVER_EXTRACTABLE |
1166 CSSM_KEYATTR_MODIFIABLE);
1167 keyAttr |= CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE;
1168 crtn = CSSM_WrapKey(ccHand,
1169 &creds,
1170 refKey,
1171 &descData,
1172 rawKey);
1173 if(crtn != CSSM_OK) {
1174 stPrintCdsaError("sslNullWrapKey: CSSM_WrapKey\n", crtn);
1175 ortn = errSSLCrypto;
1176 }
1177 if(CSSM_DeleteContext(ccHand)) {
1178 printf("CSSM_DeleteContext failure\n");
1179 }
1180 return crtn;
1181 }
1182
1183 // MARK: -
1184 // MARK: Public Certificate Functions
1185
1186 /*
1187 * Given a DER-encoded cert, obtain its public key as a CSSM_KEY_PTR.
1188 * Caller must CSSM_FreeKey and free the CSSM_KEY_PTR itself.
1189 *
1190 * For now, the returned cspHand is a copy of ctx->cspHand, so it
1191 * doesn't have to be detached later - this may change.
1192 *
1193 * Update: since CSSM_CL_CertGetKeyInfo() doesn't provide a means for
1194 * us to tell the CL what CSP to use, we really have no way of knowing
1195 * what is going on here...we return the process-wide (bare) cspHand,
1196 * which is currently always able to deal with this raw public key.
1197 */
1198 OSStatus sslPubKeyFromCert(
1199 SSLContext *ctx,
1200 const SSLBuffer *derCert,
1201 SSLPubKey *pubKey) // RETURNED
1202 {
1203 OSStatus serr;
1204 CSSM_DATA certData;
1205 CSSM_RETURN crtn;
1206
1207 assert(ctx != NULL);
1208 assert(pubKey != NULL);
1209
1210 pubKey->key = NULL;
1211 pubKey->cspHand = 0;
1212
1213 serr = attachToCl(ctx);
1214 if(serr) {
1215 return serr;
1216 }
1217 serr = attachToCsp(ctx);
1218 if(serr) {
1219 return serr;
1220 }
1221 SSLBUF_TO_CSSM(derCert, &certData);
1222 crtn = CSSM_CL_CertGetKeyInfo(ctx->clHand, &certData, &pubKey->key);
1223 if(crtn) {
1224 return errSSLBadCert;
1225 }
1226 else {
1227 pubKey->cspHand = ctx->cspHand;
1228 return errSecSuccess;
1229 }
1230 }
1231
1232 /*
1233 * Release each element in a CFArray.
1234 */
1235 static void sslReleaseArray(
1236 CFArrayRef a)
1237 {
1238 CFIndex num = CFArrayGetCount(a);
1239 CFIndex dex;
1240 for(dex=0; dex<num; dex++) {
1241 CFTypeRef elmt = (CFTypeRef)CFArrayGetValueAtIndex(a, dex);
1242 secdebug("sslcert", "Freeing cert %p", elmt);
1243 CFRelease(elmt);
1244 }
1245 }
1246
1247 /*
1248 * Verify a chain of DER-encoded certs.
1249 * Last cert in the chain is leaf.
1250 *
1251 * If arePeerCerts is true, host name verification is enabled and we
1252 * save the resulting SecTrustRef in ctx->peerSecTrust. Otherwise
1253 * we're just validating our own certs; no host name checking and
1254 * peerSecTrust is transient.
1255 */
1256 OSStatus sslVerifyCertChain(
1257 SSLContext *ctx,
1258 const SSLCertificate *certChain,
1259 bool arePeerCerts)
1260 {
1261 uint32_t numCerts;
1262 int i;
1263 OSStatus serr;
1264 SSLCertificate *c = (SSLCertificate *)certChain;
1265 CSSM_RETURN crtn;
1266 CSSM_APPLE_TP_SSL_OPTIONS sslOpts;
1267 CSSM_APPLE_TP_ACTION_DATA tpActionData;
1268 SecPolicyRef policy = NULL;
1269 SecPolicySearchRef policySearch = NULL;
1270 CFDataRef actionData = NULL;
1271 CSSM_DATA sslOptsData;
1272 CFMutableArrayRef anchors = NULL;
1273 SecCertificateRef cert; // only lives in CFArrayRefs
1274 SecTrustResultType secTrustResult;
1275 CFMutableArrayRef kcList = NULL;
1276 SecTrustRef theTrust = NULL;
1277
1278 if(ctx->peerSecTrust && arePeerCerts) {
1279 /* renegotiate - start with a new SecTrustRef */
1280 CFRelease(ctx->peerSecTrust);
1281 ctx->peerSecTrust = NULL;
1282 }
1283
1284 numCerts = SSLGetCertificateChainLength(certChain);
1285 if(numCerts == 0) {
1286 /* nope */
1287 return errSSLBadCert;
1288 }
1289
1290 /*
1291 * SSLCertificate chain --> CFArrayRef of SecCertificateRefs.
1292 * TP Cert group has root at the end, opposite of
1293 * SSLCertificate chain.
1294 */
1295 CFMutableArrayRef certGroup = CFArrayCreateMutable(NULL, numCerts,
1296 &kCFTypeArrayCallBacks);
1297 if(certGroup == NULL) {
1298 return errSecAllocate;
1299 }
1300 /* subsequent errors to errOut: */
1301
1302 for(i=numCerts-1; i>=0; i--) {
1303 CSSM_DATA cdata;
1304 SSLBUF_TO_CSSM(&c->derCert, &cdata);
1305 serr = SecCertificateCreateFromData(&cdata, CSSM_CERT_X_509v3,
1306 CSSM_CERT_ENCODING_DER, &cert);
1307 if(serr) {
1308 goto errOut;
1309 }
1310 /*
1311 * Can't set a value at index i when there is an empty element
1312 * at i=1!
1313 */
1314 secdebug("sslcert", "Adding cert %p", cert);
1315 CFArrayInsertValueAtIndex(certGroup, 0, cert);
1316 c = c->next;
1317 }
1318
1319 /*
1320 * Cook up an SSL-specific SecPolicyRef. This will persists as part
1321 * of the SecTrustRef object we'll be creating.
1322 */
1323 serr = SecPolicySearchCreate(CSSM_CERT_X_509v3,
1324 &CSSMOID_APPLE_TP_SSL,
1325 NULL,
1326 &policySearch);
1327 if(serr) {
1328 sslErrorLog("***sslVerifyCertChain: SecPolicySearchCreate rtn %d\n",
1329 (int)serr);
1330 goto errOut;
1331 }
1332 serr = SecPolicySearchCopyNext(policySearch, &policy);
1333 if(serr) {
1334 sslErrorLog("***sslVerifyCertChain: SecPolicySearchCopyNext rtn %d\n",
1335 (int)serr);
1336 goto errOut;
1337 }
1338 sslOpts.Version = CSSM_APPLE_TP_SSL_OPTS_VERSION;
1339 if(arePeerCerts) {
1340 sslOpts.ServerNameLen = ctx->peerDomainNameLen;
1341 sslOpts.ServerName = ctx->peerDomainName;
1342 }
1343 else {
1344 sslOpts.ServerNameLen = 0;
1345 sslOpts.ServerName = NULL;
1346 }
1347 sslOpts.Flags = 0;
1348 if(ctx->protocolSide == kSSLServerSide) {
1349 /* we're evaluating a client cert */
1350 sslOpts.Flags |= CSSM_APPLE_TP_SSL_CLIENT;
1351 }
1352 sslOptsData.Data = (uint8 *)&sslOpts;
1353 sslOptsData.Length = sizeof(sslOpts);
1354 serr = SecPolicySetValue(policy, &sslOptsData);
1355 if(serr) {
1356 sslErrorLog("***sslVerifyCertChain: SecPolicySetValue rtn %d\n",
1357 (int)serr);
1358 goto errOut;
1359 }
1360
1361 /* now a SecTrustRef */
1362 serr = SecTrustCreateWithCertificates(certGroup, policy, &theTrust);
1363 if(serr) {
1364 sslErrorLog("***sslVerifyCertChain: SecTrustCreateWithCertificates "
1365 "rtn %d\n", (int)serr);
1366 goto errOut;
1367 }
1368
1369 /* anchors - default, or ours? */
1370 if(ctx->trustedCerts != NULL) {
1371 serr = SecTrustSetAnchorCertificates(theTrust, ctx->trustedCerts);
1372 if(serr) {
1373 sslErrorLog("***sslVerifyCertChain: SecTrustSetAnchorCertificates "
1374 "rtn %d\n", (int)serr);
1375 goto errOut;
1376 }
1377 }
1378 tpActionData.Version = CSSM_APPLE_TP_ACTION_VERSION;
1379 tpActionData.ActionFlags = 0;
1380 if(ctx->allowExpiredCerts) {
1381 tpActionData.ActionFlags |= CSSM_TP_ACTION_ALLOW_EXPIRED;
1382 }
1383 if(ctx->allowExpiredRoots) {
1384 tpActionData.ActionFlags |= CSSM_TP_ACTION_ALLOW_EXPIRED_ROOT;
1385 }
1386 actionData = CFDataCreate(NULL, (UInt8 *)&tpActionData, sizeof(tpActionData));
1387
1388 serr = SecTrustSetParameters(theTrust, CSSM_TP_ACTION_DEFAULT,
1389 actionData);
1390 if(serr) {
1391 sslErrorLog("***sslVerifyCertChain: SecTrustSetParameters rtn %d\n",
1392 (int)serr);
1393 goto errOut;
1394 }
1395
1396 #if 0
1397 /* Disabled for Radar 3421314 */
1398 /*
1399 * Avoid searching user keychains for intermediate certs by specifying
1400 * an empty array of keychains
1401 */
1402 kcList = CFArrayCreateMutable(NULL, 0, NULL);
1403 if(kcList == NULL) {
1404 sslErrorLog("***sslVerifyCertChain: error creating null kcList\n");
1405 serr = errSecAllocate;
1406 goto errOut;
1407 }
1408 serr = SecTrustSetKeychains(theTrust, kcList);
1409 if(serr) {
1410 sslErrorLog("***sslVerifyCertChain: SecTrustSetKeychains rtn %d\n",
1411 (int)serr);
1412 goto errOut;
1413 }
1414 #endif
1415
1416 /*
1417 * Save this no matter what if we're evaluating peer certs.
1418 * We do a retain here so we can unconditionally release theTrust
1419 * at the end of this routine in case of previous error or
1420 * !arePeerCerts.
1421 */
1422 if(arePeerCerts) {
1423 ctx->peerSecTrust = theTrust;
1424 CFRetain(theTrust);
1425 }
1426
1427 if(!ctx->enableCertVerify) {
1428 /* trivial case, this is caller's responsibility */
1429 serr = errSecSuccess;
1430 goto errOut;
1431 }
1432
1433 /*
1434 * If the caller provided a list of trusted leaf certs, check them here
1435 */
1436 if(ctx->trustedLeafCerts) {
1437 if (sslGetMatchingCertInArray((SecCertificateRef)CFArrayGetValueAtIndex(certGroup, 0),
1438 ctx->trustedLeafCerts)) {
1439 serr = errSecSuccess;
1440 goto errOut;
1441 }
1442 }
1443
1444 /*
1445 * Here we go; hand it over to SecTrust/TP.
1446 */
1447 serr = SecTrustEvaluate(theTrust, &secTrustResult);
1448 if(serr) {
1449 sslErrorLog("***sslVerifyCertChain: SecTrustEvaluate rtn %d\n",
1450 (int)serr);
1451 goto errOut;
1452 }
1453 switch(secTrustResult) {
1454 case kSecTrustResultUnspecified:
1455 /* cert chain valid, no special UserTrust assignments */
1456 case kSecTrustResultProceed:
1457 /* cert chain valid AND user explicitly trusts this */
1458 crtn = CSSM_OK;
1459 break;
1460 case kSecTrustResultDeny:
1461 case kSecTrustResultConfirm:
1462 /*
1463 * Cert chain may well have verified OK, but user has flagged
1464 * one of these certs as untrustable.
1465 */
1466 crtn = CSSMERR_TP_NOT_TRUSTED;
1467 break;
1468 default:
1469 {
1470 OSStatus osCrtn;
1471 serr = SecTrustGetCssmResultCode(theTrust, &osCrtn);
1472 if(serr) {
1473 sslErrorLog("***sslVerifyCertChain: SecTrustGetCssmResultCode"
1474 " rtn %d\n", (int)serr);
1475 goto errOut;
1476 }
1477 crtn = osCrtn;
1478 }
1479 }
1480 if(crtn) {
1481 /* get some detailed error info */
1482 switch(crtn) {
1483 case CSSMERR_TP_INVALID_ANCHOR_CERT:
1484 /* root found but we don't trust it */
1485 if(ctx->allowAnyRoot) {
1486 serr = errSecSuccess;
1487 sslErrorLog("***Warning: accepting unknown root cert\n");
1488 }
1489 else {
1490 serr = errSSLUnknownRootCert;
1491 }
1492 break;
1493 case CSSMERR_TP_NOT_TRUSTED:
1494 /* no root, not even in implicit SSL roots */
1495 if(ctx->allowAnyRoot) {
1496 sslErrorLog("***Warning: accepting unverified cert chain\n");
1497 serr = errSecSuccess;
1498 }
1499 else {
1500 serr = errSSLNoRootCert;
1501 }
1502 break;
1503 case CSSMERR_TP_CERT_EXPIRED:
1504 assert(!ctx->allowExpiredCerts);
1505 serr = errSSLCertExpired;
1506 break;
1507 case CSSMERR_TP_CERT_NOT_VALID_YET:
1508 serr = errSSLCertNotYetValid;
1509 break;
1510 case CSSMERR_APPLETP_HOSTNAME_MISMATCH:
1511 serr = errSSLHostNameMismatch;
1512 break;
1513 case errSecInvalidTrustSettings:
1514 /* these get passed along unmodified */
1515 serr = crtn;
1516 break;
1517 default:
1518 stPrintCdsaError("sslVerifyCertChain: SecTrustEvaluate returned",
1519 crtn);
1520 serr = errSSLXCertChainInvalid;
1521 break;
1522 }
1523 } /* SecTrustEvaluate error */
1524
1525 errOut:
1526 /*
1527 * Free up resources - certGroup, policy, etc. Note that most of these
1528 * will actually persist as long as the current SSLContext does since
1529 * peerSecTrust holds references to these.
1530 */
1531 if(policy) {
1532 CFRelease(policy);
1533 }
1534 if(policySearch) {
1535 CFRelease(policySearch);
1536 }
1537 if(actionData) {
1538 CFRelease(actionData);
1539 }
1540 if(anchors) {
1541 sslReleaseArray(anchors);
1542 CFRelease(anchors);
1543 }
1544 if(certGroup) {
1545 sslReleaseArray(certGroup);
1546 CFRelease(certGroup);
1547 }
1548 if(kcList) {
1549 /* empty, no contents to release */
1550 CFRelease(kcList);
1551 }
1552 if(theTrust) {
1553 CFRelease(theTrust);
1554 }
1555 return serr;
1556 }
1557
1558 #ifndef NDEBUG
1559 void stPrintCdsaError(const char *op, CSSM_RETURN crtn)
1560 {
1561 cssmPerror(op, crtn);
1562 }
1563 #endif
1564
1565 // MARK: -
1566 // MARK: Diffie-Hellman Support
1567
1568 /*
1569 * Generate a Diffie-Hellman key pair. Algorithm parameters always
1570 * come from the server, so on client side we have the parameters
1571 * as two SSLBuffers. On server side we have the pre-encoded block
1572 * which comes from ServerDhParams.
1573 */
1574 OSStatus sslDhGenKeyPairClient(
1575 SSLContext *ctx,
1576 const SSLBuffer *prime,
1577 const SSLBuffer *generator,
1578 CSSM_KEY_PTR publicKey, // RETURNED
1579 CSSM_KEY_PTR privateKey) // RETURNED
1580 {
1581 assert((prime->data != NULL) && (generator->data != NULL));
1582 if(prime->data && !generator->data) {
1583 return errSSLProtocol;
1584 }
1585 if(!prime->data && generator->data) {
1586 return errSSLProtocol;
1587 }
1588
1589 SSLBuffer sParam;
1590 OSStatus ortn = sslEncodeDhParams(prime, generator, &sParam);
1591 if(ortn) {
1592 sslErrorLog("***sslDhGenerateKeyPairClient: DH param error\n");
1593 return ortn;
1594 }
1595 ortn = sslDhGenerateKeyPair(ctx, &sParam, prime->length * 8, publicKey, privateKey);
1596 SSLFreeBuffer(&sParam);
1597 return ortn;
1598 }
1599
1600 OSStatus sslDhGenerateKeyPair(
1601 SSLContext *ctx,
1602 const SSLBuffer *paramBlob,
1603 uint32_t keySizeInBits,
1604 CSSM_KEY_PTR publicKey, // RETURNED
1605 CSSM_KEY_PTR privateKey) // RETURNED
1606 {
1607 CSSM_RETURN crtn;
1608 CSSM_CC_HANDLE ccHandle;
1609 CSSM_DATA labelData = {8, (uint8 *)"tempKey"};
1610 OSStatus ortn = errSecSuccess;
1611 CSSM_DATA cParamBlob;
1612
1613 assert(ctx != NULL);
1614 assert(ctx->cspHand != 0);
1615
1616 memset(publicKey, 0, sizeof(CSSM_KEY));
1617 memset(privateKey, 0, sizeof(CSSM_KEY));
1618 SSLBUF_TO_CSSM(paramBlob, &cParamBlob);
1619
1620 crtn = CSSM_CSP_CreateKeyGenContext(ctx->cspHand,
1621 CSSM_ALGID_DH,
1622 keySizeInBits,
1623 NULL, // Seed
1624 NULL, // Salt
1625 NULL, // StartDate
1626 NULL, // EndDate
1627 &cParamBlob,
1628 &ccHandle);
1629 if(crtn) {
1630 stPrintCdsaError("DH CSSM_CSP_CreateKeyGenContext", crtn);
1631 return errSSLCrypto;
1632 }
1633
1634 crtn = CSSM_GenerateKeyPair(ccHandle,
1635 CSSM_KEYUSE_DERIVE, // only legal use of a Diffie-Hellman key
1636 CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE,
1637 &labelData,
1638 publicKey,
1639 /* private key specification */
1640 CSSM_KEYUSE_DERIVE,
1641 CSSM_KEYATTR_RETURN_REF,
1642 &labelData, // same labels
1643 NULL, // CredAndAclEntry
1644 privateKey);
1645 if(crtn) {
1646 stPrintCdsaError("DH CSSM_GenerateKeyPair", crtn);
1647 ortn = errSSLCrypto;
1648 }
1649 CSSM_DeleteContext(ccHandle);
1650 return ortn;
1651 }
1652
1653 /*
1654 * Perform Diffie-Hellman key exchange.
1655 * Valid on entry:
1656 * ctx->dhPrivate
1657 * ctx->dhPeerPublic
1658 *
1659 * This generates deriveSizeInBits of key-exchanged data.
1660 */
1661
1662 /* the alg isn't important; we just want to be able to cook up lots of bits */
1663 #define DERIVE_KEY_ALG CSSM_ALGID_RC5
1664
1665 OSStatus sslDhKeyExchange(
1666 SSLContext *ctx,
1667 uint32_t deriveSizeInBits,
1668 SSLBuffer *exchanged)
1669 {
1670 CSSM_RETURN crtn;
1671 CSSM_ACCESS_CREDENTIALS creds;
1672 CSSM_CC_HANDLE ccHandle;
1673 CSSM_DATA labelData = {8, (uint8 *)"tempKey"};
1674 CSSM_KEY derivedKey;
1675 OSStatus ortn = errSecSuccess;
1676
1677 assert(ctx != NULL);
1678 assert(ctx->cspHand != 0);
1679 assert(ctx->dhPrivate != NULL);
1680 if(ctx->dhPeerPublic.length == 0) {
1681 /* comes from peer, don't panic */
1682 sslErrorLog("cdsaDhKeyExchange: null peer public key\n");
1683 return errSSLProtocol;
1684 }
1685
1686 memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
1687 memset(&derivedKey, 0, sizeof(CSSM_KEY));
1688
1689 crtn = CSSM_CSP_CreateDeriveKeyContext(ctx->cspHand,
1690 CSSM_ALGID_DH,
1691 DERIVE_KEY_ALG,
1692 deriveSizeInBits,
1693 &creds,
1694 ctx->dhPrivate, // BaseKey
1695 0, // IterationCount
1696 0, // Salt
1697 0, // Seed
1698 &ccHandle);
1699 if(crtn) {
1700 stPrintCdsaError("DH CSSM_CSP_CreateDeriveKeyContext", crtn);
1701 return errSSLCrypto;
1702 }
1703
1704 /* public key passed in as CSSM_DATA *Param */
1705 CSSM_DATA theirPubKeyData;
1706 SSLBUF_TO_CSSM(&ctx->dhPeerPublic, &theirPubKeyData);
1707
1708 crtn = CSSM_DeriveKey(ccHandle,
1709 &theirPubKeyData,
1710 CSSM_KEYUSE_ANY,
1711 CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE,
1712 &labelData,
1713 NULL, // cread/acl
1714 &derivedKey);
1715 if(crtn) {
1716 stPrintCdsaError("DH CSSM_DeriveKey", crtn);
1717 ortn = errSSLCrypto;
1718 }
1719 else {
1720 CSSM_TO_SSLBUF(&derivedKey.KeyData, exchanged);
1721 }
1722 CSSM_DeleteContext(ccHandle);
1723 return ortn;
1724 }
1725
1726 // MARK: -
1727 // MARK: *** ECDSA support ***
1728
1729 /* specify either 32-bit integer or a pointer as an added attribute value */
1730 typedef enum {
1731 CAT_Uint32,
1732 CAT_Ptr
1733 } ContextAttrType;
1734
1735 /*
1736 * Given a context specified via a CSSM_CC_HANDLE, add a new
1737 * CSSM_CONTEXT_ATTRIBUTE to the context as specified by AttributeType,
1738 * AttributeLength, and an untyped pointer.
1739 */
1740 static CSSM_RETURN sslAddContextAttribute(CSSM_CC_HANDLE CCHandle,
1741 uint32 AttributeType,
1742 uint32 AttributeLength,
1743 ContextAttrType attrType,
1744 /* specify exactly one of these */
1745 const void *AttributePtr,
1746 uint32 attributeInt)
1747 {
1748 CSSM_CONTEXT_ATTRIBUTE newAttr;
1749 CSSM_RETURN crtn;
1750
1751 newAttr.AttributeType = AttributeType;
1752 newAttr.AttributeLength = AttributeLength;
1753 if(attrType == CAT_Uint32) {
1754 newAttr.Attribute.Uint32 = attributeInt;
1755 }
1756 else {
1757 newAttr.Attribute.Data = (CSSM_DATA_PTR)AttributePtr;
1758 }
1759 crtn = CSSM_UpdateContextAttributes(CCHandle, 1, &newAttr);
1760 if(crtn) {
1761 stPrintCdsaError("CSSM_UpdateContextAttributes", crtn);
1762 }
1763 return crtn;
1764 }
1765
1766 /*
1767 * Generate ECDH key pair with the given SSL_ECDSA_NamedCurve.
1768 * Private key, in ref form, is placed in ctx->ecdhPrivate.
1769 * Public key, in ECPoint form - which can NOT be used as
1770 * a key in any CSP ops - is placed in ecdhExchangePublic.
1771 */
1772 OSStatus sslEcdhGenerateKeyPair(
1773 SSLContext *ctx,
1774 SSL_ECDSA_NamedCurve namedCurve)
1775 {
1776 CSSM_RETURN crtn;
1777 CSSM_CC_HANDLE ccHandle = 0;
1778 CSSM_DATA labelData = {8, (uint8 *)"ecdsaKey"};
1779 OSStatus ortn = errSecSuccess;
1780 CSSM_KEY pubKey;
1781 uint32 keySizeInBits;
1782
1783 assert(ctx != NULL);
1784 assert(ctx->cspHand != 0);
1785 sslFreeKey(ctx->ecdhPrivCspHand, &ctx->ecdhPrivate, NULL);
1786 SSLFreeBuffer(&ctx->ecdhExchangePublic);
1787
1788 switch(namedCurve) {
1789 case SSL_Curve_secp256r1:
1790 keySizeInBits = 256;
1791 break;
1792 case SSL_Curve_secp384r1:
1793 keySizeInBits = 384;
1794 break;
1795 case SSL_Curve_secp521r1:
1796 keySizeInBits = 521;
1797 break;
1798 default:
1799 /* should not have gotten this far */
1800 sslErrorLog("sslEcdhGenerateKeyPair: bad namedCurve (%u)\n",
1801 (unsigned)namedCurve);
1802 return errSSLInternal;
1803 }
1804
1805 ctx->ecdhPrivate = (CSSM_KEY *)sslMalloc(sizeof(CSSM_KEY));
1806
1807 memset(ctx->ecdhPrivate, 0, sizeof(CSSM_KEY));
1808 memset(&pubKey, 0, sizeof(CSSM_KEY));
1809
1810 crtn = CSSM_CSP_CreateKeyGenContext(ctx->cspHand,
1811 CSSM_ALGID_ECDSA,
1812 keySizeInBits,
1813 NULL, // Seed
1814 NULL, // Salt
1815 NULL, // StartDate
1816 NULL, // EndDate
1817 NULL, // Params
1818 &ccHandle);
1819 if(crtn) {
1820 stPrintCdsaError("ECDH CSSM_CSP_CreateKeyGenContext", crtn);
1821 return errSSLCrypto;
1822 }
1823 /* subsequent errors to errOut: */
1824
1825 /*
1826 * Here's how we get the raw ECPoint form of a public key
1827 */
1828 crtn = sslAddContextAttribute(ccHandle,
1829 CSSM_ATTRIBUTE_PUBLIC_KEY_FORMAT,
1830 sizeof(uint32),
1831 CAT_Uint32,
1832 NULL,
1833 CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING);
1834 if(crtn) {
1835 ortn = errSSLCrypto;
1836 goto errOut;
1837 }
1838
1839 crtn = CSSM_GenerateKeyPair(ccHandle,
1840 /* public key specification */
1841 CSSM_KEYUSE_DERIVE, // only legal use - right?
1842 CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE,
1843 &labelData,
1844 &pubKey,
1845 /* private key specification */
1846 CSSM_KEYUSE_DERIVE,
1847 CSSM_KEYATTR_RETURN_REF,
1848 &labelData, // same labels
1849 NULL, // CredAndAclEntry
1850 ctx->ecdhPrivate);
1851 if(crtn) {
1852 stPrintCdsaError("ECDH CSSM_GenerateKeyPair", crtn);
1853 ortn = errSSLCrypto;
1854 goto errOut;
1855 }
1856 ctx->ecdhPrivCspHand = ctx->cspHand;
1857
1858 /*
1859 * Take that public key data, drop it into ecdhExchangePublic,
1860 * and free the key.
1861 */
1862 ortn = SSLCopyBufferFromData(pubKey.KeyData.Data, pubKey.KeyData.Length,
1863 &ctx->ecdhExchangePublic);
1864 CSSM_FreeKey(ctx->cspHand, NULL, &pubKey, CSSM_FALSE);
1865
1866 errOut:
1867 if(ccHandle != 0) {
1868 CSSM_DeleteContext(ccHandle);
1869 }
1870 return ortn;
1871
1872 }
1873
1874 /*
1875 * Perform ECDH key exchange. Obtained key material is the same
1876 * size as our private key.
1877 *
1878 * On entry, ecdhPrivate is our private key. The peer's public key
1879 * is either ctx->ecdhPeerPublic for ECDHE exchange, or
1880 * ctx->peerPubKey for ECDH exchange.
1881 */
1882 OSStatus sslEcdhKeyExchange(
1883 SSLContext *ctx,
1884 SSLBuffer *exchanged)
1885 {
1886 CSSM_RETURN crtn;
1887 CSSM_ACCESS_CREDENTIALS creds;
1888 const CSSM_ACCESS_CREDENTIALS *secCreds;
1889 const CSSM_ACCESS_CREDENTIALS *useCreds = &creds;
1890 CSSM_CC_HANDLE ccHandle;
1891 CSSM_DATA labelData = {8, (uint8 *)"tempKey"};
1892 CSSM_KEY derivedKey;
1893 OSStatus ortn = errSecSuccess;
1894 CSSM_KEY rawKey;
1895 bool useRefKeys = false;
1896 uint32 keyAttr;
1897 SSLBuffer pubKeyBits = {0, NULL};
1898
1899 assert(ctx != NULL);
1900 assert(ctx->ecdhPrivCspHand != 0);
1901 assert(ctx->ecdhPrivate != NULL);
1902
1903 memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
1904 memset(&derivedKey, 0, sizeof(CSSM_KEY));
1905 memset(&rawKey, 0, sizeof(CSSM_KEY));
1906
1907 /*
1908 * If we're using an actual CSSM_KEY for the peer public key, and its
1909 * cspHand differs from our private key, we do things a bit different -
1910 * our key is in the CSPDL space, and it has a Sec-style ACL for which
1911 * we need creds. Also, the peer public key and the derived key have
1912 * to be in reference form.
1913 */
1914 switch(ctx->selectedCipherSpec.keyExchangeMethod) {
1915 case SSL_ECDH_ECDSA:
1916 case SSL_ECDH_RSA:
1917 if(ctx->cspHand != ctx->ecdhPrivCspHand) {
1918 useRefKeys = true;
1919 }
1920 break;
1921 default:
1922 break;
1923 }
1924 if(useRefKeys) {
1925 assert(ctx->signingPrivKeyRef != NULL);
1926 ortn = SecKeyGetCredentials(ctx->signingPrivKeyRef,
1927 CSSM_ACL_AUTHORIZATION_DERIVE,
1928 kSecCredentialTypeDefault,
1929 &secCreds);
1930 if(ortn) {
1931 stPrintCdsaError("ECDH SecKeyGetCredentials", ortn);
1932 return ortn;
1933 }
1934 useCreds = secCreds;
1935 }
1936 crtn = CSSM_CSP_CreateDeriveKeyContext(ctx->ecdhPrivCspHand,
1937 CSSM_ALGID_ECDH,
1938 DERIVE_KEY_ALG,
1939 ctx->ecdhPrivate->KeyHeader.LogicalKeySizeInBits,
1940 useCreds,
1941 ctx->ecdhPrivate, // BaseKey
1942 0, // IterationCount
1943 0, // Salt
1944 0, // Seed
1945 &ccHandle);
1946 if(crtn) {
1947 stPrintCdsaError("ECDH CSSM_CSP_CreateDeriveKeyContext", crtn);
1948 return errSSLCrypto;
1949 }
1950 /* subsequent errors to errOut: */
1951
1952 CSSM_DATA theirPubKeyData = {0, NULL};
1953
1954 switch(ctx->selectedCipherSpec.keyExchangeMethod) {
1955 case SSL_ECDHE_ECDSA:
1956 case SSL_ECDHE_RSA:
1957 /* public key passed in as CSSM_DATA *Param */
1958 if(ctx->ecdhPeerPublic.length == 0) {
1959 /* comes from peer, don't panic */
1960 sslErrorLog("sslEcdhKeyExchange: null peer public key\n");
1961 ortn = errSSLProtocol;
1962 goto errOut;
1963 }
1964 SSLBUF_TO_CSSM(&ctx->ecdhPeerPublic, &theirPubKeyData);
1965 break;
1966 case SSL_ECDH_ECDSA:
1967 case SSL_ECDH_RSA:
1968 /* add pub key as a context attr */
1969 if(ctx->peerPubKey == NULL) {
1970 sslErrorLog("sslEcdhKeyExchange: no peer key\n");
1971 ortn = errSSLInternal;
1972 goto errOut;
1973 }
1974
1975 /*
1976 * If we're using CSPDL, extract the raw public key bits in ECPoint
1977 * form and transmit as CSSM_DATA *Param.
1978 * The securityd can't transmit a public key in a DeriveKey context
1979 * in any form.
1980 */
1981 if(useRefKeys) {
1982 ortn = sslEcdsaPubKeyBits(ctx->peerPubKey, &pubKeyBits);
1983 if(ortn) {
1984 goto errOut;
1985 }
1986 SSLBUF_TO_CSSM(&pubKeyBits, &theirPubKeyData);
1987 }
1988 else {
1989 crtn = sslAddContextAttribute(ccHandle,
1990 CSSM_ATTRIBUTE_PUBLIC_KEY,
1991 sizeof(CSSM_KEY),
1992 CAT_Ptr,
1993 (void *)ctx->peerPubKey,
1994 0);
1995 if(crtn) {
1996 stPrintCdsaError("AddContextAttribute(CSSM_ATTRIBUTE_PUBLIC_KEY)",
1997 crtn);
1998 ortn = errSSLInternal;
1999 goto errOut;
2000 }
2001 }
2002 break;
2003 default:
2004 /* shouldn't be here */
2005 assert(0);
2006 ortn = errSSLInternal;
2007 goto errOut;
2008 }
2009
2010 if(useRefKeys) {
2011 keyAttr = CSSM_KEYATTR_RETURN_REF | CSSM_KEYATTR_EXTRACTABLE;
2012 }
2013 else {
2014 keyAttr = CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE;
2015 }
2016 crtn = CSSM_DeriveKey(ccHandle,
2017 &theirPubKeyData,
2018 CSSM_KEYUSE_ANY,
2019 keyAttr,
2020 &labelData,
2021 NULL, // cred/acl
2022 &derivedKey);
2023 if(crtn) {
2024 stPrintCdsaError("ECDH CSSM_DeriveKey", crtn);
2025 ortn = errSSLCrypto;
2026 goto errOut;
2027 }
2028
2029 if(useRefKeys) {
2030 /*
2031 * one more step: NULL-wrap the generated ref key to something we
2032 * can use
2033 */
2034 ortn = sslNullWrapKey(ctx->ecdhPrivCspHand, &derivedKey, &rawKey);
2035 if(ortn) {
2036 goto errOut;
2037 }
2038 ortn = SSLCopyBufferFromData(rawKey.KeyData.Data, rawKey.KeyData.Length,
2039 exchanged);
2040 }
2041 else {
2042 ortn = SSLCopyBufferFromData(derivedKey.KeyData.Data,
2043 derivedKey.KeyData.Length, exchanged);
2044 }
2045 errOut:
2046 CSSM_DeleteContext(ccHandle);
2047 if(useRefKeys) {
2048 if(pubKeyBits.length) {
2049 SSLFreeBuffer(&pubKeyBits);
2050 }
2051 if(rawKey.KeyData.Length) {
2052 CSSM_FreeKey(ctx->ecdhPrivCspHand, NULL, &rawKey, CSSM_FALSE);
2053 }
2054 }
2055 return ortn;
2056 }
2057
2058
2059 /*
2060 * After ciphersuite negotiation is complete, verify that we have
2061 * the capability of actually performing the selected cipher.
2062 * Currently we just verify that we have a cert and private signing
2063 * key, if needed, and that the signing key's algorithm matches the
2064 * expected key exchange method.
2065 *
2066 * This is currently called from FindCipherSpec(), after it sets
2067 * ctx->selectedCipherSuite to a (supposedly) valid value, and from
2068 * sslBuildCipherSuiteArray(), in server mode (pre-negotiation) only.
2069 */
2070 OSStatus sslVerifySelectedCipher(
2071 SSLContext *ctx,
2072 const SSLCipherSpec *selectedCipherSpec)
2073 {
2074 if(ctx->protocolSide == kSSLClientSide) {
2075 return errSecSuccess;
2076 }
2077 #if SSL_PAC_SERVER_ENABLE
2078 if((ctx->masterSecretCallback != NULL) &&
2079 (ctx->sessionTicket.data != NULL)) {
2080 /* EAP via PAC resumption; we can do it */
2081 return errSecSuccess;
2082 }
2083 #endif /* SSL_PAC_SERVER_ENABLE */
2084
2085 CSSM_ALGORITHMS requireAlg = CSSM_ALGID_NONE;
2086 if(selectedCipherSpec == NULL) {
2087 return errSSLInternal;
2088 }
2089 switch (selectedCipherSpec->keyExchangeMethod) {
2090 case SSL_RSA:
2091 case SSL_RSA_EXPORT:
2092 case SSL_DH_RSA:
2093 case SSL_DH_RSA_EXPORT:
2094 case SSL_DHE_RSA:
2095 case SSL_DHE_RSA_EXPORT:
2096 requireAlg = CSSM_ALGID_RSA;
2097 break;
2098 case SSL_DHE_DSS:
2099 case SSL_DHE_DSS_EXPORT:
2100 case SSL_DH_DSS:
2101 case SSL_DH_DSS_EXPORT:
2102 requireAlg = CSSM_ALGID_DSA;
2103 break;
2104 case SSL_DH_anon:
2105 case SSL_DH_anon_EXPORT:
2106 /* CSSM_ALGID_NONE, no signing key */
2107 break;
2108 /*
2109 * When SSL_ECDSA_SERVER is true and we support ECDSA on the server side,
2110 * we'll need to add some logic here...
2111 */
2112 #if SSL_ECDSA_SERVER
2113 #error Work needed in sslVerifySelectedCipher
2114 #endif
2115
2116 default:
2117 /* needs update per cipherSpecs.c */
2118 assert(0);
2119 return errSSLInternal;
2120 }
2121 if(requireAlg == CSSM_ALGID_NONE) {
2122 return errSecSuccess;
2123 }
2124
2125 /* private signing key required */
2126 if(ctx->signingPrivKeyRef == NULL) {
2127 sslErrorLog("sslVerifySelectedCipher: no signing key\n");
2128 return errSSLBadConfiguration;
2129 }
2130 {
2131 const CSSM_KEY *cssmKey;
2132 OSStatus ortn = SecKeyGetCSSMKey(ctx->signingPrivKeyRef, &cssmKey);
2133 if(ortn) {
2134 sslErrorLog("sslVerifySelectedCipher: SecKeyGetCSSMKey err %d\n",
2135 (int)ortn);
2136 return ortn;
2137 }
2138 if(cssmKey->KeyHeader.AlgorithmId != requireAlg) {
2139 sslErrorLog("sslVerifySelectedCipher: signing key alg mismatch\n");
2140 return errSSLBadConfiguration;
2141 }
2142 }
2143 return errSecSuccess;
2144 }
2145
2146 #endif /* USE_CDSA_CRYPTO */
2147