X-Git-Url: https://ruderich.org/simon/gitweb/?a=blobdiff_plain;f=tests%2Fclient.c;fp=tests%2Fclient.c;h=3f2dc4b66f7ccaddaaff185b23d59410e96ee5a7;hb=c4343157f93bfeb4e6de858fdd61b8fb4eddafc2;hp=0000000000000000000000000000000000000000;hpb=3c4d48bc9f6d8228b4eb61ef7920bdc64fc2eec1;p=tlsproxy%2Ftlsproxy.git diff --git a/tests/client.c b/tests/client.c new file mode 100644 index 0000000..3f2dc4b --- /dev/null +++ b/tests/client.c @@ -0,0 +1,251 @@ +/* + * Simple GnuTLS client used for testing. + * + * Copyright (C) 2011 Simon Ruderich + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +#include +#include +#include +/* socket(), connect() */ +#include +#include +/* close() */ +#include +/* getaddrinfo() */ +#include +/* htons() */ +#include +/* errno */ +#include + +/* GnuTLS */ +#include +#include + + +#define MAX_REQUEST_LINE 4096 + +static int connect_to_host(const char *hostname, const char *port); +static int read_http_request(FILE *client_fd, char *request, size_t length); + + +int main (int argc, char *argv[]) { + int result, response; + unsigned int status; + char buffer[MAX_REQUEST_LINE]; + int server; + FILE *fd; + + gnutls_session_t session; + gnutls_certificate_credentials_t xcred; + + gnutls_x509_crt_t cert; + const gnutls_datum_t *cert_list; + unsigned int cert_list_size; + + if (5 != argc) { + fprintf(stderr, + "Usage: %s \n", + argv[0]); + return EXIT_FAILURE; + } + + gnutls_global_init(); + gnutls_certificate_allocate_credentials(&xcred); + + gnutls_certificate_set_x509_trust_file(xcred, + argv[1], GNUTLS_X509_FMT_PEM); + + gnutls_init(&session, GNUTLS_CLIENT); + gnutls_priority_set_direct(session, "NORMAL", NULL); + gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, xcred); + + server = connect_to_host("localhost", "4711"); + if (-1 == server) { + return EXIT_FAILURE; + } + fd = fdopen(server, "a+"); + if (NULL == fd) { + perror("fdopen()"); + return EXIT_FAILURE; + } + + /* Talk to tlsproxy. */ + fprintf(fd, "CONNECT %s:%s HTTP/1.0\r\n", argv[2], argv[3]); + fprintf(fd, "\r\n"); + fflush(fd); + if (-1 == read_http_request(fd, buffer, sizeof(buffer))) { + fprintf(stderr, "invalid proxy response\n"); + return EXIT_FAILURE; + } + + printf("response: %s\n", buffer); + + if (1 != sscanf(buffer, "HTTP/1.0 %d", &response)) { + fprintf(stderr, "invalid proxy response: %s\n", buffer); + return EXIT_FAILURE; + } + + if (200 != response) { + fprintf(stderr, "proxy failure\n"); + return EXIT_FAILURE; + } + + gnutls_transport_set_ptr(session, (gnutls_transport_ptr_t)server); + + result = gnutls_handshake(session); + if (GNUTLS_E_SUCCESS != result) { + fprintf(stderr, "gnutls_handshake() failed\n"); + gnutls_perror(result); + return EXIT_FAILURE; + } + + /* Verify the proxy certificate. */ + result = gnutls_certificate_verify_peers2(session, &status); + if (0 > result) { + fprintf(stderr, "gnutls_certificate_verify_peers2() failed\n"); + gnutls_perror(result); + return EXIT_FAILURE; + } + + if (status & GNUTLS_CERT_INVALID) { + fprintf(stderr, "certificate invalid\n"); + } + + /* Get proxy certificate. */ + if (0 > (result = gnutls_x509_crt_init(&cert))) { + fprintf(stderr, "gnutls_x509_crt_init() failed"); + gnutls_perror(result); + return EXIT_FAILURE; + } + + cert_list = gnutls_certificate_get_peers(session, &cert_list_size); + if (NULL == cert_list) { + fprintf(stderr, "gnutls_certificate_get_peers() failed"); + return EXIT_FAILURE; + } + + if (0 > (result = gnutls_x509_crt_import(cert, &cert_list[0], + GNUTLS_X509_FMT_DER))) { + fprintf(stderr, "gnutls_x509_crt_import() failed"); + gnutls_perror(result); + return EXIT_FAILURE; + } + + /* Check hostname. */ + if (!gnutls_x509_crt_check_hostname(cert, argv[4])) { + fprintf(stderr, "hostname didn't match '%s'\n", argv[4]); + } + + gnutls_x509_crt_deinit(cert); + + gnutls_bye(session, GNUTLS_SHUT_RDWR); + fclose(fd); + + gnutls_deinit(session); + gnutls_certificate_free_credentials(xcred); + gnutls_global_deinit(); + + return EXIT_SUCCESS; +} + + +/* Copied from src/connection.c (and removed LOG_* stuff)! Don't modify. */ + +static int connect_to_host(const char *hostname, const char *port) { + struct addrinfo gai_hints; + struct addrinfo *gai_result; + int gai_return; + + int server_socket; + struct addrinfo *server; + + if (NULL == hostname || NULL == port) { + return -1; + } + + /* Get IP of hostname server. */ + memset(&gai_hints, 0, sizeof(gai_hints)); + gai_hints.ai_family = AF_UNSPEC; + gai_hints.ai_socktype = SOCK_STREAM; + gai_hints.ai_protocol = 0; + gai_hints.ai_flags = AI_NUMERICSERV /* given port is numeric */ + | AI_ADDRCONFIG /* supported by this computer */ + | AI_V4MAPPED; /* support IPv4 through IPv6 */ + gai_return = getaddrinfo(hostname, port, &gai_hints, &gai_result); + if (0 != gai_return) { + perror("connect_to_host(): getaddrinfo()"); + return -1; + } + + /* Now try to connect to each server returned by getaddrinfo(), use the + * first successful connect. */ + for (server = gai_result; NULL != server; server = server->ai_next) { + server_socket = socket(server->ai_family, + server->ai_socktype, + server->ai_protocol); + if (-1 == server_socket) { + perror("connect_to_host(): socket(), trying next"); + continue; + } + + if (-1 != connect(server_socket, server->ai_addr, + server->ai_addrlen)) { + break; + } + perror("connect_to_host(): connect(), trying next"); + + close(server_socket); + } + /* Make sure we free the result from getaddrinfo(). */ + freeaddrinfo(gai_result); + + if (NULL == server) { + perror("connect_to_host(): no server found, abort"); + return -1; + } + + return server_socket; +} + +static int read_http_request(FILE *client_fd, char *request, size_t length) { + char buffer[MAX_REQUEST_LINE]; + + if (NULL == fgets(request, (int)length, client_fd)) { + if (ferror(client_fd)) { + perror("read_http_request(): fgets()"); + return -1; + } + + return -2; + } + + while (NULL != fgets(buffer, MAX_REQUEST_LINE, client_fd)) { + /* End of header. */ + if (0 == strcmp(buffer, "\n") || 0 == strcmp(buffer, "\r\n")) { + break; + } + } + if (ferror(client_fd)) { + perror("read_http_request(): fgets()"); + return -1; + } + + return 0; +}