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