]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
danetool: if the certificate to verify against is not provide it try to obtain it
authorNikos Mavrogiannopoulos <nmav@gnutls.org>
Fri, 8 Aug 2014 18:32:02 +0000 (20:32 +0200)
committerNikos Mavrogiannopoulos <nmav@gnutls.org>
Fri, 8 Aug 2014 18:47:29 +0000 (20:47 +0200)
src/Makefile.am
src/cli.c
src/danetool.c
src/ocsptool-common.c
src/socket.c
src/socket.h
tests/suite/testdane

index 55bcd5f4f1e5fdf0bdfacdbe8bc81a6933e5929d..78d8cb293b86ed6c544e2ffc6c587dff3ee223d9 100644 (file)
@@ -155,7 +155,7 @@ libcmd_certtool_la_LIBADD += $(LIBOPTS) $(LTLIBINTL)
 libcmd_certtool_la_LIBADD += $(LTLIBREADLINE) gl/libgnu_gpl.la
 libcmd_certtool_la_LIBADD += $(INET_PTON_LIB) $(LIB_CLOCK_GETTIME)
 
-danetool_SOURCES = danetool.c certtool-common.c certtool-extras.c common.c
+danetool_SOURCES = danetool.c certtool-common.c certtool-extras.c common.c socket.c
 danetool_LDADD = ../lib/libgnutls.la 
 danetool_LDADD += libcmd-danetool.la ../gl/libgnu.la gl/libgnu_gpl.la
 if ENABLE_DANE
index 8a76f2c55f2c729c382c55867b5423f89d77230e..3399531c3b452713845193f66d1ab54ecf3683bf 100644 (file)
--- a/src/cli.c
+++ b/src/cli.c
@@ -374,49 +374,6 @@ static int read_yesno(const char *input_str)
        return 0;
 }
 
-/* converts a textual service or port to
- * a service.
- */
-static const char *port_to_service(const char *sport)
-{
-       unsigned int port;
-       struct servent *sr;
-
-       port = atoi(sport);
-       if (port == 0)
-               return sport;
-
-       port = htons(port);
-
-       sr = getservbyport(port, udp ? "udp" : "tcp");
-       if (sr == NULL) {
-               fprintf(stderr,
-                       "Warning: getservbyport() failed. Using port number as service.\n");
-               return sport;
-       }
-
-       return sr->s_name;
-}
-
-static int service_to_port(const char *service)
-{
-       unsigned int port;
-       struct servent *sr;
-
-       port = atoi(service);
-       if (port != 0)
-               return port;
-
-       sr = getservbyname(service, udp ? "udp" : "tcp");
-       if (sr == NULL) {
-               fprintf(stderr, "Warning: getservbyname() failed.\n");
-               exit(1);
-       }
-
-       return ntohs(sr->s_port);
-}
-
-
 static int cert_verify_callback(gnutls_session_t session)
 {
        int rc;
@@ -471,7 +428,7 @@ static int cert_verify_callback(gnutls_session_t session)
                if (ca_verify == 0)
                        vflags |= DANE_VFLAG_ONLY_CHECK_EE_USAGE;
 
-               port = service_to_port(service);
+               port = service_to_port(service, udp?"udp":"tcp");
                rc = dane_verify_session_crt(NULL, session, hostname,
                                             udp ? "udp" : "tcp", port,
                                             sflags, vflags, &status);
@@ -512,7 +469,7 @@ static int cert_verify_callback(gnutls_session_t session)
                        return -1;
                }
 
