2 * Copyright (c) 2002-2011 Apple Inc. All Rights Reserved.
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
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.
20 * CLFieldsCommon.h - get/set/free routines common to certs and CRLs
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>
34 * Table to map an OID to the info needed to decode the
35 * associated extension
40 const SecAsn1Template
*templ
;
43 static const NssExtenInfo nssExtenInfo
[] = {
46 kSecAsn1KeyUsageTemplate
},
47 { CSSMOID_BasicConstraints
,
48 sizeof(NSS_BasicConstraints
),
49 kSecAsn1BasicConstraintsTemplate
},
50 { CSSMOID_ExtendedKeyUsage
,
51 sizeof(NSS_ExtKeyUsage
),
52 kSecAsn1ExtKeyUsageTemplate
},
53 { CSSMOID_SubjectKeyIdentifier
,
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
,
70 kSecAsn1NetscapeCertTypeTemplate
},
71 { CSSMOID_CrlDistributionPoints
,
72 sizeof(NSS_CRLDistributionPoints
),
73 kSecAsn1CRLDistributionPointsTemplate
},
75 sizeof(NSS_GeneralNames
),
76 kSecAsn1GeneralNamesTemplate
},
77 { CSSMOID_AuthorityInfoAccess
,
78 sizeof(NSS_AuthorityInfoAccess
),
79 kSecAsn1AuthorityInfoAccessTemplate
},
80 { CSSMOID_SubjectInfoAccess
,
81 sizeof(NSS_AuthorityInfoAccess
),
82 kSecAsn1AuthorityInfoAccessTemplate
},
86 kSecAsn1IntegerTemplate
},
87 { CSSMOID_IssuingDistributionPoint
,
88 sizeof(NSS_IssuingDistributionPoint
),
89 kSecAsn1IssuingDistributionPointTemplate
},
90 { CSSMOID_HoldInstructionCode
,
92 kSecAsn1ObjectIDTemplate
},
95 kSecAsn1EnumeratedTemplate
},
96 { CSSMOID_DeltaCrlIndicator
,
98 kSecAsn1IntegerTemplate
},
99 { CSSMOID_InvalidityDate
,
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
,
116 kSecAsn1IntegerTemplate
},
119 #define NUM_NSS_EXTEN_INFOS (sizeof(nssExtenInfo) / sizeof(nssExtenInfo[0]))
122 * Returns true if we find the OID.
126 unsigned &nssObjLen
, // RETURNED
127 const SecAsn1Template
*&templ
) // RETURNED
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
;
143 * Common code to pass info from a DecodedExten back to app.
144 * Called from getField*().
146 void getFieldExtenCommon(
147 void *cdsaObj
, // e.g. CE_KeyUsage
148 // NULL for berEncoded
149 const DecodedExten
&decodedExt
,
150 CssmOwnedData
&fieldValue
)
152 CSSM_X509_EXTENSION_PTR cssmExt
;
153 Allocator
&alloc
= fieldValue
.allocator
;
154 CssmData
&fdata
= fieldValue
.get();
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
);
164 * Common code for top of setField* and freeField*().
166 CSSM_X509_EXTENSION_PTR
verifySetFreeExtension(
167 const CssmData
&fieldValue
,
168 bool berEncoded
) // false: value in value.parsedValue
169 // true : value in BERValue
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
);
176 CSSM_X509_EXTENSION_PTR cssmExt
=
177 reinterpret_cast<CSSM_X509_EXTENSION_PTR
>(fieldValue
.data());
179 if(cssmExt
->BERvalue
.Data
== NULL
) {
180 CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER
);
184 if(cssmExt
->value
.parsedValue
== NULL
) {
185 CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER
);
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.
199 void freeFieldExtenCommon(
200 CSSM_X509_EXTENSION_PTR exten
,
203 alloc
.free(exten
->extnId
.Data
);
204 alloc
.free(exten
->BERvalue
.Data
); // may be NULL
205 alloc
.free(exten
->value
.parsedValue
); // may be NULL
209 * One common free for extensions whose parsed value doesn't go any deeper
210 * than cssmExt->value.parsedValue.
212 void freeFieldSimpleExtension (
213 CssmOwnedData
&fieldValue
)
215 CSSM_X509_EXTENSION_PTR cssmExt
= verifySetFreeExtension(fieldValue
,
217 freeFieldExtenCommon(cssmExt
, fieldValue
.allocator
);
222 *** Common code for get/set subject/issuer name (C struct version)
223 *** Format = CSSM_X509_NAME
224 *** class Name from sm_x501if
226 bool getField_RDN_NSS (
227 const NSS_Name
&nssName
,
228 CssmOwnedData
&fieldValue
) // RETURNED
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();
235 CL_nssNameToCssm(nssName
, *cssmName
, alloc
);
240 CssmOwnedData
&fieldValue
)
242 if(fieldValue
.data() == NULL
) {
245 if(fieldValue
.length() != sizeof(CSSM_X509_NAME
)) {
246 CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER
);
248 Allocator
&alloc
= fieldValue
.allocator
;
249 CSSM_X509_NAME_PTR x509Name
= (CSSM_X509_NAME_PTR
)fieldValue
.data();
250 CL_freeX509Name(x509Name
, alloc
);
252 /* top-level x509Name pointer freed by freeCertFieldData() */
256 *** Common code for Issuer Name, Subject Name (normalized and encoded
258 *** Format = CSSM_DATA containing the DER encoding of the normalized name
260 bool getField_normRDN_NSS (
261 const CSSM_DATA
&derName
,
262 uint32
&numFields
, // RETURNED (if successful, 0 or 1)
263 CssmOwnedData
&fieldValue
) // RETURNED
265 if(derName
.Data
== NULL
) {
266 /* This can happen during CertGetAllTemplateFields() because
267 * the normalized fields are only set up during cert/CRL decode */
272 * First make a temp decoded copy which we'll be manipulating.
275 NSS_Name decodedName
;
277 memset(&decodedName
, 0, sizeof(decodedName
));
278 PRErrorCode prtn
= coder
.decodeItem(derName
, kSecAsn1NameTemplate
, &decodedName
);
281 * Actually should never happen since this same bag of bits successfully
282 * decoded when the cert as a whole was decoded...
284 clErrorLog("getField_normRDN decode error\n");
285 CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT
);
290 CL_normalizeX509NameNSS(decodedName
, coder
);
293 prtn
= SecNssEncodeItemOdata(&decodedName
, kSecAsn1NameTemplate
, fieldValue
);
295 clErrorLog("getField_normRDN encode error\n");
296 CssmError::throwMe(CSSMERR_CL_INTERNAL_ERROR
);
303 *** Common code for Time fields - Validity not before, Not After,
304 *** This Update, Next Update
305 *** Format: CSSM_X509_TIME
307 bool getField_TimeNSS (
308 const NSS_Time
&nssTime
,
309 unsigned index
, // which occurrence (0 = first)
310 uint32
&numFields
, // RETURNED
311 CssmOwnedData
&fieldValue
) // RETURNED
313 if(!tbsGetCheck(nssTime
.item
.Data
, index
)) {
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
)) {
329 void setField_TimeNSS (
330 const CssmData
&fieldValue
,
334 CSSM_X509_TIME
*cssmTime
=
335 (CSSM_X509_TIME
*)fieldValue
.data();
336 CL_cssmTimeToNss(*cssmTime
, nssTime
, coder
);
339 void freeField_Time (
340 CssmOwnedData
&fieldValue
)
342 CSSM_X509_TIME
*cssmTime
= (CSSM_X509_TIME
*)fieldValue
.data();
343 if(cssmTime
== NULL
) {
346 if(fieldValue
.length() != sizeof(CSSM_X509_TIME
)) {
347 CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER
);
349 CL_freeCssmTime(cssmTime
, fieldValue
.allocator
);
353 *** TBS AlgId, Signature AlgId
354 *** Format = CSSM_X509_ALGORITHM_IDENTIFIER
356 void getField_AlgIdNSS (
357 const CSSM_X509_ALGORITHM_IDENTIFIER
&srcAlgId
,
358 CssmOwnedData
&fieldValue
) // RETURNED
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
);
367 void setField_AlgIdNSS (
368 const CssmData
&fieldValue
,
369 CSSM_X509_ALGORITHM_IDENTIFIER
&dstAlgId
,
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
);
379 void freeField_AlgId (
380 CssmOwnedData
&fieldValue
)
382 CSSM_X509_ALGORITHM_IDENTIFIER
*cssmAlgId
=
383 (CSSM_X509_ALGORITHM_IDENTIFIER
*)fieldValue
.data();
384 if(cssmAlgId
== NULL
) {
387 if(fieldValue
.length() != sizeof(CSSM_X509_ALGORITHM_IDENTIFIER
)) {
388 CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER
);
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
));
397 * Routines for common validity checking for certificateToSign fields.
399 * Call from setField*: verify field isn't already set, optionally validate
404 const CssmData
&fieldValue
,
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
);
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
);
421 * Call from getField* for unique fields - detect missing field or
422 * index out of bounds.
425 const void *requiredField
,
428 if((requiredField
== NULL
) || (reqIndex
!= 0)) {
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
444 void setFieldUnknownExt(
446 const CssmData
&fieldValue
)
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
);
456 bool getFieldUnknownExt(
458 unsigned index
, // which occurrence (0 = first)
459 uint32
&numFields
, // RETURNED
460 CssmOwnedData
&fieldValue
)
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
) {
470 getFieldExtenCommon(NULL
, *decodedExt
, fieldValue
);
474 void freeFieldUnknownExt (
475 CssmOwnedData
&fieldValue
)
477 CSSM_X509_EXTENSION_PTR cssmExt
= verifySetFreeExtension(fieldValue
, true);
478 Allocator
&alloc
= fieldValue
.allocator
;
479 freeFieldExtenCommon(cssmExt
, alloc
); // frees extnId, parsedValue, BERvalue
482 /* setField for read-only OIDs (i.e., the ones in cert/CRL, not TBS) */
483 void setField_ReadOnly (
485 const CssmData
&fieldValue
)
487 clErrorLog("Attempt to set a read-only field");
488 CssmError::throwMe(CSSMERR_CL_UNKNOWN_TAG
);
491 bool getField_Unimplemented (
493 unsigned index
, // which occurrence (0 = first)
494 uint32
&numFields
, // RETURNED
495 CssmOwnedData
&fieldValue
) // RETURNED
497 clErrorLog("Attempt to get an unimplemented field");
498 CssmError::throwMe(CSSMERR_CL_UNKNOWN_TAG
);