]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_apple_x509_cl/lib/CLFieldsCommon.cpp
Security-59754.80.3.tar.gz
[apple/security.git] / OSX / libsecurity_apple_x509_cl / lib / CLFieldsCommon.cpp
1 /*
2 * Copyright (c) 2002-2011 Apple 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 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 * CLFieldsCommon.h - get/set/free routines common to certs and CRLs
21 */
22
23 #include "CLFieldsCommon.h"
24 #include "clNameUtils.h"
25 #include "clNssUtils.h"
26 #include "AppleX509CLSession.h"
27 #include <Security/cssmapple.h>
28 #include <Security/oidscert.h>
29 #include <Security/nameTemplates.h>
30 #include <Security/certExtensionTemplates.h>
31 #include <Security/SecAsn1Templates.h>
32
33 /*
34 * Table to map an OID to the info needed to decode the
35 * associated extension
36 */
37 typedef struct {
38 const CSSM_OID &oid;
39 unsigned nssObjLen;
40 const SecAsn1Template *templ;
41 } NssExtenInfo;
42
43 static const NssExtenInfo nssExtenInfo[] = {
44 { CSSMOID_KeyUsage,
45 sizeof(CSSM_DATA),
46 kSecAsn1KeyUsageTemplate },
47 { CSSMOID_BasicConstraints,
48 sizeof(NSS_BasicConstraints),
49 kSecAsn1BasicConstraintsTemplate },
50 { CSSMOID_ExtendedKeyUsage,
51 sizeof(NSS_ExtKeyUsage),
52 kSecAsn1ExtKeyUsageTemplate },
53 { CSSMOID_SubjectKeyIdentifier,
54 sizeof(CSSM_DATA),
55 kSecAsn1SubjectKeyIdTemplate },
56 { CSSMOID_AuthorityKeyIdentifier,
57 sizeof(NSS_AuthorityKeyId),
58 kSecAsn1AuthorityKeyIdTemplate },
59 { CSSMOID_SubjectAltName,
60 sizeof(NSS_GeneralNames),
61 kSecAsn1GeneralNamesTemplate },
62 { CSSMOID_IssuerAltName,
63 sizeof(NSS_GeneralNames),
64 kSecAsn1GeneralNamesTemplate },
65 { CSSMOID_CertificatePolicies,
66 sizeof(NSS_CertPolicies),
67 kSecAsn1CertPoliciesTemplate },
68 { CSSMOID_NetscapeCertType,
69 sizeof(CSSM_DATA),
70 kSecAsn1NetscapeCertTypeTemplate },
71 { CSSMOID_CrlDistributionPoints,
72 sizeof(NSS_CRLDistributionPoints),
73 kSecAsn1CRLDistributionPointsTemplate },
74 { CSSMOID_CertIssuer,
75 sizeof(NSS_GeneralNames),
76 kSecAsn1GeneralNamesTemplate },
77 { CSSMOID_AuthorityInfoAccess,
78 sizeof(NSS_AuthorityInfoAccess),
79 kSecAsn1AuthorityInfoAccessTemplate },
80 { CSSMOID_SubjectInfoAccess,
81 sizeof(NSS_AuthorityInfoAccess),
82 kSecAsn1AuthorityInfoAccessTemplate },
83 /* CRL extensions */
84 { CSSMOID_CrlNumber,
85 sizeof(CSSM_DATA),
86 kSecAsn1IntegerTemplate },
87 { CSSMOID_IssuingDistributionPoint,
88 sizeof(NSS_IssuingDistributionPoint),
89 kSecAsn1IssuingDistributionPointTemplate },
90 { CSSMOID_HoldInstructionCode,
91 sizeof(CSSM_OID),
92 kSecAsn1ObjectIDTemplate },
93 { CSSMOID_CrlReason,
94 sizeof(CSSM_DATA),
95 kSecAsn1EnumeratedTemplate },
96 { CSSMOID_DeltaCrlIndicator,
97 sizeof(CSSM_DATA),
98 kSecAsn1IntegerTemplate },
99 { CSSMOID_InvalidityDate,
100 sizeof(CSSM_DATA),
101 kSecAsn1GeneralizedTimeTemplate },
102 { CSSMOID_QC_Statements,
103 sizeof(NSS_QC_Statements),
104 kSecAsn1QC_StatementsTemplate },
105 { CSSMOID_NameConstraints,
106 sizeof(NSS_NameConstraints),
107 kSecAsn1NameConstraintsTemplate },
108 { CSSMOID_PolicyMappings,
109 sizeof(NSS_PolicyMappings),
110 kSecAsn1PolicyMappingsTemplate },
111 { CSSMOID_PolicyConstraints,
112 sizeof(NSS_PolicyConstraints),
113 kSecAsn1PolicyConstraintsTemplate },
114 { CSSMOID_InhibitAnyPolicy,
115 sizeof(CSSM_DATA),
116 kSecAsn1IntegerTemplate },
117 };
118
119 #define NUM_NSS_EXTEN_INFOS (sizeof(nssExtenInfo) / sizeof(nssExtenInfo[0]))
120
121 /*
122 * Returns true if we find the OID.
123 */
124 bool clOidToNssInfo(
125 const CSSM_OID &oid,
126 unsigned &nssObjLen, // RETURNED
127 const SecAsn1Template *&templ) // RETURNED
128 {
129 for(unsigned dex=0; dex<NUM_NSS_EXTEN_INFOS; dex++) {
130 const NssExtenInfo &info = nssExtenInfo[dex];
131 if(clCompareCssmData(&info.oid, &oid)) {
132 nssObjLen = info.nssObjLen;
133 templ = info.templ;
134 return true;
135 }
136 }
137 return false;
138 }
139
140
141
142 /*
143 * Common code to pass info from a DecodedExten back to app.
144 * Called from getField*().
145 */
146 void getFieldExtenCommon(
147 void *cdsaObj, // e.g. CE_KeyUsage
148 // NULL for berEncoded
149 const DecodedExten &decodedExt,
150 CssmOwnedData &fieldValue)
151 {
152 CSSM_X509_EXTENSION_PTR cssmExt;
153 Allocator &alloc = fieldValue.allocator;
154 CssmData &fdata = fieldValue.get();
155
156 cssmExt = (CSSM_X509_EXTENSION_PTR)alloc.
157 malloc(sizeof(CSSM_X509_EXTENSION));
158 fdata.Data = (uint8 *)cssmExt;
159 fdata.Length = sizeof(CSSM_X509_EXTENSION);
160 decodedExt.convertToCdsa(cdsaObj, cssmExt, alloc);
161 }
162
163 /*
164 * Common code for top of setField* and freeField*().
165 */
166 CSSM_X509_EXTENSION_PTR verifySetFreeExtension(
167 const CssmData &fieldValue,
168 bool berEncoded) // false: value in value.parsedValue
169 // true : value in BERValue
170 {
171 if(fieldValue.length() != sizeof(CSSM_X509_EXTENSION)) {
172 clFieldLog("Set/FreeExtension: bad length : exp %d got %d",
173 (int)sizeof(CSSM_X509_EXTENSION), (int)fieldValue.length());
174 CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER);
175 }
176 CSSM_X509_EXTENSION_PTR cssmExt =
177 reinterpret_cast<CSSM_X509_EXTENSION_PTR>(fieldValue.data());
178 if(berEncoded) {
179 if(cssmExt->BERvalue.Data == NULL) {
180 CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER);
181 }
182 }
183 else {
184 if(cssmExt->value.parsedValue == NULL) {
185 CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER);
186 }
187 }
188 return cssmExt;
189 }
190
191 /*
192 * Common free code for all extensions. Extension-specific code must
193 * free anything beyond cdsaExt->Value.parsedValue, then we free everything
194 * else (except the extension struct itself, which is freed by
195 * DecodedCert::freeCertFieldData()).
196 * The value union may contain a parsed value, or a CSSM_X509EXT_TAGandVALUE;
197 * wed ont' care, we just free it.
198 */
199 void freeFieldExtenCommon(
200 CSSM_X509_EXTENSION_PTR exten,
201 Allocator &alloc)
202 {
203 alloc.free(exten->extnId.Data);
204 alloc.free(exten->BERvalue.Data); // may be NULL
205 alloc.free(exten->value.parsedValue); // may be NULL
206 }
207
208 /*
209 * One common free for extensions whose parsed value doesn't go any deeper
210 * than cssmExt->value.parsedValue.
211 */
212 void freeFieldSimpleExtension (
213 CssmOwnedData &fieldValue)
214 {
215 CSSM_X509_EXTENSION_PTR cssmExt = verifySetFreeExtension(fieldValue,
216 false);
217 freeFieldExtenCommon(cssmExt, fieldValue.allocator);
218 }
219
220
221 /***
222 *** Common code for get/set subject/issuer name (C struct version)
223 *** Format = CSSM_X509_NAME
224 *** class Name from sm_x501if
225 ***/
226 bool getField_RDN_NSS (
227 const NSS_Name &nssName,
228 CssmOwnedData &fieldValue) // RETURNED
229 {
230 /* alloc top-level CSSM_X509_NAME */
231 Allocator &alloc = fieldValue.allocator;
232 fieldValue.malloc(sizeof(CSSM_X509_NAME));
233 CSSM_X509_NAME_PTR cssmName = (CSSM_X509_NAME_PTR)fieldValue.data();
234
235 CL_nssNameToCssm(nssName, *cssmName, alloc);
236 return true;
237 }
238
239 void freeField_RDN (
240 CssmOwnedData &fieldValue)
241 {
242 if(fieldValue.data() == NULL) {
243 return;
244 }
245 if(fieldValue.length() != sizeof(CSSM_X509_NAME)) {
246 CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER);
247 }
248 Allocator &alloc = fieldValue.allocator;
249 CSSM_X509_NAME_PTR x509Name = (CSSM_X509_NAME_PTR)fieldValue.data();
250 CL_freeX509Name(x509Name, alloc);
251
252 /* top-level x509Name pointer freed by freeCertFieldData() */
253 }
254
255 /***
256 *** Common code for Issuer Name, Subject Name (normalized and encoded
257 *** version)
258 *** Format = CSSM_DATA containing the DER encoding of the normalized name
259 ***/
260 bool getField_normRDN_NSS (
261 const CSSM_DATA &derName,
262 uint32 &numFields, // RETURNED (if successful, 0 or 1)
263 CssmOwnedData &fieldValue) // RETURNED
264 {
265 if(derName.Data == NULL) {
266 /* This can happen during CertGetAllTemplateFields() because
267 * the normalized fields are only set up during cert/CRL decode */
268 return false;
269 }
270
271 /*
272 * First make a temp decoded copy which we'll be manipulating.
273 */
274 SecNssCoder coder;
275 NSS_Name decodedName;
276
277 memset(&decodedName, 0, sizeof(decodedName));
278 PRErrorCode prtn = coder.decodeItem(derName, kSecAsn1NameTemplate, &decodedName);
279 if(prtn) {
280 /*
281 * Actually should never happen since this same bag of bits successfully
282 * decoded when the cert as a whole was decoded...
283 */
284 clErrorLog("getField_normRDN decode error\n");
285 CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
286
287 }
288
289 /* normalize */
290 CL_normalizeX509NameNSS(decodedName, coder);
291
292 /* encode result */
293 prtn = SecNssEncodeItemOdata(&decodedName, kSecAsn1NameTemplate, fieldValue);
294 if(prtn) {
295 clErrorLog("getField_normRDN encode error\n");
296 CssmError::throwMe(CSSMERR_CL_INTERNAL_ERROR);
297 }
298 numFields = 1;
299 return true;
300 }
301
302 /***
303 *** Common code for Time fields - Validity not before, Not After,
304 *** This Update, Next Update
305 *** Format: CSSM_X509_TIME
306 ***/
307 bool getField_TimeNSS (
308 const NSS_Time &nssTime,
309 unsigned index, // which occurrence (0 = first)
310 uint32 &numFields, // RETURNED
311 CssmOwnedData &fieldValue) // RETURNED
312 {
313 if(!tbsGetCheck(nssTime.item.Data, index)) {
314 return false;
315 }
316 Allocator &alloc = fieldValue.allocator;
317 fieldValue.malloc(sizeof(CSSM_X509_TIME));
318 CSSM_X509_TIME *cssmTime =
319 (CSSM_X509_TIME *)fieldValue.data();
320 if(CL_nssTimeToCssm(nssTime, *cssmTime, alloc)) {
321 numFields = 1;
322 return true;
323 }
324 else {
325 return false;
326 }
327 }
328
329 void setField_TimeNSS (
330 const CssmData &fieldValue,
331 NSS_Time &nssTime,
332 SecNssCoder &coder)
333 {
334 CSSM_X509_TIME *cssmTime =
335 (CSSM_X509_TIME *)fieldValue.data();
336 CL_cssmTimeToNss(*cssmTime, nssTime, coder);
337 }
338
339 void freeField_Time (
340 CssmOwnedData &fieldValue)
341 {
342 CSSM_X509_TIME *cssmTime = (CSSM_X509_TIME *)fieldValue.data();
343 if(cssmTime == NULL) {
344 return;
345 }
346 if(fieldValue.length() != sizeof(CSSM_X509_TIME)) {
347 CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER);
348 }
349 CL_freeCssmTime(cssmTime, fieldValue.allocator);
350 }
351
352 /***
353 *** TBS AlgId, Signature AlgId
354 *** Format = CSSM_X509_ALGORITHM_IDENTIFIER
355 ***/
356 void getField_AlgIdNSS (
357 const CSSM_X509_ALGORITHM_IDENTIFIER &srcAlgId,
358 CssmOwnedData &fieldValue) // RETURNED
359 {
360 Allocator &alloc = fieldValue.allocator;
361 fieldValue.malloc(sizeof(CSSM_X509_ALGORITHM_IDENTIFIER));
362 CSSM_X509_ALGORITHM_IDENTIFIER *destAlgId =
363 (CSSM_X509_ALGORITHM_IDENTIFIER *)fieldValue.data();
364 CL_copyAlgId(srcAlgId, *destAlgId, alloc);
365 }
366
367 void setField_AlgIdNSS (
368 const CssmData &fieldValue,
369 CSSM_X509_ALGORITHM_IDENTIFIER &dstAlgId,
370 SecNssCoder &coder)
371 {
372 CSSM_X509_ALGORITHM_IDENTIFIER *srcAlgId =
373 (CSSM_X509_ALGORITHM_IDENTIFIER *)fieldValue.data();
374 /* allocator for this coder */
375 ArenaAllocator areanAlloc(coder);
376 CL_copyAlgId(*srcAlgId, dstAlgId, areanAlloc);
377 }
378
379 void freeField_AlgId (
380 CssmOwnedData &fieldValue)
381 {
382 CSSM_X509_ALGORITHM_IDENTIFIER *cssmAlgId =
383 (CSSM_X509_ALGORITHM_IDENTIFIER *)fieldValue.data();
384 if(cssmAlgId == NULL) {
385 return;
386 }
387 if(fieldValue.length() != sizeof(CSSM_X509_ALGORITHM_IDENTIFIER)) {
388 CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER);
389 }
390 Allocator &alloc = fieldValue.allocator;
391 alloc.free(cssmAlgId->algorithm.Data);
392 alloc.free(cssmAlgId->parameters.Data);
393 memset(cssmAlgId, 0, sizeof(CSSM_X509_ALGORITHM_IDENTIFIER));
394 }
395
396 /*
397 * Routines for common validity checking for certificateToSign fields.
398 *
399 * Call from setField*: verify field isn't already set, optionally validate
400 * input length
401 */
402 void tbsSetCheck(
403 void *fieldToSet,
404 const CssmData &fieldValue,
405 uint32 expLength,
406 const char *op)
407 {
408 if(fieldToSet != NULL) {
409 /* can't add another */
410 clErrorLog("setField(%s): field already set", op);
411 CssmError::throwMe(CSSMERR_CL_INVALID_NUMBER_OF_FIELDS);
412 }
413 if((expLength != 0) && (fieldValue.length() != expLength)) {
414 clErrorLog("setField(%s): bad length : exp %d got %d",
415 op, (int)expLength, (int)fieldValue.length());
416 CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER);
417 }
418 }
419
420 /*
421 * Call from getField* for unique fields - detect missing field or
422 * index out of bounds.
423 */
424 bool tbsGetCheck(
425 const void *requiredField,
426 uint32 reqIndex)
427 {
428 if((requiredField == NULL) || (reqIndex != 0)) {
429 return false;
430 }
431 else {
432 return true;
433 }
434 }
435
436 /***
437 *** unknown extensions
438 *** CDSA format: raw bytes in a CSSM_DATA. This data is the BER-encoding of
439 *** some extension struct we don't know about.
440 *** NSS format CSSM_DATA
441 *** OID CSSMOID_X509V3CertificateExtensionCStruct
442 ***/
443
444 void setFieldUnknownExt(
445 DecodedItem &cert,
446 const CssmData &fieldValue)
447 {
448 CSSM_X509_EXTENSION_PTR cssmExt = verifySetFreeExtension(fieldValue, true);
449 SecNssCoder &coder = cert.coder();
450 CSSM_DATA *rawExtn = (CSSM_DATA *)coder.malloc(sizeof(CSSM_DATA));
451 coder.allocCopyItem(cssmExt->BERvalue, *rawExtn);
452 cert.addExtension(NULL, cssmExt->extnId, cssmExt->critical,
453 true, NULL /* no template */, rawExtn);
454 }
455
456 bool getFieldUnknownExt(
457 DecodedItem &cert,
458 unsigned index, // which occurrence (0 = first)
459 uint32 &numFields, // RETURNED
460 CssmOwnedData &fieldValue)
461 {
462 uint8 noOidDataLikeThis[2] = {1, 2}; // a dummy argument
463 CSSM_OID noOidLikeThis = {2, noOidDataLikeThis};
464 const DecodedExten *decodedExt =
465 cert.DecodedItem::findDecodedExt(noOidLikeThis,
466 true, index, numFields);
467 if(decodedExt == NULL) {
468 return false;
469 }
470 getFieldExtenCommon(NULL, *decodedExt, fieldValue);
471 return true;
472 }
473
474 void freeFieldUnknownExt (
475 CssmOwnedData &fieldValue)
476 {
477 CSSM_X509_EXTENSION_PTR cssmExt = verifySetFreeExtension(fieldValue, true);
478 Allocator &alloc = fieldValue.allocator;
479 freeFieldExtenCommon(cssmExt, alloc); // frees extnId, parsedValue, BERvalue
480 }
481
482 /* setField for read-only OIDs (i.e., the ones in cert/CRL, not TBS) */
483 void setField_ReadOnly (
484 DecodedItem &item,
485 const CssmData &fieldValue)
486 {
487 clErrorLog("Attempt to set a read-only field");
488 CssmError::throwMe(CSSMERR_CL_UNKNOWN_TAG);
489 }
490
491 bool getField_Unimplemented (
492 DecodedItem &item,
493 unsigned index, // which occurrence (0 = first)
494 uint32 &numFields, // RETURNED
495 CssmOwnedData &fieldValue) // RETURNED
496 {
497 clErrorLog("Attempt to get an unimplemented field");
498 CssmError::throwMe(CSSMERR_CL_UNKNOWN_TAG);
499 }
500
501
502