bumped version
[gnutls.git] / src / danetool.c
blobd2361e5c50b9b55a5c49deff9c0eac4d7c5f16f1
1 /*
2 * Copyright (C) 2012 Free Software Foundation, Inc.
4 * This file is part of GnuTLS.
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.
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.
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/>.
21 #include <config.h>
23 #include <gnutls/gnutls.h>
24 #include <gnutls/x509.h>
25 #include <gnutls/openpgp.h>
26 #include <gnutls/pkcs12.h>
27 #include <gnutls/pkcs11.h>
28 #include <gnutls/abstract.h>
29 #include <gnutls/crypto.h>
31 #ifdef HAVE_DANE
32 # include <gnutls/dane.h>
33 #endif
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <ctype.h>
39 #include <time.h>
40 #include <unistd.h>
41 #include <errno.h>
42 #include <sys/types.h>
43 #include <sys/stat.h>
44 #include <fcntl.h>
45 #include <error.h>
47 /* Gnulib portability files. */
48 #include <read-file.h>
49 #include <progname.h>
50 #include <version-etc.h>
52 #include <common.h>
53 #include "danetool-args.h"
54 #include "certtool-common.h"
56 static void cmd_parser (int argc, char **argv);
57 static void dane_info(const char* host, const char* proto, unsigned int port,
58 unsigned int ca, unsigned int local, common_info_st * cinfo);
60 static void dane_check(const char* host, const char* proto, unsigned int port,
61 common_info_st * cinfo);
63 FILE *outfile;
64 static gnutls_digest_algorithm_t default_dig;
66 /* non interactive operation if set
68 int batch;
71 static void
72 tls_log_func (int level, const char *str)
74 fprintf (stderr, "|<%d>| %s", level, str);
77 int
78 main (int argc, char **argv)
80 set_program_name (argv[0]);
81 cmd_parser (argc, argv);
83 return 0;
87 static void
88 cmd_parser (int argc, char **argv)
90 int ret, privkey_op = 0;
91 common_info_st cinfo;
92 const char* proto = "tcp";
93 unsigned int port = 443;
95 optionProcess( &danetoolOptions, argc, argv);
97 if (HAVE_OPT(OUTFILE))
99 outfile = safe_open_rw (OPT_ARG(OUTFILE), privkey_op);
100 if (outfile == NULL)
101 error (EXIT_FAILURE, errno, "%s", OPT_ARG(OUTFILE));
103 else
104 outfile = stdout;
106 default_dig = GNUTLS_DIG_UNKNOWN;
107 if (HAVE_OPT(HASH))
109 if (strcasecmp (OPT_ARG(HASH), "md5") == 0)
111 fprintf (stderr,
112 "Warning: MD5 is broken, and should not be used any more for digital signatures.\n");
113 default_dig = GNUTLS_DIG_MD5;
115 else if (strcasecmp (OPT_ARG(HASH), "sha1") == 0)
116 default_dig = GNUTLS_DIG_SHA1;
117 else if (strcasecmp (OPT_ARG(HASH), "sha256") == 0)
118 default_dig = GNUTLS_DIG_SHA256;
119 else if (strcasecmp (OPT_ARG(HASH), "sha224") == 0)
120 default_dig = GNUTLS_DIG_SHA224;
121 else if (strcasecmp (OPT_ARG(HASH), "sha384") == 0)
122 default_dig = GNUTLS_DIG_SHA384;
123 else if (strcasecmp (OPT_ARG(HASH), "sha512") == 0)
124 default_dig = GNUTLS_DIG_SHA512;
125 else if (strcasecmp (OPT_ARG(HASH), "rmd160") == 0)
126 default_dig = GNUTLS_DIG_RMD160;
127 else
128 error (EXIT_FAILURE, 0, "invalid hash: %s", OPT_ARG(HASH));
131 gnutls_global_set_log_function (tls_log_func);
133 if (HAVE_OPT(DEBUG))
135 gnutls_global_set_log_level (OPT_VALUE_DEBUG);
136 printf ("Setting log level to %d\n", (int)OPT_VALUE_DEBUG);
139 if ((ret = gnutls_global_init ()) < 0)
140 error (EXIT_FAILURE, 0, "global_init: %s", gnutls_strerror (ret));
142 #ifdef ENABLE_PKCS11
143 pkcs11_common();
144 #endif
146 memset (&cinfo, 0, sizeof (cinfo));
148 if (HAVE_OPT(INDER) || HAVE_OPT(INRAW))
149 cinfo.incert_format = GNUTLS_X509_FMT_DER;
150 else
151 cinfo.incert_format = GNUTLS_X509_FMT_PEM;
153 if (HAVE_OPT(VERBOSE))
154 cinfo.verbose = 1;
156 if (HAVE_OPT(LOAD_PUBKEY))
157 cinfo.pubkey = OPT_ARG(LOAD_PUBKEY);
159 if (HAVE_OPT(LOAD_CERTIFICATE))
160 cinfo.cert = OPT_ARG(LOAD_CERTIFICATE);
162 if (HAVE_OPT(PORT))
163 port = OPT_VALUE_PORT;
164 if (HAVE_OPT(PROTO))
165 proto = OPT_ARG(PROTO);
167 if (HAVE_OPT(TLSA_RR))
168 dane_info (OPT_ARG(HOST), proto, port,
169 HAVE_OPT(CA), HAVE_OPT(LOCAL), &cinfo);
170 else if (HAVE_OPT(CHECK))
171 dane_check (OPT_ARG(CHECK), proto, port,
172 &cinfo);
173 else
174 USAGE(1);
176 fclose (outfile);
178 #ifdef ENABLE_PKCS11
179 gnutls_pkcs11_deinit ();
180 #endif
181 gnutls_global_deinit ();
184 static void dane_check(const char* host, const char* proto, unsigned int port,
185 common_info_st * cinfo)
187 #ifdef HAVE_DANE
188 dane_state_t s;
189 dane_query_t q;
190 int ret;
191 unsigned entries;
192 unsigned int flags = DANE_F_IGNORE_LOCAL_RESOLVER, i;
193 unsigned int usage, type, match;
194 gnutls_datum_t data, file;
195 size_t size;
197 if (ENABLED_OPT(LOCAL_DNS))
198 flags = 0;
200 printf("Querying %s (%s:%d)...\n", host, proto, port);
201 ret = dane_state_init(&s, flags);
202 if (ret < 0)
203 error (EXIT_FAILURE, 0, "dane_state_init: %s", dane_strerror (ret));
205 ret = dane_query_tlsa(s, &q, host, proto, port);
206 if (ret < 0)
207 error (EXIT_FAILURE, 0, "dane_query_tlsa: %s", dane_strerror (ret));
209 entries = dane_query_entries(q);
210 for (i=0;i<entries;i++)
212 ret = dane_query_data(q, i, &usage, &type, &match, &data);
213 if (ret < 0)
214 error (EXIT_FAILURE, 0, "dane_query_data: %s", dane_strerror (ret));
217 size = buffer_size;
218 ret = gnutls_hex_encode(&data, (void*)buffer, &size);
219 if (ret < 0)
220 error (EXIT_FAILURE, 0, "gnutls_hex_encode: %s", dane_strerror (ret));
222 if (entries > 1) printf("\nEntry %d:\n", i+1);
224 fprintf(outfile, "_%u._%s.%s. IN TLSA ( %.2x %.2x %.2x %s )\n", port, proto, host, usage, type, match, buffer);
225 printf("Certificate usage: %s (%.2x)\n", dane_cert_usage_name(usage), usage);
226 printf("Certificate type: %s (%.2x)\n", dane_cert_type_name(type), type);
227 printf("Contents: %s (%.2x)\n", dane_match_type_name(match), match);
228 printf("Data: %s\n", buffer);
230 /* Verify the DANE data */
231 if (cinfo->cert)
233 gnutls_x509_crt_t *clist;
234 unsigned int clist_size, status;
236 ret = gnutls_load_file(cinfo->cert, &file);
237 if (ret < 0)
238 error (EXIT_FAILURE, 0, "gnutls_load_file: %s", gnutls_strerror (ret));
240 ret = gnutls_x509_crt_list_import2( &clist, &clist_size, &file, cinfo->incert_format, 0);
241 if (ret < 0)
242 error (EXIT_FAILURE, 0, "gnutls_x509_crt_list_import2: %s", gnutls_strerror (ret));
244 if (clist_size > 0)
246 gnutls_datum_t certs[clist_size];
247 gnutls_datum_t out;
248 unsigned int i;
250 for (i=0;i<clist_size;i++)
252 ret = gnutls_x509_crt_export2( clist[i], GNUTLS_X509_FMT_DER, &certs[i]);
253 if (ret < 0)
254 error (EXIT_FAILURE, 0, "gnutls_x509_crt_export2: %s", gnutls_strerror (ret));
257 ret = dane_verify_crt( s, certs, clist_size, GNUTLS_CRT_X509,
258 host, proto, port, 0, 0, &status);
259 if (ret < 0)
260 error (EXIT_FAILURE, 0, "dane_verify_crt: %s", dane_strerror (ret));
262 ret = dane_verification_status_print(status, &out, 0);
263 if (ret < 0)
264 error (EXIT_FAILURE, 0, "dane_verification_status_print: %s", dane_strerror (ret));
266 printf("\nVerification: %s\n", out.data);
267 gnutls_free(out.data);
269 for (i=0;i<clist_size;i++)
271 gnutls_free(certs[i].data);
272 gnutls_x509_crt_deinit(clist[i]);
274 gnutls_free(clist);
280 dane_query_deinit(q);
281 dane_state_deinit(s);
282 #else
283 fprintf(stderr, "This functionality was disabled (GnuTLS was not compiled with support for DANE).\n");
284 return;
285 #endif
288 static void dane_info(const char* host, const char* proto, unsigned int port,
289 unsigned int ca, unsigned int local, common_info_st * cinfo)
291 gnutls_pubkey_t pubkey;
292 gnutls_x509_crt_t crt;
293 unsigned char digest[64];
294 gnutls_datum_t t;
295 int ret;
296 unsigned int usage, selector, type;
297 size_t size;
299 if (proto == NULL)
300 proto = "tcp";
301 if (port == 0)
302 port = 443;
304 crt = load_cert (0, cinfo);
305 if (crt != NULL && HAVE_OPT(X509))
307 selector = 0; /* X.509 */
309 size = buffer_size;
310 ret = gnutls_x509_crt_export (crt, GNUTLS_X509_FMT_DER, buffer, &size);
311 if (ret < 0)
312 error (EXIT_FAILURE, 0, "export error: %s", gnutls_strerror (ret));
314 gnutls_x509_crt_deinit (crt);
316 else /* use public key only */
318 selector = 1;
320 ret = gnutls_pubkey_init (&pubkey);
321 if (ret < 0)
322 error (EXIT_FAILURE, 0, "pubkey_init: %s", gnutls_strerror (ret));
324 if (crt != NULL)
327 ret = gnutls_pubkey_import_x509 (pubkey, crt, 0);
328 if (ret < 0)
330 error (EXIT_FAILURE, 0, "pubkey_import_x509: %s",
331 gnutls_strerror (ret));
334 size = buffer_size;
335 ret = gnutls_pubkey_export (pubkey, GNUTLS_X509_FMT_DER, buffer, &size);
336 if (ret < 0)
338 error (EXIT_FAILURE, 0, "pubkey_export: %s",
339 gnutls_strerror (ret));
342 gnutls_x509_crt_deinit(crt);
344 else
346 pubkey = load_pubkey (1, cinfo);
348 size = buffer_size;
349 ret = gnutls_pubkey_export (pubkey, GNUTLS_X509_FMT_DER, buffer, &size);
350 if (ret < 0)
351 error (EXIT_FAILURE, 0, "export error: %s", gnutls_strerror (ret));
354 gnutls_pubkey_deinit (pubkey);
357 if (default_dig != GNUTLS_DIG_SHA256 && default_dig != GNUTLS_DIG_SHA512)
359 if (default_dig != GNUTLS_DIG_UNKNOWN) fprintf(stderr, "Unsupported digest. Assuming SHA256.\n");
360 default_dig = GNUTLS_DIG_SHA256;
363 ret = gnutls_hash_fast(default_dig, buffer, size, digest);
364 if (ret < 0)
365 error (EXIT_FAILURE, 0, "hash error: %s", gnutls_strerror (ret));
367 if (default_dig == GNUTLS_DIG_SHA256)
368 type = 1;
369 else type = 2;
371 /* DANE certificate classification crap */
372 if (local==0)
374 if (ca) usage = 0;
375 else usage = 1;
377 else
379 if (ca) usage = 2;
380 else usage = 3;
383 t.data = digest;
384 t.size = gnutls_hash_get_len(default_dig);
386 size = buffer_size;
387 ret = gnutls_hex_encode(&t, (void*)buffer, &size);
388 if (ret < 0)
389 error (EXIT_FAILURE, 0, "hex encode error: %s", gnutls_strerror (ret));
391 fprintf(outfile, "_%u._%s.%s. IN TLSA ( %.2x %.2x %.2x %s )\n", port, proto, host, usage, selector, type, buffer);