1 /*
2 * Copyright (C) 2011-2014 Free Software Foundation, Inc.
3 * Copyright (C) 2016-2017 Red Hat, Inc.
4 *
5 * This file is part of GnuTLS.
6 *
7 * GnuTLS is free software: you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * GnuTLS is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see
19 * <https://www.gnu.org/licenses/>.
20 */
21
22 #include <config.h>
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <errno.h>
28
29 #include <gnutls/gnutls.h>
30 #include <gnutls/ocsp.h>
31 #include <gnutls/x509.h>
32 #include <gnutls/crypto.h>
33
34 #include <unistd.h> /* getpass */
35
36 /* Gnulib portability files. */
37 #include <read-file.h>
38 #include <socket.h>
39 #include <minmax.h>
40
41 #include <ocsptool-common.h>
42 #include <ocsptool-args.h>
43 #include "certtool-common.h"
44
45 FILE *outfile;
46 static unsigned int incert_format, outcert_format;
47 static const char *outfile_name = NULL; /* to delete on exit */
48 FILE *infile;
49 static unsigned int encoding;
50 unsigned int verbose = 0;
51 static unsigned int vflags = 0;
52
get_pass(void)53 const char *get_pass(void)
54 {
55 return getpass("Enter password: ");
56 }
57
get_confirmed_pass(bool ign)58 const char *get_confirmed_pass(bool ign)
59 {
60 return getpass("Enter password: ");
61 }
62
app_exit(int val)63 void app_exit(int val)
64 {
65 if (val != 0) {
66 if (outfile_name)
67 (void)remove(outfile_name);
68 }
69 exit(val);
70 }
71
tls_log_func(int level,const char * str)72 static void tls_log_func(int level, const char *str)
73 {
74 fprintf(stderr, "|<%d>| %s", level, str);
75 }
76
init_tls_session(const char * host)77 gnutls_session_t init_tls_session(const char *host)
78 {
79 return NULL;
80 }
81
do_handshake(socket_st * socket)82 int do_handshake(socket_st * socket)
83 {
84 return -1;
85 }
86
request_info(void)87 static void request_info(void)
88 {
89 gnutls_ocsp_req_t req;
90 int ret;
91 gnutls_datum_t dat, rbuf;
92 size_t size;
93
94 ret = gnutls_ocsp_req_init(&req);
95 if (ret < 0) {
96 fprintf(stderr, "ocsp_req_init: %s\n", gnutls_strerror(ret));
97 app_exit(1);
98 }
99
100 if (HAVE_OPT(LOAD_REQUEST))
101 dat.data =
102 (void *) read_file(OPT_ARG(LOAD_REQUEST), RF_BINARY, &size);
103 else
104 dat.data = (void *) fread_file(infile, 0, &size);
105 if (dat.data == NULL) {
106 fprintf(stderr, "error reading request\n");
107 app_exit(1);
108 }
109 dat.size = size;
110
111
112 ret = gnutls_ocsp_req_import(req, &dat);
113 free(dat.data);
114 if (ret < 0) {
115 fprintf(stderr, "error importing request: %s\n",
116 gnutls_strerror(ret));
117 app_exit(1);
118 }
119
120 ret = gnutls_ocsp_req_print(req, GNUTLS_OCSP_PRINT_FULL, &dat);
121 if (ret != 0) {
122 fprintf(stderr, "ocsp_req_print: %s\n",
123 gnutls_strerror(ret));
124 app_exit(1);
125 }
126
127 if (HAVE_OPT(OUTFILE)) {
128 ret = gnutls_ocsp_req_export(req, &rbuf);
129 if (ret < 0) {
130 fprintf(stderr, "error exporting request: %s\n",
131 gnutls_strerror(ret));
132 app_exit(1);
133 }
134
135 if (outcert_format == GNUTLS_X509_FMT_PEM) {
136 fprintf(stderr, "Cannot export requests into PEM form\n");
137 app_exit(1);
138 } else {
139 fwrite(rbuf.data, 1, rbuf.size, outfile);
140 }
141
142 gnutls_free(rbuf.data);
143 } else {
144 printf("%.*s", dat.size, dat.data);
145 }
146
147 gnutls_free(dat.data);
148
149 gnutls_ocsp_req_deinit(req);
150 }
151
_response_info(const gnutls_datum_t * data,unsigned force_print)152 static void _response_info(const gnutls_datum_t * data, unsigned force_print)
153 {
154 gnutls_ocsp_resp_t resp;
155 int ret;
156 gnutls_datum_t buf, rbuf;
157
158 if (data->size == 0) {
159 fprintf(stderr, "Received empty response\n");
160 app_exit(1);
161 }
162
163 ret = gnutls_ocsp_resp_init(&resp);
164 if (ret < 0) {
165 fprintf(stderr, "ocsp_resp_init: %s\n",
166 gnutls_strerror(ret));
167 app_exit(1);
168 }
169
170 ret = gnutls_ocsp_resp_import2(resp, data, incert_format);
171 if (ret == GNUTLS_E_BASE64_UNEXPECTED_HEADER_ERROR) {
172 int ret2 = gnutls_ocsp_resp_import(resp, data);
173 if (ret2 >= 0)
174 ret = ret2;
175 }
176 if (ret < 0) {
177 fprintf(stderr, "error importing response: %s\n",
178 gnutls_strerror(ret));
179 app_exit(1);
180 }
181
182 if (ENABLED_OPT(VERBOSE))
183 ret =
184 gnutls_ocsp_resp_print(resp, GNUTLS_OCSP_PRINT_FULL,
185 &buf);
186 else
187 ret =
188 gnutls_ocsp_resp_print(resp, GNUTLS_OCSP_PRINT_COMPACT,
189 &buf);
190 if (ret != 0) {
191 fprintf(stderr, "ocsp_resp_print: %s\n",
192 gnutls_strerror(ret));
193 app_exit(1);
194 }
195
196 if (HAVE_OPT(OUTFILE)) {
197 ret = gnutls_ocsp_resp_export2(resp, &rbuf, outcert_format);
198 if (ret < 0) {
199 fprintf(stderr, "error exporting response: %s\n",
200 gnutls_strerror(ret));
201 app_exit(1);
202 }
203
204 if (outcert_format == GNUTLS_X509_FMT_PEM)
205 fprintf(outfile, "%.*s\n", buf.size, buf.data);
206
207 fwrite(rbuf.data, 1, rbuf.size, outfile);
208
209 if (outcert_format == GNUTLS_X509_FMT_PEM)
210 fprintf(outfile, "\n");
211 gnutls_free(rbuf.data);
212 }
213
214 if (force_print || !HAVE_OPT(OUTFILE)) {
215 ret = gnutls_ocsp_resp_export2(resp, &rbuf, GNUTLS_X509_FMT_PEM);
216 if (ret < 0) {
217 fprintf(stderr, "error exporting response: %s\n",
218 gnutls_strerror(ret));
219 app_exit(1);
220 }
221
222 fprintf(stdout, "%.*s\n", buf.size, buf.data);
223 fwrite(rbuf.data, 1, rbuf.size, stdout);
224 gnutls_free(rbuf.data);
225 }
226 gnutls_free(buf.data);
227
228 gnutls_ocsp_resp_deinit(resp);
229 }
230
response_info(void)231 static void response_info(void)
232 {
233 gnutls_datum_t dat;
234 size_t size;
235
236 if (HAVE_OPT(LOAD_RESPONSE))
237 dat.data =
238 (void *) read_file(OPT_ARG(LOAD_RESPONSE), RF_BINARY, &size);
239 else
240 dat.data = (void *) fread_file(infile, 0, &size);
241 if (dat.data == NULL) {
242 fprintf(stderr, "error reading response\n");
243 app_exit(1);
244 }
245 dat.size = size;
246
247 _response_info(&dat, 0);
248
249 gnutls_free(dat.data);
250 }
251
generate_request(gnutls_datum_t * nonce)252 static void generate_request(gnutls_datum_t *nonce)
253 {
254 gnutls_datum_t dat;
255 gnutls_x509_crt_t cert, issuer;
256 common_info_st info;
257
258 memset(&info, 0, sizeof(info));
259 info.verbose = verbose;
260 if (!HAVE_OPT(LOAD_CERT)) {
261 fprintf(stderr, "Missing option --load-cert\n");
262 app_exit(1);
263 }
264 info.cert = OPT_ARG(LOAD_CERT);
265
266 cert = load_cert(1, &info);
267
268 memset(&info, 0, sizeof(info));
269 info.verbose = verbose;
270 if (!HAVE_OPT(LOAD_ISSUER)) {
271 fprintf(stderr, "Missing option --load-issuer\n");
272 app_exit(1);
273 }
274 info.cert = OPT_ARG(LOAD_ISSUER);
275
276 issuer = load_cert(1, &info);
277
278 _generate_request(cert, issuer, &dat, nonce);
279
280 gnutls_x509_crt_deinit(cert);
281 gnutls_x509_crt_deinit(issuer);
282 fwrite(dat.data, 1, dat.size, outfile);
283
284 gnutls_free(dat.data);
285 }
286
287
_verify_response(gnutls_datum_t * data,gnutls_datum_t * nonce,gnutls_x509_crt_t signer,unsigned print_resp)288 static int _verify_response(gnutls_datum_t * data, gnutls_datum_t * nonce,
289 gnutls_x509_crt_t signer, unsigned print_resp)
290 {
291 gnutls_ocsp_resp_t resp;
292 int ret;
293 size_t size;
294 gnutls_x509_crt_t *x509_ca_list = NULL;
295 gnutls_x509_trust_list_t list;
296 unsigned int x509_ncas = 0;
297 unsigned verify;
298 gnutls_datum_t dat;
299
300 ret = gnutls_ocsp_resp_init(&resp);
301 if (ret < 0) {
302 fprintf(stderr, "ocsp_resp_init: %s\n",
303 gnutls_strerror(ret));
304 app_exit(1);
305 }
306
307 ret = gnutls_ocsp_resp_import(resp, data);
308 if (ret < 0) {
309 fprintf(stderr, "importing response: %s\n",
310 gnutls_strerror(ret));
311 app_exit(1);
312 }
313
314 if (print_resp) {
315 ret =
316 gnutls_ocsp_resp_print(resp, GNUTLS_OCSP_PRINT_COMPACT,
317 &dat);
318 if (ret < 0) {
319 fprintf(stderr, "ocsp_resp_print: %s\n",
320 gnutls_strerror(ret));
321 app_exit(1);
322 }
323
324 printf("%s\n", dat.data);
325 gnutls_free(dat.data);
326 }
327
328 if (nonce) {
329 gnutls_datum_t rnonce;
330
331 ret = gnutls_ocsp_resp_get_nonce(resp, NULL, &rnonce);
332 if (ret < 0) {
333 fprintf(stderr, "could not read response's nonce: %s\n",
334 gnutls_strerror(ret));
335 app_exit(1);
336 }
337
338 if (rnonce.size != nonce->size || memcmp(nonce->data, rnonce.data,
339 nonce->size) != 0) {
340 fprintf(stderr, "nonce in the response doesn't match\n");
341 app_exit(1);
342 }
343
344 gnutls_free(rnonce.data);
345 }
346
347 if (HAVE_OPT(LOAD_TRUST)) {
348 dat.data =
349 (void *) read_file(OPT_ARG(LOAD_TRUST), RF_BINARY, &size);
350 if (dat.data == NULL) {
351 fprintf(stderr, "error reading --load-trust: %s\n",
352 OPT_ARG(LOAD_TRUST));
353 app_exit(1);
354 }
355 dat.size = size;
356
357 ret = gnutls_x509_trust_list_init(&list, 0);
358 if (ret < 0) {
359 fprintf(stderr, "gnutls_x509_trust_list_init: %s\n",
360 gnutls_strerror(ret));
361 app_exit(1);
362 }
363
364 ret =
365 gnutls_x509_crt_list_import2(&x509_ca_list, &x509_ncas,
366 &dat, GNUTLS_X509_FMT_PEM,
367 0);
368 if (ret < 0 || x509_ncas < 1) {
369 fprintf(stderr, "error parsing CAs: %s\n",
370 gnutls_strerror(ret));
371 app_exit(1);
372 }
373
374 if (HAVE_OPT(VERBOSE)) {
375 unsigned int i;
376 printf("Trust anchors:\n");
377 for (i = 0; i < x509_ncas; i++) {
378 gnutls_datum_t out;
379
380 ret =
381 gnutls_x509_crt_print(x509_ca_list[i],
382 GNUTLS_CRT_PRINT_ONELINE,
383 &out);
384 if (ret < 0) {
385 fprintf(stderr,
386 "gnutls_x509_crt_print: %s\n",
387 gnutls_strerror(ret));
388 app_exit(1);
389 }
390
391 printf("%d: %.*s\n", i, out.size,
392 out.data);
393 gnutls_free(out.data);
394 }
395 printf("\n");
396 }
397
398 ret =
399 gnutls_x509_trust_list_add_cas(list, x509_ca_list,
400 x509_ncas, 0);
401 if (ret < 0) {
402 fprintf(stderr, "gnutls_x509_trust_add_cas: %s\n",
403 gnutls_strerror(ret));
404 app_exit(1);
405 }
406
407 if (HAVE_OPT(VERBOSE))
408 fprintf(stdout, "Loaded %d trust anchors\n",
409 x509_ncas);
410
411 ret = gnutls_ocsp_resp_verify(resp, list, &verify, vflags);
412 if (ret < 0) {
413 fprintf(stderr, "gnutls_ocsp_resp_verify: %s\n",
414 gnutls_strerror(ret));
415 app_exit(1);
416 }
417 } else if (signer) {
418 if (HAVE_OPT(VERBOSE)) {
419 gnutls_datum_t out;
420
421 ret =
422 gnutls_x509_crt_print(signer,
423 GNUTLS_CRT_PRINT_ONELINE,
424 &out);
425 if (ret < 0) {
426 fprintf(stderr,
427 "gnutls_x509_crt_print: %s\n",
428 gnutls_strerror(ret));
429 app_exit(1);
430 }
431
432 printf("Signer: %.*s\n", out.size, out.data);
433 gnutls_free(out.data);
434 printf("\n");
435 }
436
437 ret =
438 gnutls_ocsp_resp_verify_direct(resp, signer, &verify,
439 vflags);
440 if (ret < 0) {
441 fprintf(stderr,
442 "\nVerifying OCSP Response: %s\n",
443 gnutls_strerror(ret));
444 app_exit(1);
445 }
446 } else {
447 fprintf(stderr, "missing --load-trust or --load-signer\n");
448 app_exit(1);
449 }
450
451 printf("\nVerifying OCSP Response: ");
452 print_ocsp_verify_res(verify);
453 printf(".\n");
454
455 gnutls_ocsp_resp_deinit(resp);
456
457 return verify;
458 }
459
460 #define MAX_CHAIN_SIZE 8
461
462 static
load_chain(gnutls_x509_crt_t chain[MAX_CHAIN_SIZE])463 unsigned load_chain(gnutls_x509_crt_t chain[MAX_CHAIN_SIZE])
464 {
465 if (HAVE_OPT(LOAD_CHAIN)) {
466 common_info_st info;
467 size_t list_size;
468
469 memset(&info, 0, sizeof(info));
470 gnutls_x509_crt_t *list;
471 unsigned i;
472
473 info.verbose = verbose;
474 info.cert = OPT_ARG(LOAD_CHAIN);
475 info.sort_chain = 1;
476 list = load_cert_list(1, &list_size, &info);
477
478 if (list_size > MAX_CHAIN_SIZE) {
479 fprintf(stderr, "Too many certificates in chain\n");
480 app_exit(1);
481 }
482
483 for (i=0;i<list_size;i++)
484 chain[i] = list[i];
485 gnutls_free(list);
486 return list_size;
487 } else {
488 common_info_st info;
489
490 memset(&info, 0, sizeof(info));
491 info.verbose = verbose;
492 if (!HAVE_OPT(LOAD_CERT)) {
493 fprintf(stderr, "Missing option --load-cert\n");
494 app_exit(1);
495 }
496 info.cert = OPT_ARG(LOAD_CERT);
497
498 chain[0] = load_cert(1, &info);
499
500 memset(&info, 0, sizeof(info));
501 info.verbose = verbose;
502 if (!HAVE_OPT(LOAD_ISSUER)) {
503 fprintf(stderr, "Missing option --load-issuer\n");
504 app_exit(1);
505 }
506 info.cert = OPT_ARG(LOAD_ISSUER);
507
508 chain[1] = load_cert(1, &info);
509 return 2;
510 }
511 }
512
verify_response(gnutls_datum_t * nonce)513 static void verify_response(gnutls_datum_t *nonce)
514 {
515 gnutls_datum_t dat;
516 size_t size;
517 gnutls_x509_crt_t signer;
518 common_info_st info;
519 int v;
520 gnutls_x509_crt_t chain[MAX_CHAIN_SIZE];
521 unsigned chain_size = 0, i;
522
523 if (HAVE_OPT(LOAD_RESPONSE))
524 dat.data =
525 (void *) read_file(OPT_ARG(LOAD_RESPONSE), RF_BINARY, &size);
526 else
527 dat.data = (void *) fread_file(infile, 0, &size);
528 if (dat.data == NULL) {
529 fprintf(stderr, "error reading response\n");
530 app_exit(1);
531 }
532 dat.size = size;
533
534 if (HAVE_OPT(LOAD_CHAIN)) {
535 chain_size = load_chain(chain);
536 if (chain_size < 1) {
537 fprintf(stderr, "Empty chain found; cannot verify\n");
538 app_exit(1);
539 }
540
541 if (chain_size == 1)
542 signer = chain[0];
543 else
544 signer = chain[1];
545
546 v = _verify_response(&dat, nonce, signer, 1);
547
548 for (i=0;i<chain_size;i++)
549 gnutls_x509_crt_deinit(chain[i]);
550 } else if (HAVE_OPT(LOAD_TRUST)) {
551 v = _verify_response(&dat, nonce, NULL, 1);
552 } else {
553 memset(&info, 0, sizeof(info));
554 info.verbose = verbose;
555 if (!HAVE_OPT(LOAD_SIGNER)) {
556 fprintf(stderr, "Missing option --load-signer or --load-chain\n");
557 app_exit(1);
558 }
559 info.cert = OPT_ARG(LOAD_SIGNER);
560
561 signer = load_cert(1, &info);
562
563 v = _verify_response(&dat, nonce, signer, 1);
564 gnutls_x509_crt_deinit(signer);
565 }
566
567 free(dat.data);
568
569 if (v && !HAVE_OPT(IGNORE_ERRORS))
570 app_exit(1);
571 }
572
ask_server(const char * url)573 static void ask_server(const char *url)
574 {
575 gnutls_datum_t resp_data;
576 int ret, v = 0, total_v = 0;
577 unsigned char noncebuf[23];
578 gnutls_datum_t nonce = { noncebuf, sizeof(noncebuf) };
579 gnutls_datum_t *n;
580 gnutls_x509_crt_t chain[MAX_CHAIN_SIZE];
581 unsigned chain_size, counter;
582 unsigned idx = 0;
583 common_info_st info;
584
585 chain_size = load_chain(chain);
586
587 if (chain_size > 2 && HAVE_OPT(OUTFILE)) {
588 if (outcert_format != GNUTLS_X509_FMT_PEM) {
589 fprintf(stderr, "error: You cannot combine --outfile when more than 2 certificates are found in a chain\n");
590 fprintf(stderr, "Did you mean to use --outpem?\n");
591 app_exit(1);
592 }
593 }
594
595 counter = chain_size;
596 while(counter > 1) {
597 if (ENABLED_OPT(NONCE)) {
598 ret =
599 gnutls_rnd(GNUTLS_RND_NONCE, nonce.data, nonce.size);
600 if (ret < 0) {
601 fprintf(stderr, "gnutls_rnd: %s\n",
602 gnutls_strerror(ret));
603 app_exit(1);
604 }
605 n = &nonce;
606 } else {
607 n = NULL;
608 }
609
610 ret =
611 send_ocsp_request(url, chain[idx], chain[idx+1], &resp_data, n);
612 if (ret < 0) {
613 fprintf(stderr, "Cannot send OCSP request\n");
614 app_exit(1);
615 }
616
617 _response_info(&resp_data, 1);
618
619 if (HAVE_OPT(LOAD_TRUST)) {
620 v = _verify_response(&resp_data, n, NULL, 0);
621 } else if (HAVE_OPT(LOAD_SIGNER)) {
622 memset(&info, 0, sizeof(info));
623 info.verbose = verbose;
624 info.cert = OPT_ARG(LOAD_SIGNER);
625
626 v = _verify_response(&resp_data, n, load_cert(1, &info), 0);
627 } else {
628 if (!HAVE_OPT(LOAD_CHAIN))
629 fprintf(stderr,
630 "\nAssuming response's signer = issuer (use --load-signer to override).\n");
631
632 v = _verify_response(&resp_data, n, chain[idx+1], 0);
633 }
634
635 total_v += v;
636
637 free(resp_data.data);
638 idx++;
639 counter--;
640 printf("\n");
641 }
642
643 for (idx = 0;idx<chain_size;idx++) {
644 gnutls_x509_crt_deinit(chain[idx]);
645 }
646
647 if (total_v && !HAVE_OPT(IGNORE_ERRORS))
648 app_exit(1);
649 }
650
main(int argc,char ** argv)651 int main(int argc, char **argv)
652 {
653 int ret;
654
655 if ((ret = gnutls_global_init()) < 0) {
656 fprintf(stderr, "global_init: %s\n", gnutls_strerror(ret));
657 app_exit(1);
658 }
659
660 optionProcess(&ocsptoolOptions, argc, argv);
661
662 gnutls_global_set_log_function(tls_log_func);
663 gnutls_global_set_log_level(OPT_VALUE_DEBUG);
664
665 if (ENABLED_OPT(INDER))
666 incert_format = GNUTLS_X509_FMT_DER;
667 else
668 incert_format = GNUTLS_X509_FMT_PEM;
669
670 if (HAVE_OPT(OUTPEM))
671 outcert_format = GNUTLS_X509_FMT_PEM;
672 else
673 outcert_format = GNUTLS_X509_FMT_DER;
674
675 if (HAVE_OPT(VERIFY_ALLOW_BROKEN))
676 vflags |= GNUTLS_VERIFY_ALLOW_BROKEN;
677
678 if (HAVE_OPT(OUTFILE)) {
679 outfile = fopen(OPT_ARG(OUTFILE), "wb");
680 if (outfile == NULL) {
681 fprintf(stderr, "%s\n", OPT_ARG(OUTFILE));
682 app_exit(1);
683 }
684 outfile_name = OPT_ARG(OUTFILE);
685 } else
686 outfile = stdout;
687
688 if (HAVE_OPT(INFILE)) {
689 infile = fopen(OPT_ARG(INFILE), "rb");
690 if (infile == NULL) {
691 fprintf(stderr, "%s\n", OPT_ARG(INFILE));
692 app_exit(1);
693 }
694 } else
695 infile = stdin;
696
697 if (ENABLED_OPT(INDER))
698 encoding = GNUTLS_X509_FMT_DER;
699 else
700 encoding = GNUTLS_X509_FMT_PEM;
701
702 if (HAVE_OPT(REQUEST_INFO))
703 request_info();
704 else if (HAVE_OPT(RESPONSE_INFO))
705 response_info();
706 else if (HAVE_OPT(GENERATE_REQUEST))
707 generate_request(NULL);
708 else if (HAVE_OPT(VERIFY_RESPONSE))
709 verify_response(NULL);
710 else if (HAVE_OPT(ASK)) {
711 if ((!HAVE_OPT(LOAD_CERT)) && (!HAVE_OPT(LOAD_CHAIN))) {
712 fprintf(stderr, "This option required --load-chain or --load-cert\n");
713 app_exit(1);
714 }
715 ask_server(OPT_ARG(ASK));
716 } else {
717 USAGE(1);
718 }
719
720 if (infile != stdin)
721 fclose(infile);
722 gnutls_global_deinit();
723
724 return 0;
725 }
726