Add the -VAfile option to 'openssl ocsp'. This option will give the
[openssl.git] / apps / ocsp.c
1 /* ocsp.c */
2 /* Written by Dr Stephen N Henson (shenson@bigfoot.com) for the OpenSSL
3  * project 2000.
4  */
5 /* ====================================================================
6  * Copyright (c) 1999 The OpenSSL Project.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer. 
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in
17  *    the documentation and/or other materials provided with the
18  *    distribution.
19  *
20  * 3. All advertising materials mentioning features or use of this
21  *    software must display the following acknowledgment:
22  *    "This product includes software developed by the OpenSSL Project
23  *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
24  *
25  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
26  *    endorse or promote products derived from this software without
27  *    prior written permission. For written permission, please contact
28  *    licensing@OpenSSL.org.
29  *
30  * 5. Products derived from this software may not be called "OpenSSL"
31  *    nor may "OpenSSL" appear in their names without prior written
32  *    permission of the OpenSSL Project.
33  *
34  * 6. Redistributions of any form whatsoever must retain the following
35  *    acknowledgment:
36  *    "This product includes software developed by the OpenSSL Project
37  *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
38  *
39  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
40  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
42  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
43  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
44  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
45  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
46  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
48  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
49  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
50  * OF THE POSSIBILITY OF SUCH DAMAGE.
51  * ====================================================================
52  *
53  * This product includes cryptographic software written by Eric Young
54  * (eay@cryptsoft.com).  This product includes software written by Tim
55  * Hudson (tjh@cryptsoft.com).
56  *
57  */
58
59 #include <stdio.h>
60 #include <string.h>
61 #include <openssl/pem.h>
62 #include <openssl/ocsp.h>
63 #include <openssl/err.h>
64 #include "apps.h"
65
66 static int add_ocsp_cert(OCSP_REQUEST **req, X509 *cert, X509 *issuer,
67                                 STACK_OF(OCSP_CERTID) *ids);
68 static int add_ocsp_serial(OCSP_REQUEST **req, char *serial, X509 *issuer,
69                                 STACK_OF(OCSP_CERTID) *ids);
70 static int print_ocsp_summary(BIO *out, OCSP_BASICRESP *bs, OCSP_REQUEST *req,
71                                 STACK *names, STACK_OF(OCSP_CERTID) *ids);
72
73 #undef PROG
74 #define PROG ocsp_main
75
76 int MAIN(int, char **);
77
78 int MAIN(int argc, char **argv)
79         {
80         char **args;
81         char *host = NULL, *path = "/";
82         char *reqin = NULL, *respin = NULL;
83         char *reqout = NULL, *respout = NULL;
84         char *signfile = NULL, *keyfile = NULL;
85         char *outfile = NULL;
86         int add_nonce = 1, noverify = 0;
87         OCSP_REQUEST *req = NULL;
88         OCSP_RESPONSE *resp = NULL;
89         OCSP_BASICRESP *bs = NULL;
90         X509 *issuer = NULL, *cert = NULL;
91         X509 *signer = NULL;
92         EVP_PKEY *key = NULL;
93         BIO *cbio = NULL, *derbio = NULL;
94         BIO *out = NULL;
95         int req_text = 0, resp_text = 0;
96         char *CAfile = NULL, *CApath = NULL;
97         char *VAfile = NULL;
98         X509_STORE *store = NULL;
99         STACK_OF(X509) *VAstore = NULL;
100         int ret = 1;
101         int badarg = 0;
102         int i;
103         STACK *reqnames = NULL;
104         STACK_OF(OCSP_CERTID) *ids = NULL;
105         if (bio_err == NULL) bio_err = BIO_new_fp(stderr, BIO_NOCLOSE);
106         ERR_load_crypto_strings();
107         args = argv + 1;
108         reqnames = sk_new_null();
109         ids = sk_OCSP_CERTID_new_null();
110         while (!badarg && *args && *args[0] == '-')
111                 {
112                 if (!strcmp(*args, "-out"))
113                         {
114                         if (args[1])
115                                 {
116                                 args++;
117                                 outfile = *args;
118                                 }
119                         else badarg = 1;
120                         }
121                 else if (!strcmp(*args, "-host"))
122                         {
123                         if (args[1])
124                                 {
125                                 args++;
126                                 host = *args;
127                                 }
128                         else badarg = 1;
129                         }
130                 else if (!strcmp(*args, "-noverify"))
131                         noverify = 1;
132                 else if (!strcmp(*args, "-nonce"))
133                         add_nonce = 2;
134                 else if (!strcmp(*args, "-no_nonce"))
135                         add_nonce = 0;
136                 else if (!strcmp(*args, "-text"))
137                         {
138                         req_text = 1;
139                         resp_text = 1;
140                         }
141                 else if (!strcmp(*args, "-req_text"))
142                         req_text = 1;
143                 else if (!strcmp(*args, "-resp_text"))
144                         resp_text = 1;
145                 else if (!strcmp(*args, "-reqin"))
146                         {
147                         if (args[1])
148                                 {
149                                 args++;
150                                 reqin = *args;
151                                 }
152                         else badarg = 1;
153                         }
154                 else if (!strcmp(*args, "-respin"))
155                         {
156                         if (args[1])
157                                 {
158                                 args++;
159                                 respin = *args;
160                                 }
161                         else badarg = 1;
162                         }
163                 else if (!strcmp(*args, "-signer"))
164                         {
165                         if (args[1])
166                                 {
167                                 args++;
168                                 signfile = *args;
169                                 }
170                         else badarg = 1;
171                         }
172                 else if (!strcmp (*args, "-VAfile"))
173                         {
174                         if (args[1])
175                                 {
176                                 args++;
177                                 VAfile = *args;
178                                 }
179                         else badarg = 1;
180                         }
181                 else if (!strcmp (*args, "-CAfile"))
182                         {
183                         if (args[1])
184                                 {
185                                 args++;
186                                 CAfile = *args;
187                                 }
188                         else badarg = 1;
189                         }
190                 else if (!strcmp (*args, "-CApath"))
191                         {
192                         if (args[1])
193                                 {
194                                 args++;
195                                 CApath = *args;
196                                 }
197                         else badarg = 1;
198                         }
199                  else if (!strcmp(*args, "-signkey"))
200                         {
201                         if (args[1])
202                                 {
203                                 args++;
204                                 keyfile = *args;
205                                 }
206                         else badarg = 1;
207                         }
208                 else if (!strcmp(*args, "-reqout"))
209                         {
210                         if (args[1])
211                                 {
212                                 args++;
213                                 reqout = *args;
214                                 }
215                         else badarg = 1;
216                         }
217                 else if (!strcmp(*args, "-respout"))
218                         {
219                         if (args[1])
220                                 {
221                                 args++;
222                                 respout = *args;
223                                 }
224                         else badarg = 1;
225                         }
226                  else if (!strcmp(*args, "-path"))
227                         {
228                         if (args[1])
229                                 {
230                                 args++;
231                                 path = *args;
232                                 }
233                         else badarg = 1;
234                         }
235                 else if (!strcmp(*args, "-issuer"))
236                         {
237                         if (args[1])
238                                 {
239                                 args++;
240                                 X509_free(issuer);
241                                 issuer = load_cert(bio_err, *args, FORMAT_PEM);
242                                 if(!issuer) goto end;
243                                 }
244                         else badarg = 1;
245                         }
246                 else if (!strcmp (*args, "-cert"))
247                         {
248                         if (args[1])
249                                 {
250                                 args++;
251                                 X509_free(cert);
252                                 cert = load_cert(bio_err, *args, FORMAT_PEM);
253                                 if(!cert) goto end;
254                                 if(!add_ocsp_cert(&req, cert, issuer, ids))
255                                         goto end;
256                                 if(!sk_push(reqnames, *args))
257                                         goto end;
258                                 }
259                         else badarg = 1;
260                         }
261                 else if (!strcmp(*args, "-serial"))
262                         {
263                         if (args[1])
264                                 {
265                                 args++;
266                                 if(!add_ocsp_serial(&req, *args, issuer, ids))
267                                         goto end;
268                                 if(!sk_push(reqnames, *args))
269                                         goto end;
270                                 }
271                         else badarg = 1;
272                         }
273                 else badarg = 1;
274                 args++;
275                 }
276
277         /* Have we anything to do? */
278         if (!req && !reqin && !respin) badarg = 1;
279
280         if (badarg)
281                 {
282                 BIO_printf (bio_err, "OCSP utility\n");
283                 BIO_printf (bio_err, "Usage ocsp [options]\n");
284                 BIO_printf (bio_err, "where options are\n");
285                 BIO_printf (bio_err, "-out file     output filename\n");
286                 BIO_printf (bio_err, "-issuer file  issuer certificate\n");
287                 BIO_printf (bio_err, "-cert file    certificate to check\n");
288                 BIO_printf (bio_err, "-serial n     serial number to check\n");
289                 BIO_printf (bio_err, "-signer file  certificate to sign OCSP request with\n");
290                 BIO_printf (bio_err, "-signkey file private key to sign OCSP request with\n");
291                 BIO_printf (bio_err, "-req_text     print text form of request\n");
292                 BIO_printf (bio_err, "-resp_text    print text form of response\n");
293                 BIO_printf (bio_err, "-text         print text form of request and response\n");
294                 BIO_printf (bio_err, "-reqout file  write DER encoded OCSP request to \"file\"\n");
295                 BIO_printf (bio_err, "-respout file write DER encoded OCSP reponse to \"file\"\n");
296                 BIO_printf (bio_err, "-reqin file   read DER encoded OCSP request from \"file\"\n");
297                 BIO_printf (bio_err, "-respin file  read DER encoded OCSP reponse from \"file\"\n");
298                 BIO_printf (bio_err, "-nonce        add OCSP nonce to request\n");
299                 BIO_printf (bio_err, "-no_nonce     don't add OCSP nonce to request\n");
300                 BIO_printf (bio_err, "-host host:n  send OCSP request to host on port n\n");
301                 BIO_printf (bio_err, "-path         path to use in OCSP request\n");
302                 BIO_printf (bio_err, "-CApath dir   trusted certificates directory\n");
303                 BIO_printf (bio_err, "-CAfile file  trusted certificates file\n");
304                 BIO_printf (bio_err, "-VAfile file  validator certificates file\n");
305                 BIO_printf (bio_err, "-noverify     don't verify response\n");
306                 goto end;
307                 }
308
309         if(outfile) out = BIO_new_file(outfile, "w");
310         else out = BIO_new_fp(stdout, BIO_NOCLOSE);
311
312         if(!out)
313                 {
314                 BIO_printf(bio_err, "Error opening output file\n");
315                 goto end;
316                 }
317
318         if (!req && (add_nonce != 2)) add_nonce = 0;
319
320         if (!req && reqin)
321                 {
322                 derbio = BIO_new_file(reqin, "rb");
323                 if (!derbio)
324                         {
325                         BIO_printf(bio_err, "Error Opening OCSP request file\n");
326                         goto end;
327                         }
328                 req = d2i_OCSP_REQUEST_bio(derbio, NULL);
329                 BIO_free(derbio);
330                 if(!req)
331                         {
332                         BIO_printf(bio_err, "Error reading OCSP request\n");
333                         goto end;
334                         }
335                 }
336
337         if (!req && (signfile || reqout || host || add_nonce))
338                 {
339                 BIO_printf(bio_err, "Need an OCSP request for this operation!\n");
340                 goto end;
341                 }
342
343         if (req && add_nonce) OCSP_request_add1_nonce(req, NULL, -1);
344
345         if (signfile)
346                 {
347                 if (!keyfile) keyfile = signfile;
348                 signer = load_cert(bio_err, signfile, FORMAT_PEM);
349                 if (!signer)
350                         {
351                         BIO_printf(bio_err, "Error loading signer certificate\n");
352                         goto end;
353                         }
354                 key = load_key(bio_err, keyfile, FORMAT_PEM, NULL, NULL);
355                 if (!key)
356                         {
357                         BIO_printf(bio_err, "Error loading signer private key\n");
358                         goto end;
359                         }
360                 if (!OCSP_request_sign(req, signer, key, EVP_sha1(), NULL, 0))
361                         {
362                         BIO_printf(bio_err, "Error signing OCSP request\n");
363                         goto end;
364                         }
365                 }
366
367         if (reqout)
368                 {
369                 derbio = BIO_new_file(reqout, "wb");
370                 if (!derbio)
371                         {
372                         BIO_printf(bio_err, "Error opening file %s\n", reqout);
373                         goto end;
374                         }
375                 i2d_OCSP_REQUEST_bio(derbio, req);
376                 BIO_free(derbio);
377                 }
378
379         if (req_text && req) OCSP_REQUEST_print(out, req, 0);
380
381         if (host)
382                 {
383                 cbio = BIO_new_connect(host);
384                 if (!cbio)
385                         {
386                         BIO_printf(bio_err, "Error creating connect BIO\n");
387                         goto end;
388                         }
389                 if (BIO_do_connect(cbio) <= 0)
390                         {
391                         BIO_printf(bio_err, "Error connecting BIO\n");
392                         goto end;
393                         }
394                 resp = OCSP_sendreq_bio(cbio, path, req);
395                 BIO_free(cbio);
396                 cbio = NULL;
397                 if (!resp)
398                         {
399                         BIO_printf(bio_err, "Error querying OCSP responsder\n");
400                         goto end;
401                         }
402                 }
403         else if (respin)
404                 {
405                 derbio = BIO_new_file(respin, "rb");
406                 if (!derbio)
407                         {
408                         BIO_printf(bio_err, "Error Opening OCSP response file\n");
409                         goto end;
410                         }
411                 resp = d2i_OCSP_RESPONSE_bio(derbio, NULL);
412                 BIO_free(derbio);
413                 if(!resp)
414                         {
415                         BIO_printf(bio_err, "Error reading OCSP response\n");
416                         goto end;
417                         }
418         
419                 }
420         else
421                 {
422                 ret = 0;
423                 goto end;
424                 }
425
426         if (respout)
427                 {
428                 derbio = BIO_new_file(respout, "wb");
429                 if(!derbio)
430                         {
431                         BIO_printf(bio_err, "Error opening file %s\n", respout);
432                         goto end;
433                         }
434                 i2d_OCSP_RESPONSE_bio(derbio, resp);
435                 BIO_free(derbio);
436                 }
437
438         i = OCSP_response_status(resp);
439
440         if (i != OCSP_RESPONSE_STATUS_SUCCESSFUL)
441                 {
442                 BIO_printf(out, "Responder Error: %s (%ld)\n",
443                                 OCSP_response_status_str(i), i);
444                 ret = 0;
445                 goto end;
446                 }
447
448         if (resp_text) OCSP_RESPONSE_print(out, resp, 0);
449
450         store = setup_verify(bio_err, CAfile, CApath);
451         if(!store) goto end;
452
453         if (VAfile) VAstore = load_certs(bio_err, VAfile, FORMAT_PEM);
454
455         bs = OCSP_response_get1_basic(resp);
456
457         if (!bs)
458                 {
459                 BIO_printf(bio_err, "Error parsing response\n");
460                 goto end;
461                 }
462
463         if (!noverify)
464                 {
465                 if (req && (OCSP_check_nonce(req, bs) <= 0))
466                         {
467                         BIO_printf(bio_err, "Nonce Verify error\n");
468                         goto end;
469                         }
470
471                 i = OCSP_basic_verify(bs, VAstore, store, OCSP_TRUSTOTHER);
472                 if (i < 0) i = OCSP_basic_verify(bs, NULL, store, 0);
473
474                 if(i <= 0)
475                         {
476                         BIO_printf(bio_err, "Response Verify Failure\n", i);
477                         ERR_print_errors(bio_err);
478                         }
479                 else
480                         BIO_printf(bio_err, "Response verify OK\n");
481
482                 }
483
484         if (!print_ocsp_summary(out, bs, req, reqnames, ids))
485                 goto end;
486
487         ret = 0;
488
489 end:
490         ERR_print_errors(bio_err);
491         X509_free(signer);
492         X509_STORE_free(store);
493         sk_X509_free(VAstore);
494         EVP_PKEY_free(key);
495         X509_free(issuer);
496         X509_free(cert);
497         BIO_free(cbio);
498         BIO_free(out);
499         OCSP_REQUEST_free(req);
500         OCSP_RESPONSE_free(resp);
501         OCSP_BASICRESP_free(bs);
502         sk_free(reqnames);
503         sk_OCSP_CERTID_free(ids);
504
505         EXIT(ret);
506 }
507
508 static int add_ocsp_cert(OCSP_REQUEST **req, X509 *cert, X509 *issuer,
509                                 STACK_OF(OCSP_CERTID) *ids)
510         {
511         OCSP_CERTID *id;
512         if(!issuer)
513                 {
514                 BIO_printf(bio_err, "No issuer certificate specified\n");
515                 return 0;
516                 }
517         if(!*req) *req = OCSP_REQUEST_new();
518         if(!*req) goto err;
519         id = OCSP_cert_to_id(NULL, cert, issuer);
520         if(!id || !sk_OCSP_CERTID_push(ids, id)) goto err;
521         if(!OCSP_request_add0_id(*req, id)) goto err;
522         return 1;
523
524         err:
525         BIO_printf(bio_err, "Error Creating OCSP request\n");
526         return 0;
527         }
528
529 static int add_ocsp_serial(OCSP_REQUEST **req, char *serial, X509 *issuer,
530                                 STACK_OF(OCSP_CERTID) *ids)
531         {
532         OCSP_CERTID *id;
533         X509_NAME *iname;
534         ASN1_BIT_STRING *ikey;
535         ASN1_INTEGER *sno;
536         if(!issuer)
537                 {
538                 BIO_printf(bio_err, "No issuer certificate specified\n");
539                 return 0;
540                 }
541         if(!*req) *req = OCSP_REQUEST_new();
542         if(!*req) goto err;
543         iname = X509_get_subject_name(issuer);
544         ikey = X509_get0_pubkey_bitstr(issuer);
545         sno = s2i_ASN1_INTEGER(NULL, serial);
546         if(!sno)
547                 {
548                 BIO_printf(bio_err, "Error converting serial number %s\n", serial);
549                 return 0;
550                 }
551         id = OCSP_cert_id_new(EVP_sha1(), iname, ikey, sno);
552         ASN1_INTEGER_free(sno);
553         if(!id || !sk_OCSP_CERTID_push(ids, id)) goto err;
554         if(!OCSP_request_add0_id(*req, id)) goto err;
555         return 1;
556
557         err:
558         BIO_printf(bio_err, "Error Creating OCSP request\n");
559         return 0;
560         }
561
562 static int print_ocsp_summary(BIO *out, OCSP_BASICRESP *bs, OCSP_REQUEST *req,
563                                         STACK *names, STACK_OF(OCSP_CERTID) *ids)
564         {
565         OCSP_CERTID *id;
566         char *name;
567         int i;
568
569         int status, reason;
570
571         ASN1_GENERALIZEDTIME *rev, *thisupd, *nextupd;
572
573         if (!bs || !req || !sk_num(names) || !sk_OCSP_CERTID_num(ids))
574                 return 1;
575
576         for (i = 0; i < sk_OCSP_CERTID_num(ids); i++)
577                 {
578                 id = sk_OCSP_CERTID_value(ids, i);
579                 name = sk_value(names, i);
580                 BIO_printf(out, "%s: ", name);
581
582                 if(!OCSP_resp_find_status(bs, id, &status, &reason,
583                                         &rev, &thisupd, &nextupd))
584                         {
585                         BIO_puts(out, "ERROR: No Status found.\n");
586                         continue;
587                         }
588                 BIO_printf(out, "%s\n", OCSP_cert_status_str(status));
589
590                 BIO_puts(out, "\tThis Update: ");
591                 ASN1_GENERALIZEDTIME_print(out, thisupd);
592                 BIO_puts(out, "\n");
593
594                 if(nextupd)
595                         {
596                         BIO_puts(out, "\tNext Update: ");
597                         ASN1_GENERALIZEDTIME_print(out, thisupd);
598                         BIO_puts(out, "\n");
599                         }
600
601                 if (status != V_OCSP_CERTSTATUS_REVOKED)
602                         continue;
603
604                 if (reason != -1)
605                         BIO_printf(out, "\tReason: %s\n",
606                                 OCSP_crl_reason_str(reason));
607
608                 BIO_puts(out, "\tRevocation Time: ");
609                 ASN1_GENERALIZEDTIME_print(out, rev);
610                 BIO_puts(out, "\n");
611                 }
612
613         return 1;
614         }
615