2 * CertBuilderApp.cpp - support for constructing certs, CDSA version
6 #include <utilLib/common.h>
7 #include "CertBuilderApp.h"
12 #include <Security/oidscert.h>
13 #include <Security/oidsalg.h>
14 #include <Security/x509defs.h>
15 #include <Security/SecAsn1Coder.h>
17 #include <Security/keyTemplates.h>
20 * Build up a CSSM_X509_NAME from an arbitrary list of name/OID pairs.
21 * We do one a/v pair per RDN.
23 CSSM_X509_NAME
*CB_BuildX509Name(
24 const CB_NameOid
*nameArray
,
27 CSSM_X509_NAME
*top
= (CSSM_X509_NAME
*)appMalloc(sizeof(CSSM_X509_NAME
), 0);
31 top
->numberOfRDNs
= numNames
;
32 top
->RelativeDistinguishedName
=
33 (CSSM_X509_RDN_PTR
)appMalloc(sizeof(CSSM_X509_RDN
) * numNames
, 0);
34 if(top
->RelativeDistinguishedName
== NULL
) {
37 CSSM_X509_RDN_PTR rdn
;
38 const CB_NameOid
*nameOid
;
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
;
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
);
59 /* free the CSSM_X509_NAME obtained from CB_BuildX509Name */
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
);
77 CSSM_FREE(rdn
->AttributeTypeAndValue
);
80 CSSM_FREE(top
->RelativeDistinguishedName
);
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 */
90 CSSM_X509_TIME
*xtime
= (CSSM_X509_TIME
*)appMalloc(sizeof(CSSM_X509_TIME
), 0);
94 xtime
->timeType
= BER_TAG_GENERALIZED_TIME
;
97 ts
= genTimeAtNowPlus(secondsFromNow
);
100 ts
= (char *)appMalloc(strlen(timeStr
) + 1, 0);
103 xtime
->time
.Data
= (uint8
*)ts
;
104 xtime
->time
.Length
= strlen(ts
);
108 /* Free CSSM_X509_TIME obtained in CB_BuildX509Time */
109 void CB_FreeX509Time(
110 CSSM_X509_TIME
*xtime
)
115 freeTimeString((char *)xtime
->time
.Data
);
120 * Encode an OID as a CSSM_X509_ALGORITHM_IDENTIFIER.
121 * Returns nonzero on error.
122 * Returned data is appMallocd's caller must appFree.
125 const CSSM_OID
*paramOid
,
128 SecAsn1CoderRef coder
= NULL
;
129 if(SecAsn1CoderCreate(&coder
)) {
130 printf("***Error in SecAsn1CoderCreate()\n");
134 CSSM_X509_ALGORITHM_IDENTIFIER algParams
;
135 memset(&algParams
, 0, sizeof(algParams
));
136 algParams
.algorithm
= *paramOid
;
137 CSSM_DATA encoded
= {0, NULL
};
139 if(SecAsn1EncodeItem(coder
, &algParams
, kSecAsn1AlgorithmIDTemplate
,
141 printf("***Error encoding CSSM_X509_ALGORITHM_IDENTIFIER\n");
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");
152 SecAsn1CoderRelease(coder
);
157 * Cook up an unsigned cert.
158 * This is just a wrapper for CSSM_CL_CertCreateTemplate().
161 #define ALWAYS_SET_VERSION 0
163 CSSM_DATA_PTR
CB_MakeCertTemplate(
165 CSSM_CL_HANDLE clHand
,
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
174 const CSSM_DATA
*subjectUniqueId
,
175 const CSSM_DATA
*issuerUniqueId
,
176 CSSM_X509_EXTENSION
*extensions
,
177 unsigned numExtensions
)
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
;
186 int setVersion
= ALWAYS_SET_VERSION
;
187 const CSSM_OID
*paramOid
= NULL
;
189 /* convert uint32-style algorithm to the associated struct */
190 CSSM_X509_ALGORITHM_IDENTIFIER algId
;
192 case CSSM_ALGID_SHA1WithRSA
:
193 algId
.algorithm
= CSSMOID_SHA1WithRSA
;
195 case CSSM_ALGID_MD5WithRSA
:
196 algId
.algorithm
= CSSMOID_MD5WithRSA
;
198 case CSSM_ALGID_MD2WithRSA
:
199 algId
.algorithm
= CSSMOID_MD2WithRSA
;
201 case CSSM_ALGID_FEE_MD5
:
202 algId
.algorithm
= CSSMOID_APPLE_FEE_MD5
;
204 case CSSM_ALGID_FEE_SHA1
:
205 algId
.algorithm
= CSSMOID_APPLE_FEE_SHA1
;
207 case CSSM_ALGID_SHA1WithECDSA
:
208 algId
.algorithm
= CSSMOID_ECDSA_WithSHA1
;
210 case CSSM_ALGID_SHA1WithDSA
:
211 algId
.algorithm
= CSSMOID_SHA1WithDSA_CMS
;
213 case CSSM_ALGID_SHA224WithRSA
:
214 algId
.algorithm
= CSSMOID_SHA224WithRSA
;
216 case CSSM_ALGID_SHA256WithRSA
:
217 algId
.algorithm
= CSSMOID_SHA256WithRSA
;
219 case CSSM_ALGID_SHA384WithRSA
:
220 algId
.algorithm
= CSSMOID_SHA384WithRSA
;
222 case CSSM_ALGID_SHA512WithRSA
:
223 algId
.algorithm
= CSSMOID_SHA512WithRSA
;
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
;
230 case CSSM_ALGID_SHA256WithECDSA
:
231 algId
.algorithm
= CSSMOID_ECDSA_WithSpecified
;
232 paramOid
= &CSSMOID_SHA256
;
234 case CSSM_ALGID_SHA384WithECDSA
:
235 algId
.algorithm
= CSSMOID_ECDSA_WithSpecified
;
236 paramOid
= &CSSMOID_SHA384
;
238 case CSSM_ALGID_SHA512WithECDSA
:
239 algId
.algorithm
= CSSMOID_ECDSA_WithSpecified
;
240 paramOid
= &CSSMOID_SHA512
;
243 printf("CB_MakeCertTemplate: unknown sig alg (%u)\n", (unsigned)sigAlg
);
246 if(paramOid
!= NULL
) {
247 /* not-quite-trivial encoding of digest algorithm */
248 if(encodeParamOid(paramOid
, &algId
.parameters
)) {
253 algId
.parameters
.Data
= NULL
;
254 algId
.parameters
.Length
= 0;
259 * serialNumber thru subjectPubKey
261 unsigned numFields
= 7 + numExtensions
;
265 if(subjectUniqueId
) {
284 certTemp
= (CSSM_FIELD
*)CSSM_MALLOC(sizeof(CSSM_FIELD
) * numFields
);
288 versionDER
= intToDER(version
);
289 certTemp
[fieldDex
].FieldOid
= CSSMOID_X509V1Version
;
290 certTemp
[fieldDex
++].FieldValue
= *versionDER
;
294 serialDER
= intToDER(serialNumber
);
295 certTemp
[fieldDex
].FieldOid
= CSSMOID_X509V1SerialNumber
;
296 certTemp
[fieldDex
++].FieldValue
= *serialDER
;
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
);
303 certTemp
[fieldDex
].FieldOid
= CSSMOID_X509V1SubjectNameCStruct
;
304 certTemp
[fieldDex
].FieldValue
.Data
= (uint8
*)subjectName
;
305 certTemp
[fieldDex
++].FieldValue
.Length
= sizeof(CSSM_X509_NAME
);
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
);
312 certTemp
[fieldDex
].FieldOid
= CSSMOID_X509V1ValidityNotAfter
;
313 certTemp
[fieldDex
].FieldValue
.Data
= (uint8
*)notAfter
;
314 certTemp
[fieldDex
++].FieldValue
.Length
= sizeof(CSSM_X509_TIME
);
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
);
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
);
326 /* subject/issuer unique IDs */
327 if(subjectUniqueId
!= 0) {
328 certTemp
[fieldDex
].FieldOid
= CSSMOID_X509V1CertificateSubjectUniqueId
;
329 certTemp
[fieldDex
++].FieldValue
= *subjectUniqueId
;
331 if(issuerUniqueId
!= 0) {
332 certTemp
[fieldDex
].FieldOid
= CSSMOID_X509V1CertificateIssuerUniqueId
;
333 certTemp
[fieldDex
++].FieldValue
= *issuerUniqueId
;
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
;
342 certTemp
[fieldDex
].FieldOid
= CSSMOID_X509V3CertificateExtensionCStruct
;
344 certTemp
[fieldDex
].FieldValue
.Data
= (uint8
*)ext
;
345 certTemp
[fieldDex
++].FieldValue
.Length
= sizeof(CSSM_X509_EXTENSION
);
347 if(fieldDex
!= numFields
) {
348 printf("CB_MakeCertTemplate numFields screwup\n");
355 rawCert
= (CSSM_DATA_PTR
)CSSM_MALLOC(sizeof(CSSM_DATA
));
356 rawCert
->Data
= NULL
;
358 CSSM_RETURN crtn
= CSSM_CL_CertCreateTemplate(clHand
,
363 printError("CSSM_CL_CertCreateTemplate", crtn
);
364 appFreeCssmData(rawCert
, CSSM_TRUE
);
368 /* free the stuff we mallocd to get here */
369 appFreeCssmData(serialDER
, CSSM_TRUE
);
370 appFreeCssmData(versionDER
, CSSM_TRUE
);
372 if((paramOid
!= NULL
) && (algId
.parameters
.Data
!= NULL
)) {
373 CSSM_FREE(algId
.parameters
.Data
);