diff options
author | jsing <> | 2014-07-13 22:42:01 +0000 |
---|---|---|
committer | jsing <> | 2014-07-13 22:42:01 +0000 |
commit | 02332d5d0dcdf23c14ec45f52fb95d580089f34a (patch) | |
tree | cc97d9a54751afd8dad5a5cf8447091489584a9c /src/lib | |
parent | 12562f20bce4aa5f48a40c04ebb898cff187e76c (diff) | |
download | openbsd-02332d5d0dcdf23c14ec45f52fb95d580089f34a.tar.gz openbsd-02332d5d0dcdf23c14ec45f52fb95d580089f34a.tar.bz2 openbsd-02332d5d0dcdf23c14ec45f52fb95d580089f34a.zip |
Move the client code into a separate file.
Diffstat (limited to 'src/lib')
-rw-r--r-- | src/lib/libressl/Makefile | 3 | ||||
-rw-r--r-- | src/lib/libressl/ressl.c | 160 | ||||
-rw-r--r-- | src/lib/libressl/ressl_client.c | 183 |
3 files changed, 185 insertions, 161 deletions
diff --git a/src/lib/libressl/Makefile b/src/lib/libressl/Makefile index 167379edff..397fefdf69 100644 --- a/src/lib/libressl/Makefile +++ b/src/lib/libressl/Makefile | |||
@@ -1,4 +1,4 @@ | |||
1 | # $OpenBSD: Makefile,v 1.2 2014/07/13 22:13:52 jsing Exp $ | 1 | # $OpenBSD: Makefile,v 1.3 2014/07/13 22:42:01 jsing Exp $ |
2 | 2 | ||
3 | CFLAGS+= -Wall -Werror -Wimplicit | 3 | CFLAGS+= -Wall -Werror -Wimplicit |
4 | CFLAGS+= -DLIBRESSL_INTERNAL | 4 | CFLAGS+= -DLIBRESSL_INTERNAL |
@@ -10,6 +10,7 @@ DPADD= ${LIBCRYPTO} ${LIBSSL} | |||
10 | HDRS= ressl.h | 10 | HDRS= ressl.h |
11 | 11 | ||
12 | SRCS= ressl.c \ | 12 | SRCS= ressl.c \ |
13 | ressl_client.c \ | ||
13 | ressl_config.c \ | 14 | ressl_config.c \ |
14 | ressl_util.c \ | 15 | ressl_util.c \ |
15 | ressl_verify.c | 16 | ressl_verify.c |
diff --git a/src/lib/libressl/ressl.c b/src/lib/libressl/ressl.c index 7295c520d2..dc82f321b1 100644 --- a/src/lib/libressl/ressl.c +++ b/src/lib/libressl/ressl.c | |||
@@ -14,18 +14,12 @@ | |||
14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | 14 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
15 | */ | 15 | */ |
16 | 16 | ||
17 | #include <sys/types.h> | ||
18 | #include <sys/socket.h> | 17 | #include <sys/socket.h> |
19 | 18 | ||
20 | #include <arpa/inet.h> | ||
21 | |||
22 | #include <errno.h> | 19 | #include <errno.h> |
23 | #include <netdb.h> | ||
24 | #include <stdlib.h> | 20 | #include <stdlib.h> |
25 | #include <unistd.h> | 21 | #include <unistd.h> |
26 | 22 | ||
27 | #include <openssl/x509.h> | ||
28 | |||
29 | #include <ressl.h> | 23 | #include <ressl.h> |
30 | #include "ressl_internal.h" | 24 | #include "ressl_internal.h" |
31 | 25 | ||
@@ -117,160 +111,6 @@ ressl_reset(struct ressl *ctx) | |||
117 | } | 111 | } |
118 | 112 | ||
119 | int | 113 | int |
120 | ressl_connect(struct ressl *ctx, const char *host, const char *port) | ||
121 | { | ||
122 | struct addrinfo hints, *res, *res0; | ||
123 | const char *h = NULL, *p = NULL; | ||
124 | char *hs = NULL, *ps = NULL; | ||
125 | int rv = -1, s = -1, ret; | ||
126 | |||
127 | if (host == NULL) { | ||
128 | ressl_set_error(ctx, "host not specified"); | ||
129 | goto err; | ||
130 | } | ||
131 | |||
132 | /* | ||
133 | * If port is NULL try to extract a port from the specified host, | ||
134 | * otherwise use the default. | ||
135 | */ | ||
136 | if ((p = (char *)port) == NULL) { | ||
137 | ret = ressl_host_port(host, &hs, &ps); | ||
138 | if (ret == -1) { | ||
139 | ressl_set_error(ctx, "memory allocation failure"); | ||
140 | goto err; | ||
141 | } | ||
142 | if (ret != 0) | ||
143 | port = HTTPS_PORT; | ||
144 | } | ||
145 | |||
146 | h = (hs != NULL) ? hs : host; | ||
147 | p = (ps != NULL) ? ps : port; | ||
148 | |||
149 | memset(&hints, 0, sizeof(hints)); | ||
150 | hints.ai_family = AF_UNSPEC; | ||
151 | hints.ai_socktype = SOCK_STREAM; | ||
152 | |||
153 | if ((ret = getaddrinfo(h, p, &hints, &res0)) != 0) { | ||
154 | ressl_set_error(ctx, "%s", gai_strerror(ret)); | ||
155 | goto err; | ||
156 | } | ||
157 | for (res = res0; res; res = res->ai_next) { | ||
158 | s = socket(res->ai_family, res->ai_socktype, res->ai_protocol); | ||
159 | if (s == -1) { | ||
160 | ressl_set_error(ctx, "socket"); | ||
161 | continue; | ||
162 | } | ||
163 | if (connect(s, res->ai_addr, res->ai_addrlen) == -1) { | ||
164 | ressl_set_error(ctx, "connect"); | ||
165 | close(s); | ||
166 | s = -1; | ||
167 | continue; | ||
168 | } | ||
169 | |||
170 | break; /* Connected. */ | ||
171 | } | ||
172 | freeaddrinfo(res0); | ||
173 | |||
174 | if (s == -1) | ||
175 | goto err; | ||
176 | |||
177 | if (ressl_connect_socket(ctx, s, h) != 0) { | ||
178 | close(s); | ||
179 | goto err; | ||
180 | } | ||
181 | |||
182 | rv = 0; | ||
183 | |||
184 | err: | ||
185 | |||
186 | free(hs); | ||
187 | free(ps); | ||
188 | |||
189 | return (rv); | ||
190 | } | ||
191 | |||
192 | int | ||
193 | ressl_connect_socket(struct ressl *ctx, int socket, const char *hostname) | ||
194 | { | ||
195 | union { struct in_addr ip4; struct in6_addr ip6; } addrbuf; | ||
196 | X509 *cert = NULL; | ||
197 | int ret; | ||
198 | |||
199 | ctx->socket = socket; | ||
200 | |||
201 | /* XXX - add a configuration option to control versions. */ | ||
202 | if ((ctx->ssl_ctx = SSL_CTX_new(SSLv23_client_method())) == NULL) { | ||
203 | ressl_set_error(ctx, "ssl context failure"); | ||
204 | goto err; | ||
205 | } | ||
206 | if (ctx->config->verify) { | ||
207 | if (hostname == NULL) { | ||
208 | ressl_set_error(ctx, "server name not specified"); | ||
209 | goto err; | ||
210 | } | ||
211 | |||
212 | SSL_CTX_set_verify(ctx->ssl_ctx, SSL_VERIFY_PEER, NULL); | ||
213 | |||
214 | if (SSL_CTX_load_verify_locations(ctx->ssl_ctx, | ||
215 | ctx->config->ca_file, ctx->config->ca_path) != 1) { | ||
216 | ressl_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 | ressl_set_error(ctx, "ssl connection failure"); | ||
226 | goto err; | ||
227 | } | ||
228 | if (SSL_set_fd(ctx->ssl_conn, ctx->socket) != 1) { | ||
229 | ressl_set_error(ctx, "ssl file descriptor failure"); | ||
230 | goto err; | ||
231 | } | ||
232 | |||
233 | /* | ||
234 | * RFC4366 (SNI): Literal IPv4 and IPv6 addresses are not | ||
235 | * permitted in "HostName". | ||
236 | */ | ||
237 | if (hostname != NULL && | ||
238 | inet_pton(AF_INET, hostname, &addrbuf) != 1 && | ||
239 | inet_pton(AF_INET6, hostname, &addrbuf) != 1) { | ||
240 | if (SSL_set_tlsext_host_name(ctx->ssl_conn, hostname) == 0) { | ||
241 | ressl_set_error(ctx, "SNI host name failed"); | ||
242 | goto err; | ||
243 | } | ||
244 | } | ||
245 | |||
246 | if ((ret = SSL_connect(ctx->ssl_conn)) != 1) { | ||
247 | ressl_set_error(ctx, "SSL connect failed: %i", | ||
248 | SSL_get_error(ctx->ssl_conn, ret)); | ||
249 | goto err; | ||
250 | } | ||
251 | |||
252 | if (ctx->config->verify) { | ||
253 | cert = SSL_get_peer_certificate(ctx->ssl_conn); | ||
254 | if (cert == NULL) { | ||
255 | ressl_set_error(ctx, "no server certificate"); | ||
256 | goto err; | ||
257 | } | ||
258 | if (ressl_check_hostname(cert, hostname) != 0) { | ||
259 | ressl_set_error(ctx, "host `%s' not present in" | ||
260 | " server certificate", hostname); | ||
261 | goto err; | ||
262 | } | ||
263 | } | ||
264 | |||
265 | return (0); | ||
266 | |||
267 | err: | ||
268 | X509_free(cert); | ||
269 | |||
270 | return (-1); | ||
271 | } | ||
272 | |||
273 | int | ||
274 | ressl_read(struct ressl *ctx, char *buf, size_t buflen, size_t *outlen) | 114 | ressl_read(struct ressl *ctx, char *buf, size_t buflen, size_t *outlen) |
275 | { | 115 | { |
276 | int ret; | 116 | int ret; |
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 | |||
31 | int | ||
32 | ressl_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 | |||
96 | err: | ||
97 | |||
98 | free(hs); | ||
99 | free(ps); | ||
100 | |||
101 | return (rv); | ||
102 | } | ||
103 | |||
104 | int | ||
105 | ressl_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 | |||
179 | err: | ||
180 | X509_free(cert); | ||
181 | |||
182 | return (-1); | ||
183 | } | ||