]>
Commit | Line | Data |
---|---|---|
b1ab9ed8 | 1 | /* |
d8f41ccd | 2 | * Copyright (c) 2000-2001,2011-2012,2014 Apple Inc. All Rights Reserved. |
427c49bc | 3 | * |
b1ab9ed8 A |
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. | |
427c49bc | 9 | * |
b1ab9ed8 A |
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 | * CertFields.cpp - convert between NSS-based Certificate components and CDSA-style | |
21 | * fields. A major component of DecodedCert. | |
22 | * | |
d8f41ccd | 23 | * Copyright (c) 2000,2011-2012,2014 Apple Inc. |
b1ab9ed8 A |
24 | */ |
25 | ||
26 | #include "DecodedCert.h" | |
27 | #include "cldebugging.h" | |
28 | #include "CLCertExtensions.h" | |
29 | #include "clNssUtils.h" | |
30 | #include "clNameUtils.h" | |
31 | #include "CLFieldsCommon.h" | |
32 | #include <Security/oidscert.h> | |
33 | #include <Security/x509defs.h> | |
34 | #include <security_utilities/utilities.h> | |
35 | ||
36 | /*** | |
37 | *** Version | |
38 | *** Format = DER-encoded int (max of four bytes in this case) | |
39 | ***/ | |
40 | static bool getField_Version ( | |
41 | DecodedItem &item, | |
42 | unsigned index, // which occurrence (0 = first) | |
43 | uint32 &numFields, // RETURNED | |
44 | CssmOwnedData &fieldValue) // RETURNED | |
45 | { | |
46 | const DecodedCert &cert = dynamic_cast<const DecodedCert &>(item); | |
47 | const CSSM_DATA &vers = cert.mCert.tbs.version; | |
48 | if(!tbsGetCheck(vers.Data, index)) { | |
49 | /* not present, optional */ | |
50 | return false; | |
51 | } | |
52 | fieldValue.copy(vers.Data, vers.Length); | |
53 | numFields = 1; | |
54 | return true; | |
55 | } | |
56 | ||
57 | static void setField_Version ( | |
58 | DecodedItem &item, | |
59 | const CssmData &fieldValue) | |
60 | { | |
61 | DecodedCert &cert = dynamic_cast<DecodedCert &>(item); | |
62 | CSSM_DATA &vers = cert.mCert.tbs.version; | |
63 | tbsSetCheck(vers.Data, fieldValue, 0, "version"); | |
64 | cert.coder().allocCopyItem(fieldValue, vers); | |
65 | } | |
66 | ||
67 | ||
68 | #if this_is_a_template | |
69 | /*** | |
70 | *** Version | |
71 | *** Format = DER-encoded int (always four bytes in this case) | |
72 | ***/ | |
73 | static bool getField_Version ( | |
74 | DecodedItem &item, | |
75 | unsigned index, // which occurrence (0 = first) | |
76 | uint32 &numFields, // RETURNED | |
77 | CssmOwnedData &fieldValue) // RETURNED | |
78 | { | |
79 | const DecodedCert &cert = dynamic_cast<const DecodedCert &>(item); | |
80 | tbsGetCheck(cert.certificateToSign->version, index); | |
81 | } | |
82 | static void setField_Version ( | |
83 | DecodedItem &item, | |
84 | const CssmData &fieldValue) | |
85 | { | |
86 | DecodedCert &cert = dynamic_cast<DecodedCert &>(item); | |
87 | tbsSetCheck(cert.certificateToSign->version, fieldValue, sizeof(uint32), | |
88 | "version"); | |
89 | ||
90 | } | |
91 | static void freeField_Version ( | |
92 | CssmOwnedData &fieldValue) | |
93 | { | |
94 | } | |
95 | #endif | |
96 | ||
97 | /*** | |
98 | *** Serial Number | |
99 | *** Format = DER-encoded int, variable length | |
100 | ***/ | |
101 | static bool getField_SerialNumber ( | |
102 | DecodedItem &item, | |
103 | unsigned index, // which occurrence (0 = first) | |
104 | uint32 &numFields, // RETURNED | |
105 | CssmOwnedData &fieldValue) // RETURNED | |
106 | { | |
107 | const DecodedCert &cert = dynamic_cast<const DecodedCert &>(item); | |
108 | const CSSM_DATA &sn = cert.mCert.tbs.serialNumber; | |
109 | if(!tbsGetCheck(sn.Data, index)) { | |
110 | return false; | |
111 | } | |
112 | fieldValue.copy(sn.Data, sn.Length); | |
113 | numFields = 1; | |
114 | return true; | |
115 | } | |
116 | ||
117 | static void setField_SerialNumber ( | |
118 | DecodedItem &item, | |
119 | const CssmData &fieldValue) | |
120 | { | |
121 | DecodedCert &cert = dynamic_cast<DecodedCert &>(item); | |
122 | CSSM_DATA &sn = cert.mCert.tbs.serialNumber; | |
123 | tbsSetCheck(sn.Data, fieldValue, 0, "SerialNumber"); | |
124 | cert.coder().allocCopyItem(fieldValue, sn); | |
125 | } | |
126 | ||
127 | /*** issuer/subject | |
128 | *** Format = CSSM_X509_NAME | |
129 | *** class Name from sm_x501if | |
130 | ***/ | |
131 | static bool getField_Issuer ( | |
132 | DecodedItem &item, | |
133 | unsigned index, // which occurrence (0 = first) | |
134 | uint32 &numFields, // RETURNED | |
135 | CssmOwnedData &fieldValue) // RETURNED | |
136 | { | |
137 | if(index != 0) { | |
138 | return false; | |
139 | } | |
140 | ||
141 | bool brtn; | |
427c49bc | 142 | |
b1ab9ed8 A |
143 | const DecodedCert &cert = dynamic_cast<const DecodedCert &>(item); |
144 | try { | |
145 | brtn = getField_RDN_NSS(cert.mCert.tbs.issuer, fieldValue); | |
146 | if(brtn) { | |
147 | numFields = 1; | |
148 | } | |
149 | } | |
150 | catch (...) { | |
151 | freeField_RDN(fieldValue); | |
152 | throw; | |
153 | } | |
154 | return brtn; | |
155 | } | |
156 | ||
157 | static void setField_Issuer ( | |
158 | DecodedItem &item, | |
159 | const CssmData &fieldValue) | |
160 | { | |
161 | DecodedCert &cert = dynamic_cast<DecodedCert &>(item); | |
162 | const CSSM_X509_NAME *cssmName = (const CSSM_X509_NAME *)fieldValue.Data; | |
163 | NSS_Name &nssName = cert.mCert.tbs.issuer; | |
164 | tbsSetCheck(nssName.rdns, fieldValue, sizeof(CSSM_X509_NAME), | |
165 | "IssuerName"); | |
166 | CL_cssmNameToNss(*cssmName, nssName, cert.coder()); | |
167 | } | |
168 | ||
169 | /*** subject ***/ | |
170 | static bool getField_Subject ( | |
171 | DecodedItem &item, | |
172 | unsigned index, // which occurrence (0 = first) | |
173 | uint32 &numFields, // RETURNED | |
174 | CssmOwnedData &fieldValue) // RETURNED | |
175 | { | |
176 | if(index != 0) { | |
177 | return false; | |
178 | } | |
179 | ||
180 | bool brtn; | |
427c49bc | 181 | |
b1ab9ed8 A |
182 | const DecodedCert &cert = dynamic_cast<const DecodedCert &>(item); |
183 | try { | |
184 | brtn = getField_RDN_NSS(cert.mCert.tbs.subject, fieldValue); | |
185 | if(brtn) { | |
186 | numFields = 1; | |
187 | } | |
188 | } | |
189 | catch (...) { | |
190 | freeField_RDN(fieldValue); | |
191 | throw; | |
192 | } | |
193 | return brtn; | |
194 | } | |
195 | ||
196 | static void setField_Subject ( | |
197 | DecodedItem &item, | |
198 | const CssmData &fieldValue) | |
199 | { | |
200 | DecodedCert &cert = dynamic_cast<DecodedCert &>(item); | |
201 | const CSSM_X509_NAME *cssmName = (const CSSM_X509_NAME *)fieldValue.Data; | |
202 | NSS_Name &nssName = cert.mCert.tbs.subject; | |
203 | tbsSetCheck(nssName.rdns, fieldValue, sizeof(CSSM_X509_NAME), | |
204 | "SubjectName"); | |
205 | CL_cssmNameToNss(*cssmName, nssName, cert.coder()); | |
206 | } | |
207 | ||
208 | /*** | |
209 | *** Issuer Name, Subject Name (normalized and encoded version) | |
210 | *** Format = CSSM_DATA containing the DER encoding of the normalized name | |
211 | ***/ | |
212 | static bool getFieldSubjectNorm( | |
213 | DecodedItem &item, | |
214 | unsigned index, // which occurrence (0 = first) | |
215 | uint32 &numFields, // RETURNED | |
216 | CssmOwnedData &fieldValue) // RETURNED | |
217 | { | |
218 | if(index != 0) { | |
219 | return false; | |
220 | } | |
221 | const DecodedCert &cert = dynamic_cast<const DecodedCert &>(item); | |
427c49bc | 222 | return getField_normRDN_NSS(cert.mCert.tbs.derSubject, numFields, |
b1ab9ed8 A |
223 | fieldValue); |
224 | } | |
225 | ||
226 | static bool getFieldIssuerNorm( | |
227 | DecodedItem &item, | |
228 | unsigned index, // which occurrence (0 = first) | |
229 | uint32 &numFields, // RETURNED | |
230 | CssmOwnedData &fieldValue) // RETURNED | |
231 | { | |
232 | if(index != 0) { | |
233 | return false; | |
234 | } | |
235 | const DecodedCert &cert = dynamic_cast<const DecodedCert &>(item); | |
236 | return getField_normRDN_NSS(cert.mCert.tbs.derIssuer, numFields, fieldValue); | |
237 | } | |
238 | ||
239 | /*** | |
240 | *** Issuer Name, Subject Name (encoded, NON-normalized version) | |
241 | *** Format = CSSM_DATA containing the DER encoding of the name | |
242 | ***/ | |
243 | static bool getFieldSubjectStd( | |
244 | DecodedItem &item, | |
245 | unsigned index, // which occurrence (0 = first) | |
246 | uint32 &numFields, // RETURNED | |
247 | CssmOwnedData &fieldValue) // RETURNED | |
248 | { | |
249 | if(index != 0) { | |
250 | return false; | |
251 | } | |
252 | const DecodedCert &cert = dynamic_cast<const DecodedCert &>(item); | |
253 | fieldValue.copy(cert.mCert.tbs.derSubject); | |
254 | numFields = 1; | |
255 | return true; | |
256 | } | |
257 | ||
258 | static bool getFieldIssuerStd( | |
259 | DecodedItem &item, | |
260 | unsigned index, // which occurrence (0 = first) | |
261 | uint32 &numFields, // RETURNED | |
262 | CssmOwnedData &fieldValue) // RETURNED | |
263 | { | |
264 | if(index != 0) { | |
265 | return false; | |
266 | } | |
267 | const DecodedCert &cert = dynamic_cast<const DecodedCert &>(item); | |
268 | fieldValue.copy(cert.mCert.tbs.derIssuer); | |
269 | numFields = 1; | |
270 | return true; | |
271 | } | |
272 | ||
273 | /*** | |
274 | *** TBS AlgId, Signature AlgId | |
275 | *** Format = CSSM_X509_ALGORITHM_IDENTIFIER | |
276 | ***/ | |
277 | /* TBS AlgId */ | |
278 | static bool getField_TbsAlgId ( | |
279 | DecodedItem &item, | |
280 | unsigned index, // which occurrence (0 = first) | |
281 | uint32 &numFields, // RETURNED | |
282 | CssmOwnedData &fieldValue) // RETURNED | |
283 | { | |
284 | const DecodedCert &cert = dynamic_cast<const DecodedCert &>(item); | |
285 | const CSSM_X509_ALGORITHM_IDENTIFIER &srcAlgId = cert.mCert.tbs.signature; | |
286 | if(!tbsGetCheck(srcAlgId.algorithm.Data, index)) { | |
287 | return false; | |
288 | } | |
289 | getField_AlgIdNSS(srcAlgId, fieldValue); | |
290 | numFields = 1; | |
291 | return true; | |
292 | } | |
293 | ||
294 | static void setField_TbsAlgId ( | |
295 | DecodedItem &item, | |
296 | const CssmData &fieldValue) | |
297 | { | |
298 | DecodedCert &cert = dynamic_cast<DecodedCert &>(item); | |
299 | CSSM_X509_ALGORITHM_IDENTIFIER &dstAlgId = cert.mCert.tbs.signature; | |
427c49bc | 300 | tbsSetCheck(dstAlgId.algorithm.Data, fieldValue, |
b1ab9ed8 A |
301 | sizeof(CSSM_X509_ALGORITHM_IDENTIFIER), "TBS_AlgId"); |
302 | setField_AlgIdNSS(fieldValue, dstAlgId, cert.coder()); | |
303 | } | |
304 | ||
305 | /* Cert AlgId - read only */ | |
306 | static bool getField_CertAlgId ( | |
307 | DecodedItem &item, | |
308 | unsigned index, // which occurrence (0 = first) | |
309 | uint32 &numFields, // RETURNED | |
310 | CssmOwnedData &fieldValue) // RETURNED | |
311 | { | |
312 | const DecodedCert &cert = dynamic_cast<const DecodedCert &>(item); | |
313 | const CSSM_X509_ALGORITHM_IDENTIFIER &srcAlgId = cert.mCert.signatureAlgorithm; | |
314 | if(!tbsGetCheck(srcAlgId.algorithm.Data, index)) { | |
315 | return false; | |
316 | } | |
317 | getField_AlgIdNSS(srcAlgId, fieldValue); | |
318 | numFields = 1; | |
319 | return true; | |
320 | } | |
321 | ||
322 | /*** | |
323 | *** Validity not before, not after | |
324 | *** Format: CSSM_X509_TIME | |
325 | ***/ | |
326 | ||
327 | /*** not before ***/ | |
328 | static bool getField_NotBefore ( | |
329 | DecodedItem &item, | |
330 | unsigned index, // which occurrence (0 = first) | |
331 | uint32 &numFields, // RETURNED | |
332 | CssmOwnedData &fieldValue) // RETURNED | |
333 | { | |
334 | const DecodedCert &cert = dynamic_cast<const DecodedCert &>(item); | |
335 | const NSS_Time &srcTime = cert.mCert.tbs.validity.notBefore; | |
336 | return getField_TimeNSS(srcTime, index, numFields, fieldValue); | |
337 | } | |
338 | ||
339 | static void setField_NotBefore ( | |
340 | DecodedItem &item, | |
341 | const CssmData &fieldValue) | |
342 | { | |
343 | DecodedCert &cert = dynamic_cast<DecodedCert &>(item); | |
344 | NSS_Time &dstTime = cert.mCert.tbs.validity.notBefore; | |
427c49bc | 345 | tbsSetCheck(dstTime.item.Data, fieldValue, |
b1ab9ed8 A |
346 | sizeof(CSSM_X509_TIME), "NotBefore"); |
347 | setField_TimeNSS(fieldValue, dstTime, cert.coder()); | |
348 | } | |
349 | ||
350 | /*** not after ***/ | |
351 | static bool getField_NotAfter ( | |
352 | DecodedItem &item, | |
353 | unsigned index, // which occurrence (0 = first) | |
354 | uint32 &numFields, // RETURNED | |
355 | CssmOwnedData &fieldValue) // RETURNED | |
356 | { | |
357 | const DecodedCert &cert = dynamic_cast<const DecodedCert &>(item); | |
358 | const NSS_Time &srcTime = cert.mCert.tbs.validity.notAfter; | |
359 | return getField_TimeNSS(srcTime, index, numFields, fieldValue); | |
360 | } | |
361 | ||
362 | static void setField_NotAfter ( | |
363 | DecodedItem &item, | |
364 | const CssmData &fieldValue) | |
365 | { | |
366 | DecodedCert &cert = dynamic_cast<DecodedCert &>(item); | |
367 | NSS_Time &dstTime = cert.mCert.tbs.validity.notAfter; | |
427c49bc | 368 | tbsSetCheck(dstTime.item.Data, fieldValue, |
b1ab9ed8 A |
369 | sizeof(CSSM_X509_TIME), "NotAfter"); |
370 | setField_TimeNSS(fieldValue, dstTime, cert.coder()); | |
371 | } | |
372 | ||
373 | /*** | |
374 | *** Subject/issuer unique ID | |
375 | *** Format: Raw bytes. It's stored in the cert as an ASN bit string; the decoded | |
427c49bc | 376 | *** bytes are present at this level (i.e., not tag and length in the bytes). |
b1ab9ed8 A |
377 | *** NOTE: this is not quite accurate in that we only provide byte-aligned size, |
378 | *** not bit-aligned. This field is rarely if ever used so I think it's O, but | |
379 | *** beware. | |
380 | ***/ | |
381 | static bool getField_SubjectUniqueId ( | |
382 | DecodedItem &item, | |
383 | unsigned index, // which occurrence (0 = first) | |
384 | uint32 &numFields, // RETURNED | |
385 | CssmOwnedData &fieldValue) // RETURNED | |
386 | { | |
387 | const DecodedCert &cert = dynamic_cast<const DecodedCert &>(item); | |
388 | const CSSM_DATA &srcBits = cert.mCert.tbs.subjectID; | |
389 | if(!tbsGetCheck(srcBits.Data, index)) { | |
390 | return false; | |
391 | } | |
392 | ||
393 | /* That CSSM_DATA is a decoded BITSTRING; its length is in bits */ | |
394 | CSSM_DATA tmp = srcBits; | |
395 | tmp.Length = (tmp.Length + 7) / 8; | |
396 | fieldValue.copy(tmp.Data, tmp.Length); | |
397 | numFields = 1; | |
398 | return true; | |
399 | } | |
400 | ||
401 | static void setField_SubjectUniqueId ( | |
402 | DecodedItem &item, | |
403 | const CssmData &fieldValue) | |
404 | { | |
405 | DecodedCert &cert = dynamic_cast<DecodedCert &>(item); | |
406 | CSSM_DATA &dstBits = cert.mCert.tbs.subjectID; | |
407 | tbsSetCheck(dstBits.Data, fieldValue, 0, "SubjectUniqueID"); | |
408 | cert.coder().allocCopyItem(fieldValue, dstBits); | |
409 | dstBits.Length *= 8; | |
410 | } | |
411 | ||
412 | static bool getField_IssuerUniqueId ( | |
413 | DecodedItem &item, | |
414 | unsigned index, // which occurrence (0 = first) | |
415 | uint32 &numFields, // RETURNED | |
416 | CssmOwnedData &fieldValue) // RETURNED | |
417 | { | |
418 | const DecodedCert &cert = dynamic_cast<const DecodedCert &>(item); | |
419 | const CSSM_DATA &srcBits = cert.mCert.tbs.issuerID; | |
420 | if(!tbsGetCheck(srcBits.Data, index)) { | |
421 | return false; | |
422 | } | |
423 | ||
424 | /* That CSSM_DATA is a decoded BITSTRING; its length is in bits */ | |
425 | CSSM_DATA tmp = srcBits; | |
426 | tmp.Length = (tmp.Length + 7) / 8; | |
427 | fieldValue.copy(tmp.Data, tmp.Length); | |
428 | numFields = 1; | |
429 | return true; | |
430 | } | |
431 | ||
432 | static void setField_IssuerUniqueId ( | |
433 | DecodedItem &item, | |
434 | const CssmData &fieldValue) | |
435 | { | |
436 | DecodedCert &cert = dynamic_cast<DecodedCert &>(item); | |
437 | CSSM_DATA &dstBits = cert.mCert.tbs.issuerID; | |
438 | tbsSetCheck(dstBits.Data, fieldValue, 0, "IssuerUniqueID"); | |
439 | cert.coder().allocCopyItem(fieldValue, dstBits); | |
440 | dstBits.Length *= 8; | |
441 | } | |
442 | ||
443 | /*** | |
444 | *** Public key info | |
445 | *** Format = CSSM_X509_SUBJECT_PUBLIC_KEY_INFO | |
446 | ***/ | |
447 | static bool getField_PublicKeyInfo ( | |
448 | DecodedItem &item, | |
449 | unsigned index, // which occurrence (0 = first) | |
450 | uint32 &numFields, // RETURNED | |
451 | CssmOwnedData &fieldValue) // RETURNED | |
452 | { | |
453 | const DecodedCert &cert = dynamic_cast<const DecodedCert &>(item); | |
427c49bc | 454 | const CSSM_X509_SUBJECT_PUBLIC_KEY_INFO &srcInfo = |
b1ab9ed8 A |
455 | cert.mCert.tbs.subjectPublicKeyInfo; |
456 | if(!tbsGetCheck(srcInfo.subjectPublicKey.Data, index)) { | |
457 | return false; | |
458 | } | |
459 | ||
460 | Allocator &alloc = fieldValue.allocator; | |
461 | fieldValue.malloc(sizeof(CSSM_X509_SUBJECT_PUBLIC_KEY_INFO)); | |
427c49bc | 462 | CSSM_X509_SUBJECT_PUBLIC_KEY_INFO *dstInfo = |
b1ab9ed8 | 463 | (CSSM_X509_SUBJECT_PUBLIC_KEY_INFO *)fieldValue.data(); |
427c49bc | 464 | |
b1ab9ed8 A |
465 | CL_copySubjPubKeyInfo(srcInfo, true, // length in bits here |
466 | *dstInfo, false, // length in bytes | |
467 | alloc); | |
468 | ||
469 | numFields = 1; | |
470 | return true; | |
471 | } | |
472 | ||
473 | static void setField_PublicKeyInfo ( | |
474 | DecodedItem &item, | |
475 | const CssmData &fieldValue) | |
476 | { | |
477 | DecodedCert &cert = dynamic_cast<DecodedCert &>(item); | |
427c49bc | 478 | CSSM_X509_SUBJECT_PUBLIC_KEY_INFO &dstKeyInfo = |
b1ab9ed8 | 479 | cert.mCert.tbs.subjectPublicKeyInfo; |
427c49bc | 480 | tbsSetCheck(dstKeyInfo.subjectPublicKey.Data, fieldValue, |
b1ab9ed8 | 481 | sizeof(CSSM_X509_SUBJECT_PUBLIC_KEY_INFO), "PubKeyInfo"); |
427c49bc A |
482 | |
483 | CSSM_X509_SUBJECT_PUBLIC_KEY_INFO *srcKeyInfo = | |
b1ab9ed8 A |
484 | (CSSM_X509_SUBJECT_PUBLIC_KEY_INFO *)fieldValue.Data; |
485 | if((srcKeyInfo->subjectPublicKey.Data == NULL) || | |
486 | (srcKeyInfo->subjectPublicKey.Length == 0)) { | |
487 | CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER); | |
488 | } | |
489 | ||
490 | ArenaAllocator arenaAlloc(cert.coder()); | |
491 | CL_copySubjPubKeyInfo(*srcKeyInfo, false, // length in bytes here | |
492 | dstKeyInfo, true, // length in bits | |
493 | arenaAlloc); | |
494 | } | |
495 | ||
496 | static void freeField_PublicKeyInfo ( | |
497 | CssmOwnedData &fieldValue) | |
498 | { | |
427c49bc | 499 | CSSM_X509_SUBJECT_PUBLIC_KEY_INFO *cssmKeyInfo = |
b1ab9ed8 A |
500 | (CSSM_X509_SUBJECT_PUBLIC_KEY_INFO *)fieldValue.data(); |
501 | if(cssmKeyInfo == NULL) { | |
502 | return; | |
503 | } | |
504 | Allocator &alloc = fieldValue.allocator; | |
505 | CL_freeCssmAlgId(&cssmKeyInfo->algorithm, alloc); | |
506 | alloc.free(cssmKeyInfo->subjectPublicKey.Data); | |
507 | memset(cssmKeyInfo, 0, sizeof(CSSM_X509_SUBJECT_PUBLIC_KEY_INFO));} | |
508 | ||
509 | /*** | |
510 | *** key info from CSSM_KEY | |
511 | *** Format = CSSM_KEY | |
512 | ***/ | |
513 | static bool getField_PublicKeyStruct ( | |
514 | DecodedItem &item, | |
515 | unsigned index, // which occurrence (0 = first) | |
516 | uint32 &numFields, // RETURNED | |
517 | CssmOwnedData &fieldValue) // RETURNED | |
518 | { | |
519 | const DecodedCert &cert = dynamic_cast<const DecodedCert &>(item); | |
520 | if(!tbsGetCheck(cert.mCert.tbs.subjectPublicKeyInfo.subjectPublicKey.Data, | |
521 | index)) { | |
522 | return false; | |
523 | } | |
524 | CSSM_KEY_PTR cssmKey = cert.extractCSSMKey(fieldValue.allocator); | |
525 | fieldValue.set(reinterpret_cast<uint8 *>(cssmKey), sizeof(CSSM_KEY)); | |
526 | numFields = 1; | |
527 | return true; | |
528 | } | |
529 | ||
530 | static void setField_PublicKeyStruct ( | |
531 | DecodedItem &item, | |
532 | const CssmData &fieldValue) | |
533 | { | |
534 | DecodedCert &cert = dynamic_cast<DecodedCert &>(item); | |
427c49bc | 535 | CSSM_X509_SUBJECT_PUBLIC_KEY_INFO &dstKeyInfo = |
b1ab9ed8 | 536 | cert.mCert.tbs.subjectPublicKeyInfo; |
427c49bc | 537 | tbsSetCheck(dstKeyInfo.subjectPublicKey.Data, fieldValue, |
b1ab9ed8 A |
538 | sizeof(CSSM_KEY), "PubKeyStruct"); |
539 | ||
540 | CSSM_KEY_PTR cssmKey = (CSSM_KEY_PTR)fieldValue.data(); | |
541 | if((cssmKey->KeyData.Data == NULL) || | |
542 | (cssmKey->KeyData.Data == 0)) { | |
543 | CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER); | |
544 | } | |
545 | CL_CSSMKeyToSubjPubKeyInfoNSS(*cssmKey, dstKeyInfo, cert.coder()); | |
546 | } | |
547 | ||
548 | static void freeField_PublicKeyStruct ( | |
549 | CssmOwnedData &fieldValue) | |
550 | { | |
551 | CSSM_KEY_PTR cssmKey = (CSSM_KEY_PTR)fieldValue.data(); | |
552 | CL_freeCSSMKey(cssmKey, fieldValue.allocator, false); | |
553 | } | |
554 | ||
555 | /*** | |
556 | *** Signature | |
557 | *** Format = raw bytes | |
558 | *** read-only | |
559 | ***/ | |
560 | static bool getField_Signature ( | |
561 | DecodedItem &item, | |
562 | unsigned index, // which occurrence (0 = first) | |
563 | uint32 &numFields, // RETURNED | |
564 | CssmOwnedData &fieldValue) // RETURNED | |
565 | { | |
566 | const DecodedCert &cert = dynamic_cast<const DecodedCert &>(item); | |
567 | const CSSM_DATA &sigBits = cert.mCert.signature; | |
568 | if(!tbsGetCheck(sigBits.Data, index)) { | |
569 | return false; | |
570 | } | |
571 | fieldValue.copy(sigBits.Data, (sigBits.Length + 7) / 8); | |
572 | numFields = 1; | |
573 | return true; | |
574 | } | |
575 | ||
576 | /*** | |
577 | *** end of field-specific triplets | |
578 | ***/ | |
427c49bc | 579 | |
b1ab9ed8 A |
580 | /* |
581 | * Table to map OID to {get,set,free}field | |
582 | */ | |
583 | typedef struct { | |
584 | const CSSM_OID *fieldId; | |
585 | getItemFieldFcn *getFcn; | |
586 | setItemFieldFcn *setFcn; | |
427c49bc | 587 | freeFieldFcn *freeFcn; // OPTIONAL - NULL means just free the |
b1ab9ed8 A |
588 | // top-level data |
589 | } oidToFieldFuncs; | |
590 | ||
591 | static const oidToFieldFuncs fieldFuncTable[] = { | |
427c49bc | 592 | { &CSSMOID_X509V1Version, |
b1ab9ed8 | 593 | &getField_Version, &setField_Version, NULL }, |
427c49bc | 594 | { &CSSMOID_X509V1SerialNumber, |
b1ab9ed8 | 595 | &getField_SerialNumber, &setField_SerialNumber, NULL }, |
427c49bc | 596 | { &CSSMOID_X509V1IssuerNameCStruct, |
b1ab9ed8 | 597 | &getField_Issuer, &setField_Issuer, &freeField_RDN }, |
427c49bc | 598 | { &CSSMOID_X509V1SubjectNameCStruct, |
b1ab9ed8 A |
599 | &getField_Subject, &setField_Subject, &freeField_RDN }, |
600 | { &CSSMOID_X509V1SignatureAlgorithmTBS, | |
601 | &getField_TbsAlgId, &setField_TbsAlgId, &freeField_AlgId }, | |
427c49bc | 602 | { &CSSMOID_X509V1SignatureAlgorithm, |
b1ab9ed8 A |
603 | &getField_CertAlgId, &setField_ReadOnly, &freeField_AlgId }, |
604 | { &CSSMOID_X509V1ValidityNotBefore, | |
605 | &getField_NotBefore, &setField_NotBefore, &freeField_Time }, | |
606 | { &CSSMOID_X509V1ValidityNotAfter, | |
607 | &getField_NotAfter, &setField_NotAfter, &freeField_Time }, | |
608 | { &CSSMOID_X509V1CertificateIssuerUniqueId, | |
609 | &getField_IssuerUniqueId, &setField_IssuerUniqueId, NULL }, | |
610 | { &CSSMOID_X509V1CertificateSubjectUniqueId, | |
611 | &getField_SubjectUniqueId, &setField_SubjectUniqueId, NULL }, | |
612 | { &CSSMOID_X509V1SubjectPublicKeyCStruct, | |
613 | &getField_PublicKeyInfo, &setField_PublicKeyInfo, &freeField_PublicKeyInfo }, | |
614 | { &CSSMOID_CSSMKeyStruct, | |
427c49bc | 615 | &getField_PublicKeyStruct, &setField_PublicKeyStruct, |
b1ab9ed8 A |
616 | &freeField_PublicKeyStruct }, |
617 | { &CSSMOID_X509V1Signature, | |
618 | &getField_Signature, &setField_ReadOnly, NULL }, | |
427c49bc | 619 | { &CSSMOID_X509V1IssuerName, |
b1ab9ed8 | 620 | getFieldIssuerNorm, &setField_ReadOnly, NULL }, |
427c49bc | 621 | { &CSSMOID_X509V1SubjectName, |
b1ab9ed8 | 622 | getFieldSubjectNorm, &setField_ReadOnly, NULL }, |
427c49bc | 623 | { &CSSMOID_X509V1IssuerNameStd, |
b1ab9ed8 | 624 | getFieldIssuerStd, &setField_ReadOnly, NULL }, |
427c49bc | 625 | { &CSSMOID_X509V1SubjectNameStd, |
b1ab9ed8 | 626 | getFieldSubjectStd, &setField_ReadOnly, NULL }, |
427c49bc A |
627 | |
628 | /* | |
629 | * Extensions, implemented in CLCertExtensions.cpp | |
b1ab9ed8 A |
630 | * When adding new ones, also add to: |
631 | * -- clOidToNssInfo() in CLFieldsCommon.cpp | |
632 | * -- get/set/free functions in CLCertExtensions.{cpp,h} | |
633 | */ | |
427c49bc | 634 | { &CSSMOID_KeyUsage, &getFieldKeyUsage, &setFieldKeyUsage, |
b1ab9ed8 | 635 | &freeFieldSimpleExtension }, |
427c49bc | 636 | { &CSSMOID_BasicConstraints, &getFieldBasicConstraints, |
b1ab9ed8 A |
637 | &setFieldBasicConstraints, &freeFieldSimpleExtension }, |
638 | { &CSSMOID_ExtendedKeyUsage, &getFieldExtKeyUsage, | |
639 | &setFieldExtKeyUsage, &freeFieldExtKeyUsage } , | |
640 | { &CSSMOID_SubjectKeyIdentifier, &getFieldSubjectKeyId, | |
641 | &setFieldSubjectKeyId, &freeFieldSubjectKeyId } , | |
642 | { &CSSMOID_AuthorityKeyIdentifier, &getFieldAuthorityKeyId, | |
643 | &setFieldAuthorityKeyId, &freeFieldAuthorityKeyId } , | |
644 | { &CSSMOID_SubjectAltName, &getFieldSubjAltName, | |
645 | &setFieldSubjIssuerAltName, &freeFieldSubjIssuerAltName } , | |
646 | { &CSSMOID_IssuerAltName, &getFieldIssuerAltName, | |
647 | &setFieldSubjIssuerAltName, &freeFieldSubjIssuerAltName } , | |
648 | { &CSSMOID_CertificatePolicies, &getFieldCertPolicies, | |
649 | &setFieldCertPolicies, &freeFieldCertPolicies } , | |
650 | { &CSSMOID_NetscapeCertType, &getFieldNetscapeCertType, | |
651 | &setFieldNetscapeCertType, &freeFieldSimpleExtension } , | |
652 | { &CSSMOID_CrlDistributionPoints, &getFieldCrlDistPoints, | |
653 | &setFieldCrlDistPoints, &freeFieldCrlDistPoints }, | |
654 | { &CSSMOID_X509V3CertificateExtensionCStruct, &getFieldUnknownExt, | |
655 | &setFieldUnknownExt, &freeFieldUnknownExt }, | |
656 | { &CSSMOID_AuthorityInfoAccess, &getFieldAuthInfoAccess, | |
657 | &setFieldAuthInfoAccess, &freeFieldInfoAccess }, | |
658 | { &CSSMOID_SubjectInfoAccess, &getFieldSubjInfoAccess, | |
659 | &setFieldAuthInfoAccess, &freeFieldInfoAccess }, | |
660 | { &CSSMOID_QC_Statements, &getFieldQualCertStatements, | |
661 | &setFieldQualCertStatements, &freeFieldQualCertStatements }, | |
662 | ||
663 | { &CSSMOID_NameConstraints, &getFieldNameConstraints, | |
664 | &setFieldNameConstraints, &freeFieldNameConstraints }, | |
665 | { &CSSMOID_PolicyMappings, &getFieldPolicyMappings, | |
666 | &setFieldPolicyMappings, &freeFieldPolicyMappings }, | |
667 | { &CSSMOID_PolicyConstraints, &getFieldPolicyConstraints, | |
668 | &setFieldPolicyConstraints, &freeFieldPolicyConstraints }, | |
669 | { &CSSMOID_InhibitAnyPolicy, &getFieldInhibitAnyPolicy, | |
670 | &setFieldInhibitAnyPolicy, &freeFieldSimpleExtension }, | |
671 | ||
672 | }; | |
673 | ||
674 | #define NUM_KNOWN_FIELDS (sizeof(fieldFuncTable) / sizeof(oidToFieldFuncs)) | |
675 | #define NUM_STD_CERT_FIELDS 17 /* not including extensions */ | |
676 | ||
677 | /* map an OID to an oidToFieldFuncs */ | |
678 | static const oidToFieldFuncs *oidToFields( | |
679 | const CssmOid &fieldId) | |
680 | { | |
681 | const oidToFieldFuncs *fieldTable = fieldFuncTable; | |
682 | for(unsigned i=0; i<NUM_KNOWN_FIELDS; i++) { | |
683 | if(fieldId == CssmData::overlay(*fieldTable->fieldId)) { | |
684 | return fieldTable; | |
685 | } | |
686 | fieldTable++; | |
687 | } | |
427c49bc A |
688 | #ifndef NDEBUG |
689 | clErrorLog("oidToFields: unknown OID (len=%d): %s\n", | |
690 | (int)fieldId.length(), fieldId.toHex().c_str()); | |
691 | #endif | |
b1ab9ed8 A |
692 | CssmError::throwMe(CSSMERR_CL_UNKNOWN_TAG); |
693 | } | |
694 | ||
695 | ||
696 | /*** | |
697 | *** Public functions | |
698 | ***/ | |
699 | ||
427c49bc | 700 | /* |
b1ab9ed8 A |
701 | * Obtain the index'th occurrence of field specified by fieldId in specified cert. |
702 | * Format of the returned field depends on fieldId. | |
703 | * Returns total number of fieldId fields in the cert if index is 0. | |
427c49bc A |
704 | * FieldValue assumed to be empty on entry. |
705 | * Returns true if specified field was found, else returns false. | |
b1ab9ed8 A |
706 | */ |
707 | bool DecodedCert::getCertFieldData( | |
708 | const CssmOid &fieldId, // which field | |
709 | unsigned index, // which occurrence (0 = first) | |
710 | uint32 &numFields, // RETURNED | |
711 | CssmOwnedData &fieldValue) // RETURNED | |
427c49bc | 712 | { |
b1ab9ed8 | 713 | switch(mState) { |
427c49bc A |
714 | case IS_Empty: |
715 | case IS_Building: | |
b1ab9ed8 A |
716 | clErrorLog("DecodedCert::getCertField: can't parse undecoded cert!"); |
717 | CssmError::throwMe(CSSMERR_CL_INTERNAL_ERROR); | |
718 | case IS_DecodedAll: | |
719 | case IS_DecodedTBS: | |
720 | break; | |
721 | } | |
722 | const oidToFieldFuncs *fieldFuncs = oidToFields(fieldId); | |
723 | return fieldFuncs->getFcn(*this, index, numFields, fieldValue); | |
724 | } | |
427c49bc | 725 | |
b1ab9ed8 | 726 | /* |
427c49bc | 727 | * Set the field specified by fieldId in the specified Cert. |
b1ab9ed8 | 728 | * Note no index - individual field routines either append (for extensions) |
427c49bc | 729 | * or if field already set ::throwMe(for all others) |
b1ab9ed8 A |
730 | */ |
731 | void DecodedCert::setCertField( | |
732 | const CssmOid &fieldId, // which field | |
427c49bc | 733 | const CssmData &fieldValue) |
b1ab9ed8 A |
734 | { |
735 | switch(mState) { | |
736 | case IS_Empty: // first time thru | |
737 | mState = IS_Building; | |
738 | break; | |
739 | case IS_Building: // subsequent passes | |
740 | break; | |
741 | case IS_DecodedAll: | |
742 | case IS_DecodedTBS: | |
743 | clErrorLog("DecodedCert::setCertField: can't build on a decoded cert!"); | |
744 | CssmError::throwMe(CSSMERR_CL_INTERNAL_ERROR); | |
745 | } | |
746 | if((fieldValue.data() == NULL) || (fieldValue.length() == 0)) { | |
747 | CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER); | |
748 | } | |
749 | const oidToFieldFuncs *fieldFuncs = oidToFields(fieldId); | |
750 | const CssmData &value = CssmData::overlay(fieldValue); | |
751 | fieldFuncs->setFcn(*this, value); | |
752 | } | |
753 | ||
754 | /* | |
427c49bc | 755 | * Free the fieldId-specific data referred to by fieldValue->Data. |
b1ab9ed8 A |
756 | */ |
757 | void DecodedCert::freeCertFieldData( | |
758 | const CssmOid &fieldId, | |
759 | CssmOwnedData &fieldValue) | |
760 | { | |
761 | if((fieldValue.data() == NULL) || (fieldValue.length() == 0)) { | |
762 | CssmError::throwMe(CSSM_ERRCODE_INVALID_FIELD_POINTER); | |
763 | } | |
764 | const oidToFieldFuncs *fieldFuncs = oidToFields(fieldId); | |
765 | if(fieldFuncs->freeFcn != NULL) { | |
766 | /* optional - simple cases handled below */ | |
767 | fieldFuncs->freeFcn(fieldValue); | |
768 | } | |
769 | fieldValue.reset(); | |
770 | fieldValue.release(); | |
771 | ||
772 | } | |
773 | ||
774 | ||
775 | /* | |
427c49bc | 776 | * Common means to get all fields from a decoded cert. Used in |
b1ab9ed8 A |
777 | * CertGetAllTemplateFields and CertGetAllFields. |
778 | */ | |
779 | void DecodedCert::getAllParsedCertFields( | |
780 | uint32 &NumberOfFields, // RETURNED | |
781 | CSSM_FIELD_PTR &CertFields) // RETURNED | |
782 | { | |
783 | /* this is the max - some might be missing */ | |
784 | uint32 maxFields = NUM_STD_CERT_FIELDS + mDecodedExtensions.numExtensions(); | |
785 | CSSM_FIELD_PTR outFields = (CSSM_FIELD_PTR)mAlloc.malloc(maxFields * sizeof(CSSM_FIELD)); | |
427c49bc | 786 | |
b1ab9ed8 A |
787 | /* |
788 | * We'll be copying oids and values for fields we find into | |
789 | * outFields; current number of valid fields found in numOutFields. | |
790 | */ | |
791 | memset(outFields, 0, maxFields * sizeof(CSSM_FIELD)); | |
792 | uint32 numOutFields = 0; | |
793 | CSSM_FIELD_PTR currOutField; | |
794 | uint32 currOidDex; | |
795 | const CSSM_OID *currOid; | |
796 | CssmAutoData aData(mAlloc); // for malloc/copy of outgoing data | |
427c49bc | 797 | |
b1ab9ed8 A |
798 | /* query for each OID we know about */ |
799 | for(currOidDex=0; currOidDex<NUM_KNOWN_FIELDS; currOidDex++) { | |
800 | const oidToFieldFuncs *fieldFuncs = &fieldFuncTable[currOidDex]; | |
801 | currOid = fieldFuncs->fieldId; | |
802 | uint32 numFields; // for THIS oid | |
803 | ||
427c49bc A |
804 | /* |
805 | * Return false if field not there, which is not an error here. | |
b1ab9ed8 A |
806 | * Actual exceptions are fatal. |
807 | */ | |
427c49bc | 808 | if(!fieldFuncs->getFcn(*this, |
b1ab9ed8 | 809 | 0, // index - looking for first one |
427c49bc | 810 | numFields, |
b1ab9ed8 A |
811 | aData)) { |
812 | continue; | |
813 | } | |
427c49bc | 814 | |
b1ab9ed8 A |
815 | /* got some data for this oid - copy it and oid to outgoing CertFields */ |
816 | assert(numOutFields < maxFields); | |
817 | currOutField = &outFields[numOutFields]; | |
818 | currOutField->FieldValue = aData.release(); | |
819 | aData.copy(*currOid); | |
820 | currOutField->FieldOid = aData.release(); | |
821 | numOutFields++; | |
427c49bc | 822 | |
b1ab9ed8 A |
823 | /* if more fields are available for this OID, snag them too */ |
824 | for(uint32 fieldDex=1; fieldDex<numFields; fieldDex++) { | |
825 | /* note this should always succeed */ | |
826 | bool brtn = fieldFuncs->getFcn(*this, | |
427c49bc | 827 | fieldDex, |
b1ab9ed8 A |
828 | numFields, // shouldn't change |
829 | aData); | |
830 | if(!brtn) { | |
831 | clErrorLog("getAllParsedCertFields: index screwup"); | |
832 | CssmError::throwMe(CSSMERR_CL_INTERNAL_ERROR); | |
833 | } | |
834 | assert(numOutFields < maxFields); | |
835 | currOutField = &outFields[numOutFields]; | |
836 | currOutField->FieldValue = aData.release(); | |
837 | aData.copy(*currOid); | |
838 | currOutField->FieldOid = aData.release(); | |
839 | numOutFields++; | |
840 | } /* multiple fields for currOid */ | |
841 | } /* for each known OID */ | |
427c49bc | 842 | |
b1ab9ed8 A |
843 | NumberOfFields = numOutFields; |
844 | CertFields = outFields; | |
845 | } | |
846 | ||
847 | void | |
848 | DecodedCert::describeFormat( | |
849 | Allocator &alloc, | |
850 | uint32 &NumberOfFields, | |
851 | CSSM_OID_PTR &OidList) | |
852 | { | |
853 | /* malloc in app's space, do deep copy (including ->Data) */ | |
854 | CSSM_OID_PTR oidList = (CSSM_OID_PTR)alloc.malloc( | |
855 | NUM_KNOWN_FIELDS * sizeof(CSSM_OID)); | |
856 | memset(oidList, 0, NUM_KNOWN_FIELDS * sizeof(CSSM_OID)); | |
857 | for(unsigned i=0; i<NUM_KNOWN_FIELDS; i++) { | |
858 | CssmAutoData oidCopy(alloc, *fieldFuncTable[i].fieldId); | |
859 | oidList[i] = oidCopy.release(); | |
860 | } | |
861 | NumberOfFields = NUM_KNOWN_FIELDS; | |
862 | OidList = oidList; | |
863 | } |