Allow setting a keypair on a tls context without specifying the private
authoreric <eric@openbsd.org>
Thu, 21 Jan 2021 19:09:10 +0000 (19:09 +0000)
committereric <eric@openbsd.org>
Thu, 21 Jan 2021 19:09:10 +0000 (19:09 +0000)
key, and fake it internally with the certificate public key instead.
It makes it easier for privsep engines like relayd that don't have to
use bogus keys anymore.

ok beck@ tb@ jsing@

lib/libtls/Symbols.list
lib/libtls/tls.c
lib/libtls/tls_config.c
lib/libtls/tls_internal.h

index e3fcb67..42c039d 100644 (file)
@@ -45,6 +45,7 @@ tls_config_set_session_lifetime
 tls_config_set_session_fd
 tls_config_set_verify_depth
 tls_config_skip_private_key_check
+tls_config_use_fake_private_key
 tls_config_verify
 tls_config_verify_client
 tls_config_verify_client_optional
index 3d6723b..02ddf44 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: tls.c,v 1.85 2020/05/24 15:12:54 jsing Exp $ */
+/* $OpenBSD: tls.c,v 1.86 2021/01/21 19:09:10 eric Exp $ */
 /*
  * Copyright (c) 2014 Joel Sing <jsing@openbsd.org>
  *
@@ -326,12 +326,69 @@ tls_cert_pubkey_hash(X509 *cert, char **hash)
        return (rv);
 }
 
+static int
+tls_keypair_to_pkey(struct tls *ctx, struct tls_keypair *keypair, EVP_PKEY **pkey)
+{
+       BIO *bio = NULL;
+       X509 *x509 = NULL;
+       char *mem;
+       size_t len;
+       int ret = -1;
+
+       *pkey = NULL;
+
+       if (ctx->config->use_fake_private_key) {
+               mem = keypair->cert_mem;
+               len = keypair->cert_len;
+       } else {
+               mem = keypair->key_mem;
+               len = keypair->key_len;
+       }
+
+       if (mem == NULL)
+               return (0);
+
+       if (len > INT_MAX) {
+               tls_set_errorx(ctx, ctx->config->use_fake_private_key ?
+                   "cert too long" : "key too long");
+               goto err;
+       }
+
+       if ((bio = BIO_new_mem_buf(mem, len)) == NULL) {
+               tls_set_errorx(ctx, "failed to create buffer");
+               goto err;
+       }
+
+       if (ctx->config->use_fake_private_key) {
+               if ((x509 = PEM_read_bio_X509(bio, NULL, tls_password_cb,
+                   NULL)) == NULL) {
+                       tls_set_errorx(ctx, "failed to read X509 certificate");
+                       goto err;
+               }
+               if ((*pkey = X509_get_pubkey(x509)) == NULL) {
+                       tls_set_errorx(ctx, "failed to retrieve pubkey");
+                       goto err;
+               }
+       } else {
+               if ((*pkey = PEM_read_bio_PrivateKey(bio, NULL, tls_password_cb,
+                   NULL)) ==  NULL) {
+                       tls_set_errorx(ctx, "failed to read private key");
+                       goto err;
+               }
+       }
+
+       ret = 0;
+ err:
+       BIO_free(bio);
+       X509_free(x509);
+       return (ret);
+}
+
 int
 tls_configure_ssl_keypair(struct tls *ctx, SSL_CTX *ssl_ctx,
     struct tls_keypair *keypair, int required)
 {
        EVP_PKEY *pkey = NULL;
-       BIO *bio = NULL;
 
        if (!required &&
            keypair->cert_mem == NULL &&
@@ -351,23 +408,9 @@ tls_configure_ssl_keypair(struct tls *ctx, SSL_CTX *ssl_ctx,
                }
        }
 
-       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(keypair->key_mem,
-                   keypair->key_len)) == NULL) {
-                       tls_set_errorx(ctx, "failed to create buffer");
-                       goto err;
-               }
-               if ((pkey = PEM_read_bio_PrivateKey(bio, NULL, tls_password_cb,
-                   NULL)) == NULL) {
-                       tls_set_errorx(ctx, "failed to read private key");
-                       goto err;
-               }
-
+       if (tls_keypair_to_pkey(ctx, keypair, &pkey) == -1)
+               goto err;
+       if (pkey != NULL) {
                if (keypair->pubkey_hash != NULL) {
                        RSA *rsa;
                        /* XXX only RSA for now for relayd privsep */
