Fix CVE-2017-6891 in minitasn1 code
[platform/upstream/gnutls.git] / src / ocsptool.c
1 /*
2  * Copyright (C) 2011-2014 Free Software Foundation, Inc.
3  *
4  * This file is part of GnuTLS.
5  *
6  * GnuTLS is free software: you can redistribute it and/or modify it
7  * 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  * GnuTLS is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * 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
18  * <http://www.gnu.org/licenses/>.
19  */
20
21 #include <config.h>
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <errno.h>
27
28 #include <gnutls/gnutls.h>
29 #include <gnutls/ocsp.h>
30 #include <gnutls/x509.h>
31 #include <gnutls/crypto.h>
32
33 /* Gnulib portability files. */
34 #include <read-file.h>
35 #include <socket.h>
36
37 #include <ocsptool-common.h>
38 #include <ocsptool-args.h>
39
40 FILE *outfile;
41 FILE *infile;
42 static unsigned int encoding;
43 unsigned int verbose = 0;
44
45 static void tls_log_func(int level, const char *str)
46 {
47         fprintf(stderr, "|<%d>| %s", level, str);
48 }
49
50 static void request_info(void)
51 {
52         gnutls_ocsp_req_t req;
53         int ret;
54         gnutls_datum_t dat;
55         size_t size;
56
57         ret = gnutls_ocsp_req_init(&req);
58         if (ret < 0) {
59                 fprintf(stderr, "ocsp_req_init: %s\n", gnutls_strerror(ret));
60                 exit(1);
61         }
62
63         if (HAVE_OPT(LOAD_REQUEST))
64                 dat.data =
65                     (void *) read_binary_file(OPT_ARG(LOAD_REQUEST),
66                                               &size);
67         else
68                 dat.data = (void *) fread_file(infile, &size);
69         if (dat.data == NULL) {
70                 fprintf(stderr, "error reading request\n");
71                 exit(1);
72         }
73         dat.size = size;
74
75         ret = gnutls_ocsp_req_import(req, &dat);
76         free(dat.data);
77         if (ret < 0) {
78                 fprintf(stderr, "error importing request: %s\n",
79                         gnutls_strerror(ret));
80                 exit(1);
81         }
82
83         ret = gnutls_ocsp_req_print(req, GNUTLS_OCSP_PRINT_FULL, &dat);
84         if (ret != 0) {
85                 fprintf(stderr, "ocsp_req_print: %s\n",
86                         gnutls_strerror(ret));
87                 exit(1);
88         }
89
90         printf("%.*s", dat.size, dat.data);
91         gnutls_free(dat.data);
92
93         gnutls_ocsp_req_deinit(req);
94 }
95
96 static void _response_info(const gnutls_datum_t * data)
97 {
98         gnutls_ocsp_resp_t resp;
99         int ret;
100         gnutls_datum buf;
101
102         ret = gnutls_ocsp_resp_init(&resp);
103         if (ret < 0) {
104                 fprintf(stderr, "ocsp_resp_init: %s\n",
105                         gnutls_strerror(ret));
106                 exit(1);
107         }
108
109         ret = gnutls_ocsp_resp_import(resp, data);
110         if (ret < 0) {
111                 fprintf(stderr, "importing response: %s\n",
112                         gnutls_strerror(ret));
113                 exit(1);
114         }
115
116         if (ENABLED_OPT(VERBOSE))
117                 ret =
118                     gnutls_ocsp_resp_print(resp, GNUTLS_OCSP_PRINT_FULL,
119                                            &buf);
120         else
121                 ret =
122                     gnutls_ocsp_resp_print(resp, GNUTLS_OCSP_PRINT_COMPACT,
123                                            &buf);
124         if (ret != 0) {
125                 fprintf(stderr, "ocsp_resp_print: %s\n",
126                         gnutls_strerror(ret));
127                 exit(1);
128         }
129
130         printf("%.*s", buf.size, buf.data);
131         gnutls_free(buf.data);
132
133         gnutls_ocsp_resp_deinit(resp);
134 }
135
136 static void response_info(void)
137 {
138         gnutls_datum_t dat;
139         size_t size;
140
141         if (HAVE_OPT(LOAD_RESPONSE))
142                 dat.data =
143                     (void *) read_binary_file(OPT_ARG(LOAD_RESPONSE),
144                                               &size);
145         else
146                 dat.data = (void *) fread_file(infile, &size);
147         if (dat.data == NULL) {
148                 fprintf(stderr, "error reading response\n");
149                 exit(1);
150         }
151         dat.size = size;
152
153         _response_info(&dat);
154         gnutls_free(dat.data);
155 }
156
157 static gnutls_x509_crt_t load_issuer(void)
158 {
159         gnutls_x509_crt_t crt;
160         int ret;
161         gnutls_datum_t dat;
162         size_t size;
163
164         if (!HAVE_OPT(LOAD_ISSUER)) {
165                 fprintf(stderr, "missing --load-issuer\n");
166                 exit(1);
167         }
168
169         ret = gnutls_x509_crt_init(&crt);
170         if (ret < 0) {
171                 fprintf(stderr, "crt_init: %s\n", gnutls_strerror(ret));
172                 exit(1);
173         }
174
175         dat.data = (void *) read_binary_file(OPT_ARG(LOAD_ISSUER), &size);
176         dat.size = size;
177
178         if (!dat.data) {
179                 fprintf(stderr, "error reading --load-issuer: %s\n",
180                         OPT_ARG(LOAD_ISSUER));
181                 exit(1);
182         }
183
184         ret = gnutls_x509_crt_import(crt, &dat, encoding);
185         free(dat.data);
186         if (ret < 0) {
187                 fprintf(stderr, "error importing --load-issuer: %s: %s\n",
188                         OPT_ARG(LOAD_ISSUER), gnutls_strerror(ret));
189                 exit(1);
190         }
191
192         return crt;
193 }
194
195 static gnutls_x509_crt_t load_signer(void)
196 {
197         gnutls_x509_crt_t crt;
198         int ret;
199         gnutls_datum_t dat;
200         size_t size;
201
202         if (!HAVE_OPT(LOAD_SIGNER)) {
203                 fprintf(stderr, "missing --load-signer\n");
204                 exit(1);
205         }
206
207         ret = gnutls_x509_crt_init(&crt);
208         if (ret < 0) {
209                 fprintf(stderr, "crt_init: %s\n", gnutls_strerror(ret));
210                 exit(1);
211         }
212
213         dat.data = (void *) read_binary_file(OPT_ARG(LOAD_SIGNER), &size);
214         dat.size = size;
215
216         if (!dat.data) {
217                 fprintf(stderr, "reading --load-signer: %s\n",
218                         OPT_ARG(LOAD_SIGNER));
219                 exit(1);
220         }
221
222         ret = gnutls_x509_crt_import(crt, &dat, encoding);
223         free(dat.data);
224         if (ret < 0) {
225                 fprintf(stderr, "importing --load-signer: %s: %s\n",
226                         OPT_ARG(LOAD_SIGNER), gnutls_strerror(ret));
227                 exit(1);
228         }
229
230         return crt;
231 }
232
233 static gnutls_x509_crt_t load_cert(void)
234 {
235         gnutls_x509_crt_t crt;
236         int ret;
237         gnutls_datum_t dat;
238         size_t size;
239
240         if (!HAVE_OPT(LOAD_CERT)) {
241                 fprintf(stderr, "missing --load-cert\n");
242                 exit(1);
243         }
244
245         ret = gnutls_x509_crt_init(&crt);
246         if (ret < 0) {
247                 fprintf(stderr, "crt_init: %s\n", gnutls_strerror(ret));
248                 exit(1);
249         }
250
251         dat.data = (void *) read_binary_file(OPT_ARG(LOAD_CERT), &size);
252         dat.size = size;
253
254         if (!dat.data) {
255                 fprintf(stderr, "reading --load-cert: %s\n",
256                         OPT_ARG(LOAD_CERT));
257                 exit(1);
258         }
259
260         ret = gnutls_x509_crt_import(crt, &dat, encoding);
261         free(dat.data);
262         if (ret < 0) {
263                 fprintf(stderr, "importing --load-cert: %s: %s\n",
264                         OPT_ARG(LOAD_CERT), gnutls_strerror(ret));
265                 exit(1);
266         }
267
268         return crt;
269 }
270
271 static void generate_request(gnutls_datum_t *nonce)
272 {
273         gnutls_datum_t dat;
274
275         _generate_request(load_cert(), load_issuer(), &dat, nonce);
276
277         fwrite(dat.data, 1, dat.size, outfile);
278
279         gnutls_free(dat.data);
280 }
281
282
283 static int _verify_response(gnutls_datum_t * data, gnutls_datum_t * nonce,
284         gnutls_x509_crt_t signer)
285 {
286         gnutls_ocsp_resp_t resp;
287         int ret;
288         size_t size;
289         gnutls_x509_crt_t *x509_ca_list = NULL;
290         gnutls_x509_trust_list_t list;
291         unsigned int x509_ncas = 0;
292         unsigned verify;
293         gnutls_datum_t dat;
294
295         ret = gnutls_ocsp_resp_init(&resp);
296         if (ret < 0) {
297                 fprintf(stderr, "ocsp_resp_init: %s\n",
298                         gnutls_strerror(ret));
299                 exit(1);
300         }
301
302         ret = gnutls_ocsp_resp_import(resp, data);
303         if (ret < 0) {
304                 fprintf(stderr, "importing response: %s\n",
305                         gnutls_strerror(ret));
306                 exit(1);
307         }
308
309         if (nonce) {
310                 gnutls_datum_t rnonce;
311
312                 ret = gnutls_ocsp_resp_get_nonce(resp, NULL, &rnonce);
313                 if (ret < 0) {
314                         fprintf(stderr, "could not read response's nonce: %s\n",
315                                 gnutls_strerror(ret));
316                         exit(1);
317                 }
318
319                 if (rnonce.size != nonce->size || memcmp(nonce->data, rnonce.data,
320                         nonce->size) != 0) {
321                         fprintf(stderr, "nonce in the response doesn't match\n");
322                         exit(1);
323                 }
324
325                 gnutls_free(rnonce.data);
326         }
327
328         if (HAVE_OPT(LOAD_TRUST)) {
329                 dat.data =
330                     (void *) read_binary_file(OPT_ARG(LOAD_TRUST), &size);
331                 if (dat.data == NULL) {
332                         fprintf(stderr, "reading --load-trust: %s\n",
333                                 OPT_ARG(LOAD_TRUST));
334                         exit(1);
335                 }
336                 dat.size = size;
337
338                 ret = gnutls_x509_trust_list_init(&list, 0);
339                 if (ret < 0) {
340                         fprintf(stderr, "gnutls_x509_trust_list_init: %s\n",
341                                 gnutls_strerror(ret));
342                         exit(1);
343                 }
344
345                 ret =
346                     gnutls_x509_crt_list_import2(&x509_ca_list, &x509_ncas,
347                                                  &dat, GNUTLS_X509_FMT_PEM,
348                                                  0);
349                 if (ret < 0 || x509_ncas < 1) {
350                         fprintf(stderr, "error parsing CAs: %s\n",
351                                 gnutls_strerror(ret));
352                         exit(1);
353                 }
354
355                 if (HAVE_OPT(VERBOSE)) {
356                         unsigned int i;
357                         printf("Trust anchors:\n");
358                         for (i = 0; i < x509_ncas; i++) {
359                                 gnutls_datum_t out;
360
361                                 ret =
362                                     gnutls_x509_crt_print(x509_ca_list[i],
363                                                           GNUTLS_CRT_PRINT_ONELINE,
364                                                           &out);
365                                 if (ret < 0) {
366                                         fprintf(stderr,
367                                                 "gnutls_x509_crt_print: %s\n",
368                                                 gnutls_strerror(ret));
369                                         exit(1);
370                                 }
371
372                                 printf("%d: %.*s\n", i, out.size,
373                                        out.data);
374                                 gnutls_free(out.data);
375                         }
376                         printf("\n");
377                 }
378
379                 ret =
380                     gnutls_x509_trust_list_add_cas(list, x509_ca_list,
381                                                    x509_ncas, 0);
382                 if (ret < 0) {
383                         fprintf(stderr, "gnutls_x509_trust_add_cas: %s\n",
384                                 gnutls_strerror(ret));
385                         exit(1);
386                 }
387
388                 if (HAVE_OPT(VERBOSE))
389                         fprintf(stdout, "Loaded %d trust anchors\n",
390                                 x509_ncas);
391
392                 ret = gnutls_ocsp_resp_verify(resp, list, &verify, 0);
393                 if (ret < 0) {
394                         fprintf(stderr, "gnutls_ocsp_resp_verify: %s\n",
395                                 gnutls_strerror(ret));
396                         exit(1);
397                 }
398         } else if (signer) {
399                 if (HAVE_OPT(VERBOSE)) {
400                         gnutls_datum_t out;
401
402                         ret =
403                             gnutls_x509_crt_print(signer,
404                                                   GNUTLS_CRT_PRINT_ONELINE,
405                                                   &out);
406                         if (ret < 0) {
407                                 fprintf(stderr,
408                                         "gnutls_x509_crt_print: %s\n",
409                                         gnutls_strerror(ret));
410                                 exit(1);
411                         }
412
413                         printf("Signer: %.*s\n", out.size, out.data);
414                         gnutls_free(out.data);
415                         printf("\n");
416                 }
417
418                 ret =
419                     gnutls_ocsp_resp_verify_direct(resp, signer, &verify,
420                                                    0);
421                 if (ret < 0) {
422                         fprintf(stderr,
423                                 "gnutls_ocsp_resp_verify_direct: %s\n",
424                                 gnutls_strerror(ret));
425                         exit(1);
426                 }
427         } else {
428                 fprintf(stderr, "missing --load-trust or --load-signer\n");
429                 exit(1);
430         }
431
432         printf("Verifying OCSP Response: ");
433         print_ocsp_verify_res(verify);
434         printf(".\n");
435
436         gnutls_ocsp_resp_deinit(resp);
437
438         return verify;
439 }
440
441 static void verify_response(gnutls_datum_t *nonce)
442 {
443         gnutls_datum_t dat;
444         size_t size;
445         gnutls_x509_crt_t signer;
446
447         if (HAVE_OPT(LOAD_RESPONSE))
448                 dat.data =
449                     (void *) read_binary_file(OPT_ARG(LOAD_RESPONSE),
450                                               &size);
451         else
452                 dat.data = (void *) fread_file(infile, &size);
453         if (dat.data == NULL) {
454                 fprintf(stderr, "error reading response\n");
455                 exit(1);
456         }
457         dat.size = size;
458
459         signer = load_signer();
460
461         _verify_response(&dat, nonce, signer);
462 }
463
464 static void ask_server(const char *url)
465 {
466         gnutls_datum_t resp_data;
467         int ret, v;
468         gnutls_x509_crt_t cert, issuer;
469         unsigned char noncebuf[23];
470         gnutls_datum_t nonce = { noncebuf, sizeof(noncebuf) };
471         gnutls_datum_t *n;
472
473         cert = load_cert();
474         issuer = load_issuer();
475
476         if (ENABLED_OPT(NONCE)) {
477                 ret =
478                     gnutls_rnd(GNUTLS_RND_NONCE, nonce.data, nonce.size);
479                 if (ret < 0) {
480                         fprintf(stderr, "gnutls_rnd: %s\n",
481                                 gnutls_strerror(ret));
482                         exit(1);
483                 }
484                 n = &nonce;
485
486         } else {
487                 n = NULL;
488         }
489
490         ret =
491             send_ocsp_request(url, cert, issuer, &resp_data, n);
492         if (ret < 0) {
493                 fprintf(stderr, "Cannot send OCSP request\n");
494                 exit(1);
495         }
496
497         _response_info(&resp_data);
498
499         if (HAVE_OPT(LOAD_TRUST)) {
500                 v = _verify_response(&resp_data, n, NULL);
501         } else if (HAVE_OPT(LOAD_SIGNER)) {
502                 v = _verify_response(&resp_data, n, load_signer());
503         } else {
504                 fprintf(stderr,
505                         "\nAssuming response's signer = issuer (use --load-signer to override).\n");
506
507                 v = _verify_response(&resp_data, n, issuer);
508         }
509
510         if (HAVE_OPT(OUTFILE) && v == 0) {
511                 fwrite(resp_data.data, 1, resp_data.size, outfile);
512         }
513 }
514
515 int main(int argc, char **argv)
516 {
517         int ret;
518
519         if ((ret = gnutls_global_init()) < 0) {
520                 fprintf(stderr, "global_init: %s\n", gnutls_strerror(ret));
521                 exit(1);
522         }
523
524         optionProcess(&ocsptoolOptions, argc, argv);
525
526         gnutls_global_set_log_function(tls_log_func);
527         gnutls_global_set_log_level(OPT_VALUE_DEBUG);
528
529         if (HAVE_OPT(OUTFILE)) {
530                 outfile = fopen(OPT_ARG(OUTFILE), "wb");
531                 if (outfile == NULL) {
532                         fprintf(stderr, "%s\n", OPT_ARG(OUTFILE));
533                         exit(1);
534                 }
535         } else
536                 outfile = stdout;
537
538         if (HAVE_OPT(INFILE)) {
539                 infile = fopen(OPT_ARG(INFILE), "rb");
540                 if (infile == NULL) {
541                         fprintf(stderr, "%s\n", OPT_ARG(INFILE));
542                         exit(1);
543                 }
544         } else
545                 infile = stdin;
546
547         if (ENABLED_OPT(INDER))
548                 encoding = GNUTLS_X509_FMT_DER;
549         else
550                 encoding = GNUTLS_X509_FMT_PEM;
551
552         if (HAVE_OPT(REQUEST_INFO))
553                 request_info();
554         else if (HAVE_OPT(RESPONSE_INFO))
555                 response_info();
556         else if (HAVE_OPT(GENERATE_REQUEST))
557                 generate_request(NULL);
558         else if (HAVE_OPT(VERIFY_RESPONSE))
559                 verify_response(NULL);
560         else if (HAVE_OPT(ASK))
561                 ask_server(OPT_ARG(ASK));
562         else {
563                 USAGE(1);
564         }
565
566         return 0;
567 }