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]; unsigned udp = 0; static char tmpfile[32]; int fd, ret; const char *str = "Obtaining certificate from"; const char *service; if (strcmp(proto, "udp") == 0) udp = 1; else if (strcmp(proto, "tcp") != 0) { /* we cannot handle this protocol */ return NULL; } strcpy(tmpfile, "danetool-certXXXXXX"); sockets_init(); snprintf(txt_port, sizeof(txt_port), "%u", port); if (quiet) str = NULL; 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); umask(066); 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; }
void socket_open(socket_st * hd, const char *hostname, const char *service, const char *app_proto, int flags, const char *msg, gnutls_datum_t *rdata) { struct addrinfo hints, *res, *ptr; int sd, err = 0; int udp = flags & SOCKET_FLAG_UDP; int ret; int fastopen = flags & SOCKET_FLAG_FASTOPEN; char buffer[MAX_BUF + 1]; char portname[16] = { 0 }; gnutls_datum_t idna; char *a_hostname; memset(hd, 0, sizeof(*hd)); if (flags & SOCKET_FLAG_VERBOSE) hd->verbose = 1; if (rdata) { hd->rdata.data = rdata->data; hd->rdata.size = rdata->size; } ret = gnutls_idna_map(hostname, strlen(hostname), &idna, 0); if (ret < 0) { fprintf(stderr, "Cannot convert %s to IDNA: %s\n", hostname, gnutls_strerror(ret)); exit(1); } hd->hostname = strdup(hostname); a_hostname = (char*)idna.data; if (msg != NULL) printf("Resolving '%s:%s'...\n", a_hostname, service); /* get server name */ memset(&hints, 0, sizeof(hints)); hints.ai_socktype = udp ? SOCK_DGRAM : SOCK_STREAM; if ((err = getaddrinfo(a_hostname, service, &hints, &res))) { fprintf(stderr, "Cannot resolve %s:%s: %s\n", hostname, service, gai_strerror(err)); exit(1); } sd = -1; for (ptr = res; ptr != NULL; ptr = ptr->ai_next) { sd = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol); if (sd == -1) continue; if ((err = getnameinfo(ptr->ai_addr, ptr->ai_addrlen, buffer, MAX_BUF, portname, sizeof(portname), NI_NUMERICHOST | NI_NUMERICSERV)) != 0) { fprintf(stderr, "getnameinfo(): %s\n", gai_strerror(err)); continue; } if (hints.ai_socktype == SOCK_DGRAM) { #if defined(IP_DONTFRAG) int yes = 1; if (setsockopt(sd, IPPROTO_IP, IP_DONTFRAG, (const void *) &yes, sizeof(yes)) < 0) perror("setsockopt(IP_DF) failed"); #elif defined(IP_MTU_DISCOVER) int yes = IP_PMTUDISC_DO; if (setsockopt(sd, IPPROTO_IP, IP_MTU_DISCOVER, (const void *) &yes, sizeof(yes)) < 0) perror("setsockopt(IP_DF) failed"); #endif } if (fastopen && ptr->ai_socktype == SOCK_STREAM && (ptr->ai_family == AF_INET || ptr->ai_family == AF_INET6)) { memcpy(&hd->connect_addr, ptr->ai_addr, ptr->ai_addrlen); hd->connect_addrlen = ptr->ai_addrlen; if (msg) printf("%s '%s:%s' (TFO)...\n", msg, buffer, portname); } else { if (msg) printf("%s '%s:%s'...\n", msg, buffer, portname); if ((err = connect(sd, ptr->ai_addr, ptr->ai_addrlen)) < 0) continue; } hd->fd = sd; if (flags & SOCKET_FLAG_STARTTLS) { hd->app_proto = app_proto; socket_starttls(hd); hd->app_proto = NULL; } if (!(flags & SOCKET_FLAG_SKIP_INIT)) { hd->session = init_tls_session(hostname); if (hd->session == NULL) { fprintf(stderr, "error initializing session\n"); exit(1); } } if (hd->session) { if (hd->rdata.data) { gnutls_session_set_data(hd->session, hd->rdata.data, hd->rdata.size); } gnutls_transport_set_int(hd->session, sd); } if (!(flags & SOCKET_FLAG_RAW) && !(flags & SOCKET_FLAG_SKIP_INIT)) { err = do_handshake(hd); if (err == GNUTLS_E_PUSH_ERROR) { /* failed connecting */ gnutls_deinit(hd->session); hd->session = NULL; continue; } else if (err < 0) { fprintf(stderr, "*** handshake has failed: %s\n", gnutls_strerror(err)); exit(1); } } break; } if (err != 0) { int e = errno; fprintf(stderr, "Could not connect to %s:%s: %s\n", buffer, portname, strerror(e)); exit(1); } if (sd == -1) { fprintf(stderr, "Could not find a supported socket\n"); exit(1); } if ((flags & SOCKET_FLAG_RAW) || (flags & SOCKET_FLAG_SKIP_INIT)) hd->secure = 0; else hd->secure = 1; hd->fd = sd; hd->ip = strdup(buffer); hd->service = strdup(portname); hd->ptr = ptr; hd->addr_info = res; hd->rdata.data = NULL; gnutls_free(idna.data); return; }
int main(int argc, char **argv) { int ret; int i; gnutls_session_t state; char portname[6]; socket_st hd; char app_proto[32] = ""; cmd_parser(argc, argv); #ifndef _WIN32 signal(SIGPIPE, SIG_IGN); #endif sockets_init(); if (gnutls_global_init() < 0) { fprintf(stderr, "global state initialization error\n"); exit(1); } gnutls_global_set_log_function(tls_log_func); gnutls_global_set_log_level(debug); /* get server name */ snprintf(portname, sizeof(portname), "%d", port); /* X509 stuff */ if (gnutls_certificate_allocate_credentials(&xcred) < 0) { /* space for 2 certificates */ fprintf(stderr, "memory error\n"); exit(1); } /* SRP stuff */ #ifdef ENABLE_SRP if (gnutls_srp_allocate_client_credentials(&srp_cred) < 0) { fprintf(stderr, "memory error\n"); exit(1); } #endif #ifdef ENABLE_ANON /* ANON stuff */ if (gnutls_anon_allocate_client_credentials(&anon_cred) < 0) { fprintf(stderr, "memory error\n"); exit(1); } #endif if (HAVE_OPT(STARTTLS_PROTO)) { snprintf(app_proto, sizeof(app_proto), "%s", OPT_ARG(STARTTLS_PROTO)); } if (app_proto[0] == 0) { snprintf(app_proto, sizeof(app_proto), "%s", port_to_service(portname, "tcp")); } sockets_init(); i = 0; printf("GnuTLS debug client %s\n", gnutls_check_version(NULL)); printf("Checking %s:%s\n", hostname, portname); do { if (tls_tests[i].test_name == NULL) break; /* finished */ /* if neither of SSL3 and TLSv1 are supported, exit */ if (i > 6 && tls1_2_ok == 0 && tls1_1_ok == 0 && tls1_ok == 0 && ssl3_ok == 0) { fprintf(stderr, "\nServer does not support any of SSL 3.0, TLS 1.0 and TLS 1.1 and TLS 1.2\n"); break; } socket_open(&hd, hostname, portname, 0, NULL); hd.verbose = verbose; socket_starttls(&hd, app_proto); gnutls_init(&state, GNUTLS_CLIENT | GNUTLS_NO_EXTENSIONS); gnutls_transport_set_ptr(state, (gnutls_transport_ptr_t) gl_fd_to_handle(hd.fd)); set_read_funcs(state); if (hostname && is_ip(hostname) == 0) gnutls_server_name_set(state, GNUTLS_NAME_DNS, hostname, strlen(hostname)); do { if (strcmp(app_proto, "https") != 0 && tls_tests[i].https_only != 0) { i++; break; } ret = tls_tests[i].func(state); if (ret != TEST_IGNORE) { printf("%58s...", tls_tests[i].test_name); fflush(stdout); } if (ret == TEST_SUCCEED) { if (tls_tests[i].suc_str == NULL) printf(" %s\n", ext_text); else printf(" %s\n", tls_tests[i].suc_str); } else if (ret == TEST_FAILED) printf(" %s\n", tls_tests[i].fail_str); else if (ret == TEST_UNSURE) printf(" %s\n", tls_tests[i].unsure_str); else if (ret == TEST_IGNORE) { if (tls_tests[i+1].test_name) i++; else break; } } while (ret == TEST_IGNORE && tls_tests[i].test_name != NULL); gnutls_deinit(state); socket_bye(&hd); i++; } while (1); #ifdef ENABLE_SRP gnutls_srp_free_client_credentials(srp_cred); #endif gnutls_certificate_free_credentials(xcred); #ifdef ENABLE_ANON gnutls_anon_free_client_credentials(anon_cred); #endif gnutls_global_deinit(); return 0; }