@@ -381,8 +424,6 @@ tls_configure_ssl_keypair(struct tls *ctx, SSL_CTX *ssl_ctx,
                        tls_set_errorx(ctx, "failed to load private key");
                        goto err;
                }
-               BIO_free(bio);
-               bio = NULL;
                EVP_PKEY_free(pkey);
                pkey = NULL;
        }
@@ -397,7 +438,6 @@ tls_configure_ssl_keypair(struct tls *ctx, SSL_CTX *ssl_ctx,
 
  err:
        EVP_PKEY_free(pkey);
-       BIO_free(bio);
 
        return (1);
 }
index 7a0d6d8..e3e90aa 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: tls_config.c,v 1.61 2020/12/22 13:07:54 bcook Exp $ */
+/* $OpenBSD: tls_config.c,v 1.62 2021/01/21 19:09:10 eric Exp $ */
 /*
  * Copyright (c) 2014 Joel Sing <jsing@openbsd.org>
  *
@@ -353,7 +353,8 @@ tls_config_add_keypair_file_internal(struct tls_config *config,
                return (-1);
        if (tls_keypair_set_cert_file(keypair, &config->error, cert_file) != 0)
                goto err;
-       if (tls_keypair_set_key_file(keypair, &config->error, key_file) != 0)
+       if (key_file != NULL &&
+           tls_keypair_set_key_file(keypair, &config->error, key_file) != 0)
                goto err;
        if (ocsp_file != NULL &&
            tls_keypair_set_ocsp_staple_file(keypair, &config->error,
@@ -380,7 +381,8 @@ tls_config_add_keypair_mem_internal(struct tls_config *config, const uint8_t *ce
                return (-1);
        if (tls_keypair_set_cert_mem(keypair, &config->error, cert, cert_len) != 0)
                goto err;
-       if (tls_keypair_set_key_mem(keypair, &config->error, key, key_len) != 0)
+       if (key != NULL &&
+           tls_keypair_set_key_mem(keypair, &config->error, key, key_len) != 0)
                goto err;
        if (staple != NULL &&
            tls_keypair_set_ocsp_staple_mem(keypair, &config->error, staple,
@@ -805,6 +807,12 @@ tls_config_skip_private_key_check(struct tls_config *config)
        config->skip_private_key_check = 1;
 }
 
+void
+tls_config_use_fake_private_key(struct tls_config *config)
+{
+       config->use_fake_private_key = 1;
+}
+
 int
 tls_config_set_ocsp_staple_file(struct tls_config *config, const char *staple_file)
 {
index 1dd5f45..5487b12 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: tls_internal.h,v 1.77 2019/11/16 21:39:52 beck Exp $ */
+/* $OpenBSD: tls_internal.h,v 1.78 2021/01/21 19:09:10 eric Exp $ */
 /*
  * Copyright (c) 2014 Jeremie Courreges-Anglas <jca@openbsd.org>
  * Copyright (c) 2014 Joel Sing <jsing@openbsd.org>
@@ -111,6 +111,7 @@ struct tls_config {
        int verify_name;
        int verify_time;
        int skip_private_key_check;
+       int use_fake_private_key;
 };
 
 struct tls_conninfo {
@@ -294,5 +295,6 @@ __END_HIDDEN_DECLS
 
 /* XXX this function is not fully hidden so relayd can use it */
 void tls_config_skip_private_key_check(struct tls_config *config);
+void tls_config_use_fake_private_key(struct tls_config *config);
 
 #endif /* HEADER_TLS_INTERNAL_H */