summaryrefslogtreecommitdiff
path: root/src/lib/libtls
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/libtls')
-rw-r--r--src/lib/libtls/Makefile58
-rw-r--r--src/lib/libtls/shlib_version2
-rw-r--r--src/lib/libtls/tls.c300
-rw-r--r--src/lib/libtls/tls.h74
-rw-r--r--src/lib/libtls/tls_client.c212
-rw-r--r--src/lib/libtls/tls_config.c201
-rw-r--r--src/lib/libtls/tls_init.3316
-rw-r--r--src/lib/libtls/tls_internal.h72
-rw-r--r--src/lib/libtls/tls_server.c134
-rw-r--r--src/lib/libtls/tls_util.c81
-rw-r--r--src/lib/libtls/tls_verify.c225
11 files changed, 1675 insertions, 0 deletions
diff --git a/src/lib/libtls/Makefile b/src/lib/libtls/Makefile
new file mode 100644
index 0000000000..b83a6de2ce
--- /dev/null
+++ b/src/lib/libtls/Makefile
@@ -0,0 +1,58 @@
1# $OpenBSD: Makefile,v 1.1 2014/10/31 13:46:17 jsing Exp $
2
3CFLAGS+= -Wall -Werror -Wimplicit
4CFLAGS+= -DLIBRESSL_INTERNAL
5
6LIB= tls
7
8DPADD= ${LIBCRYPTO} ${LIBSSL}
9
10HDRS= tls.h
11
12SRCS= tls.c \
13 tls_client.c \
14 tls_config.c \
15 tls_server.c \
16 tls_util.c \
17 tls_verify.c
18
19MAN= tls_init.3
20
21MLINKS+=tls_init.3 tls_config_new.3
22MLINKS+=tls_init.3 tls_config_free.3
23MLINKS+=tls_init.3 tls_config_set_ca_file.3
24MLINKS+=tls_init.3 tls_config_set_ca_path.3
25MLINKS+=tls_init.3 tls_config_set_cert_file.3
26MLINKS+=tls_init.3 tls_config_set_cert_mem.3
27MLINKS+=tls_init.3 tls_config_set_ciphers.3
28MLINKS+=tls_init.3 tls_config_set_ecdhcurve.3
29MLINKS+=tls_init.3 tls_config_set_key_file.3
30MLINKS+=tls_init.3 tls_config_set_key_mem.3
31MLINKS+=tls_init.3 tls_config_set_protocols.3
32MLINKS+=tls_init.3 tls_config_set_verify_depth.3
33MLINKS+=tls_init.3 tls_config_clear_keys.3
34MLINKS+=tls_init.3 tls_config_insecure_noverifyhost.3
35MLINKS+=tls_init.3 tls_config_insecure_noverifycert.3
36MLINKS+=tls_init.3 tls_config_verify.3
37MLINKS+=tls_init.3 tls_client.3
38MLINKS+=tls_init.3 tls_server.3
39MLINKS+=tls_init.3 tls_configure.3
40MLINKS+=tls_init.3 tls_error.3
41MLINKS+=tls_init.3 tls_reset.3
42MLINKS+=tls_init.3 tls_free.3
43MLINKS+=tls_init.3 tls_close.3
44MLINKS+=tls_init.3 tls_connect.3
45MLINKS+=tls_init.3 tls_connect_socket.3
46MLINKS+=tls_init.3 tls_read.3
47MLINKS+=tls_init.3 tls_write.3
48
49includes:
50 @cd ${.CURDIR}; for i in $(HDRS); do \
51 j="cmp -s $$i ${DESTDIR}/usr/include/$$i || \
52 ${INSTALL} ${INSTALL_COPY} -o ${BINOWN} -g ${BINGRP} -m 444 $$i\
53 ${DESTDIR}/usr/include/"; \
54 echo $$j; \
55 eval "$$j"; \
56 done;
57
58.include <bsd.lib.mk>
diff --git a/src/lib/libtls/shlib_version b/src/lib/libtls/shlib_version
new file mode 100644
index 0000000000..1edea46de9
--- /dev/null
+++ b/src/lib/libtls/shlib_version
@@ -0,0 +1,2 @@
1major=1
2minor=0
diff --git a/src/lib/libtls/tls.c b/src/lib/libtls/tls.c
new file mode 100644
index 0000000000..a7f612e40b
--- /dev/null
+++ b/src/lib/libtls/tls.c
@@ -0,0 +1,300 @@
1/* $OpenBSD: tls.c,v 1.1 2014/10/31 13:46:17 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/socket.h>
19
20#include <errno.h>
21#include <stdlib.h>
22#include <unistd.h>
23
24#include <openssl/bio.h>
25#include <openssl/evp.h>
26#include <openssl/pem.h>
27#include <openssl/x509.h>
28
29#include <tls.h>
30#include "tls_internal.h"
31
32static struct tls_config *tls_config_default;
33
34int
35tls_init(void)
36{
37 static int tls_initialised = 0;
38
39 if (tls_initialised)
40 return (0);
41
42 SSL_load_error_strings();
43 SSL_library_init();
44
45 if ((tls_config_default = tls_config_new()) == NULL)
46 return (-1);
47
48 tls_initialised = 1;
49
50 return (0);
51}
52
53const char *
54tls_error(struct tls *ctx)
55{
56 return ctx->errmsg;
57}
58
59int
60tls_set_error(struct tls *ctx, char *fmt, ...)
61{
62 va_list ap;
63 int rv;
64
65 ctx->err = errno;
66 free(ctx->errmsg);
67 ctx->errmsg = NULL;
68
69 va_start(ap, fmt);
70 rv = vasprintf(&ctx->errmsg, fmt, ap);
71 va_end(ap);
72
73 return (rv);
74}
75
76struct tls *
77tls_new(void)
78{
79 struct tls *ctx;
80
81 if ((ctx = calloc(1, sizeof(*ctx))) == NULL)
82 return (NULL);
83
84 ctx->config = tls_config_default;
85
86 tls_reset(ctx);
87
88 return (ctx);
89}
90
91int
92tls_configure(struct tls *ctx, struct tls_config *config)
93{
94 if (config == NULL)
95 config = tls_config_default;
96
97 ctx->config = config;
98
99 if ((ctx->flags & TLS_SERVER) != 0)
100 return (tls_configure_server(ctx));
101
102 return (0);
103}
104
105int
106tls_configure_keypair(struct tls *ctx)
107{
108 EVP_PKEY *pkey = NULL;
109 X509 *cert = NULL;
110 BIO *bio = NULL;
111
112 if (ctx->config->cert_mem != NULL) {
113 if (SSL_CTX_use_certificate_chain(ctx->ssl_ctx,
114 ctx->config->cert_mem, ctx->config->cert_len) != 1) {
115 tls_set_error(ctx, "failed to load certificate");
116 goto err;
117 }
118 cert = NULL;
119 }
120 if (ctx->config->key_mem != NULL) {
121 if ((bio = BIO_new_mem_buf(ctx->config->key_mem,
122 ctx->config->key_len)) == NULL) {
123 tls_set_error(ctx, "failed to create buffer");
124 goto err;
125 }
126 if ((pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL,
127 NULL)) == NULL) {
128 tls_set_error(ctx, "failed to read private key");
129 goto err;
130 }
131 if (SSL_CTX_use_PrivateKey(ctx->ssl_ctx, pkey) != 1) {
132 tls_set_error(ctx, "failed to load private key");
133 goto err;
134 }
135 BIO_free(bio);
136 bio = NULL;
137 EVP_PKEY_free(pkey);
138 pkey = NULL;
139 }
140
141 if (ctx->config->cert_file != NULL) {
142 if (SSL_CTX_use_certificate_chain_file(ctx->ssl_ctx,
143 ctx->config->cert_file) != 1) {
144 tls_set_error(ctx, "failed to load certificate file");
145 goto err;
146 }
147 }
148 if (ctx->config->key_file != NULL) {
149 if (SSL_CTX_use_PrivateKey_file(ctx->ssl_ctx,
150 ctx->config->key_file, SSL_FILETYPE_PEM) != 1) {
151 tls_set_error(ctx, "failed to load private key file");
152 goto err;
153 }
154 }
155
156 if (SSL_CTX_check_private_key(ctx->ssl_ctx) != 1) {
157 tls_set_error(ctx, "private/public key mismatch");
158 goto err;
159 }
160
161 return (0);
162
163err:
164 EVP_PKEY_free(pkey);
165 X509_free(cert);
166 BIO_free(bio);
167
168 return (1);
169}
170
171int
172tls_configure_ssl(struct tls *ctx)
173{
174 SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_SSLv2);
175 SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_SSLv3);
176
177 SSL_CTX_clear_options(ctx->ssl_ctx, SSL_OP_NO_TLSv1);
178 SSL_CTX_clear_options(ctx->ssl_ctx, SSL_OP_NO_TLSv1_1);
179 SSL_CTX_clear_options(ctx->ssl_ctx, SSL_OP_NO_TLSv1_2);
180
181 if ((ctx->config->protocols & TLS_PROTOCOL_TLSv1_0) == 0)
182 SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_TLSv1);
183 if ((ctx->config->protocols & TLS_PROTOCOL_TLSv1_1) == 0)
184 SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_TLSv1_1);
185 if ((ctx->config->protocols & TLS_PROTOCOL_TLSv1_2) == 0)
186 SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_TLSv1_2);
187
188 if (ctx->config->ciphers != NULL) {
189 if (SSL_CTX_set_cipher_list(ctx->ssl_ctx,
190 ctx->config->ciphers) != 1) {
191 tls_set_error(ctx, "failed to set ciphers");
192 goto err;
193 }
194 }
195
196 return (0);
197
198err:
199 return (-1);
200}
201
202void
203tls_free(struct tls *ctx)
204{
205 if (ctx == NULL)
206 return;
207 tls_reset(ctx);
208 free(ctx);
209}
210
211void
212tls_reset(struct tls *ctx)
213{
214 SSL_CTX_free(ctx->ssl_ctx);
215 SSL_free(ctx->ssl_conn);
216
217 ctx->ssl_conn = NULL;
218 ctx->ssl_ctx = NULL;
219
220 ctx->socket = -1;
221
222 ctx->err = 0;
223 free(ctx->errmsg);
224 ctx->errmsg = NULL;
225}
226
227int
228tls_read(struct tls *ctx, void *buf, size_t buflen, size_t *outlen)
229{
230 int ret, ssl_err;
231
232 ret = SSL_read(ctx->ssl_conn, buf, buflen);
233 if (ret > 0) {
234 *outlen = (size_t)ret;
235 return (0);
236 }
237
238 ssl_err = SSL_get_error(ctx->ssl_conn, ret);
239 switch (ssl_err) {
240 case SSL_ERROR_WANT_READ:
241 return (TLS_READ_AGAIN);
242 case SSL_ERROR_WANT_WRITE:
243 return (TLS_WRITE_AGAIN);
244 default:
245 tls_set_error(ctx, "read failed (%i)", ssl_err);
246 return (-1);
247 }
248}
249
250int
251tls_write(struct tls *ctx, const void *buf, size_t buflen, size_t *outlen)
252{
253 int ret, ssl_err;
254
255 ret = SSL_write(ctx->ssl_conn, buf, buflen);
256 if (ret > 0) {
257 *outlen = (size_t)ret;
258 return (0);
259 }
260
261 ssl_err = SSL_get_error(ctx->ssl_conn, ret);
262 switch (ssl_err) {
263 case SSL_ERROR_WANT_READ:
264 return (TLS_READ_AGAIN);
265 case SSL_ERROR_WANT_WRITE:
266 return (TLS_WRITE_AGAIN);
267 default:
268 tls_set_error(ctx, "write failed (%i)", ssl_err);
269 return (-1);
270 }
271}
272
273int
274tls_close(struct tls *ctx)
275{
276 /* XXX - handle case where multiple calls are required. */
277 if (ctx->ssl_conn != NULL) {
278 if (SSL_shutdown(ctx->ssl_conn) == -1) {
279 tls_set_error(ctx, "SSL shutdown failed");
280 goto err;
281 }
282 }
283
284 if (ctx->socket != -1) {
285 if (shutdown(ctx->socket, SHUT_RDWR) != 0) {
286 tls_set_error(ctx, "shutdown");
287 goto err;
288 }
289 if (close(ctx->socket) != 0) {
290 tls_set_error(ctx, "close");
291 goto err;
292 }
293 ctx->socket = -1;
294 }
295
296 return (0);
297
298err:
299 return (-1);
300}
diff --git a/src/lib/libtls/tls.h b/src/lib/libtls/tls.h
new file mode 100644
index 0000000000..0fa776e584
--- /dev/null
+++ b/src/lib/libtls/tls.h
@@ -0,0 +1,74 @@
1/* $OpenBSD: tls.h,v 1.1 2014/10/31 13:46:17 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#ifndef HEADER_TLS_H
19#define HEADER_TLS_H
20
21#define TLS_API 20141031
22
23#define TLS_PROTOCOL_TLSv1_0 (1 << 1)
24#define TLS_PROTOCOL_TLSv1_1 (1 << 2)
25#define TLS_PROTOCOL_TLSv1_2 (1 << 3)
26#define TLS_PROTOCOL_TLSv1 \
27 (TLS_PROTOCOL_TLSv1_0|TLS_PROTOCOL_TLSv1_1|TLS_PROTOCOL_TLSv1_2)
28#define TLS_PROTOCOLS_DEFAULT TLS_PROTOCOL_TLSv1
29
30#define TLS_READ_AGAIN -2
31#define TLS_WRITE_AGAIN -3
32
33struct tls;
34struct tls_config;
35
36int tls_init(void);
37
38const char *tls_error(struct tls *ctx);
39
40struct tls_config *tls_config_new(void);
41void tls_config_free(struct tls_config *config);
42
43int tls_config_set_ca_file(struct tls_config *config, const char *ca_file);
44int tls_config_set_ca_path(struct tls_config *config, const char *ca_path);
45int tls_config_set_cert_file(struct tls_config *config, const char *cert_file);
46int tls_config_set_cert_mem(struct tls_config *config, const uint8_t *cert,
47 size_t len);
48int tls_config_set_ciphers(struct tls_config *config, const char *ciphers);
49int tls_config_set_ecdhcurve(struct tls_config *config, const char *name);
50int tls_config_set_key_file(struct tls_config *config, const char *key_file);
51int tls_config_set_key_mem(struct tls_config *config, const uint8_t *key,
52 size_t len);
53void tls_config_set_protocols(struct tls_config *config, uint32_t protocols);
54void tls_config_set_verify_depth(struct tls_config *config, int verify_depth);
55
56void tls_config_clear_keys(struct tls_config *config);
57void tls_config_insecure_noverifyhost(struct tls_config *config);
58void tls_config_insecure_noverifycert(struct tls_config *config);
59void tls_config_verify(struct tls_config *config);
60
61struct tls *tls_client(void);
62struct tls *tls_server(void);
63int tls_configure(struct tls *ctx, struct tls_config *config);
64void tls_reset(struct tls *ctx);
65void tls_free(struct tls *ctx);
66
67int tls_accept_socket(struct tls *ctx, struct tls **cctx, int socket);
68int tls_connect(struct tls *ctx, const char *host, const char *port);
69int tls_connect_socket(struct tls *ctx, int s, const char *hostname);
70int tls_read(struct tls *ctx, void *buf, size_t buflen, size_t *outlen);
71int tls_write(struct tls *ctx, const void *buf, size_t buflen, size_t *outlen);
72int tls_close(struct tls *ctx);
73
74#endif /* HEADER_TLS_H */
diff --git a/src/lib/libtls/tls_client.c b/src/lib/libtls/tls_client.c
new file mode 100644
index 0000000000..853766f87b
--- /dev/null
+++ b/src/lib/libtls/tls_client.c
@@ -0,0 +1,212 @@
1/* $OpenBSD: tls_client.c,v 1.1 2014/10/31 13:46:17 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
23#include <netdb.h>
24#include <stdlib.h>
25#include <unistd.h>
26
27#include <openssl/x509.h>
28
29#include <tls.h>
30#include "tls_internal.h"
31
32struct tls *
33tls_client(void)
34{
35 struct tls *ctx;
36
37 if ((ctx = tls_new()) == NULL)
38 return (NULL);
39
40 ctx->flags |= TLS_CLIENT;
41
42 return (ctx);
43}
44
45int
46tls_connect(struct tls *ctx, const char *host, const char *port)
47{
48 struct addrinfo hints, *res, *res0;
49 const char *h = NULL, *p = NULL;
50 char *hs = NULL, *ps = NULL;
51 int rv = -1, s = -1, ret;
52
53 if ((ctx->flags & TLS_CLIENT) == 0) {
54 tls_set_error(ctx, "not a client context");
55 goto err;
56 }
57
58 if (host == NULL) {
59 tls_set_error(ctx, "host not specified");
60 goto err;
61 }
62
63 /*
64 * If port is NULL try to extract a port from the specified host,
65 * otherwise use the default.
66 */
67 if ((p = (char *)port) == NULL) {
68 ret = tls_host_port(host, &hs, &ps);
69 if (ret == -1) {
70 tls_set_error(ctx, "memory allocation failure");
71 goto err;
72 }
73 if (ret != 0)
74 port = HTTPS_PORT;
75 }
76
77 h = (hs != NULL) ? hs : host;
78 p = (ps != NULL) ? ps : port;
79
80 memset(&hints, 0, sizeof(hints));
81 hints.ai_family = AF_UNSPEC;
82 hints.ai_socktype = SOCK_STREAM;
83
84 if ((ret = getaddrinfo(h, p, &hints, &res0)) != 0) {
85 tls_set_error(ctx, "%s", gai_strerror(ret));
86 goto err;
87 }
88 for (res = res0; res; res = res->ai_next) {
89 s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
90 if (s == -1) {
91 tls_set_error(ctx, "socket");
92 continue;
93 }
94 if (connect(s, res->ai_addr, res->ai_addrlen) == -1) {
95 tls_set_error(ctx, "connect");
96 close(s);
97 s = -1;
98 continue;
99 }
100
101 break; /* Connected. */
102 }
103 freeaddrinfo(res0);
104
105 if (s == -1)
106 goto err;
107
108 if (tls_connect_socket(ctx, s, h) != 0) {
109 close(s);
110 goto err;
111 }
112
113 rv = 0;
114
115err:
116
117 free(hs);
118 free(ps);
119
120 return (rv);
121}
122
123int
124tls_connect_socket(struct tls *ctx, int socket, const char *hostname)
125{
126 union { struct in_addr ip4; struct in6_addr ip6; } addrbuf;
127 X509 *cert = NULL;
128 int ret;
129
130 if ((ctx->flags & TLS_CLIENT) == 0) {
131 tls_set_error(ctx, "not a client context");
132 goto err;
133 }
134
135 ctx->socket = socket;
136
137 if ((ctx->ssl_ctx = SSL_CTX_new(SSLv23_client_method())) == NULL) {
138 tls_set_error(ctx, "ssl context failure");
139 goto err;
140 }
141
142 if (tls_configure_ssl(ctx) != 0)
143 goto err;
144
145 if (ctx->config->verify_host) {
146 if (hostname == NULL) {
147 tls_set_error(ctx, "server name not specified");
148 goto err;
149 }
150 }
151
152 if (ctx->config->verify_cert) {
153 SSL_CTX_set_verify(ctx->ssl_ctx, SSL_VERIFY_PEER, NULL);
154
155 if (SSL_CTX_load_verify_locations(ctx->ssl_ctx,
156 ctx->config->ca_file, ctx->config->ca_path) != 1) {
157 tls_set_error(ctx, "ssl verify setup failure");
158 goto err;
159 }
160 if (ctx->config->verify_depth >= 0)
161 SSL_CTX_set_verify_depth(ctx->ssl_ctx,
162 ctx->config->verify_depth);
163 }
164
165 if ((ctx->ssl_conn = SSL_new(ctx->ssl_ctx)) == NULL) {
166 tls_set_error(ctx, "ssl connection failure");
167 goto err;
168 }
169 if (SSL_set_fd(ctx->ssl_conn, ctx->socket) != 1) {
170 tls_set_error(ctx, "ssl file descriptor failure");
171 goto err;
172 }
173
174 /*
175 * RFC4366 (SNI): Literal IPv4 and IPv6 addresses are not
176 * permitted in "HostName".
177 */
178 if (hostname != NULL &&
179 inet_pton(AF_INET, hostname, &addrbuf) != 1 &&
180 inet_pton(AF_INET6, hostname, &addrbuf) != 1) {
181 if (SSL_set_tlsext_host_name(ctx->ssl_conn, hostname) == 0) {
182 tls_set_error(ctx, "SNI host name failed");
183 goto err;
184 }
185 }
186
187 if ((ret = SSL_connect(ctx->ssl_conn)) != 1) {
188 tls_set_error(ctx, "SSL connect failed: %i",
189 SSL_get_error(ctx->ssl_conn, ret));
190 goto err;
191 }
192
193 if (ctx->config->verify_host) {
194 cert = SSL_get_peer_certificate(ctx->ssl_conn);
195 if (cert == NULL) {
196 tls_set_error(ctx, "no server certificate");
197 goto err;
198 }
199 if (tls_check_hostname(cert, hostname) != 0) {
200 tls_set_error(ctx, "host `%s' not present in"
201 " server certificate", hostname);
202 goto err;
203 }
204 }
205
206 return (0);
207
208err:
209 X509_free(cert);
210
211 return (-1);
212}
diff --git a/src/lib/libtls/tls_config.c b/src/lib/libtls/tls_config.c
new file mode 100644
index 0000000000..0e435f616a
--- /dev/null
+++ b/src/lib/libtls/tls_config.c
@@ -0,0 +1,201 @@
1/* $OpenBSD: tls_config.c,v 1.1 2014/10/31 13:46:17 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 <errno.h>
19#include <stdlib.h>
20
21#include <tls.h>
22#include "tls_internal.h"
23
24static int
25set_string(const char **dest, const char *src)
26{
27 free((char *)*dest);
28 *dest = NULL;
29 if (src != NULL)
30 if ((*dest = strdup(src)) == NULL)
31 return -1;
32 return 0;
33}
34
35static void *
36memdup(const void *in, size_t len)
37{
38 void *out;
39
40 if ((out = malloc(len)) == NULL)
41 return NULL;
42 memcpy(out, in, len);
43 return out;
44}
45
46static int
47set_mem(char **dest, size_t *destlen, const void *src, size_t srclen)
48{
49 free(*dest);
50 *dest = NULL;
51 *destlen = 0;
52 if (src != NULL)
53 if ((*dest = memdup(src, srclen)) == NULL)
54 return -1;
55 *destlen = srclen;
56 return 0;
57}
58
59struct tls_config *
60tls_config_new(void)
61{
62 struct tls_config *config;
63
64 if ((config = calloc(1, sizeof(*config))) == NULL)
65 return (NULL);
66
67 /*
68 * Default configuration.
69 */
70 if (tls_config_set_ca_file(config, _PATH_SSL_CA_FILE) != 0) {
71 tls_config_free(config);
72 return (NULL);
73 }
74 tls_config_set_ecdhcurve(config, "auto");
75 tls_config_set_protocols(config, TLS_PROTOCOLS_DEFAULT);
76 tls_config_set_verify_depth(config, 6);
77
78 tls_config_verify(config);
79
80 return (config);
81}
82
83void
84tls_config_free(struct tls_config *config)
85{
86 if (config == NULL)
87 return;
88
89 tls_config_clear_keys(config);
90
91 free((char *)config->ca_file);
92 free((char *)config->ca_path);
93 free((char *)config->cert_file);
94 free(config->cert_mem);
95 free((char *)config->ciphers);
96 free((char *)config->key_file);
97 free(config->key_mem);
98
99 free(config);
100}
101
102void
103tls_config_clear_keys(struct tls_config *config)
104{
105 tls_config_set_cert_mem(config, NULL, 0);
106 tls_config_set_key_mem(config, NULL, 0);
107}
108
109int
110tls_config_set_ca_file(struct tls_config *config, const char *ca_file)
111{
112 return set_string(&config->ca_file, ca_file);
113}
114
115int
116tls_config_set_ca_path(struct tls_config *config, const char *ca_path)
117{
118 return set_string(&config->ca_path, ca_path);
119}
120
121int
122tls_config_set_cert_file(struct tls_config *config, const char *cert_file)
123{
124 return set_string(&config->cert_file, cert_file);
125}
126
127int
128tls_config_set_cert_mem(struct tls_config *config, const uint8_t *cert,
129 size_t len)
130{
131 return set_mem(&config->cert_mem, &config->cert_len, cert, len);
132}
133
134int
135tls_config_set_ciphers(struct tls_config *config, const char *ciphers)
136{
137 return set_string(&config->ciphers, ciphers);
138}
139
140int
141tls_config_set_ecdhcurve(struct tls_config *config, const char *name)
142{
143 int nid;
144
145 if (name == NULL)
146 nid = NID_undef;
147 else if (strcasecmp(name, "auto") == 0)
148 nid = -1;
149 else if ((nid = OBJ_txt2nid(name)) == NID_undef)
150 return (-1);
151
152 config->ecdhcurve = nid;
153
154 return (0);
155}
156
157int
158tls_config_set_key_file(struct tls_config *config, const char *key_file)
159{
160 return set_string(&config->key_file, key_file);
161}
162
163int
164tls_config_set_key_mem(struct tls_config *config, const uint8_t *key,
165 size_t len)
166{
167 if (config->key_mem)
168 explicit_bzero(config->key_mem, config->key_len);
169 return set_mem(&config->key_mem, &config->key_len, key, len);
170}
171
172void
173tls_config_set_protocols(struct tls_config *config, uint32_t protocols)
174{
175 config->protocols = protocols;
176}
177
178void
179tls_config_set_verify_depth(struct tls_config *config, int verify_depth)
180{
181 config->verify_depth = verify_depth;
182}
183
184void
185tls_config_insecure_noverifyhost(struct tls_config *config)
186{
187 config->verify_host = 0;
188}
189
190void
191tls_config_insecure_noverifycert(struct tls_config *config)
192{
193 config->verify_cert = 0;
194}
195
196void
197tls_config_verify(struct tls_config *config)
198{
199 config->verify_host = 1;
200 config->verify_cert = 1;
201}
diff --git a/src/lib/libtls/tls_init.3 b/src/lib/libtls/tls_init.3
new file mode 100644
index 0000000000..faa9b99539
--- /dev/null
+++ b/src/lib/libtls/tls_init.3
@@ -0,0 +1,316 @@
1.\" $OpenBSD: tls_init.3,v 1.1 2014/10/31 13:46:17 jsing Exp $
2.\"
3.\" Copyright (c) 2014 Ted Unangst <tedu@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.Dd $Mdocdate: October 31 2014 $
18.Dt TLS 3
19.Os
20.Sh NAME
21.Nm tls_init ,
22.Nm tls_error ,
23.Nm tls_config_new ,
24.Nm tls_config_free ,
25.Nm tls_config_set_ca_file ,
26.Nm tls_config_set_ca_path ,
27.Nm tls_config_set_cert_file ,
28.Nm tls_config_set_cert_mem ,
29.Nm tls_config_set_ciphers ,
30.Nm tls_config_set_ecdhcurve ,
31.Nm tls_config_set_key_file ,
32.Nm tls_config_set_key_mem ,
33.Nm tls_config_set_protocols ,
34.Nm tls_config_set_verify_depth ,
35.Nm tls_config_clear_keys ,
36.Nm tls_config_insecure_noverifyhost ,
37.Nm tls_config_insecure_noverifycert ,
38.Nm tls_config_verify ,
39.Nm tls_client ,
40.Nm tls_server ,
41.Nm tls_configure ,
42.Nm tls_reset ,
43.Nm tls_close ,
44.Nm tls_free ,
45.Nm tls_connect ,
46.Nm tls_connect_socket ,
47.Nm tls_read ,
48.Nm tls_write ,
49.Nd tls TLS client and server API
50.Sh SYNOPSIS
51.In tls.h
52.Ft "int"
53.Fn tls_init "void"
54.Ft "const char *"
55.Fn tls_error "struct tls *ctx"
56.Ft "struct tls_config *"
57.Fn tls_config_new "void"
58.Ft "void"
59.Fn tls_config_free "struct tls_config *config"
60.Ft "int"
61.Fn tls_config_set_ca_file "struct tls_config *config" "const char *ca_file"
62.Ft "int"
63.Fn tls_config_set_ca_path "struct tls_config *config" "const char *ca_path"
64.Ft "int"
65.Fn tls_config_set_cert_file "struct tls_config *config" "const char *cert_file"
66.Ft "int"
67.Fn tls_config_set_cert_mem "struct tls_config *config" "const uint8_t *cert" "size_t len"
68.Ft "int"
69.Fn tls_config_set_ciphers "struct tls_config *config" "const char *ciphers"
70.Ft "int"
71.Fn tls_config_set_ecdhcurve "struct tls_config *config" "const char *name"
72.Ft "int"
73.Fn tls_config_set_key_file "struct tls_config *config" "const char *key_file"
74.Ft "int"
75.Fn tls_config_set_key_mem "struct tls_config *config" "const uint8_t *key" "size_t len"
76.Ft "int"
77.Fn tls_config_set_protocols "struct tls_config *config" "uint32_t protocols"
78.Ft "int"
79.Fn tls_config_set_verify_depth "struct tls_config *config" "int verify_depth"
80.Ft "void"
81.Fn tls_config_clear_keys "struct tls_config *config"
82.Ft "void"
83.Fn tls_config_insecure_noverifyhost "struct tls_config *config"
84.Ft "void"
85.Fn tls_config_insecure_noverifycert "struct tls_config *config"
86.Ft "void"
87.Fn tls_config_verify "struct tls_config *config"
88.Ft "struct tls *"
89.Fn tls_client void
90.Ft "struct tls *"
91.Fn tls_server void
92.Ft "int"
93.Fn tls_configure "struct tls *ctx" "struct tls_config *config"
94.Ft "void"
95.Fn tls_reset "struct tls *ctx"
96.Ft "int"
97.Fn tls_close "struct tls *ctx"
98.Ft "void"
99.Fn tls_free "struct tls *ctx"
100.Ft "int"
101.Fn tls_connect "struct tls *ctx" "const char *host" "const char *port"
102.Ft "int"
103.Fn tls_connect_socket "struct tls *ctx" "int s" "const char *hostname"
104.Ft "int"
105.Fn tls_read "struct tls *ctx" "void *buf" "size_t buflen" "size_t *outlen"
106.Ft "int"
107.Fn tls_write "struct tls *ctx" "const void *buf" "size_t buflen"
108.Sh DESCRIPTION
109The
110.Nm tls
111family of functions establishes a secure communications channel
112using the TLS socket protocol.
113Both clients and servers are supported.
114.Pp
115The
116.Fn tls_init
117function should be called once before any function is used.
118.Pp
119Before a connection is created, a configuration must be created.
120The
121.Fn tls_config_new
122function returns a new default configuration that can be used for future
123connections.
124Several functions exist to change the options of the configuration; see below.
125.Pp
126A
127.Em tls
128connection is represented as a
129.Em context .
130A new
131.Em context
132is created by either the
133.Fn tls_client
134or
135.Fn tls_server
136functions.
137The context can then be configured with the function
138.Fn tls_configure .
139The same
140.Em tls_config
141object can be used to configure multiple contexts.
142.Pp
143A client connection is initiated after configuration by calling
144.Fn tls_connect .
145This function will create a new socket, connect to the specified host and
146port, and then establish a secure connection.
147An already existing socket can be upgraded to a secure connection by calling
148.Fn tls_connect_socket .
149.Pp
150Two functions are provided for input and output,
151.Fn tls_read
152and
153.Fn tls_write .
154.Pp
155After use, a tls
156.Em context
157should be closed with
158.Fn tls_close ,
159and then freed by calling
160.Fn tls_free .
161When no more contexts are to be created, the
162.Em tls_config
163object should be freed by calling
164.Fn tls_config_free .
165.Sh FUNCTIONS
166The
167.Fn tls_init
168function initializes global data structures.
169It should be called once before any other functions.
170.Pp
171The following functions create and free configuration objects.
172.Bl -bullet -offset four
173.It
174.Fn tls_config_new
175allocates a new default configuration object.
176.It
177.Fn tls_config_free
178frees a configuration object.
179.El
180.Pp
181The following functions modify a configuration by setting parameters.
182Configuration options may apply to only clients or only servers or both.
183.Bl -bullet -offset four
184.It
185.Fn tls_config_set_ca_file
186sets the filename used to load a file
187containing the root certificates.
188.Em (Client)
189.It
190.Fn tls_config_set_ca_path
191sets the path (directory) which should be searched for root
192certificates.
193.Em (Client)
194.It
195.Fn tls_config_set_cert_file
196sets file from which the public certificate will be read.
197.Em (Client and server)
198.It
199.Fn tls_config_set_cert_mem
200sets the public certificate directly from memory.
201.Em (Client and server)
202.It
203.Fn tls_config_set_ciphers
204sets the list of ciphers that may be used.
205.Em (Client and server)
206.It
207.Fn tls_config_set_key_file
208sets the file from which the private key will be read.
209.Em (Server)
210.It
211.Fn tls_config_set_key_mem
212directly sets the private key from memory.
213.Em (Server)
214.It
215.Fn tls_config_set_protocols
216sets which versions of the protocol may be used.
217Possible values are the bitwise OR of:
218.Pp
219.Bl -tag -width "TLS_PROTOCOL_TLSv1_2" -offset indent -compact
220.It Dv TLS_PROTOCOL_TLSv1_0
221.It Dv TLS_PROTOCOL_TLSv1_1
222.It Dv TLS_PROTOCOL_TLSv1_2
223.El
224.Pp
225Additionally, the values
226.Dv TLS_PROTOCOL_TLSv1
227(all TLS versions) and
228.Dv TLS_PROTOCOLS_DEFAULT
229(currently all TLS versions) may be used.
230.Em (Client and server)
231.It
232.Fn tls_config_clear_keys
233clears any secret keys from memory.
234.Em (Server)
235.It
236.Fn tls_config_insecure_noverifyhost
237disables hostname verification.
238Be careful when using this option.
239.Em (Client)
240.It
241.Fn tls_config_insecure_noverifycert
242disables certificate verification.
243Be extremely careful when using this option.
244.Em (Client)
245.It
246.Fn tls_config_verify
247reenables hostname and certificate verification.
248.Em (Client)
249.El
250.Pp
251The following functions create, prepare, and free a connection context.
252.Bl -bullet -offset four
253.It
254.Fn tls_client
255creates a new tls context for client connections.
256.It
257.Fn tls_server
258creates a new tls context for server connections.
259.It
260.Fn tls_configure
261readies a tls context for use by applying the configuration
262options.
263.It
264.Fn tls_close
265closes a connection after use.
266.It
267.Fn tls_free
268frees a tls context after use.
269.El
270.Pp
271The following functions initiate a connection and perform input and output
272operations.
273.Bl -bullet -offset four
274.It
275.Fn tls_connect
276connects a client context to the server named by
277.Fa host .
278The
279.Fa port
280may be numeric or a service name.
281If it is NULL then a host of the format "hostname:port" is permitted.
282.It
283.Fn tls_connect_socket
284connects a client context to an already established socket connection.
285.It
286.Fn tls_read
287reads
288.Fa buflen
289bytes of data from the socket into
290.Fa buf .
291The amount of data read is returned in
292.Fa outlen .
293.It
294.Fn tls_write
295writes
296.Fa buflen
297bytes of data from
298.Fa buf
299to the socket.
300The amount of data written is returned in
301.Fa outlen .
302.El
303.Sh RETURN VALUES
304Functions that return
305.Vt int
306will return 0 on success and -1 on error.
307Functions that return a pointer will return NULL on error.
308.\" .Sh ERRORS
309.\" .Sh SEE ALSO
310.Sh HISTORY
311The
312.Nm tls
313API first appeared in
314.Ox 5.6
315as a response to the unnecessary challenges other APIs present in
316order to use them safely.
diff --git a/src/lib/libtls/tls_internal.h b/src/lib/libtls/tls_internal.h
new file mode 100644
index 0000000000..da696e228d
--- /dev/null
+++ b/src/lib/libtls/tls_internal.h
@@ -0,0 +1,72 @@
1/* $OpenBSD: tls_internal.h,v 1.1 2014/10/31 13:46:17 jsing Exp $ */
2/*
3 * Copyright (c) 2014 Jeremie Courreges-Anglas <jca@openbsd.org>
4 * Copyright (c) 2014 Joel Sing <jsing@openbsd.org>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19#ifndef HEADER_TLS_INTERNAL_H
20#define HEADER_TLS_INTERNAL_H
21
22#include <openssl/ssl.h>
23
24#define HTTPS_PORT "443"
25
26#define _PATH_SSL_CA_FILE "/etc/ssl/cert.pem"
27
28struct tls_config {
29 const char *ca_file;
30 const char *ca_path;
31 const char *cert_file;
32 char *cert_mem;
33 size_t cert_len;
34 const char *ciphers;
35 int ecdhcurve;
36 const char *key_file;
37 char *key_mem;
38 size_t key_len;
39 uint32_t protocols;
40 int verify_cert;
41 int verify_host;
42 int verify_depth;
43};
44
45#define TLS_CLIENT (1 << 0)
46#define TLS_SERVER (1 << 1)
47#define TLS_SERVER_CONN (1 << 2)
48
49struct tls {
50 struct tls_config *config;
51 uint64_t flags;
52
53 int err;
54 char *errmsg;
55
56 int socket;
57
58 SSL *ssl_conn;
59 SSL_CTX *ssl_ctx;
60};
61
62struct tls *tls_new(void);
63struct tls *tls_server_conn(struct tls *ctx);
64
65int tls_check_hostname(X509 *cert, const char *host);
66int tls_configure_keypair(struct tls *ctx);
67int tls_configure_server(struct tls *ctx);
68int tls_configure_ssl(struct tls *ctx);
69int tls_host_port(const char *hostport, char **host, char **port);
70int tls_set_error(struct tls *ctx, char *fmt, ...);
71
72#endif /* HEADER_TLS_INTERNAL_H */
diff --git a/src/lib/libtls/tls_server.c b/src/lib/libtls/tls_server.c
new file mode 100644
index 0000000000..001f19ded4
--- /dev/null
+++ b/src/lib/libtls/tls_server.c
@@ -0,0 +1,134 @@
1/* $OpenBSD: tls_server.c,v 1.1 2014/10/31 13:46:17 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 <openssl/ec.h>
19#include <openssl/ssl.h>
20
21#include <tls.h>
22#include "tls_internal.h"
23
24struct tls *
25tls_server(void)
26{
27 struct tls *ctx;
28
29 if ((ctx = tls_new()) == NULL)
30 return (NULL);
31
32 ctx->flags |= TLS_SERVER;
33
34 return (ctx);
35}
36
37struct tls *
38tls_server_conn(struct tls *ctx)
39{
40 struct tls *conn_ctx;
41
42 if ((conn_ctx = tls_new()) == NULL)
43 return (NULL);
44
45 conn_ctx->flags |= TLS_SERVER_CONN;
46
47 return (conn_ctx);
48}
49
50int
51tls_configure_server(struct tls *ctx)
52{
53 EC_KEY *ecdh_key;
54
55 if ((ctx->ssl_ctx = SSL_CTX_new(SSLv23_server_method())) == NULL) {
56 tls_set_error(ctx, "ssl context failure");
57 goto err;
58 }
59
60 if (tls_configure_ssl(ctx) != 0)
61 goto err;
62 if (tls_configure_keypair(ctx) != 0)
63 goto err;
64
65 if (ctx->config->ecdhcurve == -1) {
66 SSL_CTX_set_ecdh_auto(ctx->ssl_ctx, 1);
67 } else if (ctx->config->ecdhcurve != NID_undef) {
68 if ((ecdh_key = EC_KEY_new_by_curve_name(
69 ctx->config->ecdhcurve)) == NULL) {
70 tls_set_error(ctx, "failed to set ECDH curve");
71 goto err;
72 }
73 SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_SINGLE_ECDH_USE);
74 SSL_CTX_set_tmp_ecdh(ctx->ssl_ctx, ecdh_key);
75 EC_KEY_free(ecdh_key);
76 }
77
78 return (0);
79
80err:
81 return (-1);
82}
83
84int
85tls_accept_socket(struct tls *ctx, struct tls **cctx, int socket)
86{
87 struct tls *conn_ctx = *cctx;
88 int ret, ssl_err;
89
90 if ((ctx->flags & TLS_SERVER) == 0) {
91 tls_set_error(ctx, "not a server context");
92 goto err;
93 }
94
95 if (conn_ctx == NULL) {
96 if ((conn_ctx = tls_server_conn(ctx)) == NULL) {
97 tls_set_error(ctx, "connection context failure");
98 goto err;
99 }
100 *cctx = conn_ctx;
101
102 conn_ctx->socket = socket;
103
104 if ((conn_ctx->ssl_conn = SSL_new(ctx->ssl_ctx)) == NULL) {
105 tls_set_error(ctx, "ssl failure");
106 goto err;
107 }
108
109 if (SSL_set_fd(conn_ctx->ssl_conn, socket) != 1) {
110 tls_set_error(ctx, "ssl set fd failure");
111 goto err;
112 }
113 SSL_set_app_data(conn_ctx->ssl_conn, conn_ctx);
114 }
115
116 if ((ret = SSL_accept(conn_ctx->ssl_conn)) != 1) {
117 ssl_err = SSL_get_error(conn_ctx->ssl_conn, ret);
118 switch (ssl_err) {
119 case SSL_ERROR_WANT_READ:
120 return (TLS_READ_AGAIN);
121 case SSL_ERROR_WANT_WRITE:
122 return (TLS_WRITE_AGAIN);
123 default:
124 tls_set_error(ctx, "ssl accept failure (%i)",
125 ssl_err);
126 goto err;
127 }
128 }
129
130 return (0);
131
132err:
133 return (-1);
134}
diff --git a/src/lib/libtls/tls_util.c b/src/lib/libtls/tls_util.c
new file mode 100644
index 0000000000..2adfb674b8
--- /dev/null
+++ b/src/lib/libtls/tls_util.c
@@ -0,0 +1,81 @@
1/* $OpenBSD: tls_util.c,v 1.1 2014/10/31 13:46:17 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 <stdlib.h>
19
20#include "tls_internal.h"
21
22/*
23 * Extract the host and port from a colon separated value. For a literal IPv6
24 * address the address must be contained with square braces. If a host and
25 * port are successfully extracted, the function will return 0 and the
26 * caller is responsible for freeing the host and port. If no port is found
27 * then the function will return 1, with both host and port being NULL.
28 * On memory allocation failure -1 will be returned.
29 */
30int
31tls_host_port(const char *hostport, char **host, char **port)
32{
33 char *h, *p, *s;
34 int rv = 1;
35
36 *host = NULL;
37 *port = NULL;
38
39 if ((s = strdup(hostport)) == NULL)
40 goto fail;
41
42 h = p = s;
43
44 /* See if this is an IPv6 literal with square braces. */
45 if (p[0] == '[') {
46 h++;
47 if ((p = strchr(s, ']')) == NULL)
48 goto done;
49 *p++ = '\0';
50 }
51
52 /* Find the port seperator. */
53 if ((p = strchr(p, ':')) == NULL)
54 goto done;
55
56 /* If there is another separator then we have issues. */
57 if (strchr(p + 1, ':') != NULL)
58 goto done;
59
60 *p++ = '\0';
61
62 if (asprintf(host, "%s", h) == -1)
63 goto fail;
64 if (asprintf(port, "%s", p) == -1)
65 goto fail;
66
67 rv = 0;
68 goto done;
69
70fail:
71 free(*host);
72 *host = NULL;
73 free(*port);
74 *port = NULL;
75 rv = -1;
76
77done:
78 free(s);
79
80 return (rv);
81}
diff --git a/src/lib/libtls/tls_verify.c b/src/lib/libtls/tls_verify.c
new file mode 100644
index 0000000000..fa0010922f
--- /dev/null
+++ b/src/lib/libtls/tls_verify.c
@@ -0,0 +1,225 @@
1/* $OpenBSD: tls_verify.c,v 1.1 2014/10/31 13:46:17 jsing Exp $ */
2/*
3 * Copyright (c) 2014 Jeremie Courreges-Anglas <jca@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/socket.h>
19
20#include <arpa/inet.h>
21#include <netinet/in.h>
22
23#include <string.h>
24
25#include <openssl/x509v3.h>
26
27#include "tls_internal.h"
28
29int tls_match_hostname(const char *cert_hostname, const char *hostname);
30int tls_check_subject_altname(X509 *cert, const char *host);
31int tls_check_common_name(X509 *cert, const char *host);
32
33int
34tls_match_hostname(const char *cert_hostname, const char *hostname)
35{
36 const char *cert_domain, *domain, *next_dot;
37
38 if (strcasecmp(cert_hostname, hostname) == 0)
39 return 0;
40
41 /* Wildcard match? */
42 if (cert_hostname[0] == '*') {
43 /*
44 * Valid wildcards:
45 * - "*.domain.tld"
46 * - "*.sub.domain.tld"
47 * - etc.
48 * Reject "*.tld".
49 * No attempt to prevent the use of eg. "*.co.uk".
50 */
51 cert_domain = &cert_hostname[1];
52 /* Disallow "*" */
53 if (cert_domain[0] == '\0')
54 return -1;
55 /* Disallow "*foo" */
56 if (cert_domain[0] != '.')
57 return -1;
58 /* Disallow "*.." */
59 if (cert_domain[1] == '.')
60 return -1;
61 next_dot = strchr(&cert_domain[1], '.');
62 /* Disallow "*.bar" */
63 if (next_dot == NULL)
64 return -1;
65 /* Disallow "*.bar.." */
66 if (next_dot[1] == '.')
67 return -1;
68
69 domain = strchr(hostname, '.');
70
71 /* No wildcard match against a hostname with no domain part. */
72 if (domain == NULL || strlen(domain) == 1)
73 return -1;
74
75 if (strcasecmp(cert_domain, domain) == 0)
76 return 0;
77 }
78
79 return -1;
80}
81
82int
83tls_check_subject_altname(X509 *cert, const char *host)
84{
85 STACK_OF(GENERAL_NAME) *altname_stack = NULL;
86 union { struct in_addr ip4; struct in6_addr ip6; } addrbuf;
87 int addrlen, type;
88 int count, i;
89 int rv = -1;
90
91 altname_stack = X509_get_ext_d2i(cert, NID_subject_alt_name,
92 NULL, NULL);
93 if (altname_stack == NULL)
94 return -1;
95
96 if (inet_pton(AF_INET, host, &addrbuf) == 1) {
97 type = GEN_IPADD;
98 addrlen = 4;
99 } else if (inet_pton(AF_INET6, host, &addrbuf) == 1) {
100 type = GEN_IPADD;
101 addrlen = 16;
102 } else {
103 type = GEN_DNS;
104 addrlen = 0;
105 }
106
107 count = sk_GENERAL_NAME_num(altname_stack);
108 for (i = 0; i < count; i++) {
109 GENERAL_NAME *altname;
110
111 altname = sk_GENERAL_NAME_value(altname_stack, i);
112
113 if (altname->type != type)
114 continue;
115
116 if (type == GEN_DNS) {
117 unsigned char *data;
118 int format;
119
120 format = ASN1_STRING_type(altname->d.dNSName);
121 if (format == V_ASN1_IA5STRING) {
122 data = ASN1_STRING_data(altname->d.dNSName);
123
124 if (ASN1_STRING_length(altname->d.dNSName) !=
125 (int)strlen(data)) {
126 fprintf(stdout, "%s: NUL byte in "
127 "subjectAltName, probably a "
128 "malicious certificate.\n",
129 getprogname());
130 rv = -2;
131 break;
132 }
133
134 if (tls_match_hostname(data, host) == 0) {
135 rv = 0;
136 break;
137 }
138 } else
139 fprintf(stdout, "%s: unhandled subjectAltName "
140 "dNSName encoding (%d)\n", getprogname(),
141 format);
142
143 } else if (type == GEN_IPADD) {
144 unsigned char *data;
145 int datalen;
146
147 datalen = ASN1_STRING_length(altname->d.iPAddress);
148 data = ASN1_STRING_data(altname->d.iPAddress);
149
150 if (datalen == addrlen &&
151 memcmp(data, &addrbuf, addrlen) == 0) {
152 rv = 0;
153 break;
154 }
155 }
156 }
157
158 sk_GENERAL_NAME_free(altname_stack);
159 return rv;
160}
161
162int
163tls_check_common_name(X509 *cert, const char *host)
164{
165 X509_NAME *name;
166 char *common_name = NULL;
167 int common_name_len;
168 int rv = -1;
169 union { struct in_addr ip4; struct in6_addr ip6; } addrbuf;
170
171 name = X509_get_subject_name(cert);
172 if (name == NULL)
173 goto out;
174
175 common_name_len = X509_NAME_get_text_by_NID(name, NID_commonName,
176 NULL, 0);
177 if (common_name_len < 0)
178 goto out;
179
180 common_name = calloc(common_name_len + 1, 1);
181 if (common_name == NULL)
182 goto out;
183
184 X509_NAME_get_text_by_NID(name, NID_commonName, common_name,
185 common_name_len + 1);
186
187 /* NUL bytes in CN? */
188 if (common_name_len != (int)strlen(common_name)) {
189 fprintf(stdout, "%s: NUL byte in Common Name field, "
190 "probably a malicious certificate.\n", getprogname());
191 rv = -2;
192 goto out;
193 }
194
195 if (inet_pton(AF_INET, host, &addrbuf) == 1 ||
196 inet_pton(AF_INET6, host, &addrbuf) == 1) {
197 /*
198 * We don't want to attempt wildcard matching against IP
199 * addresses, so perform a simple comparison here.
200 */
201 if (strcmp(common_name, host) == 0)
202 rv = 0;
203 else
204 rv = -1;
205 goto out;
206 }
207
208 if (tls_match_hostname(common_name, host) == 0)
209 rv = 0;
210out:
211 free(common_name);
212 return rv;
213}
214
215int
216tls_check_hostname(X509 *cert, const char *host)
217{
218 int rv;
219
220 rv = tls_check_subject_altname(cert, host);
221 if (rv == 0 || rv == -2)
222 return rv;
223
224 return tls_check_common_name(cert, host);
225}