diff options
Diffstat (limited to 'src/lib/libtls')
-rw-r--r-- | src/lib/libtls/Makefile | 58 | ||||
-rw-r--r-- | src/lib/libtls/shlib_version | 2 | ||||
-rw-r--r-- | src/lib/libtls/tls.c | 300 | ||||
-rw-r--r-- | src/lib/libtls/tls.h | 74 | ||||
-rw-r--r-- | src/lib/libtls/tls_client.c | 212 | ||||
-rw-r--r-- | src/lib/libtls/tls_config.c | 201 | ||||
-rw-r--r-- | src/lib/libtls/tls_init.3 | 316 | ||||
-rw-r--r-- | src/lib/libtls/tls_internal.h | 72 | ||||
-rw-r--r-- | src/lib/libtls/tls_server.c | 134 | ||||
-rw-r--r-- | src/lib/libtls/tls_util.c | 81 | ||||
-rw-r--r-- | src/lib/libtls/tls_verify.c | 225 |
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 | |||
3 | CFLAGS+= -Wall -Werror -Wimplicit | ||
4 | CFLAGS+= -DLIBRESSL_INTERNAL | ||
5 | |||
6 | LIB= tls | ||
7 | |||
8 | DPADD= ${LIBCRYPTO} ${LIBSSL} | ||
9 | |||
10 | HDRS= tls.h | ||
11 | |||
12 | SRCS= tls.c \ | ||
13 | tls_client.c \ | ||
14 | tls_config.c \ | ||
15 | tls_server.c \ | ||
16 | tls_util.c \ | ||
17 | tls_verify.c | ||
18 | |||
19 | MAN= tls_init.3 | ||
20 | |||
21 | MLINKS+=tls_init.3 tls_config_new.3 | ||
22 | MLINKS+=tls_init.3 tls_config_free.3 | ||
23 | MLINKS+=tls_init.3 tls_config_set_ca_file.3 | ||
24 | MLINKS+=tls_init.3 tls_config_set_ca_path.3 | ||
25 | MLINKS+=tls_init.3 tls_config_set_cert_file.3 | ||
26 | MLINKS+=tls_init.3 tls_config_set_cert_mem.3 | ||
27 | MLINKS+=tls_init.3 tls_config_set_ciphers.3 | ||
28 | MLINKS+=tls_init.3 tls_config_set_ecdhcurve.3 | ||
29 | MLINKS+=tls_init.3 tls_config_set_key_file.3 | ||
30 | MLINKS+=tls_init.3 tls_config_set_key_mem.3 | ||
31 | MLINKS+=tls_init.3 tls_config_set_protocols.3 | ||
32 | MLINKS+=tls_init.3 tls_config_set_verify_depth.3 | ||
33 | MLINKS+=tls_init.3 tls_config_clear_keys.3 | ||
34 | MLINKS+=tls_init.3 tls_config_insecure_noverifyhost.3 | ||
35 | MLINKS+=tls_init.3 tls_config_insecure_noverifycert.3 | ||
36 | MLINKS+=tls_init.3 tls_config_verify.3 | ||
37 | MLINKS+=tls_init.3 tls_client.3 | ||
38 | MLINKS+=tls_init.3 tls_server.3 | ||
39 | MLINKS+=tls_init.3 tls_configure.3 | ||
40 | MLINKS+=tls_init.3 tls_error.3 | ||
41 | MLINKS+=tls_init.3 tls_reset.3 | ||
42 | MLINKS+=tls_init.3 tls_free.3 | ||
43 | MLINKS+=tls_init.3 tls_close.3 | ||
44 | MLINKS+=tls_init.3 tls_connect.3 | ||
45 | MLINKS+=tls_init.3 tls_connect_socket.3 | ||
46 | MLINKS+=tls_init.3 tls_read.3 | ||
47 | MLINKS+=tls_init.3 tls_write.3 | ||
48 | |||
49 | includes: | ||
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 @@ | |||
1 | major=1 | ||
2 | minor=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 | |||
32 | static struct tls_config *tls_config_default; | ||
33 | |||
34 | int | ||
35 | tls_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 | |||
53 | const char * | ||
54 | tls_error(struct tls *ctx) | ||
55 | { | ||
56 | return ctx->errmsg; | ||
57 | } | ||
58 | |||
59 | int | ||
60 | tls_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 | |||
76 | struct tls * | ||
77 | tls_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 | |||
91 | int | ||
92 | tls_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 | |||
105 | int | ||
106 | tls_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 | |||
163 | err: | ||
164 | EVP_PKEY_free(pkey); | ||
165 | X509_free(cert); | ||
166 | BIO_free(bio); | ||
167 | |||
168 | return (1); | ||
169 | } | ||
170 | |||
171 | int | ||
172 | tls_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 | |||
198 | err: | ||
199 | return (-1); | ||
200 | } | ||
201 | |||
202 | void | ||
203 | tls_free(struct tls *ctx) | ||
204 | { | ||
205 | if (ctx == NULL) | ||
206 | return; | ||
207 | tls_reset(ctx); | ||
208 | free(ctx); | ||
209 | } | ||
210 | |||
211 | void | ||
212 | tls_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 | |||
227 | int | ||
228 | tls_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 | |||
250 | int | ||
251 | tls_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 | |||
273 | int | ||
274 | tls_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 | |||
298 | err: | ||
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 | |||
33 | struct tls; | ||
34 | struct tls_config; | ||
35 | |||
36 | int tls_init(void); | ||
37 | |||
38 | const char *tls_error(struct tls *ctx); | ||
39 | |||
40 | struct tls_config *tls_config_new(void); | ||
41 | void tls_config_free(struct tls_config *config); | ||
42 | |||
43 | int tls_config_set_ca_file(struct tls_config *config, const char *ca_file); | ||
44 | int tls_config_set_ca_path(struct tls_config *config, const char *ca_path); | ||
45 | int tls_config_set_cert_file(struct tls_config *config, const char *cert_file); | ||
46 | int tls_config_set_cert_mem(struct tls_config *config, const uint8_t *cert, | ||
47 | size_t len); | ||
48 | int tls_config_set_ciphers(struct tls_config *config, const char *ciphers); | ||
49 | int tls_config_set_ecdhcurve(struct tls_config *config, const char *name); | ||
50 | int tls_config_set_key_file(struct tls_config *config, const char *key_file); | ||
51 | int tls_config_set_key_mem(struct tls_config *config, const uint8_t *key, | ||
52 | size_t len); | ||
53 | void tls_config_set_protocols(struct tls_config *config, uint32_t protocols); | ||
54 | void tls_config_set_verify_depth(struct tls_config *config, int verify_depth); | ||
55 | |||
56 | void tls_config_clear_keys(struct tls_config *config); | ||
57 | void tls_config_insecure_noverifyhost(struct tls_config *config); | ||
58 | void tls_config_insecure_noverifycert(struct tls_config *config); | ||
59 | void tls_config_verify(struct tls_config *config); | ||
60 | |||
61 | struct tls *tls_client(void); | ||
62 | struct tls *tls_server(void); | ||
63 | int tls_configure(struct tls *ctx, struct tls_config *config); | ||
64 | void tls_reset(struct tls *ctx); | ||
65 | void tls_free(struct tls *ctx); | ||
66 | |||
67 | int tls_accept_socket(struct tls *ctx, struct tls **cctx, int socket); | ||
68 | int tls_connect(struct tls *ctx, const char *host, const char *port); | ||
69 | int tls_connect_socket(struct tls *ctx, int s, const char *hostname); | ||
70 | int tls_read(struct tls *ctx, void *buf, size_t buflen, size_t *outlen); | ||
71 | int tls_write(struct tls *ctx, const void *buf, size_t buflen, size_t *outlen); | ||
72 | int 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 | |||
32 | struct tls * | ||
33 | tls_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 | |||
45 | int | ||
46 | tls_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 | |||
115 | err: | ||
116 | |||
117 | free(hs); | ||
118 | free(ps); | ||
119 | |||
120 | return (rv); | ||
121 | } | ||
122 | |||
123 | int | ||
124 | tls_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 | |||
208 | err: | ||
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 | |||
24 | static int | ||
25 | set_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 | |||
35 | static void * | ||
36 | memdup(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 | |||
46 | static int | ||
47 | set_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 | |||
59 | struct tls_config * | ||
60 | tls_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 | |||
83 | void | ||
84 | tls_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 | |||
102 | void | ||
103 | tls_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 | |||
109 | int | ||
110 | tls_config_set_ca_file(struct tls_config *config, const char *ca_file) | ||
111 | { | ||
112 | return set_string(&config->ca_file, ca_file); | ||
113 | } | ||
114 | |||
115 | int | ||
116 | tls_config_set_ca_path(struct tls_config *config, const char *ca_path) | ||
117 | { | ||
118 | return set_string(&config->ca_path, ca_path); | ||
119 | } | ||
120 | |||
121 | int | ||
122 | tls_config_set_cert_file(struct tls_config *config, const char *cert_file) | ||
123 | { | ||
124 | return set_string(&config->cert_file, cert_file); | ||
125 | } | ||
126 | |||
127 | int | ||
128 | tls_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 | |||
134 | int | ||
135 | tls_config_set_ciphers(struct tls_config *config, const char *ciphers) | ||
136 | { | ||
137 | return set_string(&config->ciphers, ciphers); | ||
138 | } | ||
139 | |||
140 | int | ||
141 | tls_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 | |||
157 | int | ||
158 | tls_config_set_key_file(struct tls_config *config, const char *key_file) | ||
159 | { | ||
160 | return set_string(&config->key_file, key_file); | ||
161 | } | ||
162 | |||
163 | int | ||
164 | tls_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 | |||
172 | void | ||
173 | tls_config_set_protocols(struct tls_config *config, uint32_t protocols) | ||
174 | { | ||
175 | config->protocols = protocols; | ||
176 | } | ||
177 | |||
178 | void | ||
179 | tls_config_set_verify_depth(struct tls_config *config, int verify_depth) | ||
180 | { | ||
181 | config->verify_depth = verify_depth; | ||
182 | } | ||
183 | |||
184 | void | ||
185 | tls_config_insecure_noverifyhost(struct tls_config *config) | ||
186 | { | ||
187 | config->verify_host = 0; | ||
188 | } | ||
189 | |||
190 | void | ||
191 | tls_config_insecure_noverifycert(struct tls_config *config) | ||
192 | { | ||
193 | config->verify_cert = 0; | ||
194 | } | ||
195 | |||
196 | void | ||
197 | tls_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 | ||
109 | The | ||
110 | .Nm tls | ||
111 | family of functions establishes a secure communications channel | ||
112 | using the TLS socket protocol. | ||
113 | Both clients and servers are supported. | ||
114 | .Pp | ||
115 | The | ||
116 | .Fn tls_init | ||
117 | function should be called once before any function is used. | ||
118 | .Pp | ||
119 | Before a connection is created, a configuration must be created. | ||
120 | The | ||
121 | .Fn tls_config_new | ||
122 | function returns a new default configuration that can be used for future | ||
123 | connections. | ||
124 | Several functions exist to change the options of the configuration; see below. | ||
125 | .Pp | ||
126 | A | ||
127 | .Em tls | ||
128 | connection is represented as a | ||
129 | .Em context . | ||
130 | A new | ||
131 | .Em context | ||
132 | is created by either the | ||
133 | .Fn tls_client | ||
134 | or | ||
135 | .Fn tls_server | ||
136 | functions. | ||
137 | The context can then be configured with the function | ||
138 | .Fn tls_configure . | ||
139 | The same | ||
140 | .Em tls_config | ||
141 | object can be used to configure multiple contexts. | ||
142 | .Pp | ||
143 | A client connection is initiated after configuration by calling | ||
144 | .Fn tls_connect . | ||
145 | This function will create a new socket, connect to the specified host and | ||
146 | port, and then establish a secure connection. | ||
147 | An already existing socket can be upgraded to a secure connection by calling | ||
148 | .Fn tls_connect_socket . | ||
149 | .Pp | ||
150 | Two functions are provided for input and output, | ||
151 | .Fn tls_read | ||
152 | and | ||
153 | .Fn tls_write . | ||
154 | .Pp | ||
155 | After use, a tls | ||
156 | .Em context | ||
157 | should be closed with | ||
158 | .Fn tls_close , | ||
159 | and then freed by calling | ||
160 | .Fn tls_free . | ||
161 | When no more contexts are to be created, the | ||
162 | .Em tls_config | ||
163 | object should be freed by calling | ||
164 | .Fn tls_config_free . | ||
165 | .Sh FUNCTIONS | ||
166 | The | ||
167 | .Fn tls_init | ||
168 | function initializes global data structures. | ||
169 | It should be called once before any other functions. | ||
170 | .Pp | ||
171 | The following functions create and free configuration objects. | ||
172 | .Bl -bullet -offset four | ||
173 | .It | ||
174 | .Fn tls_config_new | ||
175 | allocates a new default configuration object. | ||
176 | .It | ||
177 | .Fn tls_config_free | ||
178 | frees a configuration object. | ||
179 | .El | ||
180 | .Pp | ||
181 | The following functions modify a configuration by setting parameters. | ||
182 | Configuration 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 | ||
186 | sets the filename used to load a file | ||
187 | containing the root certificates. | ||
188 | .Em (Client) | ||
189 | .It | ||
190 | .Fn tls_config_set_ca_path | ||
191 | sets the path (directory) which should be searched for root | ||
192 | certificates. | ||
193 | .Em (Client) | ||
194 | .It | ||
195 | .Fn tls_config_set_cert_file | ||
196 | sets file from which the public certificate will be read. | ||
197 | .Em (Client and server) | ||
198 | .It | ||
199 | .Fn tls_config_set_cert_mem | ||
200 | sets the public certificate directly from memory. | ||
201 | .Em (Client and server) | ||
202 | .It | ||
203 | .Fn tls_config_set_ciphers | ||
204 | sets the list of ciphers that may be used. | ||
205 | .Em (Client and server) | ||
206 | .It | ||
207 | .Fn tls_config_set_key_file | ||
208 | sets the file from which the private key will be read. | ||
209 | .Em (Server) | ||
210 | .It | ||
211 | .Fn tls_config_set_key_mem | ||
212 | directly sets the private key from memory. | ||
213 | .Em (Server) | ||
214 | .It | ||
215 | .Fn tls_config_set_protocols | ||
216 | sets which versions of the protocol may be used. | ||
217 | Possible 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 | ||
225 | Additionally, 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 | ||
233 | clears any secret keys from memory. | ||
234 | .Em (Server) | ||
235 | .It | ||
236 | .Fn tls_config_insecure_noverifyhost | ||
237 | disables hostname verification. | ||
238 | Be careful when using this option. | ||
239 | .Em (Client) | ||
240 | .It | ||
241 | .Fn tls_config_insecure_noverifycert | ||
242 | disables certificate verification. | ||
243 | Be extremely careful when using this option. | ||
244 | .Em (Client) | ||
245 | .It | ||
246 | .Fn tls_config_verify | ||
247 | reenables hostname and certificate verification. | ||
248 | .Em (Client) | ||
249 | .El | ||
250 | .Pp | ||
251 | The following functions create, prepare, and free a connection context. | ||
252 | .Bl -bullet -offset four | ||
253 | .It | ||
254 | .Fn tls_client | ||
255 | creates a new tls context for client connections. | ||
256 | .It | ||
257 | .Fn tls_server | ||
258 | creates a new tls context for server connections. | ||
259 | .It | ||
260 | .Fn tls_configure | ||
261 | readies a tls context for use by applying the configuration | ||
262 | options. | ||
263 | .It | ||
264 | .Fn tls_close | ||
265 | closes a connection after use. | ||
266 | .It | ||
267 | .Fn tls_free | ||
268 | frees a tls context after use. | ||
269 | .El | ||
270 | .Pp | ||
271 | The following functions initiate a connection and perform input and output | ||
272 | operations. | ||
273 | .Bl -bullet -offset four | ||
274 | .It | ||
275 | .Fn tls_connect | ||
276 | connects a client context to the server named by | ||
277 | .Fa host . | ||
278 | The | ||
279 | .Fa port | ||
280 | may be numeric or a service name. | ||
281 | If it is NULL then a host of the format "hostname:port" is permitted. | ||
282 | .It | ||
283 | .Fn tls_connect_socket | ||
284 | connects a client context to an already established socket connection. | ||
285 | .It | ||
286 | .Fn tls_read | ||
287 | reads | ||
288 | .Fa buflen | ||
289 | bytes of data from the socket into | ||
290 | .Fa buf . | ||
291 | The amount of data read is returned in | ||
292 | .Fa outlen . | ||
293 | .It | ||
294 | .Fn tls_write | ||
295 | writes | ||
296 | .Fa buflen | ||
297 | bytes of data from | ||
298 | .Fa buf | ||
299 | to the socket. | ||
300 | The amount of data written is returned in | ||
301 | .Fa outlen . | ||
302 | .El | ||
303 | .Sh RETURN VALUES | ||
304 | Functions that return | ||
305 | .Vt int | ||
306 | will return 0 on success and -1 on error. | ||
307 | Functions that return a pointer will return NULL on error. | ||
308 | .\" .Sh ERRORS | ||
309 | .\" .Sh SEE ALSO | ||
310 | .Sh HISTORY | ||
311 | The | ||
312 | .Nm tls | ||
313 | API first appeared in | ||
314 | .Ox 5.6 | ||
315 | as a response to the unnecessary challenges other APIs present in | ||
316 | order 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 | |||
28 | struct 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 | |||
49 | struct 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 | |||
62 | struct tls *tls_new(void); | ||
63 | struct tls *tls_server_conn(struct tls *ctx); | ||
64 | |||
65 | int tls_check_hostname(X509 *cert, const char *host); | ||
66 | int tls_configure_keypair(struct tls *ctx); | ||
67 | int tls_configure_server(struct tls *ctx); | ||
68 | int tls_configure_ssl(struct tls *ctx); | ||
69 | int tls_host_port(const char *hostport, char **host, char **port); | ||
70 | int 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 | |||
24 | struct tls * | ||
25 | tls_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 | |||
37 | struct tls * | ||
38 | tls_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 | |||
50 | int | ||
51 | tls_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 | |||
80 | err: | ||
81 | return (-1); | ||
82 | } | ||
83 | |||
84 | int | ||
85 | tls_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 | |||
132 | err: | ||
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 | */ | ||
30 | int | ||
31 | tls_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 | |||
70 | fail: | ||
71 | free(*host); | ||
72 | *host = NULL; | ||
73 | free(*port); | ||
74 | *port = NULL; | ||
75 | rv = -1; | ||
76 | |||
77 | done: | ||
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 | |||
29 | int tls_match_hostname(const char *cert_hostname, const char *hostname); | ||
30 | int tls_check_subject_altname(X509 *cert, const char *host); | ||
31 | int tls_check_common_name(X509 *cert, const char *host); | ||
32 | |||
33 | int | ||
34 | tls_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 | |||
82 | int | ||
83 | tls_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 | |||
162 | int | ||
163 | tls_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; | ||
210 | out: | ||
211 | free(common_name); | ||
212 | return rv; | ||
213 | } | ||
214 | |||
215 | int | ||
216 | tls_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 | } | ||