-               txt_service = port_to_service(service);
+               txt_service = port_to_service(service, udp?"udp":"tcp");
 
                rc = gnutls_verify_stored_pubkey(NULL, NULL, hostname,
                                                 txt_service,
@@ -893,7 +850,7 @@ static int try_resume(socket_st * hd)
 
        printf
            ("\n\n- Connecting again- trying to resume previous session\n");
-       socket_open(hd, hostname, service, udp);
+       socket_open(hd, hostname, service, udp, CONNECT_MSG);
 
        hd->session = init_tls_session(hostname);
        gnutls_session_set_data(hd->session, session_data,
@@ -1116,7 +1073,8 @@ int main(int argc, char **argv)
 
        init_global_tls_stuff();
 
-       socket_open(&hd, hostname, service, udp);
+       socket_open(&hd, hostname, service, udp, CONNECT_MSG);
+       hd.verbose = verbose;
 
        hd.session = init_tls_session(hostname);
        if (starttls)
index 7055b94cc1f8abe21971ae99c37f9b74e8a1cedc..dd3cd62dd90b92514087f1db39a67c810e50a185 100644 (file)
@@ -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;
+}
index 2e7a359aeb43480cf7e2db119ac9ab74e3621bcb..5ea2030cbfd709ba251120a0b7c003a60ba3ed48 100644 (file)
@@ -195,7 +195,7 @@ int send_ocsp_request(const char *server,
                 (unsigned int) req.size);
        headers_size = strlen(headers);
 
-       socket_open(&hd, hostname, service, 0);
+       socket_open(&hd, hostname, service, 0, CONNECT_MSG);
 
        socket_send(&hd, headers, headers_size);
        socket_send(&hd, req.data, req.size);
index a91fea7f8152e7c0933f2ada9e206407ae63473e..1b2d851becd9e99c6c4aaa17ffaaa67bef8e9744 100644 (file)
@@ -40,7 +40,6 @@
 
 #define MAX_BUF 4096
 
-extern unsigned int verbose;
 /* Functions to manipulate sockets
  */
 
@@ -105,7 +104,7 @@ socket_send_range(const socket_st * socket, const void *buffer,
                }
                while (ret == -1 && errno == EINTR);
 
-       if (ret > 0 && ret != buffer_size && verbose)
+       if (ret > 0 && ret != buffer_size && socket->verbose)
                fprintf(stderr,
                        "*** Only sent %d bytes instead of %d.\n", ret,
                        buffer_size);
@@ -144,7 +143,7 @@ void socket_bye(socket_st * socket)
 
 void
 socket_open(socket_st * hd, const char *hostname, const char *service,
-           int udp)
+           int udp, const char *msg)
 {
        struct addrinfo hints, *res, *ptr;
        int sd, err;
@@ -194,7 +193,8 @@ socket_open(socket_st * hd, const char *hostname, const char *service,
                }
 
 
-               printf("Connecting to '%s:%s'...\n", buffer, portname);
+               if (msg)
+                       printf("%s '%s:%s'...\n", msg, buffer, portname);
 
                err = connect(sd, ptr->ai_addr, ptr->ai_addrlen);
                if (err < 0) {
@@ -240,3 +240,45 @@ void sockets_init(void)
 #endif
 
 }
+
+/* converts a textual service or port to
+ * a service.
+ */
+const char *port_to_service(const char *sport, const char *proto)
+{
+       unsigned int port;
+       struct servent *sr;
+
+       port = atoi(sport);
+       if (port == 0)
+               return sport;
+
+       port = htons(port);
+
+       sr = getservbyport(port, proto);
+       if (sr == NULL) {
+               fprintf(stderr,
+                       "Warning: getservbyport() failed. Using port number as service.\n");
+               return sport;
+       }
+
+       return sr->s_name;
+}
+
+int service_to_port(const char *service, const char *proto)
+{
+       unsigned int port;
+       struct servent *sr;
+
+       port = atoi(service);
+       if (port != 0)
+               return port;
+
+       sr = getservbyname(service, proto);
+       if (sr == NULL) {
+               fprintf(stderr, "Warning: getservbyname() failed.\n");
+               exit(1);
+       }
+
+       return ntohs(sr->s_port);
+}
index 00ec6163789c4f6f48d434fc4406840525bfb21c..d06788ce1749dc32757e2556808f57d5fe15725b 100644 (file)
@@ -9,6 +9,7 @@ typedef struct {
        char *service;
        struct addrinfo *ptr;
        struct addrinfo *addr_info;
+       int verbose;
 } socket_st;
 
 ssize_t socket_recv(const socket_st * socket, void *buffer,
@@ -18,7 +19,12 @@ ssize_t socket_send(const socket_st * socket, const void *buffer,
 ssize_t socket_send_range(const socket_st * socket, const void *buffer,
                          int buffer_size, gnutls_range_st * range);
 void socket_open(socket_st * hd, const char *hostname, const char *service,
-                int udp);
+                int udp, const char *msg);
 void socket_bye(socket_st * socket);
 
 void sockets_init(void);
+
+int service_to_port(const char *service, const char *proto);
+const char *port_to_service(const char *sport, const char *proto);
+
+#define CONNECT_MSG "Connecting to"
index eeb283cc304c81bbd66e72f2cbe9bb8124bf29ba..971b47d87f9bc655cb3a801d0d0e7cb58be8b063 100755 (executable)
@@ -19,7 +19,6 @@
 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 
 srcdir="${srcdir:-.}"
-CLI="${CLI:-../../src/gnutls-cli$EXEEXT}"
 DANETOOL="${DANETOOL:-../../src/danetool$EXEEXT}"
 unset RETCODE
 
@@ -40,14 +39,8 @@ HOSTS="$HOSTS nohats.ca"
 # used to work: dane.nox.su torproject.org jhcloos.com
 for i in $HOSTS;do
 echo -n "$i: "
-rm -f tmp
-$CLI $i -p 443 --print-cert --insecure >tmp 2>&1 </dev/null
-if [ $? != 0 ];then
-       echo "Error connecting to $i"
-       exit 1
-fi
 
-$DANETOOL --load-certificate tmp --check $i >/dev/null 2>&1
+$DANETOOL --check $i >/dev/null 2>&1
 if [ $? != 0 ];then
        echo "Error checking $i"
        exit 1
@@ -63,14 +56,7 @@ HOSTS="bad-hash.dane.verisignlabs.com bad-params.dane.verisignlabs.com"
 HOSTS="$HOSTS bad-sig.dane.verisignlabs.com"
 for i in $HOSTS;do
 echo -n "$i: "
-rm -f tmp
-$CLI $i -p 443 --print-cert --insecure >tmp 2>&1 </dev/null
-if [ $? != 0 ];then
-       echo "Error connecting to $i"
-       exit 1
-fi
-
-$DANETOOL --load-certificate tmp --check $i >/dev/null 2>&1
+$DANETOOL --check $i >/dev/null 2>&1
 if [ $? = 0 ];then
        echo "Checking $i should have failed"
        exit 1