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