]>
Commit | Line | Data |
---|---|---|
b1ab9ed8 | 1 | /* |
d8f41ccd | 2 | * Copyright (c) 2000-2001,2011-2012,2014 Apple Inc. All Rights Reserved. |
b1ab9ed8 A |
3 | * |
4 | * The contents of this file constitute Original Code as defined in and are | |
5 | * subject to the Apple Public Source License Version 1.2 (the 'License'). | |
6 | * You may not use this file except in compliance with the License. Please obtain | |
7 | * a copy of the License at http://www.apple.com/publicsource and read it before | |
8 | * using this file. | |
9 | * | |
10 | * This Original Code and all software distributed under the License are | |
11 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS | |
12 | * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT | |
13 | * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR | |
14 | * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the | |
15 | * specific language governing rights and limitations under the License. | |
16 | */ | |
17 | ||
18 | ||
19 | /* | |
20 | * CrlFields.cpp - convert between NSS-based NSS_Crl components and CDSA-style | |
21 | * fields. A major component of DecodedCrl. | |
22 | * | |
d8f41ccd | 23 | * Copyright (c) 2002,2011-2012,2014 Apple Inc. |
b1ab9ed8 A |
24 | */ |
25 | ||
26 | #include "DecodedCrl.h" | |
27 | #include <security_utilities/debugging.h> | |
28 | #include "cldebugging.h" | |
29 | #include "CLCrlExtensions.h" | |
30 | #include "CLCertExtensions.h" | |
31 | #include "CLFieldsCommon.h" | |
32 | #include "clNssUtils.h" | |
33 | #include "clNameUtils.h" | |
34 | #include <security_utilities/utilities.h> | |
35 | #include <Security/oidscrl.h> | |
36 | #include <Security/oidscert.h> | |
37 | #include <Security/cssmerr.h> | |
38 | #include <Security/x509defs.h> | |
39 | ||
40 | static void CL_freeCssmExtensions( | |
41 | CSSM_X509_EXTENSIONS &extens, | |
42 | Allocator &alloc); | |
43 | ||
44 | /*** | |
45 | *** Version | |
46 | *** Format = DER-encoded int (max of four bytes in this case) | |
47 | ***/ | |
48 | static bool getField_Version ( | |
49 | DecodedItem &item, | |
50 | unsigned index, // which occurrence (0 = first) | |
51 | uint32 &numFields, // RETURNED | |
52 | CssmOwnedData &fieldValue) // RETURNED | |
53 | { | |
54 | const DecodedCrl &crl = dynamic_cast<const DecodedCrl &>(item); | |
55 | const CSSM_DATA &vers = crl.mCrl.tbs.version; | |
56 | if(!tbsGetCheck(vers.Data, index)) { | |
57 | /* not present, optional */ | |
58 | return false; | |
59 | } | |
60 | fieldValue.copy(vers.Data, vers.Length); | |
61 | numFields = 1; | |
62 | return true; | |
63 | } | |
64 | ||
65 | static void setField_Version ( | |
66 | DecodedItem &item, | |
67 | const CssmData &fieldValue) | |
68 | { | |
69 | DecodedCrl &crl = dynamic_cast<DecodedCrl &>(item); | |
70 | CSSM_DATA &vers = crl.mCrl.tbs.version; | |
71 | tbsSetCheck(vers.Data, fieldValue, 0, "version"); | |
72 | crl.coder().allocCopyItem(fieldValue, vers); | |
73 | } | |
74 | ||
75 | /*** issuer | |
76 | *** Format = CSSM_X509_NAME | |
77 | *** class Name from sm_x501if | |
78 | ***/ | |
79 | static bool getField_Issuer ( | |
80 | DecodedItem &item, | |
81 | unsigned index, // which occurrence (0 = first) | |
82 | uint32 &numFields, // RETURNED | |
83 | CssmOwnedData &fieldValue) // RETURNED | |
84 | { | |
85 | if(index != 0) { | |
86 | return false; | |
87 | } | |
88 | ||
89 | bool brtn; | |
90 | ||
91 | const DecodedCrl &crl = dynamic_cast<const DecodedCrl &>(item); | |
92 | try { | |
93 | brtn = getField_RDN_NSS(crl.mCrl.tbs.issuer, fieldValue); | |
94 | if(brtn) { | |
95 | numFields = 1; | |
96 | } | |
97 | } | |
98 | catch (...) { | |
99 | freeField_RDN(fieldValue); | |
100 | throw; | |
101 | } | |
102 | return brtn; | |
103 | } | |
104 | ||
105 | static void setField_Issuer ( | |
106 | DecodedItem &item, | |
107 | const CssmData &fieldValue) | |
108 | { | |
109 | DecodedCrl &crl = dynamic_cast<DecodedCrl &>(item); | |
110 | const CSSM_X509_NAME *cssmName = (const CSSM_X509_NAME *)fieldValue.Data; | |
111 | NSS_Name &nssName = crl.mCrl.tbs.issuer; | |
112 | tbsSetCheck(nssName.rdns, fieldValue, sizeof(CSSM_X509_NAME), | |
113 | "IssuerName"); | |
114 | CL_cssmNameToNss(*cssmName, nssName, crl.coder()); | |
115 | } | |
116 | ||
117 | /*** | |
118 | *** This/Next update | |
119 | *** Format: CSSM_X509_TIME | |
120 | ***/ | |
121 | static bool getField_ThisUpdate ( | |
122 | DecodedItem &item, | |
123 | unsigned index, // which occurrence (0 = first) | |
124 | uint32 &numFields, // RETURNED | |
125 | CssmOwnedData &fieldValue) // RETURNED | |
126 | { | |
127 | const DecodedCrl &crl = dynamic_cast<const DecodedCrl &>(item); | |
128 | const NSS_Time &srcTime = crl.mCrl.tbs.thisUpdate; | |
129 | return getField_TimeNSS(srcTime, index, numFields, fieldValue); | |
130 | } | |
131 | ||
132 | static void setField_ThisUpdate ( | |
133 | DecodedItem &item, | |
134 | const CssmData &fieldValue) | |
135 | { | |
136 | DecodedCrl &crl = dynamic_cast<DecodedCrl &>(item); | |
137 | NSS_Time &dstTime = crl.mCrl.tbs.thisUpdate; | |
138 | tbsSetCheck(dstTime.item.Data, fieldValue, | |
139 | sizeof(CSSM_X509_TIME), "NotBefore"); | |
140 | setField_TimeNSS(fieldValue, dstTime, crl.coder()); | |
141 | } | |
142 | ||
143 | static bool getField_NextUpdate ( | |
144 | DecodedItem &item, | |
145 | unsigned index, // which occurrence (0 = first) | |
146 | uint32 &numFields, // RETURNED | |
147 | CssmOwnedData &fieldValue) // RETURNED | |
148 | { | |
149 | const DecodedCrl &crl = dynamic_cast<const DecodedCrl &>(item); | |
150 | const NSS_Time &srcTime = crl.mCrl.tbs.nextUpdate; | |
151 | return getField_TimeNSS(srcTime, index, numFields, fieldValue); | |
152 | } | |
153 | ||
154 | static void setField_NextUpdate ( | |
155 | DecodedItem &item, | |
156 | const CssmData &fieldValue) | |
157 | { | |
158 | DecodedCrl &crl = dynamic_cast<DecodedCrl &>(item); | |
159 | NSS_Time &dstTime = crl.mCrl.tbs.nextUpdate; | |
160 | tbsSetCheck(dstTime.item.Data, fieldValue, | |
161 | sizeof(CSSM_X509_TIME), "NotBefore"); | |
162 | setField_TimeNSS(fieldValue, dstTime, crl.coder()); | |
163 | } | |
164 | ||
165 | /*** | |
166 | *** Issuer Name (normalized and encoded version) | |
167 | *** Format = CSSM_DATA containing the DER encoding of the normalized name | |
168 | ***/ | |
169 | static bool getFieldIssuerNorm( | |
170 | DecodedItem &item, | |
171 | unsigned index, // which occurrence (0 = first) | |
172 | uint32 &numFields, // RETURNED | |
173 | CssmOwnedData &fieldValue) // RETURNED | |
174 | { | |
175 | if(index != 0) { | |
176 | return false; | |
177 | } | |
178 | const DecodedCrl &crl = dynamic_cast<const DecodedCrl &>(item); | |
179 | return getField_normRDN_NSS(crl.mCrl.tbs.derIssuer, numFields, | |
180 | fieldValue); | |
181 | } | |
182 | ||
183 | /*** | |
184 | *** TBS AlgId | |
185 | *** Format = CSSM_X509_ALGORITHM_IDENTIFIER | |
186 | ***/ | |
187 | static bool getField_CrlTbsAlgId ( | |
188 | DecodedItem &item, | |
189 | unsigned index, // which occurrence (0 = first) | |
190 | uint32 &numFields, // RETURNED | |
191 | CssmOwnedData &fieldValue) // RETURNED | |
192 | { | |
193 | const DecodedCrl &crl = dynamic_cast<const DecodedCrl &>(item); | |
194 | const CSSM_X509_ALGORITHM_IDENTIFIER &srcAlgId = | |
195 | crl.mCrl.signatureAlgorithm; | |
196 | if(!tbsGetCheck(srcAlgId.algorithm.Data, index)) { | |
197 | return false; | |
198 | } | |
199 | getField_AlgIdNSS(srcAlgId, fieldValue); | |
200 | numFields = 1; | |
201 | return true; | |
202 | } | |
203 | ||
204 | /* | |
205 | * Support for entries in revocation list | |
206 | */ | |
207 | static void nssRevokedEntryToCssm( | |
208 | NSS_RevokedCert &nssEntry, | |
209 | CSSM_X509_REVOKED_CERT_ENTRY &cssmEntry, | |
210 | Allocator &alloc) | |
211 | { | |
212 | clAllocCopyData(alloc, nssEntry.userCertificate, cssmEntry.certificateSerialNumber); | |
213 | CL_nssTimeToCssm(nssEntry.revocationDate, cssmEntry.revocationDate, alloc); | |
214 | ||
215 | /* CSSM_X509_EXTENSIONS extensions */ | |
216 | NSS_CertExtension **nssExtens = nssEntry.extensions; | |
217 | if(nssExtens == NULL) { | |
218 | /* done */ | |
219 | return; | |
220 | } | |
221 | ||
222 | /* | |
223 | * First we have to decode the NSS-style Extensions into a | |
224 | * DecodedExtensions object. For cert- and CRL-wide extensions, this | |
225 | * is done at the construction of Decoded{Cert,Crl}. However for | |
226 | * per-CRL-entry entensions, this is (currently) the only place | |
227 | * this decoding is done. | |
228 | */ | |
229 | SecNssCoder coder; | |
230 | DecodedExtensions decodedExtens(coder, alloc); | |
231 | decodedExtens.decodeFromNss(nssExtens); | |
232 | ||
233 | /* convert to CDSA style */ | |
234 | decodedExtens.convertToCdsa(cssmEntry.extensions, alloc); | |
235 | } | |
236 | ||
237 | static void freeCssmEntry( | |
238 | CSSM_X509_REVOKED_CERT_ENTRY_PTR cssmEntry, | |
239 | Allocator &alloc) | |
240 | { | |
241 | if(cssmEntry == NULL) { | |
242 | return; | |
243 | } | |
244 | if(cssmEntry->certificateSerialNumber.Data) { | |
245 | alloc.free(cssmEntry->certificateSerialNumber.Data); | |
246 | cssmEntry->certificateSerialNumber.Data = NULL; | |
247 | cssmEntry->certificateSerialNumber.Length = 0; | |
248 | } | |
249 | CL_freeCssmTime(&cssmEntry->revocationDate, alloc); | |
250 | ||
251 | /* CSSM_X509_EXTENSIONS extensions */ | |
252 | CL_freeCssmExtensions(cssmEntry->extensions, alloc); | |
253 | ||
254 | memset(cssmEntry, 0, sizeof(CSSM_X509_REVOKED_CERT_ENTRY)); | |
255 | } | |
256 | ||
257 | static void nssRevokedListToCssm( | |
258 | NSS_RevokedCert **nssList, // may be NULL | |
259 | CSSM_X509_REVOKED_CERT_LIST_PTR cssmList, | |
260 | Allocator &alloc) | |
261 | { | |
262 | unsigned numEntries = clNssArraySize((const void **)nssList); | |
263 | cssmList->numberOfRevokedCertEntries = numEntries; | |
264 | if(numEntries == 0) { | |
265 | cssmList->revokedCertEntry = NULL; | |
266 | return; | |
267 | } | |
268 | cssmList->revokedCertEntry = (CSSM_X509_REVOKED_CERT_ENTRY_PTR)alloc.malloc( | |
269 | sizeof(CSSM_X509_REVOKED_CERT_ENTRY) * numEntries); | |
270 | memset(cssmList->revokedCertEntry, 0, | |
271 | sizeof(CSSM_X509_REVOKED_CERT_ENTRY) * numEntries); | |
272 | for(unsigned dex=0; dex<numEntries; dex++) { | |
273 | NSS_RevokedCert *nssEntry = nssList[dex]; | |
274 | assert(nssEntry != NULL); | |
275 | CSSM_X509_REVOKED_CERT_ENTRY_PTR cssmEntry = | |
276 | &cssmList->revokedCertEntry[dex]; | |
277 | nssRevokedEntryToCssm(*nssEntry, *cssmEntry, alloc); | |
278 | } | |
279 | } | |
280 | ||
281 | ||
282 | static void freeCssmRevokedList( | |
283 | CSSM_X509_REVOKED_CERT_LIST_PTR cssmList, | |
284 | Allocator &alloc) | |
285 | { | |
286 | if(cssmList == NULL) { | |
287 | return; | |
288 | } | |
289 | for(unsigned dex=0; dex<cssmList->numberOfRevokedCertEntries; dex++) { | |
290 | CSSM_X509_REVOKED_CERT_ENTRY_PTR cssmEntry = | |
291 | &cssmList->revokedCertEntry[dex]; | |
292 | freeCssmEntry(cssmEntry, alloc); | |
293 | } | |
294 | if(cssmList->revokedCertEntry) { | |
295 | alloc.free(cssmList->revokedCertEntry); | |
296 | } | |
297 | memset(cssmList, 0, sizeof(CSSM_X509_REVOKED_CERT_LIST)); | |
298 | } | |
299 | ||
300 | /*** | |
301 | *** SignedCRL | |
302 | *** Format: CSSM_X509_SIGNED_CRL (the whole enchilada, parsed) | |
303 | ***/ | |
304 | static bool getField_SignedCrl ( | |
305 | DecodedItem &item, | |
306 | unsigned index, // which occurrence (0 = first) | |
307 | uint32 &numFields, // RETURNED | |
308 | CssmOwnedData &fieldValue) // RETURNED | |
309 | { | |
310 | Allocator &alloc = fieldValue.allocator; | |
311 | ||
312 | const DecodedCrl &nssCrl = dynamic_cast<const DecodedCrl &>(item); | |
313 | const NSS_TBSCrl &nssTbs = nssCrl.mCrl.tbs; | |
314 | fieldValue.malloc(sizeof(CSSM_X509_SIGNED_CRL)); | |
315 | CSSM_X509_SIGNED_CRL &cssmCrl = *((CSSM_X509_SIGNED_CRL *)fieldValue.data()); | |
316 | ||
317 | memset(&cssmCrl, 0, sizeof(CSSM_X509_SIGNED_CRL)); | |
318 | CSSM_X509_TBS_CERTLIST &cssmTbs = cssmCrl.tbsCertList; | |
319 | ||
320 | /* version */ | |
321 | clAllocCopyData(alloc, nssTbs.version, cssmTbs.version); | |
322 | ||
323 | /* CSSM_X509_ALGORITHM_IDENTIFIER signature - in TBS and CRL */ | |
324 | CL_copyAlgId(nssTbs.signature, cssmTbs.signature, alloc); | |
325 | CL_copyAlgId(nssCrl.mCrl.signatureAlgorithm, | |
326 | cssmCrl.signature.algorithmIdentifier, alloc); | |
327 | ||
328 | /* CSSM_X509_NAME issuer */ | |
329 | CL_nssNameToCssm(nssTbs.issuer, cssmTbs.issuer, alloc); | |
330 | ||
331 | /* CSSM_X509_TIME thisUpdate, nextUpdate */ | |
332 | CL_nssTimeToCssm(nssTbs.thisUpdate, cssmTbs.thisUpdate, alloc); | |
333 | CL_nssTimeToCssm(nssTbs.nextUpdate, cssmTbs.nextUpdate, alloc); | |
334 | ||
335 | /* CSSM_X509_REVOKED_CERT_LIST_PTR revokedCertificates */ | |
336 | if(nssTbs.revokedCerts != NULL) { | |
337 | cssmTbs.revokedCertificates = (CSSM_X509_REVOKED_CERT_LIST_PTR) | |
338 | alloc.malloc(sizeof(CSSM_X509_REVOKED_CERT_LIST)); | |
339 | memset(cssmTbs.revokedCertificates, 0, sizeof(CSSM_X509_REVOKED_CERT_LIST)); | |
340 | nssRevokedListToCssm(nssTbs.revokedCerts, | |
341 | cssmTbs.revokedCertificates, alloc); | |
342 | } | |
343 | ||
344 | /* CSSM_X509_EXTENSIONS extensions */ | |
345 | const DecodedExtensions &decodedExtens = nssCrl.decodedExtens(); | |
346 | decodedExtens.convertToCdsa(cssmTbs.extensions, alloc); | |
347 | ||
348 | /* raw signature - stored in bits - note signature.algId set above */ | |
349 | CSSM_DATA nssSig = nssCrl.mCrl.signature; | |
350 | nssSig.Length = (nssSig.Length + 7) / 8; | |
351 | clAllocCopyData(alloc, nssSig, cssmCrl.signature.encrypted); | |
352 | numFields = 1; | |
353 | return true; | |
354 | } | |
355 | ||
356 | static void setField_SignedCrl ( | |
357 | DecodedItem &item, | |
358 | const CssmData &fieldValue) | |
359 | { | |
360 | /* TBD - writing CRLs not supported now */ | |
361 | CssmError::throwMe(CSSM_ERRCODE_FUNCTION_NOT_IMPLEMENTED); | |
362 | } | |
363 | ||
427c49bc | 364 | static void freeField_SignedCrl ( |
b1ab9ed8 A |
365 | CssmOwnedData &fieldValue) |
366 | { | |
367 | CSSM_X509_SIGNED_CRL *cssmCrl = | |
368 | (CSSM_X509_SIGNED_CRL *)fieldValue.data(); | |
369 | ||
370 | if(cssmCrl == NULL) { | |
371 | return; | |
372 | } | |
373 | if(fieldValue.length() != sizeof(CSSM_X509_SIGNED_CRL)) { | |
374 | CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER); | |
375 | } | |
376 | Allocator &alloc = fieldValue.allocator; | |
377 | CSSM_X509_TBS_CERTLIST_PTR cssmTbs = &cssmCrl->tbsCertList; | |
378 | if(cssmTbs == NULL) { | |
379 | CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER); | |
380 | } | |
381 | ||
382 | /* run down the fields */ | |
383 | if(cssmTbs->version.Data) { | |
384 | alloc.free(cssmTbs->version.Data); | |
385 | } | |
386 | ||
387 | /* CSSM_X509_ALGORITHM_IDENTIFIER signature - in TBS and CRL */ | |
388 | CL_freeCssmAlgId(&cssmTbs->signature, alloc); | |
389 | CL_freeCssmAlgId(&cssmCrl->signature.algorithmIdentifier, alloc); | |
390 | ||
391 | /* issuer, thisUpdate, nextUpdate */ | |
392 | CL_freeX509Name(&cssmTbs->issuer, alloc); | |
393 | CL_freeCssmTime(&cssmTbs->thisUpdate, alloc); | |
394 | CL_freeCssmTime(&cssmTbs->nextUpdate, alloc); | |
395 | ||
396 | /* CSSM_X509_REVOKED_CERT_LIST_PTR revokedCertificates */ | |
397 | freeCssmRevokedList(cssmTbs->revokedCertificates, alloc); | |
398 | alloc.free(cssmTbs->revokedCertificates); | |
399 | ||
400 | /* CSSM_X509_EXTENSIONS extensions */ | |
401 | CL_freeCssmExtensions(cssmTbs->extensions, alloc); | |
402 | ||
403 | /* raw signature - note signature.algId freed above */ | |
404 | alloc.free(cssmCrl->signature.encrypted.Data); | |
405 | ||
406 | memset(cssmCrl, 0, sizeof(CSSM_X509_SIGNED_CRL)); | |
407 | } | |
408 | ||
409 | /* | |
410 | * Table to map OID to {get,set,free}field | |
411 | */ | |
412 | typedef struct { | |
413 | const CSSM_OID *fieldId; | |
414 | getItemFieldFcn *getFcn; | |
415 | setItemFieldFcn *setFcn; | |
416 | freeFieldFcn *freeFcn; // OPTIONAL - NULL means just free the | |
417 | // top-level data | |
418 | } oidToFieldFuncs; | |
419 | ||
420 | ||
421 | static const oidToFieldFuncs crlFieldTable[] = { | |
422 | /* this first one, which returns everything in a parsed format, | |
423 | * is intended to be normally the only field used */ | |
424 | { &CSSMOID_X509V2CRLSignedCrlCStruct, | |
425 | &getField_SignedCrl, &setField_SignedCrl, &freeField_SignedCrl }, | |
426 | { &CSSMOID_X509V2CRLVersion, | |
427 | &getField_Version, &setField_Version, NULL }, | |
428 | { &CSSMOID_X509V1CRLIssuerNameCStruct, | |
429 | &getField_Issuer, &setField_Issuer, &freeField_RDN }, | |
430 | { &CSSMOID_X509V1CRLThisUpdate, | |
431 | &getField_ThisUpdate, &setField_ThisUpdate, &freeField_Time }, | |
432 | { &CSSMOID_X509V1CRLNextUpdate, | |
433 | &getField_NextUpdate, &setField_NextUpdate, &freeField_Time }, | |
434 | { &CSSMOID_X509V1IssuerName, | |
435 | getFieldIssuerNorm, &setField_ReadOnly, NULL }, | |
436 | { &CSSMOID_X509V1SignatureAlgorithmTBS, | |
437 | &getField_CrlTbsAlgId, &setField_ReadOnly, &freeField_AlgId }, | |
438 | // ...etc.. | |
439 | /* | |
440 | * Extensions, implemented in CrlExtensions.cpp | |
441 | * When adding new ones, also add to: | |
442 | * -- clOidToNssInfo() in CLFieldsCommon.cpp | |
443 | * -- get/set/free functions in CrlExtensions.{cpp,h} | |
444 | * -- DecodedExten::parse in DecodedExtensions.cpp | |
445 | */ | |
446 | { &CSSMOID_CrlNumber, | |
447 | &getFieldCrlNumber, &setFieldCrlNumber, freeFieldSimpleExtension }, | |
448 | { &CSSMOID_DeltaCrlIndicator, | |
449 | &getFieldDeltaCrl, &setFieldCrlNumber, freeFieldSimpleExtension }, | |
450 | { &CSSMOID_CertIssuer, // get/set not implemented | |
451 | &getField_Unimplemented, &setField_ReadOnly, | |
452 | &freeFieldSubjIssuerAltName}, | |
453 | { &CSSMOID_CrlReason, // get/set not implemented | |
454 | &getField_Unimplemented, &setField_ReadOnly, | |
455 | freeFieldSimpleExtension}, | |
456 | { &CSSMOID_IssuingDistributionPoint, // get/set not implemented | |
457 | &getField_Unimplemented, &setField_ReadOnly, | |
458 | &freeFieldIssuingDistPoint}, | |
459 | { &CSSMOID_HoldInstructionCode, // get/set not implemented | |
460 | &getField_Unimplemented, &setField_ReadOnly, | |
461 | &freeFieldOidOrData}, | |
462 | { &CSSMOID_InvalidityDate, // get/set not implemented | |
463 | &getField_Unimplemented, &setField_ReadOnly, | |
464 | &freeFieldOidOrData}, | |
465 | ||
466 | /* in common with CertExtensions */ | |
467 | { &CSSMOID_AuthorityKeyIdentifier, &getFieldAuthorityKeyId, | |
468 | &setFieldAuthorityKeyId, &freeFieldAuthorityKeyId } , | |
469 | { &CSSMOID_X509V3CertificateExtensionCStruct, &getFieldUnknownExt, | |
470 | &setFieldUnknownExt, &freeFieldUnknownExt }, | |
471 | { &CSSMOID_SubjectAltName, &getFieldSubjAltName, | |
472 | &setFieldSubjIssuerAltName, &freeFieldSubjIssuerAltName } , | |
473 | { &CSSMOID_IssuerAltName, &getFieldIssuerAltName, | |
474 | &setFieldSubjIssuerAltName, &freeFieldSubjIssuerAltName } , | |
475 | ||
476 | { &CSSMOID_CrlDistributionPoints, // get/set not implemented | |
477 | &getField_Unimplemented, &setField_ReadOnly, | |
478 | &freeFieldCrlDistributionPoints}, | |
479 | // etc.. | |
480 | }; | |
481 | ||
482 | #define NUM_KNOWN_FIELDS (sizeof(crlFieldTable) / sizeof(oidToFieldFuncs)) | |
483 | #define NUM_STD_CRL_FIELDS 2 /* TBD not including extensions */ | |
484 | ||
485 | /* map an OID to an oidToFieldFuncs */ | |
486 | static const oidToFieldFuncs *oidToFields( | |
487 | const CssmOid &fieldId) | |
488 | { | |
489 | const oidToFieldFuncs *fieldTable = crlFieldTable; | |
490 | for(unsigned i=0; i<NUM_KNOWN_FIELDS; i++) { | |
491 | if(fieldId == CssmData::overlay(*fieldTable->fieldId)) { | |
492 | return fieldTable; | |
493 | } | |
494 | fieldTable++; | |
495 | } | |
496 | CssmError::throwMe(CSSMERR_CL_UNKNOWN_TAG); | |
497 | } | |
498 | ||
499 | /* | |
500 | * Common routine to free OID-specific field data. Used in the | |
501 | * public DecodedCrl::freeCrlFieldData and when freeing | |
502 | * extensions in a CSSM_X509_TBS_CERTLIST. | |
503 | */ | |
504 | static void CL_freeCrlFieldData( | |
505 | const CssmOid &fieldId, | |
506 | CssmOwnedData &fieldValue, | |
507 | bool reset = true) | |
508 | { | |
509 | if((fieldValue.data() == NULL) || (fieldValue.length() == 0)) { | |
510 | CssmError::throwMe(CSSM_ERRCODE_INVALID_FIELD_POINTER); | |
511 | } | |
512 | const oidToFieldFuncs *fieldFuncs = oidToFields(fieldId); | |
513 | if(fieldFuncs->freeFcn != NULL) { | |
514 | /* optional - simple cases handled below */ | |
515 | fieldFuncs->freeFcn(fieldValue); | |
516 | } | |
517 | if(reset) { | |
518 | fieldValue.reset(); | |
519 | fieldValue.release(); | |
520 | } | |
521 | } | |
522 | ||
523 | /* | |
524 | * Common routime to free a CSSM_X509_EXTENSIONS. Used to free | |
525 | * CSSM_X509_TBS_CERTLIST.extensions and | |
526 | * CSSM_X509_REVOKED_CERT_ENTRY.extensions. | |
527 | * We just cook up a CssmOid and a CssmOwnedData for each extension | |
528 | * and pass to CL_freeCrlFieldData(). | |
529 | */ | |
530 | static void CL_freeCssmExtensions( | |
531 | CSSM_X509_EXTENSIONS &extens, | |
532 | Allocator &alloc) | |
533 | { | |
534 | for(uint32 dex=0; dex<extens.numberOfExtensions; dex++) { | |
535 | CSSM_X509_EXTENSION_PTR exten = &extens.extensions[dex]; | |
536 | const CSSM_OID *fieldOid; | |
537 | ||
538 | /* | |
539 | * The field OID is either the same as the extension's OID (if we parsed | |
540 | * it) or CSSMOID_X509V3CertificateExtensionCStruct (if we didn't). | |
541 | */ | |
542 | switch(exten->format) { | |
543 | case CSSM_X509_DATAFORMAT_ENCODED: | |
544 | fieldOid = &CSSMOID_X509V3CertificateExtensionCStruct; | |
545 | break; | |
546 | case CSSM_X509_DATAFORMAT_PARSED: | |
547 | case CSSM_X509_DATAFORMAT_PAIR: | |
548 | fieldOid = &exten->extnId; | |
549 | break; | |
550 | default: | |
551 | clErrorLog("CL_freeCssmExtensions: bad exten->format (%d)", | |
552 | (int)exten->format); | |
553 | CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER); | |
554 | } | |
555 | ||
556 | const CssmOid &fieldId = CssmOid::overlay(*fieldOid); | |
557 | ||
558 | if (exten->extnId.Data != NULL) // if this is null, something threw when it was instantiated | |
559 | { | |
560 | CssmData cData((uint8 *)exten, sizeof(CSSM_X509_EXTENSION)); | |
561 | CssmRemoteData fieldValue(alloc, cData); | |
562 | CL_freeCrlFieldData(fieldId, fieldValue, false); | |
563 | fieldValue.release(); // but no free (via reset() */ | |
564 | } | |
565 | } | |
566 | alloc.free(extens.extensions); | |
567 | memset(&extens, 0, sizeof(CSSM_X509_EXTENSIONS)); | |
568 | } | |
569 | ||
570 | ||
571 | ||
572 | /*** | |
573 | *** Public functions | |
574 | ***/ | |
575 | ||
576 | /* | |
577 | * Obtain the index'th occurrence of field specified by fieldId in specified cert. | |
578 | * Format of the returned field depends on fieldId. | |
579 | * Returns total number of fieldId fields in the cert if index is 0. | |
580 | * FieldValue assumed to be empty on entry. | |
581 | * Returns true if specified field was found, else returns false. | |
582 | */ | |
583 | bool DecodedCrl::getCrlFieldData( | |
584 | const CssmOid &fieldId, // which field | |
585 | unsigned index, // which occurrence (0 = first) | |
586 | uint32 &numFields, // RETURNED | |
587 | CssmOwnedData &fieldValue) // RETURNED | |
588 | { | |
589 | switch(mState) { | |
590 | case IS_Empty: | |
591 | case IS_Building: | |
592 | clErrorLog("DecodedCrl::getCrlField: can't parse undecoded CRL!"); | |
593 | CssmError::throwMe(CSSMERR_CL_INTERNAL_ERROR); | |
594 | case IS_DecodedAll: | |
595 | case IS_DecodedTBS: | |
596 | break; | |
597 | } | |
598 | const oidToFieldFuncs *fieldFuncs = oidToFields(fieldId); | |
599 | return fieldFuncs->getFcn(*this, index, numFields, fieldValue); | |
600 | } | |
601 | ||
602 | /* | |
603 | * Set the field specified by fieldId in the specified Cert. | |
604 | * Note no index - individual field routines either append (for extensions) | |
605 | * or if field already set ::throwMe(for all others) | |
606 | */ | |
607 | void DecodedCrl::setCrlField( | |
608 | const CssmOid &fieldId, // which field | |
609 | const CssmData &fieldValue) | |
610 | { | |
611 | switch(mState) { | |
612 | case IS_Empty: // first time thru | |
613 | mState = IS_Building; | |
614 | break; | |
615 | case IS_Building: // subsequent passes | |
616 | break; | |
617 | case IS_DecodedAll: | |
618 | case IS_DecodedTBS: | |
619 | clErrorLog("DecodedCrl::setCrlField: can't build on a decoded CRL!"); | |
620 | CssmError::throwMe(CSSMERR_CL_INTERNAL_ERROR); | |
621 | } | |
622 | if((fieldValue.data() == NULL) || (fieldValue.length() == 0)) { | |
623 | CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER); | |
624 | } | |
625 | const oidToFieldFuncs *fieldFuncs = oidToFields(fieldId); | |
626 | const CssmData &value = CssmData::overlay(fieldValue); | |
627 | fieldFuncs->setFcn(*this, value); | |
628 | } | |
629 | ||
630 | /* | |
631 | * Free the fieldId-specific data referred to by fieldValue->Data. | |
632 | * No state from DecodedCrl needed; use the routine shared with | |
633 | * CL_freeCssmExtensions(). | |
634 | */ | |
635 | void DecodedCrl::freeCrlFieldData( | |
636 | const CssmOid &fieldId, | |
637 | CssmOwnedData &fieldValue) | |
638 | { | |
639 | CL_freeCrlFieldData(fieldId, fieldValue); | |
640 | } | |
641 | ||
642 | ||
643 | /* | |
644 | * Common means to get all fields from a decoded CRL. Used in | |
645 | * CrlGetAllTemplateFields and CrlGetAllFields. | |
646 | */ | |
647 | void DecodedCrl::getAllParsedCrlFields( | |
648 | uint32 &NumberOfFields, // RETURNED | |
649 | CSSM_FIELD_PTR &CrlFields) // RETURNED | |
650 | { | |
651 | /* this is the max - some might be missing */ | |
652 | uint32 maxFields = NUM_STD_CRL_FIELDS + mDecodedExtensions.numExtensions(); | |
653 | CSSM_FIELD_PTR outFields = (CSSM_FIELD_PTR)mAlloc.malloc( | |
654 | maxFields * sizeof(CSSM_FIELD)); | |
655 | ||
656 | /* | |
657 | * We'll be copying oids and values for fields we find into | |
658 | * outFields; current number of valid fields found in numOutFields. | |
659 | */ | |
660 | memset(outFields, 0, maxFields * sizeof(CSSM_FIELD)); | |
661 | uint32 numOutFields = 0; | |
662 | CSSM_FIELD_PTR currOutField; | |
663 | uint32 currOidDex; | |
664 | const CSSM_OID *currOid; | |
665 | CssmAutoData aData(mAlloc); // for malloc/copy of outgoing data | |
666 | ||
667 | /* query for each OID we know about */ | |
668 | for(currOidDex=0; currOidDex<NUM_KNOWN_FIELDS; currOidDex++) { | |
669 | const oidToFieldFuncs *fieldFuncs = &crlFieldTable[currOidDex]; | |
670 | currOid = fieldFuncs->fieldId; | |
671 | uint32 numFields; // for THIS oid | |
672 | ||
673 | /* | |
674 | * Return false if field not there, which is not an error here. | |
675 | * Actual exceptions are fatal. | |
676 | */ | |
677 | if(!fieldFuncs->getFcn(*this, | |
678 | 0, // index - looking for first one | |
679 | numFields, | |
680 | aData)) { | |
681 | continue; | |
682 | } | |
683 | ||
684 | /* got some data for this oid - copy it and oid to outgoing CrlFields */ | |
685 | assert(numOutFields < maxFields); | |
686 | currOutField = &outFields[numOutFields]; | |
687 | currOutField->FieldValue = aData.release(); | |
688 | aData.copy(*currOid); | |
689 | currOutField->FieldOid = aData.release(); | |
690 | numOutFields++; | |
691 | ||
692 | /* if more fields are available for this OID, snag them too */ | |
693 | for(uint32 fieldDex=1; fieldDex<numFields; fieldDex++) { | |
694 | /* note this should always succeed */ | |
695 | bool brtn = fieldFuncs->getFcn(*this, | |
696 | fieldDex, | |
697 | numFields, // shouldn't change | |
698 | aData); | |
699 | if(!brtn) { | |
700 | clErrorLog("getAllParsedCrlFields: index screwup"); | |
701 | CssmError::throwMe(CSSMERR_CL_INTERNAL_ERROR); | |
702 | } | |
703 | assert(numOutFields < maxFields); | |
704 | currOutField = &outFields[numOutFields]; | |
705 | currOutField->FieldValue = aData.release(); | |
706 | aData.copy(*currOid); | |
707 | currOutField->FieldOid = aData.release(); | |
708 | numOutFields++; | |
709 | } /* multiple fields for currOid */ | |
710 | } /* for each known OID */ | |
711 | ||
712 | NumberOfFields = numOutFields; | |
713 | CrlFields = outFields; | |
714 | } | |
715 | ||
716 | void | |
717 | DecodedCrl::describeFormat( | |
718 | Allocator &alloc, | |
719 | uint32 &NumberOfFields, | |
720 | CSSM_OID_PTR &OidList) | |
721 | { | |
722 | /* malloc in app's space, do deep copy (including ->Data) */ | |
723 | CSSM_OID_PTR oidList = (CSSM_OID_PTR)alloc.malloc( | |
724 | NUM_KNOWN_FIELDS * sizeof(CSSM_OID)); | |
725 | memset(oidList, 0, NUM_KNOWN_FIELDS * sizeof(CSSM_OID)); | |
726 | for(unsigned i=0; i<NUM_KNOWN_FIELDS; i++) { | |
727 | CssmAutoData oidCopy(alloc, *crlFieldTable[i].fieldId); | |
728 | oidList[i] = oidCopy.release(); | |
729 | } | |
730 | NumberOfFields = NUM_KNOWN_FIELDS; | |
731 | OidList = oidList; | |
732 | } |