summaryrefslogtreecommitdiff
path: root/src/lib/libressl/ressl_client.c
diff options
context:
space:
mode:
authorjsing <>2014-07-13 22:42:01 +0000
committerjsing <>2014-07-13 22:42:01 +0000
commit02332d5d0dcdf23c14ec45f52fb95d580089f34a (patch)
treecc97d9a54751afd8dad5a5cf8447091489584a9c /src/lib/libressl/ressl_client.c
parent12562f20bce4aa5f48a40c04ebb898cff187e76c (diff)
downloadopenbsd-02332d5d0dcdf23c14ec45f52fb95d580089f34a.tar.gz
openbsd-02332d5d0dcdf23c14ec45f52fb95d580089f34a.tar.bz2
openbsd-02332d5d0dcdf23c14ec45f52fb95d580089f34a.zip
Move the client code into a separate file.
Diffstat (limited to 'src/lib/libressl/ressl_client.c')
-rw-r--r--src/lib/libressl/ressl_client.c183
1 files changed, 183 insertions, 0 deletions
diff --git a/src/lib/libressl/ressl_client.c b/src/lib/libressl/ressl_client.c
new file mode 100644
index 0000000000..2e4f253856
--- /dev/null
+++ b/src/lib/libressl/ressl_client.c
@@ -0,0 +1,183 @@
1/*
2 * Copyright (c) 2014 Joel Sing <jsing@openbsd.org>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#include <sys/types.h>
18#include <sys/socket.h>
19
20#include <arpa/inet.h>
21
22#include <netdb.h>
23#include <stdlib.h>
24#include <unistd.h>
25
26#include <openssl/x509.h>
27
28#include <ressl.h>
29#include "ressl_internal.h"
30
31int
32ressl_connect(struct ressl *ctx, const char *host, const char *port)
33{
34 struct addrinfo hints, *res, *res0;
35 const char *h = NULL, *p = NULL;
36 char *hs = NULL, *ps = NULL;
37 int rv = -1, s = -1, ret;
38
39 if (host == NULL) {
40 ressl_set_error(ctx, "host not specified");
41 goto err;
42 }
43
44 /*
45 * If port is NULL try to extract a port from the specified host,
46 * otherwise use the default.
47 */
48 if ((p = (char *)port) == NULL) {
49 ret = ressl_host_port(host, &hs, &ps);
50 if (ret == -1) {
51 ressl_set_error(ctx, "memory allocation failure");
52 goto err;
53 }
54 if (ret != 0)
55 port = HTTPS_PORT;
56 }
57
58 h = (hs != NULL) ? hs : host;
59 p = (ps != NULL) ? ps : port;
60
61 memset(&hints, 0, sizeof(hints));
62 hints.ai_family = AF_UNSPEC;
63 hints.ai_socktype = SOCK_STREAM;
64
65 if ((ret = getaddrinfo(h, p, &hints, &res0)) != 0) {
66 ressl_set_error(ctx, "%s", gai_strerror(ret));
67 goto err;
68 }
69 for (res = res0; res; res = res->ai_next) {
70 s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
71 if (s == -1) {
72 ressl_set_error(ctx, "socket");
73 continue;
74 }
75 if (connect(s, res->ai_addr, res->ai_addrlen) == -1) {
76 ressl_set_error(ctx, "connect");
77 close(s);
78 s = -1;
79 continue;
80 }
81
82 break; /* Connected. */
83 }
84 freeaddrinfo(res0);
85
86 if (s == -1)
87 goto err;
88
89 if (ressl_connect_socket(ctx, s, h) != 0) {
90 close(s);
91 goto err;
92 }
93
94 rv = 0;
95
96err:
97
98 free(hs);
99 free(ps);
100
101 return (rv);
102}
103
104int
105ressl_connect_socket(struct ressl *ctx, int socket, const char *hostname)
106{
107 union { struct in_addr ip4; struct in6_addr ip6; } addrbuf;
108 X509 *cert = NULL;
109 int ret;
110
111 ctx->socket = socket;
112
113 /* XXX - add a configuration option to control versions. */
114 if ((ctx->ssl_ctx = SSL_CTX_new(SSLv23_client_method())) == NULL) {
115 ressl_set_error(ctx, "ssl context failure");
116 goto err;
117 }
118 if (ctx->config->verify) {
119 if (hostname == NULL) {
120 ressl_set_error(ctx, "server name not specified");
121 goto err;
122 }
123
124 SSL_CTX_set_verify(ctx->ssl_ctx, SSL_VERIFY_PEER, NULL);
125
126 if (SSL_CTX_load_verify_locations(ctx->ssl_ctx,
127 ctx->config->ca_file, ctx->config->ca_path) != 1) {
128 ressl_set_error(ctx, "ssl verify setup failure");
129 goto err;
130 }
131 if (ctx->config->verify_depth >= 0)
132 SSL_CTX_set_verify_depth(ctx->ssl_ctx,
133 ctx->config->verify_depth);
134 }
135
136 if ((ctx->ssl_conn = SSL_new(ctx->ssl_ctx)) == NULL) {
137 ressl_set_error(ctx, "ssl connection failure");
138 goto err;
139 }
140 if (SSL_set_fd(ctx->ssl_conn, ctx->socket) != 1) {
141 ressl_set_error(ctx, "ssl file descriptor failure");
142 goto err;
143 }
144
145 /*
146 * RFC4366 (SNI): Literal IPv4 and IPv6 addresses are not
147 * permitted in "HostName".
148 */
149 if (hostname != NULL &&
150 inet_pton(AF_INET, hostname, &addrbuf) != 1 &&
151 inet_pton(AF_INET6, hostname, &addrbuf) != 1) {
152 if (SSL_set_tlsext_host_name(ctx->ssl_conn, hostname) == 0) {
153 ressl_set_error(ctx, "SNI host name failed");
154 goto err;
155 }
156 }
157
158 if ((ret = SSL_connect(ctx->ssl_conn)) != 1) {
159 ressl_set_error(ctx, "SSL connect failed: %i",
160 SSL_get_error(ctx->ssl_conn, ret));
161 goto err;
162 }
163
164 if (ctx->config->verify) {
165 cert = SSL_get_peer_certificate(ctx->ssl_conn);
166 if (cert == NULL) {
167 ressl_set_error(ctx, "no server certificate");
168 goto err;
169 }
170 if (ressl_check_hostname(cert, hostname) != 0) {
171 ressl_set_error(ctx, "host `%s' not present in"
172 " server certificate", hostname);
173 goto err;
174 }
175 }
176
177 return (0);
178
179err:
180 X509_free(cert);
181
182 return (-1);
183}