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/lib/libtls/tls_client.c | |
| 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 'src/lib/libtls/tls_client.c')
| -rw-r--r-- | src/lib/libtls/tls_client.c | 128 |
1 files changed, 127 insertions, 1 deletions
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: |
