diff options
author | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2014-08-08 20:32:02 +0200 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2014-08-08 20:47:29 +0200 |
commit | 9b0d293f5877596f65eebcb5076c17758acdd417 (patch) | |
tree | a1f24d33dc32405f55f28b6f0dfafdf0dacf51ac /src/danetool.c | |
parent | 6cc9644052a243ff48b207a4a793587ab36d47df (diff) | |
download | gnutls-9b0d293f5877596f65eebcb5076c17758acdd417.tar.gz |
danetool: if the certificate to verify against is not provide it try to obtain it
Diffstat (limited to 'src/danetool.c')
-rw-r--r-- | src/danetool.c | 136 |
1 files changed, 134 insertions, 2 deletions
diff --git a/src/danetool.c b/src/danetool.c index 7055b94cc1..dd3cd62dd9 100644 --- a/src/danetool.c +++ b/src/danetool.c @@ -49,7 +49,9 @@ #include <common.h> #include "danetool-args.h" #include "certtool-common.h" +#include "socket.h" +static const char* obtain_cert(const char *hostname, const char *proto, unsigned int port); static void cmd_parser(int argc, char **argv); static void dane_info(const char *host, const char *proto, unsigned int port, unsigned int ca, @@ -187,6 +189,7 @@ static void dane_check(const char *host, const char *proto, unsigned int usage, type, match; gnutls_datum_t data, file; size_t size; + unsigned del = 0; unsigned vflags = DANE_VFLAG_FAIL_IF_NOT_CHECKED; if (ENABLED_OPT(LOCAL_DNS)) @@ -264,6 +267,8 @@ static void dane_check(const char *host, const char *proto, entries = dane_query_entries(q); for (i = 0; i < entries; i++) { + del = 0; + ret = dane_query_data(q, i, &usage, &type, &match, &data); if (ret < 0) { fprintf(stderr, "dane_query_data: %s\n", @@ -292,7 +297,12 @@ static void dane_check(const char *host, const char *proto, dane_cert_type_name(type), type); printf("Contents: %s (%.2x)\n", dane_match_type_name(match), match); - printf("Data: %s\n", lbuffer); + printf("Data: %s\n\n", lbuffer); + + if (!cinfo->cert) { + cinfo->cert = obtain_cert(host, proto, port); + del = 1; + } /* Verify the DANE data */ if (cinfo->cert) { @@ -375,9 +385,13 @@ static void dane_check(const char *host, const char *proto, } gnutls_free(clist); } + + if (del != 0) { + remove(cinfo->cert); + } } else { fprintf(stderr, - "\nCertificate was not verified. Use --load-certificate.\n"); + "\nCertificate could not be obtained. You can explicitly load the certificate using --load-certificate.\n"); } } @@ -522,3 +536,121 @@ static void dane_info(const char *host, const char *proto, port, proto, host, usage, selector, type, lbuffer); } + + +struct priv_st { + int fd; + int found; +}; + +static int cert_callback(gnutls_session_t session) +{ + const gnutls_datum_t *cert_list; + unsigned int cert_list_size = 0; + int ret; + unsigned i; + gnutls_datum_t t; + struct priv_st *priv; + + cert_list = gnutls_certificate_get_peers(session, &cert_list_size); + if (cert_list_size == 0) { + fprintf(stderr, "no certificates sent by server!\n"); + return -1; + } + + priv = gnutls_session_get_ptr(session); + + for (i=0;i<cert_list_size;i++) { + ret = gnutls_pem_base64_encode_alloc("CERTIFICATE", &cert_list[i], &t); + if (ret < 0) { + fprintf(stderr, "error[%d]: %s\n", __LINE__, + gnutls_strerror(ret)); + exit(1); + } + + write(priv->fd, t.data, t.size); + gnutls_free(t.data); + } + priv->found = 1; + + return -1; +} + +static int get_cert(socket_st *hd, const char *hostname, unsigned udp, int fd) +{ + gnutls_certificate_credentials_t xcred; + gnutls_session_t session; + int ret; + struct priv_st priv; + + priv.found = 0; + priv.fd = fd; + + ret = gnutls_certificate_allocate_credentials(&xcred); + if (ret < 0) { + fprintf(stderr, "error[%d]: %s\n", __LINE__, + gnutls_strerror(ret)); + exit(1); + } + gnutls_certificate_set_verify_function(xcred, cert_callback); + + ret = gnutls_init(&session, (udp?GNUTLS_DATAGRAM:0)|GNUTLS_CLIENT); + if (ret < 0) { + fprintf(stderr, "error[%d]: %s\n", __LINE__, + gnutls_strerror(ret)); + exit(1); + } + gnutls_session_set_ptr(session, &priv); + gnutls_transport_set_int(session, hd->fd); + + gnutls_set_default_priority(session); + gnutls_server_name_set(session, GNUTLS_NAME_DNS, hostname, strlen(hostname)); + gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, xcred); + + do { + ret = gnutls_handshake(session); + } while(ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_WARNING_ALERT_RECEIVED); + /* we don't care on the result */ + + gnutls_deinit(session); + gnutls_certificate_free_credentials(xcred); + + if (priv.found == 0) + return -1; + + return 0; +} + +static const char *obtain_cert(const char *hostname, const char *proto, unsigned int port) +{ + socket_st hd; + char txt_port[16]; + unsigned udp = 0; + static char tmpfile[32] = "danetool-certXXXXXX"; + int fd, ret; + + if (strcmp(proto, "udp") == 0) + udp = 1; + + sockets_init(); + snprintf(txt_port, sizeof(txt_port), "%u", port); + socket_open(&hd, hostname, port_to_service(txt_port, proto), udp, "Obtaining certificate from"); + + fd = mkstemp(tmpfile); + if (fd == -1) { + int e = errno; + fprintf(stderr, "error[%d]: %s\n", __LINE__, + strerror(e)); + exit(1); + } + + ret = get_cert(&hd, hostname, udp, fd); + close(fd); + + socket_bye(&hd); + + if (ret == -1) + return NULL; + else + return tmpfile; +} |