2 * Simple GnuTLS client used for testing.
4 * Copyright (C) 2011-2013 Simon Ruderich
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
25 /* socket(), connect() */
26 #include <sys/types.h>
27 #include <sys/socket.h>
33 #include <arpa/inet.h>
38 #include <gnutls/gnutls.h>
39 #include <gnutls/x509.h>
42 #define MAX_REQUEST_LINE 4096
44 static int connect_to_host(const char *hostname, const char *port);
45 static int read_http_request(FILE *client_fd, char *request, size_t length);
48 int main (int argc, char *argv[]) {
51 char buffer[MAX_REQUEST_LINE];
55 gnutls_session_t session;
56 gnutls_certificate_credentials_t xcred;
58 gnutls_x509_crt_t cert;
59 const gnutls_datum_t *cert_list;
60 unsigned int cert_list_size;
64 "Usage: %s <ca-file> <hostname> <port> <hostname-verify>\n",
70 gnutls_certificate_allocate_credentials(&xcred);
72 gnutls_certificate_set_x509_trust_file(xcred,
73 argv[1], GNUTLS_X509_FMT_PEM);
75 gnutls_init(&session, GNUTLS_CLIENT);
76 gnutls_priority_set_direct(session, "NORMAL", NULL);
77 gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, xcred);
79 server = connect_to_host("localhost", "4711");
83 fd = fdopen(server, "a+");
89 /* Talk to tlsproxy. */
90 fprintf(fd, "CONNECT %s:%s HTTP/1.0\r\n", argv[2], argv[3]);
93 if (-1 == read_http_request(fd, buffer, sizeof(buffer))) {
94 fprintf(stderr, "invalid proxy response\n");
98 printf("response: %s\n", buffer);
100 if (1 != sscanf(buffer, "HTTP/1.0 %d", &response)) {
101 fprintf(stderr, "invalid proxy response: %s\n", buffer);
105 if (200 != response) {
106 fprintf(stderr, "proxy failure\n");
110 gnutls_transport_set_ptr(session, (gnutls_transport_ptr_t)server);
112 result = gnutls_handshake(session);
113 if (GNUTLS_E_SUCCESS != result) {
114 fprintf(stderr, "gnutls_handshake() failed\n");
115 gnutls_perror(result);
119 /* Verify the proxy certificate. */
120 result = gnutls_certificate_verify_peers2(session, &status);
122 fprintf(stderr, "gnutls_certificate_verify_peers2() failed\n");
123 gnutls_perror(result);
127 if (status & GNUTLS_CERT_INVALID) {
128 fprintf(stderr, "certificate invalid\n");
131 /* Get proxy certificate. */
132 if (0 > (result = gnutls_x509_crt_init(&cert))) {
133 fprintf(stderr, "gnutls_x509_crt_init() failed");
134 gnutls_perror(result);
138 cert_list = gnutls_certificate_get_peers(session, &cert_list_size);
139 if (NULL == cert_list) {
140 fprintf(stderr, "gnutls_certificate_get_peers() failed");
144 if (0 > (result = gnutls_x509_crt_import(cert, &cert_list[0],
145 GNUTLS_X509_FMT_DER))) {
146 fprintf(stderr, "gnutls_x509_crt_import() failed");
147 gnutls_perror(result);
151 /* Check hostname. */
152 if (!gnutls_x509_crt_check_hostname(cert, argv[4])) {
153 fprintf(stderr, "hostname didn't match '%s'\n", argv[4]);
157 gnutls_x509_crt_deinit(cert);
159 gnutls_bye(session, GNUTLS_SHUT_RDWR);
162 gnutls_deinit(session);
163 gnutls_certificate_free_credentials(xcred);
164 gnutls_global_deinit();
170 /* Copied from src/connection.c (and removed LOG_* stuff)! Don't modify. */
172 static int connect_to_host(const char *hostname, const char *port) {
173 struct addrinfo gai_hints;
174 struct addrinfo *gai_result;
178 struct addrinfo *server;
180 if (NULL == hostname || NULL == port) {
184 /* Get IP of hostname server. */
185 memset(&gai_hints, 0, sizeof(gai_hints));
186 gai_hints.ai_family = AF_UNSPEC;
187 gai_hints.ai_socktype = SOCK_STREAM;
188 gai_hints.ai_protocol = 0;
189 gai_hints.ai_flags = AI_NUMERICSERV /* given port is numeric */
190 | AI_ADDRCONFIG /* supported by this computer */
191 | AI_V4MAPPED; /* support IPv4 through IPv6 */
192 gai_return = getaddrinfo(hostname, port, &gai_hints, &gai_result);
193 if (0 != gai_return) {
194 perror("connect_to_host(): getaddrinfo()");
198 /* Now try to connect to each server returned by getaddrinfo(), use the
199 * first successful connect. */
200 for (server = gai_result; NULL != server; server = server->ai_next) {
201 server_socket = socket(server->ai_family,
203 server->ai_protocol);
204 if (-1 == server_socket) {
205 perror("connect_to_host(): socket(), trying next");
209 if (-1 != connect(server_socket, server->ai_addr,
210 server->ai_addrlen)) {
213 perror("connect_to_host(): connect(), trying next");
215 close(server_socket);
217 /* Make sure we free the result from getaddrinfo(). */
218 freeaddrinfo(gai_result);
220 if (NULL == server) {
221 perror("connect_to_host(): no server found, abort");
225 return server_socket;
228 static int read_http_request(FILE *client_fd, char *request, size_t length) {
229 char buffer[MAX_REQUEST_LINE];
231 if (NULL == fgets(request, (int)length, client_fd)) {
232 if (ferror(client_fd)) {
233 perror("read_http_request(): fgets()");
240 while (NULL != fgets(buffer, MAX_REQUEST_LINE, client_fd)) {
242 if (0 == strcmp(buffer, "\n") || 0 == strcmp(buffer, "\r\n")) {
246 if (ferror(client_fd)) {
247 perror("read_http_request(): fgets()");