]> git.saurik.com Git - apple/security.git/blob - AppleX509TP/rootCerts.cpp
Security-177.tar.gz
[apple/security.git] / AppleX509TP / rootCerts.cpp
1 /*
2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
3 *
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please
7 * obtain a copy of the License at http://www.apple.com/publicsource and
8 * read it before 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
12 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
13 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS
14 * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please
15 * see the License for the specific language governing rights and
16 * limitations under the License.
17 */
18
19
20 /*
21 File: rootCerts.cp
22
23 Contains: Bridge between SecTrustGetCSSMAnchorCertificates() and
24 TP's internally cached tpRootCert array.
25
26 Written by: Doug Mitchell.
27
28 Copyright: Copyright 2002 by Apple Computer, Inc., all rights reserved.
29
30 */
31
32 #include "rootCerts.h"
33
34 #if TP_ROOT_CERT_ENABLE
35
36 #include "certGroupUtils.h"
37 #include "tpdebugging.h"
38 #include <Security/Trust.h>
39 #include <Security/TrustStore.h>
40 #include <Security/debugging.h>
41 #include <Security/oidscert.h>
42
43 /* static in TPRootStore */
44 ModuleNexus<TPRootStore> TPRootStore::tpGlobalRoots;
45
46 TPRootStore::~TPRootStore()
47 {
48 /*
49 * Technically this never gets called because the only instance
50 * of a TPRootStore is via tpGlobalRoots. Freeing mRootCerts
51 * here really doesn't accomplish anything.
52 */
53 }
54
55 const tpRootCert *TPRootStore::rootCerts(
56 CSSM_CL_HANDLE clHand,
57 unsigned &numRootCerts)
58 {
59 StLock<Mutex> _(mLock);
60 if(mRootCerts) {
61 numRootCerts = mNumRootCerts;
62 return mRootCerts;
63 }
64
65 CssmAllocator &alloc(CssmAllocator::standard());
66 CertGroup roots;
67 tpRootCert *tpRoots = NULL; // copy to mRootCerts on success
68 unsigned numTpRoots = 0;
69
70 try {
71 /* Obtain system-wide root certs in blob format */
72 Security::KeychainCore::TrustStore &trustStore =
73 Security::KeychainCore::Trust::gStore();
74 trustStore.getCssmRootCertificates(roots);
75 if(roots.type() != CSSM_CERTGROUP_DATA) {
76 secdebug("tpAnchor", "Bad certGroup Type (%d)\n",
77 (int)roots.type());
78 return NULL;
79 }
80 numTpRoots = roots.count();
81 if(numTpRoots == 0) {
82 secdebug("tpAnchor", "empty certGroup\n");
83 return NULL;
84 }
85
86 /* set up tpRoots array, one for each cert in the group */
87 tpRoots =
88 (tpRootCert *)alloc.malloc(numTpRoots * sizeof(tpRootCert));
89 memset(tpRoots, 0, numTpRoots * sizeof(tpRootCert));
90 for(uint32 certNum=0; certNum<numTpRoots; certNum++) {
91 tpRootCert *tpRoot = &tpRoots[certNum];
92 const CSSM_DATA *certData = &((roots.blobCerts())[certNum]);
93
94 /* extract normalized subject name */
95 CSSM_DATA *field;
96 CSSM_HANDLE ResultsHandle;
97 uint32 numFields;
98 CSSM_RETURN crtn;
99 crtn = CSSM_CL_CertGetFirstFieldValue(
100 clHand,
101 certData,
102 &CSSMOID_X509V1SubjectName,
103 &ResultsHandle,
104 &numFields,
105 &field);
106 if(crtn) {
107 secdebug("tpAnchor", "GetFirstFieldValue error on cert %u",
108 (unsigned)certNum);
109 continue;
110 }
111 CSSM_CL_CertAbortQuery(clHand, ResultsHandle);
112 tpCopyCssmData(alloc, field, &tpRoot->subjectName);
113 CSSM_CL_FreeFieldValue(clHand, &CSSMOID_X509V1SubjectName,
114 field);
115
116 /* extract public key info - the blob and key size in bits */
117 CSSM_KEY_PTR key;
118 crtn = CSSM_CL_CertGetKeyInfo(clHand, certData, &key);
119 if(crtn) {
120 secdebug("tpAnchor", "CSSM_CL_CertGetKeyInfo error on cert %u",
121 (unsigned)certNum);
122 /* clear out this tpRoot? */
123 continue;
124 }
125 tpCopyCssmData(alloc, &key->KeyData, &tpRoot->publicKey);
126 tpRoot->keySize = key->KeyHeader.LogicalKeySizeInBits;
127
128 /* A hole in the CDSA API: there is no free function at the
129 * CL API for this key. It got mallocd with clHand's
130 * allocator....
131 */
132 CSSM_API_MEMORY_FUNCS memFuncs;
133 crtn = CSSM_GetAPIMemoryFunctions(clHand, &memFuncs);
134 if(crtn) {
135 secdebug("tpAnchor", "CSSM_GetAPIMemoryFunctions error");
136 /* Oh well.. */
137 continue;
138 }
139 memFuncs.free_func(key->KeyData.Data, memFuncs.AllocRef);
140 memFuncs.free_func(key, memFuncs.AllocRef);
141 } /* main loop */
142 }
143 catch(...) {
144 /* TBD */
145 return NULL;
146 }
147 mNumRootCerts = numTpRoots;
148 numRootCerts = mNumRootCerts;
149 mRootCerts = tpRoots;
150 return mRootCerts;
151 }
152
153 /*
154 * Compare a root cert to a list of known embedded roots.
155 */
156 CSSM_BOOL tp_isKnownRootCert(
157 TPCertInfo *rootCert, // raw cert to compare
158 CSSM_CL_HANDLE clHand)
159 {
160 const CSSM_DATA *subjectName = NULL;
161 CSSM_DATA_PTR publicKey = NULL;
162 unsigned dex;
163 CSSM_BOOL brtn = CSSM_FALSE;
164 CSSM_DATA_PTR valToFree = NULL;
165 const tpRootCert *roots;
166 unsigned numRoots;
167
168 roots = TPRootStore::tpGlobalRoots().rootCerts(clHand, numRoots);
169
170 subjectName = rootCert->subjectName();
171 publicKey = tp_CertGetPublicKey(rootCert, &valToFree);
172 if(publicKey == NULL) {
173 tpPolicyError("tp_isKnownRootCert: error retrieving public "
174 "key info!");
175 goto errOut;
176 }
177
178 /*
179 * Grind thru the list of known certs, demanding perfect match of
180 * both fields
181 */
182 for(dex=0; dex<numRoots; dex++) {
183 if(!tpCompareCssmData(subjectName,
184 &roots[dex].subjectName)) {
185 continue;
186 }
187 if(!tpCompareCssmData(publicKey,
188 &roots[dex].publicKey)) {
189 continue;
190 }
191 brtn = CSSM_TRUE;
192 break;
193 }
194 errOut:
195 tp_CertFreePublicKey(rootCert->clHand(), valToFree);
196 return brtn;
197 }
198
199 /*
200 * Attempt to verify specified cert (from the end of a chain) with one of
201 * our known roots.
202 */
203 CSSM_BOOL tp_verifyWithKnownRoots(
204 CSSM_CL_HANDLE clHand,
205 CSSM_CSP_HANDLE cspHand,
206 TPCertInfo *certToVfy) // last in chain, not root
207 {
208 CSSM_KEY rootKey; // pub key manufactured from tpRootCert info
209 CSSM_CC_HANDLE ccHand; // signature context
210 CSSM_RETURN crtn;
211 unsigned dex;
212 const tpRootCert *rootInfo;
213 CSSM_BOOL brtn = CSSM_FALSE;
214 CSSM_KEYHEADER *hdr = &rootKey.KeyHeader;
215 CSSM_X509_ALGORITHM_IDENTIFIER_PTR algId;
216 CSSM_DATA_PTR valToFree = NULL;
217 CSSM_ALGORITHMS sigAlg;
218 const tpRootCert *rootCerts = NULL;
219 unsigned numRootCerts = 0;
220
221 memset(&rootKey, 0, sizeof(CSSM_KEY));
222
223 /*
224 * Get signature algorithm from subject key
225 */
226 algId = tp_CertGetAlgId(certToVfy, &valToFree);
227 if(algId == NULL) {
228 /* bad cert */
229 return CSSM_FALSE;
230 }
231 /* subsequest errors to errOut: */
232
233 /* map to key and signature algorithm */
234 sigAlg = tpOidToAldId(&algId->algorithm, &hdr->AlgorithmId);
235 if(sigAlg == CSSM_ALGID_NONE) {
236 tpPolicyError("tp_verifyWithKnownRoots: unknown sig alg");
237 goto errOut;
238 }
239
240 /* Set up other constant key fields */
241 hdr->BlobType = CSSM_KEYBLOB_RAW;
242 switch(hdr->AlgorithmId) {
243 case CSSM_ALGID_RSA:
244 hdr->Format = CSSM_KEYBLOB_RAW_FORMAT_PKCS1;
245 break;
246 case CSSM_ALGID_DSA:
247 hdr->Format = CSSM_KEYBLOB_RAW_FORMAT_FIPS186;
248 break;
249 case CSSM_ALGID_FEE:
250 hdr->Format = CSSM_KEYBLOB_RAW_FORMAT_OCTET_STRING;
251 break;
252 default:
253 /* punt */
254 hdr->Format = CSSM_KEYBLOB_RAW_FORMAT_NONE;
255 }
256 hdr->KeyClass = CSSM_KEYCLASS_PUBLIC_KEY;
257 hdr->KeyAttr = CSSM_KEYATTR_MODIFIABLE | CSSM_KEYATTR_EXTRACTABLE;
258 hdr->KeyUsage = CSSM_KEYUSE_VERIFY;
259
260 rootCerts = TPRootStore::tpGlobalRoots().rootCerts(clHand, numRootCerts);
261 for(dex=0; dex<numRootCerts; dex++) {
262 rootInfo = &rootCerts[dex];
263 if(!tpCompareCssmData(&rootInfo->subjectName, certToVfy->issuerName())) {
264 /* not this root */
265 continue;
266 }
267
268 /* only variation in key in the loop - raw key bits and size */
269 rootKey.KeyData = rootInfo->publicKey;
270 hdr->LogicalKeySizeInBits = rootInfo->keySize;
271 crtn = CSSM_CSP_CreateSignatureContext(cspHand,
272 sigAlg,
273 NULL, // AcccedCred
274 &rootKey,
275 &ccHand);
276 if(crtn) {
277 tpPolicyError("tp_verifyWithKnownRoots: "
278 "CSSM_CSP_CreateSignatureContext err");
279 CssmError::throwMe(CSSMERR_TP_INTERNAL_ERROR);
280 }
281 crtn = CSSM_CL_CertVerify(clHand,
282 ccHand,
283 certToVfy->itemData(),
284 NULL, // no signer cert
285 NULL, // VerifyScope
286 0); // ScopeSize
287 CSSM_DeleteContext(ccHand);
288 if(crtn == CSSM_OK) {
289 /* success! */
290 brtn = CSSM_TRUE;
291 break;
292 }
293 }
294 errOut:
295 if(valToFree != NULL) {
296 tp_CertFreeAlgId(clHand, valToFree);
297 }
298 return brtn;
299 }
300
301 #endif /* TP_ROOT_CERT_ENABLE */
302