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 *
get_oid_desc(const char * oid)43 get_oid_desc (const char *oid)
44 {
45 int i;
46
47 if (oid)
48 for (i=0; oidtranstbl[i].oid; i++)
49 if (!strcmp (oidtranstbl[i].oid, oid))
50 return oidtranstbl[i].desc;
51 return NULL;
52 }
53
54
55 static unsigned char *
read_file(const char * fname,size_t * r_length)56 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 fp = fopen (fname, "rb");
64 if (!fp)
65 {
66 fprintf (stderr, "can't open `%s': %s\n", fname, strerror (errno));
67 return NULL;
68 }
69
70 if (fstat (fileno(fp), &st))
71 {
72 fprintf (stderr, "can't stat `%s': %s\n", fname, strerror (errno));
73 fclose (fp);
74 return NULL;
75 }
76
77 buflen = st.st_size;
78 buf = xmalloc (buflen+1);
79 if (fread (buf, buflen, 1, fp) != 1)
80 {
81 fprintf (stderr, "error reading `%s': %s\n", fname, strerror (errno));
82 fclose (fp);
83 xfree (buf);
84 return NULL;
85 }
86 fclose (fp);
87
88 *r_length = buflen;
89 return buf;
90 }
91
92
93
94 ksba_cert_t
get_one_cert(const char * fname)95 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 fp = fopen (fname, "r");
103 if (!fp)
104 {
105 fprintf (stderr, "%s:%d: can't open `%s': %s\n",
106 __FILE__, __LINE__, fname, strerror (errno));
107 exit (1);
108 }
109
110 err = ksba_reader_new (&r);
111 if (err)
112 fail_if_err (err);
113 err = ksba_reader_set_file (r, fp);
114 fail_if_err (err);
115
116 err = ksba_cert_new (&cert);
117 if (err)
118 fail_if_err (err);
119
120 err = ksba_cert_read_der (cert, r);
121 fail_if_err2 (fname, err);
122 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
one_request(const char * cert_fname,const char * issuer_cert_fname)130 one_request (const char *cert_fname, const char *issuer_cert_fname)
131 {
132 gpg_error_t err;
133 ksba_cert_t cert = get_one_cert (cert_fname);
134 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 err = ksba_ocsp_new (&ocsp);
140 fail_if_err (err);
141
142 err = ksba_ocsp_add_target (ocsp, cert, issuer_cert);
143 fail_if_err (err);
144 ksba_cert_release (cert);
145 ksba_cert_release (issuer_cert);
146
147 if (!no_nonce)
148 ksba_ocsp_set_nonce (ocsp, "ABCDEFGHIJKLMNOP", 16);
149
150 err = ksba_ocsp_build_request (ocsp, &request, &requestlen);
151 fail_if_err (err);
152 ksba_ocsp_release (ocsp);
153
154 printf ("OCSP request of length %u created\n", (unsigned int)requestlen);
155 {
156
157 FILE *fp = fopen ("a.req", "wb");
158 if (!fp)
159 fail ("can't create output file `a.req'");
160 if (fwrite (request, requestlen, 1, fp) != 1)
161 fail ("can't write output");
162 fclose (fp);
163 }
164
165 xfree (request);
166 }
167
168
169 void
one_response(const char * cert_fname,const char * issuer_cert_fname,char * response_fname)170 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 ksba_cert_t cert = get_one_cert (cert_fname);
178 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 err = ksba_ocsp_new (&ocsp);
183 fail_if_err (err);
184
185 /* We need to build a request, so that the context is properly
186 prepared for the response. */
187 err = ksba_ocsp_add_target (ocsp, cert, issuer_cert);
188 fail_if_err (err);
189 ksba_cert_release (issuer_cert);
190
191 if (!no_nonce)
192 ksba_ocsp_set_nonce (ocsp, "ABCDEFGHIJKLMNOP", 16);
193
194 err = ksba_ocsp_build_request (ocsp, &request, &requestlen);
195 fail_if_err (err);
196 xfree (request);
197
198 /* Now for the response. */
199 response = read_file (response_fname, &responselen);
200 if (!response)
201 fail ("file error");
202
203 err = ksba_ocsp_parse_response (ocsp, response, responselen,
204 &response_status);
205 fail_if_err (err);
206 switch (response_status)
207 {
208 case KSBA_OCSP_RSPSTATUS_SUCCESS: t = "success"; break;
209 case KSBA_OCSP_RSPSTATUS_MALFORMED: t = "malformed"; break;
210 case KSBA_OCSP_RSPSTATUS_INTERNAL: t = "internal error"; break;
211 case KSBA_OCSP_RSPSTATUS_TRYLATER: t = "try later"; break;
212 case KSBA_OCSP_RSPSTATUS_SIGREQUIRED: t = "must sign request"; break;
213 case KSBA_OCSP_RSPSTATUS_UNAUTHORIZED: t = "unauthorized"; break;
214 case KSBA_OCSP_RSPSTATUS_REPLAYED: t = "replay detected"; break;
215 case KSBA_OCSP_RSPSTATUS_OTHER: t = "other (unknown)"; break;
216 case KSBA_OCSP_RSPSTATUS_NONE: t = "no status"; break;
217 default: fail ("impossible response_status"); break;
218 }
219 printf ("response status ..: %s\n", t);
220
221 if (response_status == KSBA_OCSP_RSPSTATUS_SUCCESS
222 || 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 err = ksba_ocsp_get_responder_id (ocsp, &name, &keyid);
232 fail_if_err (err);
233 printf ("responder id .....: ");
234 if (name)
235 printf ("`%s'", name);
236 else
237 print_sexp (keyid);
238 putchar ('\n');
239 ksba_free (name);
240 ksba_free (keyid);
241
242 sigval = ksba_ocsp_get_sig_val (ocsp, produced_at);
243 printf ("signature value ..: ");
244 print_sexp (sigval);
245 printf ("\nproduced at ......: ");
246 print_time (produced_at);
247 putchar ('\n');
248 err = ksba_ocsp_get_status (ocsp, cert,
249 &status, this_update, next_update,
250 revocation_time, &reason);
251 fail_if_err (err);
252 printf ("certificate status: %s\n",
253 status == KSBA_STATUS_GOOD? "good":
254 status == KSBA_STATUS_REVOKED? "revoked":
255 status == KSBA_STATUS_UNKNOWN? "unknown":
256 status == KSBA_STATUS_NONE? "none": "?");
257 if (status == KSBA_STATUS_REVOKED)
258 {
259 printf ("revocation time ..: ");
260 print_time (revocation_time);
261 printf ("\nrevocation reason : %s\n",
262 reason == KSBA_CRLREASON_UNSPECIFIED? "unspecified":
263 reason == KSBA_CRLREASON_KEY_COMPROMISE? "key compromise":
264 reason == KSBA_CRLREASON_CA_COMPROMISE? "CA compromise":
265 reason == KSBA_CRLREASON_AFFILIATION_CHANGED?
266 "affiliation changed":
267 reason == KSBA_CRLREASON_SUPERSEDED? "superseeded":
268 reason == KSBA_CRLREASON_CESSATION_OF_OPERATION?
269 "cessation of operation":
270 reason == KSBA_CRLREASON_CERTIFICATE_HOLD?
271 "certificate on hold":
272 reason == KSBA_CRLREASON_REMOVE_FROM_CRL? "removed from CRL":
273 reason == KSBA_CRLREASON_PRIVILEGE_WITHDRAWN?
274 "privilege withdrawn":
275 reason == KSBA_CRLREASON_AA_COMPROMISE? "AA compromise":
276 reason == KSBA_CRLREASON_OTHER? "other":"?");
277 }
278 printf ("this update ......: ");
279 print_time (this_update);
280 printf ("\nnext update ......: ");
281 print_time (next_update);
282 putchar ('\n');
283 {
284 int cert_idx;
285 ksba_cert_t acert;
286
287 for (cert_idx=0; (acert = ksba_ocsp_get_cert (ocsp, cert_idx));
288 cert_idx++)
289 ksba_cert_release (acert);
290 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 for (idx=0; !(err=ksba_ocsp_get_extension (ocsp, NULL, idx,
300 &oid, &crit,
301 &der, &derlen)); idx++)
302 {
303 const char *s = get_oid_desc (oid);
304 printf ("%sresp-extn ..%s: %s%s%s%s (",
305 crit? "crit. ":"",
306 crit?"":"......",
307 s?"(":"", s?s:"", s?") ":"", oid);
308 print_hex (der, derlen);
309 putchar (')');
310 putchar ('\n');
311 }
312 if (err && gpg_err_code (err) != GPG_ERR_EOF)
313 fail_if_err (err);
314
315 for (idx=0; !(err=ksba_ocsp_get_extension (ocsp, cert, idx,
316 &oid, &crit,
317 &der, &derlen)); idx++)
318 {
319 const char *s = get_oid_desc (oid);
320 printf ("%ssngl-extn ..%s: %s%s%s%s (",
321 crit? "crit. ":"",
322 crit?"":"......",
323 s?"(":"", s?s:"", s?") ":"", oid);
324 print_hex (der, derlen);
325 putchar (')');
326 putchar ('\n');
327 }
328 if (err && gpg_err_code (err) != GPG_ERR_EOF)
329 fail_if_err (err);
330 }
331 }
332
333
334 ksba_cert_release (cert);
335 ksba_ocsp_release (ocsp);
336 xfree (response);
337 }
338
339
340 static gpg_error_t
my_hash_buffer(void * arg,const char * oid,const void * buffer,size_t length,size_t resultsize,unsigned char * result,size_t * resultlen)341 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 if (oid && strcmp (oid, "1.3.14.3.2.26"))
348 return gpg_error (GPG_ERR_NOT_SUPPORTED); /* We only support SHA-1. */
349 if (resultsize < 20)
350 return gpg_error (GPG_ERR_BUFFER_TOO_SHORT);
351 sha1_hash_buffer (result, buffer, length);
352 *resultlen = 20;
353 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
main(int argc,char ** argv)384 main (int argc, char **argv)
385 {
386 int last_argc = -1;
387 int response_mode = 0;
388 const char *srcdir = getenv ("srcdir");
389
390 if (!srcdir)
391 srcdir = ".";
392
393 ksba_set_hash_buffer_function (my_hash_buffer, NULL);
394
395 if (argc)
396 {
397 argc--; argv++;
398 }
399 while (argc && last_argc != argc )
400 {
401 last_argc = argc;
402 if (!strcmp (*argv, "--help"))
403 {
404 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 exit (0);
410 }
411 if (!strcmp (*argv, "--verbose"))
412 {
413 verbose = 1;
414 argc--; argv++;
415 }
416 else if (!strcmp (*argv, "--debug"))
417 {
418 verbose = debug = 1;
419 argc--; argv++;
420 }
421 else if (!strcmp (*argv, "--response"))
422 {
423 response_mode = 1;
424 argc--; argv++;
425 }
426 else if (!strcmp (*argv, "--no-nonce"))
427 {
428 no_nonce = 1;
429 argc--; argv++;
430 }
431 }
432
433
434 if (response_mode)
435 {
436 for ( ; argc > 2; argc -=3, argv += 3)
437 one_response (*argv, argv[1], argv[2]);
438 if (argc)
439 fputs ("warning: extra argument ignored\n", stderr);
440 }
441 else if (argc)
442 {
443 for ( ; argc > 1; argc -=2, argv += 2)
444 one_request (*argv, argv[1]);
445 if (argc)
446 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 } files[] = {
455 { "samples/ov-userrev.crt", "samples/ov-root-ca-cert.crt", NULL },
456 { NULL }
457 };
458 int idx;
459
460 for (idx=0; files[idx].cert_fname; idx++)
461 {
462 char *f1, *f2;
463
464 f1 = prepend_srcdir (files[idx].cert_fname);
465 f2 = prepend_srcdir (files[idx].issuer_cert_fname);
466 one_request (f1, f2);
467 xfree (f2);
468 xfree (f1);
469 }
470 }
471
472 return 0;
473 }
474