bea16ebb711763f7fbe162abeebfb4663e575d2f
[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 static int add_ocsp_serial(OCSP_REQUEST **req, char *serial, X509 *issuer);
68
69 #undef PROG
70 #define PROG ocsp_main
71
72 int MAIN(int, char **);
73
74 int MAIN(int argc, char **argv)
75         {
76         char **args;
77         char *host = NULL, *path = "/";
78         char *reqin = NULL, *respin = NULL;
79         char *reqout = NULL, *respout = NULL;
80         char *signfile = NULL, *keyfile = NULL;
81         char *outfile = NULL;
82         int add_nonce = 1;
83         OCSP_REQUEST *req = NULL;
84         OCSP_RESPONSE *resp = NULL;
85         OCSP_BASICRESP *bs = NULL;
86         X509 *issuer = NULL, *cert = NULL;
87         X509 *signer = NULL;
88         EVP_PKEY *key = NULL;
89         BIO *cbio = NULL, *derbio = NULL;
90         BIO *out = NULL;
91         int req_text = 0, resp_text = 0;
92         char *CAfile = NULL, *CApath = NULL;
93         X509_STORE *store = NULL;
94         int ret = 1;
95         int badarg = 0;
96         int i;
97         if (bio_err == NULL) bio_err = BIO_new_fp(stderr, BIO_NOCLOSE);
98         ERR_load_crypto_strings();
99         args = argv + 1;
100         while (!badarg && *args && *args[0] == '-')
101                 {
102                 if (!strcmp(*args, "-out"))
103                         {
104                         if (args[1])
105                                 {
106                                 args++;
107                                 outfile = *args;
108                                 }
109                         else badarg = 1;
110                         }
111                 else if (!strcmp(*args, "-host"))
112                         {
113                         if (args[1])
114                                 {
115                                 args++;
116                                 host = *args;
117                                 }
118                         else badarg = 1;
119                         }
120                 else if (!strcmp(*args, "-nonce"))
121                         add_nonce = 2;
122                 else if (!strcmp(*args, "-no_nonce"))
123                         add_nonce = 0;
124                 else if (!strcmp(*args, "-text"))
125                         {
126                         req_text = 1;
127                         resp_text = 1;
128                         }
129                 else if (!strcmp(*args, "-req_text"))
130                         req_text = 1;
131                 else if (!strcmp(*args, "-resp_text"))
132                         resp_text = 1;
133                 else if (!strcmp(*args, "-reqin"))
134                         {
135                         if (args[1])
136                                 {
137                                 args++;
138                                 reqin = *args;
139                                 }
140                         else badarg = 1;
141                         }
142                 else if (!strcmp(*args, "-respin"))
143                         {
144                         if (args[1])
145                                 {
146                                 args++;
147                                 respin = *args;
148                                 }
149                         else badarg = 1;
150                         }
151                 else if (!strcmp(*args, "-signer"))
152                         {
153                         if (args[1])
154                                 {
155                                 args++;
156                                 signfile = *args;
157                                 }
158                         else badarg = 1;
159                         }
160                 else if (!strcmp (*args, "-CAfile"))
161                         {
162                         if (args[1])
163                                 {
164                                 args++;
165                                 CAfile = *args;
166                                 }
167                         else badarg = 1;
168                         }
169                 else if (!strcmp (*args, "-CApath"))
170                         {
171                         if (args[1])
172                                 {
173                                 args++;
174                                 CApath = *args;
175                                 }
176                         else badarg = 1;
177                         }
178                  else if (!strcmp(*args, "-signkey"))
179                         {
180                         if (args[1])
181                                 {
182                                 args++;
183                                 keyfile = *args;
184                                 }
185                         else badarg = 1;
186                         }
187                 else if (!strcmp(*args, "-reqout"))
188                         {
189                         if (args[1])
190                                 {
191                                 args++;
192                                 reqout = *args;
193                                 }
194                         else badarg = 1;
195                         }
196                 else if (!strcmp(*args, "-respout"))
197                         {
198                         if (args[1])
199                                 {
200                                 args++;
201                                 respout = *args;
202                                 }
203                         else badarg = 1;
204                         }
205                  else if (!strcmp(*args, "-path"))
206                         {
207                         if (args[1])
208                                 {
209                                 args++;
210                                 path = *args;
211                                 }
212                         else badarg = 1;
213                         }
214                 else if (!strcmp(*args, "-issuer"))
215                         {
216                         if (args[1])
217                                 {
218                                 args++;
219                                 X509_free(issuer);
220                                 issuer = load_cert(bio_err, *args, FORMAT_PEM);
221                                 if(!issuer) goto end;
222                                 }
223                         else badarg = 1;
224                         }
225                 else if (!strcmp (*args, "-cert"))
226                         {
227                         if (args[1])
228                                 {
229                                 args++;
230                                 X509_free(cert);
231                                 cert = load_cert(bio_err, *args, FORMAT_PEM);
232                                 if(!cert) goto end;
233                                 if(!add_ocsp_cert(&req, cert, issuer))
234                                         goto end;
235                                 }
236                         else badarg = 1;
237                         }
238                 else if (!strcmp(*args, "-serial"))
239                         {
240                         if (args[1])
241                                 {
242                                 args++;
243                                 if(!add_ocsp_serial(&req, *args, issuer))
244                                         goto end;
245                                 }
246                         else badarg = 1;
247                         }
248                 else badarg = 1;
249                 args++;
250                 }
251
252         /* Have we anything to do? */
253         if (!req && !reqin && !respin) badarg = 1;
254
255         if (badarg)
256                 {
257                 BIO_printf (bio_err, "OCSP utility\n");
258                 BIO_printf (bio_err, "Usage ocsp [options]\n");
259                 BIO_printf (bio_err, "where options are\n");
260                 BIO_printf (bio_err, "-out file     output filename\n");
261                 BIO_printf (bio_err, "-issuer file  issuer certificate\n");
262                 BIO_printf (bio_err, "-cert file    certificate to check\n");
263                 BIO_printf (bio_err, "-serial n     serial number to check\n");
264                 BIO_printf (bio_err, "-signer file  certificate to sign OCSP request with\n");
265                 BIO_printf (bio_err, "-signkey file private key to sign OCSP request with\n");
266                 BIO_printf (bio_err, "-req_text     print text form of request\n");
267                 BIO_printf (bio_err, "-resp_text    print text form of response\n");
268                 BIO_printf (bio_err, "-text         print text form of request and response\n");
269                 BIO_printf (bio_err, "-reqout file  write DER encoded OCSP request to \"file\"\n");
270                 BIO_printf (bio_err, "-respout file write DER encoded OCSP reponse to \"file\"\n");
271                 BIO_printf (bio_err, "-reqin file   read DER encoded OCSP request from \"file\"\n");
272                 BIO_printf (bio_err, "-respin file  read DER encoded OCSP reponse from \"file\"\n");
273                 BIO_printf (bio_err, "-nonce        add OCSP nonce to request\n");
274                 BIO_printf (bio_err, "-no_nonce     don't add OCSP nonce to request\n");
275                 BIO_printf (bio_err, "-host host:n  send OCSP request to host on port n\n");
276                 BIO_printf (bio_err, "-path         path to use in OCSP request\n");
277                 goto end;
278                 }
279
280         if(outfile) out = BIO_new_file(outfile, "w");
281         else out = BIO_new_fp(stdout, BIO_NOCLOSE);
282
283         if(!out)
284                 {
285                 BIO_printf(bio_err, "Error opening output file\n");
286                 goto end;
287                 }
288
289         if (!req && (add_nonce != 2)) add_nonce = 0;
290
291         if (!req && reqin)
292                 {
293                 derbio = BIO_new_file(reqin, "rb");
294                 if (!derbio)
295                         {
296                         BIO_printf(bio_err, "Error Opening OCSP request file\n");
297                         goto end;
298                         }
299                 req = d2i_OCSP_REQUEST_bio(derbio, NULL);
300                 BIO_free(derbio);
301                 if(!req)
302                         {
303                         BIO_printf(bio_err, "Error reading OCSP request\n");
304                         goto end;
305                         }
306                 }
307
308         if (!req && (signfile || reqout || host || add_nonce))
309                 {
310                 BIO_printf(bio_err, "Need an OCSP request for this operation!\n");
311                 goto end;
312                 }
313
314         if (req) OCSP_request_add1_nonce(req, NULL, -1);
315
316         if (signfile)
317                 {
318                 if (!keyfile) keyfile = signfile;
319                 signer = load_cert(bio_err, signfile, FORMAT_PEM);
320                 if (!signer)
321                         {
322                         BIO_printf(bio_err, "Error loading signer certificate\n");
323                         goto end;
324                         }
325                 key = load_key(bio_err, keyfile, FORMAT_PEM, NULL, NULL);
326                 if (!key)
327                         {
328                         BIO_printf(bio_err, "Error loading signer private key\n");
329                         goto end;
330                         }
331                 if (!OCSP_request_sign(req, signer, key, EVP_sha1(), NULL, 0))
332                         {
333                         BIO_printf(bio_err, "Error signing OCSP request\n");
334                         goto end;
335                         }
336                 }
337
338         if (reqout)
339                 {
340                 derbio = BIO_new_file(reqout, "wb");
341                 if (!derbio)
342                         {
343                         BIO_printf(bio_err, "Error opening file %s\n", reqout);
344                         goto end;
345                         }
346                 i2d_OCSP_REQUEST_bio(derbio, req);
347                 BIO_free(derbio);
348                 }
349
350         if (req_text && req) OCSP_REQUEST_print(out, req, 0);
351
352         if (host)
353                 {
354                 cbio = BIO_new_connect(host);
355                 if (!cbio)
356                         {
357                         BIO_printf(bio_err, "Error creating connect BIO\n");
358                         goto end;
359                         }
360                 if (BIO_do_connect(cbio) <= 0)
361                         {
362                         BIO_printf(bio_err, "Error connecting BIO\n");
363                         goto end;
364                         }
365                 resp = OCSP_sendreq_bio(cbio, path, req);
366                 BIO_free(cbio);
367                 cbio = NULL;
368                 if (!resp)
369                         {
370                         BIO_printf(bio_err, "Error querying OCSP responsder\n");
371                         goto end;
372                         }
373                 }
374         else if (respin)
375                 {
376                 derbio = BIO_new_file(respin, "rb");
377                 if (!derbio)
378                         {
379                         BIO_printf(bio_err, "Error Opening OCSP response file\n");
380                         goto end;
381                         }
382                 resp = d2i_OCSP_RESPONSE_bio(derbio, NULL);
383                 BIO_free(derbio);
384                 if(!resp)
385                         {
386                         BIO_printf(bio_err, "Error reading OCSP response\n");
387                         goto end;
388                         }
389         
390                 }
391         else
392                 {
393                 ret = 0;
394                 goto end;
395                 }
396
397         if (respout)
398                 {
399                 derbio = BIO_new_file(respout, "wb");
400                 if(!derbio)
401                         {
402                         BIO_printf(bio_err, "Error opening file %s\n", respout);
403                         goto end;
404                         }
405                 i2d_OCSP_RESPONSE_bio(derbio, resp);
406                 BIO_free(derbio);
407                 }
408
409         if (resp_text) OCSP_RESPONSE_print(out, resp, 0);
410
411         store = setup_verify(bio_err, CAfile, CApath);
412         if(!store) goto end;
413
414         bs = OCSP_response_get1_basic(resp);
415
416         i = OCSP_basic_verify(bs, NULL, store, 0);
417
418         if(i <= 0)
419                 {
420                 BIO_printf(bio_err, "Response verify error (%d)\n", i);
421                 ERR_print_errors(bio_err);
422                 }
423         else
424                 BIO_printf(bio_err, "Response verify OK\n");
425
426         ret = 0;
427
428 end:
429         ERR_print_errors(bio_err);
430         X509_free(signer);
431         X509_STORE_free(store);
432         EVP_PKEY_free(key);
433         X509_free(issuer);
434         X509_free(cert);
435         BIO_free(cbio);
436         BIO_free(out);
437         OCSP_REQUEST_free(req);
438         OCSP_RESPONSE_free(resp);
439         OCSP_BASICRESP_free(bs);
440
441         EXIT(ret);
442 }
443
444 static int add_ocsp_cert(OCSP_REQUEST **req, X509 *cert, X509 *issuer)
445         {
446         OCSP_CERTID *id;
447         if(!issuer)
448                 {
449                 BIO_printf(bio_err, "No issuer certificate specified\n");
450                 return 0;
451                 }
452         if(!*req) *req = OCSP_REQUEST_new();
453         if(!*req) goto err;
454         id = OCSP_cert_to_id(NULL, cert, issuer);
455         if(!id) goto err;
456         if(!OCSP_request_add0_id(*req, id)) goto err;
457         return 1;
458
459         err:
460         BIO_printf(bio_err, "Error Creating OCSP request\n");
461         return 0;
462         }
463
464 static int add_ocsp_serial(OCSP_REQUEST **req, char *serial, X509 *issuer)
465         {
466         OCSP_CERTID *id;
467         X509_NAME *iname;
468         ASN1_BIT_STRING *ikey;
469         ASN1_INTEGER *sno;
470         if(!issuer)
471                 {
472                 BIO_printf(bio_err, "No issuer certificate specified\n");
473                 return 0;
474                 }
475         if(!*req) *req = OCSP_REQUEST_new();
476         if(!*req) goto err;
477         iname = X509_get_subject_name(issuer);
478         ikey = issuer->cert_info->key->public_key;
479         sno = s2i_ASN1_INTEGER(NULL, serial);
480         if(!sno)
481                 {
482                 BIO_printf(bio_err, "Error converting serial number %s\n", serial);
483                 return 0;
484                 }
485         id = OCSP_cert_id_new(EVP_sha1(), iname, ikey, sno);
486         ASN1_INTEGER_free(sno);
487         if(!id) goto err;
488         if(!OCSP_request_add0_id(*req, id)) goto err;
489         return 1;
490
491         err:
492         BIO_printf(bio_err, "Error Creating OCSP request\n");
493         return 0;
494         }