diff options
author | jsing <> | 2018-02-10 04:41:24 +0000 |
---|---|---|
committer | jsing <> | 2018-02-10 04:41:24 +0000 |
commit | ad2580ae7b71760c38ec88f34f360d5f1e6b3f13 (patch) | |
tree | d414866dbbe43d007a4873fb2dc7e6cb637f7bce /src/lib/libtls/tls_client.c | |
parent | 87264e9d7a6c2a965876fcf5e4b3dc46470e2562 (diff) | |
download | openbsd-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/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: |