]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: ssl/ckch: Move EVP_PKEY and cert code generation from acme
authorFrederic Lecaille <flecaille@haproxy.com>
Thu, 5 Feb 2026 13:52:35 +0000 (14:52 +0100)
committerWilly Tarreau <w@1wt.eu>
Thu, 19 Feb 2026 13:46:47 +0000 (14:46 +0100)
Move acme_EVP_PKEY_gen() implementation to ssl_gencrt.c and rename it to
ssl_EVP_PKEY_gen().  Also extract from acme_gen_tmp_x509() the generic
part to implement ssl_gen_x509() into ssl_gencrt.c.

To generate a self-signed expired certificate ssl_EVP_PKEY_gen() must be
used to generate the private key. Then, ssl_gen_x509() must be called
with the private key as argument.  acme_gen_tmp_x509() is also modified
to called these two functions to generate a temporary certificate has
done before modifying this part.

Such an expired self-signed certificate should not be use on the field
but only during testing and development steps.

include/haproxy/ssl_gencert.h
src/acme.c
src/ssl_gencert.c

index 686b2d5bc3211543f1402ca48c692930d772aa4c..39c0b3c7f22104eac1b6f396c1de84e3ba9a7cc2 100644 (file)
@@ -32,6 +32,8 @@ int ssl_sock_set_generated_cert(SSL_CTX *ctx, unsigned int key, struct bind_conf
 unsigned int ssl_sock_generated_cert_key(const void *data, size_t len);
 int ssl_sock_gencert_load_ca(struct bind_conf *bind_conf);
 void ssl_sock_gencert_free_ca(struct bind_conf *bind_conf);
+EVP_PKEY *ssl_gen_EVP_PKEY(int keytype, int curves, int bits, char **errmsg);
+X509 *ssl_gen_x509(EVP_PKEY *pkey);
 
 #endif /* USE_OPENSSL */
 #endif /* _HAPROXY_SSL_GENCERT_H */
index f14759747329957c09360b60dccb925b8a019f71..10fb6baa369ebc7f1b6979378aca697f3f5c6015 100644 (file)
@@ -30,6 +30,7 @@
 #include <haproxy/pattern.h>
 #include <haproxy/sink.h>
 #include <haproxy/ssl_ckch.h>
+#include <haproxy/ssl_gencert.h>
 #include <haproxy/ssl_sock.h>
 #include <haproxy/ssl_utils.h>
 #include <haproxy/tools.h>
@@ -157,7 +158,6 @@ enum acme_ret {
        ACME_RET_FAIL = 2
 };
 
-static EVP_PKEY *acme_EVP_PKEY_gen(int keytype, int curves, int bits, char **errmsg);
 static int acme_start_task(struct ckch_store *store, char **errmsg);
 static struct task *acme_scheduler(struct task *task, void *context, unsigned int state);
 
@@ -698,7 +698,7 @@ static int cfg_postsection_acme()
        } else {
                ha_notice("acme: generate account key '%s' for acme section '%s'.\n", path, cur_acme->name);
 
-               if ((key = acme_EVP_PKEY_gen(cur_acme->key.type, cur_acme->key.curves, cur_acme->key.bits, &errmsg)) == NULL) {
+               if ((key = ssl_gen_EVP_PKEY(cur_acme->key.type, cur_acme->key.curves, cur_acme->key.bits, &errmsg)) == NULL) {
                        ha_alert("acme: %s\n", errmsg);
                        goto out;
                }
@@ -2587,45 +2587,6 @@ error:
 
 }
 
-/* Return a new Generated private key of type <keytype> with <bits> and <curves> */
-static EVP_PKEY *acme_EVP_PKEY_gen(int keytype, int curves, int bits, char **errmsg)
-{
-
-       EVP_PKEY_CTX *pkey_ctx = NULL;
-       EVP_PKEY *pkey = NULL;
-
-       if ((pkey_ctx = EVP_PKEY_CTX_new_id(keytype, NULL)) == NULL) {
-               memprintf(errmsg, "%sCan't generate a private key.\n", errmsg && *errmsg ? *errmsg : "");
-               goto err;
-       }
-
-       if (EVP_PKEY_keygen_init(pkey_ctx) <= 0) {
-               memprintf(errmsg, "%sCan't generate a private key.\n", errmsg && *errmsg ? *errmsg : "");
-               goto err;
-       }
-
-       if (keytype == EVP_PKEY_EC) {
-               if (EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pkey_ctx, curves) <= 0) {
-                       memprintf(errmsg, "%sCan't set the curves on the new private key.\n", errmsg && *errmsg ? *errmsg : "");
-                       goto err;
-               }
-       } else if (keytype == EVP_PKEY_RSA) {
-               if (EVP_PKEY_CTX_set_rsa_keygen_bits(pkey_ctx, bits) <= 0) {
-                       memprintf(errmsg, "%sCan't set the bits on the new private key.\n", errmsg && *errmsg ? *errmsg : "");
-                       goto err;
-               }
-       }
-
-       if (EVP_PKEY_keygen(pkey_ctx, &pkey) <= 0) {
-               memprintf(errmsg, "%sCan't generate a private key.\n", errmsg && *errmsg ? *errmsg : "");
-               goto err;
-       }
-
-err:
-       EVP_PKEY_CTX_free(pkey_ctx);
-       return pkey;
-}
-
 /*
  * Generate a temporary expired X509  or reuse the one generated.
  * Use tmp_pkey to generate
@@ -2634,84 +2595,19 @@ err:
  */
 X509 *acme_gen_tmp_x509()
 {
-       X509         *newcrt  = NULL;
-       X509_NAME    *name;
-       const EVP_MD *digest = NULL;
-       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, (unsigned char *)"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) {
-               X509_NAME_free(name);
-               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();
-       else
-               goto mkcert_error;
-
-       if (!(X509_sign(newcrt, pkey, digest)))
-               goto mkcert_error;
-
-       tmp_x509 = newcrt;
+               return NULL;
 
-       return newcrt;
-
-mkcert_error:
-       if (ctmp) NCONF_free(ctmp);
-       if (newcrt)  X509_free(newcrt);
-       return NULL;
+       tmp_x509 = ssl_gen_x509(tmp_pkey);
 
+       return tmp_x509;
 }
 
