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