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
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;
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);
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,
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,
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)
#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,
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))
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",
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) {
}
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");
}
}
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;
+}
(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);
#define MAX_BUF 4096
-extern unsigned int verbose;
/* Functions to manipulate sockets
*/
}
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);
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;
}
- 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) {
#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);
+}
char *service;
struct addrinfo *ptr;
struct addrinfo *addr_info;
+ int verbose;
} socket_st;
ssize_t socket_recv(const socket_st * socket, 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"
# 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
# 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
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