1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
20 | |
21 | #include <config.h> |
22 | |
23 | #include <stdio.h> |
24 | #include <stdlib.h> |
25 | #include <string.h> |
26 | #include <errno(*__errno_location ()).h> |
27 | |
28 | #include <gnutls/gnutls.h> |
29 | #include <gnutls/ocsp.h> |
30 | #include <gnutls/x509.h> |
31 | #include <gnutls/crypto.h> |
32 | |
33 | |
34 | #include <error.h> |
35 | #include <progname.h> |
36 | #include <version-etc.h> |
37 | #include <read-file.h> |
38 | |
39 | #include <ocsptool-common.h> |
40 | #include <ocsptool-gaa.h> |
41 | |
42 | gaainfo info; |
43 | FILE *outfile; |
44 | FILE *infile; |
45 | |
46 | static void |
47 | tls_log_func (int level, const char *str) |
48 | { |
49 | fprintf (stderrstderr, "|<%d>| %s", level, str); |
50 | } |
51 | |
52 | static void |
53 | request_info (void) |
54 | { |
55 | gnutls_ocsp_req_t req; |
56 | int ret; |
57 | gnutls_datum_t dat; |
58 | size_t size; |
59 | |
60 | ret = gnutls_ocsp_req_init (&req); |
61 | if (ret < 0) |
62 | error (EXIT_FAILURE1, 0, "ocsp_req_init: %s", gnutls_strerror (ret)); |
63 | |
64 | if (info.req) |
65 | dat.data = read_binary_file_gnutls_read_binary_file (info.req, &size); |
66 | else |
67 | dat.data = fread_file_gnutls_fread_file (infile, &size); |
68 | if (dat.data == NULL((void*)0)) |
69 | error (EXIT_FAILURE1, errno(*__errno_location ()), "reading request"); |
70 | dat.size = size; |
71 | |
72 | ret = gnutls_ocsp_req_import (req, &dat); |
73 | free (dat.data); |
74 | if (ret < 0) |
75 | error (EXIT_FAILURE1, 0, "importing request: %s", gnutls_strerror (ret)); |
76 | |
77 | ret = gnutls_ocsp_req_print (req, GNUTLS_OCSP_PRINT_FULL, &dat); |
78 | if (ret != 0) |
79 | error (EXIT_FAILURE1, 0, "ocsp_req_print: %s", gnutls_strerror (ret)); |
80 | |
81 | printf ("%.*s", dat.size, dat.data); |
82 | gnutls_free (dat.data); |
83 | |
84 | gnutls_ocsp_req_deinit (req); |
85 | } |
86 | |
87 | static void |
88 | response_info (void) |
89 | { |
90 | gnutls_ocsp_resp_t resp; |
91 | int ret; |
92 | gnutls_datum_t dat; |
93 | size_t size; |
94 | |
95 | ret = gnutls_ocsp_resp_init (&resp); |
96 | if (ret < 0) |
97 | error (EXIT_FAILURE1, 0, "ocsp_resp_init: %s", gnutls_strerror (ret)); |
98 | |
99 | if (info.resp) |
100 | dat.data = read_binary_file_gnutls_read_binary_file (info.resp, &size); |
101 | else |
102 | dat.data = fread_file_gnutls_fread_file (infile, &size); |
103 | if (dat.data == NULL((void*)0)) |
104 | error (EXIT_FAILURE1, errno(*__errno_location ()), "reading response"); |
105 | dat.size = size; |
106 | |
107 | ret = gnutls_ocsp_resp_import (resp, &dat); |
108 | free (dat.data); |
109 | if (ret < 0) |
110 | error (EXIT_FAILURE1, 0, "importing response: %s", gnutls_strerror (ret)); |
111 | |
112 | ret = gnutls_ocsp_resp_print (resp, GNUTLS_OCSP_PRINT_FULL, &dat); |
113 | if (ret != 0) |
114 | error (EXIT_FAILURE1, 0, "ocsp_resp_print: %s", gnutls_strerror (ret)); |
115 | |
116 | printf ("%.*s", dat.size, dat.data); |
117 | gnutls_free (dat.data); |
118 | |
119 | gnutls_ocsp_resp_deinit (resp); |
120 | } |
121 | |
122 | static gnutls_x509_crt_t |
123 | load_issuer (void) |
124 | { |
125 | gnutls_x509_crt_t crt; |
126 | int ret; |
127 | gnutls_datum_t dat; |
128 | size_t size; |
129 | |
130 | if (info.issuer == NULL((void*)0)) |
131 | error (EXIT_FAILURE1, 0, "missing --load-issuer"); |
132 | |
133 | ret = gnutls_x509_crt_init (&crt); |
134 | if (ret < 0) |
135 | error (EXIT_FAILURE1, 0, "crt_init: %s", gnutls_strerror (ret)); |
136 | |
137 | dat.data = read_binary_file_gnutls_read_binary_file (info.issuer, &size); |
138 | dat.size = size; |
139 | |
140 | if (!dat.data) |
141 | error (EXIT_FAILURE1, errno(*__errno_location ()), "reading --load-issuer: %s", info.issuer); |
142 | |
143 | ret = gnutls_x509_crt_import (crt, &dat, info.inder); |
144 | free (dat.data); |
145 | if (ret < 0) |
146 | error (EXIT_FAILURE1, 0, "importing --load-issuer: %s: %s", |
147 | info.issuer, gnutls_strerror (ret)); |
148 | |
149 | return crt; |
150 | } |
151 | |
152 | static gnutls_x509_crt_t |
153 | load_cert (void) |
154 | { |
155 | gnutls_x509_crt_t crt; |
156 | int ret; |
157 | gnutls_datum_t dat; |
158 | size_t size; |
159 | |
160 | if (info.cert == NULL((void*)0)) |
161 | error (EXIT_FAILURE1, 0, "missing --load-cert"); |
162 | |
163 | ret = gnutls_x509_crt_init (&crt); |
164 | if (ret < 0) |
165 | error (EXIT_FAILURE1, 0, "crt_init: %s", gnutls_strerror (ret)); |
166 | |
167 | dat.data = read_binary_file_gnutls_read_binary_file (info.cert, &size); |
168 | dat.size = size; |
169 | |
170 | if (!dat.data) |
171 | error (EXIT_FAILURE1, errno(*__errno_location ()), "reading --load-cert: %s", info.cert); |
172 | |
173 | ret = gnutls_x509_crt_import (crt, &dat, info.inder); |
174 | free (dat.data); |
175 | if (ret < 0) |
176 | error (EXIT_FAILURE1, 0, "importing --load-cert: %s: %s", |
177 | info.cert, gnutls_strerror (ret)); |
178 | |
179 | return crt; |
180 | } |
181 | |
182 | static void |
183 | generate_request (void) |
184 | { |
185 | gnutls_ocsp_req_t req; |
186 | int ret; |
187 | gnutls_datum_t dat; |
188 | gnutls_x509_crt_t issuer, cert; |
189 | |
190 | ret = gnutls_ocsp_req_init (&req); |
191 | if (ret < 0) |
192 | error (EXIT_FAILURE1, 0, "ocsp_req_init: %s", gnutls_strerror (ret)); |
193 | |
194 | issuer = load_issuer (); |
195 | cert = load_cert (); |
196 | |
197 | ret = gnutls_ocsp_req_add_cert (req, GNUTLS_DIG_SHA1, |
198 | issuer, cert); |
199 | if (ret < 0) |
200 | error (EXIT_FAILURE1, 0, "ocsp_req_add_cert: %s", gnutls_strerror (ret)); |
201 | |
202 | gnutls_x509_crt_deinit (cert); |
203 | gnutls_x509_crt_deinit (issuer); |
204 | |
205 | if (!info.nononce) |
206 | { |
207 | char noncebuf[23]; |
208 | gnutls_datum_t nonce = { noncebuf, sizeof (noncebuf) }; |
209 | |
210 | ret = gnutls_rnd (GNUTLS_RND_RANDOM, nonce.data, nonce.size); |
211 | if (ret < 0) |
212 | error (EXIT_FAILURE1, 0, "gnutls_rnd: %s", gnutls_strerror (ret)); |
213 | |
214 | ret = gnutls_ocsp_req_set_nonce (req, 0, &nonce); |
215 | if (ret < 0) |
216 | error (EXIT_FAILURE1, 0, "ocsp_req_set_nonce: %s", |
217 | gnutls_strerror (ret)); |
218 | } |
219 | |
220 | ret = gnutls_ocsp_req_export (req, &dat); |
221 | if (ret != 0) |
222 | error (EXIT_FAILURE1, 0, "ocsp_req_export: %s", gnutls_strerror (ret)); |
223 | |
224 | fwrite (dat.data, 1, dat.size, outfile); |
225 | |
226 | gnutls_free (dat.data); |
227 | |
228 | gnutls_ocsp_req_deinit (req); |
229 | } |
230 | |
231 | static void |
232 | print_verify_res (unsigned int output) |
233 | { |
234 | int comma = 0; |
235 | |
236 | if (output) |
237 | { |
238 | printf ("Failure"); |
239 | comma = 1; |
240 | } |
241 | else |
242 | { |
243 | printf ("Success"); |
244 | comma = 1; |
245 | } |
246 | |
247 | if (output & GNUTLS_OCSP_VERIFY_SIGNER_NOT_FOUND) |
248 | { |
249 | if (comma) |
250 | printf (", "); |
251 | printf ("Signer cert not found"); |
252 | comma = 1; |
253 | } |
254 | |
255 | if (output & GNUTLS_OCSP_VERIFY_SIGNER_KEYUSAGE_ERROR) |
256 | { |
257 | if (comma) |
258 | printf (", "); |
259 | printf ("Signer cert keyusage error"); |
260 | comma = 1; |
261 | } |
262 | |
263 | if (output & GNUTLS_OCSP_VERIFY_UNTRUSTED_SIGNER) |
264 | { |
265 | if (comma) |
266 | printf (", "); |
267 | printf ("Signer cert is not trusted"); |
268 | comma = 1; |
269 | } |
270 | |
271 | if (output & GNUTLS_OCSP_VERIFY_INSECURE_ALGORITHM) |
272 | { |
273 | if (comma) |
274 | printf (", "); |
275 | printf ("Insecure algorithm"); |
276 | comma = 1; |
277 | } |
278 | |
279 | if (output & GNUTLS_OCSP_VERIFY_SIGNATURE_FAILURE) |
280 | { |
281 | if (comma) |
282 | printf (", "); |
283 | printf ("Signature failure"); |
284 | comma = 1; |
285 | } |
286 | |
287 | if (output & GNUTLS_OCSP_VERIFY_CERT_NOT_ACTIVATED) |
288 | { |
289 | if (comma) |
290 | printf (", "); |
291 | printf ("Signer cert not yet activated"); |
292 | comma = 1; |
293 | } |
294 | |
295 | if (output & GNUTLS_OCSP_VERIFY_CERT_EXPIRED) |
296 | { |
297 | if (comma) |
298 | printf (", "); |
299 | printf ("Signer cert expired"); |
300 | comma = 1; |
| Value stored to 'comma' is never read |
301 | } |
302 | } |
303 | |
304 | static void |
305 | verify_response (void) |
306 | { |
307 | gnutls_ocsp_resp_t resp; |
308 | int ret; |
309 | gnutls_datum_t dat; |
310 | size_t size; |
311 | gnutls_x509_crt_t *x509_ca_list = NULL((void*)0); |
312 | unsigned int x509_ncas = 0; |
313 | gnutls_x509_trust_list_t list; |
314 | gnutls_x509_crt_t signer; |
315 | unsigned verify; |
316 | |
317 | ret = gnutls_ocsp_resp_init (&resp); |
318 | if (ret < 0) |
319 | error (EXIT_FAILURE1, 0, "ocsp_resp_init: %s", gnutls_strerror (ret)); |
320 | |
321 | if (info.resp) |
322 | dat.data = read_binary_file_gnutls_read_binary_file (info.resp, &size); |
323 | else |
324 | dat.data = fread_file_gnutls_fread_file (infile, &size); |
325 | if (dat.data == NULL((void*)0)) |
326 | error (EXIT_FAILURE1, errno(*__errno_location ()), "reading response"); |
327 | dat.size = size; |
328 | |
329 | ret = gnutls_ocsp_resp_import (resp, &dat); |
330 | free (dat.data); |
331 | if (ret < 0) |
332 | error (EXIT_FAILURE1, 0, "importing response: %s", gnutls_strerror (ret)); |
333 | |
334 | if (info.trust && info.signer) |
335 | error (EXIT_FAILURE1, 0, "cannot mix --load-trust and --load-signer"); |
336 | else if (info.signer == NULL((void*)0)) |
337 | { |
338 | dat.data = read_binary_file_gnutls_read_binary_file (info.trust, &size); |
339 | if (dat.data == NULL((void*)0)) |
340 | error (EXIT_FAILURE1, errno(*__errno_location ()), "reading --load-trust: %s", info.trust); |
341 | dat.size = size; |
342 | |
343 | ret = gnutls_x509_trust_list_init (&list, 0); |
344 | if (ret < 0) |
345 | error (EXIT_FAILURE1, 0, "gnutls_x509_trust_list_init: %s", |
346 | gnutls_strerror (ret)); |
347 | |
348 | ret = gnutls_x509_crt_list_import2 (&x509_ca_list, &x509_ncas, &dat, |
349 | GNUTLS_X509_FMT_PEM, 0); |
350 | if (ret < 0 || x509_ncas < 1) |
351 | error (EXIT_FAILURE1, 0, "error parsing CAs: %s", |
352 | gnutls_strerror (ret)); |
353 | |
354 | if (info.verbose) |
355 | { |
356 | unsigned int i; |
357 | for (i = 0; i < x509_ncas; i++) |
358 | { |
359 | gnutls_datum_t out; |
360 | |
361 | ret = gnutls_x509_crt_print (x509_ca_list[i], |
362 | GNUTLS_CRT_PRINT_ONELINE, &out); |
363 | if (ret < 0) |
364 | error (EXIT_FAILURE1, 0, "gnutls_x509_crt_print: %s", |
365 | gnutls_strerror (ret)); |
366 | |
367 | printf ("Trust anchor %d: %.*s\n", i, out.size, out.data); |
368 | gnutls_free (out.data); |
369 | } |
370 | } |
371 | |
372 | ret = gnutls_x509_trust_list_add_cas (list, x509_ca_list, x509_ncas, 0); |
373 | if (ret < 0) |
374 | error (EXIT_FAILURE1, 0, "gnutls_x509_trust_add_cas: %s", |
375 | gnutls_strerror (ret)); |
376 | |
377 | if (info.verbose) |
378 | fprintf (stdoutstdout, "Loaded %d trust anchors\n", x509_ncas); |
379 | |
380 | ret = gnutls_ocsp_resp_verify (resp, list, &verify, 0); |
381 | if (ret < 0) |
382 | error (EXIT_FAILURE1, 0, "gnutls_ocsp_resp_verify: %s", |
383 | gnutls_strerror (ret)); |
384 | } |
385 | else if (info.trust == NULL((void*)0)) |
386 | { |
387 | ret = gnutls_x509_crt_init (&signer); |
388 | if (ret < 0) |
389 | error (EXIT_FAILURE1, 0, "crt_init: %s", gnutls_strerror (ret)); |
390 | |
391 | dat.data = read_binary_file_gnutls_read_binary_file (info.signer, &size); |
392 | if (dat.data == NULL((void*)0)) |
393 | error (EXIT_FAILURE1, errno(*__errno_location ()), "reading --load-signer: %s", info.signer); |
394 | dat.size = size; |
395 | |
396 | ret = gnutls_x509_crt_import (signer, &dat, info.inder); |
397 | free (dat.data); |
398 | if (ret < 0) |
399 | error (EXIT_FAILURE1, 0, "importing --load-signer: %s: %s", |
400 | info.signer, gnutls_strerror (ret)); |
401 | |
402 | if (info.verbose) |
403 | { |
404 | gnutls_datum_t out; |
405 | |
406 | ret = gnutls_x509_crt_print (signer, GNUTLS_CRT_PRINT_ONELINE, &out); |
407 | if (ret < 0) |
408 | error (EXIT_FAILURE1, 0, "gnutls_x509_crt_print: %s", |
409 | gnutls_strerror (ret)); |
410 | |
411 | printf ("Signer: %.*s\n", out.size, out.data); |
412 | gnutls_free (out.data); |
413 | } |
414 | |
415 | ret = gnutls_ocsp_resp_verify_direct (resp, signer, &verify, 0); |
416 | if (ret < 0) |
417 | error (EXIT_FAILURE1, 0, "gnutls_ocsp_resp_verify_direct: %s", |
418 | gnutls_strerror (ret)); |
419 | } |
420 | else |
421 | error (EXIT_FAILURE1, 0, "missing --load-trust or --load-signer"); |
422 | |
423 | printf ("Verifying OCSP Response: "); |
424 | print_verify_res (verify); |
425 | printf (".\n"); |
426 | |
427 | gnutls_ocsp_resp_deinit (resp); |
428 | } |
429 | |
430 | int |
431 | main (int argc, char **argv) |
432 | { |
433 | int ret; |
434 | |
435 | set_program_name (argv[0]); |
436 | |
437 | if ((ret = gnutls_global_init ()) < 0) |
438 | error (EXIT_FAILURE1, 0, "global_init: %s", gnutls_strerror (ret)); |
439 | |
440 | if (gaa (argc, argv, &info) != -1) |
441 | { |
442 | fprintf (stderrstderr, "Try `%s --help' for more information.\n", |
443 | program_name); |
444 | exit (EXIT_FAILURE1); |
445 | } |
446 | |
447 | gnutls_global_set_log_function (tls_log_func); |
448 | gnutls_global_set_log_level (info.debug); |
449 | |
450 | if (info.outfile) |
451 | { |
452 | outfile = fopen (info.outfile, "wb"); |
453 | if (outfile == NULL((void*)0)) |
454 | error (EXIT_FAILURE1, errno(*__errno_location ()), "%s", info.outfile); |
455 | } |
456 | else |
457 | outfile = stdoutstdout; |
458 | |
459 | if (info.infile) |
460 | { |
461 | infile = fopen (info.infile, "rb"); |
462 | if (infile == NULL((void*)0)) |
463 | error (EXIT_FAILURE1, errno(*__errno_location ()), "%s", info.infile); |
464 | } |
465 | else |
466 | infile = stdinstdin; |
467 | |
468 | if (info.inder) |
469 | info.inder = GNUTLS_X509_FMT_DER; |
470 | else |
471 | info.inder = GNUTLS_X509_FMT_PEM; |
472 | |
473 | switch (info.action) |
474 | { |
475 | case ACTION_REQ_INFO: |
476 | request_info (); |
477 | break; |
478 | |
479 | case ACTION_RESP_INFO: |
480 | response_info (); |
481 | break; |
482 | |
483 | case ACTION_GEN_REQ: |
484 | generate_request (); |
485 | break; |
486 | |
487 | case ACTION_VERIFY_RESP: |
488 | verify_response (); |
489 | break; |
490 | |
491 | default: |
492 | gaa_help(); |
493 | } |
494 | |
495 | return 0; |
496 | } |
497 | |
498 | void |
499 | ocsptool_version (void) |
500 | { |
501 | const char *p = PACKAGE_NAME"GnuTLS"; |
502 | if (strcmp (gnutls_check_version (NULL((void*)0)), PACKAGE_VERSION"3.0.12") != 0) |
503 | p = PACKAGE_STRING"GnuTLS 3.0.12"; |
504 | version_etc (stdoutstdout, "ocsptool", p, gnutls_check_version (NULL((void*)0)), |
505 | "Simon Josefsson", (char *) NULL((void*)0)); |
506 | } |