xref: /openbsd-src/lib/libtls/tls_client.c (revision cb39b41371628601fbe4c618205356d538b9d08a)
1 /* $OpenBSD: tls_client.c,v 1.17 2015/03/31 12:21:27 jsing Exp $ */
2 /*
3  * Copyright (c) 2014 Joel Sing <jsing@openbsd.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <sys/types.h>
19 #include <sys/socket.h>
20 
21 #include <arpa/inet.h>
22 #include <netinet/in.h>
23 
24 #include <limits.h>
25 #include <netdb.h>
26 #include <stdlib.h>
27 #include <unistd.h>
28 
29 #include <openssl/x509.h>
30 
31 #include <tls.h>
32 #include "tls_internal.h"
33 
34 struct tls *
35 tls_client(void)
36 {
37 	struct tls *ctx;
38 
39 	if ((ctx = tls_new()) == NULL)
40 		return (NULL);
41 
42 	ctx->flags |= TLS_CLIENT;
43 
44 	return (ctx);
45 }
46 
47 static int
48 tls_connect_host(struct tls *ctx, const char *host, const char *port,
49     int af, int flag)
50 {
51 	struct addrinfo hints, *res, *res0;
52 	int s = -1;
53 
54 	memset(&hints, 0, sizeof(hints));
55 	hints.ai_family = af;
56 	hints.ai_socktype = SOCK_STREAM;
57 	hints.ai_flags = flag;
58 
59 	if ((s = getaddrinfo(host, port, &hints, &res0)) != 0) {
60 		tls_set_error(ctx, "%s", gai_strerror(s));
61 		return (-1);
62 	}
63 	for (res = res0; res; res = res->ai_next) {
64 		s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
65 		if (s == -1) {
66 			tls_set_error(ctx, "socket");
67 			continue;
68 		}
69 		if (connect(s, res->ai_addr, res->ai_addrlen) == -1) {
70 			tls_set_error(ctx, "connect");
71 			close(s);
72 			s = -1;
73 			continue;
74 		}
75 
76 		break;  /* Connected. */
77 	}
78 	freeaddrinfo(res0);
79 
80 	return (s);
81 }
82 
83 int
84 tls_connect(struct tls *ctx, const char *host, const char *port)
85 {
86 	return tls_connect_servername(ctx, host, port, NULL);
87 }
88 
89 int
90 tls_connect_servername(struct tls *ctx, const char *host, const char *port,
91     const char *servername)
92 {
93 	const char *h = NULL, *p = NULL;
94 	char *hs = NULL, *ps = NULL;
95 	int rv = -1, s = -1, ret;
96 
97 	if ((ctx->flags & TLS_CLIENT) == 0) {
98 		tls_set_error(ctx, "not a client context");
99 		goto err;
100 	}
101 
102 	if (host == NULL) {
103 		tls_set_error(ctx, "host not specified");
104 		goto err;
105 	}
106 
107 	/*
108 	 * If port is NULL try to extract a port from the specified host,
109 	 * otherwise use the default.
110 	 */
111 	if ((p = (char *)port) == NULL) {
112 		ret = tls_host_port(host, &hs, &ps);
113 		if (ret == -1) {
114 			tls_set_error(ctx, "memory allocation failure");
115 			goto err;
116 		}
117 		if (ret != 0)
118 			port = HTTPS_PORT;
119 	}
120 
121 	h = (hs != NULL) ? hs : host;
122 	p = (ps != NULL) ? ps : port;
123 
124 	/*
125 	 * First check if the host is specified as a numeric IP address,
126 	 * either IPv4 or IPv6, before trying to resolve the host.
127 	 * The AI_ADDRCONFIG resolver option will not return IPv4 or IPv6
128 	 * records if it is not configured on an interface;  not considering
129 	 * loopback addresses.  Checking the numeric addresses first makes
130 	 * sure that connection attempts to numeric addresses and especially
131 	 * 127.0.0.1 or ::1 loopback addresses are always possible.
132 	 */
133 	if ((s = tls_connect_host(ctx, h, p, AF_INET, AI_NUMERICHOST)) == -1 &&
134 	    (s = tls_connect_host(ctx, h, p, AF_INET6, AI_NUMERICHOST)) == -1 &&
135 	    (s = tls_connect_host(ctx, h, p, AF_UNSPEC, AI_ADDRCONFIG)) == -1)
136 		goto err;
137 
138 	if (servername == NULL)
139 		servername = h;
140 
141 	if (tls_connect_socket(ctx, s, servername) != 0) {
142 		close(s);
143 		goto err;
144 	}
145 
146 	rv = 0;
147 
148 err:
149 	free(hs);
150 	free(ps);
151 
152 	return (rv);
153 }
154 
155 int
156 tls_connect_socket(struct tls *ctx, int s, const char *servername)
157 {
158 	ctx->socket = s;
159 
160 	return tls_connect_fds(ctx, s, s, servername);
161 }
162 
163 int
164 tls_connect_fds(struct tls *ctx, int fd_read, int fd_write,
165     const char *servername)
166 {
167 	union { struct in_addr ip4; struct in6_addr ip6; } addrbuf;
168 	X509 *cert = NULL;
169 	int ret, err;
170 
171 	if (ctx->flags & TLS_CONNECTING)
172 		goto connecting;
173 
174 	if ((ctx->flags & TLS_CLIENT) == 0) {
175 		tls_set_error(ctx, "not a client context");
176 		goto err;
177 	}
178 
179 	if (fd_read < 0 || fd_write < 0) {
180 		tls_set_error(ctx, "invalid file descriptors");
181 		return (-1);
182 	}
183 
184 	if ((ctx->ssl_ctx = SSL_CTX_new(SSLv23_client_method())) == NULL) {
185 		tls_set_error(ctx, "ssl context failure");
186 		goto err;
187 	}
188 
189 	if (tls_configure_ssl(ctx) != 0)
190 		goto err;
191 
192 	if (ctx->config->verify_name) {
193 		if (servername == NULL) {
194 			tls_set_error(ctx, "server name not specified");
195 			goto err;
196 		}
197 	}
198 
199 	if (ctx->config->verify_cert) {
200 		SSL_CTX_set_verify(ctx->ssl_ctx, SSL_VERIFY_PEER, NULL);
201 
202 		if (ctx->config->ca_mem != NULL) {
203 			if (ctx->config->ca_len > INT_MAX) {
204 				tls_set_error(ctx, "ca too long");
205 				goto err;
206 			}
207 
208 			if (SSL_CTX_load_verify_mem(ctx->ssl_ctx,
209 			    ctx->config->ca_mem, ctx->config->ca_len) != 1) {
210 				tls_set_error(ctx,
211 				    "ssl verify memory setup failure");
212 				goto err;
213 			}
214 		} else if (SSL_CTX_load_verify_locations(ctx->ssl_ctx,
215 		    ctx->config->ca_file, ctx->config->ca_path) != 1) {
216 			tls_set_error(ctx, "ssl verify setup failure");
217 			goto err;
218 		}
219 		if (ctx->config->verify_depth >= 0)
220 			SSL_CTX_set_verify_depth(ctx->ssl_ctx,
221 			    ctx->config->verify_depth);
222 	}
223 
224 	if ((ctx->ssl_conn = SSL_new(ctx->ssl_ctx)) == NULL) {
225 		tls_set_error(ctx, "ssl connection failure");
226 		goto err;
227 	}
228 	if (SSL_set_rfd(ctx->ssl_conn, fd_read) != 1 ||
229 	    SSL_set_wfd(ctx->ssl_conn, fd_write) != 1) {
230 		tls_set_error(ctx, "ssl file descriptor failure");
231 		goto err;
232 	}
233 
234 	/*
235 	 * RFC4366 (SNI): Literal IPv4 and IPv6 addresses are not
236 	 * permitted in "HostName".
237 	 */
238 	if (servername != NULL &&
239 	    inet_pton(AF_INET, servername, &addrbuf) != 1 &&
240 	    inet_pton(AF_INET6, servername, &addrbuf) != 1) {
241 		if (SSL_set_tlsext_host_name(ctx->ssl_conn, servername) == 0) {
242 			tls_set_error(ctx, "server name indication failure");
243 			goto err;
244 		}
245 	}
246 
247  connecting:
248 	if ((ret = SSL_connect(ctx->ssl_conn)) != 1) {
249 		err = tls_ssl_error(ctx, ctx->ssl_conn, ret, "connect");
250 		if (err == TLS_READ_AGAIN || err == TLS_WRITE_AGAIN) {
251 			ctx->flags |= TLS_CONNECTING;
252 			return (err);
253 		}
254 		goto err;
255 	}
256 	ctx->flags &= ~TLS_CONNECTING;
257 
258 	if (ctx->config->verify_name) {
259 		cert = SSL_get_peer_certificate(ctx->ssl_conn);
260 		if (cert == NULL) {
261 			tls_set_error(ctx, "no server certificate");
262 			goto err;
263 		}
264 		if ((ret = tls_check_servername(ctx, cert, servername)) != 0) {
265 			if (ret != -2)
266 				tls_set_error(ctx, "name `%s' not present in"
267 				    " server certificate", servername);
268 			goto err;
269 		}
270 		X509_free(cert);
271 	}
272 
273 	return (0);
274 
275 err:
276 	X509_free(cert);
277 
278 	return (-1);
279 }
280