]> git.saurik.com Git - apple/security.git/blob - SecurityTests/clxutils/clAppUtils/CertParser.cpp
Security-57031.10.10.tar.gz
[apple/security.git] / SecurityTests / clxutils / clAppUtils / CertParser.cpp
1 /*
2 * Copyright (c) 2003-2005 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,
14 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
15 * Please see the License for the specific language governing rights and
16 * limitations under the License.
17 */
18
19 /*
20 * CertParser.h - cert parser with autorelease of fetched fields
21 *
22 * Created 24 October 2003 by Doug Mitchell
23 */
24
25 #include "CertParser.h"
26 #import <AvailabilityMacros.h>
27
28 #define CP_DEBUG 1
29 #if CP_DEBUG
30 #define dprintf(args...) printf(args)
31 #else
32 #define dprintf(args...)
33 #endif
34
35 #pragma mark --- CP_FetchedField ---
36
37 class CP_FetchedField
38 {
39 public:
40 /* construct one fetched field (which will be stored in CertParser's
41 * mFetchedFields) */
42 CP_FetchedField(
43 const CSSM_OID &fieldOid,
44 CSSM_DATA_PTR fieldData,
45 CSSM_CL_HANDLE clHand);
46
47 /* Free the field via CL */
48 ~CP_FetchedField();
49 private:
50 CSSM_OID mFieldOid;
51 CSSM_DATA_PTR mFieldData;
52 CSSM_CL_HANDLE mClHand;
53 };
54
55 CP_FetchedField::CP_FetchedField(
56 const CSSM_OID &fieldOid,
57 CSSM_DATA_PTR fieldData,
58 CSSM_CL_HANDLE clHand)
59 : mFieldOid(fieldOid), mFieldData(fieldData), mClHand(clHand)
60 {
61 }
62
63 /* Free the field via CL */
64 CP_FetchedField::~CP_FetchedField()
65 {
66 CSSM_CL_FreeFieldValue(mClHand, &mFieldOid, mFieldData);
67 }
68
69 #pragma mark --- CertParser implementation ---
70
71 /* Construct with or without data - you can add the data later with
72 * initWithData() to parse without exceptions */
73 CertParser::CertParser()
74 {
75 initFields();
76 }
77
78 CertParser::CertParser(
79 CSSM_CL_HANDLE clHand)
80 {
81 initFields();
82 mClHand = clHand;
83 }
84
85 CertParser::CertParser(
86 CSSM_CL_HANDLE clHand,
87 const CSSM_DATA &certData)
88 {
89 initFields();
90 mClHand = clHand;
91 CSSM_RETURN crtn = initWithData(certData);
92 if(crtn) {
93 throw ((int)crtn);
94 }
95 }
96
97 CertParser::CertParser(
98 SecCertificateRef secCert)
99 {
100 initFields();
101 OSStatus ortn = initWithSecCert(secCert);
102 if(ortn) {
103 throw ((int)ortn);
104 }
105 }
106
107 /* frees all the fields we fetched */
108 CertParser::~CertParser()
109 {
110 if(mClHand && mCacheHand) {
111 CSSM_RETURN crtn = CSSM_CL_CertAbortCache(mClHand, mCacheHand);
112 if(crtn) {
113 /* almost certainly a bug */
114 printf("Internal Error: CertParser error on free.");
115 cssmPerror("CSSM_CL_CertAbortCache", crtn);
116 }
117 }
118 vector<CP_FetchedField *>::iterator iter;
119 for(iter=mFetchedFields.begin(); iter!=mFetchedFields.end(); iter++) {
120 delete *iter;
121 }
122 }
123
124 /* common init for all constructors */
125 void CertParser::initFields()
126 {
127 mClHand = 0;
128 mCacheHand = 0;
129 }
130
131 /*** NO MORE EXCEPTIONS ***/
132
133 /*
134 * No cert- or CDSA-related exceptions thrown by remainder.
135 * This is the core initializer: have the CL parse and cache the cert.
136 */
137 CSSM_RETURN CertParser::initWithData(
138 const CSSM_DATA &certData)
139 {
140 assert(mClHand != 0);
141 CSSM_RETURN crtn = CSSM_CL_CertCache(mClHand, &certData, &mCacheHand);
142 #if CP_DEBUG
143 if(crtn) {
144 cssmPerror("CSSM_CL_CertCache", crtn);
145 }
146 #endif
147 return crtn;
148 }
149
150 OSStatus CertParser::initWithSecCert(
151 SecCertificateRef secCert)
152 {
153 OSStatus ortn;
154 CSSM_DATA certData;
155
156 assert(mClHand == 0);
157 ortn = SecCertificateGetCLHandle(secCert, &mClHand);
158 if(ortn) {
159 return ortn;
160 }
161 ortn = SecCertificateGetData(secCert, &certData);
162 if(ortn) {
163 return ortn;
164 }
165 return (OSStatus)initWithData(certData);
166 }
167
168 CSSM_RETURN CertParser::initWithCFData(
169 CFDataRef cfData)
170 {
171 CSSM_DATA cdata;
172
173 cdata.Data = (uint8 *)CFDataGetBytePtr(cfData);
174 cdata.Length = CFDataGetLength(cfData);
175 return initWithData(cdata);
176 }
177
178 /*
179 * Obtain atrbitrary field from cached cert. This class takes care of freeing
180 * the field in its destructor.
181 *
182 * Returns NULL if field not found (not exception).
183 *
184 * Caller optionally specifies field length to check - specifying zero means
185 * "don't care, don't check". Actual field length always returned in fieldLength.
186 */
187 const void *CertParser::fieldForOid(
188 const CSSM_OID &oid,
189 CSSM_SIZE &fieldLength) // IN/OUT
190 {
191 CSSM_RETURN crtn;
192
193 uint32 NumberOfFields = 0;
194 CSSM_HANDLE resultHand = 0;
195 CSSM_DATA_PTR fieldData = NULL;
196
197 assert(mClHand != 0);
198 assert(mCacheHand != 0);
199 crtn = CSSM_CL_CertGetFirstCachedFieldValue(
200 mClHand,
201 mCacheHand,
202 &oid,
203 &resultHand,
204 &NumberOfFields,
205 &fieldData);
206 if(crtn) {
207 /* not an error; just means that the cert doesn't have this field */
208 return NULL;
209 }
210 assert(NumberOfFields == 1);
211 CSSM_CL_CertAbortQuery(mClHand, resultHand);
212
213 if(fieldLength) {
214 if(fieldLength != fieldData->Length) {
215 /* FIXME what's a good way to log in this situation? */
216 printf("***CertParser::fieldForOid: field length mismatch\n");
217 return NULL;
218 }
219 }
220 /* Store the OID and the field for autorelease */
221 CP_FetchedField *cpField = new CP_FetchedField(oid, fieldData, mClHand);
222 mFetchedFields.push_back(cpField);
223 fieldLength = fieldData->Length;
224 return fieldData->Data;
225 }
226
227 /*
228 * Conveneince routine to fetch an extension we "know" the CL can parse.
229 * The return value gets cast to one of the CE_Data types.
230 */
231 const void *CertParser::extensionForOid(
232 const CSSM_OID &oid)
233 {
234 CSSM_SIZE len = sizeof(CSSM_X509_EXTENSION);
235 CSSM_X509_EXTENSION *cssmExt =
236 (CSSM_X509_EXTENSION *)fieldForOid(oid, len);
237 if(cssmExt) {
238 if(cssmExt->format != CSSM_X509_DATAFORMAT_PARSED) {
239 printf("***Badly formatted extension");
240 return NULL;
241 }
242 return cssmExt->value.parsedValue;
243 }
244 else {
245 return NULL;
246 }
247 }
248