]> git.saurik.com Git - apple/security.git/blob - SecurityTests/clxutils/clAppUtils/CertBuilderApp.cpp
Security-57031.1.35.tar.gz
[apple/security.git] / SecurityTests / clxutils / clAppUtils / CertBuilderApp.cpp
1 /*
2 * CertBuilderApp.cpp - support for constructing certs, CDSA version
3 */
4
5 #include "clutils.h"
6 #include <utilLib/common.h>
7 #include "CertBuilderApp.h"
8 #include "timeStr.h"
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <Security/oidscert.h>
13 #include <Security/oidsalg.h>
14 #include <Security/x509defs.h>
15 #include <Security/SecAsn1Coder.h>
16 /* private header */
17 #include <Security/keyTemplates.h>
18
19 /*
20 * Build up a CSSM_X509_NAME from an arbitrary list of name/OID pairs.
21 * We do one a/v pair per RDN.
22 */
23 CSSM_X509_NAME *CB_BuildX509Name(
24 const CB_NameOid *nameArray,
25 unsigned numNames)
26 {
27 CSSM_X509_NAME *top = (CSSM_X509_NAME *)appMalloc(sizeof(CSSM_X509_NAME), 0);
28 if(top == NULL) {
29 return NULL;
30 }
31 top->numberOfRDNs = numNames;
32 top->RelativeDistinguishedName =
33 (CSSM_X509_RDN_PTR)appMalloc(sizeof(CSSM_X509_RDN) * numNames, 0);
34 if(top->RelativeDistinguishedName == NULL) {
35 return NULL;
36 }
37 CSSM_X509_RDN_PTR rdn;
38 const CB_NameOid *nameOid;
39 unsigned nameDex;
40 for(nameDex=0; nameDex<numNames; nameDex++) {
41 rdn = &top->RelativeDistinguishedName[nameDex];
42 nameOid = &nameArray[nameDex];
43 rdn->numberOfPairs = 1;
44 rdn->AttributeTypeAndValue = (CSSM_X509_TYPE_VALUE_PAIR_PTR)
45 appMalloc(sizeof(CSSM_X509_TYPE_VALUE_PAIR), 0);
46 CSSM_X509_TYPE_VALUE_PAIR_PTR atvp = rdn->AttributeTypeAndValue;
47 if(atvp == NULL) {
48 return NULL;
49 }
50 appCopyCssmData(nameOid->oid, &atvp->type);
51 atvp->valueType = BER_TAG_PRINTABLE_STRING;
52 atvp->value.Length = strlen(nameOid->string);
53 atvp->value.Data = (uint8 *)CSSM_MALLOC(atvp->value.Length);
54 memmove(atvp->value.Data, nameOid->string, atvp->value.Length);
55 }
56 return top;
57 }
58
59 /* free the CSSM_X509_NAME obtained from CB_BuildX509Name */
60 void CB_FreeX509Name(
61 CSSM_X509_NAME *top)
62 {
63 if(top == NULL) {
64 return;
65 }
66 unsigned nameDex;
67 CSSM_X509_RDN_PTR rdn;
68 for(nameDex=0; nameDex<top->numberOfRDNs; nameDex++) {
69 rdn = &top->RelativeDistinguishedName[nameDex];
70 if(rdn->AttributeTypeAndValue) {
71 for(unsigned aDex=0; aDex<rdn->numberOfPairs; aDex++) {
72 CSSM_X509_TYPE_VALUE_PAIR_PTR atvp =
73 &rdn->AttributeTypeAndValue[aDex];
74 CSSM_FREE(atvp->type.Data);
75 CSSM_FREE(atvp->value.Data);
76 }
77 CSSM_FREE(rdn->AttributeTypeAndValue);
78 }
79 }
80 CSSM_FREE(top->RelativeDistinguishedName);
81 CSSM_FREE(top);
82 }
83
84 /* Obtain a CSSM_X509_TIME representing "now" plus specified seconds, or
85 * from a preformatted gen time string */
86 CSSM_X509_TIME *CB_BuildX509Time(
87 unsigned secondsFromNow, /* ignored if timeStr non-NULL */
88 const char *timeStr) /* optional, from genTimeAtNowPlus */
89 {
90 CSSM_X509_TIME *xtime = (CSSM_X509_TIME *)appMalloc(sizeof(CSSM_X509_TIME), 0);
91 if(xtime == NULL) {
92 return NULL;
93 }
94 xtime->timeType = BER_TAG_GENERALIZED_TIME;
95 char *ts;
96 if(timeStr == NULL) {
97 ts = genTimeAtNowPlus(secondsFromNow);
98 }
99 else {
100 ts = (char *)appMalloc(strlen(timeStr) + 1, 0);
101 strcpy(ts, timeStr);
102 }
103 xtime->time.Data = (uint8 *)ts;
104 xtime->time.Length = strlen(ts);
105 return xtime;
106 }
107
108 /* Free CSSM_X509_TIME obtained in CB_BuildX509Time */
109 void CB_FreeX509Time(
110 CSSM_X509_TIME *xtime)
111 {
112 if(xtime == NULL) {
113 return;
114 }
115 freeTimeString((char *)xtime->time.Data);
116 appFree(xtime, 0);
117 }
118
119 /*
120 * Encode an OID as a CSSM_X509_ALGORITHM_IDENTIFIER.
121 * Returns nonzero on error.
122 * Returned data is appMallocd's caller must appFree.
123 */
124 int encodeParamOid(
125 const CSSM_OID *paramOid,
126 CSSM_DATA *params)
127 {
128 SecAsn1CoderRef coder = NULL;
129 if(SecAsn1CoderCreate(&coder)) {
130 printf("***Error in SecAsn1CoderCreate()\n");
131 return -1;
132 }
133
134 CSSM_X509_ALGORITHM_IDENTIFIER algParams;
135 memset(&algParams, 0, sizeof(algParams));
136 algParams.algorithm = *paramOid;
137 CSSM_DATA encoded = {0, NULL};
138 int ourRtn = 0;
139 if(SecAsn1EncodeItem(coder, &algParams, kSecAsn1AlgorithmIDTemplate,
140 &encoded)) {
141 printf("***Error encoding CSSM_X509_ALGORITHM_IDENTIFIER\n");
142 ourRtn = -1;
143 goto errOut;
144 }
145
146 /* That data is in the coder's memory space: copy ou9t to caller */
147 if(appCopyCssmData(&encoded, params)) {
148 printf("***encodeParamOid malloc failure\n");
149 ourRtn = -1;
150 }
151 errOut:
152 SecAsn1CoderRelease(coder);
153 return ourRtn;
154 }
155
156 /*
157 * Cook up an unsigned cert.
158 * This is just a wrapper for CSSM_CL_CertCreateTemplate().
159 */
160
161 #define ALWAYS_SET_VERSION 0
162
163 CSSM_DATA_PTR CB_MakeCertTemplate(
164 /* required */
165 CSSM_CL_HANDLE clHand,
166 uint32 serialNumber,
167 const CSSM_X509_NAME *issuerName,
168 const CSSM_X509_NAME *subjectName,
169 const CSSM_X509_TIME *notBefore,
170 const CSSM_X509_TIME *notAfter,
171 const CSSM_KEY_PTR subjectPubKey,
172 CSSM_ALGORITHMS sigAlg, // e.g., CSSM_ALGID_SHA1WithRSA
173 /* optional */
174 const CSSM_DATA *subjectUniqueId,
175 const CSSM_DATA *issuerUniqueId,
176 CSSM_X509_EXTENSION *extensions,
177 unsigned numExtensions)
178 {
179 CSSM_FIELD *certTemp;
180 unsigned fieldDex = 0; // index into certTemp
181 CSSM_DATA_PTR serialDER = NULL; // serial number, DER format
182 CSSM_DATA_PTR rawCert; // from CSSM_CL_CertCreateTemplate
183 unsigned version = 0;
184 CSSM_DATA_PTR versionDER = NULL;
185 unsigned extNum;
186 int setVersion = ALWAYS_SET_VERSION;
187 const CSSM_OID *paramOid = NULL;
188
189 /* convert uint32-style algorithm to the associated struct */
190 CSSM_X509_ALGORITHM_IDENTIFIER algId;
191 switch(sigAlg) {
192 case CSSM_ALGID_SHA1WithRSA:
193 algId.algorithm = CSSMOID_SHA1WithRSA;
194 break;
195 case CSSM_ALGID_MD5WithRSA:
196 algId.algorithm = CSSMOID_MD5WithRSA;
197 break;
198 case CSSM_ALGID_MD2WithRSA:
199 algId.algorithm = CSSMOID_MD2WithRSA;
200 break;
201 case CSSM_ALGID_FEE_MD5:
202 algId.algorithm = CSSMOID_APPLE_FEE_MD5;
203 break;
204 case CSSM_ALGID_FEE_SHA1:
205 algId.algorithm = CSSMOID_APPLE_FEE_SHA1;
206 break;
207 case CSSM_ALGID_SHA1WithECDSA:
208 algId.algorithm = CSSMOID_ECDSA_WithSHA1;
209 break;
210 case CSSM_ALGID_SHA1WithDSA:
211 algId.algorithm = CSSMOID_SHA1WithDSA_CMS;
212 break;
213 case CSSM_ALGID_SHA224WithRSA:
214 algId.algorithm = CSSMOID_SHA224WithRSA;
215 break;
216 case CSSM_ALGID_SHA256WithRSA:
217 algId.algorithm = CSSMOID_SHA256WithRSA;
218 break;
219 case CSSM_ALGID_SHA384WithRSA:
220 algId.algorithm = CSSMOID_SHA384WithRSA;
221 break;
222 case CSSM_ALGID_SHA512WithRSA:
223 algId.algorithm = CSSMOID_SHA512WithRSA;
224 break;
225 /* These specify the digest algorithm via an additional parameter OID */
226 case CSSM_ALGID_SHA224WithECDSA:
227 algId.algorithm = CSSMOID_ECDSA_WithSpecified;
228 paramOid = &CSSMOID_SHA224;
229 break;
230 case CSSM_ALGID_SHA256WithECDSA:
231 algId.algorithm = CSSMOID_ECDSA_WithSpecified;
232 paramOid = &CSSMOID_SHA256;
233 break;
234 case CSSM_ALGID_SHA384WithECDSA:
235 algId.algorithm = CSSMOID_ECDSA_WithSpecified;
236 paramOid = &CSSMOID_SHA384;
237 break;
238 case CSSM_ALGID_SHA512WithECDSA:
239 algId.algorithm = CSSMOID_ECDSA_WithSpecified;
240 paramOid = &CSSMOID_SHA512;
241 break;
242 default:
243 printf("CB_MakeCertTemplate: unknown sig alg (%u)\n", (unsigned)sigAlg);
244 return NULL;
245 }
246 if(paramOid != NULL) {
247 /* not-quite-trivial encoding of digest algorithm */
248 if(encodeParamOid(paramOid, &algId.parameters)) {
249 return NULL;
250 }
251 }
252 else {
253 algId.parameters.Data = NULL;
254 algId.parameters.Length = 0;
255 }
256
257 /*
258 * version, we infer
259 * serialNumber thru subjectPubKey
260 */
261 unsigned numFields = 7 + numExtensions;
262 if(numExtensions) {
263 version = 2;
264 }
265 if(subjectUniqueId) {
266 numFields++;
267 if(version == 0) {
268 version = 1;
269 }
270 }
271 if(issuerUniqueId) {
272 numFields++;
273 if(version == 0) {
274 version = 1;
275 }
276 }
277 if(version > 0) {
278 setVersion = 1;
279 }
280 if(setVersion) {
281 numFields++;
282 }
283
284 certTemp = (CSSM_FIELD *)CSSM_MALLOC(sizeof(CSSM_FIELD) * numFields);
285
286 /* version */
287 if(setVersion) {
288 versionDER = intToDER(version);
289 certTemp[fieldDex].FieldOid = CSSMOID_X509V1Version;
290 certTemp[fieldDex++].FieldValue = *versionDER;
291 }
292
293 /* serial number */
294 serialDER = intToDER(serialNumber);
295 certTemp[fieldDex].FieldOid = CSSMOID_X509V1SerialNumber;
296 certTemp[fieldDex++].FieldValue = *serialDER;
297
298 /* subject and issuer name */
299 certTemp[fieldDex].FieldOid = CSSMOID_X509V1IssuerNameCStruct;
300 certTemp[fieldDex].FieldValue.Data = (uint8 *)issuerName;
301 certTemp[fieldDex++].FieldValue.Length = sizeof(CSSM_X509_NAME);
302
303 certTemp[fieldDex].FieldOid = CSSMOID_X509V1SubjectNameCStruct;
304 certTemp[fieldDex].FieldValue.Data = (uint8 *)subjectName;
305 certTemp[fieldDex++].FieldValue.Length = sizeof(CSSM_X509_NAME);
306
307 /* not before/after */
308 certTemp[fieldDex].FieldOid = CSSMOID_X509V1ValidityNotBefore;
309 certTemp[fieldDex].FieldValue.Data = (uint8 *)notBefore;
310 certTemp[fieldDex++].FieldValue.Length = sizeof(CSSM_X509_TIME);
311
312 certTemp[fieldDex].FieldOid = CSSMOID_X509V1ValidityNotAfter;
313 certTemp[fieldDex].FieldValue.Data = (uint8 *)notAfter;
314 certTemp[fieldDex++].FieldValue.Length = sizeof(CSSM_X509_TIME);
315
316 /* the subject key */
317 certTemp[fieldDex].FieldOid = CSSMOID_CSSMKeyStruct;
318 certTemp[fieldDex].FieldValue.Data = (uint8 *)subjectPubKey;
319 certTemp[fieldDex++].FieldValue.Length = sizeof(CSSM_KEY);
320
321 /* signature algorithm */
322 certTemp[fieldDex].FieldOid = CSSMOID_X509V1SignatureAlgorithmTBS;
323 certTemp[fieldDex].FieldValue.Data = (uint8 *)&algId;
324 certTemp[fieldDex++].FieldValue.Length = sizeof(CSSM_X509_ALGORITHM_IDENTIFIER);
325
326 /* subject/issuer unique IDs */
327 if(subjectUniqueId != 0) {
328 certTemp[fieldDex].FieldOid = CSSMOID_X509V1CertificateSubjectUniqueId;
329 certTemp[fieldDex++].FieldValue = *subjectUniqueId;
330 }
331 if(issuerUniqueId != 0) {
332 certTemp[fieldDex].FieldOid = CSSMOID_X509V1CertificateIssuerUniqueId;
333 certTemp[fieldDex++].FieldValue = *issuerUniqueId;
334 }
335
336 for(extNum=0; extNum<numExtensions; extNum++) {
337 CSSM_X509_EXTENSION_PTR ext = &extensions[extNum];
338 if(ext->format == CSSM_X509_DATAFORMAT_PARSED) {
339 certTemp[fieldDex].FieldOid = ext->extnId;
340 }
341 else {
342 certTemp[fieldDex].FieldOid = CSSMOID_X509V3CertificateExtensionCStruct;
343 }
344 certTemp[fieldDex].FieldValue.Data = (uint8 *)ext;
345 certTemp[fieldDex++].FieldValue.Length = sizeof(CSSM_X509_EXTENSION);
346 }
347 if(fieldDex != numFields) {
348 printf("CB_MakeCertTemplate numFields screwup\n");
349 return NULL;
350 }
351
352 /*
353 * OK, here we go
354 */
355 rawCert = (CSSM_DATA_PTR)CSSM_MALLOC(sizeof(CSSM_DATA));
356 rawCert->Data = NULL;
357 rawCert->Length = 0;
358 CSSM_RETURN crtn = CSSM_CL_CertCreateTemplate(clHand,
359 fieldDex,
360 certTemp,
361 rawCert);
362 if(crtn) {
363 printError("CSSM_CL_CertCreateTemplate", crtn);
364 appFreeCssmData(rawCert, CSSM_TRUE);
365 rawCert = NULL;
366 }
367
368 /* free the stuff we mallocd to get here */
369 appFreeCssmData(serialDER, CSSM_TRUE);
370 appFreeCssmData(versionDER, CSSM_TRUE);
371 CSSM_FREE(certTemp);
372 if((paramOid != NULL) && (algId.parameters.Data != NULL)) {
373 CSSM_FREE(algId.parameters.Data);
374 }
375 return rawCert;
376 }