@@ -2737,6 +2737,14 @@ tls_process(struct tls_multi *multi,
{
tls_ctx_reload_crl(&session->opt->ssl_ctx,
session->opt->crl_file, session->opt->crl_file_inline);
+
+#ifdef ENABLE_CRYPTO_MBEDTLS
+ /* With mbedtls, the new CRL doesn't end up in the key_state
+ * automatically, so we need to put it there and recreate the
+ * mbedtls_ssl_context. */
+ update_key_state_crl(&ks->ks_ssl, &session->opt->ssl_ctx);
+#endif
+
}
/* New connection, remove any old X509 env variables */
@@ -105,6 +105,45 @@ tls_clear_error(void)
{
}
+/* Functions to handle reference counting for CRLs.
+ *
+ * The config of an mbedtls_ssl_context is not supposed to be changed
+ * after mbedtls_ssl_setup() has been called. Therefore, we need to
+ * leave previous CRLs in memory. They will be freed when they are no
+ * longer needed.
+ */
+static struct refcounted_crl *
+init_refcounted_crl(void)
+{
+ struct refcounted_crl *ref_crl;
+ ALLOC_OBJ(ref_crl, struct refcounted_crl);
+ mbedtls_x509_crl_init(&ref_crl->crl);
+ ref_crl->refcount = 1;
+
+ return ref_crl;
+}
+
+static struct refcounted_crl *
+get_refcounted_crl(struct refcounted_crl *ref_crl)
+{
+ ASSERT(ref_crl->refcount < SIZE_MAX);
+ ref_crl->refcount += 1;
+ return ref_crl;
+}
+
+static void
+release_refcounted_crl(struct refcounted_crl *ref_crl)
+{
+ if (ref_crl != NULL) {
+ ASSERT(ref_crl->refcount > 0);
+ if (--ref_crl->refcount == 0)
+ {
+ mbedtls_x509_crl_free(&ref_crl->crl);
+ free(ref_crl);
+ }
+ }
+}
+
void
tls_ctx_server_new(struct tls_root_ctx *ctx)
{
@@ -149,8 +188,7 @@ tls_ctx_free(struct tls_root_ctx *ctx)
mbedtls_dhm_free(ctx->dhm_ctx);
free(ctx->dhm_ctx);
- mbedtls_x509_crl_free(ctx->crl);
- free(ctx->crl);
+ release_refcounted_crl(ctx->ref_crl);
#if defined(ENABLE_PKCS11)
pkcs11h_certificate_freeCertificate(ctx->pkcs11_cert);
@@ -1013,15 +1051,12 @@ backend_tls_ctx_reload_crl(struct tls_root_ctx *ctx, const char *crl_file,
{
ASSERT(crl_file);
- if (ctx->crl == NULL)
- {
- ALLOC_OBJ_CLEAR(ctx->crl, mbedtls_x509_crl);
- }
- mbedtls_x509_crl_free(ctx->crl);
+ release_refcounted_crl(ctx->ref_crl);
+ ctx->ref_crl = init_refcounted_crl();
if (crl_inline)
{
- if (!mbed_ok(mbedtls_x509_crl_parse(ctx->crl,
+ if (!mbed_ok(mbedtls_x509_crl_parse(&ctx->ref_crl->crl,
(const unsigned char *)crl_file,
strlen(crl_file) + 1)))
{
@@ -1031,7 +1066,7 @@ backend_tls_ctx_reload_crl(struct tls_root_ctx *ctx, const char *crl_file,
}
else
{
- if (!mbed_ok(mbedtls_x509_crl_parse_file(ctx->crl, crl_file)))
+ if (!mbed_ok(mbedtls_x509_crl_parse_file(&ctx->ref_crl->crl, crl_file)))
{
msg(M_WARN, "CRL: cannot read CRL from file %s", crl_file);
goto err;
@@ -1040,7 +1075,9 @@ backend_tls_ctx_reload_crl(struct tls_root_ctx *ctx, const char *crl_file,
return;
err:
- mbedtls_x509_crl_free(ctx->crl);
+ /* Leaving the CRL in the freed state causes all connection attempts to
+ * be rejected. */
+ mbedtls_x509_crl_free(&ctx->ref_crl->crl);
}
void
@@ -1121,8 +1158,17 @@ key_state_ssl_init(struct key_state_ssl *ks_ssl,
}
mbedtls_ssl_conf_verify(ks_ssl->ssl_config, verify_callback, session);
+ if (ssl_ctx->ref_crl)
+ {
+ ks_ssl->ref_crl = get_refcounted_crl(ssl_ctx->ref_crl);
+ }
+ else
+ {
+ ks_ssl->ref_crl = NULL;
+ }
+
/* TODO: mbed TLS does not currently support sending the CA chain to the client */
- mbedtls_ssl_conf_ca_chain(ks_ssl->ssl_config, ssl_ctx->ca_chain, ssl_ctx->crl);
+ mbedtls_ssl_conf_ca_chain(ks_ssl->ssl_config, ssl_ctx->ca_chain, &ks_ssl->ref_crl->crl);
/* Initialize minimum TLS version */
{
@@ -1196,10 +1242,45 @@ key_state_ssl_free(struct key_state_ssl *ks_ssl)
buf_free_entries(&ks_ssl->bio_ctx->out);
free(ks_ssl->bio_ctx);
}
+ release_refcounted_crl(ks_ssl->ref_crl);
CLEAR(*ks_ssl);
}
}
+void
+update_key_state_crl(struct key_state_ssl *ks_ssl, struct tls_root_ctx *ctx)
+{
+ ASSERT(ks_ssl != NULL);
+ ASSERT(ks_ssl->ctx != NULL);
+ ASSERT(ks_ssl->bio_ctx != NULL);
+
+ /* Free the old mbedtls_ssl_context struct. The config should not be
+ * updated while it is in use. */
+ mbedtls_ssl_free(ks_ssl->ctx);
+
+ release_refcounted_crl(ks_ssl->ref_crl);
+ if (ctx->ref_crl != NULL)
+ {
+ ks_ssl->ref_crl = get_refcounted_crl(ctx->ref_crl);
+ }
+ else
+ {
+ ks_ssl->ref_crl = NULL;
+ }
+
+ /* Set new CRL in ssl_config. */
+ mbedtls_ssl_conf_ca_chain(ks_ssl->ssl_config, ctx->ca_chain, &ks_ssl->ref_crl->crl);
+
+ /* Initialize new mbedtls_ssl_context. */
+ mbedtls_ssl_init(ks_ssl->ctx);
+ mbedtls_ssl_setup(ks_ssl->ctx, ks_ssl->ssl_config);
+
+ buf_free_entries(&ks_ssl->bio_ctx->in);
+ buf_free_entries(&ks_ssl->bio_ctx->out);
+ mbedtls_ssl_set_bio(ks_ssl->ctx, ks_ssl->bio_ctx, ssl_bio_write,
+ ssl_bio_read, NULL);
+}
+
int
key_state_write_plaintext(struct key_state_ssl *ks, struct buffer *buf)
{
@@ -96,6 +96,17 @@ struct tls_key_cache { };
#endif
/**
+ * This structure wraps a CRL and counts how many structures currently
+ * have a pointer to it. The config of a mbedtls_ssl_context is not
+ * supposed to be changed after changed after setup, so we have to leave
+ * old CRLs in memory after loading a new one.
+ */
+struct refcounted_crl {
+ mbedtls_x509_crl crl;
+ size_t refcount;
+};
+
+/**
* Structure that wraps the TLS context. Contents differ depending on the
* SSL library used.
*
@@ -110,7 +121,7 @@ struct tls_root_ctx {
mbedtls_x509_crt *crt_chain; /**< Local Certificate chain */
mbedtls_x509_crt *ca_chain; /**< CA chain for remote verification */
mbedtls_pk_context *priv_key; /**< Local private key */
- mbedtls_x509_crl *crl; /**< Certificate Revocation List */
+ struct refcounted_crl *ref_crl; /**< Certificate Revocation List */
time_t crl_last_mtime; /**< CRL last modification time */
off_t crl_last_size; /**< size of last loaded CRL */
#ifdef ENABLE_PKCS11
@@ -125,6 +136,7 @@ struct tls_root_ctx {
struct key_state_ssl {
mbedtls_ssl_config *ssl_config; /**< mbedTLS global ssl config */
mbedtls_ssl_context *ctx; /**< mbedTLS connection context */
+ struct refcounted_crl *ref_crl; /**< CRL belonging to ssl_config and ctx */
bio_ctx *bio_ctx;
struct tls_key_cache tls_key_cache;
@@ -144,4 +156,15 @@ int tls_ctx_use_external_signing_func(struct tls_root_ctx *ctx,
external_sign_func sign_func,
void *sign_ctx);
+/**
+ * Update the Certificate Revocation List in ks_ssl.
+ *
+ * This involves creating a new mbedtls_ssl_context in ks_ssl and should only
+ * be called if that context has not been used yet.
+ *
+ * @param ks_ssl The SSL channel's state info
+ * @param ctx The TLS context with the new CRL
+ */
+void update_key_state_crl(struct key_state_ssl *ks_ssl, struct tls_root_ctx *ctx);
+
#endif /* SSL_MBEDTLS_H_ */
@@ -560,7 +560,7 @@ bool
tls_verify_crl_missing(const struct tls_options *opt)
{
if (opt->crl_file && !(opt->ssl_flags & SSLF_CRL_VERIFY_DIR)
- && (opt->ssl_ctx.crl == NULL || opt->ssl_ctx.crl->version == 0))
+ && (opt->ssl_ctx.ref_crl == NULL || opt->ssl_ctx.ref_crl->crl.version == 0))
{
return true;
}