Imported Upstream version 1.6.5
[platform/upstream/libksba.git] / tests / t-ocsp.c
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 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 *
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
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
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
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
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
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 }