diff options
| author | jsing <> | 2018-02-10 04:41:24 +0000 |
|---|---|---|
| committer | jsing <> | 2018-02-10 04:41:24 +0000 |
| commit | 7f2c0ca878baa76136bb91e6e42ba28feb243a6b (patch) | |
| tree | d414866dbbe43d007a4873fb2dc7e6cb637f7bce /src | |
| parent | 8bb2c697afde11037803819ad6589618da0b6552 (diff) | |
| download | openbsd-7f2c0ca878baa76136bb91e6e42ba28feb243a6b.tar.gz openbsd-7f2c0ca878baa76136bb91e6e42ba28feb243a6b.tar.bz2 openbsd-7f2c0ca878baa76136bb91e6e42ba28feb243a6b.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 '')
| -rw-r--r-- | src/lib/libtls/Symbols.list | 2 | ||||
| -rw-r--r-- | src/lib/libtls/tls.h | 4 | ||||
| -rw-r--r-- | src/lib/libtls/tls_client.c | 128 | ||||
| -rw-r--r-- | src/lib/libtls/tls_config.c | 41 | ||||
| -rw-r--r-- | src/lib/libtls/tls_conninfo.c | 21 | ||||
| -rw-r--r-- | src/lib/libtls/tls_internal.h | 4 |
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 | |||
| 42 | tls_config_set_protocols | 42 | tls_config_set_protocols |
| 43 | tls_config_set_session_id | 43 | tls_config_set_session_id |
| 44 | tls_config_set_session_lifetime | 44 | tls_config_set_session_lifetime |
| 45 | tls_config_set_session_fd | ||
| 45 | tls_config_set_verify_depth | 46 | tls_config_set_verify_depth |
| 46 | tls_config_skip_private_key_check | 47 | tls_config_skip_private_key_check |
| 47 | tls_config_verify | 48 | tls_config_verify |
| @@ -51,6 +52,7 @@ tls_configure | |||
| 51 | tls_conn_alpn_selected | 52 | tls_conn_alpn_selected |
| 52 | tls_conn_cipher | 53 | tls_conn_cipher |
| 53 | tls_conn_servername | 54 | tls_conn_servername |
| 55 | tls_conn_session_resumed | ||
| 54 | tls_conn_version | 56 | tls_conn_version |
| 55 | tls_connect | 57 | tls_connect |
| 56 | tls_connect_cbs | 58 | tls_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, | |||
| 128 | int tls_config_set_ocsp_staple_file(struct tls_config *_config, | 128 | int tls_config_set_ocsp_staple_file(struct tls_config *_config, |
| 129 | const char *_staple_file); | 129 | const char *_staple_file); |
| 130 | int tls_config_set_protocols(struct tls_config *_config, uint32_t _protocols); | 130 | int tls_config_set_protocols(struct tls_config *_config, uint32_t _protocols); |
| 131 | int tls_config_set_session_fd(struct tls_config *_config, int _session_fd); | ||
| 131 | int tls_config_set_verify_depth(struct tls_config *_config, int _verify_depth); | 132 | int tls_config_set_verify_depth(struct tls_config *_config, int _verify_depth); |
| 132 | 133 | ||
| 133 | void tls_config_prefer_ciphers_client(struct tls_config *_config); | 134 | void 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); | |||
| 188 | const char *tls_conn_alpn_selected(struct tls *_ctx); | 189 | const char *tls_conn_alpn_selected(struct tls *_ctx); |
| 189 | const char *tls_conn_cipher(struct tls *_ctx); | 190 | const char *tls_conn_cipher(struct tls *_ctx); |
| 190 | const char *tls_conn_servername(struct tls *_ctx); | 191 | const char *tls_conn_servername(struct tls *_ctx); |
| 192 | int tls_conn_session_resumed(struct tls *_ctx); | ||
| 191 | const char *tls_conn_version(struct tls *_ctx); | 193 | const char *tls_conn_version(struct tls *_ctx); |
| 192 | 194 | ||
| 193 | uint8_t *tls_load_file(const char *_file, size_t *_len, char *_password); | 195 | uint8_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 | ||
| 161 | static int | 163 | static int |
| 164 | tls_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 | |||
| 221 | static int | ||
| 222 | tls_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 | |||
| 275 | static int | ||
| 162 | tls_connect_common(struct tls *ctx, const char *servername) | 276 | tls_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 | ||
| 672 | int | 673 | int |
| 674 | tls_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 | |||
| 711 | int | ||
| 673 | tls_config_set_verify_depth(struct tls_config *config, int verify_depth) | 712 | tls_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 | ||
| 224 | static int | ||
| 225 | tls_conninfo_session(struct tls *ctx) | ||
| 226 | { | ||
| 227 | ctx->conninfo->session_resumed = SSL_session_reused(ctx->ssl_conn); | ||
| 228 | |||
| 229 | return 0; | ||
| 230 | } | ||
| 231 | |||
| 224 | int | 232 | int |
| 225 | tls_conninfo_populate(struct tls *ctx) | 233 | tls_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 | ||
| 327 | int | ||
| 328 | tls_conn_session_resumed(struct tls *ctx) | ||
| 329 | { | ||
| 330 | if (ctx->conninfo == NULL) | ||
| 331 | return (0); | ||
| 332 | return (ctx->conninfo->session_resumed); | ||
| 333 | } | ||
| 334 | |||
| 316 | const char * | 335 | const char * |
| 317 | tls_conn_version(struct tls *ctx) | 336 | tls_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; |
