|
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
2 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
4 |
|
5 /* |
|
6 ** certutil.c |
|
7 ** |
|
8 ** utility for managing certificates and the cert database |
|
9 ** |
|
10 */ |
|
11 /* test only */ |
|
12 |
|
13 #include "nspr.h" |
|
14 #include "plgetopt.h" |
|
15 #include "secutil.h" |
|
16 #include "cert.h" |
|
17 #include "certi.h" |
|
18 #include "certdb.h" |
|
19 #include "nss.h" |
|
20 #include "pk11func.h" |
|
21 #include "crlgen.h" |
|
22 |
|
23 #define SEC_CERT_DB_EXISTS 0 |
|
24 #define SEC_CREATE_CERT_DB 1 |
|
25 |
|
26 static char *progName; |
|
27 |
|
28 static CERTSignedCrl *FindCRL |
|
29 (CERTCertDBHandle *certHandle, char *name, int type) |
|
30 { |
|
31 CERTSignedCrl *crl = NULL; |
|
32 CERTCertificate *cert = NULL; |
|
33 SECItem derName; |
|
34 |
|
35 derName.data = NULL; |
|
36 derName.len = 0; |
|
37 |
|
38 cert = CERT_FindCertByNicknameOrEmailAddr(certHandle, name); |
|
39 if (!cert) { |
|
40 CERTName *certName = NULL; |
|
41 PLArenaPool *arena = NULL; |
|
42 |
|
43 certName = CERT_AsciiToName(name); |
|
44 if (certName) { |
|
45 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); |
|
46 if (arena) { |
|
47 SECItem *nameItem = |
|
48 SEC_ASN1EncodeItem (arena, NULL, (void *)certName, |
|
49 SEC_ASN1_GET(CERT_NameTemplate)); |
|
50 if (nameItem) { |
|
51 SECITEM_CopyItem(NULL, &derName, nameItem); |
|
52 } |
|
53 PORT_FreeArena(arena, PR_FALSE); |
|
54 } |
|
55 CERT_DestroyName(certName); |
|
56 } |
|
57 |
|
58 if (!derName.len || !derName.data) { |
|
59 SECU_PrintError(progName, "could not find certificate named '%s'", name); |
|
60 return ((CERTSignedCrl *)NULL); |
|
61 } |
|
62 } else { |
|
63 SECITEM_CopyItem(NULL, &derName, &cert->derSubject); |
|
64 CERT_DestroyCertificate (cert); |
|
65 } |
|
66 |
|
67 crl = SEC_FindCrlByName(certHandle, &derName, type); |
|
68 if (crl ==NULL) |
|
69 SECU_PrintError |
|
70 (progName, "could not find %s's CRL", name); |
|
71 if (derName.data) { |
|
72 SECITEM_FreeItem(&derName, PR_FALSE); |
|
73 } |
|
74 return (crl); |
|
75 } |
|
76 |
|
77 static SECStatus DisplayCRL (CERTCertDBHandle *certHandle, char *nickName, int crlType) |
|
78 { |
|
79 CERTSignedCrl *crl = NULL; |
|
80 |
|
81 crl = FindCRL (certHandle, nickName, crlType); |
|
82 |
|
83 if (crl) { |
|
84 SECU_PrintCRLInfo (stdout, &crl->crl, "CRL Info:\n", 0); |
|
85 SEC_DestroyCrl (crl); |
|
86 return SECSuccess; |
|
87 } |
|
88 return SECFailure; |
|
89 } |
|
90 |
|
91 static void ListCRLNames (CERTCertDBHandle *certHandle, int crlType, PRBool deletecrls) |
|
92 { |
|
93 CERTCrlHeadNode *crlList = NULL; |
|
94 CERTCrlNode *crlNode = NULL; |
|
95 CERTName *name = NULL; |
|
96 PLArenaPool *arena = NULL; |
|
97 SECStatus rv; |
|
98 |
|
99 do { |
|
100 arena = PORT_NewArena (SEC_ASN1_DEFAULT_ARENA_SIZE); |
|
101 if (arena == NULL) { |
|
102 fprintf(stderr, "%s: fail to allocate memory\n", progName); |
|
103 break; |
|
104 } |
|
105 |
|
106 name = PORT_ArenaZAlloc (arena, sizeof(*name)); |
|
107 if (name == NULL) { |
|
108 fprintf(stderr, "%s: fail to allocate memory\n", progName); |
|
109 break; |
|
110 } |
|
111 name->arena = arena; |
|
112 |
|
113 rv = SEC_LookupCrls (certHandle, &crlList, crlType); |
|
114 if (rv != SECSuccess) { |
|
115 fprintf(stderr, "%s: fail to look up CRLs (%s)\n", progName, |
|
116 SECU_Strerror(PORT_GetError())); |
|
117 break; |
|
118 } |
|
119 |
|
120 /* just in case */ |
|
121 if (!crlList) |
|
122 break; |
|
123 |
|
124 crlNode = crlList->first; |
|
125 |
|
126 fprintf (stdout, "\n"); |
|
127 fprintf (stdout, "\n%-40s %-5s\n\n", "CRL names", "CRL Type"); |
|
128 while (crlNode) { |
|
129 char* asciiname = NULL; |
|
130 CERTCertificate *cert = NULL; |
|
131 if (crlNode->crl && &crlNode->crl->crl.derName) { |
|
132 cert = CERT_FindCertByName(certHandle, |
|
133 &crlNode->crl->crl.derName); |
|
134 if (!cert) { |
|
135 SECU_PrintError(progName, "could not find signing " |
|
136 "certificate in database"); |
|
137 } |
|
138 } |
|
139 if (cert) { |
|
140 char* certName = NULL; |
|
141 if (cert->nickname && PORT_Strlen(cert->nickname) > 0) { |
|
142 certName = cert->nickname; |
|
143 } else if (cert->emailAddr && PORT_Strlen(cert->emailAddr) > 0) { |
|
144 certName = cert->emailAddr; |
|
145 } |
|
146 if (certName) { |
|
147 asciiname = PORT_Strdup(certName); |
|
148 } |
|
149 CERT_DestroyCertificate(cert); |
|
150 } |
|
151 |
|
152 if (!asciiname) { |
|
153 name = &crlNode->crl->crl.name; |
|
154 if (!name){ |
|
155 SECU_PrintError(progName, "fail to get the CRL " |
|
156 "issuer name"); |
|
157 continue; |
|
158 } |
|
159 asciiname = CERT_NameToAscii(name); |
|
160 } |
|
161 fprintf (stdout, "%-40s %-5s\n", asciiname, "CRL"); |
|
162 if (asciiname) { |
|
163 PORT_Free(asciiname); |
|
164 } |
|
165 if ( PR_TRUE == deletecrls) { |
|
166 CERTSignedCrl* acrl = NULL; |
|
167 SECItem* issuer = &crlNode->crl->crl.derName; |
|
168 acrl = SEC_FindCrlByName(certHandle, issuer, crlType); |
|
169 if (acrl) |
|
170 { |
|
171 SEC_DeletePermCRL(acrl); |
|
172 SEC_DestroyCrl(acrl); |
|
173 } |
|
174 } |
|
175 crlNode = crlNode->next; |
|
176 } |
|
177 |
|
178 } while (0); |
|
179 if (crlList) |
|
180 PORT_FreeArena (crlList->arena, PR_FALSE); |
|
181 PORT_FreeArena (arena, PR_FALSE); |
|
182 } |
|
183 |
|
184 static SECStatus ListCRL (CERTCertDBHandle *certHandle, char *nickName, int crlType) |
|
185 { |
|
186 if (nickName == NULL) { |
|
187 ListCRLNames (certHandle, crlType, PR_FALSE); |
|
188 return SECSuccess; |
|
189 } |
|
190 |
|
191 return DisplayCRL (certHandle, nickName, crlType); |
|
192 } |
|
193 |
|
194 |
|
195 |
|
196 static SECStatus DeleteCRL (CERTCertDBHandle *certHandle, char *name, int type) |
|
197 { |
|
198 CERTSignedCrl *crl = NULL; |
|
199 SECStatus rv = SECFailure; |
|
200 |
|
201 crl = FindCRL (certHandle, name, type); |
|
202 if (!crl) { |
|
203 SECU_PrintError |
|
204 (progName, "could not find the issuer %s's CRL", name); |
|
205 return SECFailure; |
|
206 } |
|
207 rv = SEC_DeletePermCRL (crl); |
|
208 SEC_DestroyCrl(crl); |
|
209 if (rv != SECSuccess) { |
|
210 SECU_PrintError(progName, "fail to delete the issuer %s's CRL " |
|
211 "from the perm database (reason: %s)", |
|
212 name, SECU_Strerror(PORT_GetError())); |
|
213 return SECFailure; |
|
214 } |
|
215 return (rv); |
|
216 } |
|
217 |
|
218 SECStatus ImportCRL (CERTCertDBHandle *certHandle, char *url, int type, |
|
219 PRFileDesc *inFile, PRInt32 importOptions, PRInt32 decodeOptions, |
|
220 secuPWData *pwdata) |
|
221 { |
|
222 CERTSignedCrl *crl = NULL; |
|
223 SECItem crlDER; |
|
224 PK11SlotInfo* slot = NULL; |
|
225 int rv; |
|
226 #if defined(DEBUG_jp96085) |
|
227 PRIntervalTime starttime, endtime, elapsed; |
|
228 PRUint32 mins, secs, msecs; |
|
229 #endif |
|
230 |
|
231 crlDER.data = NULL; |
|
232 |
|
233 |
|
234 /* Read in the entire file specified with the -f argument */ |
|
235 rv = SECU_ReadDERFromFile(&crlDER, inFile, PR_FALSE, PR_FALSE); |
|
236 if (rv != SECSuccess) { |
|
237 SECU_PrintError(progName, "unable to read input file"); |
|
238 return (SECFailure); |
|
239 } |
|
240 |
|
241 decodeOptions |= CRL_DECODE_DONT_COPY_DER; |
|
242 |
|
243 slot = PK11_GetInternalKeySlot(); |
|
244 |
|
245 if (PK11_NeedLogin(slot)) { |
|
246 rv = PK11_Authenticate(slot, PR_TRUE, pwdata); |
|
247 if (rv != SECSuccess) |
|
248 goto loser; |
|
249 } |
|
250 |
|
251 #if defined(DEBUG_jp96085) |
|
252 starttime = PR_IntervalNow(); |
|
253 #endif |
|
254 crl = PK11_ImportCRL(slot, &crlDER, url, type, |
|
255 NULL, importOptions, NULL, decodeOptions); |
|
256 #if defined(DEBUG_jp96085) |
|
257 endtime = PR_IntervalNow(); |
|
258 elapsed = endtime - starttime; |
|
259 mins = PR_IntervalToSeconds(elapsed) / 60; |
|
260 secs = PR_IntervalToSeconds(elapsed) % 60; |
|
261 msecs = PR_IntervalToMilliseconds(elapsed) % 1000; |
|
262 printf("Elapsed : %2d:%2d.%3d\n", mins, secs, msecs); |
|
263 #endif |
|
264 if (!crl) { |
|
265 const char *errString; |
|
266 |
|
267 rv = SECFailure; |
|
268 errString = SECU_Strerror(PORT_GetError()); |
|
269 if ( errString && PORT_Strlen (errString) == 0) |
|
270 SECU_PrintError (progName, |
|
271 "CRL is not imported (error: input CRL is not up to date.)"); |
|
272 else |
|
273 SECU_PrintError (progName, "unable to import CRL"); |
|
274 } else { |
|
275 SEC_DestroyCrl (crl); |
|
276 } |
|
277 loser: |
|
278 if (slot) { |
|
279 PK11_FreeSlot(slot); |
|
280 } |
|
281 return (rv); |
|
282 } |
|
283 |
|
284 SECStatus DumpCRL(PRFileDesc *inFile) |
|
285 { |
|
286 int rv; |
|
287 PLArenaPool *arena = NULL; |
|
288 CERTSignedCrl *newCrl = NULL; |
|
289 |
|
290 SECItem crlDER; |
|
291 crlDER.data = NULL; |
|
292 |
|
293 /* Read in the entire file specified with the -f argument */ |
|
294 rv = SECU_ReadDERFromFile(&crlDER, inFile, PR_FALSE, PR_FALSE); |
|
295 if (rv != SECSuccess) { |
|
296 SECU_PrintError(progName, "unable to read input file"); |
|
297 return (SECFailure); |
|
298 } |
|
299 |
|
300 rv = SEC_ERROR_NO_MEMORY; |
|
301 arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); |
|
302 if (!arena) |
|
303 return rv; |
|
304 |
|
305 newCrl = CERT_DecodeDERCrlWithFlags(arena, &crlDER, SEC_CRL_TYPE, |
|
306 CRL_DECODE_DEFAULT_OPTIONS); |
|
307 if (!newCrl) |
|
308 return SECFailure; |
|
309 |
|
310 SECU_PrintCRLInfo (stdout, &newCrl->crl, "CRL file contents", 0); |
|
311 |
|
312 PORT_FreeArena (arena, PR_FALSE); |
|
313 return rv; |
|
314 } |
|
315 |
|
316 static CERTCertificate* |
|
317 FindSigningCert(CERTCertDBHandle *certHandle, CERTSignedCrl *signCrl, |
|
318 char *certNickName) |
|
319 { |
|
320 CERTCertificate *cert = NULL, *certTemp = NULL; |
|
321 SECStatus rv = SECFailure; |
|
322 CERTAuthKeyID* authorityKeyID = NULL; |
|
323 SECItem* subject = NULL; |
|
324 |
|
325 PORT_Assert(certHandle != NULL); |
|
326 if (!certHandle || (!signCrl && !certNickName)) { |
|
327 SECU_PrintError(progName, "invalid args for function " |
|
328 "FindSigningCert \n"); |
|
329 return NULL; |
|
330 } |
|
331 |
|
332 if (signCrl) { |
|
333 #if 0 |
|
334 authorityKeyID = SECU_FindCRLAuthKeyIDExten(tmpArena, scrl); |
|
335 #endif |
|
336 subject = &signCrl->crl.derName; |
|
337 } else { |
|
338 certTemp = CERT_FindCertByNickname(certHandle, certNickName); |
|
339 if (!certTemp) { |
|
340 SECU_PrintError(progName, "could not find certificate \"%s\" " |
|
341 "in database", certNickName); |
|
342 goto loser; |
|
343 } |
|
344 subject = &certTemp->derSubject; |
|
345 } |
|
346 |
|
347 cert = SECU_FindCrlIssuer(certHandle, subject, authorityKeyID, PR_Now()); |
|
348 if (!cert) { |
|
349 SECU_PrintError(progName, "could not find signing certificate " |
|
350 "in database"); |
|
351 goto loser; |
|
352 } else { |
|
353 rv = SECSuccess; |
|
354 } |
|
355 |
|
356 loser: |
|
357 if (certTemp) |
|
358 CERT_DestroyCertificate(certTemp); |
|
359 if (cert && rv != SECSuccess) |
|
360 CERT_DestroyCertificate(cert); |
|
361 return cert; |
|
362 } |
|
363 |
|
364 static CERTSignedCrl* |
|
365 CreateModifiedCRLCopy(PLArenaPool *arena, CERTCertDBHandle *certHandle, |
|
366 CERTCertificate **cert, char *certNickName, |
|
367 PRFileDesc *inFile, PRInt32 decodeOptions, |
|
368 PRInt32 importOptions) |
|
369 { |
|
370 SECItem crlDER = {0, NULL, 0}; |
|
371 CERTSignedCrl *signCrl = NULL; |
|
372 CERTSignedCrl *modCrl = NULL; |
|
373 PLArenaPool *modArena = NULL; |
|
374 SECStatus rv = SECSuccess; |
|
375 |
|
376 if (!arena || !certHandle || !certNickName) { |
|
377 PORT_SetError(SEC_ERROR_INVALID_ARGS); |
|
378 SECU_PrintError(progName, "CreateModifiedCRLCopy: invalid args\n"); |
|
379 return NULL; |
|
380 } |
|
381 |
|
382 modArena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE); |
|
383 if (!modArena) { |
|
384 SECU_PrintError(progName, "fail to allocate memory\n"); |
|
385 return NULL; |
|
386 } |
|
387 |
|
388 if (inFile != NULL) { |
|
389 rv = SECU_ReadDERFromFile(&crlDER, inFile, PR_FALSE, PR_FALSE); |
|
390 if (rv != SECSuccess) { |
|
391 SECU_PrintError(progName, "unable to read input file"); |
|
392 PORT_FreeArena(modArena, PR_FALSE); |
|
393 goto loser; |
|
394 } |
|
395 |
|
396 decodeOptions |= CRL_DECODE_DONT_COPY_DER; |
|
397 |
|
398 modCrl = CERT_DecodeDERCrlWithFlags(modArena, &crlDER, SEC_CRL_TYPE, |
|
399 decodeOptions); |
|
400 if (!modCrl) { |
|
401 SECU_PrintError(progName, "fail to decode CRL"); |
|
402 goto loser; |
|
403 } |
|
404 |
|
405 if (0 == (importOptions & CRL_IMPORT_BYPASS_CHECKS)){ |
|
406 /* If caCert is a v2 certificate, make sure that it |
|
407 * can be used for crl signing purpose */ |
|
408 *cert = FindSigningCert(certHandle, modCrl, NULL); |
|
409 if (!*cert) { |
|
410 goto loser; |
|
411 } |
|
412 |
|
413 rv = CERT_VerifySignedData(&modCrl->signatureWrap, *cert, |
|
414 PR_Now(), NULL); |
|
415 if (rv != SECSuccess) { |
|
416 SECU_PrintError(progName, "fail to verify signed data\n"); |
|
417 goto loser; |
|
418 } |
|
419 } |
|
420 } else { |
|
421 modCrl = FindCRL(certHandle, certNickName, SEC_CRL_TYPE); |
|
422 if (!modCrl) { |
|
423 SECU_PrintError(progName, "fail to find crl %s in database\n", |
|
424 certNickName); |
|
425 goto loser; |
|
426 } |
|
427 } |
|
428 |
|
429 signCrl = PORT_ArenaZNew(arena, CERTSignedCrl); |
|
430 if (signCrl == NULL) { |
|
431 SECU_PrintError(progName, "fail to allocate memory\n"); |
|
432 goto loser; |
|
433 } |
|
434 |
|
435 rv = SECU_CopyCRL(arena, &signCrl->crl, &modCrl->crl); |
|
436 if (rv != SECSuccess) { |
|
437 SECU_PrintError(progName, "unable to dublicate crl for " |
|
438 "modification."); |
|
439 goto loser; |
|
440 } |
|
441 |
|
442 /* Make sure the update time is current. It can be modified later |
|
443 * by "update <time>" command from crl generation script */ |
|
444 rv = DER_EncodeTimeChoice(arena, &signCrl->crl.lastUpdate, PR_Now()); |
|
445 if (rv != SECSuccess) { |
|
446 SECU_PrintError(progName, "fail to encode current time\n"); |
|
447 goto loser; |
|
448 } |
|
449 |
|
450 signCrl->arena = arena; |
|
451 |
|
452 loser: |
|
453 if (crlDER.data) { |
|
454 SECITEM_FreeItem(&crlDER, PR_FALSE); |
|
455 } |
|
456 if (modCrl) |
|
457 SEC_DestroyCrl(modCrl); |
|
458 if (rv != SECSuccess && signCrl) { |
|
459 SEC_DestroyCrl(signCrl); |
|
460 signCrl = NULL; |
|
461 } |
|
462 return signCrl; |
|
463 } |
|
464 |
|
465 |
|
466 static CERTSignedCrl* |
|
467 CreateNewCrl(PLArenaPool *arena, CERTCertDBHandle *certHandle, |
|
468 CERTCertificate *cert) |
|
469 { |
|
470 CERTSignedCrl *signCrl = NULL; |
|
471 void *dummy = NULL; |
|
472 SECStatus rv; |
|
473 void* mark = NULL; |
|
474 |
|
475 /* if the CERTSignedCrl structure changes, this function will need to be |
|
476 updated as well */ |
|
477 if (!cert || !arena) { |
|
478 PORT_SetError(SEC_ERROR_INVALID_ARGS); |
|
479 SECU_PrintError(progName, "invalid args for function " |
|
480 "CreateNewCrl\n"); |
|
481 return NULL; |
|
482 } |
|
483 |
|
484 mark = PORT_ArenaMark(arena); |
|
485 |
|
486 signCrl = PORT_ArenaZNew(arena, CERTSignedCrl); |
|
487 if (signCrl == NULL) { |
|
488 SECU_PrintError(progName, "fail to allocate memory\n"); |
|
489 return NULL; |
|
490 } |
|
491 |
|
492 dummy = SEC_ASN1EncodeInteger(arena, &signCrl->crl.version, |
|
493 SEC_CRL_VERSION_2); |
|
494 /* set crl->version */ |
|
495 if (!dummy) { |
|
496 SECU_PrintError(progName, "fail to create crl version data " |
|
497 "container\n"); |
|
498 goto loser; |
|
499 } |
|
500 |
|
501 /* copy SECItem name from cert */ |
|
502 rv = SECITEM_CopyItem(arena, &signCrl->crl.derName, &cert->derSubject); |
|
503 if (rv != SECSuccess) { |
|
504 SECU_PrintError(progName, "fail to duplicate der name from " |
|
505 "certificate.\n"); |
|
506 goto loser; |
|
507 } |
|
508 |
|
509 /* copy CERTName name structure from cert issuer */ |
|
510 rv = CERT_CopyName (arena, &signCrl->crl.name, &cert->subject); |
|
511 if (rv != SECSuccess) { |
|
512 SECU_PrintError(progName, "fail to duplicate RD name from " |
|
513 "certificate.\n"); |
|
514 goto loser; |
|
515 } |
|
516 |
|
517 rv = DER_EncodeTimeChoice(arena, &signCrl->crl.lastUpdate, PR_Now()); |
|
518 if (rv != SECSuccess) { |
|
519 SECU_PrintError(progName, "fail to encode current time\n"); |
|
520 goto loser; |
|
521 } |
|
522 |
|
523 /* set fields */ |
|
524 signCrl->arena = arena; |
|
525 signCrl->dbhandle = certHandle; |
|
526 signCrl->crl.arena = arena; |
|
527 |
|
528 return signCrl; |
|
529 |
|
530 loser: |
|
531 PORT_ArenaRelease(arena, mark); |
|
532 return NULL; |
|
533 } |
|
534 |
|
535 |
|
536 static SECStatus |
|
537 UpdateCrl(CERTSignedCrl *signCrl, PRFileDesc *inCrlInitFile) |
|
538 { |
|
539 CRLGENGeneratorData *crlGenData = NULL; |
|
540 SECStatus rv; |
|
541 |
|
542 if (!signCrl || !inCrlInitFile) { |
|
543 PORT_SetError(SEC_ERROR_INVALID_ARGS); |
|
544 SECU_PrintError(progName, "invalid args for function " |
|
545 "CreateNewCrl\n"); |
|
546 return SECFailure; |
|
547 } |
|
548 |
|
549 crlGenData = CRLGEN_InitCrlGeneration(signCrl, inCrlInitFile); |
|
550 if (!crlGenData) { |
|
551 SECU_PrintError(progName, "can not initialize parser structure.\n"); |
|
552 return SECFailure; |
|
553 } |
|
554 |
|
555 rv = CRLGEN_ExtHandleInit(crlGenData); |
|
556 if (rv == SECFailure) { |
|
557 SECU_PrintError(progName, "can not initialize entries handle.\n"); |
|
558 goto loser; |
|
559 } |
|
560 |
|
561 rv = CRLGEN_StartCrlGen(crlGenData); |
|
562 if (rv != SECSuccess) { |
|
563 SECU_PrintError(progName, "crl generation failed"); |
|
564 goto loser; |
|
565 } |
|
566 |
|
567 loser: |
|
568 /* CommitExtensionsAndEntries is partially responsible for freeing |
|
569 * up memory that was used for CRL generation. Should be called regardless |
|
570 * of previouse call status, but only after initialization of |
|
571 * crlGenData was done. It will commit all changes that was done before |
|
572 * an error has occurred. |
|
573 */ |
|
574 if (SECSuccess != CRLGEN_CommitExtensionsAndEntries(crlGenData)) { |
|
575 SECU_PrintError(progName, "crl generation failed"); |
|
576 rv = SECFailure; |
|
577 } |
|
578 CRLGEN_FinalizeCrlGeneration(crlGenData); |
|
579 return rv; |
|
580 } |
|
581 |
|
582 static SECStatus |
|
583 SignAndStoreCrl(CERTSignedCrl *signCrl, CERTCertificate *cert, |
|
584 char *outFileName, SECOidTag hashAlgTag, int ascii, |
|
585 char *slotName, char *url, secuPWData *pwdata) |
|
586 { |
|
587 PK11SlotInfo *slot = NULL; |
|
588 PRFileDesc *outFile = NULL; |
|
589 SECStatus rv; |
|
590 SignAndEncodeFuncExitStat errCode; |
|
591 |
|
592 PORT_Assert(signCrl && (!ascii || outFileName)); |
|
593 if (!signCrl || (ascii && !outFileName)) { |
|
594 SECU_PrintError(progName, "invalid args for function " |
|
595 "SignAndStoreCrl\n"); |
|
596 return SECFailure; |
|
597 } |
|
598 |
|
599 if (!slotName || !PL_strcmp(slotName, "internal")) |
|
600 slot = PK11_GetInternalKeySlot(); |
|
601 else |
|
602 slot = PK11_FindSlotByName(slotName); |
|
603 if (!slot) { |
|
604 SECU_PrintError(progName, "can not find requested slot"); |
|
605 return SECFailure; |
|
606 } |
|
607 |
|
608 if (PK11_NeedLogin(slot)) { |
|
609 rv = PK11_Authenticate(slot, PR_TRUE, pwdata); |
|
610 if (rv != SECSuccess) |
|
611 goto loser; |
|
612 } |
|
613 |
|
614 rv = SECU_SignAndEncodeCRL(cert, signCrl, hashAlgTag, &errCode); |
|
615 if (rv != SECSuccess) { |
|
616 char* errMsg = NULL; |
|
617 switch (errCode) |
|
618 { |
|
619 case noKeyFound: |
|
620 errMsg = "No private key found of signing cert"; |
|
621 break; |
|
622 |
|
623 case noSignatureMatch: |
|
624 errMsg = "Key and Algorithm OId are do not match"; |
|
625 break; |
|
626 |
|
627 default: |
|
628 case failToEncode: |
|
629 errMsg = "Failed to encode crl structure"; |
|
630 break; |
|
631 |
|
632 case failToSign: |
|
633 errMsg = "Failed to sign crl structure"; |
|
634 break; |
|
635 |
|
636 case noMem: |
|
637 errMsg = "Can not allocate memory"; |
|
638 break; |
|
639 } |
|
640 SECU_PrintError(progName, "%s\n", errMsg); |
|
641 goto loser; |
|
642 } |
|
643 |
|
644 if (outFileName) { |
|
645 outFile = PR_Open(outFileName, PR_WRONLY|PR_CREATE_FILE, PR_IRUSR | PR_IWUSR); |
|
646 if (!outFile) { |
|
647 SECU_PrintError(progName, "unable to open \"%s\" for writing\n", |
|
648 outFileName); |
|
649 goto loser; |
|
650 } |
|
651 } |
|
652 |
|
653 rv = SECU_StoreCRL(slot, signCrl->derCrl, outFile, ascii, url); |
|
654 if (rv != SECSuccess) { |
|
655 SECU_PrintError(progName, "fail to save CRL\n"); |
|
656 } |
|
657 |
|
658 loser: |
|
659 if (outFile) |
|
660 PR_Close(outFile); |
|
661 if (slot) |
|
662 PK11_FreeSlot(slot); |
|
663 return rv; |
|
664 } |
|
665 |
|
666 static SECStatus |
|
667 GenerateCRL (CERTCertDBHandle *certHandle, char *certNickName, |
|
668 PRFileDesc *inCrlInitFile, PRFileDesc *inFile, |
|
669 char *outFileName, int ascii, char *slotName, |
|
670 PRInt32 importOptions, char *alg, PRBool quiet, |
|
671 PRInt32 decodeOptions, char *url, secuPWData *pwdata, |
|
672 int modifyFlag) |
|
673 { |
|
674 CERTCertificate *cert = NULL; |
|
675 CERTSignedCrl *signCrl = NULL; |
|
676 PLArenaPool *arena = NULL; |
|
677 SECStatus rv; |
|
678 SECOidTag hashAlgTag = SEC_OID_UNKNOWN; |
|
679 |
|
680 if (alg) { |
|
681 hashAlgTag = SECU_StringToSignatureAlgTag(alg); |
|
682 if (hashAlgTag == SEC_OID_UNKNOWN) { |
|
683 SECU_PrintError(progName, "%s -Z: %s is not a recognized type.\n", |
|
684 progName, alg); |
|
685 return SECFailure; |
|
686 } |
|
687 } else { |
|
688 hashAlgTag = SEC_OID_UNKNOWN; |
|
689 } |
|
690 |
|
691 arena = PORT_NewArena (SEC_ASN1_DEFAULT_ARENA_SIZE); |
|
692 if (!arena) { |
|
693 SECU_PrintError(progName, "fail to allocate memory\n"); |
|
694 return SECFailure; |
|
695 } |
|
696 |
|
697 if (modifyFlag == PR_TRUE) { |
|
698 signCrl = CreateModifiedCRLCopy(arena, certHandle, &cert, certNickName, |
|
699 inFile, decodeOptions, importOptions); |
|
700 if (signCrl == NULL) { |
|
701 goto loser; |
|
702 } |
|
703 } |
|
704 |
|
705 if (!cert) { |
|
706 cert = FindSigningCert(certHandle, signCrl, certNickName); |
|
707 if (cert == NULL) { |
|
708 goto loser; |
|
709 } |
|
710 } |
|
711 |
|
712 if (!signCrl) { |
|
713 if (modifyFlag == PR_TRUE) { |
|
714 if (!outFileName) { |
|
715 int len = strlen(certNickName) + 5; |
|
716 outFileName = PORT_ArenaAlloc(arena, len); |
|
717 PR_snprintf(outFileName, len, "%s.crl", certNickName); |
|
718 } |
|
719 SECU_PrintError(progName, "Will try to generate crl. " |
|
720 "It will be saved in file: %s", |
|
721 outFileName); |
|
722 } |
|
723 signCrl = CreateNewCrl(arena, certHandle, cert); |
|
724 if (!signCrl) |
|
725 goto loser; |
|
726 } |
|
727 |
|
728 rv = UpdateCrl(signCrl, inCrlInitFile); |
|
729 if (rv != SECSuccess) { |
|
730 goto loser; |
|
731 } |
|
732 |
|
733 rv = SignAndStoreCrl(signCrl, cert, outFileName, hashAlgTag, ascii, |
|
734 slotName, url, pwdata); |
|
735 if (rv != SECSuccess) { |
|
736 goto loser; |
|
737 } |
|
738 |
|
739 if (signCrl && !quiet) { |
|
740 SECU_PrintCRLInfo (stdout, &signCrl->crl, "CRL Info:\n", 0); |
|
741 } |
|
742 |
|
743 loser: |
|
744 if (arena && (!signCrl || !signCrl->arena)) |
|
745 PORT_FreeArena (arena, PR_FALSE); |
|
746 if (signCrl) |
|
747 SEC_DestroyCrl (signCrl); |
|
748 if (cert) |
|
749 CERT_DestroyCertificate (cert); |
|
750 return (rv); |
|
751 } |
|
752 |
|
753 static void Usage(char *progName) |
|
754 { |
|
755 fprintf(stderr, |
|
756 "Usage: %s -L [-n nickname] [-d keydir] [-P dbprefix] [-t crlType]\n" |
|
757 " %s -D -n nickname [-d keydir] [-P dbprefix]\n" |
|
758 " %s -S -i crl\n" |
|
759 " %s -I -i crl -t crlType [-u url] [-d keydir] [-P dbprefix] [-B] " |
|
760 "[-p pwd-file] -w [pwd-string]\n" |
|
761 " %s -E -t crlType [-d keydir] [-P dbprefix]\n" |
|
762 " %s -T\n" |
|
763 " %s -G|-M -c crl-init-file -n nickname [-i crl] [-u url] " |
|
764 "[-d keydir] [-P dbprefix] [-Z alg] ] [-p pwd-file] -w [pwd-string] " |
|
765 "[-a] [-B]\n", |
|
766 progName, progName, progName, progName, progName, progName, progName); |
|
767 |
|
768 fprintf (stderr, "%-15s List CRL\n", "-L"); |
|
769 fprintf(stderr, "%-20s Specify the nickname of the CA certificate\n", |
|
770 "-n nickname"); |
|
771 fprintf(stderr, "%-20s Key database directory (default is ~/.netscape)\n", |
|
772 "-d keydir"); |
|
773 fprintf(stderr, "%-20s Cert & Key database prefix (default is \"\")\n", |
|
774 "-P dbprefix"); |
|
775 |
|
776 fprintf (stderr, "%-15s Delete a CRL from the cert database\n", "-D"); |
|
777 fprintf(stderr, "%-20s Specify the nickname for the CA certificate\n", |
|
778 "-n nickname"); |
|
779 fprintf(stderr, "%-20s Specify the crl type.\n", "-t crlType"); |
|
780 fprintf(stderr, "%-20s Key database directory (default is ~/.netscape)\n", |
|
781 "-d keydir"); |
|
782 fprintf(stderr, "%-20s Cert & Key database prefix (default is \"\")\n", |
|
783 "-P dbprefix"); |
|
784 |
|
785 fprintf (stderr, "%-15s Erase all CRLs of specified type from hte cert database\n", "-E"); |
|
786 fprintf(stderr, "%-20s Specify the crl type.\n", "-t crlType"); |
|
787 fprintf(stderr, "%-20s Key database directory (default is ~/.netscape)\n", |
|
788 "-d keydir"); |
|
789 fprintf(stderr, "%-20s Cert & Key database prefix (default is \"\")\n", |
|
790 "-P dbprefix"); |
|
791 |
|
792 fprintf (stderr, "%-15s Show contents of a CRL file (without database)\n", "-S"); |
|
793 fprintf(stderr, "%-20s Specify the file which contains the CRL to show\n", |
|
794 "-i crl"); |
|
795 |
|
796 fprintf (stderr, "%-15s Import a CRL to the cert database\n", "-I"); |
|
797 fprintf(stderr, "%-20s Specify the file which contains the CRL to import\n", |
|
798 "-i crl"); |
|
799 fprintf(stderr, "%-20s Specify the url.\n", "-u url"); |
|
800 fprintf(stderr, "%-20s Specify the crl type.\n", "-t crlType"); |
|
801 fprintf(stderr, "%-20s Key database directory (default is ~/.netscape)\n", |
|
802 "-d keydir"); |
|
803 fprintf(stderr, "%-20s Cert & Key database prefix (default is \"\")\n", |
|
804 "-P dbprefix"); |
|
805 #ifdef DEBUG |
|
806 fprintf (stderr, "%-15s Test . Only for debugging purposes. See source code\n", "-T"); |
|
807 #endif |
|
808 fprintf(stderr, "%-20s CRL Types (default is SEC_CRL_TYPE):\n", " "); |
|
809 fprintf(stderr, "%-20s \t 0 - SEC_KRL_TYPE\n", " "); |
|
810 fprintf(stderr, "%-20s \t 1 - SEC_CRL_TYPE\n", " "); |
|
811 fprintf(stderr, "\n%-20s Bypass CA certificate checks.\n", "-B"); |
|
812 fprintf(stderr, "\n%-20s Partial decode for faster operation.\n", "-p"); |
|
813 fprintf(stderr, "%-20s Repeat the operation.\n", "-r <iterations>"); |
|
814 fprintf(stderr, "\n%-15s Create CRL\n", "-G"); |
|
815 fprintf(stderr, "%-15s Modify CRL\n", "-M"); |
|
816 fprintf(stderr, "%-20s Specify crl initialization file\n", |
|
817 "-c crl-conf-file"); |
|
818 fprintf(stderr, "%-20s Specify the nickname of the CA certificate\n", |
|
819 "-n nickname"); |
|
820 fprintf(stderr, "%-20s Specify the file which contains the CRL to import\n", |
|
821 "-i crl"); |
|
822 fprintf(stderr, "%-20s Specify a CRL output file\n", |
|
823 "-o crl-output-file"); |
|
824 fprintf(stderr, "%-20s Specify to use base64 encoded CRL output format\n", |
|
825 "-a"); |
|
826 fprintf(stderr, "%-20s Key database directory (default is ~/.netscape)\n", |
|
827 "-d keydir"); |
|
828 fprintf(stderr, "%-20s Provide path to a default pwd file\n", |
|
829 "-f pwd-file"); |
|
830 fprintf(stderr, "%-20s Provide db password in command line\n", |
|
831 "-w pwd-string"); |
|
832 fprintf(stderr, "%-20s Cert & Key database prefix (default is \"\")\n", |
|
833 "-P dbprefix"); |
|
834 fprintf(stderr, "%-20s Specify the url.\n", "-u url"); |
|
835 fprintf(stderr, "\n%-20s Bypass CA certificate checks.\n", "-B"); |
|
836 |
|
837 exit(-1); |
|
838 } |
|
839 |
|
840 int main(int argc, char **argv) |
|
841 { |
|
842 CERTCertDBHandle *certHandle; |
|
843 PRFileDesc *inFile; |
|
844 PRFileDesc *inCrlInitFile = NULL; |
|
845 int generateCRL; |
|
846 int modifyCRL; |
|
847 int listCRL; |
|
848 int importCRL; |
|
849 int showFileCRL; |
|
850 int deleteCRL; |
|
851 int rv; |
|
852 char *nickName; |
|
853 char *url; |
|
854 char *dbPrefix = ""; |
|
855 char *alg = NULL; |
|
856 char *outFile = NULL; |
|
857 char *slotName = NULL; |
|
858 int ascii = 0; |
|
859 int crlType; |
|
860 PLOptState *optstate; |
|
861 PLOptStatus status; |
|
862 SECStatus secstatus; |
|
863 PRInt32 decodeOptions = CRL_DECODE_DEFAULT_OPTIONS; |
|
864 PRInt32 importOptions = CRL_IMPORT_DEFAULT_OPTIONS; |
|
865 PRBool quiet = PR_FALSE; |
|
866 PRBool test = PR_FALSE; |
|
867 PRBool erase = PR_FALSE; |
|
868 PRInt32 i = 0; |
|
869 PRInt32 iterations = 1; |
|
870 PRBool readonly = PR_FALSE; |
|
871 |
|
872 secuPWData pwdata = { PW_NONE, 0 }; |
|
873 |
|
874 progName = strrchr(argv[0], '/'); |
|
875 progName = progName ? progName+1 : argv[0]; |
|
876 |
|
877 rv = 0; |
|
878 deleteCRL = importCRL = listCRL = generateCRL = modifyCRL = showFileCRL = 0; |
|
879 inFile = NULL; |
|
880 nickName = url = NULL; |
|
881 certHandle = NULL; |
|
882 crlType = SEC_CRL_TYPE; |
|
883 /* |
|
884 * Parse command line arguments |
|
885 */ |
|
886 optstate = PL_CreateOptState(argc, argv, "sqBCDGILMSTEP:f:d:i:h:n:p:t:u:r:aZ:o:c:"); |
|
887 while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) { |
|
888 switch (optstate->option) { |
|
889 case '?': |
|
890 Usage(progName); |
|
891 break; |
|
892 |
|
893 case 'T': |
|
894 test = PR_TRUE; |
|
895 break; |
|
896 |
|
897 case 'E': |
|
898 erase = PR_TRUE; |
|
899 break; |
|
900 |
|
901 case 'B': |
|
902 importOptions |= CRL_IMPORT_BYPASS_CHECKS; |
|
903 break; |
|
904 |
|
905 case 'G': |
|
906 generateCRL = 1; |
|
907 break; |
|
908 |
|
909 case 'M': |
|
910 modifyCRL = 1; |
|
911 break; |
|
912 |
|
913 case 'D': |
|
914 deleteCRL = 1; |
|
915 break; |
|
916 |
|
917 case 'I': |
|
918 importCRL = 1; |
|
919 break; |
|
920 |
|
921 case 'S': |
|
922 showFileCRL = 1; |
|
923 break; |
|
924 |
|
925 case 'C': |
|
926 case 'L': |
|
927 listCRL = 1; |
|
928 break; |
|
929 |
|
930 case 'P': |
|
931 dbPrefix = strdup(optstate->value); |
|
932 break; |
|
933 |
|
934 case 'Z': |
|
935 alg = strdup(optstate->value); |
|
936 break; |
|
937 |
|
938 case 'a': |
|
939 ascii = 1; |
|
940 break; |
|
941 |
|
942 case 'c': |
|
943 inCrlInitFile = PR_Open(optstate->value, PR_RDONLY, 0); |
|
944 if (!inCrlInitFile) { |
|
945 PR_fprintf(PR_STDERR, "%s: unable to open \"%s\" for reading\n", |
|
946 progName, optstate->value); |
|
947 PL_DestroyOptState(optstate); |
|
948 return -1; |
|
949 } |
|
950 break; |
|
951 |
|
952 case 'd': |
|
953 SECU_ConfigDirectory(optstate->value); |
|
954 break; |
|
955 |
|
956 case 'f': |
|
957 pwdata.source = PW_FROMFILE; |
|
958 pwdata.data = strdup(optstate->value); |
|
959 break; |
|
960 |
|
961 case 'h': |
|
962 slotName = strdup(optstate->value); |
|
963 break; |
|
964 |
|
965 case 'i': |
|
966 inFile = PR_Open(optstate->value, PR_RDONLY, 0); |
|
967 if (!inFile) { |
|
968 PR_fprintf(PR_STDERR, "%s: unable to open \"%s\" for reading\n", |
|
969 progName, optstate->value); |
|
970 PL_DestroyOptState(optstate); |
|
971 return -1; |
|
972 } |
|
973 break; |
|
974 |
|
975 case 'n': |
|
976 nickName = strdup(optstate->value); |
|
977 break; |
|
978 |
|
979 case 'o': |
|
980 outFile = strdup(optstate->value); |
|
981 break; |
|
982 |
|
983 case 'p': |
|
984 decodeOptions |= CRL_DECODE_SKIP_ENTRIES; |
|
985 break; |
|
986 |
|
987 case 'r': { |
|
988 const char* str = optstate->value; |
|
989 if (str && atoi(str)>0) |
|
990 iterations = atoi(str); |
|
991 } |
|
992 break; |
|
993 |
|
994 case 't': { |
|
995 crlType = atoi(optstate->value); |
|
996 if (crlType != SEC_CRL_TYPE && crlType != SEC_KRL_TYPE) { |
|
997 PR_fprintf(PR_STDERR, "%s: invalid crl type\n", progName); |
|
998 PL_DestroyOptState(optstate); |
|
999 return -1; |
|
1000 } |
|
1001 break; |
|
1002 |
|
1003 case 'q': |
|
1004 quiet = PR_TRUE; |
|
1005 break; |
|
1006 |
|
1007 case 'w': |
|
1008 pwdata.source = PW_PLAINTEXT; |
|
1009 pwdata.data = strdup(optstate->value); |
|
1010 break; |
|
1011 |
|
1012 case 'u': |
|
1013 url = strdup(optstate->value); |
|
1014 break; |
|
1015 |
|
1016 } |
|
1017 } |
|
1018 } |
|
1019 PL_DestroyOptState(optstate); |
|
1020 |
|
1021 if (deleteCRL && !nickName) Usage (progName); |
|
1022 if (importCRL && !inFile) Usage (progName); |
|
1023 if (showFileCRL && !inFile) Usage (progName); |
|
1024 if ((generateCRL && !nickName) || |
|
1025 (modifyCRL && !inFile && !nickName)) Usage (progName); |
|
1026 if (!(listCRL || deleteCRL || importCRL || showFileCRL || generateCRL || |
|
1027 modifyCRL || test || erase)) Usage (progName); |
|
1028 |
|
1029 if (listCRL || showFileCRL) { |
|
1030 readonly = PR_TRUE; |
|
1031 } |
|
1032 |
|
1033 PR_Init( PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1); |
|
1034 |
|
1035 PK11_SetPasswordFunc(SECU_GetModulePassword); |
|
1036 |
|
1037 if (showFileCRL) { |
|
1038 NSS_NoDB_Init(NULL); |
|
1039 } |
|
1040 else { |
|
1041 secstatus = NSS_Initialize(SECU_ConfigDirectory(NULL), dbPrefix, dbPrefix, |
|
1042 "secmod.db", readonly ? NSS_INIT_READONLY : 0); |
|
1043 if (secstatus != SECSuccess) { |
|
1044 SECU_PrintPRandOSError(progName); |
|
1045 return -1; |
|
1046 } |
|
1047 } |
|
1048 |
|
1049 SECU_RegisterDynamicOids(); |
|
1050 |
|
1051 certHandle = CERT_GetDefaultCertDB(); |
|
1052 if (certHandle == NULL) { |
|
1053 SECU_PrintError(progName, "unable to open the cert db"); |
|
1054 /*ignoring return value of NSS_Shutdown() as code returns -1*/ |
|
1055 (void) NSS_Shutdown(); |
|
1056 return (-1); |
|
1057 } |
|
1058 |
|
1059 CRLGEN_InitCrlGenParserLock(); |
|
1060 |
|
1061 for (i=0; i<iterations; i++) { |
|
1062 /* Read in the private key info */ |
|
1063 if (deleteCRL) |
|
1064 DeleteCRL (certHandle, nickName, crlType); |
|
1065 else if (listCRL) { |
|
1066 rv = ListCRL (certHandle, nickName, crlType); |
|
1067 } |
|
1068 else if (importCRL) { |
|
1069 rv = ImportCRL (certHandle, url, crlType, inFile, importOptions, |
|
1070 decodeOptions, &pwdata); |
|
1071 } |
|
1072 else if (showFileCRL) { |
|
1073 rv = DumpCRL (inFile); |
|
1074 } else if (generateCRL || modifyCRL) { |
|
1075 if (!inCrlInitFile) |
|
1076 inCrlInitFile = PR_STDIN; |
|
1077 rv = GenerateCRL (certHandle, nickName, inCrlInitFile, |
|
1078 inFile, outFile, ascii, slotName, |
|
1079 importOptions, alg, quiet, |
|
1080 decodeOptions, url, &pwdata, |
|
1081 modifyCRL); |
|
1082 } |
|
1083 else if (erase) { |
|
1084 /* list and delete all CRLs */ |
|
1085 ListCRLNames (certHandle, crlType, PR_TRUE); |
|
1086 } |
|
1087 #ifdef DEBUG |
|
1088 else if (test) { |
|
1089 /* list and delete all CRLs */ |
|
1090 ListCRLNames (certHandle, crlType, PR_TRUE); |
|
1091 /* list CRLs */ |
|
1092 ListCRLNames (certHandle, crlType, PR_FALSE); |
|
1093 /* import CRL as a blob */ |
|
1094 rv = ImportCRL (certHandle, url, crlType, inFile, importOptions, |
|
1095 decodeOptions, &pwdata); |
|
1096 /* list CRLs */ |
|
1097 ListCRLNames (certHandle, crlType, PR_FALSE); |
|
1098 } |
|
1099 #endif |
|
1100 } |
|
1101 |
|
1102 CRLGEN_DestroyCrlGenParserLock(); |
|
1103 |
|
1104 if (NSS_Shutdown() != SECSuccess) { |
|
1105 rv = SECFailure; |
|
1106 } |
|
1107 |
|
1108 return (rv != SECSuccess); |
|
1109 } |