summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorjsing <>2014-07-12 01:20:25 +0000
committerjsing <>2014-07-12 01:20:25 +0000
commit2b0153d4f076d501b21de2e54937a5bb1b139635 (patch)
treecb217fd8fb935cea61fc26de366b7e407229df65 /src
parentc95157e4b6c5e281cb496ef41f9969df25abef91 (diff)
downloadopenbsd-2b0153d4f076d501b21de2e54937a5bb1b139635.tar.gz
openbsd-2b0153d4f076d501b21de2e54937a5bb1b139635.tar.bz2
openbsd-2b0153d4f076d501b21de2e54937a5bb1b139635.zip
Initial version of libressl - a library that provides a clean, simple,
consistent and secure-by-default API for SSL clients (and soon servers). This is a long way from complete and the interface will likely change substantially - committing now so that further work can happen in the tree. Initiated by tedu@ and inspired by discussions with tedu@, beck@ and other developers.
Diffstat (limited to 'src')
-rw-r--r--src/lib/libressl/Makefile28
-rw-r--r--src/lib/libressl/ressl.c335
-rw-r--r--src/lib/libressl/ressl.h39
-rw-r--r--src/lib/libressl/ressl_config.c88
-rw-r--r--src/lib/libressl/ressl_config.h33
-rw-r--r--src/lib/libressl/ressl_internal.h52
-rw-r--r--src/lib/libressl/ressl_util.c80
-rw-r--r--src/lib/libressl/ressl_verify.c190
-rw-r--r--src/lib/libressl/shlib_version2
9 files changed, 847 insertions, 0 deletions
diff --git a/src/lib/libressl/Makefile b/src/lib/libressl/Makefile
new file mode 100644
index 0000000000..c6f4328b79
--- /dev/null
+++ b/src/lib/libressl/Makefile
@@ -0,0 +1,28 @@
1# $OpenBSD: Makefile,v 1.1 2014/07/12 01:20:24 jsing Exp $
2
3CFLAGS+= -Wall -Werror -Wimplicit
4CFLAGS+= -DLIBRESSL_INTERNAL
5
6LIB= ressl
7
8DPADD= ${LIBCRYPTO} ${LIBSSL}
9
10HDRS= ressl.h ressl_config.h
11
12SRCS= ressl.c \
13 ressl_config.c \
14 ressl_util.c \
15 ressl_verify.c
16
17includes:
18 @test -d ${DESTDIR}/usr/include/ressl || \
19 mkdir ${DESTDIR}/usr/include/ressl
20 @cd ${.CURDIR}; for i in $(HDRS); do \
21 j="cmp -s $$i ${DESTDIR}/usr/include/ressl/$$i || \
22 ${INSTALL} ${INSTALL_COPY} -o ${BINOWN} -g ${BINGRP} -m 444 $$i\
23 ${DESTDIR}/usr/include/ressl"; \
24 echo $$j; \
25 eval "$$j"; \
26 done;
27
28.include <bsd.lib.mk>
diff --git a/src/lib/libressl/ressl.c b/src/lib/libressl/ressl.c
new file mode 100644
index 0000000000..21b7c0ead0
--- /dev/null
+++ b/src/lib/libressl/ressl.c
@@ -0,0 +1,335 @@
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 <errno.h>
23#include <netdb.h>
24#include <stdlib.h>
25#include <unistd.h>
26
27#include <openssl/x509.h>
28
29#include <ressl/ressl.h>
30
31#include "ressl_internal.h"
32
33extern struct ressl_config ressl_config_default;
34
35int
36ressl_init(void)
37{
38 static int ressl_initialised = 0;
39
40 if (ressl_initialised)
41 return (0);
42
43 SSL_load_error_strings();
44 SSL_library_init();
45
46 ressl_initialised = 1;
47
48 return (0);
49}
50
51const char *
52ressl_error(struct ressl *ctx)
53{
54 return ctx->errmsg;
55}
56
57int
58ressl_set_error(struct ressl *ctx, char *fmt, ...)
59{
60 va_list ap;
61 int rv;
62
63 ctx->err = errno;
64 free(ctx->errmsg);
65 ctx->errmsg = NULL;
66
67 va_start(ap, fmt);
68 rv = vasprintf(&ctx->errmsg, fmt, ap);
69 va_end(ap);
70
71 return (rv);
72}
73
74struct ressl *
75ressl_new(struct ressl_config *config)
76{
77 struct ressl *ctx;
78
79 if ((ctx = calloc(1, sizeof(*ctx))) == NULL)
80 return (NULL);
81
82 if (config == NULL)
83 config = &ressl_config_default;
84
85 ctx->config = config;
86
87 ressl_reset(ctx);
88
89 return (ctx);
90}
91
92void
93ressl_free(struct ressl *ctx)
94{
95 if (ctx == NULL)
96 return;
97 ressl_reset(ctx);
98 free(ctx);
99}
100
101void
102ressl_reset(struct ressl *ctx)
103{
104 /* SSL_free frees the SSL context. */
105 if (ctx->ssl_conn != NULL)
106 SSL_free(ctx->ssl_conn);
107 else
108 SSL_CTX_free(ctx->ssl_ctx);
109
110 ctx->ssl_conn = NULL;
111 ctx->ssl_ctx = NULL;
112
113 ctx->socket = -1;
114
115 ctx->err = 0;
116 free(ctx->errmsg);
117 ctx->errmsg = NULL;
118}
119
120int
121ressl_connect(struct ressl *ctx, const char *host, const char *port)
122{
123 struct addrinfo hints, *res, *res0;
124 const char *h = NULL, *p = NULL;
125 char *hs = NULL, *ps = NULL;
126 int rv = -1, s = -1, ret;
127
128 if (host == NULL) {
129 ressl_set_error(ctx, "host not specified");
130 goto err;
131 }
132
133 /*
134 * If port is NULL try to extract a port from the specified host,
135 * otherwise use the default.
136 */
137 if ((p = (char *)port) == NULL) {
138 ret = ressl_host_port(host, &hs, &ps);
139 if (ret == -1) {
140 ressl_set_error(ctx, "memory allocation failure");
141 goto err;
142 }
143 if (ret != 0)
144 port = HTTPS_PORT;
145 }
146
147 h = (hs != NULL) ? hs : host;
148 p = (ps != NULL) ? ps : port;
149
150 memset(&hints, 0, sizeof(hints));
151 hints.ai_family = AF_UNSPEC;
152 hints.ai_socktype = SOCK_STREAM;
153
154 if ((ret = getaddrinfo(h, p, &hints, &res0)) != 0) {
155 ressl_set_error(ctx, "%s", gai_strerror(ret));
156 goto err;
157 }
158 for (res = res0; res; res = res->ai_next) {
159 s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
160 if (s == -1) {
161 ressl_set_error(ctx, "socket");
162 continue;
163 }
164 if (connect(s, res->ai_addr, res->ai_addrlen) == -1) {
165 ressl_set_error(ctx, "connect");
166 close(s);
167 s = -1;
168 continue;
169 }
170
171 break; /* Connected. */
172 }
173 freeaddrinfo(res0);
174
175 if (s == -1)
176 goto err;
177
178 if (ressl_connect_socket(ctx, s, h) != 0) {
179 close(s);
180 goto err;
181 }
182
183 rv = 0;
184
185err:
186
187 free(hs);
188 free(ps);
189
190 return (rv);
191}
192
193int
194ressl_connect_socket(struct ressl *ctx, int socket, const char *hostname)
195{
196 union { struct in_addr ip4; struct in6_addr ip6; } addrbuf;
197 X509 *cert = NULL;
198 int ret;
199
200 ctx->socket = socket;
201
202 /* XXX - add a configuration option to control versions. */
203 if ((ctx->ssl_ctx = SSL_CTX_new(SSLv23_client_method())) == NULL) {
204 ressl_set_error(ctx, "ssl context failure");
205 goto err;
206 }
207 if (ctx->config->verify) {
208 if (hostname == NULL) {
209 ressl_set_error(ctx, "server name not specified");
210 goto err;
211 }
212
213 SSL_CTX_set_verify(ctx->ssl_ctx, SSL_VERIFY_PEER, NULL);
214
215 if (SSL_CTX_load_verify_locations(ctx->ssl_ctx,
216 ctx->config->ca_file, ctx->config->ca_path) != 1) {
217 ressl_set_error(ctx, "ssl verify setup failure");
218 goto err;
219 }
220 if (ctx->config->verify_depth >= 0)
221 SSL_CTX_set_verify_depth(ctx->ssl_ctx,
222 ctx->config->verify_depth);
223 }
224
225 if ((ctx->ssl_conn = SSL_new(ctx->ssl_ctx)) == NULL) {
226 ressl_set_error(ctx, "ssl connection failure");
227 goto err;
228 }
229 if (SSL_set_fd(ctx->ssl_conn, ctx->socket) != 1) {
230 ressl_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 (hostname != NULL &&
239 inet_pton(AF_INET, hostname, &addrbuf) != 1 &&
240 inet_pton(AF_INET6, hostname, &addrbuf) != 1) {
241 if (SSL_set_tlsext_host_name(ctx->ssl_conn, hostname) == 0) {
242 ressl_set_error(ctx, "SNI host name failed");
243 goto err;
244 }
245 }
246
247 if ((ret = SSL_connect(ctx->ssl_conn)) != 1) {
248 ressl_set_error(ctx, "SSL connect failed: %i",
249 SSL_get_error(ctx->ssl_conn, ret));
250 goto err;
251 }
252
253 if (ctx->config->verify) {
254 cert = SSL_get_peer_certificate(ctx->ssl_conn);
255 if (cert == NULL) {
256 ressl_set_error(ctx, "no server certificate");
257 goto err;
258 }
259 if (ressl_check_hostname(cert, hostname) != 0) {
260 ressl_set_error(ctx, "host `%s' not present in"
261 " server certificate", hostname);
262 goto err;
263 }
264 }
265
266 return (0);
267
268err:
269 X509_free(cert);
270
271 return (-1);
272}
273
274int
275ressl_read(struct ressl *ctx, char *buf, size_t buflen, size_t *outlen)
276{
277 int ret;
278
279 /* XXX - handle async/non-blocking. */
280 ret = SSL_read(ctx->ssl_conn, buf, buflen);
281 if (ret <= 0) {
282 ret = SSL_get_error(ctx->ssl_conn, ret);
283 if (ret == SSL_ERROR_WANT_READ)
284 return (-2);
285 ressl_set_error(ctx, "read failed: %i", ret);
286 return (-1);
287 }
288 *outlen = (size_t)ret;
289 return (0);
290}
291
292int
293ressl_write(struct ressl *ctx, const char *buf, size_t buflen, size_t *outlen)
294{
295 int ret;
296
297 /* XXX - handle async/non-blocking. */
298 ret = SSL_write(ctx->ssl_conn, buf, buflen);
299 if (ret < 0) {
300 ressl_set_error(ctx, "write failed %d",
301 SSL_get_error(ctx->ssl_conn, ret));
302 return (-1);
303 }
304 *outlen = (size_t)ret;
305 return (0);
306}
307
308int
309ressl_close(struct ressl *ctx)
310{
311 /* XXX - handle case where multiple calls are required. */
312 if (ctx->ssl_conn != NULL) {
313 if (SSL_shutdown(ctx->ssl_conn) == -1) {
314 ressl_set_error(ctx, "SSL shutdown failed");
315 goto err;
316 }
317 }
318
319 if (ctx->socket != -1) {
320 if (shutdown(ctx->socket, SHUT_RDWR) != 0) {
321 ressl_set_error(ctx, "shutdown");
322 goto err;
323 }
324 if (close(ctx->socket) != 0) {
325 ressl_set_error(ctx, "close");
326 goto err;
327 }
328 ctx->socket = -1;
329 }
330
331 return (0);
332
333err:
334 return (-1);
335}
diff --git a/src/lib/libressl/ressl.h b/src/lib/libressl/ressl.h
new file mode 100644
index 0000000000..5217a69c15
--- /dev/null
+++ b/src/lib/libressl/ressl.h
@@ -0,0 +1,39 @@
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#ifndef HEADER_RESSL_H
18#define HEADER_RESSL_H
19
20#include <ressl/ressl_config.h>
21
22struct ressl;
23
24int ressl_init(void);
25
26const char *ressl_error(struct ressl *ctx);
27
28struct ressl *ressl_new(struct ressl_config *config);
29void ressl_reset(struct ressl *ctx);
30void ressl_free(struct ressl *ctx);
31
32int ressl_connect(struct ressl *ctx, const char *host, const char *port);
33int ressl_connect_socket(struct ressl *ctx, int s, const char *hostname);
34int ressl_read(struct ressl *ctx, char *buf, size_t buflen, size_t *outlen);
35int ressl_write(struct ressl *ctx, const char *buf, size_t buflen,
36 size_t *outlen);
37int ressl_close(struct ressl *ctx);
38
39#endif /* HEADER_RESSL_H */
diff --git a/src/lib/libressl/ressl_config.c b/src/lib/libressl/ressl_config.c
new file mode 100644
index 0000000000..a84de591bc
--- /dev/null
+++ b/src/lib/libressl/ressl_config.c
@@ -0,0 +1,88 @@
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 <errno.h>
18#include <stdlib.h>
19
20#include <ressl/ressl.h>
21
22#include "ressl_internal.h"
23
24/*
25 * Default configuration.
26 */
27struct ressl_config ressl_config_default = {
28 .ca_file = _PATH_SSL_CA_FILE,
29 .ca_path = NULL,
30 .ciphers = NULL,
31 .verify = 1,
32 .verify_depth = 6,
33};
34
35struct ressl_config *
36ressl_config_new(void)
37{
38 struct ressl_config *config;
39
40 if ((config = malloc(sizeof(*config))) == NULL)
41 return (NULL);
42
43 memcpy(config, &ressl_config_default, sizeof(*config));
44
45 return (config);
46}
47
48void
49ressl_config_free(struct ressl_config *config)
50{
51 free(config);
52}
53
54void
55ressl_config_ca_file(struct ressl_config *config, char *ca_file)
56{
57 config->ca_file = ca_file;
58}
59
60void
61ressl_config_ca_path(struct ressl_config *config, char *ca_path)
62{
63 config->ca_path = ca_path;
64}
65
66void
67ressl_config_ciphers(struct ressl_config *config, char *ciphers)
68{
69 config->ciphers = ciphers;
70}
71
72void
73ressl_config_insecure(struct ressl_config *config)
74{
75 config->verify = 0;
76}
77
78void
79ressl_config_secure(struct ressl_config *config)
80{
81 config->verify = 1;
82}
83
84void
85ressl_config_verify_depth(struct ressl_config *config, int verify_depth)
86{
87 config->verify_depth = verify_depth;
88}
diff --git a/src/lib/libressl/ressl_config.h b/src/lib/libressl/ressl_config.h
new file mode 100644
index 0000000000..da13d91efa
--- /dev/null
+++ b/src/lib/libressl/ressl_config.h
@@ -0,0 +1,33 @@
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#ifndef HEADER_RESSL_CONFIG_H
18#define HEADER_RESSL_CONFIG_H
19
20struct ressl_config;
21
22struct ressl_config *ressl_config_new(void);
23void ressl_config_free(struct ressl_config *config);
24
25void ressl_config_ca_file(struct ressl_config *config, char *ca_file);
26void ressl_config_ca_path(struct ressl_config *config, char *ca_path);
27void ressl_config_ciphers(struct ressl_config *config, char *ciphers);
28void ressl_config_verify_depth(struct ressl_config *config, int verify_depth);
29
30void ressl_config_insecure(struct ressl_config *config);
31void ressl_config_secure(struct ressl_config *config);
32
33#endif /* HEADER_RESSL_H */
diff --git a/src/lib/libressl/ressl_internal.h b/src/lib/libressl/ressl_internal.h
new file mode 100644
index 0000000000..f4eec10e63
--- /dev/null
+++ b/src/lib/libressl/ressl_internal.h
@@ -0,0 +1,52 @@
1/*
2 * Copyright (c) 2014 Jeremie Courreges-Anglas <jca@openbsd.org>
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#ifndef HEADER_RESSL_INTERNAL_H
19#define HEADER_RESSL_INTERNAL_H
20
21#include <openssl/ssl.h>
22
23#define HTTPS_PORT "443"
24
25#define _PATH_SSL_CA_FILE "/etc/ssl/cert.pem"
26
27struct ressl_config {
28 const char *ca_file;
29 const char *ca_path;
30 const char *ciphers;
31 const char *server_name;
32 int verify;
33 int verify_depth;
34};
35
36struct ressl {
37 struct ressl_config *config;
38
39 int err;
40 char *errmsg;
41
42 int socket;
43
44 SSL *ssl_conn;
45 SSL_CTX *ssl_ctx;
46};
47
48int ressl_check_hostname(X509 *cert, const char *host);
49int ressl_host_port(const char *hostport, char **host, char **port);
50int ressl_set_error(struct ressl *ctx, char *fmt, ...);
51
52#endif /* HEADER_RESSL_INTERNAL_H */
diff --git a/src/lib/libressl/ressl_util.c b/src/lib/libressl/ressl_util.c
new file mode 100644
index 0000000000..ee7b1edbd3
--- /dev/null
+++ b/src/lib/libressl/ressl_util.c
@@ -0,0 +1,80 @@
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 <stdlib.h>
18
19#include "ressl_internal.h"
20
21/*
22 * Extract the host and port from a colon separated value. For a literal IPv6
23 * address the address must be contained with square braces. If a host and
24 * port are successfully extracted, the function will return 0 and the
25 * caller is responsible for freeing the host and port. If no port is found
26 * then the function will return 1, with both host and port being NULL.
27 * On memory allocation failure -1 will be returned.
28 */
29int
30ressl_host_port(const char *hostport, char **host, char **port)
31{
32 char *h, *p, *s;
33 int rv = 1;
34
35 *host = NULL;
36 *port = NULL;
37
38 if ((s = strdup(hostport)) == NULL)
39 goto fail;
40
41 h = p = s;
42
43 /* See if this is an IPv6 literal with square braces. */
44 if (p[0] == '[') {
45 h++;
46 if ((p = strchr(s, ']')) == NULL)
47 goto done;
48 *p++ = '\0';
49 }
50
51 /* Find the port seperator. */
52 if ((p = strchr(p, ':')) == NULL)
53 goto done;
54
55 /* If there is another separator then we have issues. */
56 if (strchr(p + 1, ':') != NULL)
57 goto done;
58
59 *p++ = '\0';
60
61 if (asprintf(host, "%s", h) == -1)
62 goto fail;
63 if (asprintf(port, "%s", p) == -1)
64 goto fail;
65
66 rv = 0;
67 goto done;
68
69fail:
70 free(*host);
71 *host = NULL;
72 free(*port);
73 *port = NULL;
74 rv = -1;
75
76done:
77 free(s);
78
79 return (rv);
80}
diff --git a/src/lib/libressl/ressl_verify.c b/src/lib/libressl/ressl_verify.c
new file mode 100644
index 0000000000..e98a264f4f
--- /dev/null
+++ b/src/lib/libressl/ressl_verify.c
@@ -0,0 +1,190 @@
1/*
2 * Copyright (c) 2014 Jeremie Courreges-Anglas <jca@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/socket.h>
18
19#include <arpa/inet.h>
20#include <netinet/in.h>
21
22#include <string.h>
23
24#include <openssl/x509v3.h>
25
26#include "ressl_internal.h"
27
28int ressl_match_hostname(const char *cert_hostname, const char *hostname);
29int ressl_check_subject_altname(X509 *cert, const char *host);
30int ressl_check_common_name(X509 *cert, const char *host);
31
32int
33ressl_match_hostname(const char *cert_hostname, const char *hostname)
34{
35 const char *cert_domain, *domain;
36
37 if (strcasecmp(cert_hostname, hostname) == 0)
38 return 0;
39
40 /* Wildcard match? */
41 if (cert_hostname[0] == '*') {
42 cert_domain = &cert_hostname[1];
43 if (cert_domain[0] != '.')
44 return -1;
45 if (strlen(cert_domain) == 1)
46 return -1;
47
48 domain = strchr(hostname, '.');
49
50 /* No wildcard match against a hostname with no domain part. */
51 if (domain == NULL || strlen(domain) == 1)
52 return -1;
53
54 if (strcasecmp(cert_domain, domain) == 0)
55 return 0;
56 }
57
58 return -1;
59}
60
61int
62ressl_check_subject_altname(X509 *cert, const char *host)
63{
64 STACK_OF(GENERAL_NAME) *altname_stack = NULL;
65 union { struct in_addr ip4; struct in6_addr ip6; } addrbuf;
66 int addrlen, type;
67 int count, i;
68 int rv = -1;
69
70 altname_stack = X509_get_ext_d2i(cert, NID_subject_alt_name,
71 NULL, NULL);
72 if (altname_stack == NULL)
73 return -1;
74
75 if (inet_pton(AF_INET, host, &addrbuf) == 1) {
76 type = GEN_IPADD;
77 addrlen = 4;
78 } else if (inet_pton(AF_INET6, host, &addrbuf) == 1) {
79 type = GEN_IPADD;
80 addrlen = 16;
81 } else {
82 type = GEN_DNS;
83 addrlen = 0;
84 }
85
86 count = sk_GENERAL_NAME_num(altname_stack);
87 for (i = 0; i < count; i++) {
88 GENERAL_NAME *altname;
89
90 altname = sk_GENERAL_NAME_value(altname_stack, i);
91
92 if (altname->type != type)
93 continue;
94
95 if (type == GEN_DNS) {
96 unsigned char *data;
97 int format;
98
99 format = ASN1_STRING_type(altname->d.dNSName);
100 if (format == V_ASN1_IA5STRING) {
101 data = ASN1_STRING_data(altname->d.dNSName);
102
103 if (ASN1_STRING_length(altname->d.dNSName) !=
104 (int)strlen(data)) {
105 fprintf(stdout, "%s: NUL byte in "
106 "subjectAltName, probably a "
107 "malicious certificate.\n",
108 getprogname());
109 rv = -2;
110 break;
111 }
112
113 if (ressl_match_hostname(data, host) == 0) {
114 rv = 0;
115 break;
116 }
117 } else
118 fprintf(stdout, "%s: unhandled subjectAltName "
119 "dNSName encoding (%d)\n", getprogname(),
120 format);
121
122 } else if (type == GEN_IPADD) {
123 unsigned char *data;
124 int datalen;
125
126 datalen = ASN1_STRING_length(altname->d.iPAddress);
127 data = ASN1_STRING_data(altname->d.iPAddress);
128
129 if (datalen == addrlen &&
130 memcmp(data, &addrbuf, addrlen) == 0) {
131 rv = 0;
132 break;
133 }
134 }
135 }
136
137 sk_GENERAL_NAME_free(altname_stack);
138 return rv;
139}
140
141int
142ressl_check_common_name(X509 *cert, const char *host)
143{
144 X509_NAME *name;
145 char *common_name = NULL;
146 size_t common_name_len;
147 int rv = -1;
148
149 name = X509_get_subject_name(cert);
150 if (name == NULL)
151 goto out;
152
153 common_name_len = X509_NAME_get_text_by_NID(name, NID_commonName,
154 NULL, 0);
155 if (common_name_len < 0)
156 goto out;
157
158 common_name = calloc(common_name_len + 1, 1);
159 if (common_name == NULL)
160 goto out;
161
162 X509_NAME_get_text_by_NID(name, NID_commonName, common_name,
163 common_name_len + 1);
164
165 /* NUL bytes in CN? */
166 if (common_name_len != (int)strlen(common_name)) {
167 fprintf(stdout, "%s: NUL byte in Common Name field, "
168 "probably a malicious certificate.\n", getprogname());
169 rv = -2;
170 goto out;
171 }
172
173 if (ressl_match_hostname(common_name, host) == 0)
174 rv = 0;
175out:
176 free(common_name);
177 return rv;
178}
179
180int
181ressl_check_hostname(X509 *cert, const char *host)
182{
183 int rv;
184
185 rv = ressl_check_subject_altname(cert, host);
186 if (rv == 0 || rv == -2)
187 return rv;
188
189 return ressl_check_common_name(cert, host);
190}
diff --git a/src/lib/libressl/shlib_version b/src/lib/libressl/shlib_version
new file mode 100644
index 0000000000..1edea46de9
--- /dev/null
+++ b/src/lib/libressl/shlib_version
@@ -0,0 +1,2 @@
1major=1
2minor=0