]> git.saurik.com Git - apple/security.git/blob - AppleX509CL/CLFieldsCommon.cpp
Security-177.tar.gz
[apple/security.git] / AppleX509CL / CLFieldsCommon.cpp
1 /*
2 * Copyright (c) 2002 Apple Computer, 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 <SecurityNssAsn1/nameTemplates.h>
30 #include <SecurityNssAsn1/certExtensionTemplates.h>
31
32 /*
33 * Table to map an OID to the info needed to decode the
34 * associated extension
35 */
36 typedef struct {
37 const CSSM_OID &oid;
38 unsigned nssObjLen;
39 const SEC_ASN1Template *templ;
40 } NssExtenInfo;
41
42 static const NssExtenInfo nssExtenInfo[] = {
43 { CSSMOID_KeyUsage,
44 sizeof(CSSM_DATA),
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,
53 sizeof(CSSM_DATA),
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,
68 sizeof(CSSM_DATA),
69 NSS_NetscapeCertTypeTemplate },
70 { CSSMOID_CrlDistributionPoints,
71 sizeof(NSS_CRLDistributionPoints),
72 NSS_CRLDistributionPointsTemplate },
73 { CSSMOID_CertIssuer,
74 sizeof(NSS_GeneralNames),
75 NSS_GeneralNamesTemplate },
76 /* CRL extensions */
77 { CSSMOID_CrlNumber,
78 sizeof(CSSM_DATA),
79 SEC_IntegerTemplate },
80 { CSSMOID_IssuingDistributionPoint,
81 sizeof(NSS_IssuingDistributionPoint),
82 NSS_IssuingDistributionPointTemplate },
83 { CSSMOID_HoldInstructionCode,
84 sizeof(CSSM_OID),
85 SEC_ObjectIDTemplate },
86 { CSSMOID_CrlReason,
87 sizeof(CSSM_DATA),
88 SEC_EnumeratedTemplate },
89 { CSSMOID_DeltaCrlIndicator,
90 sizeof(CSSM_DATA),
91 SEC_IntegerTemplate },
92 { CSSMOID_InvalidityDate,
93 sizeof(CSSM_DATA),
94 SEC_GeneralizedTimeTemplate }
95 };
96
97 #define NUM_NSS_EXTEN_INFOS (sizeof(nssExtenInfo) / sizeof(nssExtenInfo[0]))
98
99 /*
100 * Returns true if we find the OID.
101 */
102 bool clOidToNssInfo(
103 const CSSM_OID &oid,
104 unsigned &nssObjLen, // RETURNED
105 const SEC_ASN1Template *&templ) // RETURNED
106 {
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;
111 templ = info.templ;
112 return true;
113 }
114 }
115 return false;
116 }
117
118
119
120 /*
121 * Common code to pass info from a DecodedExten back to app.
122 * Called from getField*().
123 */
124 void getFieldExtenCommon(
125 void *cdsaObj, // e.g. CE_KeyUsage
126 // NULL for berEncoded
127 const DecodedExten &decodedExt,
128 CssmOwnedData &fieldValue)
129 {
130 CSSM_X509_EXTENSION_PTR cssmExt;
131 CssmAllocator &alloc = fieldValue.allocator;
132 CssmData &fdata = fieldValue.get();
133
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);
139 }
140
141 /*
142 * Common code for top of setField* and freeField*().
143 */
144 CSSM_X509_EXTENSION_PTR verifySetFreeExtension(
145 const CssmData &fieldValue,
146 bool berEncoded) // false: value in value.parsedValue
147 // true : value in BERValue
148 {
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);
153 }
154 CSSM_X509_EXTENSION_PTR cssmExt =
155 reinterpret_cast<CSSM_X509_EXTENSION_PTR>(fieldValue.data());
156 if(berEncoded) {
157 if((cssmExt->value.parsedValue != NULL) ||
158 (cssmExt->BERvalue.Data == NULL)) {
159 CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER);
160 }
161 }
162 else {
163 if(cssmExt->value.parsedValue == NULL) {
164 CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER);
165 }
166 }
167 return cssmExt;
168 }
169
170 /*
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()).
175 */
176 void freeFieldExtenCommon(
177 CSSM_X509_EXTENSION_PTR exten,
178 CssmAllocator &alloc)
179 {
180 alloc.free(exten->extnId.Data);
181 alloc.free(exten->BERvalue.Data); // may be NULL
182 alloc.free(exten->value.parsedValue); // may be NULL
183 }
184
185 /*
186 * One common free for extensions whose parsed value doesn't go any deeper
187 * than cssmExt->value.parsedValue.
188 */
189 void freeFieldSimpleExtension (
190 CssmOwnedData &fieldValue)
191 {
192 CSSM_X509_EXTENSION_PTR cssmExt = verifySetFreeExtension(fieldValue,
193 false);
194 freeFieldExtenCommon(cssmExt, fieldValue.allocator);
195 }
196
197
198 /***
199 *** Common code for get/set subject/issuer name (C struct version)
200 *** Format = CSSM_X509_NAME
201 *** class Name from sm_x501if
202 ***/
203 bool getField_RDN_NSS (
204 const NSS_Name &nssName,
205 CssmOwnedData &fieldValue) // RETURNED
206 {
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();
211
212 CL_nssNameToCssm(nssName, *cssmName, alloc);
213 return true;
214 }
215
216 void freeField_RDN (
217 CssmOwnedData &fieldValue)
218 {
219 if(fieldValue.data() == NULL) {
220 return;
221 }
222 if(fieldValue.length() != sizeof(CSSM_X509_NAME)) {
223 CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER);
224 }
225 CssmAllocator &alloc = fieldValue.allocator;
226 CSSM_X509_NAME_PTR x509Name = (CSSM_X509_NAME_PTR)fieldValue.data();
227 CL_freeX509Name(x509Name, alloc);
228
229 /* top-level x509Name pointer freed by freeCertFieldData() */
230 }
231
232 /***
233 *** Common code for Issuer Name, Subject Name (normalized and encoded
234 *** version)
235 *** Format = CSSM_DATA containing the DER encoding of the normalized name
236 ***/
237 bool getField_normRDN_NSS (
238 const CSSM_DATA &derName,
239 uint32 &numFields, // RETURNED (if successful, 0 or 1)
240 CssmOwnedData &fieldValue) // RETURNED
241 {
242 if(derName.Data == NULL) {
243 /* This can happen during CertGetAllTemplateFields() because
244 * the normalized fields are only set up during cert/CRL decode */
245 return false;
246 }
247
248 /*
249 * First make a temp decoded copy which we'll be manipulating.
250 */
251 SecNssCoder coder;
252 NSS_Name decodedName;
253
254 memset(&decodedName, 0, sizeof(decodedName));
255 PRErrorCode prtn = coder.decodeItem(derName, NSS_NameTemplate, &decodedName);
256 if(prtn) {
257 /*
258 * Actually should never happen since this same bag of bits successfully
259 * decoded when the cert as a whole was decoded...
260 */
261 clErrorLog("getField_normRDN decode error\n");
262 CssmError::throwMe(CSSMERR_CL_UNKNOWN_FORMAT);
263
264 }
265
266 /* normalize */
267 CL_normalizeX509NameNSS(decodedName, coder);
268
269 /* encode result */
270 prtn = SecNssEncodeItemOdata(&decodedName, NSS_NameTemplate, fieldValue);
271 if(prtn) {
272 clErrorLog("getField_normRDN encode error\n");
273 CssmError::throwMe(CSSMERR_CL_INTERNAL_ERROR);
274 }
275 numFields = 1;
276 return true;
277 }
278
279 /***
280 *** Common code for Time fields - Validity not before, Not After,
281 *** This Update, Next Update
282 *** Format: CSSM_X509_TIME
283 ***/
284 bool getField_TimeNSS (
285 const NSS_Time &nssTime,
286 unsigned index, // which occurrence (0 = first)
287 uint32 &numFields, // RETURNED
288 CssmOwnedData &fieldValue) // RETURNED
289 {
290 if(!tbsGetCheck(nssTime.item.Data, index)) {
291 return false;
292 }
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)) {
298 numFields = 1;
299 return true;
300 }
301 else {
302 return false;
303 }
304 }
305
306 void setField_TimeNSS (
307 const CssmData &fieldValue,
308 NSS_Time &nssTime,
309 SecNssCoder &coder)
310 {
311 CSSM_X509_TIME *cssmTime =
312 (CSSM_X509_TIME *)fieldValue.data();
313 CL_cssmTimeToNss(*cssmTime, nssTime, coder);
314 }
315
316 void freeField_Time (
317 CssmOwnedData &fieldValue)
318 {
319 CSSM_X509_TIME *cssmTime = (CSSM_X509_TIME *)fieldValue.data();
320 if(cssmTime == NULL) {
321 return;
322 }
323 if(fieldValue.length() != sizeof(CSSM_X509_TIME)) {
324 CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER);
325 }
326 CL_freeCssmTime(cssmTime, fieldValue.allocator);
327 }
328
329 /***
330 *** TBS AlgId, Signature AlgId
331 *** Format = CSSM_X509_ALGORITHM_IDENTIFIER
332 ***/
333 void getField_AlgIdNSS (
334 const CSSM_X509_ALGORITHM_IDENTIFIER &srcAlgId,
335 CssmOwnedData &fieldValue) // RETURNED
336 {
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);
342 }
343
344 void setField_AlgIdNSS (
345 const CssmData &fieldValue,
346 CSSM_X509_ALGORITHM_IDENTIFIER &dstAlgId,
347 SecNssCoder &coder)
348 {
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);
354 }
355
356 void freeField_AlgId (
357 CssmOwnedData &fieldValue)
358 {
359 CSSM_X509_ALGORITHM_IDENTIFIER *cssmAlgId =
360 (CSSM_X509_ALGORITHM_IDENTIFIER *)fieldValue.data();
361 if(cssmAlgId == NULL) {
362 return;
363 }
364 if(fieldValue.length() != sizeof(CSSM_X509_ALGORITHM_IDENTIFIER)) {
365 CssmError::throwMe(CSSMERR_CL_INVALID_FIELD_POINTER);
366 }
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));
371 }
372
373 /*
374 * Routines for common validity checking for certificateToSign fields.
375 *
376 * Call from setField*: verify field isn't already set, optionally validate
377 * input length
378 */
379 void tbsSetCheck(
380 void *fieldToSet,
381 const CssmData &fieldValue,
382 uint32 expLength,
383 const char *op)
384 {
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);
389 }
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);
394 }
395 }
396
397 /*
398 * Call from getField* for unique fields - detect missing field or
399 * index out of bounds.
400 */
401 bool tbsGetCheck(
402 const void *requiredField,
403 uint32 reqIndex)
404 {
405 if((requiredField == NULL) || (reqIndex != 0)) {
406 return false;
407 }
408 else {
409 return true;
410 }
411 }
412
413 /***
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
419 ***/
420
421 void setFieldUnknownExt(
422 DecodedItem &cert,
423 const CssmData &fieldValue)
424 {
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);
431 }
432
433 bool getFieldUnknownExt(
434 DecodedItem &cert,
435 unsigned index, // which occurrence (0 = first)
436 uint32 &numFields, // RETURNED
437 CssmOwnedData &fieldValue)
438 {
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) {
445 return false;
446 }
447 getFieldExtenCommon(NULL, *decodedExt, fieldValue);
448 return true;
449 }
450
451 void freeFieldUnknownExt (
452 CssmOwnedData &fieldValue)
453 {
454 CSSM_X509_EXTENSION_PTR cssmExt = verifySetFreeExtension(fieldValue, true);
455 CssmAllocator &alloc = fieldValue.allocator;
456 freeFieldExtenCommon(cssmExt, alloc); // frees extnId, parsedValue, BERvalue
457 }
458
459 /* setField for read-only OIDs (i.e., the ones in cert/CRL, not TBS) */
460 void setField_ReadOnly (
461 DecodedItem &item,
462 const CssmData &fieldValue)
463 {
464 clErrorLog("Attempt to set a read-only field");
465 CssmError::throwMe(CSSMERR_CL_UNKNOWN_TAG);
466 }
467
468 bool getField_Unimplemented (
469 DecodedItem &item,
470 unsigned index, // which occurrence (0 = first)
471 uint32 &numFields, // RETURNED
472 CssmOwnedData &fieldValue) // RETURNED
473 {
474 clErrorLog("Attempt to get an unimplemented field");
475 CssmError::throwMe(CSSMERR_CL_UNKNOWN_TAG);
476 }
477
478
479