]> git.saurik.com Git - apple/security.git/blob - SecureTransport/appleCdsa.cpp
987d1e97e5f43ca17deb4d228bc412935ed0316a
[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
51 /* X.509 includes, from cssmapi */
52 #include <Security/x509defs.h> /* x.509 function and type defs */
53 #include <Security/oidsalg.h>
54 #include <Security/oidscert.h>
55
56 #pragma mark *** Utilities ***
57
58 /*
59 * Set up a Raw symmetric key with specified algorithm and key bits.
60 */
61 OSStatus sslSetUpSymmKey(
62 CSSM_KEY_PTR symKey,
63 CSSM_ALGORITHMS alg,
64 CSSM_KEYUSE keyUse, // CSSM_KEYUSE_ENCRYPT, etc.
65 CSSM_BOOL copyKey, // true: copy keyData false: set by reference
66 uint8 *keyData,
67 uint32 keyDataLen) // in bytes
68 {
69 OSStatus serr;
70 CSSM_KEYHEADER *hdr;
71
72 memset(symKey, 0, sizeof(CSSM_KEY));
73 if(copyKey) {
74 serr = stSetUpCssmData(&symKey->KeyData, keyDataLen);
75 if(serr) {
76 return serr;
77 }
78 memmove(symKey->KeyData.Data, keyData, keyDataLen);
79 }
80 else {
81 symKey->KeyData.Data = keyData;
82 symKey->KeyData.Length = keyDataLen;
83 }
84
85 /* set up the header */
86 hdr = &symKey->KeyHeader;
87 hdr->BlobType = CSSM_KEYBLOB_RAW;
88 hdr->Format = CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING;
89 hdr->AlgorithmId = alg;
90 hdr->KeyClass = CSSM_KEYCLASS_SESSION_KEY;
91 hdr->LogicalKeySizeInBits = keyDataLen * 8;
92 hdr->KeyAttr = CSSM_KEYATTR_MODIFIABLE | CSSM_KEYATTR_EXTRACTABLE;
93 hdr->KeyUsage = keyUse;
94 hdr->WrapAlgorithmId = CSSM_ALGID_NONE;
95 return noErr;
96 }
97
98 /*
99 * Free a CSSM_KEY - its CSP resources, KCItemRef, and the key itself.
100 */
101 OSStatus sslFreeKey(
102 CSSM_CSP_HANDLE cspHand,
103 CSSM_KEY_PTR *key, /* so we can null it out */
104 #if ST_KC_KEYS_NEED_REF
105 SecKeychainRef *kcItem)
106 #else
107 void *kcItem)
108 #endif
109 {
110 assert(key != NULL);
111
112 if(*key != NULL) {
113 if(cspHand != 0) {
114 CSSM_FreeKey(cspHand, NULL, *key, CSSM_FALSE);
115 }
116 stAppFree(*key, NULL); // key mallocd by CL using our callback
117 *key = NULL;
118 }
119 #if ST_KC_KEYS_NEED_REF
120 if((kcItem != NULL) && (*kcItem != NULL)) {
121 KCReleaseItem(kcItem); /* does this NULL the referent? */
122 *kcItem = NULL;
123 }
124 #endif
125 return noErr;
126 }
127
128 /*
129 * Standard app-level memory functions required by CDSA.
130 */
131 void * stAppMalloc (uint32 size, void *allocRef) {
132 return( malloc(size) );
133 }
134 void stAppFree (void *mem_ptr, void *allocRef) {
135 free(mem_ptr);
136 return;
137 }
138 void * stAppRealloc (void *ptr, uint32 size, void *allocRef) {
139 return( realloc( ptr, size ) );
140 }
141 void * stAppCalloc (uint32 num, uint32 size, void *allocRef) {
142 return( calloc( num, size ) );
143 }
144
145 /*
146 * Ensure there's a connection to ctx->cspHand. If there
147 * already is one, fine.
148 * Note that as of 12/18/00, we assume we're connected to
149 * all modules all the time (since we do an attachToAll() in
150 * SSLNewContext()).
151 */
152 OSStatus attachToCsp(SSLContext *ctx)
153 {
154 assert(ctx != NULL);
155 if(ctx->cspHand != 0) {
156 return noErr;
157 }
158 else {
159 return errSSLModuleAttach;
160 }
161 }
162
163 /*
164 * Connect to TP, CL; reusable.
165 */
166 OSStatus attachToCl(SSLContext *ctx)
167 {
168 assert(ctx != NULL);
169 if(ctx->clHand != 0) {
170 return noErr;
171 }
172 else {
173 return errSSLModuleAttach;
174 }
175 }
176
177 OSStatus attachToTp(SSLContext *ctx)
178 {
179 assert(ctx != NULL);
180 if(ctx->tpHand != 0) {
181 return noErr;
182 }
183 else {
184 return errSSLModuleAttach;
185 }
186 }
187
188 /*
189 * Convenience function - attach to CSP, CL, TP. Reusable.
190 */
191 OSStatus attachToAll(SSLContext *ctx)
192 {
193 CSSM_RETURN crtn;
194
195 assert(ctx != NULL);
196 crtn = attachToModules(&ctx->cspHand, &ctx->clHand, &ctx->tpHand);
197 if(crtn) {
198 return errSSLModuleAttach;
199 }
200 else {
201 return noErr;
202 }
203 }
204
205 OSStatus detachFromAll(SSLContext *ctx)
206 {
207 #if 0
208 /* No more, attachments are kept on a global basis */
209 assert(ctx != NULL);
210 if(ctx->cspHand != 0) {
211 CSSM_ModuleDetach(ctx->cspHand);
212 ctx->cspHand = 0;
213 }
214 if(ctx->tpHand != 0) {
215 CSSM_ModuleDetach(ctx->tpHand);
216 ctx->tpHand = 0;
217 }
218 if(ctx->clHand != 0) {
219 CSSM_ModuleDetach(ctx->clHand);
220 ctx->clHand = 0;
221 }
222 #endif /* 0 */
223 return noErr;
224 }
225
226 #pragma mark -
227 #pragma mark *** CSSM_DATA routines ***
228
229 CSSM_DATA_PTR stMallocCssmData(
230 uint32 size)
231 {
232 CSSM_DATA_PTR rtn = (CSSM_DATA_PTR)stAppMalloc(sizeof(CSSM_DATA), NULL);
233
234 if(rtn == NULL) {
235 return NULL;
236 }
237 rtn->Length = size;
238 if(size == 0) {
239 rtn->Data = NULL;
240 }
241 else {
242 rtn->Data = (uint8 *)stAppMalloc(size, NULL);
243 }
244 return rtn;
245 }
246
247 void stFreeCssmData(
248 CSSM_DATA_PTR data,
249 CSSM_BOOL freeStruct)
250 {
251 if(data == NULL) {
252 return;
253 }
254 if(data->Data != NULL) {
255 stAppFree(data->Data, NULL);
256 data->Data = NULL;
257 }
258 data->Length = 0;
259 if(freeStruct) {
260 stAppFree(data, NULL);
261 }
262 }
263
264 /*
265 * Ensure that indicated CSSM_DATA_PTR can handle 'length' bytes of data.
266 * Malloc the Data ptr if necessary.
267 */
268 OSStatus stSetUpCssmData(
269 CSSM_DATA_PTR data,
270 uint32 length)
271 {
272 assert(data != NULL);
273 if(data->Length == 0) {
274 data->Data = (uint8 *)stAppMalloc(length, NULL);
275 if(data->Data == NULL) {
276 return memFullErr;
277 }
278 }
279 else if(data->Length < length) {
280 sslErrorLog("stSetUpCssmData: length too small\n");
281 return memFullErr;
282 }
283 data->Length = length;
284 return noErr;
285 }
286
287 #pragma mark -
288 #pragma mark *** Public CSP Functions ***
289
290 /*
291 * Raw RSA sign/verify.
292 *
293 * Initial X port: CSP doesns't support this, so we'll do sign/verify via
294 * raw RSA encrypt/decrypt here.
295 */
296 #define SIGN_VFY_VIA_ENCR_DECR 0
297
298 #if SIGN_VFY_VIA_ENCR_DECR
299
300 OSStatus sslRsaRawSign(
301 SSLContext *ctx,
302 const CSSM_KEY *privKey,
303 CSSM_CSP_HANDLE cspHand,
304 const UInt8 *plainText,
305 UInt32 plainTextLen,
306 UInt8 *sig, // mallocd by caller; RETURNED
307 UInt32 sigLen, // available
308 UInt32 *actualBytes) // RETURNED
309 {
310 /* Raw RSA sign with no digest is the same as raw RSA encrypt. */
311 /* Force CSSM_KEYUSE_ANY in case CL provided keyuse bits more specific
312 * than we really want */
313 OSStatus serr;
314 CSSM_KEYUSE savedKeyUse = privKey->KeyHeader.KeyUsage;
315 privKey->KeyHeader.KeyUsage = CSSM_KEYUSE_ANY;
316 serr = sslRsaEncrypt(ctx,
317 privKey,
318 cspHand,
319 plainText,
320 plainTextLen,
321 sig,
322 sigLen,
323 actualBytes);
324 privKey->KeyHeader.KeyUsage = savedKeyUse;
325 return serr;
326 }
327
328 OSStatus sslRsaRawVerify(
329 SSLContext *ctx,
330 const CSSM_KEY *pubKey,
331 CSSM_CSP_HANDLE cspHand,
332 const UInt8 *plainText,
333 UInt32 plainTextLen,
334 const UInt8 *sig,
335 UInt32 sigLen)
336 {
337 /*
338 * Raw RSA verify with no digest is just a comparison of the incoming
339 * plaintext with (signature, decrypted via raw RSA decrypt).
340 */
341
342 UInt32 actualBytes;
343 OSStatus serr;
344 UInt8 *digest;
345
346 /* Force CSSM_KEYUSE_ANY in case CL provided keyuse bits more specific
347 * than we really want */
348 CSSM_KEYUSE savedKeyUse = pubKey->KeyHeader.KeyUsage;
349 pubKey->KeyHeader.KeyUsage = CSSM_KEYUSE_ANY;
350
351 /* malloc space for decrypting the signature */
352 digest = sslMalloc(plainTextLen);
353 if(digest == NULL) {
354 return memFullErr;
355 }
356
357 /* decrypt signature */
358 serr = sslRsaDecrypt(ctx,
359 pubKey,
360 cspHand,
361 sig,
362 sigLen,
363 digest,
364 plainTextLen,
365 &actualBytes);
366 pubKey->KeyHeader.KeyUsage = savedKeyUse;
367 if(serr) {
368 goto errOut;
369 }
370 if((actualBytes != plainTextLen) ||
371 (memcmp(plainText, digest, plainTextLen))) {
372 sslErrorLog("sslRsaRawVerify: sig miscompare\n");
373 serr = errSSLCrypto;
374 }
375 else {
376 serr = noErr;
377 }
378 errOut:
379 sslFree(digest);
380 return serr;
381 }
382
383 #else /* OS9 and future post-cheetah version */
384
385 OSStatus sslRsaRawSign(
386 SSLContext *ctx,
387 const CSSM_KEY *privKey,
388 CSSM_CSP_HANDLE cspHand,
389 const UInt8 *plainText,
390 UInt32 plainTextLen,
391 UInt8 *sig, // mallocd by caller; RETURNED
392 UInt32 sigLen, // available
393 UInt32 *actualBytes) // RETURNED
394 {
395 CSSM_CC_HANDLE sigHand = 0;
396 CSSM_RETURN crtn;
397 OSStatus serr;
398 CSSM_DATA sigData;
399 CSSM_DATA ptextData;
400
401 assert(ctx != NULL);
402 if((privKey == NULL) ||
403 (cspHand == 0) ||
404 (plainText == NULL) ||
405 (sig == NULL) ||
406 (actualBytes == NULL)) {
407 sslErrorLog("sslRsaRawSign: bad arguments\n");
408 return errSSLInternal;
409 }
410 *actualBytes = 0;
411
412 crtn = CSSM_CSP_CreateSignatureContext(cspHand,
413 CSSM_ALGID_RSA,
414 NULL, // passPhrase
415 privKey,
416 &sigHand);
417 if(crtn) {
418 stPrintCdsaError("CSSM_CSP_CreateSignatureContext (1)", crtn);
419 return errSSLCrypto;
420 }
421
422 ptextData.Data = (uint8 *)plainText;
423 ptextData.Length = plainTextLen;
424
425 /* caller better get this right, or the SignData will fail */
426 sigData.Data = sig;
427 sigData.Length = sigLen;
428
429 crtn = CSSM_SignData(sigHand,
430 &ptextData,
431 1,
432 CSSM_ALGID_NONE, // digestAlg
433 &sigData);
434 if(crtn) {
435 stPrintCdsaError("CSSM_SignData", crtn);
436 serr = errSSLCrypto;
437 }
438 else {
439 *actualBytes = sigData.Length;
440 serr = noErr;
441 }
442 if(sigHand != 0) {
443 CSSM_DeleteContext(sigHand);
444 }
445 return serr;
446 }
447
448 OSStatus sslRsaRawVerify(
449 SSLContext *ctx,
450 const CSSM_KEY *pubKey,
451 CSSM_CSP_HANDLE cspHand,
452 const UInt8 *plainText,
453 UInt32 plainTextLen,
454 const UInt8 *sig,
455 UInt32 sigLen)
456 {
457 CSSM_CC_HANDLE sigHand = 0;
458 CSSM_RETURN crtn;
459 OSStatus serr;
460 CSSM_DATA sigData;
461 CSSM_DATA ptextData;
462
463 assert(ctx != NULL);
464 if((pubKey == NULL) ||
465 (cspHand == 0) ||
466 (plainText == NULL) ||
467 (sig == NULL)) {
468 sslErrorLog("sslRsaRawVerify: bad arguments\n");
469 return errSSLInternal;
470 }
471
472 crtn = CSSM_CSP_CreateSignatureContext(cspHand,
473 CSSM_ALGID_RSA,
474 NULL, // passPhrase
475 pubKey,
476 &sigHand);
477 if(sigHand == 0) {
478 stPrintCdsaError("CSSM_CSP_CreateSignatureContext (2)", crtn);
479 return errSSLCrypto;
480 }
481
482 ptextData.Data = (uint8 *)plainText;
483 ptextData.Length = plainTextLen;
484 sigData.Data = (uint8 *)sig;
485 sigData.Length = sigLen;
486
487 crtn = CSSM_VerifyData(sigHand,
488 &ptextData,
489 1,
490 CSSM_ALGID_NONE, // digestAlg
491 &sigData);
492 if(crtn) {
493 stPrintCdsaError("CSSM_VerifyData", crtn);
494 serr = errSSLCrypto;
495 }
496 else {
497 serr = noErr;
498 }
499 if(sigHand != 0) {
500 CSSM_DeleteContext(sigHand);
501 }
502 return serr;
503 }
504 #endif /* SIGN_VFY_VIA_ENCR_DECR */
505
506 /*
507 * Encrypt/Decrypt
508 */
509 OSStatus sslRsaEncrypt(
510 SSLContext *ctx,
511 const CSSM_KEY *pubKey,
512 CSSM_CSP_HANDLE cspHand,
513 const UInt8 *plainText,
514 UInt32 plainTextLen,
515 UInt8 *cipherText, // mallocd by caller; RETURNED
516 UInt32 cipherTextLen, // available
517 UInt32 *actualBytes) // RETURNED
518 {
519 CSSM_DATA ctextData = {0, NULL};
520 CSSM_DATA ptextData;
521 CSSM_DATA remData = {0, NULL};
522 CSSM_CC_HANDLE cryptHand = 0;
523 OSStatus serr = errSSLInternal;
524 CSSM_RETURN crtn;
525 uint32 bytesMoved = 0;
526 CSSM_ACCESS_CREDENTIALS creds;
527
528 assert(ctx != NULL);
529 assert(actualBytes != NULL);
530 *actualBytes = 0;
531
532 if((pubKey == NULL) || (cspHand == 0)) {
533 sslErrorLog("sslRsaEncrypt: bad pubKey/cspHand\n");
534 return errSSLInternal;
535 }
536
537 #if RSA_PUB_KEY_USAGE_HACK
538 ((CSSM_KEY_PTR)pubKey)->KeyHeader.KeyUsage |= CSSM_KEYUSE_ENCRYPT;
539 #endif
540 memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
541
542 crtn = CSSM_CSP_CreateAsymmetricContext(cspHand,
543 CSSM_ALGID_RSA,
544 &creds,
545 pubKey,
546 CSSM_PADDING_PKCS1,
547 &cryptHand);
548 if(crtn) {
549 stPrintCdsaError("CSSM_CSP_CreateAsymmetricContext", crtn);
550 return errSSLCrypto;
551 }
552 ptextData.Data = (uint8 *)plainText;
553 ptextData.Length = plainTextLen;
554
555 if(pubKey->KeyHeader.KeyClass == CSSM_KEYCLASS_PRIVATE_KEY) {
556 /*
557 * Special case, encrypting with private key (i.e., raw sign). Add
558 * the required context attr.
559 */
560 CSSM_CONTEXT_ATTRIBUTE modeAttr;
561
562 modeAttr.AttributeType = CSSM_ATTRIBUTE_MODE;
563 modeAttr.AttributeLength = sizeof(uint32);
564 modeAttr.Attribute.Uint32 = CSSM_ALGMODE_PRIVATE_KEY;
565 crtn = CSSM_UpdateContextAttributes(cryptHand, 1, &modeAttr);
566 if(crtn) {
567 stPrintCdsaError("CSSM_UpdateContextAttributes", crtn);
568 CSSM_DeleteContext(cryptHand);
569 return errSSLCrypto;
570 }
571 }
572
573 /*
574 * Have CSP malloc ciphertext
575 */
576 crtn = CSSM_EncryptData(cryptHand,
577 &ptextData,
578 1,
579 &ctextData,
580 1,
581 &bytesMoved,
582 &remData);
583 if(crtn == CSSM_OK) {
584 /*
585 * ciphertext in both ctextData and remData; ensure it'll fit
586 * in caller's buf & copy
587 */
588 if(bytesMoved > cipherTextLen) {
589 sslErrorLog("sslRsaEncrypt overflow; cipherTextLen %ld bytesMoved %ld\n",
590 cipherTextLen, bytesMoved);
591 serr = errSSLCrypto;
592 }
593 else {
594 UInt32 toMoveCtext;
595 UInt32 toMoveRem;
596
597 *actualBytes = bytesMoved;
598 /*
599 * Snag valid data from ctextData - its length or bytesMoved,
600 * whichever is less
601 */
602 if(ctextData.Length > bytesMoved) {
603 /* everything's in ctext */
604 toMoveCtext = bytesMoved;
605 toMoveRem = 0;
606 }
607 else {
608 /* must be some in remData too */
609 toMoveCtext = ctextData.Length;
610 toMoveRem = bytesMoved - toMoveCtext; // remainder
611 }
612 if(toMoveCtext) {
613 memmove(cipherText, ctextData.Data, toMoveCtext);
614 }
615 if(toMoveRem) {
616 memmove(cipherText + toMoveCtext, remData.Data,
617 toMoveRem);
618 }
619 serr = noErr;
620 }
621 }
622 else {
623 stPrintCdsaError("CSSM_EncryptData", crtn);
624 serr = errSSLCrypto;
625 }
626 if(cryptHand != 0) {
627 CSSM_DeleteContext(cryptHand);
628 }
629
630 /* free data mallocd by CSP */
631 stFreeCssmData(&ctextData, CSSM_FALSE);
632 stFreeCssmData(&remData, CSSM_FALSE);
633 return serr;
634 }
635
636 OSStatus sslRsaDecrypt(
637 SSLContext *ctx,
638 const CSSM_KEY *privKey,
639 CSSM_CSP_HANDLE cspHand,
640 const UInt8 *cipherText,
641 UInt32 cipherTextLen,
642 UInt8 *plainText, // mallocd by caller; RETURNED
643 UInt32 plainTextLen, // available
644 UInt32 *actualBytes) // RETURNED
645 {
646 CSSM_DATA ptextData = {0, NULL};
647 CSSM_DATA ctextData;
648 CSSM_DATA remData = {0, NULL};
649 CSSM_CC_HANDLE cryptHand = 0;
650 OSStatus serr = errSSLInternal;
651 CSSM_RETURN crtn;
652 uint32 bytesMoved = 0;
653 CSSM_ACCESS_CREDENTIALS creds;
654
655 assert(ctx != NULL);
656 assert(actualBytes != NULL);
657 *actualBytes = 0;
658
659 if((privKey == NULL) || (cspHand == 0)) {
660 sslErrorLog("sslRsaDecrypt: bad privKey/cspHand\n");
661 return errSSLInternal;
662 }
663 memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
664 crtn = CSSM_CSP_CreateAsymmetricContext(cspHand,
665 CSSM_ALGID_RSA,
666 &creds,
667 privKey,
668 CSSM_PADDING_PKCS1,
669 &cryptHand);
670 if(crtn) {
671 stPrintCdsaError("CSSM_CSP_CreateAsymmetricContext", crtn);
672 return errSSLCrypto;
673 }
674 ctextData.Data = (uint8 *)cipherText;
675 ctextData.Length = cipherTextLen;
676
677 if(privKey->KeyHeader.KeyClass == CSSM_KEYCLASS_PUBLIC_KEY) {
678 /*
679 * Special case, decrypting with public key (i.e., raw verify). Add
680 * the required context attr.
681 */
682 CSSM_CONTEXT_ATTRIBUTE modeAttr;
683
684 modeAttr.AttributeType = CSSM_ATTRIBUTE_MODE;
685 modeAttr.AttributeLength = sizeof(uint32);
686 modeAttr.Attribute.Uint32 = CSSM_ALGMODE_PUBLIC_KEY;
687 crtn = CSSM_UpdateContextAttributes(cryptHand, 1, &modeAttr);
688 if(crtn) {
689 stPrintCdsaError("CSSM_UpdateContextAttributes", crtn);
690 CSSM_DeleteContext(cryptHand);
691 return errSSLCrypto;
692 }
693 }
694
695 /*
696 * Have CSP malloc plaintext
697 */
698 crtn = CSSM_DecryptData(cryptHand,
699 &ctextData,
700 1,
701 &ptextData,
702 1,
703 &bytesMoved,
704 &remData);
705 if(crtn == CSSM_OK) {
706 /*
707 * plaintext in both ptextData and remData; ensure it'll fit
708 * in caller's buf & copy
709 */
710 if(bytesMoved > plainTextLen) {
711 sslErrorLog("sslRsaDecrypt overflow; plainTextLen %ld bytesMoved %ld\n",
712 plainTextLen, bytesMoved);
713 serr = errSSLCrypto;
714 }
715 else {
716 UInt32 toMovePtext;
717 UInt32 toMoveRem;
718
719 *actualBytes = bytesMoved;
720 /*
721 * Snag valid data from ptextData - its length or bytesMoved,
722 * whichever is less
723 */
724 if(ptextData.Length > bytesMoved) {
725 /* everything's in ptext */
726 toMovePtext = bytesMoved;
727 toMoveRem = 0;
728 }
729 else {
730 /* must be some in remData too */
731 toMovePtext = ptextData.Length;
732 toMoveRem = bytesMoved - toMovePtext; // remainder
733 }
734 if(toMovePtext) {
735 memmove(plainText, ptextData.Data, toMovePtext);
736 }
737 if(toMoveRem) {
738 memmove(plainText + toMovePtext, remData.Data,
739 toMoveRem);
740 }
741 serr = noErr;
742 }
743 }
744 else {
745 stPrintCdsaError("CSSM_DecryptData", crtn);
746 serr = errSSLCrypto;
747 }
748 if(cryptHand != 0) {
749 CSSM_DeleteContext(cryptHand);
750 }
751
752 /* free data mallocd by CSP */
753 stFreeCssmData(&ptextData, CSSM_FALSE);
754 stFreeCssmData(&remData, CSSM_FALSE);
755 return serr;
756 }
757
758 /*
759 * Obtain size of key in bytes.
760 */
761 UInt32 sslKeyLengthInBytes(const CSSM_KEY *key)
762 {
763 assert(key != NULL);
764 return (((key->KeyHeader.LogicalKeySizeInBits) + 7) / 8);
765 }
766
767 /*
768 * Get raw key bits from an RSA public key.
769 */
770 OSStatus sslGetPubKeyBits(
771 SSLContext *ctx,
772 const CSSM_KEY *pubKey,
773 CSSM_CSP_HANDLE cspHand,
774 SSLBuffer *modulus, // data mallocd and RETURNED
775 SSLBuffer *exponent) // data mallocd and RETURNED
776 {
777 CSSM_KEY wrappedKey;
778 CSSM_BOOL didWrap = CSSM_FALSE;
779 const CSSM_KEYHEADER *hdr;
780 CSSM_CC_HANDLE ccHand;
781 CSSM_RETURN crtn;
782 SSLBuffer pubKeyBlob;
783 OSStatus srtn;
784 CSSM_ACCESS_CREDENTIALS creds;
785
786 assert(ctx != NULL);
787 assert(modulus != NULL);
788 assert(exponent != NULL);
789 assert(pubKey != NULL);
790
791 hdr = &pubKey->KeyHeader;
792 if(hdr->KeyClass != CSSM_KEYCLASS_PUBLIC_KEY) {
793 sslErrorLog("sslGetPubKeyBits: bad keyClass (%ld)\n", hdr->KeyClass);
794 return errSSLInternal;
795 }
796 if(hdr->AlgorithmId != CSSM_ALGID_RSA) {
797 sslErrorLog("sslGetPubKeyBits: bad AlgorithmId (%ld)\n", hdr->AlgorithmId);
798 return errSSLInternal;
799 }
800
801 /*
802 * Handle possible reference format - I think it should be in
803 * blob form since it came from the DL, but conversion is
804 * simple.
805 */
806 switch(hdr->BlobType) {
807 case CSSM_KEYBLOB_RAW:
808 /* easy case */
809 CSSM_TO_SSLBUF(&pubKey->KeyData, &pubKeyBlob);
810 break;
811
812 case CSSM_KEYBLOB_REFERENCE:
813 /*
814 * Convert to a blob via "NULL wrap"; no wrapping key,
815 * ALGID_NONE
816 */
817 srtn = attachToCsp(ctx);
818 if(srtn) {
819 return srtn;
820 }
821 memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
822 crtn = CSSM_CSP_CreateSymmetricContext(ctx->cspHand,
823 CSSM_ALGID_NONE,
824 CSSM_ALGMODE_NONE,
825 &creds, // creds
826 pubKey,
827 NULL, // InitVector
828 CSSM_PADDING_NONE,
829 0, // reserved
830 &ccHand);
831 if(crtn) {
832 stPrintCdsaError("sslGetPubKeyBits: CreateSymmetricContext failure", crtn);
833 return errSSLCrypto;
834 }
835 memset(&wrappedKey, 0, sizeof(CSSM_KEY));
836 crtn = CSSM_WrapKey(ccHand,
837 &creds,
838 pubKey,
839 NULL, // descriptiveData
840 &wrappedKey);
841 CSSM_DeleteContext(ccHand);
842 if(crtn) {
843 stPrintCdsaError("CSSM_WrapKey", crtn);
844 return errSSLCrypto;
845 }
846 hdr = &wrappedKey.KeyHeader;
847 if(hdr->BlobType != CSSM_KEYBLOB_RAW) {
848 sslErrorLog("sslGetPubKeyBits: bad BlobType (%ld) after WrapKey\n",
849 hdr->BlobType);
850 return errSSLCrypto;
851 }
852 didWrap = CSSM_TRUE;
853 CSSM_TO_SSLBUF(&wrappedKey.KeyData, &pubKeyBlob);
854 break;
855
856 default:
857 sslErrorLog("sslGetPubKeyBits: bad BlobType (%ld)\n",
858 hdr->BlobType);
859 return errSSLInternal;
860
861 } /* switch BlobType */
862
863 assert(hdr->BlobType == CSSM_KEYBLOB_RAW);
864 srtn = sslDecodeRsaBlob(&pubKeyBlob, modulus, exponent);
865 if(didWrap) {
866 CSSM_FreeKey(ctx->cspHand, NULL, &wrappedKey, CSSM_FALSE);
867 }
868 return srtn;
869 }
870
871 /*
872 * Given raw RSA key bits, cook up a CSSM_KEY_PTR. Used in
873 * Server-initiated key exchange.
874 */
875 OSStatus sslGetPubKeyFromBits(
876 SSLContext *ctx,
877 const SSLBuffer *modulus,
878 const SSLBuffer *exponent,
879 CSSM_KEY_PTR *pubKey, // mallocd and RETURNED
880 CSSM_CSP_HANDLE *cspHand) // RETURNED
881 {
882 CSSM_KEY_PTR key = NULL;
883 OSStatus serr;
884 SSLBuffer blob;
885 CSSM_KEYHEADER_PTR hdr;
886 CSSM_KEY_SIZE keySize;
887 CSSM_RETURN crtn;
888
889 assert((ctx != NULL) && (modulus != NULL) && (exponent != NULL));
890 assert((pubKey != NULL) && (cspHand != NULL));
891
892 *pubKey = NULL;
893 *cspHand = 0;
894
895 serr = attachToCsp(ctx);
896 if(serr) {
897 return serr;
898 }
899 serr = sslEncodeRsaBlob(modulus, exponent, &blob);
900 if(serr) {
901 return serr;
902 }
903
904 /* the rest is boilerplate, cook up a good-looking public key */
905 key = (CSSM_KEY_PTR)sslMalloc(sizeof(CSSM_KEY));
906 if(key == NULL) {
907 return memFullErr;
908 }
909 memset(key, 0, sizeof(CSSM_KEY));
910 hdr = &key->KeyHeader;
911
912 hdr->HeaderVersion = CSSM_KEYHEADER_VERSION;
913 /* key_ptr->KeyHeader.CspId is unknown (remains 0) */
914 hdr->BlobType = CSSM_KEYBLOB_RAW;
915 hdr->AlgorithmId = CSSM_ALGID_RSA;
916 hdr->Format = CSSM_KEYBLOB_RAW_FORMAT_PKCS1;
917 hdr->KeyClass = CSSM_KEYCLASS_PUBLIC_KEY;
918 /* comply with ASA requirements */
919 hdr->KeyUsage = CSSM_KEYUSE_VERIFY;
920 hdr->KeyAttr = CSSM_KEYATTR_EXTRACTABLE;
921 /* key_ptr->KeyHeader.StartDate is unknown (remains 0) */
922 /* key_ptr->KeyHeader.EndDate is unknown (remains 0) */
923 hdr->WrapAlgorithmId = CSSM_ALGID_NONE;
924 hdr->WrapMode = CSSM_ALGMODE_NONE;
925
926 /* blob->data was mallocd by sslEncodeRsaBlob, pass it over to
927 * actual key */
928 SSLBUF_TO_CSSM(&blob, &key->KeyData);
929
930 /*
931 * Get keySizeInBits. This also serves to validate the key blob
932 * we just cooked up.
933 */
934 crtn = CSSM_QueryKeySizeInBits(ctx->cspHand, CSSM_INVALID_HANDLE, key, &keySize);
935 if(crtn) {
936 stPrintCdsaError("sslGetPubKeyFromBits: QueryKeySizeInBits\n", crtn);
937 serr = errSSLCrypto;
938 goto abort;
939 }
940
941 /* success */
942 hdr->LogicalKeySizeInBits = keySize.EffectiveKeySizeInBits;
943 *pubKey = key;
944 *cspHand = ctx->cspHand;
945 return noErr;
946
947 abort:
948 /* note this frees the blob */
949 sslFreeKey(ctx->cspHand, &key, NULL);
950 return serr;
951 }
952
953 #pragma mark -
954 #pragma mark *** Public Certificate Functions ***
955
956 /*
957 * Given a DER-encoded cert, obtain its public key as a CSSM_KEY_PTR.
958 * Caller must CSSM_FreeKey and free the CSSM_KEY_PTR itself.
959 *
960 * For now, the returned cspHand is a copy of ctx->cspHand, so it
961 * doesn't have to be detached later - this may change.
962 *
963 * Update: since CSSM_CL_CertGetKeyInfo() doesn't provide a means for
964 * us to tell the CL what CSP to use, we really have no way of knowing
965 * what is going on here...we return the process-wide (bare) cspHand,
966 * which is currently always able to deal with this raw public key.
967 */
968 OSStatus sslPubKeyFromCert(
969 SSLContext *ctx,
970 const SSLBuffer &derCert,
971 CSSM_KEY_PTR *pubKey, // RETURNED
972 CSSM_CSP_HANDLE *cspHand) // RETURNED
973 {
974 OSStatus serr;
975 CSSM_DATA certData;
976 CSSM_RETURN crtn;
977
978 assert(ctx != NULL);
979 assert(pubKey != NULL);
980 assert(cspHand != NULL);
981
982 *pubKey = NULL;
983 *cspHand = 0;
984
985 serr = attachToCl(ctx);
986 if(serr) {
987 return serr;
988 }
989 serr = attachToCsp(ctx);
990 if(serr) {
991 return serr;
992 }
993 SSLBUF_TO_CSSM(&derCert, &certData);
994 crtn = CSSM_CL_CertGetKeyInfo(ctx->clHand, &certData, pubKey);
995 if(crtn) {
996 return errSSLBadCert;
997 }
998 else {
999 *cspHand = ctx->cspHand;
1000 return noErr;
1001 }
1002 }
1003
1004 #if ST_MANAGES_TRUSTED_ROOTS
1005
1006 /*
1007 * Given a CSSM_CERTGROUP which fails due to CSSM_TP_INVALID_ANCHOR
1008 * (chain verifies to an unknown root):
1009 *
1010 * -- find the root cert
1011 * -- add it to newRootCertKc if present (else error)
1012 * -- add it to trustedCerts
1013 * -- re-verify certgroup, demand full success
1014 */
1015 static OSStatus sslHandleNewRoot(
1016 SSLContext *ctx,
1017 CSSM_CERTGROUP_PTR certGroup)
1018 {
1019 int i;
1020 CSSM_DATA_PTR rootCert;
1021 CSSM_BOOL expired;
1022 OSStatus serr;
1023 CSSM_BOOL brtn;
1024
1025 assert(ctx != NULL);
1026 assert(certGroup != NULL);
1027
1028 if(ctx->newRootCertKc == NULL) {
1029 /* no place to add this; done */
1030 return errSSLUnknownRootCert;
1031 }
1032
1033 /*
1034 * The root cert "should" be at the end of the chain, but
1035 * let's not assume that. (We are assuming that there is
1036 * only one root in the cert group...)
1037 */
1038 for(i=0; i<certGroup->NumCerts; i++) {
1039 rootCert = &certGroup->CertList[i];
1040 if(sslVerifyCert(ctx, rootCert, rootCert, ctx->cspHand, &expired)) {
1041 break;
1042 }
1043 }
1044 if(i == certGroup->NumCerts) {
1045 /* Huh! no root cert!? We should not have been called! */
1046 sslErrorLog("sslHandleNewRoot: no root cert!\n");
1047 return errSSLInternal;
1048 }
1049
1050 /*
1051 * Add to newRootCertKc. This may well fail due to user interaction.
1052 */
1053 serr = sslAddNewRoot(ctx, rootCert);
1054 if(serr) {
1055 return serr;
1056 }
1057
1058 /*
1059 * Just to be sure...reverify the whole cert chain.
1060 */
1061 brtn = CSSM_TP_CertGroupVerify(
1062 ctx->tpHand,
1063 ctx->clHand,
1064 ctx->cspHand,
1065 NULL, // DBList
1066 NULL, // PolicyIdentifiers
1067 0, // NumberofPolicyIdentifiers
1068 CSSM_TP_STOP_ON_POLICY,
1069 certGroup,
1070 ctx->trustedCerts, // AnchorCerts
1071 ctx->numTrustedCerts,
1072 NULL, // VerifyScope
1073 0, // ScopeSize
1074 0, // Action
1075 0, // Data
1076 NULL, // evidence
1077 NULL); // evidenceSize
1078 if(brtn == CSSM_FALSE) {
1079 sslErrorLog("sslHandleNewRoot: adding new root did not help!\n");
1080 return errSSLUnknownRootCert;
1081 }
1082 return noErr;
1083 }
1084
1085 #endif /* ST_MANAGES_TRUSTED_ROOTS */
1086
1087 /*
1088 * Verify a chain of DER-encoded certs.
1089 * First cert in a chain is root; this must also be present
1090 * in ctx->trustedCerts.
1091 */
1092 OSStatus sslVerifyCertChain(
1093 SSLContext *ctx,
1094 const SSLCertificate &certChain,
1095 bool verifyHostName /* = true */)
1096 {
1097 UInt32 numCerts;
1098 CSSM_CERTGROUP certGroup;
1099 int i;
1100 OSStatus serr;
1101 SSLCertificate *c = (SSLCertificate *)&certChain;
1102 CSSM_RETURN crtn;
1103 CSSM_TP_VERIFY_CONTEXT vfyCtx;
1104 CSSM_TP_CALLERAUTH_CONTEXT authCtx;
1105 CSSM_FIELD policyId;
1106 CSSM_DL_DB_LIST dbList;
1107 CSSM_APPLE_TP_SSL_OPTIONS sslOpts;
1108 CSSM_APPLE_TP_ACTION_DATA actionData;
1109
1110 if(!ctx->enableCertVerify) {
1111 /* trivial case, this is caller's responsibility */
1112 return noErr;
1113 }
1114 numCerts = SSLGetCertificateChainLength(&certChain);
1115 if(numCerts == 0) {
1116 /* nope */
1117 return errSSLBadCert;
1118 }
1119 #if 0
1120 serr = attachToAll(ctx);
1121 if(serr) {
1122 return serr;
1123 }
1124 #endif
1125
1126 /*
1127 * SSLCertificate chain --> CSSM TP cert group.
1128 * TP Cert group has root at the end, opposite of
1129 * SSLCertificate chain.
1130 */
1131 certGroup.GroupList.CertList =
1132 (CSSM_DATA_PTR)sslMalloc(numCerts * sizeof(CSSM_DATA));
1133 if(certGroup.GroupList.CertList == NULL) {
1134 return memFullErr;
1135 }
1136 certGroup.CertGroupType = CSSM_CERTGROUP_DATA;
1137 certGroup.CertType = CSSM_CERT_X_509v3;
1138 certGroup.CertEncoding = CSSM_CERT_ENCODING_DER;
1139 certGroup.NumCerts = numCerts;
1140
1141 memset(certGroup.GroupList.CertList, 0, numCerts * sizeof(CSSM_DATA));
1142
1143 for(i=numCerts-1; i>=0; i--) {
1144 SSLBUF_TO_CSSM(&c->derCert, &certGroup.GroupList.CertList[i]);
1145 c = c->next;
1146 }
1147
1148 memset(&vfyCtx, 0, sizeof(CSSM_TP_VERIFY_CONTEXT));
1149 vfyCtx.Action = CSSM_TP_ACTION_DEFAULT;
1150 vfyCtx.Cred = &authCtx;
1151
1152 /* CSSM_TP_CALLERAUTH_CONTEXT components */
1153 /*
1154 typedef struct cssm_tp_callerauth_context {
1155 CSSM_TP_POLICYINFO Policy;
1156 CSSM_TIMESTRING VerifyTime;
1157 CSSM_TP_STOP_ON VerificationAbortOn;
1158 CSSM_TP_VERIFICATION_RESULTS_CALLBACK CallbackWithVerifiedCert;
1159 uint32 NumberOfAnchorCerts;
1160 CSSM_DATA_PTR AnchorCerts;
1161 CSSM_DL_DB_LIST_PTR DBList;
1162 CSSM_ACCESS_CREDENTIALS_PTR CallerCredentials;
1163 } CSSM_TP_CALLERAUTH_CONTEXT, *CSSM_TP_CALLERAUTH_CONTEXT_PTR;
1164 */
1165
1166 /* SSL-specific FieldValue */
1167 sslOpts.Version = CSSM_APPLE_TP_SSL_OPTS_VERSION;
1168 if(verifyHostName) {
1169 sslOpts.ServerNameLen = ctx->peerDomainNameLen;
1170 sslOpts.ServerName = ctx->peerDomainName;
1171 }
1172 else {
1173 sslOpts.ServerNameLen = 0;
1174 sslOpts.ServerName = NULL;
1175 }
1176
1177 /* TP-wide ActionData */
1178 actionData.Version = CSSM_APPLE_TP_ACTION_VERSION;
1179 if(ctx->numTrustedCerts != 0) {
1180 /* use our anchors */
1181 actionData.ActionFlags = 0;
1182 }
1183 else {
1184 /* secret root-cert-enable */
1185 actionData.ActionFlags = 0x80000000;
1186 }
1187 if(ctx->allowExpiredCerts) {
1188 actionData.ActionFlags |= CSSM_TP_ACTION_ALLOW_EXPIRED;
1189 }
1190 if(ctx->allowExpiredRoots) {
1191 actionData.ActionFlags |= CSSM_TP_ACTION_ALLOW_EXPIRED_ROOT;
1192 }
1193 vfyCtx.ActionData.Data = (uint8 *)&actionData;
1194 vfyCtx.ActionData.Length = sizeof(actionData);
1195
1196 /* zero or one policy here */
1197 policyId.FieldOid = CSSMOID_APPLE_TP_SSL;
1198 policyId.FieldValue.Data = (uint8 *)&sslOpts;
1199 policyId.FieldValue.Length = sizeof(sslOpts);
1200 authCtx.Policy.NumberOfPolicyIds = 1;
1201 authCtx.Policy.PolicyIds = &policyId;
1202
1203 authCtx.VerifyTime = NULL;
1204 authCtx.VerificationAbortOn = CSSM_TP_STOP_ON_POLICY;
1205 authCtx.CallbackWithVerifiedCert = NULL;
1206 authCtx.NumberOfAnchorCerts = ctx->numTrustedCerts;
1207 authCtx.AnchorCerts = ctx->trustedCerts;
1208 memset(&dbList, 0, sizeof(CSSM_DL_DB_LIST));
1209 authCtx.DBList = &dbList;
1210 authCtx.CallerCredentials = NULL;
1211
1212 /*
1213 * Here we go; hand it over to TP. Note trustedCerts are our
1214 * known good Anchor certs; they're already formatted properly.
1215 * Unlike most other Apple code, we demand full success here,
1216 * implying that the last cert in the chain is indeed an Anchor
1217 * cert. We already know that all of our anchor certs are
1218 * roots, so on successful return, we'll know the incoming
1219 * chain has a root, it verifies to that root, and that that
1220 * root is in trustedCerts.
1221 */
1222 crtn = CSSM_TP_CertGroupVerify(ctx->tpHand,
1223 ctx->clHand,
1224 ctx->cspHand,
1225 &certGroup,
1226 &vfyCtx,
1227 NULL); // no evidence needed
1228
1229 serr = noErr;
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 sslErrorLog("***Warning: accepting unknown root cert\n");
1237 break;
1238 }
1239 #if ST_MANAGES_TRUSTED_ROOTS
1240 if(ctx->newRootCertKc != NULL) {
1241 /* see if user wants to handle new root */
1242 serr = sslHandleNewRoot(ctx, &certGroup);
1243 }
1244 else {
1245 serr = errSSLUnknownRootCert;
1246 }
1247 #else
1248 serr = errSSLUnknownRootCert;
1249 #endif /* ST_MANAGES_TRUSTED_ROOTS */
1250 break;
1251 case CSSMERR_TP_NOT_TRUSTED:
1252 /* no root, not even in implicit SSL roots */
1253 if(ctx->allowAnyRoot) {
1254 sslErrorLog("***Warning: accepting unverified cert chain\n");
1255 break;
1256 }
1257 serr = errSSLNoRootCert;
1258 break;
1259 case CSSMERR_TP_CERT_EXPIRED:
1260 assert(!ctx->allowExpiredCerts);
1261 serr = errSSLCertExpired;
1262 break;
1263 case CSSMERR_TP_CERT_NOT_VALID_YET:
1264 serr = errSSLCertNotYetValid;
1265 break;
1266 default:
1267 stPrintCdsaError(
1268 "sslVerifyCertChain: CSSM_TP_CertGroupVerify returned", crtn);
1269 serr = errSSLXCertChainInvalid;
1270 break;
1271 }
1272 } /* brtn FALSE */
1273
1274 /*
1275 * don't free individual certs - caller still owns them
1276 * don't free struct - on stack
1277 */
1278 sslFree(certGroup.GroupList.CertList);
1279 return serr;
1280 }
1281
1282 #if ST_MANAGES_TRUSTED_ROOTS
1283
1284 /*
1285 * Given a DER-encoded cert, obtain its DER-encoded subject name.
1286 */
1287 CSSM_DATA_PTR sslGetCertSubjectName(
1288 SSLContext *ctx,
1289 const CSSM_DATA_PTR cert)
1290 {
1291 uint32 NumberOfFields = 0;
1292 CSSM_HANDLE ResultsHandle = 0;
1293 CSSM_DATA_PTR pEncodedName = NULL;
1294 CSSM_RETURN crtn;
1295
1296 /* ensure connection to CL */
1297 if(attachToCl(ctx)) {
1298 return NULL;
1299 }
1300 crtn = CSSM_CL_CertGetFirstFieldValue(
1301 ctx->clHand,
1302 cert,
1303 &CSSMOID_X509V1SubjectName,
1304 &ResultsHandle,
1305 &NumberOfFields,
1306 &pEncodedName);
1307 if(crtn) {
1308 stPrintCdsaError("CertGetFirstFieldValue", crtn);
1309 }
1310 CSSM_CL_CertAbortQuery(ctx->clHand, ResultsHandle);
1311 return pEncodedName;
1312 }
1313 #endif /* ST_MANAGES_TRUSTED_ROOTS */
1314
1315 #if (SSL_DEBUG && ST_MANAGES_TRUSTED_ROOTS)
1316 void verifyTrustedRoots(SSLContext *ctx,
1317 CSSM_DATA_PTR certs,
1318 unsigned numCerts)
1319 {
1320 int i;
1321 CSSM_DATA_PTR cert;
1322 CSSM_BOOL expired;
1323
1324 for(i=0; i<numCerts; i++) {
1325 cert = &certs[i];
1326 if(!sslVerifyCert(ctx,
1327 cert,
1328 cert,
1329 ctx->cspHand,
1330 &expired)) {
1331 sslErrorLog("Bad trusted cert!\n");
1332 }
1333 }
1334 }
1335 #endif
1336
1337 #ifndef NDEBUG
1338 void stPrintCdsaError(const char *op, CSSM_RETURN crtn)
1339 {
1340 cssmPerror(op, crtn);
1341 }
1342
1343 char *stCssmErrToStr(CSSM_RETURN err)
1344 {
1345 string errStr = cssmErrorString(err);
1346 return const_cast<char *>(errStr.c_str());
1347 }
1348 #endif
1349
1350