2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
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
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.
22 Contains: Apple Keychain routines
24 Written by: Doug Mitchell, based on Netscape SSLRef 3.0
26 Copyright: (c) 1999 by Apple Computer, Inc., all rights reserved.
33 #include "appleCdsa.h"
34 #include "appleGlue.h"
37 #include "sslKeychain.h"
41 #include <CoreServices/../Frameworks/CarbonCore.framework/Headers/MacErrors.h>
42 #include <Security/cssm.h>
43 /* these are to be replaced by Security/Security.h */
44 #include <Security/SecCertificate.h>
45 #include <Security/SecKeychainItem.h>
46 #include <Security/SecKeychain.h>
47 #include <Security/SecIdentity.h>
48 #include <Security/SecIdentitySearch.h>
49 #include <Security/SecKey.h>
51 #if ST_KEYCHAIN_ENABLE && ST_MANAGES_TRUSTED_ROOTS
56 CSSM_DATA_PTR certData
,
57 Boolean
*goodCert
); /* RETURNED */
58 #endif /* ST_KEYCHAIN_ENABLE && ST_MANAGES_TRUSTED_ROOTS */
60 #if (ST_SERVER_MODE_ENABLE || ST_CLIENT_AUTHENTICATION)
64 * Routines which will be replaced by SecKeychainAPI.
68 * Given a DLDB, find the first private key in the DB. It's the application's
69 * responsibility to ensure that there is only one private key. The returned
70 * PrintName attribute will be used to search for an associated cert using
73 * Caller must free returned key and PrintName.
78 CSSM_DL_DB_HANDLE dlDbHand
,
79 CSSM_KEY_PTR
*privKey
, // mallocd and RETURNED
80 CSSM_DATA
*printName
) // referent mallocd and RETURNED
83 CSSM_DB_UNIQUE_RECORD_PTR record
= NULL
;
85 CSSM_HANDLE resultHand
;
86 CSSM_DB_RECORD_ATTRIBUTE_DATA recordAttrs
;
87 CSSM_DB_ATTRIBUTE_DATA theAttr
;
88 CSSM_DB_ATTRIBUTE_INFO_PTR attrInfo
= &theAttr
.Info
;
89 CSSM_DATA theData
= {0, NULL
};
91 /* search by record type, no predicates (though we do want the PrintName
93 query
.RecordType
= CSSM_DL_DB_RECORD_PRIVATE_KEY
;
94 query
.Conjunctive
= CSSM_DB_NONE
;
95 query
.NumSelectionPredicates
= 0;
96 query
.SelectionPredicate
= NULL
;
97 query
.QueryLimits
.TimeLimit
= 0; // FIXME - meaningful?
98 query
.QueryLimits
.SizeLimit
= 1; // FIXME - meaningful?
99 query
.QueryFlags
= CSSM_QUERY_RETURN_DATA
; // FIXME - used?
101 recordAttrs
.DataRecordType
= CSSM_DL_DB_RECORD_PRIVATE_KEY
;
102 recordAttrs
.SemanticInformation
= 0;
103 recordAttrs
.NumberOfAttributes
= 1;
104 recordAttrs
.AttributeData
= &theAttr
;
106 attrInfo
->AttributeNameFormat
= CSSM_DB_ATTRIBUTE_NAME_AS_STRING
;
107 attrInfo
->Label
.AttributeName
= "PrintName";
108 attrInfo
->AttributeFormat
= CSSM_DB_ATTRIBUTE_FORMAT_BLOB
;
110 theAttr
.NumberOfValues
= 1;
111 theAttr
.Value
= NULL
;
113 crtn
= CSSM_DL_DataGetFirst(dlDbHand
,
119 /* terminate query only on success */
120 if(crtn
== CSSM_OK
) {
121 CSSM_DL_DataAbortQuery(dlDbHand
, resultHand
);
122 *privKey
= (CSSM_KEY_PTR
)theData
.Data
;
124 * Both the struct and the referent are mallocd by DL. Give our
125 * caller the referent; free the struct.
127 *printName
= *theAttr
.Value
;
128 stAppFree(theAttr
.Value
, NULL
);
132 stPrintCdsaError("CSSM_DL_DataGetFirst", crtn
);
133 errorLog0("findCertInDb: cert not found\n");
134 return errSSLBadCert
;
141 CSSM_DL_DB_HANDLE dlDbHand
,
142 const CSSM_DATA
*printName
, // obtained from findPrivateKeyInDb
143 CSSM_DATA
*certData
) // referent mallocd and RETURNED
146 CSSM_SELECTION_PREDICATE predicate
;
147 CSSM_DB_UNIQUE_RECORD_PTR record
= NULL
;
149 CSSM_HANDLE resultHand
;
151 predicate
.DbOperator
= CSSM_DB_EQUAL
;
152 predicate
.Attribute
.Info
.AttributeNameFormat
=
153 CSSM_DB_ATTRIBUTE_NAME_AS_STRING
;
154 predicate
.Attribute
.Info
.Label
.AttributeName
= "PrintName";
155 predicate
.Attribute
.Info
.AttributeFormat
= CSSM_DB_ATTRIBUTE_FORMAT_BLOB
;
156 /* hope this const_cast is OK */
157 predicate
.Attribute
.Value
= (CSSM_DATA_PTR
)printName
;
158 predicate
.Attribute
.NumberOfValues
= 1;
160 query
.RecordType
= CSSM_DL_DB_RECORD_X509_CERTIFICATE
;
161 query
.Conjunctive
= CSSM_DB_NONE
;
162 query
.NumSelectionPredicates
= 1;
163 query
.SelectionPredicate
= &predicate
;
164 query
.QueryLimits
.TimeLimit
= 0; // FIXME - meaningful?
165 query
.QueryLimits
.SizeLimit
= 1; // FIXME - meaningful?
166 query
.QueryFlags
= 0; // FIXME - used?
168 crtn
= CSSM_DL_DataGetFirst(dlDbHand
,
171 NULL
, // no attrs returned
174 /* terminate query only on success */
175 if(crtn
== CSSM_OK
) {
176 CSSM_DL_DataAbortQuery(dlDbHand
, resultHand
);
180 stPrintCdsaError("CSSM_DL_DataGetFirst", crtn
);
181 errorLog0("findCertInDb: cert not found\n");
182 return errSSLBadCert
;
187 #endif /* ST_FAKE_KEYCHAIN */
189 * Given an array of certs (as SecIdentityRefs, specified by caller
190 * in SSLSetCertificate or SSLSetEncryptionCertificate) and a
191 * destination SSLCertificate:
193 * -- free destCerts if we have any
194 * -- Get raw cert data, convert to array of SSLCertificates in *destCert
195 * -- validate cert chain
196 * -- get pub, priv keys from certRef[0], store in *pubKey, *privKey
201 * In this incarnation, the certs array actually holds one pointer to a
202 * CSSM_DL_DB_HANDLE. In that DL/DB is exactly one private key; that's
203 * our privKey. We use the KeyLabel of that key to look up a cert with
204 * the same label. We get the public key from the cert. Other certs and
205 * public keys in the DL/DB are ignored.
211 SSLCertificate
**destCert
, /* &ctx->{localCert,encryptCert} */
212 CSSM_KEY_PTR
*pubKey
, /* &ctx->signingPubKey, etc. */
213 CSSM_KEY_PTR
*privKey
, /* &ctx->signingPrivKey, etc. */
214 CSSM_CSP_HANDLE
*cspHand
/* &ctx->signingKeyCsp, etc. */
215 #if ST_KC_KEYS_NEED_REF
217 SecKeychainRef
*privKeyRef
) /* &ctx->signingKeyRef, etc. */
220 #endif /* ST_KC_KEYS_NEED_REF */
222 CSSM_DL_DB_HANDLE_PTR dlDbHand
= NULL
;
224 CSSM_KEY_PTR lookupPriv
= NULL
;
225 CSSM_DATA lookupLabel
= {0, NULL
};
226 CSSM_DATA lookupCert
= {0, NULL
};
228 SSLCertificate
*certChain
= NULL
;
229 SSLCertificate
*thisSslCert
;
231 CSSM_CSP_HANDLE dummyCsp
;
234 assert(destCert
!= NULL
); /* though its referent may be NULL */
235 assert(pubKey
!= NULL
);
236 assert(privKey
!= NULL
);
237 assert(cspHand
!= NULL
);
239 sslDeleteCertificateChain(*destCert
, ctx
);
246 dprintf0("parseIncomingCerts: NULL incoming cert (DLDB) array\n");
247 return errSSLBadCert
;
249 numCerts
= CFArrayGetCount(certs
);
251 dprintf0("parseIncomingCerts: empty incoming cert (DLDB) array\n");
252 return errSSLBadCert
;
254 dlDbHand
= (CSSM_DL_DB_HANDLE_PTR
)CFArrayGetValueAtIndex(certs
, 0);
255 if(dlDbHand
== NULL
) {
256 errorLog0("parseIncomingCerts: bad cert (DLDB) array\n");
260 /* get private key - app has to ensure there is only one (for now) */
261 ortn
= findPrivateKeyInDb(ctx
, *dlDbHand
, &lookupPriv
, &lookupLabel
);
263 errorLog0("parseIncomingCerts: no private key\n");
266 assert(lookupPriv
->KeyHeader
.BlobType
== CSSM_KEYBLOB_REFERENCE
);
267 assert(lookupPriv
->KeyHeader
.KeyClass
== CSSM_KEYCLASS_PRIVATE_KEY
);
269 /* get associated cert */
270 ortn
= findCertInDb(ctx
, *dlDbHand
, &lookupLabel
, &lookupCert
);
272 errorLog0("parseIncomingCerts: no cert\n");
275 sslFree(lookupLabel
.Data
);
276 assert(lookupCert
.Length
> 100); // quickie check
279 * Cook up an SSLCertificate and its associated SSLBuffer.
281 thisSslCert
= sslMalloc(sizeof(SSLCertificate
));
282 if(thisSslCert
== NULL
) {
285 if(SSLAllocBuffer(&thisSslCert
->derCert
, lookupCert
.Length
, &ctx
->sysCtx
)) {
289 /* copy cert data mallocd by DL */
290 memmove(thisSslCert
->derCert
.data
, lookupCert
.Data
, lookupCert
.Length
);
291 sslFree(lookupCert
.Data
);
293 /* enqueue onto head of cert chain */
294 thisSslCert
->next
= certChain
;
295 certChain
= thisSslCert
;
297 /* TBD - we might fetch other certs from CFArrayRef certs here and enqueue
298 * them on certChain */
300 /* now the public key of the first cert, from CL */
301 srtn
= sslPubKeyFromCert(ctx
,
306 errorLog1("sslPubKeyFromCert returned %d\n", srtn
);
307 ortn
= sslErrToOsStatus(srtn
);
310 assert((*pubKey
)->KeyHeader
.BlobType
== CSSM_KEYBLOB_RAW
);
311 assert((*pubKey
)->KeyHeader
.KeyClass
== CSSM_KEYCLASS_PUBLIC_KEY
);
314 * NOTE: as of 2/7/02, the size of the extracted public key will NOT
315 * always equal the size of the private key. Non-byte-aligned key sizes
316 * for RSA keys result in the extracted public key's size to be rounded
317 * UP to the next byte boundary.
319 assert((*pubKey
)->KeyHeader
.LogicalKeySizeInBits
==
320 ((lookupPriv
->KeyHeader
.LogicalKeySizeInBits
+ 7) & ~7));
323 *destCert
= certChain
;
324 *privKey
= lookupPriv
;
326 /* we get this at context create time */
327 assert(ctx
->cspDlHand
!= 0);
328 *cspHand
= ctx
->cspDlHand
;
329 *privKeyRef
= NULL
; // not used
333 /* free certChain, everything in it, other vars, return ortn */
334 sslDeleteCertificateChain(certChain
, ctx
);
335 if(lookupPriv
!= NULL
) {
336 sslFreeKey(ctx
->cspDlHand
, &lookupPriv
, NULL
);
341 #else /* !ST_FAKE_KEYCHAIN */
343 /* Convert a SecCertificateRef to an SSLCertificate * */
344 static OSStatus
secCertToSslCert(
346 SecCertificateRef certRef
,
347 SSLCertificate
**sslCert
)
349 CSSM_DATA certData
; // struct is transient, referent owned by
352 SSLCertificate
*thisSslCert
= NULL
;
354 ortn
= SecCertificateGetData(certRef
, &certData
);
356 errorLog1("SecCertificateGetData() returned %d\n", (int)ortn
);
360 thisSslCert
= sslMalloc(sizeof(SSLCertificate
));
361 if(thisSslCert
== NULL
) {
364 if(SSLAllocBuffer(&thisSslCert
->derCert
, certData
.Length
,
368 memcpy(thisSslCert
->derCert
.data
, certData
.Data
, certData
.Length
);
369 thisSslCert
->derCert
.length
= certData
.Length
;
370 *sslCert
= thisSslCert
;
378 SSLCertificate
**destCert
, /* &ctx->{localCert,encryptCert} */
379 CSSM_KEY_PTR
*pubKey
, /* &ctx->signingPubKey, etc. */
380 CSSM_KEY_PTR
*privKey
, /* &ctx->signingPrivKey, etc. */
381 CSSM_CSP_HANDLE
*cspHand
/* &ctx->signingKeyCsp, etc. */
382 #if ST_KC_KEYS_NEED_REF
384 SecKeychainRef
*privKeyRef
) /* &ctx->signingKeyRef, etc. */
387 #endif /* ST_KC_KEYS_NEED_REF */
391 SSLCertificate
*certChain
= NULL
;
392 SSLCertificate
*thisSslCert
;
393 SecKeychainRef kcRef
;
396 SecIdentityRef identity
;
397 SecCertificateRef certRef
;
400 CSSM_CL_HANDLE clHand
; // carefully derive from a SecCertificateRef
403 CASSERT(ctx
!= NULL
);
404 CASSERT(destCert
!= NULL
); /* though its referent may be NULL */
405 CASSERT(pubKey
!= NULL
);
406 CASSERT(privKey
!= NULL
);
407 CASSERT(cspHand
!= NULL
);
409 sslDeleteCertificateChain(*destCert
, ctx
);
416 dprintf0("parseIncomingCerts: NULL incoming cert array\n");
417 return errSSLBadCert
;
419 numCerts
= CFArrayGetCount(certs
);
421 dprintf0("parseIncomingCerts: empty incoming cert array\n");
422 return errSSLBadCert
;
426 * Certs[0] is an SecIdentityRef from which we extract subject cert,
427 * privKey, pubKey, and cspHand.
429 * 1. ensure the first element is a SecIdentityRef.
431 identity
= (SecIdentityRef
)CFArrayGetValueAtIndex(certs
, 0);
432 if(identity
== NULL
) {
433 errorLog0("parseIncomingCerts: bad cert array (1)\n");
436 if(CFGetTypeID(identity
) != SecIdentityGetTypeID()) {
437 errorLog0("parseIncomingCerts: bad cert array (2)\n");
442 * 2. Extract cert, keys, CSP handle and convert to local format.
444 ortn
= SecIdentityCopyCertificate(identity
, &certRef
);
446 errorLog0("parseIncomingCerts: bad cert array (3)\n");
449 ortn
= secCertToSslCert(ctx
, certRef
, &thisSslCert
);
451 errorLog0("parseIncomingCerts: bad cert array (4)\n");
454 /* enqueue onto head of cert chain */
455 thisSslCert
->next
= certChain
;
456 certChain
= thisSslCert
;
458 /* fetch private key from identity */
459 ortn
= SecIdentityCopyPrivateKey(identity
, &keyRef
);
461 errorLog1("parseIncomingCerts: SecIdentityCopyPrivateKey err %d\n",
465 ortn
= SecKeyGetCSSMKey(keyRef
, (const CSSM_KEY
**)privKey
);
467 errorLog1("parseIncomingCerts: SecKeyGetCSSMKey err %d\n",
471 /* FIXME = release keyRef? */
473 /* obtain public key from cert */
474 ortn
= SecCertificateGetCLHandle(certRef
, &clHand
);
476 errorLog1("parseIncomingCerts: SecCertificateGetCLHandle err %d\n",
480 certData
.Data
= thisSslCert
->derCert
.data
;
481 certData
.Length
= thisSslCert
->derCert
.length
;
482 crtn
= CSSM_CL_CertGetKeyInfo(clHand
, &certData
, pubKey
);
484 errorLog0("parseIncomingCerts: CSSM_CL_CertGetKeyInfo err\n");
485 return (OSStatus
)crtn
;
488 #if ST_FAKE_GET_CSPDL_HANDLE
489 /* we get this at context create time until SecKeychainGetCSPHandle
491 assert(ctx
->cspDlHand
!= 0);
492 *cspHand
= ctx
->cspDlHand
;
493 #else /* ST_FAKE_GET_CSPDL_HANDLE */
494 /* obtain keychain from key, CSP handle from keychain */
495 ortn
= SecKeychainItemCopyKeychain((SecKeychainItemRef
)keyRef
, &kcRef
);
497 errorLog1("parseIncomingCerts: SecKeychainItemCopyKeychain err %d\n",
501 ortn
= SecKeychainGetCSPHandle(kcRef
, cspHand
);
503 errorLog1("parseIncomingCerts: SecKeychainGetCSPHandle err %d\n",
507 #endif /* ST_FAKE_GET_CSPDL_HANDLE */
509 /* OK, that's the subject cert. Fetch optional remaining certs. */
511 * Convert: CFArray of SecCertificateRefs --> chain of SSLCertificates.
512 * Incoming certs have root last; SSLCertificate chain has root
515 for(cert
=1; cert
<numCerts
; cert
++) {
516 certRef
= (SecCertificateRef
)CFArrayGetValueAtIndex(certs
, cert
);
517 if(certRef
== NULL
) {
518 errorLog0("parseIncomingCerts: bad cert array (5)\n");
521 if(CFGetTypeID(certRef
) != SecCertificateGetTypeID()) {
522 errorLog0("parseIncomingCerts: bad cert array (6)\n");
526 /* Extract cert, convert to local format.
528 ortn
= secCertToSslCert(ctx
, certRef
, &thisSslCert
);
530 errorLog0("parseIncomingCerts: bad cert array (7)\n");
533 /* enqueue onto head of cert chain */
534 thisSslCert
->next
= certChain
;
535 certChain
= thisSslCert
;
538 /* validate the whole mess */
539 srtn
= sslVerifyCertChain(ctx
, certChain
);
541 ortn
= sslErrToOsStatus(srtn
);
546 *destCert
= certChain
;
550 /* free certChain, everything in it, other vars, return ortn */
551 sslDeleteCertificateChain(certChain
, ctx
);
552 /* FIXME - anything else? */
555 #endif /* ST_FAKE_KEYCHAIN */
556 #endif /* (ST_SERVER_MODE_ENABLE || ST_CLIENT_AUTHENTICATION) */
559 * Add Apple built-in root certs to ctx->trustedCerts.
561 OSStatus
addBuiltInCerts (SSLContextRef ctx
)
563 #if ST_KEYCHAIN_ENABLE && ST_MANAGES_TRUSTED_ROOTS
567 ortn
= KCDispatch(kKCGetRootCertificateKeychain
, &kc
);
569 errorLog1("KCDispatch(kKCGetRootCertificateKeychain) returned %d\n",
573 return parseTrustedKeychain(ctx
, kc
);
575 /* nothing for now */
577 #endif /* ST_KEYCHAIN_ENABLE && ST_MANAGES_TRUSTED_ROOTS */
580 #if ST_KEYCHAIN_ENABLE && ST_MANAGES_TRUSTED_ROOTS
583 * Given an open Keychain:
584 * -- Get raw cert data, add to array of CSSM_DATAs in
586 * -- verify that each of these is a valid (self-verifying)
588 * -- add each subject name to acceptableDNList
591 parseTrustedKeychain (SSLContextRef ctx
,
594 CFMutableArrayRef kcCerts
= NULL
; /* all certs in one keychain */
595 uint32 numGoodCerts
= 0; /* # of good root certs */
596 CSSM_DATA_PTR certData
= NULL
; /* array of CSSM_DATAs */
597 CFIndex certDex
; /* index into kcCerts */
598 CFIndex certsPerKc
; /* # of certs in this KC */
600 KCItemRef kcItem
; /* one cert */
603 CASSERT(ctx
!= NULL
);
604 if(keyChainRef
== NULL
) {
608 ortn
= KCFindX509Certificates(keyChainRef
,
610 NULL
, // emailAddress, XXX
611 kCertSearchAny
, // options
612 &kcCerts
); // results
616 case errKCItemNotFound
:
617 return noErr
; // no certs; done
619 errorLog1("parseTrustedKeychains: KCFindX509Certificates returned %d\n",
623 if(kcCerts
== NULL
) {
624 dprintf0("parseTrustedKeychains: no certs in KC\n");
628 /* Note kcCerts must be released on any exit, successful or
631 certsPerKc
= CFArrayGetCount(kcCerts
);
634 * This array gets allocd locally; we'll add it to
635 * ctx->trustedCerts when we're done.
637 certData
= sslMalloc(certsPerKc
* sizeof(CSSM_DATA
));
638 if(certData
== NULL
) {
642 memset(certData
, 0, certsPerKc
* sizeof(CSSM_DATA
));
645 * Build up local certData one root cert at a time.
646 * Some certs might not pass muster, hence the numGoodCerts
647 * which may or may not increment each time thru.
649 for(certDex
=0; certDex
<certsPerKc
; certDex
++) {
650 kcItem
= (KCItemRef
)CFArrayGetValueAtIndex(kcCerts
, certDex
);
652 errorLog0("parseTrustedKeychains: CF error 1\n");
653 ortn
= errSSLInternal
;
656 if(!KCIsRootCertificate(kcItem
)) {
657 /* not root, OK, skip to next cert */
658 dprintf1("parseTrustedKeychains: cert %d NOT ROOT\n", certDex
);
661 ortn
= addCertData(ctx
,
663 &certData
[numGoodCerts
],
669 /* added valid root to certData */
672 } /* for each cert in kcCerts */
675 verifyTrustedRoots(ctx
, certData
, numGoodCerts
);
678 /* Realloc ctx->trustedCerts, add new root certs */
679 ctx
->trustedCerts
= sslRealloc(ctx
->trustedCerts
,
680 ctx
->numTrustedCerts
* sizeof(CSSM_DATA
),
681 (ctx
->numTrustedCerts
+ numGoodCerts
) * sizeof(CSSM_DATA
));
682 if(ctx
->trustedCerts
== NULL
) {
686 for(certDex
=0; certDex
<numGoodCerts
; certDex
++) {
687 ctx
->trustedCerts
[ctx
->numTrustedCerts
+ certDex
] = certData
[certDex
];
689 ctx
->numTrustedCerts
+= numGoodCerts
;
693 verifyTrustedRoots(ctx
, ctx
->trustedCerts
, ctx
->numTrustedCerts
);
698 if(kcCerts
!= NULL
) {
705 * Given a (supposedly) root cert as a KCItemRef:
706 * -- verify that the cert self-verifies
707 * -- add its DER-encoded data *certData.
708 * -- Add its subjectName to acceptableDNList.
709 * -- If all is well, return True in *goodCert.
711 * The actual CSSM_DATA.Data is mallocd via CSSM_Malloc.
717 CSSM_DATA_PTR certData
,
718 Boolean
*goodCert
) /* RETURNED */
723 CSSM_BOOL subjectExpired
;
724 CSSM_DATA_PTR dnData
;
726 CASSERT(ctx
!= NULL
);
727 CASSERT(certData
!= NULL
);
728 CASSERT(kcItem
!= NULL
);
729 CASSERT(goodCert
!= NULL
);
733 /* how big is the cert? */
734 ortn
= KCGetData (kcItem
, 0, NULL
, &certSize
);
736 errorLog1("addCertData: KCGetData(1) returned %d\n", ortn
);
740 /* Allocate the buffer. */
741 srtn
= stSetUpCssmData(certData
, certSize
);
743 return sslErrToOsStatus(srtn
);
747 ortn
= KCGetData (kcItem
, certSize
, certData
->Data
, &certSize
);
749 errorLog1("addCertData: KCGetData(2) returned %d\n", ortn
);
750 stFreeCssmData(certData
, CSSM_FALSE
);
755 * Do actual cert verify, which
756 * KCIsRootCertificate does not do. A failure isn't
757 * fatal; we just don't add the cert to the array in
760 * FIXME - we assume here that our common cspHand can
761 * do this cert verify; if not, we have some API work to
762 * do (to let the caller specify which CSP to use with
765 if(!sslVerifyCert(ctx
,
770 dprintf0("addCertData: cert does not self-verify!\n");
771 stFreeCssmData(certData
, CSSM_FALSE
);
775 /* Add this cert's subject name to (poss. existing) acceptableDNList */
776 dnData
= sslGetCertSubjectName(ctx
, certData
);
778 DNListElem
*dn
= sslMalloc(sizeof(DNListElem
));
782 dn
->next
= ctx
->acceptableDNList
;
783 ctx
->acceptableDNList
= dn
;
785 /* move actual data to dn; free the CSSM_DATA struct (must be
786 * via CSSM_Free()!) */
787 CSSM_TO_SSLBUF(dnData
, &dn
->derDN
);
796 * Given a newly encountered root cert (obtained from a peer's cert chain),
797 * add it to newRootCertKc if the user so allows, and if so, add it to
803 const CSSM_DATA_PTR rootCert
)
806 Boolean bDefaultKcExists
;
807 KCItemRef certRef
= NULL
;
809 CSSM_DATA_PTR newTrustee
;
812 CASSERT(ctx
!= NULL
);
813 CASSERT(rootCert
!= NULL
);
814 CASSERT(ctx
->newRootCertKc
!= NULL
); /* caller verifies this */
817 * Get default KC, temporarily set new default.
819 ortn
= KCGetDefaultKeychain(&defaultKc
);
821 bDefaultKcExists
= false;
824 bDefaultKcExists
= true;
826 ortn
= KCSetDefaultKeychain(ctx
->newRootCertKc
);
828 errorLog1("sslAddNewRoot: KCSetDefaultKeychain returned %d\n", ortn
);
829 return SSLUnknownRootCert
;
833 * Add cert to newRootCertKc. This may well fail due to user
834 * interaction ("Do you want to add this root cert...?").
836 ortn
= KCAddX509Certificate(rootCert
->Data
, rootCert
->Length
, &certRef
);
838 /* restore default KC in any case */
839 if(bDefaultKcExists
) {
840 KCSetDefaultKeychain(defaultKc
);
843 dprintf1("sslAddNewRoot: KCAddX509Certificate returned %d\n", ortn
);
844 return SSLUnknownRootCert
;
848 * OK, user accepted new root. Now add to our private stash of
849 * trusted roots. Realloc the whole pile...
851 ctx
->trustedCerts
= (CSSM_DATA_PTR
)sslRealloc(ctx
->trustedCerts
,
852 (ctx
->numTrustedCerts
* sizeof(CSSM_DATA
)),
853 ((ctx
->numTrustedCerts
+ 1) * sizeof(CSSM_DATA
)));
854 if(ctx
->trustedCerts
== NULL
) {
858 /* Now add a copy of the new root. */
859 newTrustee
= &ctx
->trustedCerts
[ctx
->numTrustedCerts
];
860 newTrustee
->Data
= NULL
;
861 newTrustee
->Length
= 0;
862 serr
= stSetUpCssmData(newTrustee
, rootCert
->Length
);
866 BlockMove(rootCert
->Data
, newTrustee
->Data
, rootCert
->Length
);
867 (ctx
->numTrustedCerts
)++;
871 #endif /* ST_KEYCHAIN_ENABLE && ST_MANAGES_TRUSTED_ROOTS */