summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@gnutls.org>2014-08-09 09:43:45 +0200
committerNikos Mavrogiannopoulos <nmav@gnutls.org>2014-08-09 09:54:49 +0200
commit12319413359c538fd8b249ed949af94e0ea29b49 (patch)
tree8f7025cc72b12f2e0d9f7df680f49ce87a8f433a
parent5f596c0194c42d68f8bc3442e3e38a147f729a06 (diff)
downloadgnutls-12319413359c538fd8b249ed949af94e0ea29b49.tar.gz
danetool: supports SMTP starttls
-rw-r--r--src/danetool-args.def7
-rw-r--r--src/danetool.c27
-rw-r--r--src/socket.c57
-rw-r--r--src/socket.h2
4 files changed, 86 insertions, 7 deletions
diff --git a/src/danetool-args.def b/src/danetool-args.def
index 80a26f20fc..5185e7190f 100644
--- a/src/danetool-args.def
+++ b/src/danetool-args.def
@@ -91,6 +91,13 @@ flag = {
};
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";
doc = "Marks the DANE RR as a CA certificate if specified.";
diff --git a/src/danetool.c b/src/danetool.c
index cce6b37471..a1dcbca782 100644
--- a/src/danetool.c
+++ b/src/danetool.c
@@ -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) {
diff --git a/src/socket.c b/src/socket.c
index ca38027f51..6885efcc0d 100644
--- a/src/socket.c
+++ b/src/socket.c
@@ -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;
diff --git a/src/socket.h b/src/socket.h
index d06788ce17..e47138cf9e 100644
--- a/src/socket.h
+++ b/src/socket.h
@@ -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);