Line data Source code
1 : /* t-ocsp.c - Basic tests for the OCSP subsystem.
2 : * Copyright (C) 2003 g10 Code GmbH
3 : *
4 : * This file is part of KSBA.
5 : *
6 : * KSBA is free software; you can redistribute it and/or modify
7 : * it under the terms of the GNU General Public License as published by
8 : * the Free Software Foundation; either version 3 of the License, or
9 : * (at your option) any later version.
10 : *
11 : * KSBA is distributed in the hope that it will be useful,
12 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : * GNU General Public License for more details.
15 : *
16 : * You should have received a copy of the GNU General Public License
17 : * along with this program; if not, see <http://www.gnu.org/licenses/>.
18 : */
19 :
20 : #include <stdio.h>
21 : #include <stdlib.h>
22 : #include <string.h>
23 : #include <assert.h>
24 : #include <sys/stat.h>
25 : #include <unistd.h>
26 : #include <time.h>
27 : #include <errno.h>
28 :
29 : #include "../src/ksba.h"
30 :
31 :
32 : #include "t-common.h"
33 : #include "oidtranstbl.h"
34 :
35 :
36 : int verbose;
37 : int debug;
38 : int no_nonce;
39 :
40 : /* Return the description for OID; if no description is available
41 : NULL is returned. */
42 : static const char *
43 0 : get_oid_desc (const char *oid)
44 : {
45 : int i;
46 :
47 0 : if (oid)
48 0 : for (i=0; oidtranstbl[i].oid; i++)
49 0 : if (!strcmp (oidtranstbl[i].oid, oid))
50 0 : return oidtranstbl[i].desc;
51 0 : return NULL;
52 : }
53 :
54 :
55 : static unsigned char *
56 0 : read_file (const char *fname, size_t *r_length)
57 : {
58 : FILE *fp;
59 : struct stat st;
60 : char *buf;
61 : size_t buflen;
62 :
63 0 : fp = fopen (fname, "rb");
64 0 : if (!fp)
65 : {
66 0 : fprintf (stderr, "can't open `%s': %s\n", fname, strerror (errno));
67 0 : return NULL;
68 : }
69 :
70 0 : if (fstat (fileno(fp), &st))
71 : {
72 0 : fprintf (stderr, "can't stat `%s': %s\n", fname, strerror (errno));
73 0 : fclose (fp);
74 0 : return NULL;
75 : }
76 :
77 0 : buflen = st.st_size;
78 0 : buf = xmalloc (buflen+1);
79 0 : if (fread (buf, buflen, 1, fp) != 1)
80 : {
81 0 : fprintf (stderr, "error reading `%s': %s\n", fname, strerror (errno));
82 0 : fclose (fp);
83 0 : xfree (buf);
84 0 : return NULL;
85 : }
86 0 : fclose (fp);
87 :
88 0 : *r_length = buflen;
89 0 : return buf;
90 : }
91 :
92 :
93 :
94 : ksba_cert_t
95 0 : get_one_cert (const char *fname)
96 : {
97 : gpg_error_t err;
98 : FILE *fp;
99 : ksba_reader_t r;
100 : ksba_cert_t cert;
101 :
102 0 : fp = fopen (fname, "r");
103 0 : if (!fp)
104 : {
105 0 : fprintf (stderr, "%s:%d: can't open `%s': %s\n",
106 0 : __FILE__, __LINE__, fname, strerror (errno));
107 0 : exit (1);
108 : }
109 :
110 0 : err = ksba_reader_new (&r);
111 0 : if (err)
112 0 : fail_if_err (err);
113 0 : err = ksba_reader_set_file (r, fp);
114 0 : fail_if_err (err);
115 :
116 0 : err = ksba_cert_new (&cert);
117 0 : if (err)
118 0 : fail_if_err (err);
119 :
120 0 : err = ksba_cert_read_der (cert, r);
121 0 : fail_if_err2 (fname, err);
122 0 : return cert;
123 : }
124 :
125 :
126 : /* Create a request for the DER encoded certificate in the file
127 : CERT_FNAME and its issuer's certificate in the file
128 : ISSUER_CERT_FNAME. */
129 : void
130 0 : one_request (const char *cert_fname, const char *issuer_cert_fname)
131 : {
132 : gpg_error_t err;
133 0 : ksba_cert_t cert = get_one_cert (cert_fname);
134 0 : ksba_cert_t issuer_cert = get_one_cert (issuer_cert_fname);
135 : ksba_ocsp_t ocsp;
136 : unsigned char *request;
137 : size_t requestlen;
138 :
139 0 : err = ksba_ocsp_new (&ocsp);
140 0 : fail_if_err (err);
141 :
142 0 : err = ksba_ocsp_add_target (ocsp, cert, issuer_cert);
143 0 : fail_if_err (err);
144 0 : ksba_cert_release (cert);
145 0 : ksba_cert_release (issuer_cert);
146 :
147 0 : if (!no_nonce)
148 0 : ksba_ocsp_set_nonce (ocsp, "ABCDEFGHIJKLMNOP", 16);
149 :
150 0 : err = ksba_ocsp_build_request (ocsp, &request, &requestlen);
151 0 : fail_if_err (err);
152 0 : ksba_ocsp_release (ocsp);
153 :
154 0 : printf ("OCSP request of length %u created\n", (unsigned int)requestlen);
155 : {
156 :
157 0 : FILE *fp = fopen ("a.req", "wb");
158 0 : if (!fp)
159 0 : fail ("can't create output file `a.req'");
160 0 : if (fwrite (request, requestlen, 1, fp) != 1)
161 0 : fail ("can't write output");
162 0 : fclose (fp);
163 : }
164 :
165 0 : xfree (request);
166 0 : }
167 :
168 :
169 : void
170 0 : one_response (const char *cert_fname, const char *issuer_cert_fname,
171 : char *response_fname)
172 : {
173 : gpg_error_t err;
174 : ksba_ocsp_t ocsp;
175 : unsigned char *request, *response;
176 : size_t requestlen, responselen;
177 0 : ksba_cert_t cert = get_one_cert (cert_fname);
178 0 : ksba_cert_t issuer_cert = get_one_cert (issuer_cert_fname);
179 : ksba_ocsp_response_status_t response_status;
180 : const char *t;
181 :
182 0 : err = ksba_ocsp_new (&ocsp);
183 0 : fail_if_err (err);
184 :
185 : /* We need to build a request, so that the context is properly
186 : prepared for the response. */
187 0 : err = ksba_ocsp_add_target (ocsp, cert, issuer_cert);
188 0 : fail_if_err (err);
189 0 : ksba_cert_release (issuer_cert);
190 :
191 0 : if (!no_nonce)
192 0 : ksba_ocsp_set_nonce (ocsp, "ABCDEFGHIJKLMNOP", 16);
193 :
194 0 : err = ksba_ocsp_build_request (ocsp, &request, &requestlen);
195 0 : fail_if_err (err);
196 0 : xfree (request);
197 :
198 : /* Now for the response. */
199 0 : response = read_file (response_fname, &responselen);
200 0 : if (!response)
201 0 : fail ("file error");
202 :
203 0 : err = ksba_ocsp_parse_response (ocsp, response, responselen,
204 : &response_status);
205 0 : fail_if_err (err);
206 0 : switch (response_status)
207 : {
208 0 : case KSBA_OCSP_RSPSTATUS_SUCCESS: t = "success"; break;
209 0 : case KSBA_OCSP_RSPSTATUS_MALFORMED: t = "malformed"; break;
210 0 : case KSBA_OCSP_RSPSTATUS_INTERNAL: t = "internal error"; break;
211 0 : case KSBA_OCSP_RSPSTATUS_TRYLATER: t = "try later"; break;
212 0 : case KSBA_OCSP_RSPSTATUS_SIGREQUIRED: t = "must sign request"; break;
213 0 : case KSBA_OCSP_RSPSTATUS_UNAUTHORIZED: t = "unauthorized"; break;
214 0 : case KSBA_OCSP_RSPSTATUS_REPLAYED: t = "replay detected"; break;
215 0 : case KSBA_OCSP_RSPSTATUS_OTHER: t = "other (unknown)"; break;
216 0 : case KSBA_OCSP_RSPSTATUS_NONE: t = "no status"; break;
217 0 : default: fail ("impossible response_status"); break;
218 : }
219 0 : printf ("response status ..: %s\n", t);
220 :
221 0 : if (response_status == KSBA_OCSP_RSPSTATUS_SUCCESS
222 0 : || response_status == KSBA_OCSP_RSPSTATUS_REPLAYED)
223 : {
224 : ksba_status_t status;
225 : ksba_crl_reason_t reason;
226 : ksba_isotime_t this_update, next_update, revocation_time, produced_at;
227 : ksba_sexp_t sigval;
228 : char *name;
229 : ksba_sexp_t keyid;
230 :
231 0 : err = ksba_ocsp_get_responder_id (ocsp, &name, &keyid);
232 0 : fail_if_err (err);
233 0 : printf ("responder id .....: ");
234 0 : if (name)
235 0 : printf ("`%s'", name);
236 : else
237 0 : print_sexp (keyid);
238 0 : putchar ('\n');
239 0 : ksba_free (name);
240 0 : ksba_free (keyid);
241 :
242 0 : sigval = ksba_ocsp_get_sig_val (ocsp, produced_at);
243 0 : printf ("signature value ..: ");
244 0 : print_sexp (sigval);
245 0 : printf ("\nproduced at ......: ");
246 0 : print_time (produced_at);
247 0 : putchar ('\n');
248 0 : err = ksba_ocsp_get_status (ocsp, cert,
249 : &status, this_update, next_update,
250 : revocation_time, &reason);
251 0 : fail_if_err (err);
252 0 : printf ("certificate status: %s\n",
253 0 : status == KSBA_STATUS_GOOD? "good":
254 0 : status == KSBA_STATUS_REVOKED? "revoked":
255 0 : status == KSBA_STATUS_UNKNOWN? "unknown":
256 0 : status == KSBA_STATUS_NONE? "none": "?");
257 0 : if (status == KSBA_STATUS_REVOKED)
258 : {
259 0 : printf ("revocation time ..: ");
260 0 : print_time (revocation_time);
261 0 : printf ("\nrevocation reason : %s\n",
262 0 : reason == KSBA_CRLREASON_UNSPECIFIED? "unspecified":
263 0 : reason == KSBA_CRLREASON_KEY_COMPROMISE? "key compromise":
264 0 : reason == KSBA_CRLREASON_CA_COMPROMISE? "CA compromise":
265 0 : reason == KSBA_CRLREASON_AFFILIATION_CHANGED?
266 0 : "affiliation changed":
267 0 : reason == KSBA_CRLREASON_SUPERSEDED? "superseeded":
268 0 : reason == KSBA_CRLREASON_CESSATION_OF_OPERATION?
269 0 : "cessation of operation":
270 0 : reason == KSBA_CRLREASON_CERTIFICATE_HOLD?
271 0 : "certificate on hold":
272 0 : reason == KSBA_CRLREASON_REMOVE_FROM_CRL? "removed from CRL":
273 0 : reason == KSBA_CRLREASON_PRIVILEGE_WITHDRAWN?
274 0 : "privilege withdrawn":
275 0 : reason == KSBA_CRLREASON_AA_COMPROMISE? "AA compromise":
276 0 : reason == KSBA_CRLREASON_OTHER? "other":"?");
277 : }
278 0 : printf ("this update ......: ");
279 0 : print_time (this_update);
280 0 : printf ("\nnext update ......: ");
281 0 : print_time (next_update);
282 0 : putchar ('\n');
283 : {
284 : int cert_idx;
285 : ksba_cert_t acert;
286 :
287 0 : for (cert_idx=0; (acert = ksba_ocsp_get_cert (ocsp, cert_idx));
288 0 : cert_idx++)
289 0 : ksba_cert_release (acert);
290 0 : printf ("extra certificates: %d\n", cert_idx );
291 : }
292 :
293 : {
294 : int idx, crit;
295 : const char *oid;
296 : const unsigned char *der;
297 : size_t derlen;
298 :
299 0 : for (idx=0; !(err=ksba_ocsp_get_extension (ocsp, NULL, idx,
300 : &oid, &crit,
301 0 : &der, &derlen)); idx++)
302 : {
303 0 : const char *s = get_oid_desc (oid);
304 0 : printf ("%sresp-extn ..%s: %s%s%s%s (",
305 0 : crit? "crit. ":"",
306 0 : crit?"":"......",
307 : s?"(":"", s?s:"", s?") ":"", oid);
308 0 : print_hex (der, derlen);
309 0 : putchar (')');
310 0 : putchar ('\n');
311 : }
312 0 : if (err && gpg_err_code (err) != GPG_ERR_EOF)
313 0 : fail_if_err (err);
314 :
315 0 : for (idx=0; !(err=ksba_ocsp_get_extension (ocsp, cert, idx,
316 : &oid, &crit,
317 0 : &der, &derlen)); idx++)
318 : {
319 0 : const char *s = get_oid_desc (oid);
320 0 : printf ("%ssngl-extn ..%s: %s%s%s%s (",
321 0 : crit? "crit. ":"",
322 0 : crit?"":"......",
323 : s?"(":"", s?s:"", s?") ":"", oid);
324 0 : print_hex (der, derlen);
325 0 : putchar (')');
326 0 : putchar ('\n');
327 : }
328 0 : if (err && gpg_err_code (err) != GPG_ERR_EOF)
329 0 : fail_if_err (err);
330 : }
331 : }
332 :
333 :
334 0 : ksba_cert_release (cert);
335 0 : ksba_ocsp_release (ocsp);
336 0 : xfree (response);
337 0 : }
338 :
339 :
340 : static gpg_error_t
341 0 : my_hash_buffer (void *arg, const char *oid,
342 : const void *buffer, size_t length, size_t resultsize,
343 : unsigned char *result, size_t *resultlen)
344 : {
345 : (void)arg; /* Not used. */
346 :
347 0 : if (oid && strcmp (oid, "1.3.14.3.2.26"))
348 0 : return gpg_error (GPG_ERR_NOT_SUPPORTED); /* We only support SHA-1. */
349 0 : if (resultsize < 20)
350 0 : return gpg_error (GPG_ERR_BUFFER_TOO_SHORT);
351 0 : sha1_hash_buffer (result, buffer, length);
352 0 : *resultlen = 20;
353 0 : return 0;
354 : }
355 :
356 :
357 :
358 :
359 : /* ( printf "POST / HTTP/1.0\r\nContent-Type: application/ocsp-request\r\nContent-Length: `wc -c <a.req | tr -d ' '`\r\n\r\n"; cat a.req ) | nc -v ocsp.openvalidation.org 8088 | sed '1,/^\r$/d' >a.rsp
360 :
361 : Openvalidation test reponders:
362 :
363 : Port: 80 Standard configuration. OCSP Responder will accept
364 : all proper requests and send a signed response.
365 : Port: 8080 Response does not contain any attached certificates.
366 : Client must accept this response
367 : Port: 8081 Never replies nonce. Insecure but standard conform mode.
368 : Client application should warn in case of replay-attacks.
369 : Port: 8082 The OCSP Responder will sign the response with randomized
370 : bytecode. Client should NOT accept this response.
371 : Port: 8083 OCSP response will always be revoked.
372 : Port: 8084 OCSP response will always be unknown.
373 : Port: 8085 OCSP response will always be malformed.
374 : Port: 8086 OCSP response will always be internal error.
375 : Port: 8087 OCSP response will always be try later.
376 : Port: 8088 OCSP response will always be signature required.
377 : Port: 8089 OCSP response will always be unauth.
378 : Port: 8090 Standard configuration with full Debuglogs. Access the
379 : logs at http://www.openvalidation.org/en/test/logs.html
380 :
381 : */
382 :
383 : int
384 0 : main (int argc, char **argv)
385 : {
386 0 : int last_argc = -1;
387 0 : int response_mode = 0;
388 0 : const char *srcdir = getenv ("srcdir");
389 :
390 0 : if (!srcdir)
391 0 : srcdir = ".";
392 :
393 0 : ksba_set_hash_buffer_function (my_hash_buffer, NULL);
394 :
395 0 : if (argc)
396 : {
397 0 : argc--; argv++;
398 : }
399 0 : while (argc && last_argc != argc )
400 : {
401 0 : last_argc = argc;
402 0 : if (!strcmp (*argv, "--help"))
403 : {
404 0 : puts (
405 : "usage: ./t-ocsp [options] {CERTFILE ISSUERCERTFILE}\n"
406 : " ./t-ocsp [options] --response {CERTFILE ISSUERCERTFILE RESPONSEFILE}\n"
407 : "\n"
408 : " Options are --verbose and --debug");
409 0 : exit (0);
410 : }
411 0 : if (!strcmp (*argv, "--verbose"))
412 : {
413 0 : verbose = 1;
414 0 : argc--; argv++;
415 : }
416 0 : else if (!strcmp (*argv, "--debug"))
417 : {
418 0 : verbose = debug = 1;
419 0 : argc--; argv++;
420 : }
421 0 : else if (!strcmp (*argv, "--response"))
422 : {
423 0 : response_mode = 1;
424 0 : argc--; argv++;
425 : }
426 0 : else if (!strcmp (*argv, "--no-nonce"))
427 : {
428 0 : no_nonce = 1;
429 0 : argc--; argv++;
430 : }
431 : }
432 :
433 :
434 0 : if (response_mode)
435 : {
436 0 : for ( ; argc > 2; argc -=3, argv += 3)
437 0 : one_response (*argv, argv[1], argv[2]);
438 0 : if (argc)
439 0 : fputs ("warning: extra argument ignored\n", stderr);
440 : }
441 0 : else if (argc)
442 : {
443 0 : for ( ; argc > 1; argc -=2, argv += 2)
444 0 : one_request (*argv, argv[1]);
445 0 : if (argc)
446 0 : fputs ("warning: extra argument ignored\n", stderr);
447 : }
448 : else
449 : {
450 : struct {
451 : const char *cert_fname;
452 : const char *issuer_cert_fname;
453 : const char *response_fname;
454 0 : } files[] = {
455 : { "samples/ov-userrev.crt", "samples/ov-root-ca-cert.crt", NULL },
456 : { NULL }
457 : };
458 : int idx;
459 :
460 0 : for (idx=0; files[idx].cert_fname; idx++)
461 : {
462 : char *f1, *f2;
463 :
464 0 : f1 = prepend_srcdir (files[idx].cert_fname);
465 0 : f2 = prepend_srcdir (files[idx].issuer_cert_fname);
466 0 : one_request (f1, f2);
467 0 : xfree (f2);
468 0 : xfree (f1);
469 : }
470 : }
471 :
472 0 : return 0;
473 : }
|