From b2daa22e54e25c4f73060dc598119941bda99041 Mon Sep 17 00:00:00 2001 From: Joel Sing Date: Thu, 28 Apr 2016 17:06:00 +0000 Subject: Factor our the keypair handling in libtls. This results in more readable and self-contained code, while preparing for the ability to handle multiple keypairs. Also provide two additional functions that allow a public certificate and private key to be set with a single function call. ok beck@ --- lib/libtls/tls.c | 45 +++++++++--------- lib/libtls/tls.h | 6 ++- lib/libtls/tls_client.c | 4 +- lib/libtls/tls_config.c | 114 ++++++++++++++++++++++++++++++++++++++++------ lib/libtls/tls_init.3 | 20 ++++++-- lib/libtls/tls_internal.h | 23 ++++++---- lib/libtls/tls_server.c | 4 +- 7 files changed, 164 insertions(+), 52 deletions(-) diff --git a/lib/libtls/tls.c b/lib/libtls/tls.c index 661aa6ad0ad..d067309cd30 100644 --- a/lib/libtls/tls.c +++ b/lib/libtls/tls.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tls.c,v 1.36 2016/04/28 16:48:44 jsing Exp $ */ +/* $OpenBSD: tls.c,v 1.37 2016/04/28 17:05:59 jsing Exp $ */ /* * Copyright (c) 2014 Joel Sing * @@ -179,40 +179,41 @@ tls_configure(struct tls *ctx, struct tls_config *config) } int -tls_configure_keypair(struct tls *ctx, int required) +tls_configure_keypair(struct tls *ctx, SSL_CTX *ssl_ctx, + struct tls_keypair *keypair, int required) { EVP_PKEY *pkey = NULL; X509 *cert = NULL; BIO *bio = NULL; if (!required && - ctx->config->cert_mem == NULL && - ctx->config->key_mem == NULL && - ctx->config->cert_file == NULL && - ctx->config->key_file == NULL) + keypair->cert_mem == NULL && + keypair->key_mem == NULL && + keypair->cert_file == NULL && + keypair->key_file == NULL) return(0); - if (ctx->config->cert_mem != NULL) { - if (ctx->config->cert_len > INT_MAX) { + if (keypair->cert_mem != NULL) { + if (keypair->cert_len > INT_MAX) { tls_set_errorx(ctx, "certificate too long"); goto err; } - if (SSL_CTX_use_certificate_chain_mem(ctx->ssl_ctx, - ctx->config->cert_mem, ctx->config->cert_len) != 1) { + if (SSL_CTX_use_certificate_chain_mem(ssl_ctx, + keypair->cert_mem, keypair->cert_len) != 1) { tls_set_errorx(ctx, "failed to load certificate"); goto err; } cert = NULL; } - if (ctx->config->key_mem != NULL) { - if (ctx->config->key_len > INT_MAX) { + if (keypair->key_mem != NULL) { + if (keypair->key_len > INT_MAX) { tls_set_errorx(ctx, "key too long"); goto err; } - if ((bio = BIO_new_mem_buf(ctx->config->key_mem, - ctx->config->key_len)) == NULL) { + if ((bio = BIO_new_mem_buf(keypair->key_mem, + keypair->key_len)) == NULL) { tls_set_errorx(ctx, "failed to create buffer"); goto err; } @@ -221,7 +222,7 @@ tls_configure_keypair(struct tls *ctx, int required) tls_set_errorx(ctx, "failed to read private key"); goto err; } - if (SSL_CTX_use_PrivateKey(ctx->ssl_ctx, pkey) != 1) { + if (SSL_CTX_use_PrivateKey(ssl_ctx, pkey) != 1) { tls_set_errorx(ctx, "failed to load private key"); goto err; } @@ -231,22 +232,22 @@ tls_configure_keypair(struct tls *ctx, int required) pkey = NULL; } - if (ctx->config->cert_file != NULL) { - if (SSL_CTX_use_certificate_chain_file(ctx->ssl_ctx, - ctx->config->cert_file) != 1) { + if (keypair->cert_file != NULL) { + if (SSL_CTX_use_certificate_chain_file(ssl_ctx, + keypair->cert_file) != 1) { tls_set_errorx(ctx, "failed to load certificate file"); goto err; } } - if (ctx->config->key_file != NULL) { - if (SSL_CTX_use_PrivateKey_file(ctx->ssl_ctx, - ctx->config->key_file, SSL_FILETYPE_PEM) != 1) { + if (keypair->key_file != NULL) { + if (SSL_CTX_use_PrivateKey_file(ssl_ctx, + keypair->key_file, SSL_FILETYPE_PEM) != 1) { tls_set_errorx(ctx, "failed to load private key file"); goto err; } } - if (SSL_CTX_check_private_key(ctx->ssl_ctx) != 1) { + if (SSL_CTX_check_private_key(ssl_ctx) != 1) { tls_set_errorx(ctx, "private/public key mismatch"); goto err; } diff --git a/lib/libtls/tls.h b/lib/libtls/tls.h index da229d1feed..6994f1417b9 100644 --- a/lib/libtls/tls.h +++ b/lib/libtls/tls.h @@ -1,4 +1,4 @@ -/* $OpenBSD: tls.h,v 1.27 2016/04/28 16:48:44 jsing Exp $ */ +/* $OpenBSD: tls.h,v 1.28 2016/04/28 17:05:59 jsing Exp $ */ /* * Copyright (c) 2014 Joel Sing * @@ -66,6 +66,10 @@ int tls_config_set_ecdhecurve(struct tls_config *_config, const char *_name); int tls_config_set_key_file(struct tls_config *_config, const char *_key_file); int tls_config_set_key_mem(struct tls_config *_config, const uint8_t *_key, size_t _len); +int tls_config_set_keypair_file(struct tls_config *_config, + const char *_cert_file, const char *_key_file); +int tls_config_set_keypair_mem(struct tls_config *_config, const uint8_t *_cert, + size_t _cert_len, const uint8_t *_key, size_t _key_len); void tls_config_set_protocols(struct tls_config *_config, uint32_t _protocols); void tls_config_set_verify_depth(struct tls_config *_config, int _verify_depth); diff --git a/lib/libtls/tls_client.c b/lib/libtls/tls_client.c index 6bb24cd512f..3847f4c46cd 100644 --- a/lib/libtls/tls_client.c +++ b/lib/libtls/tls_client.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tls_client.c,v 1.32 2015/10/09 04:13:34 deraadt Exp $ */ +/* $OpenBSD: tls_client.c,v 1.33 2016/04/28 17:05:59 jsing Exp $ */ /* * Copyright (c) 2014 Joel Sing * @@ -195,7 +195,7 @@ tls_connect_fds(struct tls *ctx, int fd_read, int fd_write, if (tls_configure_ssl(ctx) != 0) goto err; - if (tls_configure_keypair(ctx, 0) != 0) + if (tls_configure_keypair(ctx, ctx->ssl_ctx, ctx->config->keypair, 0) != 0) goto err; if (ctx->config->verify_name) { diff --git a/lib/libtls/tls_config.c b/lib/libtls/tls_config.c index 9c2b5810f68..b395337f498 100644 --- a/lib/libtls/tls_config.c +++ b/lib/libtls/tls_config.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tls_config.c,v 1.15 2016/04/28 16:48:44 jsing Exp $ */ +/* $OpenBSD: tls_config.c,v 1.16 2016/04/28 17:05:59 jsing Exp $ */ /* * Copyright (c) 2014 Joel Sing * @@ -57,6 +57,63 @@ set_mem(char **dest, size_t *destlen, const void *src, size_t srclen) return 0; } +static struct tls_keypair * +tls_keypair_new() +{ + return calloc(1, sizeof(struct tls_keypair)); +} + +static int +tls_keypair_set_cert_file(struct tls_keypair *keypair, const char *cert_file) +{ + return set_string(&keypair->cert_file, cert_file); +} + +static int +tls_keypair_set_cert_mem(struct tls_keypair *keypair, const uint8_t *cert, + size_t len) +{ + return set_mem(&keypair->cert_mem, &keypair->cert_len, cert, len); +} + +static int +tls_keypair_set_key_file(struct tls_keypair *keypair, const char *key_file) +{ + return set_string(&keypair->key_file, key_file); +} + +static int +tls_keypair_set_key_mem(struct tls_keypair *keypair, const uint8_t *key, + size_t len) +{ + if (keypair->key_mem != NULL) + explicit_bzero(keypair->key_mem, keypair->key_len); + return set_mem(&keypair->key_mem, &keypair->key_len, key, len); +} + +static void +tls_keypair_clear(struct tls_keypair *keypair) +{ + tls_keypair_set_cert_mem(keypair, NULL, 0); + tls_keypair_set_key_mem(keypair, NULL, 0); +} + +static void +tls_keypair_free(struct tls_keypair *keypair) +{ + if (keypair == NULL) + return; + + tls_keypair_clear(keypair); + + free((char *)keypair->cert_file); + free(keypair->cert_mem); + free((char *)keypair->key_file); + free(keypair->key_mem); + + free(keypair); +} + struct tls_config * tls_config_new(void) { @@ -65,6 +122,9 @@ tls_config_new(void) if ((config = calloc(1, sizeof(*config))) == NULL) return (NULL); + if ((config->keypair = tls_keypair_new()) == NULL) + goto err; + /* * Default configuration. */ @@ -94,20 +154,21 @@ tls_config_new(void) void tls_config_free(struct tls_config *config) { + struct tls_keypair *kp, *nkp; + if (config == NULL) return; - tls_config_clear_keys(config); + for (kp = config->keypair; kp != NULL; kp = nkp) { + nkp = kp->next; + tls_keypair_free(kp); + } free(config->error.msg); free((char *)config->ca_file); free((char *)config->ca_path); - free((char *)config->cert_file); - free(config->cert_mem); free((char *)config->ciphers); - free((char *)config->key_file); - free(config->key_mem); free(config); } @@ -121,9 +182,12 @@ tls_config_error(struct tls_config *config) void tls_config_clear_keys(struct tls_config *config) { + struct tls_keypair *kp; + + for (kp = config->keypair; kp != NULL; kp = kp->next) + tls_keypair_clear(kp); + tls_config_set_ca_mem(config, NULL, 0); - tls_config_set_cert_mem(config, NULL, 0); - tls_config_set_key_mem(config, NULL, 0); } int @@ -205,14 +269,14 @@ tls_config_set_ca_mem(struct tls_config *config, const uint8_t *ca, size_t len) int tls_config_set_cert_file(struct tls_config *config, const char *cert_file) { - return set_string(&config->cert_file, cert_file); + return tls_keypair_set_cert_file(config->keypair, cert_file); } int tls_config_set_cert_mem(struct tls_config *config, const uint8_t *cert, size_t len) { - return set_mem(&config->cert_mem, &config->cert_len, cert, len); + return tls_keypair_set_cert_mem(config->keypair, cert, len); } int @@ -272,16 +336,38 @@ tls_config_set_ecdhecurve(struct tls_config *config, const char *name) int tls_config_set_key_file(struct tls_config *config, const char *key_file) { - return set_string(&config->key_file, key_file); + return tls_keypair_set_key_file(config->keypair, key_file); } int tls_config_set_key_mem(struct tls_config *config, const uint8_t *key, size_t len) { - if (config->key_mem) - explicit_bzero(config->key_mem, config->key_len); - return set_mem(&config->key_mem, &config->key_len, key, len); + return tls_keypair_set_key_mem(config->keypair, key, len); +} + +int +tls_config_set_keypair_file(struct tls_config *config, + const char *cert_file, const char *key_file) +{ + if (tls_config_set_cert_file(config, cert_file) != 0) + return (-1); + if (tls_config_set_key_file(config, key_file) != 0) + return (-1); + + return (0); +} + +int +tls_config_set_keypair_mem(struct tls_config *config, const uint8_t *cert, + size_t cert_len, const uint8_t *key, size_t key_len) +{ + if (tls_config_set_cert_mem(config, cert, cert_len) != 0) + return (-1); + if (tls_config_set_key_mem(config, key, key_len) != 0) + return (-1); + + return (0); } void diff --git a/lib/libtls/tls_init.3 b/lib/libtls/tls_init.3 index 48662e08683..da8565a248d 100644 --- a/lib/libtls/tls_init.3 +++ b/lib/libtls/tls_init.3 @@ -1,4 +1,4 @@ -.\" $OpenBSD: tls_init.3,v 1.57 2016/04/28 16:48:44 jsing Exp $ +.\" $OpenBSD: tls_init.3,v 1.58 2016/04/28 17:05:59 jsing Exp $ .\" .\" Copyright (c) 2014 Ted Unangst .\" @@ -34,6 +34,8 @@ .Nm tls_config_set_ecdhecurve , .Nm tls_config_set_key_file , .Nm tls_config_set_key_mem , +.Nm tls_config_set_keypair_file , +.Nm tls_config_set_keypair_mem , .Nm tls_config_set_protocols , .Nm tls_config_set_verify_depth , .Nm tls_config_prefer_ciphers_client , @@ -105,6 +107,10 @@ .Fn tls_config_set_key_file "struct tls_config *config" "const char *key_file" .Ft "int" .Fn tls_config_set_key_mem "struct tls_config *config" "const uint8_t *key" "size_t len" +.Ft "int" +.Fn tls_config_set_keypair_file "struct tls_config *config" "const char *cert_file" "const char *key_file" +.Ft "int" +.Fn tls_config_set_keypair_mem "struct tls_config *config" "const uint8_t *cert" "size_t cert_len" "const uint8_t *key" "size_t key_len" .Ft "void" .Fn tls_config_set_protocols "struct tls_config *config" "uint32_t protocols" .Ft "void" @@ -327,11 +333,19 @@ permitted names are: .It .Fn tls_config_set_key_file sets the file from which the private key will be read. -.Em (Server) +.Em (Client and server) .It .Fn tls_config_set_key_mem directly sets the private key from memory. -.Em (Server) +.Em (Client and server) +.It +.Fn tls_config_set_keypair_file +sets the files from which the public certificate and private key will be read. +.Em (Client and server) +.It +.Fn tls_config_set_keypair_mem +directly sets the public certifcate and private key from memory. +.Em (Client and server) .It .Fn tls_config_set_protocols sets which versions of the protocol may be used. diff --git a/lib/libtls/tls_internal.h b/lib/libtls/tls_internal.h index 21bf2b46130..cb5d90f5427 100644 --- a/lib/libtls/tls_internal.h +++ b/lib/libtls/tls_internal.h @@ -1,4 +1,4 @@ -/* $OpenBSD: tls_internal.h,v 1.27 2016/04/28 16:48:44 jsing Exp $ */ +/* $OpenBSD: tls_internal.h,v 1.28 2016/04/28 17:05:59 jsing Exp $ */ /* * Copyright (c) 2014 Jeremie Courreges-Anglas * Copyright (c) 2014 Joel Sing @@ -39,6 +39,17 @@ struct tls_error { int num; }; +struct tls_keypair { + struct tls_keypair *next; + + const char *cert_file; + char *cert_mem; + size_t cert_len; + const char *key_file; + char *key_mem; + size_t key_len; +}; + struct tls_config { struct tls_error error; @@ -46,16 +57,11 @@ struct tls_config { const char *ca_path; char *ca_mem; size_t ca_len; - const char *cert_file; - char *cert_mem; - size_t cert_len; const char *ciphers; int ciphers_server; int dheparams; int ecdhecurve; - const char *key_file; - char *key_mem; - size_t key_len; + struct tls_keypair *keypair; uint32_t protocols; int verify_cert; int verify_client; @@ -103,7 +109,8 @@ struct tls *tls_new(void); struct tls *tls_server_conn(struct tls *ctx); int tls_check_name(struct tls *ctx, X509 *cert, const char *servername); -int tls_configure_keypair(struct tls *ctx, int); +int tls_configure_keypair(struct tls *ctx, SSL_CTX *ssl_ctx, + struct tls_keypair *keypair, int required); int tls_configure_server(struct tls *ctx); int tls_configure_ssl(struct tls *ctx); int tls_configure_ssl_verify(struct tls *ctx, int verify); diff --git a/lib/libtls/tls_server.c b/lib/libtls/tls_server.c index ad98cf3d7e8..1d94c99bc01 100644 --- a/lib/libtls/tls_server.c +++ b/lib/libtls/tls_server.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tls_server.c,v 1.18 2015/09/29 10:17:04 deraadt Exp $ */ +/* $OpenBSD: tls_server.c,v 1.19 2016/04/28 17:05:59 jsing Exp $ */ /* * Copyright (c) 2014 Joel Sing * @@ -61,7 +61,7 @@ tls_configure_server(struct tls *ctx) if (tls_configure_ssl(ctx) != 0) goto err; - if (tls_configure_keypair(ctx, 1) != 0) + if (tls_configure_keypair(ctx, ctx->ssl_ctx, ctx->config->keypair, 1) != 0) goto err; if (ctx->config->verify_client != 0) { int verify = SSL_VERIFY_PEER; -- cgit v1.2.3