From 546c67d137c8712750715061ceb8a09aa10b4f21 Mon Sep 17 00:00:00 2001 From: William Lallemand Date: Wed, 5 Nov 2025 18:44:22 +0100 Subject: [PATCH] MINOR: acme: generate a temporary key pair This patch provides two functions acme_gen_tmp_pkey() and acme_gen_tmp_x509(). These functions generates a unique keypair and X509 certificate that will be stored in tmp_x509 and tmp_pkey. If the key pair or certificate was already generated they will return the existing one. The key is an RSA2048 and the X509 is generated with a expiration in the past. The CN is "expired". These are just placeholders to be used if we don't have files. --- include/haproxy/acme.h | 3 ++ src/acme.c | 107 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 110 insertions(+) diff --git a/include/haproxy/acme.h b/include/haproxy/acme.h index a6a0ed810..763a4692a 100644 --- a/include/haproxy/acme.h +++ b/include/haproxy/acme.h @@ -5,5 +5,8 @@ #include int ckch_conf_acme_init(void *value, char *buf, struct ckch_store *s, int cli, const char *filename, int linenum, char **err); +EVP_PKEY *acme_gen_tmp_pkey(); +X509 *acme_gen_tmp_x509(); + #endif diff --git a/src/acme.c b/src/acme.c index 9a34ab5e4..9af0a6540 100644 --- a/src/acme.c +++ b/src/acme.c @@ -40,6 +40,10 @@ #if defined(HAVE_ACME) +static EVP_PKEY *tmp_pkey = NULL; +static X509 *tmp_x509 = NULL; + + static void acme_trace(enum trace_level level, uint64_t mask, const struct trace_source *src, const struct ist where, const struct ist func, const void *a1, const void *a2, const void *a3, const void *a4); @@ -2611,6 +2615,109 @@ err: return pkey; } +/* + * Generate a temporary expired X509 or reuse the one generated. + * Use tmp_pkey to generate + * + * Increment the refcount when returning the existing one + */ +X509 *acme_gen_tmp_x509() +{ + X509 *newcrt = NULL; + X509_NAME *name; + const EVP_MD *digest; + X509V3_CTX ctx; + unsigned int i; + CONF *ctmp = NULL; + int key_type; + EVP_PKEY *pkey = tmp_pkey; + + if (tmp_x509) { + X509_up_ref(tmp_x509); + return tmp_x509; + } + + if (!tmp_pkey) + goto mkcert_error; + + /* Create the certificate */ + if (!(newcrt = X509_new())) + goto mkcert_error; + + /* Set version number for the certificate (X509v3) and the serial + * number */ + if (X509_set_version(newcrt, 2L) != 1) + goto mkcert_error; + + /* Generate an expired certificate */ + if (!X509_gmtime_adj(X509_getm_notBefore(newcrt), (long)-60*60*48) || + !X509_gmtime_adj(X509_getm_notAfter(newcrt),(long)-60*60*24)) + goto mkcert_error; + + /* set public key in the certificate */ + if (X509_set_pubkey(newcrt, pkey) != 1) + goto mkcert_error; + + if ((name = X509_NAME_new()) == NULL) + goto mkcert_error; + + /* Set the subject name using the servername but the CN */ + if (X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, "expired", + -1, -1, 0) != 1) { + X509_NAME_free(name); + goto mkcert_error; + } + if (X509_set_subject_name(newcrt, name) != 1) { + X509_NAME_free(name); + goto mkcert_error; + } + /* Set issuer name as itself */ + if (X509_set_issuer_name(newcrt, name) != 1) + goto mkcert_error; + X509_NAME_free(name); + + /* Autosign the certificate with the private key */ + key_type = EVP_PKEY_base_id(pkey); + + if (key_type == EVP_PKEY_RSA) + digest = EVP_sha256(); + else if (key_type == EVP_PKEY_EC) + digest = EVP_sha256(); + + if (!(X509_sign(newcrt, pkey, digest))) + goto mkcert_error; + + tmp_x509 = newcrt; + + return newcrt; + +mkcert_error: + if (ctmp) NCONF_free(ctmp); + if (newcrt) X509_free(newcrt); + return NULL; + +} + + +/* + * Generate a temporary RSA2048 pkey or reuse the one generated. + * + * Increment the refcount when returning the existing one + * + */ +EVP_PKEY *acme_gen_tmp_pkey() +{ + if (tmp_pkey) { + EVP_PKEY_up_ref(tmp_pkey); + return tmp_pkey; + } + + tmp_pkey = acme_EVP_PKEY_gen(EVP_PKEY_RSA, 0, 2048, NULL); + + return tmp_pkey; +} + + /* start an ACME task */ static int acme_start_task(struct ckch_store *store, char **errmsg) { -- 2.47.3