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