]>
Commit | Line | Data |
---|---|---|
d8f41ccd A |
1 | /* |
2 | * makeCrl.cpp - create a CRL revoking a given cert | |
3 | */ | |
4 | ||
5 | #include <stdlib.h> | |
6 | #include <strings.h> | |
7 | #include <stdio.h> | |
8 | #include <unistd.h> | |
9 | #include <Security/Security.h> | |
10 | #include <Security/SecAsn1Coder.h> | |
11 | #include <Security/SecAsn1Types.h> | |
12 | #include <Security/X509Templates.h> | |
13 | #include <Security/keyTemplates.h> | |
14 | #include <Security/SecKeyPriv.h> | |
15 | #include <Security/SecIdentityPriv.h> | |
16 | #include <utilLib/common.h> | |
17 | #include <security_cdsa_utils/cuFileIo.h> | |
18 | #include <clAppUtils/timeStr.h> | |
19 | ||
20 | #define THIS_UPDATE_DEF 0 | |
21 | #define NEXT_UPDATE_DEF (60 * 60 * 24) | |
22 | #define REVOKE_TIME_DEF (60 * 60 * 12) | |
23 | ||
24 | static void usage(char **argv) | |
25 | { | |
26 | printf("usage: %s [requiredParams...] [options...]\n", argv[0]); | |
27 | printf("Required parameters:\n"); | |
28 | printf(" -s subjectCert\n"); | |
29 | printf(" -i issuerCert\n"); | |
30 | printf(" -o outputFile\n"); | |
31 | printf("Options:\n"); | |
32 | printf(" -k keychain -- contains issuerCert identity; default is default KC list\n"); | |
33 | printf(" -r revokeTime -- seconds after 'now' cert is revoked; default is %d\n", | |
34 | REVOKE_TIME_DEF); | |
35 | printf(" -t thisUpdate -- CRL thisUpdate, seconds after 'now'; default is %d\n", | |
36 | THIS_UPDATE_DEF); | |
37 | printf(" -n thisUpdate -- CRL nextUpdate, seconds after 'now'; default is %d\n", | |
38 | NEXT_UPDATE_DEF); | |
39 | /* etc. */ | |
40 | exit(1); | |
41 | } | |
42 | ||
43 | /* seconds from now --> NSS_Time */ | |
44 | /* caller must eventually free nssTime.item.Data */ | |
45 | static void secondsToNssTime( | |
46 | int seconds, | |
47 | NSS_Time *nssTime) | |
48 | { | |
49 | char *revocationDate = genTimeAtNowPlus(seconds); | |
50 | nssTime->item.Data = (uint8 *)revocationDate; | |
51 | nssTime->item.Length = strlen(revocationDate); | |
52 | nssTime->tag = SEC_ASN1_GENERALIZED_TIME; | |
53 | } | |
54 | ||
55 | /* sign some data using a SecKeyRef */ | |
56 | static OSStatus secSign( | |
57 | SecKeyRef signingKey, | |
58 | CSSM_ALGORITHMS sigAlg, | |
59 | const CSSM_DATA *ptext, | |
60 | CSSM_DATA *sig) | |
61 | { | |
62 | const CSSM_KEY *cssmKey; | |
63 | CSSM_CSP_HANDLE cspHand; | |
64 | const CSSM_ACCESS_CREDENTIALS *creds; | |
65 | CSSM_CC_HANDLE sigHand = 0; | |
66 | CSSM_RETURN crtn; | |
67 | OSStatus ortn; | |
68 | ||
69 | ortn = SecKeyGetCSSMKey(signingKey, &cssmKey); | |
70 | if(ortn) { | |
71 | cssmPerror("SecKeyGetCSSMKey", ortn); | |
72 | return ortn; | |
73 | } | |
74 | ortn = SecKeyGetCSPHandle(signingKey, &cspHand); | |
75 | if(ortn) { | |
76 | cssmPerror("SecKeyGetCSPHandle", ortn); | |
77 | return ortn; | |
78 | } | |
79 | ortn = SecKeyGetCredentials(signingKey, | |
80 | CSSM_ACL_AUTHORIZATION_SIGN, | |
81 | kSecCredentialTypeDefault, | |
82 | &creds); | |
83 | if(ortn) { | |
84 | cssmPerror("SecKeyGetCredentials", ortn); | |
85 | return ortn; | |
86 | } | |
87 | crtn = CSSM_CSP_CreateSignatureContext(cspHand, | |
88 | sigAlg, | |
89 | creds, | |
90 | cssmKey, | |
91 | &sigHand); | |
92 | if(crtn) { | |
93 | cssmPerror("CSSM_CSP_CreateSignatureContext", crtn); | |
94 | return crtn; | |
95 | } | |
96 | sig->Data = NULL; | |
97 | sig->Length = 0; | |
98 | crtn = CSSM_SignData(sigHand, | |
99 | ptext, | |
100 | 1, | |
101 | CSSM_ALGID_NONE, // digestAlg for raw sign | |
102 | sig); | |
103 | CSSM_DeleteContext(sigHand); | |
104 | return crtn; | |
105 | } | |
106 | ||
107 | /* basic "create and sign a CRL" routine - the CL is not capable of this */ | |
108 | static int makeCrl( | |
109 | const unsigned char *subjectCert, | |
110 | unsigned subjectCertLen, | |
111 | SecKeyRef signingKey, | |
112 | int revokeTime, // revocation time, seconds from now (+/-) | |
113 | int crlThisUpdate, // CRL thisUpdate, seconds from now (+/-) | |
114 | int crlNextUpdate, // CRL nextUpdate, seconds from now (+/-) | |
115 | unsigned char **crlOut, // mallocd and returned | |
116 | unsigned *crlOutLen) // returned | |
117 | { | |
118 | SecAsn1CoderRef coder = NULL; | |
119 | OSStatus ortn; | |
120 | int ourRtn = -1; | |
121 | NSS_Certificate subject; | |
122 | NSS_RevokedCert revokedCert; | |
123 | NSS_TBSCrl tbsCrl; | |
124 | NSS_SignedCertOrCRL crl; | |
125 | CSSM_DATA encodedCrl = {0, NULL}; | |
126 | uint8 nullEnc[2] = {5, 0}; | |
127 | CSSM_DATA nullEncData = {2, nullEnc}; | |
128 | ||
129 | ortn = SecAsn1CoderCreate(&coder); | |
130 | if(ortn) { | |
131 | cssmPerror("SecAsn1CoderCreate", ortn); | |
132 | goto errOut; | |
133 | } | |
134 | ||
135 | /* decode subject to get serial number and issuer */ | |
136 | memset(&subject, 0, sizeof(subject)); | |
137 | ortn = SecAsn1Decode(coder, subjectCert, subjectCertLen, kSecAsn1SignedCertTemplate, | |
138 | &subject); | |
139 | if(ortn) { | |
140 | cssmPerror("SecAsn1Decode(subjectCert)", ortn); | |
141 | goto errOut; | |
142 | } | |
143 | ||
144 | /* revoked cert entry - no extensions */ | |
145 | revokedCert.userCertificate = subject.tbs.serialNumber; | |
146 | secondsToNssTime(revokeTime, &revokedCert.revocationDate); | |
147 | revokedCert.extensions = NULL; | |
148 | ||
149 | /* TBS CRL - assume RSA signing key for now */ | |
150 | memset(&tbsCrl, 0, sizeof(tbsCrl)); | |
151 | tbsCrl.signature.algorithm = CSSMOID_SHA1WithRSA; | |
152 | tbsCrl.signature.parameters = nullEncData; | |
153 | tbsCrl.issuer = subject.tbs.issuer; | |
154 | secondsToNssTime(crlThisUpdate, &tbsCrl.thisUpdate); | |
155 | secondsToNssTime(crlNextUpdate, &tbsCrl.nextUpdate); | |
156 | tbsCrl.revokedCerts = (NSS_RevokedCert **)(SecAsn1Malloc(coder, sizeof(void *) * 2)); | |
157 | tbsCrl.revokedCerts[0] = &revokedCert; | |
158 | tbsCrl.revokedCerts[1] = NULL; | |
159 | tbsCrl.extensions = NULL; | |
160 | ||
161 | /* encode TBS */ | |
162 | memset(&crl, 0, sizeof(crl)); | |
163 | ortn = SecAsn1EncodeItem(coder, &tbsCrl, kSecAsn1TBSCrlTemplate, &crl.tbsBlob); | |
164 | if(ortn) { | |
165 | cssmPerror("SecAsn1EncodeItem(tbsCrl)", ortn); | |
166 | goto errOut; | |
167 | } | |
168 | ||
169 | /* encode top-level algid */ | |
170 | ortn = SecAsn1EncodeItem(coder, &tbsCrl.signature, | |
171 | kSecAsn1AlgorithmIDTemplate, &crl.signatureAlgorithm); | |
172 | if(ortn) { | |
173 | cssmPerror("SecAsn1EncodeItem(signatureAlgorithm)", ortn); | |
174 | goto errOut; | |
175 | } | |
176 | ||
177 | /* sign TBS */ | |
178 | ortn = secSign(signingKey, CSSM_ALGID_SHA1WithRSA, &crl.tbsBlob, | |
179 | &crl.signature); | |
180 | if(ortn) { | |
181 | goto errOut; | |
182 | } | |
183 | ||
184 | /* Encode result. Signature is bit string... */ | |
185 | crl.signature.Length *= 8; | |
186 | ortn = SecAsn1EncodeItem(coder, &crl, | |
187 | kSecAsn1SignedCertOrCRLTemplate, &encodedCrl); | |
188 | if(ortn) { | |
189 | cssmPerror("SecAsn1EncodeItem(encodedCrl)", ortn); | |
190 | goto errOut; | |
191 | } | |
192 | *crlOut = (unsigned char *)malloc(encodedCrl.Length); | |
193 | *crlOut = (unsigned char *)encodedCrl.Data; | |
194 | *crlOutLen = encodedCrl.Length; | |
195 | ourRtn = 0; | |
196 | ||
197 | errOut: | |
198 | if(coder) { | |
199 | SecAsn1CoderRelease(coder); | |
200 | } | |
201 | if(revokedCert.revocationDate.item.Data) { | |
202 | CSSM_FREE(revokedCert.revocationDate.item.Data); | |
203 | } | |
204 | if(tbsCrl.thisUpdate.item.Data) { | |
205 | CSSM_FREE(tbsCrl.thisUpdate.item.Data); | |
206 | } | |
207 | if(revokedCert.revocationDate.item.Data) { | |
208 | CSSM_FREE(tbsCrl.nextUpdate.item.Data); | |
209 | } | |
210 | return ourRtn; | |
211 | } | |
212 | ||
213 | int main(int argc, char **argv) | |
214 | { | |
215 | char *subjectName = NULL; | |
216 | char *issuerName = NULL; | |
217 | char *outFileName = NULL; | |
218 | char *kcName = NULL; | |
219 | int revokeTime = REVOKE_TIME_DEF; | |
220 | int thisUpdate = THIS_UPDATE_DEF; | |
221 | int nextUpdate = NEXT_UPDATE_DEF; | |
222 | ||
223 | extern char *optarg; | |
224 | int arg; | |
225 | while ((arg = getopt(argc, argv, "s:i:o:k:r:t:n:h")) != -1) { | |
226 | switch (arg) { | |
227 | case 's': | |
228 | subjectName = optarg; | |
229 | break; | |
230 | case 'i': | |
231 | issuerName = optarg; | |
232 | break; | |
233 | case 'o': | |
234 | outFileName = optarg; | |
235 | break; | |
236 | case 'k': | |
237 | kcName = optarg; | |
238 | break; | |
239 | case 'r': | |
240 | revokeTime = atoi(optarg); | |
241 | break; | |
242 | case 't': | |
243 | thisUpdate = atoi(optarg); | |
244 | break; | |
245 | case 'n': | |
246 | nextUpdate = atoi(optarg); | |
247 | break; | |
248 | default: | |
249 | case 'h': | |
250 | usage(argv); | |
251 | } | |
252 | } | |
253 | if(optind != argc) { | |
254 | usage(argv); | |
255 | } | |
256 | if((subjectName == NULL) || (issuerName == NULL) || (outFileName == NULL)) { | |
257 | usage(argv); | |
258 | } | |
259 | ||
260 | /* get input files */ | |
261 | unsigned char *subjectCert; | |
262 | unsigned subjectCertLen; | |
263 | unsigned char *issuerCert; | |
264 | unsigned issuerCertLen; | |
265 | if(readFile(subjectName, &subjectCert, &subjectCertLen)) { | |
266 | printf("***Error reading %s. \n", subjectName); | |
267 | exit(1); | |
268 | } | |
269 | if(readFile(issuerName, &issuerCert, &issuerCertLen)) { | |
270 | printf("***Error reading %s. \n", issuerName); | |
271 | exit(1); | |
272 | } | |
273 | ||
274 | /* get issuer identity and signing key */ | |
275 | SecKeychainRef kcRef = NULL; | |
276 | OSStatus ortn; | |
277 | if(kcName) { | |
278 | ortn = SecKeychainOpen(kcName, &kcRef); | |
279 | if(ortn) { | |
280 | cssmPerror("SecKeychainOpen", ortn); | |
281 | exit(1); | |
282 | } | |
283 | } | |
284 | SecCertificateRef certRef = NULL; | |
285 | SecIdentityRef idRef = NULL; | |
286 | SecKeyRef signingKey = NULL; | |
287 | CSSM_DATA issuerCData = {issuerCertLen, (uint8 *)issuerCert}; | |
288 | ortn = SecCertificateCreateFromData(&issuerCData, | |
289 | CSSM_CERT_X_509v3, | |
290 | CSSM_CERT_ENCODING_DER, | |
291 | &certRef); | |
292 | if(ortn) { | |
293 | cssmPerror("SecCertificateCreateFromData", ortn); | |
294 | exit(1); | |
295 | } | |
296 | ortn = SecIdentityCreateWithCertificate(kcRef, certRef, &idRef); | |
297 | if(ortn) { | |
298 | cssmPerror("SecIdentityCreateWithCertificate", ortn); | |
299 | exit(1); | |
300 | } | |
301 | ortn = SecIdentityCopyPrivateKey(idRef, &signingKey); | |
302 | if(ortn) { | |
303 | cssmPerror("SecIdentityCopyPrivateKey", ortn); | |
304 | exit(1); | |
305 | } | |
306 | ||
307 | /* create and sign the CRL */ | |
308 | unsigned char *crlOut = NULL; | |
309 | unsigned crlOutLen = 0; | |
310 | if(makeCrl(subjectCert, subjectCertLen, | |
311 | signingKey, | |
312 | revokeTime, thisUpdate, nextUpdate, | |
313 | &crlOut, &crlOutLen)) { | |
314 | printf("***Error creating CRL. Aborting.\n"); | |
315 | exit(1); | |
316 | } | |
317 | ||
318 | /* ==> outFile */ | |
319 | if(writeFile(outFileName, crlOut, crlOutLen)) { | |
320 | printf("***Error writing CRL to %s\n", outFileName); | |
321 | } | |
322 | else { | |
323 | printf("...wrote %u bytes to %s.\n", crlOutLen, outFileName); | |
324 | } | |
325 | /* cleanup if you must */ | |
326 | ||
327 | return 0; | |
328 | } |