2 * Copyright (c) 2002 Apple Computer, 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 <SecurityNssAsn1/nameTemplates.h>
30 #include <SecurityNssAsn1/certExtensionTemplates.h>
33 * Table to map an OID to the info needed to decode the
34 * associated extension
39 const SEC_ASN1Template
*templ
;
42 static const NssExtenInfo nssExtenInfo
[] = {
45 NSS_KeyUsageTemplate
},
46 { CSSMOID_BasicConstraints
,
47 sizeof(NSS_BasicConstraints
),
48 NSS_BasicConstraintsTemplate
},
49 { CSSMOID_ExtendedKeyUsage
,
50 sizeof(NSS_ExtKeyUsage
),
51 NSS_ExtKeyUsageTemplate
},
52 { CSSMOID_SubjectKeyIdentifier
,
54 NSS_SubjectKeyIdTemplate
},
55 { CSSMOID_AuthorityKeyIdentifier
,
56 sizeof(NSS_AuthorityKeyId
),
57 NSS_AuthorityKeyIdTemplate
},
58 { CSSMOID_SubjectAltName
,
59 sizeof(NSS_GeneralNames
),
60 NSS_GeneralNamesTemplate
},
61 { CSSMOID_IssuerAltName
,
62 sizeof(NSS_GeneralNames
),
63 NSS_GeneralNamesTemplate
},
64 { CSSMOID_CertificatePolicies
,
65 sizeof(NSS_CertPolicies
),
66 NSS_CertPoliciesTemplate
},
67 { CSSMOID_NetscapeCertType
,
69 NSS_NetscapeCertTypeTemplate
},
70 { CSSMOID_CrlDistributionPoints
,
71 sizeof(NSS_CRLDistributionPoints
),
72 NSS_CRLDistributionPointsTemplate
},
74 sizeof(NSS_GeneralNames
),
75 NSS_GeneralNamesTemplate
},
79 SEC_IntegerTemplate
},
80 { CSSMOID_IssuingDistributionPoint
,
81 sizeof(NSS_IssuingDistributionPoint
),
82 NSS_IssuingDistributionPointTemplate
},
83 { CSSMOID_HoldInstructionCode
,
85 SEC_ObjectIDTemplate
},
88 SEC_EnumeratedTemplate
},
89 { CSSMOID_DeltaCrlIndicator
,
91 SEC_IntegerTemplate
},
92 { CSSMOID_InvalidityDate
,
94 SEC_GeneralizedTimeTemplate
}
97 #define NUM_NSS_EXTEN_INFOS (sizeof(nssExtenInfo) / sizeof(nssExtenInfo[0]))
100 * Returns true if we find the OID.
104 unsigned &nssObjLen
, // RETURNED
105 const SEC_ASN1Template
*&templ
) // RETURNED
107 for(unsigned dex
=0; dex
<NUM_NSS_EXTEN_INFOS
; dex
++) {
108 const NssExtenInfo
&info
= nssExtenInfo
[dex
];
109 if(clCompareCssmData(&info
.oid
, &oid
)) {
110 nssObjLen
= info
.nssObjLen
;
121 * Common code to pass info from a DecodedExten back to app.
122 * Called from getField*().
124 void getFieldExtenCommon(
125 void *cdsaObj
, // e.g. CE_KeyUsage
126 // NULL for berEncoded
127 const DecodedExten
&decodedExt
,
128 CssmOwnedData
&fieldValue
)
130 CSSM_X509_EXTENSION_PTR cssmExt
;
131 CssmAllocator
&alloc
= fieldValue
.allocator
;
132 CssmData
&fdata
= fieldValue
.get();
134 cssmExt
= (CSSM_X509_EXTENSION_PTR
)alloc
.
135 malloc(sizeof(CSSM_X509_EXTENSION
));
136 fdata
.Data
= (uint8
*)cssmExt
;
137 fdata
.Length
= sizeof(CSSM_X509_EXTENSION
);
138 decodedExt
.convertToCdsa(cdsaObj
, cssmExt
, alloc
);
142 * Common code for top of setField* and freeField*().
144 CSSM_X509_EXTENSION_PTR
verifySetFreeExtension(
145 const CssmData
&fieldValue
,
146 bool berEncoded
) // false: value in value.parsedValue
147 // true : value in BERValue
149 if(fieldValue
.length() != sizeof(CSSM_X509_EXTENSION
)) {
150 clFieldLog("Set/FreeExtension: bad length : exp %d got %d",
151 (int)sizeof(CSSM_X509_EXTENSION
), (int)fieldValue
.length());
152 CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER
);
154 CSSM_X509_EXTENSION_PTR cssmExt
=
155 reinterpret_cast<CSSM_X509_EXTENSION_PTR
>(fieldValue
.data());
157 if((cssmExt
->value
.parsedValue
!= NULL
) ||
158 (cssmExt
->BERvalue
.Data
== NULL
)) {
159 CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER
);
163 if(cssmExt
->value
.parsedValue
== NULL
) {
164 CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER
);
171 * Common free code for all extensions. Extension-specific code must
172 * free anything beyond cdsaExt->Value.parsedValue, then we free everything
173 * else (except the extension struct itself, which is freed by
174 * DecodedCert::freeCertFieldData()).
176 void freeFieldExtenCommon(
177 CSSM_X509_EXTENSION_PTR exten
,
178 CssmAllocator
&alloc
)
180 alloc
.free(exten
->extnId
.Data
);
181 alloc
.free(exten
->BERvalue
.Data
); // may be NULL
182 alloc
.free(exten
->value
.parsedValue
); // may be NULL
186 * One common free for extensions whose parsed value doesn't go any deeper
187 * than cssmExt->value.parsedValue.
189 void freeFieldSimpleExtension (
190 CssmOwnedData
&fieldValue
)
192 CSSM_X509_EXTENSION_PTR cssmExt
= verifySetFreeExtension(fieldValue
,
194 freeFieldExtenCommon(cssmExt
, fieldValue
.allocator
);
199 *** Common code for get/set subject/issuer name (C struct version)
200 *** Format = CSSM_X509_NAME
201 *** class Name from sm_x501if
203 bool getField_RDN_NSS (
204 const NSS_Name
&nssName
,
205 CssmOwnedData
&fieldValue
) // RETURNED
207 /* alloc top-level CSSM_X509_NAME */
208 CssmAllocator
&alloc
= fieldValue
.allocator
;
209 fieldValue
.malloc(sizeof(CSSM_X509_NAME
));
210 CSSM_X509_NAME_PTR cssmName
= (CSSM_X509_NAME_PTR
)fieldValue
.data();
212 CL_nssNameToCssm(nssName
, *cssmName
, alloc
);
217 CssmOwnedData
&fieldValue
)
219 if(fieldValue
.data() == NULL
) {
222 if(fieldValue
.length() != sizeof(CSSM_X509_NAME
)) {
223 CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER
);
225 CssmAllocator
&alloc
= fieldValue
.allocator
;
226 CSSM_X509_NAME_PTR x509Name
= (CSSM_X509_NAME_PTR
)fieldValue
.data();
227 CL_freeX509Name(x509Name
, alloc
);
229 /* top-level x509Name pointer freed by freeCertFieldData() */
233 *** Common code for Issuer Name, Subject Name (normalized and encoded
235 *** Format = CSSM_DATA containing the DER encoding of the normalized name
237 bool getField_normRDN_NSS (
238 const CSSM_DATA
&derName
,
239 uint32
&numFields
, // RETURNED (if successful, 0 or 1)
240 CssmOwnedData
&fieldValue
) // RETURNED
242 if(derName
.Data
== NULL
) {
243 /* This can happen during CertGetAllTemplateFields() because
244 * the normalized fields are only set up during cert/CRL decode */
249 * First make a temp decoded copy which we'll be manipulating.
252 NSS_Name decodedName
;
254 memset(&decodedName
, 0, sizeof(decodedName
));
255 PRErrorCode prtn
= coder
.decodeItem(derName
, NSS_NameTemplate
, &decodedName
);
258 * Actually should never happen since this same bag of bits successfully
259 * decoded when the cert as a whole was decoded...
261 clErrorLog("getField_normRDN decode error\n");
262 CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT
);
267 CL_normalizeX509NameNSS(decodedName
, coder
);
270 prtn
= SecNssEncodeItemOdata(&decodedName
, NSS_NameTemplate
, fieldValue
);
272 clErrorLog("getField_normRDN encode error\n");
273 CssmError::throwMe(CSSMERR_CL_INTERNAL_ERROR
);
280 *** Common code for Time fields - Validity not before, Not After,
281 *** This Update, Next Update
282 *** Format: CSSM_X509_TIME
284 bool getField_TimeNSS (
285 const NSS_Time
&nssTime
,
286 unsigned index
, // which occurrence (0 = first)
287 uint32
&numFields
, // RETURNED
288 CssmOwnedData
&fieldValue
) // RETURNED
290 if(!tbsGetCheck(nssTime
.item
.Data
, index
)) {
293 CssmAllocator
&alloc
= fieldValue
.allocator
;
294 fieldValue
.malloc(sizeof(CSSM_X509_TIME
));
295 CSSM_X509_TIME
*cssmTime
=
296 (CSSM_X509_TIME
*)fieldValue
.data();
297 if(CL_nssTimeToCssm(nssTime
, *cssmTime
, alloc
)) {
306 void setField_TimeNSS (
307 const CssmData
&fieldValue
,
311 CSSM_X509_TIME
*cssmTime
=
312 (CSSM_X509_TIME
*)fieldValue
.data();
313 CL_cssmTimeToNss(*cssmTime
, nssTime
, coder
);
316 void freeField_Time (
317 CssmOwnedData
&fieldValue
)
319 CSSM_X509_TIME
*cssmTime
= (CSSM_X509_TIME
*)fieldValue
.data();
320 if(cssmTime
== NULL
) {
323 if(fieldValue
.length() != sizeof(CSSM_X509_TIME
)) {
324 CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER
);
326 CL_freeCssmTime(cssmTime
, fieldValue
.allocator
);
330 *** TBS AlgId, Signature AlgId
331 *** Format = CSSM_X509_ALGORITHM_IDENTIFIER
333 void getField_AlgIdNSS (
334 const CSSM_X509_ALGORITHM_IDENTIFIER
&srcAlgId
,
335 CssmOwnedData
&fieldValue
) // RETURNED
337 CssmAllocator
&alloc
= fieldValue
.allocator
;
338 fieldValue
.malloc(sizeof(CSSM_X509_ALGORITHM_IDENTIFIER
));
339 CSSM_X509_ALGORITHM_IDENTIFIER
*destAlgId
=
340 (CSSM_X509_ALGORITHM_IDENTIFIER
*)fieldValue
.data();
341 CL_copyAlgId(srcAlgId
, *destAlgId
, alloc
);
344 void setField_AlgIdNSS (
345 const CssmData
&fieldValue
,
346 CSSM_X509_ALGORITHM_IDENTIFIER
&dstAlgId
,
349 CSSM_X509_ALGORITHM_IDENTIFIER
*srcAlgId
=
350 (CSSM_X509_ALGORITHM_IDENTIFIER
*)fieldValue
.data();
351 /* allocator for this coder */
352 ArenaAllocator
areanAlloc(coder
);
353 CL_copyAlgId(*srcAlgId
, dstAlgId
, areanAlloc
);
356 void freeField_AlgId (
357 CssmOwnedData
&fieldValue
)
359 CSSM_X509_ALGORITHM_IDENTIFIER
*cssmAlgId
=
360 (CSSM_X509_ALGORITHM_IDENTIFIER
*)fieldValue
.data();
361 if(cssmAlgId
== NULL
) {
364 if(fieldValue
.length() != sizeof(CSSM_X509_ALGORITHM_IDENTIFIER
)) {
365 CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER
);
367 CssmAllocator
&alloc
= fieldValue
.allocator
;
368 alloc
.free(cssmAlgId
->algorithm
.Data
);
369 alloc
.free(cssmAlgId
->parameters
.Data
);
370 memset(cssmAlgId
, 0, sizeof(CSSM_X509_ALGORITHM_IDENTIFIER
));
374 * Routines for common validity checking for certificateToSign fields.
376 * Call from setField*: verify field isn't already set, optionally validate
381 const CssmData
&fieldValue
,
385 if(fieldToSet
!= NULL
) {
386 /* can't add another */
387 clErrorLog("setField(%s): field already set", op
);
388 CssmError::throwMe(CSSMERR_CL_INVALID_NUMBER_OF_FIELDS
);
390 if((expLength
!= 0) && (fieldValue
.length() != expLength
)) {
391 clErrorLog("setField(%s): bad length : exp %d got %d",
392 op
, (int)expLength
, (int)fieldValue
.length());
393 CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER
);
398 * Call from getField* for unique fields - detect missing field or
399 * index out of bounds.
402 const void *requiredField
,
405 if((requiredField
== NULL
) || (reqIndex
!= 0)) {
414 *** unknown extensions
415 *** CDSA format: raw bytes in a CSSM_DATA. This data is the BER-encoding of
416 *** some extension struct we don't know about.
417 *** NSS format CSSM_DATA
418 *** OID CSSMOID_X509V3CertificateExtensionCStruct
421 void setFieldUnknownExt(
423 const CssmData
&fieldValue
)
425 CSSM_X509_EXTENSION_PTR cssmExt
= verifySetFreeExtension(fieldValue
, true);
426 SecNssCoder
&coder
= cert
.coder();
427 CSSM_DATA
*rawExtn
= (CSSM_DATA
*)coder
.malloc(sizeof(CSSM_DATA
));
428 coder
.allocCopyItem(cssmExt
->BERvalue
, *rawExtn
);
429 cert
.addExtension(NULL
, cssmExt
->extnId
, cssmExt
->critical
,
430 true, NULL
/* no template */, rawExtn
);
433 bool getFieldUnknownExt(
435 unsigned index
, // which occurrence (0 = first)
436 uint32
&numFields
, // RETURNED
437 CssmOwnedData
&fieldValue
)
439 uint8 noOidDataLikeThis
[2] = {1, 2}; // a dummy argument
440 CSSM_OID noOidLikeThis
= {2, noOidDataLikeThis
};
441 const DecodedExten
*decodedExt
=
442 cert
.DecodedItem::findDecodedExt(noOidLikeThis
,
443 true, index
, numFields
);
444 if(decodedExt
== NULL
) {
447 getFieldExtenCommon(NULL
, *decodedExt
, fieldValue
);
451 void freeFieldUnknownExt (
452 CssmOwnedData
&fieldValue
)
454 CSSM_X509_EXTENSION_PTR cssmExt
= verifySetFreeExtension(fieldValue
, true);
455 CssmAllocator
&alloc
= fieldValue
.allocator
;
456 freeFieldExtenCommon(cssmExt
, alloc
); // frees extnId, parsedValue, BERvalue
459 /* setField for read-only OIDs (i.e., the ones in cert/CRL, not TBS) */
460 void setField_ReadOnly (
462 const CssmData
&fieldValue
)
464 clErrorLog("Attempt to set a read-only field");
465 CssmError::throwMe(CSSMERR_CL_UNKNOWN_TAG
);
468 bool getField_Unimplemented (
470 unsigned index
, // which occurrence (0 = first)
471 uint32
&numFields
, // RETURNED
472 CssmOwnedData
&fieldValue
) // RETURNED
474 clErrorLog("Attempt to get an unimplemented field");
475 CssmError::throwMe(CSSMERR_CL_UNKNOWN_TAG
);