summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorjsing <>2018-02-10 04:41:24 +0000
committerjsing <>2018-02-10 04:41:24 +0000
commitad2580ae7b71760c38ec88f34f360d5f1e6b3f13 (patch)
treed414866dbbe43d007a4873fb2dc7e6cb637f7bce /src
parent87264e9d7a6c2a965876fcf5e4b3dc46470e2562 (diff)
downloadopenbsd-ad2580ae7b71760c38ec88f34f360d5f1e6b3f13.tar.gz
openbsd-ad2580ae7b71760c38ec88f34f360d5f1e6b3f13.tar.bz2
openbsd-ad2580ae7b71760c38ec88f34f360d5f1e6b3f13.zip
Add support to libtls for client-side TLS session resumption.
A libtls client can specify a session file descriptor (a regular file with appropriate ownership and permissions) and libtls will manage reading and writing of session data across TLS handshakes. Discussed at length with deraadt@ and tedu@. Rides previous minor bump. ok beck@
Diffstat (limited to 'src')
-rw-r--r--src/lib/libtls/Symbols.list2
-rw-r--r--src/lib/libtls/tls.h4
-rw-r--r--src/lib/libtls/tls_client.c128
-rw-r--r--src/lib/libtls/tls_config.c41
-rw-r--r--src/lib/libtls/tls_conninfo.c21
-rw-r--r--src/lib/libtls/tls_internal.h4
6 files changed, 195 insertions, 5 deletions
diff --git a/src/lib/libtls/Symbols.list b/src/lib/libtls/Symbols.list
index 1e7538cfd4..923924fc40 100644
--- a/src/lib/libtls/Symbols.list
+++ b/src/lib/libtls/Symbols.list
@@ -42,6 +42,7 @@ tls_config_set_ocsp_staple_file
42tls_config_set_protocols 42tls_config_set_protocols
43tls_config_set_session_id 43tls_config_set_session_id
44tls_config_set_session_lifetime 44tls_config_set_session_lifetime
45tls_config_set_session_fd
45tls_config_set_verify_depth 46tls_config_set_verify_depth
46tls_config_skip_private_key_check 47tls_config_skip_private_key_check
47tls_config_verify 48tls_config_verify
@@ -51,6 +52,7 @@ tls_configure
51tls_conn_alpn_selected 52tls_conn_alpn_selected
52tls_conn_cipher 53tls_conn_cipher
53tls_conn_servername 54tls_conn_servername
55tls_conn_session_resumed
54tls_conn_version 56tls_conn_version
55tls_connect 57tls_connect
56tls_connect_cbs 58tls_connect_cbs
diff --git a/src/lib/libtls/tls.h b/src/lib/libtls/tls.h
index cc8627f2af..8d66c2fbaa 100644
--- a/src/lib/libtls/tls.h
+++ b/src/lib/libtls/tls.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: tls.h,v 1.51 2017/08/10 18:18:30 jsing Exp $ */ 1/* $OpenBSD: tls.h,v 1.52 2018/02/10 04:41:24 jsing Exp $ */
2/* 2/*
3 * Copyright (c) 2014 Joel Sing <jsing@openbsd.org> 3 * Copyright (c) 2014 Joel Sing <jsing@openbsd.org>
4 * 4 *
@@ -128,6 +128,7 @@ int tls_config_set_ocsp_staple_mem(struct tls_config *_config,
128int tls_config_set_ocsp_staple_file(struct tls_config *_config, 128int tls_config_set_ocsp_staple_file(struct tls_config *_config,
129 const char *_staple_file); 129 const char *_staple_file);
130int tls_config_set_protocols(struct tls_config *_config, uint32_t _protocols); 130int tls_config_set_protocols(struct tls_config *_config, uint32_t _protocols);
131int tls_config_set_session_fd(struct tls_config *_config, int _session_fd);
131int tls_config_set_verify_depth(struct tls_config *_config, int _verify_depth); 132int tls_config_set_verify_depth(struct tls_config *_config, int _verify_depth);
132 133
133void tls_config_prefer_ciphers_client(struct tls_config *_config); 134void tls_config_prefer_ciphers_client(struct tls_config *_config);
@@ -188,6 +189,7 @@ const uint8_t *tls_peer_cert_chain_pem(struct tls *_ctx, size_t *_len);
188const char *tls_conn_alpn_selected(struct tls *_ctx); 189const char *tls_conn_alpn_selected(struct tls *_ctx);
189const char *tls_conn_cipher(struct tls *_ctx); 190const char *tls_conn_cipher(struct tls *_ctx);
190const char *tls_conn_servername(struct tls *_ctx); 191const char *tls_conn_servername(struct tls *_ctx);
192int tls_conn_session_resumed(struct tls *_ctx);
191const char *tls_conn_version(struct tls *_ctx); 193const char *tls_conn_version(struct tls *_ctx);
192 194
193uint8_t *tls_load_file(const char *_file, size_t *_len, char *_password); 195uint8_t *tls_load_file(const char *_file, size_t *_len, char *_password);
diff --git a/src/lib/libtls/tls_client.c b/src/lib/libtls/tls_client.c
index c79f462a3a..14c716fa17 100644
--- a/src/lib/libtls/tls_client.c
+++ b/src/lib/libtls/tls_client.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: tls_client.c,v 1.43 2017/08/10 18:18:30 jsing Exp $ */ 1/* $OpenBSD: tls_client.c,v 1.44 2018/02/10 04:41:24 jsing Exp $ */
2/* 2/*
3 * Copyright (c) 2014 Joel Sing <jsing@openbsd.org> 3 * Copyright (c) 2014 Joel Sing <jsing@openbsd.org>
4 * 4 *
@@ -17,10 +17,12 @@
17 17
18#include <sys/types.h> 18#include <sys/types.h>
19#include <sys/socket.h> 19#include <sys/socket.h>
20#include <sys/stat.h>
20 21
21#include <arpa/inet.h> 22#include <arpa/inet.h>
22#include <netinet/in.h> 23#include <netinet/in.h>
23 24
25#include <limits.h>
24#include <netdb.h> 26#include <netdb.h>
25#include <stdlib.h> 27#include <stdlib.h>
26#include <unistd.h> 28#include <unistd.h>
@@ -159,6 +161,118 @@ tls_connect_servername(struct tls *ctx, const char *host, const char *port,
159} 161}
160 162
161static int 163static int
164tls_client_read_session(struct tls *ctx)
165{
166 int sfd = ctx->config->session_fd;
167 uint8_t *session = NULL;
168 size_t session_len = 0;
169 SSL_SESSION *ss = NULL;
170 BIO *bio = NULL;
171 struct stat sb;
172 ssize_t n;
173 int rv = -1;
174
175 if (fstat(sfd, &sb) == -1) {
176 tls_set_error(ctx, "failed to stat session file");
177 goto err;
178 }
179 if (sb.st_size < 0 || sb.st_size > INT_MAX) {
180 tls_set_errorx(ctx, "invalid session file size");
181 goto err;
182 }
183 session_len = (size_t)sb.st_size;
184
185 /* A zero size file means that we do not yet have a valid session. */
186 if (session_len == 0)
187 goto done;
188
189 if ((session = malloc(session_len)) == NULL)
190 goto err;
191
192 n = pread(sfd, session, session_len, 0);
193 if (n < 0 || (size_t)n != session_len) {
194 tls_set_error(ctx, "failed to read session file");
195 goto err;
196 }
197 if ((bio = BIO_new_mem_buf(session, session_len)) == NULL)
198 goto err;
199 if ((ss = PEM_read_bio_SSL_SESSION(bio, NULL, tls_password_cb,
200 NULL)) == NULL) {
201 tls_set_errorx(ctx, "failed to parse session");
202 goto err;
203 }
204
205 if (SSL_set_session(ctx->ssl_conn, ss) != 1) {
206 tls_set_errorx(ctx, "failed to set session");
207 goto err;
208 }
209
210 done:
211 rv = 0;
212
213 err:
214 freezero(session, session_len);
215 SSL_SESSION_free(ss);
216 BIO_free(bio);
217
218 return rv;
219}
220
221static int
222tls_client_write_session(struct tls *ctx)
223{
224 int sfd = ctx->config->session_fd;
225 SSL_SESSION *ss = NULL;
226 BIO *bio = NULL;
227 long data_len;
228 char *data;
229 off_t offset;
230 size_t len;
231 ssize_t n;
232 int rv = -1;
233
234 if ((ss = SSL_get1_session(ctx->ssl_conn)) == NULL) {
235 if (ftruncate(sfd, 0) == -1) {
236 tls_set_error(ctx, "failed to truncate session file");
237 goto err;
238 }
239 goto done;
240 }
241
242 if ((bio = BIO_new(BIO_s_mem())) == NULL)
243 goto err;
244 if (PEM_write_bio_SSL_SESSION(bio, ss) == 0)
245 goto err;
246 if ((data_len = BIO_get_mem_data(bio, &data)) <= 0)
247 goto err;
248
249 len = (size_t)data_len;
250 offset = 0;
251
252 if (ftruncate(sfd, len) == -1) {
253 tls_set_error(ctx, "failed to truncate session file");
254 goto err;
255 }
256 while (len > 0) {
257 if ((n = pwrite(sfd, data + offset, len, offset)) == -1) {
258 tls_set_error(ctx, "failed to write session file");
259 goto err;
260 }
261 offset += n;
262 len -= n;
263 }
264
265 done:
266 rv = 0;
267
268 err:
269 SSL_SESSION_free(ss);
270 BIO_free_all(bio);
271
272 return (rv);
273}
274
275static int
162tls_connect_common(struct tls *ctx, const char *servername) 276tls_connect_common(struct tls *ctx, const char *servername)
163{ 277{
164 union tls_addr addrbuf; 278 union tls_addr addrbuf;
@@ -221,6 +335,12 @@ tls_connect_common(struct tls *ctx, const char *servername)
221 goto err; 335 goto err;
222 } 336 }
223 337
338 if (ctx->config->session_fd != -1) {
339 SSL_clear_options(ctx->ssl_conn, SSL_OP_NO_TICKET);
340 if (tls_client_read_session(ctx) == -1)
341 goto err;
342 }
343
224 if (SSL_set_tlsext_status_type(ctx->ssl_conn, TLSEXT_STATUSTYPE_ocsp) != 1) { 344 if (SSL_set_tlsext_status_type(ctx->ssl_conn, TLSEXT_STATUSTYPE_ocsp) != 1) {
225 tls_set_errorx(ctx, "ssl OCSP extension setup failure"); 345 tls_set_errorx(ctx, "ssl OCSP extension setup failure");
226 goto err; 346 goto err;
@@ -336,6 +456,12 @@ tls_handshake_client(struct tls *ctx)
336 } 456 }
337 457
338 ctx->state |= TLS_HANDSHAKE_COMPLETE; 458 ctx->state |= TLS_HANDSHAKE_COMPLETE;
459
460 if (ctx->config->session_fd != -1) {
461 if (tls_client_write_session(ctx) == -1)
462 goto err;
463 }
464
339 rv = 0; 465 rv = 0;
340 466
341 err: 467 err:
diff --git a/src/lib/libtls/tls_config.c b/src/lib/libtls/tls_config.c
index 3db75dc62f..6dfebfaebf 100644
--- a/src/lib/libtls/tls_config.c
+++ b/src/lib/libtls/tls_config.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: tls_config.c,v 1.47 2018/02/08 05:56:49 jsing Exp $ */ 1/* $OpenBSD: tls_config.c,v 1.48 2018/02/10 04:41:24 jsing Exp $ */
2/* 2/*
3 * Copyright (c) 2014 Joel Sing <jsing@openbsd.org> 3 * Copyright (c) 2014 Joel Sing <jsing@openbsd.org>
4 * 4 *
@@ -89,6 +89,7 @@ tls_config_new(void)
89 goto err; 89 goto err;
90 90
91 config->refcount = 1; 91 config->refcount = 1;
92 config->session_fd = -1;
92 93
93 /* 94 /*
94 * Default configuration. 95 * Default configuration.
@@ -670,6 +671,44 @@ tls_config_set_protocols(struct tls_config *config, uint32_t protocols)
670} 671}
671 672
672int 673int
674tls_config_set_session_fd(struct tls_config *config, int session_fd)
675{
676 struct stat sb;
677 mode_t mugo;
678
679 if (session_fd == -1) {
680 config->session_fd = session_fd;
681 return (0);
682 }
683
684 if (fstat(session_fd, &sb) == -1) {
685 tls_config_set_error(config, "failed to stat session file");
686 return (-1);
687 }
688 if (!S_ISREG(sb.st_mode)) {
689 tls_config_set_errorx(config,
690 "session file is not a regular file");
691 return (-1);
692 }
693
694 if (sb.st_uid != getuid()) {
695 tls_config_set_errorx(config, "session file has incorrect "
696 "owner (uid %i != %i)", sb.st_uid, getuid());
697 return (-1);
698 }
699 mugo = sb.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO);
700 if (mugo != (S_IRUSR|S_IWUSR)) {
701 tls_config_set_errorx(config, "session file has incorrect "
702 "permissions (%o != 600)", mugo);
703 return (-1);
704 }
705
706 config->session_fd = session_fd;
707
708 return (0);
709}
710
711int
673tls_config_set_verify_depth(struct tls_config *config, int verify_depth) 712tls_config_set_verify_depth(struct tls_config *config, int verify_depth)
674{ 713{
675 config->verify_depth = verify_depth; 714 config->verify_depth = verify_depth;
diff --git a/src/lib/libtls/tls_conninfo.c b/src/lib/libtls/tls_conninfo.c
index 685ed194e4..34535b5668 100644
--- a/src/lib/libtls/tls_conninfo.c
+++ b/src/lib/libtls/tls_conninfo.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: tls_conninfo.c,v 1.17 2018/02/08 10:02:48 jsing Exp $ */ 1/* $OpenBSD: tls_conninfo.c,v 1.18 2018/02/10 04:41:24 jsing Exp $ */
2/* 2/*
3 * Copyright (c) 2015 Joel Sing <jsing@openbsd.org> 3 * Copyright (c) 2015 Joel Sing <jsing@openbsd.org>
4 * Copyright (c) 2015 Bob Beck <beck@openbsd.org> 4 * Copyright (c) 2015 Bob Beck <beck@openbsd.org>
@@ -221,6 +221,14 @@ tls_conninfo_cert_pem(struct tls *ctx)
221 return rv; 221 return rv;
222} 222}
223 223
224static int
225tls_conninfo_session(struct tls *ctx)
226{
227 ctx->conninfo->session_resumed = SSL_session_reused(ctx->ssl_conn);
228
229 return 0;
230}
231
224int 232int
225tls_conninfo_populate(struct tls *ctx) 233tls_conninfo_populate(struct tls *ctx)
226{ 234{
@@ -260,6 +268,9 @@ tls_conninfo_populate(struct tls *ctx)
260 if (tls_conninfo_cert_pem(ctx) == -1) 268 if (tls_conninfo_cert_pem(ctx) == -1)
261 goto err; 269 goto err;
262 270
271 if (tls_conninfo_session(ctx) == -1)
272 goto err;
273
263 return (0); 274 return (0);
264 275
265 err: 276 err:
@@ -313,6 +324,14 @@ tls_conn_servername(struct tls *ctx)
313 return (ctx->conninfo->servername); 324 return (ctx->conninfo->servername);
314} 325}
315 326
327int
328tls_conn_session_resumed(struct tls *ctx)
329{
330 if (ctx->conninfo == NULL)
331 return (0);
332 return (ctx->conninfo->session_resumed);
333}
334
316const char * 335const char *
317tls_conn_version(struct tls *ctx) 336tls_conn_version(struct tls *ctx)
318{ 337{
diff --git a/src/lib/libtls/tls_internal.h b/src/lib/libtls/tls_internal.h
index eb08d47074..14265037eb 100644
--- a/src/lib/libtls/tls_internal.h
+++ b/src/lib/libtls/tls_internal.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: tls_internal.h,v 1.68 2018/02/08 10:19:31 jsing Exp $ */ 1/* $OpenBSD: tls_internal.h,v 1.69 2018/02/10 04:41:24 jsing Exp $ */
2/* 2/*
3 * Copyright (c) 2014 Jeremie Courreges-Anglas <jca@openbsd.org> 3 * Copyright (c) 2014 Jeremie Courreges-Anglas <jca@openbsd.org>
4 * Copyright (c) 2014 Joel Sing <jsing@openbsd.org> 4 * Copyright (c) 2014 Joel Sing <jsing@openbsd.org>
@@ -95,6 +95,7 @@ struct tls_config {
95 int ocsp_require_stapling; 95 int ocsp_require_stapling;
96 uint32_t protocols; 96 uint32_t protocols;
97 unsigned char session_id[TLS_MAX_SESSION_ID_LENGTH]; 97 unsigned char session_id[TLS_MAX_SESSION_ID_LENGTH];
98 int session_fd;
98 int session_lifetime; 99 int session_lifetime;
99 struct tls_ticket_key ticket_keys[TLS_NUM_TICKETS]; 100 struct tls_ticket_key ticket_keys[TLS_NUM_TICKETS];
100 uint32_t ticket_keyrev; 101 uint32_t ticket_keyrev;
@@ -111,6 +112,7 @@ struct tls_conninfo {
111 char *alpn; 112 char *alpn;
112 char *cipher; 113 char *cipher;
113 char *servername; 114 char *servername;
115 int session_resumed;
114 char *version; 116 char *version;
115 117
116 char *hash; 118 char *hash;