]> git.saurik.com Git - apple/security.git/blame - SecureTransport/appleCdsa.cpp
Security-176.tar.gz
[apple/security.git] / SecureTransport / appleCdsa.cpp
CommitLineData
bac41a7b
A
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/*
5a719ac8 20 File: appleCdsa.cpp
bac41a7b
A
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"
5a719ac8
A
31#include "sslContext.h"
32#include "sslMemory.h"
bac41a7b 33#include "appleCdsa.h"
5a719ac8 34#include "sslUtils.h"
bac41a7b
A
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>
29654253 45#include <assert.h>
bac41a7b
A
46
47#include <Security/cssm.h>
48#include <Security/cssmapple.h>
5a719ac8 49#include <Security/cssmerrno.h>
df0e469f
A
50#include <Security/Security.h>
51#include <Security/SecTrustPriv.h>
52#include <Security/SecPolicyPriv.h>
9a27adb2 53#include <Security/SecKeyPriv.h>
bac41a7b
A
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
29654253
A
62/*
63 * Set up a Raw symmetric key with specified algorithm and key bits.
64 */
5a719ac8 65OSStatus sslSetUpSymmKey(
29654253
A
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{
5a719ac8 73 OSStatus serr;
29654253
A
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;
5a719ac8 99 return noErr;
29654253
A
100}
101
bac41a7b
A
102/*
103 * Free a CSSM_KEY - its CSP resources, KCItemRef, and the key itself.
104 */
5a719ac8 105OSStatus sslFreeKey(
bac41a7b
A
106 CSSM_CSP_HANDLE cspHand,
107 CSSM_KEY_PTR *key, /* so we can null it out */
5a719ac8 108 #if ST_KC_KEYS_NEED_REF
29654253
A
109 SecKeychainRef *kcItem)
110 #else
111 void *kcItem)
bac41a7b
A
112 #endif
113{
5a719ac8 114 assert(key != NULL);
bac41a7b
A
115
116 if(*key != NULL) {
117 if(cspHand != 0) {
118 CSSM_FreeKey(cspHand, NULL, *key, CSSM_FALSE);
119 }
5a719ac8 120 stAppFree(*key, NULL); // key mallocd by CL using our callback
bac41a7b
A
121 *key = NULL;
122 }
5a719ac8 123 #if ST_KC_KEYS_NEED_REF
bac41a7b
A
124 if((kcItem != NULL) && (*kcItem != NULL)) {
125 KCReleaseItem(kcItem); /* does this NULL the referent? */
126 *kcItem = NULL;
127 }
128 #endif
5a719ac8 129 return noErr;
bac41a7b
A
130}
131
132/*
133 * Standard app-level memory functions required by CDSA.
134 */
135void * stAppMalloc (uint32 size, void *allocRef) {
136 return( malloc(size) );
137}
138void stAppFree (void *mem_ptr, void *allocRef) {
139 free(mem_ptr);
140 return;
141}
142void * stAppRealloc (void *ptr, uint32 size, void *allocRef) {
143 return( realloc( ptr, size ) );
144}
145void * 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 */
5a719ac8 156OSStatus attachToCsp(SSLContext *ctx)
bac41a7b 157{
5a719ac8 158 assert(ctx != NULL);
bac41a7b 159 if(ctx->cspHand != 0) {
5a719ac8 160 return noErr;
bac41a7b
A
161 }
162 else {
5a719ac8 163 return errSSLModuleAttach;
bac41a7b
A
164 }
165}
166
167/*
168 * Connect to TP, CL; reusable.
169 */
5a719ac8 170OSStatus attachToCl(SSLContext *ctx)
bac41a7b 171{
5a719ac8 172 assert(ctx != NULL);
bac41a7b 173 if(ctx->clHand != 0) {
5a719ac8 174 return noErr;
bac41a7b
A
175 }
176 else {
5a719ac8 177 return errSSLModuleAttach;
bac41a7b
A
178 }
179}
180
5a719ac8 181OSStatus attachToTp(SSLContext *ctx)
bac41a7b 182{
5a719ac8 183 assert(ctx != NULL);
bac41a7b 184 if(ctx->tpHand != 0) {
5a719ac8 185 return noErr;
bac41a7b
A
186 }
187 else {
5a719ac8 188 return errSSLModuleAttach;
bac41a7b
A
189 }
190}
191
192/*
193 * Convenience function - attach to CSP, CL, TP. Reusable.
194 */
5a719ac8 195OSStatus attachToAll(SSLContext *ctx)
bac41a7b
A
196{
197 CSSM_RETURN crtn;
198
5a719ac8
A
199 assert(ctx != NULL);
200 crtn = attachToModules(&ctx->cspHand, &ctx->clHand, &ctx->tpHand);
bac41a7b 201 if(crtn) {
5a719ac8 202 return errSSLModuleAttach;
bac41a7b
A
203 }
204 else {
5a719ac8 205 return noErr;
bac41a7b
A
206 }
207}
208
5a719ac8 209OSStatus detachFromAll(SSLContext *ctx)
bac41a7b
A
210{
211 #if 0
212 /* No more, attachments are kept on a global basis */
5a719ac8 213 assert(ctx != NULL);
bac41a7b
A
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 */
5a719ac8 227 return noErr;
bac41a7b
A
228}
229
df0e469f
A
230/*
231 * Add a CSSM_ATTRIBUTE_RSA_BLINDING attribute to
232 * specified crypto context.
233 */
234static 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
9a27adb2
A
250/* Get CSP, key in CSSM format from a SecKeyRef */
251static 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
bac41a7b
A
270#pragma mark -
271#pragma mark *** CSSM_DATA routines ***
272
273CSSM_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
291void 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 */
5a719ac8 312OSStatus stSetUpCssmData(
bac41a7b
A
313 CSSM_DATA_PTR data,
314 uint32 length)
315{
5a719ac8 316 assert(data != NULL);
bac41a7b
A
317 if(data->Length == 0) {
318 data->Data = (uint8 *)stAppMalloc(length, NULL);
319 if(data->Data == NULL) {
5a719ac8 320 return memFullErr;
bac41a7b
A
321 }
322 }
323 else if(data->Length < length) {
5a719ac8
A
324 sslErrorLog("stSetUpCssmData: length too small\n");
325 return memFullErr;
bac41a7b
A
326 }
327 data->Length = length;
5a719ac8 328 return noErr;
bac41a7b
A
329}
330
df0e469f
A
331static OSStatus sslKeyToSigAlg(
332 const CSSM_KEY *cssmKey,
333 CSSM_ALGORITHMS &sigAlg) /* RETURNED */
bac41a7b 334
df0e469f
A
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;
bac41a7b 347 }
df0e469f 348 return ortn;
bac41a7b
A
349}
350
df0e469f
A
351#pragma mark -
352#pragma mark *** Public CSP Functions ***
bac41a7b 353
df0e469f
A
354/*
355 * Raw RSA/DSA sign/verify.
356 */
357OSStatus sslRawSign(
bac41a7b 358 SSLContext *ctx,
9a27adb2 359 SecKeyRef privKeyRef,
bac41a7b
A
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;
df0e469f 368 OSStatus serr;
bac41a7b
A
369 CSSM_DATA sigData;
370 CSSM_DATA ptextData;
9a27adb2
A
371 CSSM_CSP_HANDLE cspHand;
372 const CSSM_KEY *privKey;
373 const CSSM_ACCESS_CREDENTIALS *creds;
bac41a7b 374
5a719ac8 375 assert(ctx != NULL);
9a27adb2 376 if((privKeyRef == NULL) ||
bac41a7b
A
377 (plainText == NULL) ||
378 (sig == NULL) ||
379 (actualBytes == NULL)) {
5a719ac8
A
380 sslErrorLog("sslRsaRawSign: bad arguments\n");
381 return errSSLInternal;
bac41a7b
A
382 }
383 *actualBytes = 0;
384
9a27adb2
A
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
df0e469f
A
392 CSSM_ALGORITHMS sigAlg;
393 serr = sslKeyToSigAlg(privKey, sigAlg);
394 if(serr) {
395 return serr;
396 }
9a27adb2
A
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
bac41a7b 412 crtn = CSSM_CSP_CreateSignatureContext(cspHand,
df0e469f 413 sigAlg,
9a27adb2 414 creds,
bac41a7b
A
415 privKey,
416 &sigHand);
417 if(crtn) {
418 stPrintCdsaError("CSSM_CSP_CreateSignatureContext (1)", crtn);
5a719ac8 419 return errSSLCrypto;
bac41a7b 420 }
df0e469f
A
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 }
bac41a7b
A
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,
df0e469f 443 CSSM_ALGID_NONE, // digestAlg for raw sign
bac41a7b
A
444 &sigData);
445 if(crtn) {
446 stPrintCdsaError("CSSM_SignData", crtn);
5a719ac8 447 serr = errSSLCrypto;
bac41a7b
A
448 }
449 else {
450 *actualBytes = sigData.Length;
5a719ac8 451 serr = noErr;
bac41a7b
A
452 }
453 if(sigHand != 0) {
454 CSSM_DeleteContext(sigHand);
455 }
456 return serr;
457}
458
df0e469f 459OSStatus sslRawVerify(
bac41a7b 460 SSLContext *ctx,
29654253 461 const CSSM_KEY *pubKey,
bac41a7b
A
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;
df0e469f 470 OSStatus serr;
bac41a7b
A
471 CSSM_DATA sigData;
472 CSSM_DATA ptextData;
473
5a719ac8 474 assert(ctx != NULL);
bac41a7b
A
475 if((pubKey == NULL) ||
476 (cspHand == 0) ||
477 (plainText == NULL) ||
478 (sig == NULL)) {
df0e469f 479 sslErrorLog("sslRawVerify: bad arguments\n");
5a719ac8 480 return errSSLInternal;
bac41a7b
A
481 }
482
df0e469f
A
483 CSSM_ALGORITHMS sigAlg;
484 serr = sslKeyToSigAlg(pubKey, sigAlg);
485 if(serr) {
486 return serr;
487 }
bac41a7b 488 crtn = CSSM_CSP_CreateSignatureContext(cspHand,
df0e469f 489 sigAlg,
bac41a7b
A
490 NULL, // passPhrase
491 pubKey,
492 &sigHand);
493 if(sigHand == 0) {
494 stPrintCdsaError("CSSM_CSP_CreateSignatureContext (2)", crtn);
5a719ac8 495 return errSSLCrypto;
bac41a7b
A
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);
5a719ac8 510 serr = errSSLCrypto;
bac41a7b
A
511 }
512 else {
5a719ac8 513 serr = noErr;
bac41a7b
A
514 }
515 if(sigHand != 0) {
516 CSSM_DeleteContext(sigHand);
517 }
518 return serr;
519}
bac41a7b
A
520
521/*
522 * Encrypt/Decrypt
523 */
5a719ac8 524OSStatus sslRsaEncrypt(
bac41a7b 525 SSLContext *ctx,
29654253 526 const CSSM_KEY *pubKey,
bac41a7b
A
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;
df0e469f 538 OSStatus serr = errSSLInternal;
bac41a7b
A
539 CSSM_RETURN crtn;
540 uint32 bytesMoved = 0;
541 CSSM_ACCESS_CREDENTIALS creds;
542
5a719ac8
A
543 assert(ctx != NULL);
544 assert(actualBytes != NULL);
bac41a7b
A
545 *actualBytes = 0;
546
547 if((pubKey == NULL) || (cspHand == 0)) {
5a719ac8
A
548 sslErrorLog("sslRsaEncrypt: bad pubKey/cspHand\n");
549 return errSSLInternal;
bac41a7b 550 }
df0e469f 551 assert(pubKey->KeyHeader.KeyClass == CSSM_KEYCLASS_PUBLIC_KEY);
bac41a7b
A
552
553 #if RSA_PUB_KEY_USAGE_HACK
29654253 554 ((CSSM_KEY_PTR)pubKey)->KeyHeader.KeyUsage |= CSSM_KEYUSE_ENCRYPT;
bac41a7b
A
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,
29654253 562 CSSM_PADDING_PKCS1,
bac41a7b
A
563 &cryptHand);
564 if(crtn) {
565 stPrintCdsaError("CSSM_CSP_CreateAsymmetricContext", crtn);
5a719ac8 566 return errSSLCrypto;
bac41a7b
A
567 }
568 ptextData.Data = (uint8 *)plainText;
569 ptextData.Length = plainTextLen;
570
bac41a7b
A
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) {
5a719ac8 587 sslErrorLog("sslRsaEncrypt overflow; cipherTextLen %ld bytesMoved %ld\n",
bac41a7b 588 cipherTextLen, bytesMoved);
5a719ac8 589 serr = errSSLCrypto;
bac41a7b
A
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 }
5a719ac8 617 serr = noErr;
bac41a7b
A
618 }
619 }
620 else {
621 stPrintCdsaError("CSSM_EncryptData", crtn);
5a719ac8 622 serr = errSSLCrypto;
bac41a7b
A
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
5a719ac8 634OSStatus sslRsaDecrypt(
bac41a7b 635 SSLContext *ctx,
9a27adb2 636 SecKeyRef privKeyRef,
bac41a7b
A
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;
df0e469f 647 OSStatus serr = errSSLInternal;
bac41a7b
A
648 CSSM_RETURN crtn;
649 uint32 bytesMoved = 0;
9a27adb2
A
650 CSSM_CSP_HANDLE cspHand;
651 const CSSM_KEY *privKey;
652 const CSSM_ACCESS_CREDENTIALS *creds;
bac41a7b 653
5a719ac8
A
654 assert(ctx != NULL);
655 assert(actualBytes != NULL);
bac41a7b
A
656 *actualBytes = 0;
657
9a27adb2
A
658 if(privKeyRef == NULL) {
659 sslErrorLog("sslRsaDecrypt: bad privKey\n");
5a719ac8 660 return errSSLInternal;
bac41a7b 661 }
9a27adb2
A
662
663 /* Get CSP, signing key in CSSM format */
664 serr = sslGetKeyParts(privKeyRef, &privKey, &cspHand);
665 if(serr) {
666 return serr;
667 }
df0e469f 668 assert(privKey->KeyHeader.KeyClass == CSSM_KEYCLASS_PRIVATE_KEY);
9a27adb2
A
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 }
bac41a7b
A
683 crtn = CSSM_CSP_CreateAsymmetricContext(cspHand,
684 CSSM_ALGID_RSA,
9a27adb2 685 creds,
bac41a7b 686 privKey,
29654253 687 CSSM_PADDING_PKCS1,
bac41a7b
A
688 &cryptHand);
689 if(crtn) {
690 stPrintCdsaError("CSSM_CSP_CreateAsymmetricContext", crtn);
5a719ac8 691 return errSSLCrypto;
bac41a7b
A
692 }
693 ctextData.Data = (uint8 *)cipherText;
694 ctextData.Length = cipherTextLen;
695
df0e469f
A
696 if((ctx->rsaBlindingEnable) &&
697 (privKey->KeyHeader.AlgorithmId == CSSM_ALGID_RSA)) {
bac41a7b 698 /*
df0e469f 699 * Turn on RSA blinding to defeat timing attacks
bac41a7b 700 */
df0e469f 701 crtn = sslAddBlindingAttr(cryptHand);
bac41a7b 702 if(crtn) {
df0e469f 703 return crtn;
bac41a7b
A
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) {
5a719ac8 723 sslErrorLog("sslRsaDecrypt overflow; plainTextLen %ld bytesMoved %ld\n",
bac41a7b 724 plainTextLen, bytesMoved);
5a719ac8 725 serr = errSSLCrypto;
bac41a7b
A
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 }
5a719ac8 753 serr = noErr;
bac41a7b
A
754 }
755 }
756 else {
757 stPrintCdsaError("CSSM_DecryptData", crtn);
5a719ac8 758 serr = errSSLCrypto;
bac41a7b
A
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
bac41a7b
A
770/*
771 * Obtain size of key in bytes.
772 */
29654253 773UInt32 sslKeyLengthInBytes(const CSSM_KEY *key)
bac41a7b 774{
5a719ac8 775 assert(key != NULL);
bac41a7b
A
776 return (((key->KeyHeader.LogicalKeySizeInBits) + 7) / 8);
777}
778
df0e469f
A
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 */
783OSStatus 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}
bac41a7b
A
810/*
811 * Get raw key bits from an RSA public key.
812 */
5a719ac8 813OSStatus sslGetPubKeyBits(
bac41a7b 814 SSLContext *ctx,
29654253 815 const CSSM_KEY *pubKey,
bac41a7b
A
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;
29654253 822 const CSSM_KEYHEADER *hdr;
bac41a7b 823 SSLBuffer pubKeyBlob;
9a27adb2 824 OSStatus srtn;
bac41a7b 825
5a719ac8
A
826 assert(ctx != NULL);
827 assert(modulus != NULL);
828 assert(exponent != NULL);
829 assert(pubKey != NULL);
bac41a7b
A
830
831 hdr = &pubKey->KeyHeader;
832 if(hdr->KeyClass != CSSM_KEYCLASS_PUBLIC_KEY) {
5a719ac8
A
833 sslErrorLog("sslGetPubKeyBits: bad keyClass (%ld)\n", hdr->KeyClass);
834 return errSSLInternal;
bac41a7b
A
835 }
836 if(hdr->AlgorithmId != CSSM_ALGID_RSA) {
5a719ac8
A
837 sslErrorLog("sslGetPubKeyBits: bad AlgorithmId (%ld)\n", hdr->AlgorithmId);
838 return errSSLInternal;
bac41a7b 839 }
9a27adb2
A
840
841 /* Note currently ALL public keys are raw, obtained from the CL... */
842 assert(hdr->BlobType == CSSM_KEYBLOB_RAW);
843
bac41a7b
A
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:
9a27adb2
A
856
857 sslErrorLog("sslGetPubKeyBits: bad BlobType (%ld)\n",
858 hdr->BlobType);
859 return errSSLInternal;
860
861 #if 0
bac41a7b
A
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);
5a719ac8 882 return errSSLCrypto;
bac41a7b
A
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);
5a719ac8 893 return errSSLCrypto;
bac41a7b
A
894 }
895 hdr = &wrappedKey.KeyHeader;
896 if(hdr->BlobType != CSSM_KEYBLOB_RAW) {
5a719ac8 897 sslErrorLog("sslGetPubKeyBits: bad BlobType (%ld) after WrapKey\n",
bac41a7b 898 hdr->BlobType);
5a719ac8 899 return errSSLCrypto;
bac41a7b
A
900 }
901 didWrap = CSSM_TRUE;
902 CSSM_TO_SSLBUF(&wrappedKey.KeyData, &pubKeyBlob);
903 break;
9a27adb2
A
904 #endif /* 0 */
905
bac41a7b 906 default:
5a719ac8 907 sslErrorLog("sslGetPubKeyBits: bad BlobType (%ld)\n",
bac41a7b 908 hdr->BlobType);
5a719ac8 909 return errSSLInternal;
bac41a7b
A
910
911 } /* switch BlobType */
912
5a719ac8 913 assert(hdr->BlobType == CSSM_KEYBLOB_RAW);
bac41a7b
A
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 */
5a719ac8 925OSStatus sslGetPubKeyFromBits(
bac41a7b
A
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;
5a719ac8 933 OSStatus serr;
bac41a7b
A
934 SSLBuffer blob;
935 CSSM_KEYHEADER_PTR hdr;
936 CSSM_KEY_SIZE keySize;
937 CSSM_RETURN crtn;
938
5a719ac8
A
939 assert((ctx != NULL) && (modulus != NULL) && (exponent != NULL));
940 assert((pubKey != NULL) && (cspHand != NULL));
bac41a7b
A
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 */
5a719ac8 955 key = (CSSM_KEY_PTR)sslMalloc(sizeof(CSSM_KEY));
bac41a7b 956 if(key == NULL) {
5a719ac8 957 return memFullErr;
bac41a7b
A
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);
5a719ac8 987 serr = errSSLCrypto;
bac41a7b
A
988 goto abort;
989 }
990
991 /* success */
992 hdr->LogicalKeySizeInBits = keySize.EffectiveKeySizeInBits;
993 *pubKey = key;
994 *cspHand = ctx->cspHand;
5a719ac8 995 return noErr;
bac41a7b
A
996
997abort:
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
29654253
A
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.
bac41a7b 1017 */
5a719ac8 1018OSStatus sslPubKeyFromCert(
bac41a7b 1019 SSLContext *ctx,
5a719ac8 1020 const SSLBuffer &derCert,
bac41a7b
A
1021 CSSM_KEY_PTR *pubKey, // RETURNED
1022 CSSM_CSP_HANDLE *cspHand) // RETURNED
1023{
5a719ac8 1024 OSStatus serr;
bac41a7b
A
1025 CSSM_DATA certData;
1026 CSSM_RETURN crtn;
1027
5a719ac8
A
1028 assert(ctx != NULL);
1029 assert(pubKey != NULL);
1030 assert(cspHand != NULL);
bac41a7b
A
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 }
5a719ac8 1043 SSLBUF_TO_CSSM(&derCert, &certData);
bac41a7b
A
1044 crtn = CSSM_CL_CertGetKeyInfo(ctx->clHand, &certData, pubKey);
1045 if(crtn) {
5a719ac8 1046 return errSSLBadCert;
bac41a7b
A
1047 }
1048 else {
1049 *cspHand = ctx->cspHand;
5a719ac8 1050 return noErr;
bac41a7b
A
1051 }
1052}
1053
bac41a7b 1054/*
df0e469f 1055 * Release each element in a CFArray.
bac41a7b 1056 */
df0e469f
A
1057static void sslReleaseArray(
1058 CFArrayRef a)
bac41a7b 1059{
df0e469f
A
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);
bac41a7b 1065 }
bac41a7b
A
1066}
1067
bac41a7b
A
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.
df0e469f
A
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.
bac41a7b 1077 */
df0e469f 1078 OSStatus sslVerifyCertChain(
bac41a7b 1079 SSLContext *ctx,
5a719ac8 1080 const SSLCertificate &certChain,
df0e469f 1081 bool arePeerCerts /* = true */)
bac41a7b
A
1082{
1083 UInt32 numCerts;
bac41a7b 1084 int i;
df0e469f 1085 OSStatus serr;
5a719ac8 1086 SSLCertificate *c = (SSLCertificate *)&certChain;
bac41a7b 1087 CSSM_RETURN crtn;
29654253 1088 CSSM_APPLE_TP_SSL_OPTIONS sslOpts;
df0e469f
A
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;
bac41a7b 1099
df0e469f
A
1100 if(ctx->peerSecTrust && arePeerCerts) {
1101 /* renegotiate - start with a new SecTrustRef */
1102 CFRelease(ctx->peerSecTrust);
1103 ctx->peerSecTrust = NULL;
5a719ac8 1104 }
df0e469f 1105
5a719ac8 1106 numCerts = SSLGetCertificateChainLength(&certChain);
bac41a7b
A
1107 if(numCerts == 0) {
1108 /* nope */
5a719ac8 1109 return errSSLBadCert;
bac41a7b 1110 }
bac41a7b
A
1111
1112 /*
df0e469f 1113 * SSLCertificate chain --> CFArrayRef of SecCertificateRefs.
bac41a7b
A
1114 * TP Cert group has root at the end, opposite of
1115 * SSLCertificate chain.
1116 */
df0e469f
A
1117 CFMutableArrayRef certGroup = CFArrayCreateMutable(NULL, numCerts,
1118 &kCFTypeArrayCallBacks);
1119 if(certGroup == NULL) {
5a719ac8 1120 return memFullErr;
bac41a7b 1121 }
df0e469f 1122 /* subsequent errors to errOut: */
bac41a7b
A
1123
1124 for(i=numCerts-1; i>=0; i--) {
df0e469f
A
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);
bac41a7b
A
1138 c = c->next;
1139 }
1140
bac41a7b 1141 /*
df0e469f
A
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 }
29654253 1160 sslOpts.Version = CSSM_APPLE_TP_SSL_OPTS_VERSION;
df0e469f 1161 if(arePeerCerts) {
5a719ac8
A
1162 sslOpts.ServerNameLen = ctx->peerDomainNameLen;
1163 sslOpts.ServerName = ctx->peerDomainName;
1164 }
1165 else {
1166 sslOpts.ServerNameLen = 0;
1167 sslOpts.ServerName = NULL;
1168 }
df0e469f
A
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 }
29654253 1177
df0e469f
A
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;
5a719ac8 1184 }
df0e469f
A
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 }
5a719ac8 1209 }
df0e469f
A
1210 tpActionData.Version = CSSM_APPLE_TP_ACTION_VERSION;
1211 tpActionData.ActionFlags = 0;
29654253 1212 if(ctx->allowExpiredCerts) {
df0e469f 1213 tpActionData.ActionFlags |= CSSM_TP_ACTION_ALLOW_EXPIRED;
29654253 1214 }
5a719ac8 1215 if(ctx->allowExpiredRoots) {
df0e469f 1216 tpActionData.ActionFlags |= CSSM_TP_ACTION_ALLOW_EXPIRED_ROOT;
5a719ac8 1217 }
df0e469f 1218 actionData = CFDataCreate(NULL, (UInt8 *)&tpActionData, sizeof(tpActionData));
29654253 1219
df0e469f
A
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 }
bac41a7b 1227
df0e469f
A
1228 #if 0
1229 /* Disabled for Radar 3421314 */
bac41a7b 1230 /*
df0e469f
A
1231 * Avoid searching user keychains for intermediate certs by specifying
1232 * an empty array of keychains
bac41a7b 1233 */
df0e469f
A
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 }
bac41a7b 1258
df0e469f
A
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 }
bac41a7b
A
1301 if(crtn) {
1302 /* get some detailed error info */
1303 switch(crtn) {
29654253 1304 case CSSMERR_TP_INVALID_ANCHOR_CERT:
bac41a7b
A
1305 /* root found but we don't trust it */
1306 if(ctx->allowAnyRoot) {
df0e469f 1307 serr = noErr;
5a719ac8 1308 sslErrorLog("***Warning: accepting unknown root cert\n");
bac41a7b
A
1309 }
1310 else {
5a719ac8 1311 serr = errSSLUnknownRootCert;
bac41a7b 1312 }
bac41a7b
A
1313 break;
1314 case CSSMERR_TP_NOT_TRUSTED:
1315 /* no root, not even in implicit SSL roots */
1316 if(ctx->allowAnyRoot) {
5a719ac8 1317 sslErrorLog("***Warning: accepting unverified cert chain\n");
df0e469f
A
1318 serr = noErr;
1319 }
1320 else {
1321 serr = errSSLNoRootCert;
bac41a7b 1322 }
bac41a7b
A
1323 break;
1324 case CSSMERR_TP_CERT_EXPIRED:
29654253 1325 assert(!ctx->allowExpiredCerts);
5a719ac8 1326 serr = errSSLCertExpired;
bac41a7b
A
1327 break;
1328 case CSSMERR_TP_CERT_NOT_VALID_YET:
5a719ac8 1329 serr = errSSLCertNotYetValid;
bac41a7b
A
1330 break;
1331 default:
df0e469f
A
1332 stPrintCdsaError("sslVerifyCertChain: SecTrustEvaluate returned",
1333 crtn);
5a719ac8 1334 serr = errSSLXCertChainInvalid;
bac41a7b
A
1335 break;
1336 }
df0e469f 1337 } /* SecTrustEvaluate error */
bac41a7b 1338
df0e469f 1339errOut:
bac41a7b 1340 /*
df0e469f
A
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.
bac41a7b 1344 */
df0e469f
A
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 }
bac41a7b
A
1369 return serr;
1370}
1371
df0e469f
A
1372#ifndef NDEBUG
1373void stPrintCdsaError(const char *op, CSSM_RETURN crtn)
1374{
1375 cssmPerror(op, crtn);
1376}
1377
1378char *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 ***
bac41a7b
A
1387
1388/*
df0e469f
A
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.
bac41a7b 1393 */
df0e469f
A
1394OSStatus sslDhGenKeyPairClient(
1395 SSLContext *ctx,
1396 const SSLBuffer &prime,
1397 const SSLBuffer &generator,
1398 CSSM_KEY_PTR publicKey, // RETURNED
1399 CSSM_KEY_PTR privateKey) // RETURNED
bac41a7b 1400{
df0e469f
A
1401 assert((prime.data != NULL) && (generator.data != NULL));
1402 if(prime.data && !generator.data) {
1403 return errSSLProtocol;
bac41a7b 1404 }
df0e469f
A
1405 if(!prime.data && generator.data) {
1406 return errSSLProtocol;
bac41a7b 1407 }
df0e469f
A
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;
bac41a7b 1418}
bac41a7b 1419
df0e469f
A
1420OSStatus 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);
bac41a7b 1435
df0e469f
A
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;
bac41a7b 1452 }
df0e469f
A
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;
bac41a7b 1471}
bac41a7b 1472
df0e469f
A
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
1486OSStatus sslDhKeyExchange(
1487 SSLContext *ctx,
1488 uint32 deriveSizeInBits,
1489 SSLBuffer *exchanged)
5a719ac8 1490{
df0e469f
A
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;
5a719ac8
A
1550}
1551
df0e469f
A
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 */
1561OSStatus sslVerifyNegotiatedCipher(
1562 SSLContext *ctx)
5a719ac8 1563{
df0e469f
A
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 */
9a27adb2 1598 if(ctx->signingPrivKeyRef == NULL) {
df0e469f
A
1599 sslErrorLog("sslVerifyNegotiatedCipher: no signing key\n");
1600 return errSSLBadConfiguration;
1601 }
9a27adb2
A
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 }
df0e469f
A
1614 }
1615 return noErr;
5a719ac8 1616}
bac41a7b 1617