-
 /*
  * Generate a temporary RSA2048 pkey or reuse the one generated.
  *
@@ -2725,7 +2621,7 @@ EVP_PKEY *acme_gen_tmp_pkey()
                return tmp_pkey;
        }
 
-       tmp_pkey = acme_EVP_PKEY_gen(EVP_PKEY_RSA, 0, 2048, NULL);
+       tmp_pkey = ssl_gen_EVP_PKEY(EVP_PKEY_RSA, 0, 2048, NULL);
 
        return tmp_pkey;
 }
@@ -2784,7 +2680,7 @@ static int acme_start_task(struct ckch_store *store, char **errmsg)
        ctx->retries = ACME_RETRY;
 
        if (!cfg->reuse_key) {
-               if ((pkey = acme_EVP_PKEY_gen(cfg->key.type, cfg->key.curves, cfg->key.bits, errmsg)) == NULL)
+               if ((pkey = ssl_gen_EVP_PKEY(cfg->key.type, cfg->key.curves, cfg->key.bits, errmsg)) == NULL)
                        goto err;
 
                EVP_PKEY_free(newstore->data->key);
index ca4b3c530f4e09501c20770e319efb981899587c..50e3e9c8828c00bcb8c3bae28f6bf51e8bd72e07 100644 (file)
@@ -475,5 +475,117 @@ static void __ssl_gencert_deinit(void)
        }
 #endif
 }
+
+/* Return a new Generated private key of type <keytype> with <bits> and <curves> */
+EVP_PKEY *ssl_gen_EVP_PKEY(int keytype, int curves, int bits, char **errmsg)
+{
+
+       EVP_PKEY_CTX *pkey_ctx = NULL;
+       EVP_PKEY *pkey = NULL;
+
+       if ((pkey_ctx = EVP_PKEY_CTX_new_id(keytype, NULL)) == NULL) {
+               memprintf(errmsg, "%sCan't generate a private key.\n", errmsg && *errmsg ? *errmsg : "");
+               goto err;
+       }
+
+       if (EVP_PKEY_keygen_init(pkey_ctx) <= 0) {
+               memprintf(errmsg, "%sCan't generate a private key.\n", errmsg && *errmsg ? *errmsg : "");
+               goto err;
+       }
+
+       if (keytype == EVP_PKEY_EC) {
+               if (EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pkey_ctx, curves) <= 0) {
+                       memprintf(errmsg, "%sCan't set the curves on the new private key.\n", errmsg && *errmsg ? *errmsg : "");
+                       goto err;
+               }
+       } else if (keytype == EVP_PKEY_RSA) {
+               if (EVP_PKEY_CTX_set_rsa_keygen_bits(pkey_ctx, bits) <= 0) {
+                       memprintf(errmsg, "%sCan't set the bits on the new private key.\n", errmsg && *errmsg ? *errmsg : "");
+                       goto err;
+               }
+       }
+
+       if (EVP_PKEY_keygen(pkey_ctx, &pkey) <= 0) {
+               memprintf(errmsg, "%sCan't generate a private key.\n", errmsg && *errmsg ? *errmsg : "");
+               goto err;
+       }
+
+err:
+       EVP_PKEY_CTX_free(pkey_ctx);
+       return pkey;
+}
+
+/*
+ * Generate an expired X509 from <pkey> private key which must be initialized.
+ * Return a pointer to the created X509 object if succeeded, NULL if not.
+ */
+X509 *ssl_gen_x509(EVP_PKEY *pkey)
+{
+       X509         *newcrt  = NULL;
+       X509_NAME    *name;
+       const EVP_MD *digest = NULL;
+       CONF         *ctmp    = NULL;
+       int           key_type;
+
+       /* 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, (unsigned char *)"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) {
+               X509_NAME_free(name);
+               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();
+       else
+               goto mkcert_error;
+
+       if (!(X509_sign(newcrt, pkey, digest)))
+               goto mkcert_error;
+
+       return newcrt;
+
+mkcert_error:
+       if (ctmp) NCONF_free(ctmp);
+       if (newcrt)  X509_free(newcrt);
+       return NULL;
+
+}
+
 REGISTER_POST_DEINIT(__ssl_gencert_deinit);