]> git.saurik.com Git - apple/security.git/blob - SecureTransport/appleCdsa.cpp
Security-179.tar.gz
[apple/security.git] / SecureTransport / appleCdsa.cpp
1 /*
2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
3 *
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
8 * using this file.
9 *
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS
12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
15 * specific language governing rights and limitations under the License.
16 */
17
18
19 /*
20 File: appleCdsa.cpp
21
22 Contains: interface between SSL and CDSA
23
24 Written by: Doug Mitchell
25
26 Copyright: (c) 1999 by Apple Computer, Inc., all rights reserved.
27
28 */
29
30 #include "ssl.h"
31 #include "sslContext.h"
32 #include "sslMemory.h"
33 #include "appleCdsa.h"
34 #include "sslUtils.h"
35 #include "sslDebug.h"
36 #include "sslBER.h"
37 #include "ModuleAttacher.h"
38
39 #ifndef _SSL_KEYCHAIN_H_
40 #include "sslKeychain.h"
41 #endif
42
43 #include <string.h>
44 #include <stdlib.h>
45 #include <assert.h>
46
47 #include <Security/cssm.h>
48 #include <Security/cssmapple.h>
49 #include <Security/cssmerrno.h>
50 #include <Security/Security.h>
51 #include <Security/SecTrustPriv.h>
52 #include <Security/SecPolicyPriv.h>
53 #include <Security/SecKeyPriv.h>
54
55 /* X.509 includes, from cssmapi */
56 #include <Security/x509defs.h> /* x.509 function and type defs */
57 #include <Security/oidsalg.h>
58 #include <Security/oidscert.h>
59
60 #pragma mark *** Utilities ***
61
62 /*
63 * Set up a Raw symmetric key with specified algorithm and key bits.
64 */
65 OSStatus sslSetUpSymmKey(
66 CSSM_KEY_PTR symKey,
67 CSSM_ALGORITHMS alg,
68 CSSM_KEYUSE keyUse, // CSSM_KEYUSE_ENCRYPT, etc.
69 CSSM_BOOL copyKey, // true: copy keyData false: set by reference
70 uint8 *keyData,
71 uint32 keyDataLen) // in bytes
72 {
73 OSStatus serr;
74 CSSM_KEYHEADER *hdr;
75
76 memset(symKey, 0, sizeof(CSSM_KEY));
77 if(copyKey) {
78 serr = stSetUpCssmData(&symKey->KeyData, keyDataLen);
79 if(serr) {
80 return serr;
81 }
82 memmove(symKey->KeyData.Data, keyData, keyDataLen);
83 }
84 else {
85 symKey->KeyData.Data = keyData;
86 symKey->KeyData.Length = keyDataLen;
87 }
88
89 /* set up the header */
90 hdr = &symKey->KeyHeader;
91 hdr->BlobType = CSSM_KEYBLOB_RAW;
92 hdr->Format = CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING;
93 hdr->AlgorithmId = alg;
94 hdr->KeyClass = CSSM_KEYCLASS_SESSION_KEY;
95 hdr->LogicalKeySizeInBits = keyDataLen * 8;
96 hdr->KeyAttr = CSSM_KEYATTR_MODIFIABLE | CSSM_KEYATTR_EXTRACTABLE;
97 hdr->KeyUsage = keyUse;
98 hdr->WrapAlgorithmId = CSSM_ALGID_NONE;
99 return noErr;
100 }
101
102 /*
103 * Free a CSSM_KEY - its CSP resources, KCItemRef, and the key itself.
104 */
105 OSStatus sslFreeKey(
106 CSSM_CSP_HANDLE cspHand,
107 CSSM_KEY_PTR *key, /* so we can null it out */
108 #if ST_KC_KEYS_NEED_REF
109 SecKeychainRef *kcItem)
110 #else
111 void *kcItem)
112 #endif
113 {
114 assert(key != NULL);
115
116 if(*key != NULL) {
117 if(cspHand != 0) {
118 CSSM_FreeKey(cspHand, NULL, *key, CSSM_FALSE);
119 }
120 stAppFree(*key, NULL); // key mallocd by CL using our callback
121 *key = NULL;
122 }
123 #if ST_KC_KEYS_NEED_REF
124 if((kcItem != NULL) && (*kcItem != NULL)) {
125 KCReleaseItem(kcItem); /* does this NULL the referent? */
126 *kcItem = NULL;
127 }
128 #endif
129 return noErr;
130 }
131
132 /*
133 * Standard app-level memory functions required by CDSA.
134 */
135 void * stAppMalloc (uint32 size, void *allocRef) {
136 return( malloc(size) );
137 }
138 void stAppFree (void *mem_ptr, void *allocRef) {
139 free(mem_ptr);
140 return;
141 }
142 void * stAppRealloc (void *ptr, uint32 size, void *allocRef) {
143 return( realloc( ptr, size ) );
144 }
145 void * stAppCalloc (uint32 num, uint32 size, void *allocRef) {
146 return( calloc( num, size ) );
147 }
148
149 /*
150 * Ensure there's a connection to ctx->cspHand. If there
151 * already is one, fine.
152 * Note that as of 12/18/00, we assume we're connected to
153 * all modules all the time (since we do an attachToAll() in
154 * SSLNewContext()).
155 */
156 OSStatus attachToCsp(SSLContext *ctx)
157 {
158 assert(ctx != NULL);
159 if(ctx->cspHand != 0) {
160 return noErr;
161 }
162 else {
163 return errSSLModuleAttach;
164 }
165 }
166
167 /*
168 * Connect to TP, CL; reusable.
169 */
170 OSStatus attachToCl(SSLContext *ctx)
171 {
172 assert(ctx != NULL);
173 if(ctx->clHand != 0) {
174 return noErr;
175 }
176 else {
177 return errSSLModuleAttach;
178 }
179 }
180
181 OSStatus attachToTp(SSLContext *ctx)
182 {
183 assert(ctx != NULL);
184 if(ctx->tpHand != 0) {
185 return noErr;
186 }
187 else {
188 return errSSLModuleAttach;
189 }
190 }
191
192 /*
193 * Convenience function - attach to CSP, CL, TP. Reusable.
194 */
195 OSStatus attachToAll(SSLContext *ctx)
196 {
197 CSSM_RETURN crtn;
198
199 assert(ctx != NULL);
200 crtn = attachToModules(&ctx->cspHand, &ctx->clHand, &ctx->tpHand);
201 if(crtn) {
202 return errSSLModuleAttach;
203 }
204 else {
205 return noErr;
206 }
207 }
208
209 OSStatus detachFromAll(SSLContext *ctx)
210 {
211 #if 0
212 /* No more, attachments are kept on a global basis */
213 assert(ctx != NULL);
214 if(ctx->cspHand != 0) {
215 CSSM_ModuleDetach(ctx->cspHand);
216 ctx->cspHand = 0;
217 }
218 if(ctx->tpHand != 0) {
219 CSSM_ModuleDetach(ctx->tpHand);
220 ctx->tpHand = 0;
221 }
222 if(ctx->clHand != 0) {
223 CSSM_ModuleDetach(ctx->clHand);
224 ctx->clHand = 0;
225 }
226 #endif /* 0 */
227 return noErr;
228 }
229
230 /*
231 * Add a CSSM_ATTRIBUTE_RSA_BLINDING attribute to
232 * specified crypto context.
233 */
234 static CSSM_RETURN sslAddBlindingAttr(
235 CSSM_CC_HANDLE ccHand)
236 {
237 CSSM_CONTEXT_ATTRIBUTE newAttr;
238 CSSM_RETURN crtn;
239
240 newAttr.AttributeType = CSSM_ATTRIBUTE_RSA_BLINDING;
241 newAttr.AttributeLength = sizeof(uint32);
242 newAttr.Attribute.Uint32 = 1;
243 crtn = CSSM_UpdateContextAttributes(ccHand, 1, &newAttr);
244 if(crtn) {
245 stPrintCdsaError("CSSM_UpdateContextAttributes", crtn);
246 }
247 return crtn;
248 }
249
250 /* Get CSP, key in CSSM format from a SecKeyRef */
251 static OSStatus sslGetKeyParts(
252 SecKeyRef keyRef,
253 const CSSM_KEY **cssmKey,
254 CSSM_CSP_HANDLE *cspHand)
255 {
256 OSStatus ortn = SecKeyGetCSSMKey(keyRef, cssmKey);
257 if(ortn) {
258 sslErrorLog("sslGetKeyParts: SecKeyGetCSSMKey err %d\n",
259 (int)ortn);
260 return ortn;
261 }
262 ortn = SecKeyGetCSPHandle(keyRef, cspHand);
263 if(ortn) {
264 sslErrorLog("sslGetKeyParts: SecKeyGetCSPHandle err %d\n",
265 (int)ortn);
266 }
267 return ortn;
268 }
269
270 #pragma mark -
271 #pragma mark *** CSSM_DATA routines ***
272
273 CSSM_DATA_PTR stMallocCssmData(
274 uint32 size)
275 {
276 CSSM_DATA_PTR rtn = (CSSM_DATA_PTR)stAppMalloc(sizeof(CSSM_DATA), NULL);
277
278 if(rtn == NULL) {
279 return NULL;
280 }
281 rtn->Length = size;
282 if(size == 0) {
283 rtn->Data = NULL;
284 }
285 else {
286 rtn->Data = (uint8 *)stAppMalloc(size, NULL);
287 }
288 return rtn;
289 }
290
291 void stFreeCssmData(
292 CSSM_DATA_PTR data,
293 CSSM_BOOL freeStruct)
294 {
295 if(data == NULL) {
296 return;
297 }
298 if(data->Data != NULL) {
299 stAppFree(data->Data, NULL);
300 data->Data = NULL;
301 }
302 data->Length = 0;
303 if(freeStruct) {
304 stAppFree(data, NULL);
305 }
306 }
307
308 /*
309 * Ensure that indicated CSSM_DATA_PTR can handle 'length' bytes of data.
310 * Malloc the Data ptr if necessary.
311 */
312 OSStatus stSetUpCssmData(
313 CSSM_DATA_PTR data,
314 uint32 length)
315 {
316 assert(data != NULL);
317 if(data->Length == 0) {
318 data->Data = (uint8 *)stAppMalloc(length, NULL);
319 if(data->Data == NULL) {
320 return memFullErr;
321 }
322 }
323 else if(data->Length < length) {
324 sslErrorLog("stSetUpCssmData: length too small\n");
325 return memFullErr;
326 }
327 data->Length = length;
328 return noErr;
329 }
330
331 static OSStatus sslKeyToSigAlg(
332 const CSSM_KEY *cssmKey,
333 CSSM_ALGORITHMS &sigAlg) /* RETURNED */
334
335 {
336 OSStatus ortn = noErr;
337 switch(cssmKey->KeyHeader.AlgorithmId) {
338 case CSSM_ALGID_RSA:
339 sigAlg = CSSM_ALGID_RSA;
340 break;
341 case CSSM_ALGID_DSA:
342 sigAlg = CSSM_ALGID_DSA;
343 break;
344 default:
345 ortn = errSSLBadConfiguration;
346 break;
347 }
348 return ortn;
349 }
350
351 #pragma mark -
352 #pragma mark *** Public CSP Functions ***
353
354 /*
355 * Raw RSA/DSA sign/verify.
356 */
357 OSStatus sslRawSign(
358 SSLContext *ctx,
359 SecKeyRef privKeyRef,
360 const UInt8 *plainText,
361 UInt32 plainTextLen,
362 UInt8 *sig, // mallocd by caller; RETURNED
363 UInt32 sigLen, // available
364 UInt32 *actualBytes) // RETURNED
365 {
366 CSSM_CC_HANDLE sigHand = 0;
367 CSSM_RETURN crtn;
368 OSStatus serr;
369 CSSM_DATA sigData;
370 CSSM_DATA ptextData;
371 CSSM_CSP_HANDLE cspHand;
372 const CSSM_KEY *privKey;
373 const CSSM_ACCESS_CREDENTIALS *creds;
374
375 assert(ctx != NULL);
376 if((privKeyRef == NULL) ||
377 (plainText == NULL) ||
378 (sig == NULL) ||
379 (actualBytes == NULL)) {
380 sslErrorLog("sslRsaRawSign: bad arguments\n");
381 return errSSLInternal;
382 }
383 *actualBytes = 0;
384
385 /* Get CSP, signing key in CSSM format */
386 serr = sslGetKeyParts(privKeyRef, &privKey, &cspHand);
387 if(serr) {
388 return serr;
389 }
390 assert(privKey->KeyHeader.KeyClass == CSSM_KEYCLASS_PRIVATE_KEY);
391
392 CSSM_ALGORITHMS sigAlg;
393 serr = sslKeyToSigAlg(privKey, sigAlg);
394 if(serr) {
395 return serr;
396 }
397
398 /*
399 * Get default creds
400 * FIXME: per 3420180, this needs to allow app-specified creds via
401 * an new API
402 */
403 serr = SecKeyGetCredentials(privKeyRef,
404 CSSM_ACL_AUTHORIZATION_SIGN,
405 kSecCredentialTypeDefault,
406 &creds);
407 if(serr) {
408 sslErrorLog("sslRawSign: SecKeyGetCredentials err %lu\n", serr);
409 return serr;
410 }
411
412 crtn = CSSM_CSP_CreateSignatureContext(cspHand,
413 sigAlg,
414 creds,
415 privKey,
416 &sigHand);
417 if(crtn) {
418 stPrintCdsaError("CSSM_CSP_CreateSignatureContext (1)", crtn);
419 return errSSLCrypto;
420 }
421
422 if((ctx->rsaBlindingEnable) &&
423 (privKey->KeyHeader.AlgorithmId == CSSM_ALGID_RSA)) {
424 /*
425 * Turn on RSA blinding to defeat timing attacks
426 */
427 crtn = sslAddBlindingAttr(sigHand);
428 if(crtn) {
429 return crtn;
430 }
431 }
432
433 ptextData.Data = (uint8 *)plainText;
434 ptextData.Length = plainTextLen;
435
436 /* caller better get this right, or the SignData will fail */
437 sigData.Data = sig;
438 sigData.Length = sigLen;
439
440 crtn = CSSM_SignData(sigHand,
441 &ptextData,
442 1,
443 CSSM_ALGID_NONE, // digestAlg for raw sign
444 &sigData);
445 if(crtn) {
446 stPrintCdsaError("CSSM_SignData", crtn);
447 serr = errSSLCrypto;
448 }
449 else {
450 *actualBytes = sigData.Length;
451 serr = noErr;
452 }
453 if(sigHand != 0) {
454 CSSM_DeleteContext(sigHand);
455 }
456 return serr;
457 }
458
459 OSStatus sslRawVerify(
460 SSLContext *ctx,
461 const CSSM_KEY *pubKey,
462 CSSM_CSP_HANDLE cspHand,
463 const UInt8 *plainText,
464 UInt32 plainTextLen,
465 const UInt8 *sig,
466 UInt32 sigLen)
467 {
468 CSSM_CC_HANDLE sigHand = 0;
469 CSSM_RETURN crtn;
470 OSStatus serr;
471 CSSM_DATA sigData;
472 CSSM_DATA ptextData;
473
474 assert(ctx != NULL);
475 if((pubKey == NULL) ||
476 (cspHand == 0) ||
477 (plainText == NULL) ||
478 (sig == NULL)) {
479 sslErrorLog("sslRawVerify: bad arguments\n");
480 return errSSLInternal;
481 }
482
483 CSSM_ALGORITHMS sigAlg;
484 serr = sslKeyToSigAlg(pubKey, sigAlg);
485 if(serr) {
486 return serr;
487 }
488 crtn = CSSM_CSP_CreateSignatureContext(cspHand,
489 sigAlg,
490 NULL, // passPhrase
491 pubKey,
492 &sigHand);
493 if(sigHand == 0) {
494 stPrintCdsaError("CSSM_CSP_CreateSignatureContext (2)", crtn);
495 return errSSLCrypto;
496 }
497
498 ptextData.Data = (uint8 *)plainText;
499 ptextData.Length = plainTextLen;
500 sigData.Data = (uint8 *)sig;
501 sigData.Length = sigLen;
502
503 crtn = CSSM_VerifyData(sigHand,
504 &ptextData,
505 1,
506 CSSM_ALGID_NONE, // digestAlg
507 &sigData);
508 if(crtn) {
509 stPrintCdsaError("CSSM_VerifyData", crtn);
510 serr = errSSLCrypto;
511 }
512 else {
513 serr = noErr;
514 }
515 if(sigHand != 0) {
516 CSSM_DeleteContext(sigHand);
517 }
518 return serr;
519 }
520
521 /*
522 * Encrypt/Decrypt
523 */
524 OSStatus sslRsaEncrypt(
525 SSLContext *ctx,
526 const CSSM_KEY *pubKey,
527 CSSM_CSP_HANDLE cspHand,
528 const UInt8 *plainText,
529 UInt32 plainTextLen,
530 UInt8 *cipherText, // mallocd by caller; RETURNED
531 UInt32 cipherTextLen, // available
532 UInt32 *actualBytes) // RETURNED
533 {
534 CSSM_DATA ctextData = {0, NULL};
535 CSSM_DATA ptextData;
536 CSSM_DATA remData = {0, NULL};
537 CSSM_CC_HANDLE cryptHand = 0;
538 OSStatus serr = errSSLInternal;
539 CSSM_RETURN crtn;
540 uint32 bytesMoved = 0;
541 CSSM_ACCESS_CREDENTIALS creds;
542
543 assert(ctx != NULL);
544 assert(actualBytes != NULL);
545 *actualBytes = 0;
546
547 if((pubKey == NULL) || (cspHand == 0)) {
548 sslErrorLog("sslRsaEncrypt: bad pubKey/cspHand\n");
549 return errSSLInternal;
550 }
551 assert(pubKey->KeyHeader.KeyClass == CSSM_KEYCLASS_PUBLIC_KEY);
552
553 #if RSA_PUB_KEY_USAGE_HACK
554 ((CSSM_KEY_PTR)pubKey)->KeyHeader.KeyUsage |= CSSM_KEYUSE_ENCRYPT;
555 #endif
556 memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
557
558 crtn = CSSM_CSP_CreateAsymmetricContext(cspHand,
559 CSSM_ALGID_RSA,
560 &creds,
561 pubKey,
562 CSSM_PADDING_PKCS1,
563 &cryptHand);
564 if(crtn) {
565 stPrintCdsaError("CSSM_CSP_CreateAsymmetricContext", crtn);
566 return errSSLCrypto;
567 }
568 ptextData.Data = (uint8 *)plainText;
569 ptextData.Length = plainTextLen;
570
571 /*
572 * Have CSP malloc ciphertext
573 */
574 crtn = CSSM_EncryptData(cryptHand,
575 &ptextData,
576 1,
577 &ctextData,
578 1,
579 &bytesMoved,
580 &remData);
581 if(crtn == CSSM_OK) {
582 /*
583 * ciphertext in both ctextData and remData; ensure it'll fit
584 * in caller's buf & copy
585 */
586 if(bytesMoved > cipherTextLen) {
587 sslErrorLog("sslRsaEncrypt overflow; cipherTextLen %ld bytesMoved %ld\n",
588 cipherTextLen, bytesMoved);
589 serr = errSSLCrypto;
590 }
591 else {
592 UInt32 toMoveCtext;
593 UInt32 toMoveRem;
594
595 *actualBytes = bytesMoved;
596 /*
597 * Snag valid data from ctextData - its length or bytesMoved,
598 * whichever is less
599 */
600 if(ctextData.Length > bytesMoved) {
601 /* everything's in ctext */
602 toMoveCtext = bytesMoved;
603 toMoveRem = 0;
604 }
605 else {
606 /* must be some in remData too */
607 toMoveCtext = ctextData.Length;
608 toMoveRem = bytesMoved - toMoveCtext; // remainder
609 }
610 if(toMoveCtext) {
611 memmove(cipherText, ctextData.Data, toMoveCtext);
612 }
613 if(toMoveRem) {
614 memmove(cipherText + toMoveCtext, remData.Data,
615 toMoveRem);
616 }
617 serr = noErr;
618 }
619 }
620 else {
621 stPrintCdsaError("CSSM_EncryptData", crtn);
622 serr = errSSLCrypto;
623 }
624 if(cryptHand != 0) {
625 CSSM_DeleteContext(cryptHand);
626 }
627
628 /* free data mallocd by CSP */
629 stFreeCssmData(&ctextData, CSSM_FALSE);
630 stFreeCssmData(&remData, CSSM_FALSE);
631 return serr;
632 }
633
634 OSStatus sslRsaDecrypt(
635 SSLContext *ctx,
636 SecKeyRef privKeyRef,
637 const UInt8 *cipherText,
638 UInt32 cipherTextLen,
639 UInt8 *plainText, // mallocd by caller; RETURNED
640 UInt32 plainTextLen, // available
641 UInt32 *actualBytes) // RETURNED
642 {
643 CSSM_DATA ptextData = {0, NULL};
644 CSSM_DATA ctextData;
645 CSSM_DATA remData = {0, NULL};
646 CSSM_CC_HANDLE cryptHand = 0;
647 OSStatus serr = errSSLInternal;
648 CSSM_RETURN crtn;
649 uint32 bytesMoved = 0;
650 CSSM_CSP_HANDLE cspHand;
651 const CSSM_KEY *privKey;
652 const CSSM_ACCESS_CREDENTIALS *creds;
653
654 assert(ctx != NULL);
655 assert(actualBytes != NULL);
656 *actualBytes = 0;
657
658 if(privKeyRef == NULL) {
659 sslErrorLog("sslRsaDecrypt: bad privKey\n");
660 return errSSLInternal;
661 }
662
663 /* Get CSP, signing key in CSSM format */
664 serr = sslGetKeyParts(privKeyRef, &privKey, &cspHand);
665 if(serr) {
666 return serr;
667 }
668 assert(privKey->KeyHeader.KeyClass == CSSM_KEYCLASS_PRIVATE_KEY);
669
670 /*
671 * Get default creds
672 * FIXME: per 3420180, this needs to allow app-specified creds via
673 * an new API
674 */
675 serr = SecKeyGetCredentials(privKeyRef,
676 CSSM_ACL_AUTHORIZATION_DECRYPT,
677 kSecCredentialTypeDefault,
678 &creds);
679 if(serr) {
680 sslErrorLog("sslRsaDecrypt: SecKeyGetCredentials err %lu\n", serr);
681 return serr;
682 }
683 crtn = CSSM_CSP_CreateAsymmetricContext(cspHand,
684 CSSM_ALGID_RSA,
685 creds,
686 privKey,
687 CSSM_PADDING_PKCS1,
688 &cryptHand);
689 if(crtn) {
690 stPrintCdsaError("CSSM_CSP_CreateAsymmetricContext", crtn);
691 return errSSLCrypto;
692 }
693 ctextData.Data = (uint8 *)cipherText;
694 ctextData.Length = cipherTextLen;
695
696 if((ctx->rsaBlindingEnable) &&
697 (privKey->KeyHeader.AlgorithmId == CSSM_ALGID_RSA)) {
698 /*
699 * Turn on RSA blinding to defeat timing attacks
700 */
701 crtn = sslAddBlindingAttr(cryptHand);
702 if(crtn) {
703 return crtn;
704 }
705 }
706
707 /*
708 * Have CSP malloc plaintext
709 */
710 crtn = CSSM_DecryptData(cryptHand,
711 &ctextData,
712 1,
713 &ptextData,
714 1,
715 &bytesMoved,
716 &remData);
717 if(crtn == CSSM_OK) {
718 /*
719 * plaintext in both ptextData and remData; ensure it'll fit
720 * in caller's buf & copy
721 */
722 if(bytesMoved > plainTextLen) {
723 sslErrorLog("sslRsaDecrypt overflow; plainTextLen %ld bytesMoved %ld\n",
724 plainTextLen, bytesMoved);
725 serr = errSSLCrypto;
726 }
727 else {
728 UInt32 toMovePtext;
729 UInt32 toMoveRem;
730
731 *actualBytes = bytesMoved;
732 /*
733 * Snag valid data from ptextData - its length or bytesMoved,
734 * whichever is less
735 */
736 if(ptextData.Length > bytesMoved) {
737 /* everything's in ptext */
738 toMovePtext = bytesMoved;
739 toMoveRem = 0;
740 }
741 else {
742 /* must be some in remData too */
743 toMovePtext = ptextData.Length;
744 toMoveRem = bytesMoved - toMovePtext; // remainder
745 }
746 if(toMovePtext) {
747 memmove(plainText, ptextData.Data, toMovePtext);
748 }
749 if(toMoveRem) {
750 memmove(plainText + toMovePtext, remData.Data,
751 toMoveRem);
752 }
753 serr = noErr;
754 }
755 }
756 else {
757 stPrintCdsaError("CSSM_DecryptData", crtn);
758 serr = errSSLCrypto;
759 }
760 if(cryptHand != 0) {
761 CSSM_DeleteContext(cryptHand);
762 }
763
764 /* free data mallocd by CSP */
765 stFreeCssmData(&ptextData, CSSM_FALSE);
766 stFreeCssmData(&remData, CSSM_FALSE);
767 return serr;
768 }
769
770 /*
771 * Obtain size of key in bytes.
772 */
773 UInt32 sslKeyLengthInBytes(const CSSM_KEY *key)
774 {
775 assert(key != NULL);
776 return (((key->KeyHeader.LogicalKeySizeInBits) + 7) / 8);
777 }
778
779 /*
780 * Obtain maximum size of signature in bytes. A bit of a kludge; we could
781 * ask the CSP to do this but that would be kind of expensive.
782 */
783 OSStatus sslGetMaxSigSize(
784 const CSSM_KEY *privKey,
785 UInt32 &maxSigSize)
786 {
787 OSStatus ortn = noErr;
788 assert(privKey != NULL);
789 assert(privKey->KeyHeader.KeyClass == CSSM_KEYCLASS_PRIVATE_KEY);
790 switch(privKey->KeyHeader.AlgorithmId) {
791 case CSSM_ALGID_RSA:
792 maxSigSize = sslKeyLengthInBytes(privKey);
793 break;
794 case CSSM_ALGID_DSA:
795 {
796 /* DSA sig is DER sequence of two 160-bit integers */
797 UInt32 sizeOfOneInt;
798 sizeOfOneInt = (160 / 8) + // the raw contents
799 1 + // possible leading zero
800 2; // tag + length (assume DER, not BER)
801 maxSigSize = (2 * sizeOfOneInt) + 5;
802 break;
803 }
804 default:
805 ortn = errSSLBadConfiguration;
806 break;
807 }
808 return ortn;
809 }
810 /*
811 * Get raw key bits from an RSA public key.
812 */
813 OSStatus sslGetPubKeyBits(
814 SSLContext *ctx,
815 const CSSM_KEY *pubKey,
816 CSSM_CSP_HANDLE cspHand,
817 SSLBuffer *modulus, // data mallocd and RETURNED
818 SSLBuffer *exponent) // data mallocd and RETURNED
819 {
820 CSSM_KEY wrappedKey;
821 CSSM_BOOL didWrap = CSSM_FALSE;
822 const CSSM_KEYHEADER *hdr;
823 SSLBuffer pubKeyBlob;
824 OSStatus srtn;
825
826 assert(ctx != NULL);
827 assert(modulus != NULL);
828 assert(exponent != NULL);
829 assert(pubKey != NULL);
830
831 hdr = &pubKey->KeyHeader;
832 if(hdr->KeyClass != CSSM_KEYCLASS_PUBLIC_KEY) {
833 sslErrorLog("sslGetPubKeyBits: bad keyClass (%ld)\n", hdr->KeyClass);
834 return errSSLInternal;
835 }
836 if(hdr->AlgorithmId != CSSM_ALGID_RSA) {
837 sslErrorLog("sslGetPubKeyBits: bad AlgorithmId (%ld)\n", hdr->AlgorithmId);
838 return errSSLInternal;
839 }
840
841 /* Note currently ALL public keys are raw, obtained from the CL... */
842 assert(hdr->BlobType == CSSM_KEYBLOB_RAW);
843
844 /*
845 * Handle possible reference format - I think it should be in
846 * blob form since it came from the DL, but conversion is
847 * simple.
848 */
849 switch(hdr->BlobType) {
850 case CSSM_KEYBLOB_RAW:
851 /* easy case */
852 CSSM_TO_SSLBUF(&pubKey->KeyData, &pubKeyBlob);
853 break;
854
855 case CSSM_KEYBLOB_REFERENCE:
856
857 sslErrorLog("sslGetPubKeyBits: bad BlobType (%ld)\n",
858 hdr->BlobType);
859 return errSSLInternal;
860
861 #if 0
862 /*
863 * Convert to a blob via "NULL wrap"; no wrapping key,
864 * ALGID_NONE
865 */
866 srtn = attachToCsp(ctx);
867 if(srtn) {
868 return srtn;
869 }
870 memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
871 crtn = CSSM_CSP_CreateSymmetricContext(ctx->cspHand,
872 CSSM_ALGID_NONE,
873 CSSM_ALGMODE_NONE,
874 &creds, // creds
875 pubKey,
876 NULL, // InitVector
877 CSSM_PADDING_NONE,
878 0, // reserved
879 &ccHand);
880 if(crtn) {
881 stPrintCdsaError("sslGetPubKeyBits: CreateSymmetricContext failure", crtn);
882 return errSSLCrypto;
883 }
884 memset(&wrappedKey, 0, sizeof(CSSM_KEY));
885 crtn = CSSM_WrapKey(ccHand,
886 &creds,
887 pubKey,
888 NULL, // descriptiveData
889 &wrappedKey);
890 CSSM_DeleteContext(ccHand);
891 if(crtn) {
892 stPrintCdsaError("CSSM_WrapKey", crtn);
893 return errSSLCrypto;
894 }
895 hdr = &wrappedKey.KeyHeader;
896 if(hdr->BlobType != CSSM_KEYBLOB_RAW) {
897 sslErrorLog("sslGetPubKeyBits: bad BlobType (%ld) after WrapKey\n",
898 hdr->BlobType);
899 return errSSLCrypto;
900 }
901 didWrap = CSSM_TRUE;
902 CSSM_TO_SSLBUF(&wrappedKey.KeyData, &pubKeyBlob);
903 break;
904 #endif /* 0 */
905
906 default:
907 sslErrorLog("sslGetPubKeyBits: bad BlobType (%ld)\n",
908 hdr->BlobType);
909 return errSSLInternal;
910
911 } /* switch BlobType */
912
913 assert(hdr->BlobType == CSSM_KEYBLOB_RAW);
914 srtn = sslDecodeRsaBlob(&pubKeyBlob, modulus, exponent);
915 if(didWrap) {
916 CSSM_FreeKey(ctx->cspHand, NULL, &wrappedKey, CSSM_FALSE);
917 }
918 return srtn;
919 }
920
921 /*
922 * Given raw RSA key bits, cook up a CSSM_KEY_PTR. Used in
923 * Server-initiated key exchange.
924 */
925 OSStatus sslGetPubKeyFromBits(
926 SSLContext *ctx,
927 const SSLBuffer *modulus,
928 const SSLBuffer *exponent,
929 CSSM_KEY_PTR *pubKey, // mallocd and RETURNED
930 CSSM_CSP_HANDLE *cspHand) // RETURNED
931 {
932 CSSM_KEY_PTR key = NULL;
933 OSStatus serr;
934 SSLBuffer blob;
935 CSSM_KEYHEADER_PTR hdr;
936 CSSM_KEY_SIZE keySize;
937 CSSM_RETURN crtn;
938
939 assert((ctx != NULL) && (modulus != NULL) && (exponent != NULL));
940 assert((pubKey != NULL) && (cspHand != NULL));
941
942 *pubKey = NULL;
943 *cspHand = 0;
944
945 serr = attachToCsp(ctx);
946 if(serr) {
947 return serr;
948 }
949 serr = sslEncodeRsaBlob(modulus, exponent, &blob);
950 if(serr) {
951 return serr;
952 }
953
954 /* the rest is boilerplate, cook up a good-looking public key */
955 key = (CSSM_KEY_PTR)sslMalloc(sizeof(CSSM_KEY));
956 if(key == NULL) {
957 return memFullErr;
958 }
959 memset(key, 0, sizeof(CSSM_KEY));
960 hdr = &key->KeyHeader;
961
962 hdr->HeaderVersion = CSSM_KEYHEADER_VERSION;
963 /* key_ptr->KeyHeader.CspId is unknown (remains 0) */
964 hdr->BlobType = CSSM_KEYBLOB_RAW;
965 hdr->AlgorithmId = CSSM_ALGID_RSA;
966 hdr->Format = CSSM_KEYBLOB_RAW_FORMAT_PKCS1;
967 hdr->KeyClass = CSSM_KEYCLASS_PUBLIC_KEY;
968 /* comply with ASA requirements */
969 hdr->KeyUsage = CSSM_KEYUSE_VERIFY;
970 hdr->KeyAttr = CSSM_KEYATTR_EXTRACTABLE;
971 /* key_ptr->KeyHeader.StartDate is unknown (remains 0) */
972 /* key_ptr->KeyHeader.EndDate is unknown (remains 0) */
973 hdr->WrapAlgorithmId = CSSM_ALGID_NONE;
974 hdr->WrapMode = CSSM_ALGMODE_NONE;
975
976 /* blob->data was mallocd by sslEncodeRsaBlob, pass it over to
977 * actual key */
978 SSLBUF_TO_CSSM(&blob, &key->KeyData);
979
980 /*
981 * Get keySizeInBits. This also serves to validate the key blob
982 * we just cooked up.
983 */
984 crtn = CSSM_QueryKeySizeInBits(ctx->cspHand, CSSM_INVALID_HANDLE, key, &keySize);
985 if(crtn) {
986 stPrintCdsaError("sslGetPubKeyFromBits: QueryKeySizeInBits\n", crtn);
987 serr = errSSLCrypto;
988 goto abort;
989 }
990
991 /* success */
992 hdr->LogicalKeySizeInBits = keySize.EffectiveKeySizeInBits;
993 *pubKey = key;
994 *cspHand = ctx->cspHand;
995 return noErr;
996
997 abort:
998 /* note this frees the blob */
999 sslFreeKey(ctx->cspHand, &key, NULL);
1000 return serr;
1001 }
1002
1003 #pragma mark -
1004 #pragma mark *** Public Certificate Functions ***
1005
1006 /*
1007 * Given a DER-encoded cert, obtain its public key as a CSSM_KEY_PTR.
1008 * Caller must CSSM_FreeKey and free the CSSM_KEY_PTR itself.
1009 *
1010 * For now, the returned cspHand is a copy of ctx->cspHand, so it
1011 * doesn't have to be detached later - this may change.
1012 *
1013 * Update: since CSSM_CL_CertGetKeyInfo() doesn't provide a means for
1014 * us to tell the CL what CSP to use, we really have no way of knowing
1015 * what is going on here...we return the process-wide (bare) cspHand,
1016 * which is currently always able to deal with this raw public key.
1017 */
1018 OSStatus sslPubKeyFromCert(
1019 SSLContext *ctx,
1020 const SSLBuffer &derCert,
1021 CSSM_KEY_PTR *pubKey, // RETURNED
1022 CSSM_CSP_HANDLE *cspHand) // RETURNED
1023 {
1024 OSStatus serr;
1025 CSSM_DATA certData;
1026 CSSM_RETURN crtn;
1027
1028 assert(ctx != NULL);
1029 assert(pubKey != NULL);
1030 assert(cspHand != NULL);
1031
1032 *pubKey = NULL;
1033 *cspHand = 0;
1034
1035 serr = attachToCl(ctx);
1036 if(serr) {
1037 return serr;
1038 }
1039 serr = attachToCsp(ctx);
1040 if(serr) {
1041 return serr;
1042 }
1043 SSLBUF_TO_CSSM(&derCert, &certData);
1044 crtn = CSSM_CL_CertGetKeyInfo(ctx->clHand, &certData, pubKey);
1045 if(crtn) {
1046 return errSSLBadCert;
1047 }
1048 else {
1049 *cspHand = ctx->cspHand;
1050 return noErr;
1051 }
1052 }
1053
1054 /*
1055 * Release each element in a CFArray.
1056 */
1057 static void sslReleaseArray(
1058 CFArrayRef a)
1059 {
1060 CFIndex num = CFArrayGetCount(a);
1061 for(CFIndex dex=0; dex<num; dex++) {
1062 CFTypeRef elmt = (CFTypeRef)CFArrayGetValueAtIndex(a, dex);
1063 secdebug("sslcert", "Freeing cert %p", elmt);
1064 CFRelease(elmt);
1065 }
1066 }
1067
1068 /*
1069 * Verify a chain of DER-encoded certs.
1070 * First cert in a chain is root; this must also be present
1071 * in ctx->trustedCerts.
1072 *
1073 * If arePeerCerts is true, host name verification is enabled and we
1074 * save the resulting SecTrustRef in ctx->peerSecTrust. Otherwise
1075 * we're just validating our own certs; no host name checking and
1076 * peerSecTrust is transient.
1077 */
1078 OSStatus sslVerifyCertChain(
1079 SSLContext *ctx,
1080 const SSLCertificate &certChain,
1081 bool arePeerCerts /* = true */)
1082 {
1083 UInt32 numCerts;
1084 int i;
1085 OSStatus serr;
1086 SSLCertificate *c = (SSLCertificate *)&certChain;
1087 CSSM_RETURN crtn;
1088 CSSM_APPLE_TP_SSL_OPTIONS sslOpts;
1089 CSSM_APPLE_TP_ACTION_DATA tpActionData;
1090 SecPolicyRef policy = NULL;
1091 SecPolicySearchRef policySearch = NULL;
1092 CFDataRef actionData = NULL;
1093 CSSM_DATA sslOptsData;
1094 CFMutableArrayRef anchors = NULL;
1095 SecCertificateRef cert; // only lives in CFArrayRefs
1096 SecTrustResultType secTrustResult;
1097 CFMutableArrayRef kcList = NULL;
1098 SecTrustRef theTrust = NULL;
1099
1100 if(ctx->peerSecTrust && arePeerCerts) {
1101 /* renegotiate - start with a new SecTrustRef */
1102 CFRelease(ctx->peerSecTrust);
1103 ctx->peerSecTrust = NULL;
1104 }
1105
1106 numCerts = SSLGetCertificateChainLength(&certChain);
1107 if(numCerts == 0) {
1108 /* nope */
1109 return errSSLBadCert;
1110 }
1111
1112 /*
1113 * SSLCertificate chain --> CFArrayRef of SecCertificateRefs.
1114 * TP Cert group has root at the end, opposite of
1115 * SSLCertificate chain.
1116 */
1117 CFMutableArrayRef certGroup = CFArrayCreateMutable(NULL, numCerts,
1118 &kCFTypeArrayCallBacks);
1119 if(certGroup == NULL) {
1120 return memFullErr;
1121 }
1122 /* subsequent errors to errOut: */
1123
1124 for(i=numCerts-1; i>=0; i--) {
1125 CSSM_DATA cdata;
1126 SSLBUF_TO_CSSM(&c->derCert, &cdata);
1127 serr = SecCertificateCreateFromData(&cdata, CSSM_CERT_X_509v3,
1128 CSSM_CERT_ENCODING_DER, &cert);
1129 if(serr) {
1130 goto errOut;
1131 }
1132 /*
1133 * Can't set a value at index i when there is an empty element
1134 * at i=1!
1135 */
1136 secdebug("sslcert", "Adding cert %p", cert);
1137 CFArrayInsertValueAtIndex(certGroup, 0, cert);
1138 c = c->next;
1139 }
1140
1141 /*
1142 * Cook up an SSL-specific SecPolicyRef. This will persists as part
1143 * of the SecTrustRef object we'll be creating.
1144 */
1145 serr = SecPolicySearchCreate(CSSM_CERT_X_509v3,
1146 &CSSMOID_APPLE_TP_SSL,
1147 NULL,
1148 &policySearch);
1149 if(serr) {
1150 sslErrorLog("***sslVerifyCertChain: SecPolicySearchCreate rtn %d\n",
1151 (int)serr);
1152 goto errOut;
1153 }
1154 serr = SecPolicySearchCopyNext(policySearch, &policy);
1155 if(serr) {
1156 sslErrorLog("***sslVerifyCertChain: SecPolicySearchCopyNext rtn %d\n",
1157 (int)serr);
1158 goto errOut;
1159 }
1160 sslOpts.Version = CSSM_APPLE_TP_SSL_OPTS_VERSION;
1161 if(arePeerCerts) {
1162 sslOpts.ServerNameLen = ctx->peerDomainNameLen;
1163 sslOpts.ServerName = ctx->peerDomainName;
1164 }
1165 else {
1166 sslOpts.ServerNameLen = 0;
1167 sslOpts.ServerName = NULL;
1168 }
1169 sslOptsData.Data = (uint8 *)&sslOpts;
1170 sslOptsData.Length = sizeof(sslOpts);
1171 serr = SecPolicySetValue(policy, &sslOptsData);
1172 if(serr) {
1173 sslErrorLog("***sslVerifyCertChain: SecPolicySetValue rtn %d\n",
1174 (int)serr);
1175 goto errOut;
1176 }
1177
1178 /* now a SecTrustRef */
1179 serr = SecTrustCreateWithCertificates(certGroup, policy, &theTrust);
1180 if(serr) {
1181 sslErrorLog("***sslVerifyCertChain: SecTrustCreateWithCertificates "
1182 "rtn %d\n", (int)serr);
1183 goto errOut;
1184 }
1185
1186 /* anchors - default, or ours? */
1187 if(ctx->numTrustedCerts != 0) {
1188 anchors = CFArrayCreateMutable(NULL, ctx->numTrustedCerts,
1189 &kCFTypeArrayCallBacks);
1190 if(anchors == NULL) {
1191 serr = memFullErr;
1192 goto errOut;
1193 }
1194 for(i=0; i<(int)ctx->numTrustedCerts; i++) {
1195 serr = SecCertificateCreateFromData(&ctx->trustedCerts[i],
1196 CSSM_CERT_X_509v3, CSSM_CERT_ENCODING_DER, &cert);
1197 if(serr) {
1198 goto errOut;
1199 }
1200 secdebug("sslcert", "Adding cert %p", cert);
1201 CFArraySetValueAtIndex(anchors, i, cert);
1202 }
1203 serr = SecTrustSetAnchorCertificates(theTrust, anchors);
1204 if(serr) {
1205 sslErrorLog("***sslVerifyCertChain: SecTrustSetAnchorCertificates "
1206 "rtn %d\n", (int)serr);
1207 goto errOut;
1208 }
1209 }
1210 tpActionData.Version = CSSM_APPLE_TP_ACTION_VERSION;
1211 tpActionData.ActionFlags = 0;
1212 if(ctx->allowExpiredCerts) {
1213 tpActionData.ActionFlags |= CSSM_TP_ACTION_ALLOW_EXPIRED;
1214 }
1215 if(ctx->allowExpiredRoots) {
1216 tpActionData.ActionFlags |= CSSM_TP_ACTION_ALLOW_EXPIRED_ROOT;
1217 }
1218 actionData = CFDataCreate(NULL, (UInt8 *)&tpActionData, sizeof(tpActionData));
1219
1220 serr = SecTrustSetParameters(theTrust, CSSM_TP_ACTION_DEFAULT,
1221 actionData);
1222 if(serr) {
1223 sslErrorLog("***sslVerifyCertChain: SecTrustSetParameters rtn %d\n",
1224 (int)serr);
1225 goto errOut;
1226 }
1227
1228 #if 0
1229 /* Disabled for Radar 3421314 */
1230 /*
1231 * Avoid searching user keychains for intermediate certs by specifying
1232 * an empty array of keychains
1233 */
1234 kcList = CFArrayCreateMutable(NULL, 0, NULL);
1235 if(kcList == NULL) {
1236 sslErrorLog("***sslVerifyCertChain: error creating null kcList\n");
1237 serr = memFullErr;
1238 goto errOut;
1239 }
1240 serr = SecTrustSetKeychains(theTrust, kcList);
1241 if(serr) {
1242 sslErrorLog("***sslVerifyCertChain: SecTrustSetKeychains rtn %d\n",
1243 (int)serr);
1244 goto errOut;
1245 }
1246 #endif
1247
1248 /*
1249 * Save this no matter what if we're evaluating peer certs.
1250 * We do a retain here so we can unconditionally release theTrust
1251 * at the end of this routine in case of previous error or
1252 * !arePeerCerts.
1253 */
1254 if(arePeerCerts) {
1255 ctx->peerSecTrust = theTrust;
1256 CFRetain(theTrust);
1257 }
1258
1259 if(!ctx->enableCertVerify) {
1260 /* trivial case, this is caller's responsibility */
1261 serr = noErr;
1262 goto errOut;
1263 }
1264
1265 /*
1266 * Here we go; hand it over to SecTrust/TP.
1267 */
1268 serr = SecTrustEvaluate(theTrust, &secTrustResult);
1269 if(serr) {
1270 sslErrorLog("***sslVerifyCertChain: SecTrustEvaluate rtn %d\n",
1271 (int)serr);
1272 goto errOut;
1273 }
1274 switch(secTrustResult) {
1275 case kSecTrustResultUnspecified:
1276 /* cert chain valid, no special UserTrust assignments */
1277 case kSecTrustResultProceed:
1278 /* cert chain valid AND user explicitly trusts this */
1279 crtn = CSSM_OK;
1280 break;
1281 case kSecTrustResultDeny:
1282 case kSecTrustResultConfirm:
1283 /*
1284 * Cert chain may well have verified OK, but user has flagged
1285 * one of these certs as untrustable.
1286 */
1287 crtn = CSSMERR_TP_NOT_TRUSTED;
1288 break;
1289 default:
1290 {
1291 OSStatus osCrtn;
1292 serr = SecTrustGetCssmResultCode(theTrust, &osCrtn);
1293 if(serr) {
1294 sslErrorLog("***sslVerifyCertChain: SecTrustGetCssmResultCode"
1295 " rtn %d\n", (int)serr);
1296 goto errOut;
1297 }
1298 crtn = osCrtn;
1299 }
1300 }
1301 if(crtn) {
1302 /* get some detailed error info */
1303 switch(crtn) {
1304 case CSSMERR_TP_INVALID_ANCHOR_CERT:
1305 /* root found but we don't trust it */
1306 if(ctx->allowAnyRoot) {
1307 serr = noErr;
1308 sslErrorLog("***Warning: accepting unknown root cert\n");
1309 }
1310 else {
1311 serr = errSSLUnknownRootCert;
1312 }
1313 break;
1314 case CSSMERR_TP_NOT_TRUSTED:
1315 /* no root, not even in implicit SSL roots */
1316 if(ctx->allowAnyRoot) {
1317 sslErrorLog("***Warning: accepting unverified cert chain\n");
1318 serr = noErr;
1319 }
1320 else {
1321 serr = errSSLNoRootCert;
1322 }
1323 break;
1324 case CSSMERR_TP_CERT_EXPIRED:
1325 assert(!ctx->allowExpiredCerts);
1326 serr = errSSLCertExpired;
1327 break;
1328 case CSSMERR_TP_CERT_NOT_VALID_YET:
1329 serr = errSSLCertNotYetValid;
1330 break;
1331 default:
1332 stPrintCdsaError("sslVerifyCertChain: SecTrustEvaluate returned",
1333 crtn);
1334 serr = errSSLXCertChainInvalid;
1335 break;
1336 }
1337 } /* SecTrustEvaluate error */
1338
1339 errOut:
1340 /*
1341 * Free up resources - certGroup, policy, etc. Note that most of these
1342 * will actually persist as long as the current SSLContext does since
1343 * peerSecTrust holds references to these.
1344 */
1345 if(policy) {
1346 CFRelease(policy);
1347 }
1348 if(policySearch) {
1349 CFRelease(policySearch);
1350 }
1351 if(actionData) {
1352 CFRelease(actionData);
1353 }
1354 if(anchors) {
1355 sslReleaseArray(anchors);
1356 CFRelease(anchors);
1357 }
1358 if(certGroup) {
1359 sslReleaseArray(certGroup);
1360 CFRelease(certGroup);
1361 }
1362 if(kcList) {
1363 /* empty, no contents to release */
1364 CFRelease(kcList);
1365 }
1366 if(theTrust) {
1367 CFRelease(theTrust);
1368 }
1369 return serr;
1370 }
1371
1372 #ifndef NDEBUG
1373 void stPrintCdsaError(const char *op, CSSM_RETURN crtn)
1374 {
1375 cssmPerror(op, crtn);
1376 }
1377
1378 char *stCssmErrToStr(CSSM_RETURN err)
1379 {
1380 string errStr = cssmErrorString(err);
1381 return const_cast<char *>(errStr.c_str());
1382 }
1383 #endif
1384
1385 #pragma mark -
1386 #pragma mark *** Diffie-Hellman support ***
1387
1388 /*
1389 * Generate a Diffie-Hellman key pair. Algorithm parameters always
1390 * come from the server, so on client side we have the parameters
1391 * as two SSLBuffers. On server side we have the pre-encoded block
1392 * which comes from ServerDhParams.
1393 */
1394 OSStatus sslDhGenKeyPairClient(
1395 SSLContext *ctx,
1396 const SSLBuffer &prime,
1397 const SSLBuffer &generator,
1398 CSSM_KEY_PTR publicKey, // RETURNED
1399 CSSM_KEY_PTR privateKey) // RETURNED
1400 {
1401 assert((prime.data != NULL) && (generator.data != NULL));
1402 if(prime.data && !generator.data) {
1403 return errSSLProtocol;
1404 }
1405 if(!prime.data && generator.data) {
1406 return errSSLProtocol;
1407 }
1408
1409 SSLBuffer sParam;
1410 OSStatus ortn = sslEncodeDhParams(&prime, &generator, &sParam);
1411 if(ortn) {
1412 sslErrorLog("***sslDhGenerateKeyPairClient: DH param error\n");
1413 return ortn;
1414 }
1415 ortn = sslDhGenerateKeyPair(ctx, sParam, prime.length * 8, publicKey, privateKey);
1416 SSLFreeBuffer(sParam, ctx);
1417 return ortn;
1418 }
1419
1420 OSStatus sslDhGenerateKeyPair(
1421 SSLContext *ctx,
1422 const SSLBuffer &paramBlob,
1423 UInt32 keySizeInBits,
1424 CSSM_KEY_PTR publicKey, // RETURNED
1425 CSSM_KEY_PTR privateKey) // RETURNED
1426 {
1427 CSSM_RETURN crtn;
1428 CSSM_CC_HANDLE ccHandle;
1429 CSSM_DATA labelData = {8, (uint8 *)"tempKey"};
1430 OSStatus ortn = noErr;
1431 CSSM_DATA cParamBlob;
1432
1433 assert(ctx != NULL);
1434 assert(ctx->cspHand != 0);
1435
1436 memset(publicKey, 0, sizeof(CSSM_KEY));
1437 memset(privateKey, 0, sizeof(CSSM_KEY));
1438 SSLBUF_TO_CSSM(&paramBlob, &cParamBlob);
1439
1440 crtn = CSSM_CSP_CreateKeyGenContext(ctx->cspHand,
1441 CSSM_ALGID_DH,
1442 keySizeInBits,
1443 NULL, // Seed
1444 NULL, // Salt
1445 NULL, // StartDate
1446 NULL, // EndDate
1447 &cParamBlob,
1448 &ccHandle);
1449 if(crtn) {
1450 stPrintCdsaError("DH CSSM_CSP_CreateKeyGenContext", crtn);
1451 return errSSLCrypto;
1452 }
1453
1454 crtn = CSSM_GenerateKeyPair(ccHandle,
1455 CSSM_KEYUSE_DERIVE, // only legal use of a Diffie-Hellman key
1456 CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE,
1457 &labelData,
1458 publicKey,
1459 /* private key specification */
1460 CSSM_KEYUSE_DERIVE,
1461 CSSM_KEYATTR_RETURN_REF,
1462 &labelData, // same labels
1463 NULL, // CredAndAclEntry
1464 privateKey);
1465 if(crtn) {
1466 stPrintCdsaError("DH CSSM_GenerateKeyPair", crtn);
1467 ortn = errSSLCrypto;
1468 }
1469 CSSM_DeleteContext(ccHandle);
1470 return ortn;
1471 }
1472
1473 /*
1474 * Perform Diffie-Hellman key exchange.
1475 * Valid on entry:
1476 * ctx->dhPrivate
1477 * ctx->dhPeerPublic
1478 *
1479 * This generates deriveSizeInBits of key-exchanged data.
1480 */
1481
1482 /* the alg isn't important; we just want to be able to cook up lots of bits */
1483 #define DERIVE_KEY_ALG CSSM_ALGID_RC5
1484 #define DERIVE_KEY_MAX_BYTES 255
1485
1486 OSStatus sslDhKeyExchange(
1487 SSLContext *ctx,
1488 uint32 deriveSizeInBits,
1489 SSLBuffer *exchanged)
1490 {
1491 CSSM_RETURN crtn;
1492 CSSM_ACCESS_CREDENTIALS creds;
1493 CSSM_CC_HANDLE ccHandle;
1494 CSSM_DATA labelData = {8, (uint8 *)"tempKey"};
1495 CSSM_KEY derivedKey;
1496 OSStatus ortn = noErr;
1497
1498 assert(ctx != NULL);
1499 assert(ctx->cspHand != 0);
1500 assert(ctx->dhPrivate != NULL);
1501 if(ctx->dhPeerPublic.length == 0) {
1502 /* comes from peer, don't panic */
1503 sslErrorLog("cdsaDhKeyExchange: null peer public key\n");
1504 return errSSLProtocol;
1505 }
1506 if(deriveSizeInBits > (DERIVE_KEY_MAX_BYTES * 8)) {
1507 sslErrorLog("cdsaDhKeyExchange: deriveSizeInBits %u bits\n",
1508 (unsigned)deriveSizeInBits);
1509 return errSSLProtocol;
1510 }
1511
1512 memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
1513 memset(&derivedKey, 0, sizeof(CSSM_KEY));
1514
1515 crtn = CSSM_CSP_CreateDeriveKeyContext(ctx->cspHand,
1516 CSSM_ALGID_DH,
1517 DERIVE_KEY_ALG,
1518 deriveSizeInBits,
1519 &creds,
1520 ctx->dhPrivate, // BaseKey
1521 0, // IterationCount
1522 0, // Salt
1523 0, // Seed
1524 &ccHandle);
1525 if(crtn) {
1526 stPrintCdsaError("DH CSSM_CSP_CreateDeriveKeyContext", crtn);
1527 return errSSLCrypto;
1528 }
1529
1530 /* public key passed in as CSSM_DATA *Param */
1531 CSSM_DATA theirPubKeyData;
1532 SSLBUF_TO_CSSM(&ctx->dhPeerPublic, &theirPubKeyData);
1533
1534 crtn = CSSM_DeriveKey(ccHandle,
1535 &theirPubKeyData,
1536 CSSM_KEYUSE_ANY,
1537 CSSM_KEYATTR_RETURN_DATA | CSSM_KEYATTR_EXTRACTABLE,
1538 &labelData,
1539 NULL, // cread/acl
1540 &derivedKey);
1541 if(crtn) {
1542 stPrintCdsaError("DH CSSM_DeriveKey", crtn);
1543 ortn = errSSLCrypto;
1544 }
1545 else {
1546 CSSM_TO_SSLBUF(&derivedKey.KeyData, exchanged);
1547 }
1548 CSSM_DeleteContext(ccHandle);
1549 return ortn;
1550 }
1551
1552 /*
1553 * After ciphersuite negotiation is complete, verify that we have
1554 * the capability of actually performing the negotiated cipher.
1555 * Currently we just verify that we have a cert and private signing
1556 * key, if needed, and that the signing key's algorithm matches the
1557 * expected key exchange method.
1558 * This is currnetly only called from FindCipherSpec(), after
1559 * it sets ctx->selectedCipherSpec to a (supposedly) valid value.
1560 */
1561 OSStatus sslVerifyNegotiatedCipher(
1562 SSLContext *ctx)
1563 {
1564 if(ctx->protocolSide == SSL_ClientSide) {
1565 return noErr;
1566 }
1567 CSSM_ALGORITHMS requireAlg = CSSM_ALGID_NONE;
1568
1569 switch (ctx->selectedCipherSpec->keyExchangeMethod) {
1570 case SSL_RSA:
1571 case SSL_RSA_EXPORT:
1572 case SSL_DH_RSA:
1573 case SSL_DH_RSA_EXPORT:
1574 case SSL_DHE_RSA:
1575 case SSL_DHE_RSA_EXPORT:
1576 requireAlg = CSSM_ALGID_RSA;
1577 break;
1578 case SSL_DHE_DSS:
1579 case SSL_DHE_DSS_EXPORT:
1580 case SSL_DH_DSS:
1581 case SSL_DH_DSS_EXPORT:
1582 requireAlg = CSSM_ALGID_DSA;
1583 break;
1584 case SSL_DH_anon:
1585 case SSL_DH_anon_EXPORT:
1586 /* CSSM_ALGID_NONE, no signing key */
1587 break;
1588 default:
1589 /* needs update per cipherSpecs.cpp */
1590 assert(0);
1591 return errSSLInternal;
1592 }
1593 if(requireAlg == CSSM_ALGID_NONE) {
1594 return noErr;
1595 }
1596
1597 /* private signing key required */
1598 if(ctx->signingPrivKeyRef == NULL) {
1599 sslErrorLog("sslVerifyNegotiatedCipher: no signing key\n");
1600 return errSSLBadConfiguration;
1601 }
1602 {
1603 const CSSM_KEY *cssmKey;
1604 OSStatus ortn = SecKeyGetCSSMKey(ctx->signingPrivKeyRef, &cssmKey);
1605 if(ortn) {
1606 sslErrorLog("sslVerifyNegotiatedCipher: SecKeyGetCSSMKey err %d\n",
1607 (int)ortn);
1608 return ortn;
1609 }
1610 if(cssmKey->KeyHeader.AlgorithmId != requireAlg) {
1611 sslErrorLog("sslVerifyNegotiatedCipher: signing key alg mismatch\n");
1612 return errSSLBadConfiguration;
1613 }
1614 }
1615 return noErr;
1616 }
1617