summaryrefslogtreecommitdiff
path: root/src/lib/libtls/tls_client.c
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/lib/libtls/tls_client.c
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/lib/libtls/tls_client.c')
-rw-r--r--src/lib/libtls/tls_client.c128
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
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: