]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
danetool: supports SMTP starttls
authorNikos Mavrogiannopoulos <nmav@gnutls.org>
Sat, 9 Aug 2014 07:43:45 +0000 (09:43 +0200)
committerNikos Mavrogiannopoulos <nmav@gnutls.org>
Sat, 9 Aug 2014 07:52:09 +0000 (09:52 +0200)
src/danetool-args.def
src/danetool.c
src/socket.c
src/socket.h

index 80a26f20fca1fd60db04e43e5558b8fd12d897ff..5185e7190f3aac566a9bcb31b116706a20c2c008 100644 (file)
@@ -90,6 +90,13 @@ flag = {
     doc      = "";
 };
 
+flag = {
+    name      = app-proto;
+    descrip   = "The application protocol to be used to obtain the server's certificate (https, smtp)";
+    arg-type  = string;
+    doc = "When the server's certificate isn't provided danetool will connect to the server to obtain the certificate. In that case it is required to known the protocol to talk with the server prior to initiating the TLS handshake.";
+};
+
 flag = {
     name      = ca;
     descrip   = "Whether the provided certificate or public key is a Certificate Authority";
index cce6b3747105d20770bcd086f61b4842dd55cec3..a1dcbca78235c1bfa596aad9355d0b16080dba48 100644 (file)
@@ -51,7 +51,8 @@
 #include "certtool-common.h"
 #include "socket.h"
 
-static const char* obtain_cert(const char *hostname, const char *proto, unsigned int port, unsigned quiet);
+static const char* obtain_cert(const char *hostname, const char *proto, unsigned int port,
+                               const char *app_proto, unsigned quiet);
 static void cmd_parser(int argc, char **argv);
 static void dane_info(const char *host, const char *proto,
                      unsigned int port, unsigned int ca,
@@ -236,7 +237,7 @@ static void dane_check(const char *host, const char *proto,
                int *dane_data_len;
                int secure;
                int bogus;
-               
+
                ret = dane_query_to_raw_tlsa(q, &entries, &dane_data,
                        &dane_data_len, &secure, &bogus);
                if (ret < 0) {
@@ -292,7 +293,7 @@ static void dane_check(const char *host, const char *proto,
                fprintf(outfile,
                        "_%u._%s.%s. IN TLSA ( %.2x %.2x %.2x %s )\n",
                        port, proto, host, usage, type, match, lbuffer);
-               
+
                if (!HAVE_OPT(QUIET)) {
                        str = dane_cert_usage_name(usage);
                        if (str == NULL) str= "Unknown";
@@ -309,7 +310,11 @@ static void dane_check(const char *host, const char *proto,
                }
 
                if (!cinfo->cert) {
-                       cinfo->cert = obtain_cert(host, proto, port, HAVE_OPT(QUIET));
+                       const char *app_proto = NULL;
+                       if (HAVE_OPT(APP_PROTO))
+                               app_proto = OPT_ARG(APP_PROTO);
+
+                       cinfo->cert = obtain_cert(host, proto, port, app_proto, HAVE_OPT(QUIET));
                        del = 1;
                }
 
@@ -616,7 +621,9 @@ static int get_cert(socket_st *hd, const char *hostname, unsigned udp, int fd)
        gnutls_transport_set_int(session, hd->fd);
 
        gnutls_set_default_priority(session);
-       gnutls_server_name_set(session, GNUTLS_NAME_DNS, hostname, strlen(hostname));
+       if (hostname && !isdigit(hostname[0])) {
+               gnutls_server_name_set(session, GNUTLS_NAME_DNS, hostname, strlen(hostname));
+       }
        gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, xcred);
 
        do {
@@ -633,7 +640,8 @@ static int get_cert(socket_st *hd, const char *hostname, unsigned udp, int fd)
        return 0;
 }
 
-static const char *obtain_cert(const char *hostname, const char *proto, unsigned port, unsigned quiet)
+static const char *obtain_cert(const char *hostname, const char *proto, unsigned port,
+                               const char *app_proto, unsigned quiet)
 {
        socket_st hd;
        char txt_port[16];
@@ -641,6 +649,7 @@ static const char *obtain_cert(const char *hostname, const char *proto, unsigned
        static char tmpfile[32];
        int fd, ret;
        const char *str = "Obtaining certificate from";
+       const char *service;
 
        if (strcmp(proto, "udp") == 0)
                udp = 1;
@@ -656,7 +665,11 @@ static const char *obtain_cert(const char *hostname, const char *proto, unsigned
 
        if (quiet)
                str = NULL;
-       socket_open(&hd, hostname, port_to_service(txt_port, proto), udp, str);
+       service = port_to_service(txt_port, proto);
+       socket_open(&hd, hostname, service, udp, str);
+
+       if (app_proto == NULL) app_proto = service;
+       socket_starttls(&hd, app_proto);
 
        fd = mkstemp(tmpfile);
        if (fd == -1) {
index ca38027f51d7c8c983556705d138432125ec3a93..6885efcc0d18d97ea5817a2af3d5c8ced6f8ccc1 100644 (file)
@@ -112,6 +112,63 @@ socket_send_range(const socket_st * socket, const void *buffer,
        return ret;
 }
 
+static
+ssize_t send_line(int fd, const char *txt)
+{
+       int len = strlen(txt);
+       int ret;
+
+       ret = send(fd, txt, len, 0);
+
+       if (ret == -1) {
+               fprintf(stderr, "error sending %s\n", txt);
+               exit(1);
+       }
+
+       return ret;
+}
+
+static
+ssize_t wait_for_text(int fd, const char *txt, unsigned txt_size)
+{
+       char buf[256];
+       int ret;
+
+       alarm(10);
+       do {
+               ret = recv(fd, buf, sizeof(buf), 0);
+               if (ret == -1) {
+                       fprintf(stderr, "error receiving %s\n", txt);
+                       exit(1);
+               }
+       } while(ret < (int)txt_size || strncmp(buf, txt, txt_size) != 0);
+
+       alarm(0);
+
+       return ret;
+}
+
+void
+socket_starttls(socket_st * socket, const char *app_proto)
+{
+       if (socket->secure)
+               return;
+
+       if (app_proto == NULL || strcasecmp(app_proto, "https") == 0)
+               return;
+
+       if (strcasecmp(app_proto, "smtp") == 0) {
+               send_line(socket->fd, "EHLO mail.example.com\n");
+               wait_for_text(socket->fd, "220 ", 4);
+               send_line(socket->fd, "STARTTLS\n");
+               wait_for_text(socket->fd, "220 ", 4);
+       } else {
+               fprintf(stderr, "unknown protocol %s\n", app_proto);
+       }
+
+       return;
+}
+
 void socket_bye(socket_st * socket)
 {
        int ret;
index d06788ce1749dc32757e2556808f57d5fe15725b..e47138cf9ec932b512aa56d1ea2827b6686b2b13 100644 (file)
@@ -20,6 +20,8 @@ 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, const char *msg);
+
+void socket_starttls(socket_st * hd, const char *app_proto);
 void socket_bye(socket_st * socket);
 
 void sockets_init(void);