|
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 * Test program for client-side OCSP. |
|
7 */ |
|
8 |
|
9 #include "secutil.h" |
|
10 #include "nspr.h" |
|
11 #include "plgetopt.h" |
|
12 #include "nss.h" |
|
13 #include "cert.h" |
|
14 #include "ocsp.h" |
|
15 #include "xconst.h" /* |
|
16 * XXX internal header file; needed to get at |
|
17 * cert_DecodeAuthInfoAccessExtension -- would be |
|
18 * nice to not need this, but that would require |
|
19 * better/different APIs. |
|
20 */ |
|
21 |
|
22 #ifndef NO_PP /* |
|
23 * Compile with this every once in a while to be |
|
24 * sure that no dependencies on it get added |
|
25 * outside of the pretty-printing routines. |
|
26 */ |
|
27 #include "ocspti.h" /* internals for pretty-printing routines *only* */ |
|
28 #endif /* NO_PP */ |
|
29 |
|
30 #if defined(_WIN32) |
|
31 #include "fcntl.h" |
|
32 #include "io.h" |
|
33 #endif |
|
34 |
|
35 #define DEFAULT_DB_DIR "~/.netscape" |
|
36 |
|
37 /* global */ |
|
38 char *program_name; |
|
39 |
|
40 |
|
41 static void |
|
42 synopsis (char *program_name) |
|
43 { |
|
44 PRFileDesc *pr_stderr; |
|
45 |
|
46 pr_stderr = PR_STDERR; |
|
47 PR_fprintf (pr_stderr, "Usage:"); |
|
48 PR_fprintf (pr_stderr, |
|
49 "\t%s -p [-d <dir>]\n", |
|
50 program_name); |
|
51 PR_fprintf (pr_stderr, |
|
52 "\t%s -P [-d <dir>]\n", |
|
53 program_name); |
|
54 PR_fprintf (pr_stderr, |
|
55 "\t%s -r <name> [-a] [-L] [-s <name>] [-d <dir>]\n", |
|
56 program_name); |
|
57 PR_fprintf (pr_stderr, |
|
58 "\t%s -R <name> [-a] [-l <location>] [-s <name>] [-d <dir>]\n", |
|
59 program_name); |
|
60 PR_fprintf (pr_stderr, |
|
61 "\t%s -S <name> [-a] [-l <location> -t <name>]\n", |
|
62 program_name); |
|
63 PR_fprintf (pr_stderr, |
|
64 "\t\t [-s <name>] [-w <time>] [-d <dir>]\n"); |
|
65 PR_fprintf (pr_stderr, |
|
66 "\t%s -V <name> [-a] -u <usage> [-l <location> -t <name>]\n", |
|
67 program_name); |
|
68 PR_fprintf (pr_stderr, |
|
69 "\t\t [-s <name>] [-w <time>] [-d <dir>]\n"); |
|
70 } |
|
71 |
|
72 |
|
73 static void |
|
74 short_usage (char *program_name) |
|
75 { |
|
76 PR_fprintf (PR_STDERR, |
|
77 "Type %s -H for more detailed descriptions\n", |
|
78 program_name); |
|
79 synopsis (program_name); |
|
80 } |
|
81 |
|
82 |
|
83 static void |
|
84 long_usage (char *program_name) |
|
85 { |
|
86 PRFileDesc *pr_stderr; |
|
87 |
|
88 pr_stderr = PR_STDERR; |
|
89 synopsis (program_name); |
|
90 PR_fprintf (pr_stderr, "\nCommands (must specify exactly one):\n"); |
|
91 PR_fprintf (pr_stderr, |
|
92 " %-13s Pretty-print a binary request read from stdin\n", |
|
93 "-p"); |
|
94 PR_fprintf (pr_stderr, |
|
95 " %-13s Pretty-print a binary response read from stdin\n", |
|
96 "-P"); |
|
97 PR_fprintf (pr_stderr, |
|
98 " %-13s Create a request for cert \"nickname\" on stdout\n", |
|
99 "-r nickname"); |
|
100 PR_fprintf (pr_stderr, |
|
101 " %-13s Get response for cert \"nickname\", dump to stdout\n", |
|
102 "-R nickname"); |
|
103 PR_fprintf (pr_stderr, |
|
104 " %-13s Get status for cert \"nickname\"\n", |
|
105 "-S nickname"); |
|
106 PR_fprintf (pr_stderr, |
|
107 " %-13s Fully verify cert \"nickname\", w/ status check\n", |
|
108 "-V nickname"); |
|
109 PR_fprintf (pr_stderr, |
|
110 "\n %-10s also can be the name of the file with DER or\n" |
|
111 " %-13s PEM(use -a option) cert encoding\n", "nickname", ""); |
|
112 PR_fprintf (pr_stderr, "Options:\n"); |
|
113 PR_fprintf (pr_stderr, |
|
114 " %-13s Decode input cert from PEM format. DER is default\n", |
|
115 "-a"); |
|
116 PR_fprintf (pr_stderr, |
|
117 " %-13s Add the service locator extension to the request\n", |
|
118 "-L"); |
|
119 PR_fprintf (pr_stderr, |
|
120 " %-13s Find security databases in \"dbdir\" (default %s)\n", |
|
121 "-d dbdir", DEFAULT_DB_DIR); |
|
122 PR_fprintf (pr_stderr, |
|
123 " %-13s Use \"location\" as URL of responder\n", |
|
124 "-l location"); |
|
125 PR_fprintf (pr_stderr, |
|
126 " %-13s Trust cert \"nickname\" as response signer\n", |
|
127 "-t nickname"); |
|
128 PR_fprintf (pr_stderr, |
|
129 " %-13s Sign requests with cert \"nickname\"\n", |
|
130 "-s nickname"); |
|
131 PR_fprintf (pr_stderr, |
|
132 " %-13s Type of certificate usage for verification:\n", |
|
133 "-u usage"); |
|
134 PR_fprintf (pr_stderr, |
|
135 "%-17s c SSL Client\n", ""); |
|
136 PR_fprintf (pr_stderr, |
|
137 "%-17s s SSL Server\n", ""); |
|
138 PR_fprintf (pr_stderr, |
|
139 "%-17s e Email Recipient\n", ""); |
|
140 PR_fprintf (pr_stderr, |
|
141 "%-17s E Email Signer\n", ""); |
|
142 PR_fprintf (pr_stderr, |
|
143 "%-17s S Object Signer\n", ""); |
|
144 PR_fprintf (pr_stderr, |
|
145 "%-17s C CA\n", ""); |
|
146 PR_fprintf (pr_stderr, |
|
147 " %-13s Validity time (default current time), one of:\n", |
|
148 "-w time"); |
|
149 PR_fprintf (pr_stderr, |
|
150 "%-17s %-25s (GMT)\n", "", "YYMMDDhhmm[ss]Z"); |
|
151 PR_fprintf (pr_stderr, |
|
152 "%-17s %-25s (later than GMT)\n", "", "YYMMDDhhmm[ss]+hhmm"); |
|
153 PR_fprintf (pr_stderr, |
|
154 "%-17s %-25s (earlier than GMT)\n", "", "YYMMDDhhmm[ss]-hhmm"); |
|
155 } |
|
156 |
|
157 #if defined(WIN32) |
|
158 /* We're going to write binary data to stdout, or read binary from stdin. |
|
159 * We must put stdout or stdin into O_BINARY mode or else |
|
160 outgoing \n's will become \r\n's, and incoming \r\n's will become \n's. |
|
161 */ |
|
162 static SECStatus |
|
163 make_file_binary(FILE * binfile) |
|
164 { |
|
165 int smrv = _setmode(_fileno(binfile), _O_BINARY); |
|
166 if (smrv == -1) { |
|
167 fprintf(stderr, "%s: Cannot change stdout to binary mode.\n", |
|
168 program_name); |
|
169 } |
|
170 return smrv; |
|
171 } |
|
172 #define MAKE_FILE_BINARY make_file_binary |
|
173 #else |
|
174 #define MAKE_FILE_BINARY(file) |
|
175 #endif |
|
176 |
|
177 /* |
|
178 * XXX This is a generic function that would probably make a good |
|
179 * replacement for SECU_DER_Read (which is not at all specific to DER, |
|
180 * despite its name), but that requires fixing all of the tools... |
|
181 * Still, it should be done, whenenver I/somebody has the time. |
|
182 * (Also, consider whether this actually belongs in the security |
|
183 * library itself, not just in the command library.) |
|
184 * |
|
185 * This function takes an open file (a PRFileDesc *) and reads the |
|
186 * entire file into a SECItem. (Obviously, the file is intended to |
|
187 * be small enough that such a thing is advisable.) Both the SECItem |
|
188 * and the buffer it points to are allocated from the heap; the caller |
|
189 * is expected to free them. ("SECITEM_FreeItem(item, PR_TRUE)") |
|
190 */ |
|
191 static SECItem * |
|
192 read_file_into_item (PRFileDesc *in_file, SECItemType si_type) |
|
193 { |
|
194 PRStatus prv; |
|
195 SECItem *item; |
|
196 PRFileInfo file_info; |
|
197 PRInt32 bytes_read; |
|
198 |
|
199 prv = PR_GetOpenFileInfo (in_file, &file_info); |
|
200 if (prv != PR_SUCCESS) |
|
201 return NULL; |
|
202 |
|
203 if (file_info.size == 0) { |
|
204 /* XXX Need a better error; just grabbed this one for expediency. */ |
|
205 PORT_SetError (SEC_ERROR_INPUT_LEN); |
|
206 return NULL; |
|
207 } |
|
208 |
|
209 if (file_info.size > 0xffff) { /* I think this is too big. */ |
|
210 PORT_SetError (SEC_ERROR_NO_MEMORY); |
|
211 return NULL; |
|
212 } |
|
213 |
|
214 item = PORT_Alloc (sizeof (SECItem)); |
|
215 if (item == NULL) |
|
216 return NULL; |
|
217 |
|
218 item->type = si_type; |
|
219 item->len = (unsigned int) file_info.size; |
|
220 item->data = PORT_Alloc ((size_t)item->len); |
|
221 if (item->data == NULL) |
|
222 goto loser; |
|
223 |
|
224 bytes_read = PR_Read (in_file, item->data, (PRInt32) item->len); |
|
225 if (bytes_read < 0) { |
|
226 /* Something went wrong; error is already set for us. */ |
|
227 goto loser; |
|
228 } else if (bytes_read == 0) { |
|
229 /* Something went wrong; we read nothing. But no system/nspr error. */ |
|
230 /* XXX Need to set an error here. */ |
|
231 goto loser; |
|
232 } else if (item->len != (unsigned int)bytes_read) { |
|
233 /* Something went wrong; we read less (or more!?) than we expected. */ |
|
234 /* XXX Need to set an error here. */ |
|
235 goto loser; |
|
236 } |
|
237 |
|
238 return item; |
|
239 |
|
240 loser: |
|
241 SECITEM_FreeItem (item, PR_TRUE); |
|
242 return NULL; |
|
243 } |
|
244 |
|
245 |
|
246 /* |
|
247 * Create a DER-encoded OCSP request (for the certificate whose nickname |
|
248 * is "name") and dump it out. |
|
249 */ |
|
250 static SECStatus |
|
251 create_request (FILE *out_file, CERTCertDBHandle *handle, CERTCertificate *cert, |
|
252 PRBool add_service_locator, PRBool add_acceptable_responses) |
|
253 { |
|
254 CERTCertList *certs = NULL; |
|
255 CERTCertificate *myCert = NULL; |
|
256 CERTOCSPRequest *request = NULL; |
|
257 PRTime now = PR_Now(); |
|
258 SECItem *encoding = NULL; |
|
259 SECStatus rv = SECFailure; |
|
260 |
|
261 if (handle == NULL || cert == NULL) |
|
262 return rv; |
|
263 |
|
264 myCert = CERT_DupCertificate(cert); |
|
265 if (myCert == NULL) |
|
266 goto loser; |
|
267 |
|
268 /* |
|
269 * We need to create a list of one. |
|
270 */ |
|
271 certs = CERT_NewCertList(); |
|
272 if (certs == NULL) |
|
273 goto loser; |
|
274 |
|
275 if (CERT_AddCertToListTail (certs, myCert) != SECSuccess) |
|
276 goto loser; |
|
277 |
|
278 /* |
|
279 * Now that cert is included in the list, we need to be careful |
|
280 * that we do not try to destroy it twice. This will prevent that. |
|
281 */ |
|
282 myCert = NULL; |
|
283 |
|
284 request = CERT_CreateOCSPRequest (certs, now, add_service_locator, NULL); |
|
285 if (request == NULL) |
|
286 goto loser; |
|
287 |
|
288 if (add_acceptable_responses) { |
|
289 rv = CERT_AddOCSPAcceptableResponses(request, |
|
290 SEC_OID_PKIX_OCSP_BASIC_RESPONSE); |
|
291 if (rv != SECSuccess) |
|
292 goto loser; |
|
293 } |
|
294 |
|
295 encoding = CERT_EncodeOCSPRequest (NULL, request, NULL); |
|
296 if (encoding == NULL) |
|
297 goto loser; |
|
298 |
|
299 MAKE_FILE_BINARY(out_file); |
|
300 if (fwrite (encoding->data, encoding->len, 1, out_file) != 1) |
|
301 goto loser; |
|
302 |
|
303 rv = SECSuccess; |
|
304 |
|
305 loser: |
|
306 if (encoding != NULL) |
|
307 SECITEM_FreeItem(encoding, PR_TRUE); |
|
308 if (request != NULL) |
|
309 CERT_DestroyOCSPRequest(request); |
|
310 if (certs != NULL) |
|
311 CERT_DestroyCertList (certs); |
|
312 if (myCert != NULL) |
|
313 CERT_DestroyCertificate(myCert); |
|
314 |
|
315 return rv; |
|
316 } |
|
317 |
|
318 |
|
319 /* |
|
320 * Create a DER-encoded OCSP request (for the certificate whose nickname is |
|
321 * "cert_name"), then get and dump a corresponding response. The responder |
|
322 * location is either specified explicitly (as "responder_url") or found |
|
323 * via the AuthorityInfoAccess URL in the cert. |
|
324 */ |
|
325 static SECStatus |
|
326 dump_response (FILE *out_file, CERTCertDBHandle *handle, CERTCertificate *cert, |
|
327 const char *responder_url) |
|
328 { |
|
329 CERTCertList *certs = NULL; |
|
330 CERTCertificate *myCert = NULL; |
|
331 char *loc = NULL; |
|
332 PRTime now = PR_Now(); |
|
333 SECItem *response = NULL; |
|
334 SECStatus rv = SECFailure; |
|
335 PRBool includeServiceLocator; |
|
336 |
|
337 if (handle == NULL || cert == NULL) |
|
338 return rv; |
|
339 |
|
340 myCert = CERT_DupCertificate(cert); |
|
341 if (myCert == NULL) |
|
342 goto loser; |
|
343 |
|
344 if (responder_url != NULL) { |
|
345 loc = (char *) responder_url; |
|
346 includeServiceLocator = PR_TRUE; |
|
347 } else { |
|
348 loc = CERT_GetOCSPAuthorityInfoAccessLocation (cert); |
|
349 if (loc == NULL) |
|
350 goto loser; |
|
351 includeServiceLocator = PR_FALSE; |
|
352 } |
|
353 |
|
354 /* |
|
355 * We need to create a list of one. |
|
356 */ |
|
357 certs = CERT_NewCertList(); |
|
358 if (certs == NULL) |
|
359 goto loser; |
|
360 |
|
361 if (CERT_AddCertToListTail (certs, myCert) != SECSuccess) |
|
362 goto loser; |
|
363 |
|
364 /* |
|
365 * Now that cert is included in the list, we need to be careful |
|
366 * that we do not try to destroy it twice. This will prevent that. |
|
367 */ |
|
368 myCert = NULL; |
|
369 |
|
370 response = CERT_GetEncodedOCSPResponse (NULL, certs, loc, now, |
|
371 includeServiceLocator, |
|
372 NULL, NULL, NULL); |
|
373 if (response == NULL) |
|
374 goto loser; |
|
375 |
|
376 MAKE_FILE_BINARY(out_file); |
|
377 if (fwrite (response->data, response->len, 1, out_file) != 1) |
|
378 goto loser; |
|
379 |
|
380 rv = SECSuccess; |
|
381 |
|
382 loser: |
|
383 if (response != NULL) |
|
384 SECITEM_FreeItem (response, PR_TRUE); |
|
385 if (certs != NULL) |
|
386 CERT_DestroyCertList (certs); |
|
387 if (myCert != NULL) |
|
388 CERT_DestroyCertificate(myCert); |
|
389 if (loc != NULL && loc != responder_url) |
|
390 PORT_Free (loc); |
|
391 |
|
392 return rv; |
|
393 } |
|
394 |
|
395 |
|
396 /* |
|
397 * Get the status for the specified certificate (whose nickname is "cert_name"). |
|
398 * Directly use the OCSP function rather than doing a full verification. |
|
399 */ |
|
400 static SECStatus |
|
401 get_cert_status (FILE *out_file, CERTCertDBHandle *handle, |
|
402 CERTCertificate *cert, const char *cert_name, |
|
403 PRTime verify_time) |
|
404 { |
|
405 SECStatus rv = SECFailure; |
|
406 |
|
407 if (handle == NULL || cert == NULL) |
|
408 goto loser; |
|
409 |
|
410 rv = CERT_CheckOCSPStatus (handle, cert, verify_time, NULL); |
|
411 |
|
412 fprintf (out_file, "Check of certificate \"%s\" ", cert_name); |
|
413 if (rv == SECSuccess) { |
|
414 fprintf (out_file, "succeeded.\n"); |
|
415 } else { |
|
416 const char *error_string = SECU_Strerror(PORT_GetError()); |
|
417 fprintf (out_file, "failed. Reason:\n"); |
|
418 if (error_string != NULL && PORT_Strlen(error_string) > 0) |
|
419 fprintf (out_file, "%s\n", error_string); |
|
420 else |
|
421 fprintf (out_file, "Unknown\n"); |
|
422 } |
|
423 |
|
424 rv = SECSuccess; |
|
425 |
|
426 loser: |
|
427 |
|
428 return rv; |
|
429 } |
|
430 |
|
431 |
|
432 /* |
|
433 * Verify the specified certificate (whose nickname is "cert_name"). |
|
434 * OCSP is already turned on, so we just need to call the standard |
|
435 * certificate verification API and let it do all the work. |
|
436 */ |
|
437 static SECStatus |
|
438 verify_cert (FILE *out_file, CERTCertDBHandle *handle, CERTCertificate *cert, |
|
439 const char *cert_name, SECCertUsage cert_usage, PRTime verify_time) |
|
440 { |
|
441 SECStatus rv = SECFailure; |
|
442 |
|
443 if (handle == NULL || cert == NULL) |
|
444 return rv; |
|
445 |
|
446 rv = CERT_VerifyCert (handle, cert, PR_TRUE, cert_usage, verify_time, |
|
447 NULL, NULL); |
|
448 |
|
449 fprintf (out_file, "Verification of certificate \"%s\" ", cert_name); |
|
450 if (rv == SECSuccess) { |
|
451 fprintf (out_file, "succeeded.\n"); |
|
452 } else { |
|
453 const char *error_string = SECU_Strerror(PORT_GetError()); |
|
454 fprintf (out_file, "failed. Reason:\n"); |
|
455 if (error_string != NULL && PORT_Strlen(error_string) > 0) |
|
456 fprintf (out_file, "%s\n", error_string); |
|
457 else |
|
458 fprintf (out_file, "Unknown\n"); |
|
459 } |
|
460 |
|
461 rv = SECSuccess; |
|
462 |
|
463 return rv; |
|
464 } |
|
465 |
|
466 CERTCertificate* |
|
467 find_certificate(CERTCertDBHandle *handle, const char *name, PRBool ascii) |
|
468 { |
|
469 CERTCertificate *cert = NULL; |
|
470 SECItem der; |
|
471 PRFileDesc *certFile; |
|
472 |
|
473 if (handle == NULL || name == NULL) |
|
474 return NULL; |
|
475 |
|
476 if (ascii == PR_FALSE) { |
|
477 /* by default need to check if there is cert nick is given */ |
|
478 cert = CERT_FindCertByNicknameOrEmailAddr (handle, (char *) name); |
|
479 if (cert != NULL) |
|
480 return cert; |
|
481 } |
|
482 |
|
483 certFile = PR_Open(name, PR_RDONLY, 0); |
|
484 if (certFile == NULL) { |
|
485 return NULL; |
|
486 } |
|
487 |
|
488 if (SECU_ReadDERFromFile(&der, certFile, ascii, PR_FALSE) == SECSuccess) { |
|
489 cert = CERT_DecodeCertFromPackage((char*)der.data, der.len); |
|
490 SECITEM_FreeItem(&der, PR_FALSE); |
|
491 } |
|
492 PR_Close(certFile); |
|
493 |
|
494 return cert; |
|
495 } |
|
496 |
|
497 |
|
498 #ifdef NO_PP |
|
499 |
|
500 static SECStatus |
|
501 print_request (FILE *out_file, SECItem *data) |
|
502 { |
|
503 fprintf (out_file, "Cannot pretty-print request compiled with NO_PP.\n"); |
|
504 return SECSuccess; |
|
505 } |
|
506 |
|
507 static SECStatus |
|
508 print_response (FILE *out_file, SECItem *data, CERTCertDBHandle *handle) |
|
509 { |
|
510 fprintf (out_file, "Cannot pretty-print response compiled with NO_PP.\n"); |
|
511 return SECSuccess; |
|
512 } |
|
513 |
|
514 #else /* NO_PP */ |
|
515 |
|
516 static void |
|
517 print_ocsp_version (FILE *out_file, SECItem *version, int level) |
|
518 { |
|
519 if (version->len > 0) { |
|
520 SECU_PrintInteger (out_file, version, "Version", level); |
|
521 } else { |
|
522 SECU_Indent (out_file, level); |
|
523 fprintf (out_file, "Version: DEFAULT\n"); |
|
524 } |
|
525 } |
|
526 |
|
527 |
|
528 static void |
|
529 print_ocsp_cert_id (FILE *out_file, CERTOCSPCertID *cert_id, int level) |
|
530 { |
|
531 SECU_Indent (out_file, level); |
|
532 fprintf (out_file, "Cert ID:\n"); |
|
533 level++; |
|
534 |
|
535 SECU_PrintAlgorithmID (out_file, &(cert_id->hashAlgorithm), |
|
536 "Hash Algorithm", level); |
|
537 SECU_PrintAsHex (out_file, &(cert_id->issuerNameHash), |
|
538 "Issuer Name Hash", level); |
|
539 SECU_PrintAsHex (out_file, &(cert_id->issuerKeyHash), |
|
540 "Issuer Key Hash", level); |
|
541 SECU_PrintInteger (out_file, &(cert_id->serialNumber), |
|
542 "Serial Number", level); |
|
543 /* XXX lookup the cert; if found, print something nice (nickname?) */ |
|
544 } |
|
545 |
|
546 |
|
547 static void |
|
548 print_raw_certificates (FILE *out_file, SECItem **raw_certs, int level) |
|
549 { |
|
550 SECItem *raw_cert; |
|
551 int i = 0; |
|
552 char cert_label[50]; |
|
553 |
|
554 SECU_Indent (out_file, level); |
|
555 |
|
556 if (raw_certs == NULL) { |
|
557 fprintf (out_file, "No Certificates.\n"); |
|
558 return; |
|
559 } |
|
560 |
|
561 fprintf (out_file, "Certificate List:\n"); |
|
562 while ((raw_cert = raw_certs[i++]) != NULL) { |
|
563 sprintf (cert_label, "Certificate (%d)", i); |
|
564 (void) SECU_PrintSignedData (out_file, raw_cert, cert_label, level + 1, |
|
565 SECU_PrintCertificate); |
|
566 } |
|
567 } |
|
568 |
|
569 |
|
570 static void |
|
571 print_ocsp_extensions (FILE *out_file, CERTCertExtension **extensions, |
|
572 char *msg, int level) |
|
573 { |
|
574 if (extensions) { |
|
575 SECU_PrintExtensions (out_file, extensions, msg, level); |
|
576 } else { |
|
577 SECU_Indent (out_file, level); |
|
578 fprintf (out_file, "No %s\n", msg); |
|
579 } |
|
580 } |
|
581 |
|
582 |
|
583 static void |
|
584 print_single_request (FILE *out_file, ocspSingleRequest *single, int level) |
|
585 { |
|
586 print_ocsp_cert_id (out_file, single->reqCert, level); |
|
587 print_ocsp_extensions (out_file, single->singleRequestExtensions, |
|
588 "Single Request Extensions", level); |
|
589 } |
|
590 |
|
591 |
|
592 /* |
|
593 * Decode the DER/BER-encoded item "data" as an OCSP request |
|
594 * and pretty-print the subfields. |
|
595 */ |
|
596 static SECStatus |
|
597 print_request (FILE *out_file, SECItem *data) |
|
598 { |
|
599 CERTOCSPRequest *request; |
|
600 ocspTBSRequest *tbsRequest; |
|
601 int level = 0; |
|
602 |
|
603 PORT_Assert (out_file != NULL); |
|
604 PORT_Assert (data != NULL); |
|
605 if (out_file == NULL || data == NULL) { |
|
606 PORT_SetError (SEC_ERROR_INVALID_ARGS); |
|
607 return SECFailure; |
|
608 } |
|
609 |
|
610 request = CERT_DecodeOCSPRequest (data); |
|
611 if (request == NULL || request->tbsRequest == NULL) |
|
612 return SECFailure; |
|
613 |
|
614 tbsRequest = request->tbsRequest; |
|
615 |
|
616 fprintf (out_file, "TBS Request:\n"); |
|
617 level++; |
|
618 |
|
619 print_ocsp_version (out_file, &(tbsRequest->version), level); |
|
620 |
|
621 /* |
|
622 * XXX Probably should be an interface to get the signer name |
|
623 * without looking inside the tbsRequest at all. |
|
624 */ |
|
625 if (tbsRequest->requestorName != NULL) { |
|
626 SECU_Indent (out_file, level); |
|
627 fprintf (out_file, "XXX print the requestorName\n"); |
|
628 } else { |
|
629 SECU_Indent (out_file, level); |
|
630 fprintf (out_file, "No Requestor Name.\n"); |
|
631 } |
|
632 |
|
633 if (tbsRequest->requestList != NULL) { |
|
634 int i; |
|
635 |
|
636 for (i = 0; tbsRequest->requestList[i] != NULL; i++) { |
|
637 SECU_Indent (out_file, level); |
|
638 fprintf (out_file, "Request %d:\n", i); |
|
639 print_single_request (out_file, tbsRequest->requestList[i], |
|
640 level + 1); |
|
641 } |
|
642 } else { |
|
643 fprintf (out_file, "Request list is empty.\n"); |
|
644 } |
|
645 |
|
646 print_ocsp_extensions (out_file, tbsRequest->requestExtensions, |
|
647 "Request Extensions", level); |
|
648 |
|
649 if (request->optionalSignature != NULL) { |
|
650 ocspSignature *whole_sig; |
|
651 SECItem rawsig; |
|
652 |
|
653 fprintf (out_file, "Signature:\n"); |
|
654 |
|
655 whole_sig = request->optionalSignature; |
|
656 SECU_PrintAlgorithmID (out_file, &(whole_sig->signatureAlgorithm), |
|
657 "Signature Algorithm", level); |
|
658 |
|
659 rawsig = whole_sig->signature; |
|
660 DER_ConvertBitString (&rawsig); |
|
661 SECU_PrintAsHex (out_file, &rawsig, "Signature", level); |
|
662 |
|
663 print_raw_certificates (out_file, whole_sig->derCerts, level); |
|
664 |
|
665 fprintf (out_file, "XXX verify the sig and print result\n"); |
|
666 } else { |
|
667 fprintf (out_file, "No Signature\n"); |
|
668 } |
|
669 |
|
670 CERT_DestroyOCSPRequest (request); |
|
671 return SECSuccess; |
|
672 } |
|
673 |
|
674 |
|
675 static void |
|
676 print_revoked_info (FILE *out_file, ocspRevokedInfo *revoked_info, int level) |
|
677 { |
|
678 SECU_PrintGeneralizedTime (out_file, &(revoked_info->revocationTime), |
|
679 "Revocation Time", level); |
|
680 |
|
681 if (revoked_info->revocationReason != NULL) { |
|
682 SECU_PrintAsHex (out_file, revoked_info->revocationReason, |
|
683 "Revocation Reason", level); |
|
684 } else { |
|
685 SECU_Indent (out_file, level); |
|
686 fprintf (out_file, "No Revocation Reason.\n"); |
|
687 } |
|
688 } |
|
689 |
|
690 |
|
691 static void |
|
692 print_cert_status (FILE *out_file, ocspCertStatus *status, int level) |
|
693 { |
|
694 SECU_Indent (out_file, level); |
|
695 fprintf (out_file, "Status: "); |
|
696 |
|
697 switch (status->certStatusType) { |
|
698 case ocspCertStatus_good: |
|
699 fprintf (out_file, "Cert is good.\n"); |
|
700 break; |
|
701 case ocspCertStatus_revoked: |
|
702 fprintf (out_file, "Cert has been revoked.\n"); |
|
703 print_revoked_info (out_file, status->certStatusInfo.revokedInfo, |
|
704 level + 1); |
|
705 break; |
|
706 case ocspCertStatus_unknown: |
|
707 fprintf (out_file, "Cert is unknown to responder.\n"); |
|
708 break; |
|
709 default: |
|
710 fprintf (out_file, "Unrecognized status.\n"); |
|
711 break; |
|
712 } |
|
713 } |
|
714 |
|
715 |
|
716 static void |
|
717 print_single_response (FILE *out_file, CERTOCSPSingleResponse *single, |
|
718 int level) |
|
719 { |
|
720 print_ocsp_cert_id (out_file, single->certID, level); |
|
721 |
|
722 print_cert_status (out_file, single->certStatus, level); |
|
723 |
|
724 SECU_PrintGeneralizedTime (out_file, &(single->thisUpdate), |
|
725 "This Update", level); |
|
726 |
|
727 if (single->nextUpdate != NULL) { |
|
728 SECU_PrintGeneralizedTime (out_file, single->nextUpdate, |
|
729 "Next Update", level); |
|
730 } else { |
|
731 SECU_Indent (out_file, level); |
|
732 fprintf (out_file, "No Next Update\n"); |
|
733 } |
|
734 |
|
735 print_ocsp_extensions (out_file, single->singleExtensions, |
|
736 "Single Response Extensions", level); |
|
737 } |
|
738 |
|
739 |
|
740 static void |
|
741 print_responder_id (FILE *out_file, ocspResponderID *responderID, int level) |
|
742 { |
|
743 SECU_Indent (out_file, level); |
|
744 fprintf (out_file, "Responder ID "); |
|
745 |
|
746 switch (responderID->responderIDType) { |
|
747 case ocspResponderID_byName: |
|
748 fprintf (out_file, "(byName):\n"); |
|
749 SECU_PrintName (out_file, &(responderID->responderIDValue.name), |
|
750 "Name", level + 1); |
|
751 break; |
|
752 case ocspResponderID_byKey: |
|
753 fprintf (out_file, "(byKey):\n"); |
|
754 SECU_PrintAsHex (out_file, &(responderID->responderIDValue.keyHash), |
|
755 "Key Hash", level + 1); |
|
756 break; |
|
757 default: |
|
758 fprintf (out_file, "Unrecognized Responder ID Type\n"); |
|
759 break; |
|
760 } |
|
761 } |
|
762 |
|
763 |
|
764 static void |
|
765 print_response_data (FILE *out_file, ocspResponseData *responseData, int level) |
|
766 { |
|
767 SECU_Indent (out_file, level); |
|
768 fprintf (out_file, "Response Data:\n"); |
|
769 level++; |
|
770 |
|
771 print_ocsp_version (out_file, &(responseData->version), level); |
|
772 |
|
773 print_responder_id (out_file, responseData->responderID, level); |
|
774 |
|
775 SECU_PrintGeneralizedTime (out_file, &(responseData->producedAt), |
|
776 "Produced At", level); |
|
777 |
|
778 if (responseData->responses != NULL) { |
|
779 int i; |
|
780 |
|
781 for (i = 0; responseData->responses[i] != NULL; i++) { |
|
782 SECU_Indent (out_file, level); |
|
783 fprintf (out_file, "Response %d:\n", i); |
|
784 print_single_response (out_file, responseData->responses[i], |
|
785 level + 1); |
|
786 } |
|
787 } else { |
|
788 fprintf (out_file, "Response list is empty.\n"); |
|
789 } |
|
790 |
|
791 print_ocsp_extensions (out_file, responseData->responseExtensions, |
|
792 "Response Extensions", level); |
|
793 } |
|
794 |
|
795 |
|
796 static void |
|
797 print_basic_response (FILE *out_file, ocspBasicOCSPResponse *basic, int level) |
|
798 { |
|
799 SECItem rawsig; |
|
800 |
|
801 SECU_Indent (out_file, level); |
|
802 fprintf (out_file, "Basic OCSP Response:\n"); |
|
803 level++; |
|
804 |
|
805 print_response_data (out_file, basic->tbsResponseData, level); |
|
806 |
|
807 SECU_PrintAlgorithmID (out_file, |
|
808 &(basic->responseSignature.signatureAlgorithm), |
|
809 "Signature Algorithm", level); |
|
810 |
|
811 rawsig = basic->responseSignature.signature; |
|
812 DER_ConvertBitString (&rawsig); |
|
813 SECU_PrintAsHex (out_file, &rawsig, "Signature", level); |
|
814 |
|
815 print_raw_certificates (out_file, basic->responseSignature.derCerts, level); |
|
816 } |
|
817 |
|
818 |
|
819 /* |
|
820 * Note this must match (exactly) the enumeration ocspResponseStatus. |
|
821 */ |
|
822 static char *responseStatusNames[] = { |
|
823 "successful (Response has valid confirmations)", |
|
824 "malformedRequest (Illegal confirmation request)", |
|
825 "internalError (Internal error in issuer)", |
|
826 "tryLater (Try again later)", |
|
827 "unused ((4) is not used)", |
|
828 "sigRequired (Must sign the request)", |
|
829 "unauthorized (Request unauthorized)" |
|
830 }; |
|
831 |
|
832 /* |
|
833 * Decode the DER/BER-encoded item "data" as an OCSP response |
|
834 * and pretty-print the subfields. |
|
835 */ |
|
836 static SECStatus |
|
837 print_response (FILE *out_file, SECItem *data, CERTCertDBHandle *handle) |
|
838 { |
|
839 CERTOCSPResponse *response; |
|
840 int level = 0; |
|
841 |
|
842 PORT_Assert (out_file != NULL); |
|
843 PORT_Assert (data != NULL); |
|
844 if (out_file == NULL || data == NULL) { |
|
845 PORT_SetError (SEC_ERROR_INVALID_ARGS); |
|
846 return SECFailure; |
|
847 } |
|
848 |
|
849 response = CERT_DecodeOCSPResponse (data); |
|
850 if (response == NULL) |
|
851 return SECFailure; |
|
852 |
|
853 if (response->statusValue >= ocspResponse_min && |
|
854 response->statusValue <= ocspResponse_max) { |
|
855 fprintf (out_file, "Response Status: %s\n", |
|
856 responseStatusNames[response->statusValue]); |
|
857 } else { |
|
858 fprintf (out_file, |
|
859 "Response Status: other (Status value %d out of defined range)\n", |
|
860 (int)response->statusValue); |
|
861 } |
|
862 |
|
863 if (response->statusValue == ocspResponse_successful) { |
|
864 ocspResponseBytes *responseBytes = response->responseBytes; |
|
865 SECStatus sigStatus; |
|
866 CERTCertificate *signerCert = NULL; |
|
867 |
|
868 PORT_Assert (responseBytes != NULL); |
|
869 |
|
870 level++; |
|
871 fprintf (out_file, "Response Bytes:\n"); |
|
872 SECU_PrintObjectID (out_file, &(responseBytes->responseType), |
|
873 "Response Type", level); |
|
874 switch (response->responseBytes->responseTypeTag) { |
|
875 case SEC_OID_PKIX_OCSP_BASIC_RESPONSE: |
|
876 print_basic_response (out_file, |
|
877 responseBytes->decodedResponse.basic, |
|
878 level); |
|
879 break; |
|
880 default: |
|
881 SECU_Indent (out_file, level); |
|
882 fprintf (out_file, "Unknown response syntax\n"); |
|
883 break; |
|
884 } |
|
885 |
|
886 sigStatus = CERT_VerifyOCSPResponseSignature (response, handle, |
|
887 NULL, &signerCert, NULL); |
|
888 SECU_Indent (out_file, level); |
|
889 fprintf (out_file, "Signature verification "); |
|
890 if (sigStatus != SECSuccess) { |
|
891 fprintf (out_file, "failed: %s\n", SECU_Strerror (PORT_GetError())); |
|
892 } else { |
|
893 fprintf (out_file, "succeeded.\n"); |
|
894 if (signerCert != NULL) { |
|
895 SECU_PrintName (out_file, &signerCert->subject, "Signer", |
|
896 level); |
|
897 CERT_DestroyCertificate (signerCert); |
|
898 } else { |
|
899 SECU_Indent (out_file, level); |
|
900 fprintf (out_file, "No signer cert returned?\n"); |
|
901 } |
|
902 } |
|
903 } else { |
|
904 SECU_Indent (out_file, level); |
|
905 fprintf (out_file, "Unsuccessful response, no more information.\n"); |
|
906 } |
|
907 |
|
908 CERT_DestroyOCSPResponse (response); |
|
909 return SECSuccess; |
|
910 } |
|
911 |
|
912 #endif /* NO_PP */ |
|
913 |
|
914 |
|
915 static SECStatus |
|
916 cert_usage_from_char (const char *cert_usage_str, SECCertUsage *cert_usage) |
|
917 { |
|
918 PORT_Assert (cert_usage_str != NULL); |
|
919 PORT_Assert (cert_usage != NULL); |
|
920 |
|
921 if (PORT_Strlen (cert_usage_str) != 1) |
|
922 return SECFailure; |
|
923 |
|
924 switch (*cert_usage_str) { |
|
925 case 'c': |
|
926 *cert_usage = certUsageSSLClient; |
|
927 break; |
|
928 case 's': |
|
929 *cert_usage = certUsageSSLServer; |
|
930 break; |
|
931 case 'e': |
|
932 *cert_usage = certUsageEmailRecipient; |
|
933 break; |
|
934 case 'E': |
|
935 *cert_usage = certUsageEmailSigner; |
|
936 break; |
|
937 case 'S': |
|
938 *cert_usage = certUsageObjectSigner; |
|
939 break; |
|
940 case 'C': |
|
941 *cert_usage = certUsageVerifyCA; |
|
942 break; |
|
943 default: |
|
944 return SECFailure; |
|
945 } |
|
946 |
|
947 return SECSuccess; |
|
948 } |
|
949 |
|
950 |
|
951 int |
|
952 main (int argc, char **argv) |
|
953 { |
|
954 int retval; |
|
955 PRFileDesc *in_file; |
|
956 FILE *out_file; /* not PRFileDesc until SECU accepts it */ |
|
957 int crequest, dresponse; |
|
958 int prequest, presponse; |
|
959 int ccert, vcert; |
|
960 const char *db_dir, *date_str, *cert_usage_str, *name; |
|
961 const char *responder_name, *responder_url, *signer_name; |
|
962 PRBool add_acceptable_responses, add_service_locator; |
|
963 SECItem *data = NULL; |
|
964 PLOptState *optstate; |
|
965 SECStatus rv; |
|
966 CERTCertDBHandle *handle = NULL; |
|
967 SECCertUsage cert_usage; |
|
968 PRTime verify_time; |
|
969 CERTCertificate *cert = NULL; |
|
970 PRBool ascii = PR_FALSE; |
|
971 |
|
972 retval = -1; /* what we return/exit with on error */ |
|
973 |
|
974 program_name = PL_strrchr(argv[0], '/'); |
|
975 program_name = program_name ? (program_name + 1) : argv[0]; |
|
976 |
|
977 in_file = PR_STDIN; |
|
978 out_file = stdout; |
|
979 |
|
980 crequest = 0; |
|
981 dresponse = 0; |
|
982 prequest = 0; |
|
983 presponse = 0; |
|
984 ccert = 0; |
|
985 vcert = 0; |
|
986 |
|
987 db_dir = NULL; |
|
988 date_str = NULL; |
|
989 cert_usage_str = NULL; |
|
990 name = NULL; |
|
991 responder_name = NULL; |
|
992 responder_url = NULL; |
|
993 signer_name = NULL; |
|
994 |
|
995 add_acceptable_responses = PR_FALSE; |
|
996 add_service_locator = PR_FALSE; |
|
997 |
|
998 optstate = PL_CreateOptState (argc, argv, "AHLPR:S:V:d:l:pr:s:t:u:w:"); |
|
999 if (optstate == NULL) { |
|
1000 SECU_PrintError (program_name, "PL_CreateOptState failed"); |
|
1001 return retval; |
|
1002 } |
|
1003 |
|
1004 while (PL_GetNextOpt (optstate) == PL_OPT_OK) { |
|
1005 switch (optstate->option) { |
|
1006 case '?': |
|
1007 short_usage (program_name); |
|
1008 return retval; |
|
1009 |
|
1010 case 'A': |
|
1011 add_acceptable_responses = PR_TRUE; |
|
1012 break; |
|
1013 |
|
1014 case 'H': |
|
1015 long_usage (program_name); |
|
1016 return retval; |
|
1017 |
|
1018 case 'L': |
|
1019 add_service_locator = PR_TRUE; |
|
1020 break; |
|
1021 |
|
1022 case 'P': |
|
1023 presponse = 1; |
|
1024 break; |
|
1025 |
|
1026 case 'R': |
|
1027 dresponse = 1; |
|
1028 name = optstate->value; |
|
1029 break; |
|
1030 |
|
1031 case 'S': |
|
1032 ccert = 1; |
|
1033 name = optstate->value; |
|
1034 break; |
|
1035 |
|
1036 case 'V': |
|
1037 vcert = 1; |
|
1038 name = optstate->value; |
|
1039 break; |
|
1040 |
|
1041 case 'a': |
|
1042 ascii = PR_TRUE; |
|
1043 break; |
|
1044 |
|
1045 case 'd': |
|
1046 db_dir = optstate->value; |
|
1047 break; |
|
1048 |
|
1049 case 'l': |
|
1050 responder_url = optstate->value; |
|
1051 break; |
|
1052 |
|
1053 case 'p': |
|
1054 prequest = 1; |
|
1055 break; |
|
1056 |
|
1057 case 'r': |
|
1058 crequest = 1; |
|
1059 name = optstate->value; |
|
1060 break; |
|
1061 |
|
1062 case 's': |
|
1063 signer_name = optstate->value; |
|
1064 break; |
|
1065 |
|
1066 case 't': |
|
1067 responder_name = optstate->value; |
|
1068 break; |
|
1069 |
|
1070 case 'u': |
|
1071 cert_usage_str = optstate->value; |
|
1072 break; |
|
1073 |
|
1074 case 'w': |
|
1075 date_str = optstate->value; |
|
1076 break; |
|
1077 } |
|
1078 } |
|
1079 |
|
1080 PL_DestroyOptState(optstate); |
|
1081 |
|
1082 if ((crequest + dresponse + prequest + presponse + ccert + vcert) != 1) { |
|
1083 PR_fprintf (PR_STDERR, "%s: must specify exactly one command\n\n", |
|
1084 program_name); |
|
1085 short_usage (program_name); |
|
1086 return retval; |
|
1087 } |
|
1088 |
|
1089 if (vcert) { |
|
1090 if (cert_usage_str == NULL) { |
|
1091 PR_fprintf (PR_STDERR, "%s: verification requires cert usage\n\n", |
|
1092 program_name); |
|
1093 short_usage (program_name); |
|
1094 return retval; |
|
1095 } |
|
1096 |
|
1097 rv = cert_usage_from_char (cert_usage_str, &cert_usage); |
|
1098 if (rv != SECSuccess) { |
|
1099 PR_fprintf (PR_STDERR, "%s: invalid cert usage (\"%s\")\n\n", |
|
1100 program_name, cert_usage_str); |
|
1101 long_usage (program_name); |
|
1102 return retval; |
|
1103 } |
|
1104 } |
|
1105 |
|
1106 if (ccert + vcert) { |
|
1107 if (responder_url != NULL || responder_name != NULL) { |
|
1108 /* |
|
1109 * To do a full status check, both the URL and the cert name |
|
1110 * of the responder must be specified if either one is. |
|
1111 */ |
|
1112 if (responder_url == NULL || responder_name == NULL) { |
|
1113 if (responder_url == NULL) |
|
1114 PR_fprintf (PR_STDERR, |
|
1115 "%s: must also specify responder location\n\n", |
|
1116 program_name); |
|
1117 else |
|
1118 PR_fprintf (PR_STDERR, |
|
1119 "%s: must also specify responder name\n\n", |
|
1120 program_name); |
|
1121 short_usage (program_name); |
|
1122 return retval; |
|
1123 } |
|
1124 } |
|
1125 |
|
1126 if (date_str != NULL) { |
|
1127 rv = DER_AsciiToTime (&verify_time, (char *) date_str); |
|
1128 if (rv != SECSuccess) { |
|
1129 SECU_PrintError (program_name, "error converting time string"); |
|
1130 PR_fprintf (PR_STDERR, "\n"); |
|
1131 long_usage (program_name); |
|
1132 return retval; |
|
1133 } |
|
1134 } else { |
|
1135 verify_time = PR_Now(); |
|
1136 } |
|
1137 } |
|
1138 |
|
1139 retval = -2; /* errors change from usage to runtime */ |
|
1140 |
|
1141 /* |
|
1142 * Initialize the NSPR and Security libraries. |
|
1143 */ |
|
1144 PR_Init (PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1); |
|
1145 db_dir = SECU_ConfigDirectory (db_dir); |
|
1146 rv = NSS_Init (db_dir); |
|
1147 if (rv != SECSuccess) { |
|
1148 SECU_PrintError (program_name, "NSS_Init failed"); |
|
1149 goto prdone; |
|
1150 } |
|
1151 SECU_RegisterDynamicOids(); |
|
1152 |
|
1153 if (prequest + presponse) { |
|
1154 MAKE_FILE_BINARY(stdin); |
|
1155 data = read_file_into_item (in_file, siBuffer); |
|
1156 if (data == NULL) { |
|
1157 SECU_PrintError (program_name, "problem reading input"); |
|
1158 goto nssdone; |
|
1159 } |
|
1160 } |
|
1161 |
|
1162 if (crequest + dresponse + presponse + ccert + vcert) { |
|
1163 handle = CERT_GetDefaultCertDB(); |
|
1164 if (handle == NULL) { |
|
1165 SECU_PrintError (program_name, "problem getting certdb handle"); |
|
1166 goto nssdone; |
|
1167 } |
|
1168 |
|
1169 /* |
|
1170 * It would be fine to do the enable for all of these commands, |
|
1171 * but this way we check that everything but an overall verify |
|
1172 * can be done without it. That is, that the individual pieces |
|
1173 * work on their own. |
|
1174 */ |
|
1175 if (vcert) { |
|
1176 rv = CERT_EnableOCSPChecking (handle); |
|
1177 if (rv != SECSuccess) { |
|
1178 SECU_PrintError (program_name, "error enabling OCSP checking"); |
|
1179 goto nssdone; |
|
1180 } |
|
1181 } |
|
1182 |
|
1183 if ((ccert + vcert) && (responder_name != NULL)) { |
|
1184 rv = CERT_SetOCSPDefaultResponder (handle, responder_url, |
|
1185 responder_name); |
|
1186 if (rv != SECSuccess) { |
|
1187 SECU_PrintError (program_name, |
|
1188 "error setting default responder"); |
|
1189 goto nssdone; |
|
1190 } |
|
1191 |
|
1192 rv = CERT_EnableOCSPDefaultResponder (handle); |
|
1193 if (rv != SECSuccess) { |
|
1194 SECU_PrintError (program_name, |
|
1195 "error enabling default responder"); |
|
1196 goto nssdone; |
|
1197 } |
|
1198 } |
|
1199 } |
|
1200 |
|
1201 #define NOTYET(opt) \ |
|
1202 { \ |
|
1203 PR_fprintf (PR_STDERR, "%s not yet working\n", opt); \ |
|
1204 exit (-1); \ |
|
1205 } |
|
1206 |
|
1207 if (name) { |
|
1208 cert = find_certificate(handle, name, ascii); |
|
1209 } |
|
1210 |
|
1211 if (crequest) { |
|
1212 if (signer_name != NULL) { |
|
1213 NOTYET("-s"); |
|
1214 } |
|
1215 rv = create_request (out_file, handle, cert, add_service_locator, |
|
1216 add_acceptable_responses); |
|
1217 } else if (dresponse) { |
|
1218 if (signer_name != NULL) { |
|
1219 NOTYET("-s"); |
|
1220 } |
|
1221 rv = dump_response (out_file, handle, cert, responder_url); |
|
1222 } else if (prequest) { |
|
1223 rv = print_request (out_file, data); |
|
1224 } else if (presponse) { |
|
1225 rv = print_response (out_file, data, handle); |
|
1226 } else if (ccert) { |
|
1227 if (signer_name != NULL) { |
|
1228 NOTYET("-s"); |
|
1229 } |
|
1230 rv = get_cert_status (out_file, handle, cert, name, verify_time); |
|
1231 } else if (vcert) { |
|
1232 if (signer_name != NULL) { |
|
1233 NOTYET("-s"); |
|
1234 } |
|
1235 rv = verify_cert (out_file, handle, cert, name, cert_usage, verify_time); |
|
1236 } |
|
1237 |
|
1238 if (rv != SECSuccess) |
|
1239 SECU_PrintError (program_name, "error performing requested operation"); |
|
1240 else |
|
1241 retval = 0; |
|
1242 |
|
1243 nssdone: |
|
1244 if (cert) { |
|
1245 CERT_DestroyCertificate(cert); |
|
1246 } |
|
1247 |
|
1248 if (data != NULL) { |
|
1249 SECITEM_FreeItem (data, PR_TRUE); |
|
1250 } |
|
1251 |
|
1252 if (handle != NULL) { |
|
1253 CERT_DisableOCSPDefaultResponder(handle); |
|
1254 CERT_DisableOCSPChecking (handle); |
|
1255 } |
|
1256 |
|
1257 if (NSS_Shutdown () != SECSuccess) { |
|
1258 retval = 1; |
|
1259 } |
|
1260 |
|
1261 prdone: |
|
1262 PR_Cleanup (); |
|
1263 return retval; |
|
1264 } |