Preliminary ocsp utility documentation.
[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, "-out file     output filename\n");
239                 BIO_printf (bio_err, "-issuer file  issuer certificate\n");
240                 BIO_printf (bio_err, "-cert file    certificate to check\n");
241                 BIO_printf (bio_err, "-serial n     serial number to check\n");
242                 BIO_printf (bio_err, "-signer file  certificate to sign OCSP request with\n");
243                 BIO_printf (bio_err, "-signkey file private key to sign OCSP request with\n");
244                 BIO_printf (bio_err, "-req_text     print text form of request\n");
245                 BIO_printf (bio_err, "-resp_text    print text form of response\n");
246                 BIO_printf (bio_err, "-text         print text form of request and response\n");
247                 BIO_printf (bio_err, "-reqout file  write DER encoded OCSP request to \"file\"\n");
248                 BIO_printf (bio_err, "-respout file write DER encoded OCSP reponse to \"file\"\n");
249                 BIO_printf (bio_err, "-reqin file   read DER encoded OCSP request from \"file\"\n");
250                 BIO_printf (bio_err, "-respin file  read DER encoded OCSP reponse from \"file\"\n");
251                 BIO_printf (bio_err, "-nonce        add OCSP nonce to request\n");
252                 BIO_printf (bio_err, "-no_nonce     don't add OCSP nonce to request\n");
253                 BIO_printf (bio_err, "-host host:n  send OCSP request to host on port n\n");
254                 BIO_printf (bio_err, "-path         path to use in OCSP request\n");
255                 goto end;
256                 }
257
258         if(outfile) out = BIO_new_file(outfile, "w");
259         else out = BIO_new_fp(stdout, BIO_NOCLOSE);
260
261         if(!out)
262                 {
263                 BIO_printf(bio_err, "Error opening output file\n");
264                 goto end;
265                 }
266
267         if (!req && (add_nonce != 2)) add_nonce = 0;
268
269         if (!req && reqin)
270                 {
271                 derbio = BIO_new_file(reqin, "rb");
272                 if (!derbio)
273                         {
274                         BIO_printf(bio_err, "Error Opening OCSP request file\n");
275                         goto end;
276                         }
277                 req = d2i_OCSP_REQUEST_bio(derbio, NULL);
278                 BIO_free(derbio);
279                 if(!req)
280                         {
281                         BIO_printf(bio_err, "Error reading OCSP request\n");
282                         goto end;
283                         }
284                 }
285
286         if (!req && (signfile || reqout || host || add_nonce))
287                 {
288                 BIO_printf(bio_err, "Need an OCSP request for this operation!\n");
289                 goto end;
290                 }
291
292         if (req) OCSP_request_add1_nonce(req, NULL, -1);
293
294         if (signfile)
295                 {
296                 if (!keyfile) keyfile = signfile;
297                 signer = load_cert(bio_err, signfile, FORMAT_PEM);
298                 if (!signer)
299                         {
300                         BIO_printf(bio_err, "Error loading signer certificate\n");
301                         goto end;
302                         }
303                 key = load_key(bio_err, keyfile, FORMAT_PEM, NULL, NULL);
304                 if (!key)
305                         {
306                         BIO_printf(bio_err, "Error loading signer private key\n");
307                         goto end;
308                         }
309                 if (!OCSP_request_sign(req, signer, key, EVP_sha1(), NULL, 0))
310                         {
311                         BIO_printf(bio_err, "Error signing OCSP request\n");
312                         goto end;
313                         }
314                 }
315
316         if (reqout)
317                 {
318                 derbio = BIO_new_file(reqout, "wb");
319                 if (!derbio)
320                         {
321                         BIO_printf(bio_err, "Error opening file %s\n", reqout);
322                         goto end;
323                         }
324                 i2d_OCSP_REQUEST_bio(derbio, req);
325                 BIO_free(derbio);
326                 }
327
328         if (req_text && req) OCSP_REQUEST_print(out, req, 0);
329
330         if (host)
331                 {
332                 cbio = BIO_new_connect(host);
333                 if (!cbio)
334                         {
335                         BIO_printf(bio_err, "Error creating connect BIO\n");
336                         goto end;
337                         }
338                 if (BIO_do_connect(cbio) <= 0)
339                         {
340                         BIO_printf(bio_err, "Error connecting BIO\n");
341                         goto end;
342                         }
343                 resp = OCSP_sendreq_bio(cbio, path, req);
344                 BIO_free(cbio);
345                 cbio = NULL;
346                 if (!resp)
347                         {
348                         BIO_printf(bio_err, "Error querying OCSP responsder\n");
349                         goto end;
350                         }
351                 }
352         else if (respin)
353                 {
354                 derbio = BIO_new_file(respin, "rb");
355                 if (!derbio)
356                         {
357                         BIO_printf(bio_err, "Error Opening OCSP response file\n");
358                         goto end;
359                         }
360                 resp = d2i_OCSP_RESPONSE_bio(derbio, NULL);
361                 BIO_free(derbio);
362                 if(!resp)
363                         {
364                         BIO_printf(bio_err, "Error reading OCSP response\n");
365                         goto end;
366                         }
367         
368                 }
369         else
370                 {
371                 ret = 0;
372                 goto end;
373                 }
374
375         if (respout)
376                 {
377                 derbio = BIO_new_file(respout, "wb");
378                 if(!derbio)
379                         {
380                         BIO_printf(bio_err, "Error opening file %s\n", respout);
381                         goto end;
382                         }
383                 i2d_OCSP_RESPONSE_bio(derbio, resp);
384                 BIO_free(derbio);
385                 }
386
387         if (resp_text) OCSP_RESPONSE_print(out, resp, 0);
388
389         ret = 0;
390
391 end:
392         ERR_print_errors(bio_err);
393         X509_free(signer);
394         EVP_PKEY_free(key);
395         X509_free(issuer);
396         X509_free(cert);
397         BIO_free(cbio);
398         BIO_free(out);
399         OCSP_REQUEST_free(req);
400         OCSP_RESPONSE_free(resp);
401
402         EXIT(ret);
403 }
404
405 static int add_ocsp_cert(OCSP_REQUEST **req, X509 *cert, X509 *issuer)
406         {
407         OCSP_CERTID *id;
408         if(!issuer)
409                 {
410                 BIO_printf(bio_err, "No issuer certificate specified\n");
411                 return 0;
412                 }
413         if(!*req) *req = OCSP_REQUEST_new();
414         if(!*req) goto err;
415         id = OCSP_cert_to_id(NULL, cert, issuer);
416         if(!id) goto err;
417         if(!OCSP_request_add0_id(*req, id)) goto err;
418         return 1;
419
420         err:
421         BIO_printf(bio_err, "Error Creating OCSP request\n");
422         return 0;
423         }
424
425 static int add_ocsp_serial(OCSP_REQUEST **req, char *serial, X509 *issuer)
426         {
427         OCSP_CERTID *id;
428         X509_NAME *iname;
429         ASN1_BIT_STRING *ikey;
430         ASN1_INTEGER *sno;
431         if(!issuer)
432                 {
433                 BIO_printf(bio_err, "No issuer certificate specified\n");
434                 return 0;
435                 }
436         if(!*req) *req = OCSP_REQUEST_new();
437         if(!*req) goto err;
438         iname = X509_get_subject_name(issuer);
439         ikey = issuer->cert_info->key->public_key;
440         sno = s2i_ASN1_INTEGER(NULL, serial);
441         if(!sno)
442                 {
443                 BIO_printf(bio_err, "Error converting serial number %s\n", serial);
444                 return 0;
445                 }
446         id = OCSP_cert_id_new(EVP_sha1(), iname, ikey, sno);
447         ASN1_INTEGER_free(sno);
448         if(!id) goto err;
449         if(!OCSP_request_add0_id(*req, id)) goto err;
450         return 1;
451
452         err:
453         BIO_printf(bio_err, "Error Creating OCSP request\n");
454         return 0;
455         }