[Privoxy-commits] [privoxy] 03/07: Add elliptic-curve-keys directive and enable it by default
User Git
git at git.privoxy.org
Mon Feb 23 12:55:30 CET 2026
This is an automated email from the git hooks/post-receive script.
git pushed a commit to branch master
in repository privoxy.
commit 1ae617e11cd0bea2797af384f7ccc963f6052502
Author: Fabian Keil <fk at fabiankeil.de>
AuthorDate: Wed Feb 4 14:15:29 2026 +0100
Add elliptic-curve-keys directive and enable it by default
It lets Privoxy use the SN_X9_62_prime256v1 group instead of
RSA when generating website keys and certificates.
This is expected to be faster but may not be supported by older clients.
The OpenSSL-specific code is based on on a patch by Steven Smith
submitted in SF#933.
---
loadcfg.c | 15 +++-
openssl.c | 120 +++++++++++++++++++++--------
project.h | 2 +
ssl.c | 46 ++++++++---
wolfssl.c | 260 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++------
5 files changed, 375 insertions(+), 68 deletions(-)
diff --git a/loadcfg.c b/loadcfg.c
index 1e9fe2d3..580643ef 100644
--- a/loadcfg.c
+++ b/loadcfg.c
@@ -7,7 +7,7 @@
* routine to load the configuration and the global
* variables it writes to.
*
- * Copyright : Written by and Copyright (C) 2001-2022 the
+ * Copyright : Written by and Copyright (C) 2001-2026 the
* Privoxy team. https://www.privoxy.org/
*
* Based on the Internet Junkbuster originally written
@@ -148,6 +148,7 @@ static struct file_list *current_configfile = NULL;
#define hash_debug 78263U /* "debug" */
#define hash_default_server_timeout 2530089913U /* "default-server-timeout" */
#define hash_deny_access 1227333715U /* "deny-access" */
+#define hash_elliptic_curve_keys 258906537U /* "elliptic-curve-keys" */
#define hash_enable_accept_filter 2909040407U /* "enable-accept-filter" */
#define hash_enable_edit_actions 2517097536U /* "enable-edit-actions" */
#define hash_enable_compression 3943696946U /* "enable-compression" */
@@ -678,6 +679,9 @@ struct configuration_spec * load_config(void)
#endif
config->feature_flags &= ~RUNTIME_FEATURE_TOLERATE_PIPELINING;
config->cors_allowed_origin = NULL;
+#ifdef FEATURE_HTTPS_INSPECTION
+ config->elliptic_curve_keys = 1;
+#endif
configfp = fopen(configfile, "r");
if (NULL == configfp)
@@ -1027,6 +1031,15 @@ struct configuration_spec * load_config(void)
break;
#endif /* def FEATURE_ACL */
+#ifdef FEATURE_HTTPS_INSPECTION
+/* *************************************************************************
+ * elliptic-curve-keys 0|1
+ * *************************************************************************/
+ case hash_elliptic_curve_keys :
+ config->elliptic_curve_keys = parse_toggle_state(cmd, arg);
+ break;
+#endif /* def FEATURE_HTTPS_INSPECTION */
+
#if defined(FEATURE_ACCEPT_FILTER) && defined(SO_ACCEPTFILTER)
/* *************************************************************************
* enable-accept-filter 0|1
diff --git a/openssl.c b/openssl.c
index bc6d6e53..3a5bf1e5 100644
--- a/openssl.c
+++ b/openssl.c
@@ -8,7 +8,7 @@
*
* Copyright : Written by and Copyright (c) 2020 Maxim Antonov <mantonov at gmail.com>
* Copyright (C) 2017 Vaclav Svec. FIT CVUT.
- * Copyright (C) 2018-2024 by Fabian Keil <fk at fabiankeil.de>
+ * Copyright (C) 2018-2026 by Fabian Keil <fk at fabiankeil.de>
*
* This program is free software; you can redistribute it
* and/or modify it under the terms of the GNU General
@@ -1448,6 +1448,7 @@ static int generate_key(struct client_state *csp, char **key_buf)
#if (OPENSSL_VERSION_NUMBER < 0x30000000L)
BIGNUM *exp;
RSA *rsa;
+ EC_KEY *ec_key;
#endif
EVP_PKEY *key;
@@ -1468,45 +1469,90 @@ static int generate_key(struct client_state *csp, char **key_buf)
}
#if (OPENSSL_VERSION_NUMBER < 0x30000000L)
- exp = BN_new();
- rsa = RSA_new();
key = EVP_PKEY_new();
- if (exp == NULL || rsa == NULL || key == NULL)
+ if (key == NULL)
{
- log_ssl_errors(LOG_LEVEL_ERROR, "RSA key memory allocation failure");
+ log_ssl_errors(LOG_LEVEL_ERROR, "RSA/EC key memory allocation failure.");
ret = -1;
goto exit;
}
-
- if (BN_set_word(exp, RSA_KEY_PUBLIC_EXPONENT) != 1)
+ if (csp->config->elliptic_curve_keys)
{
- log_ssl_errors(LOG_LEVEL_ERROR, "Setting RSA key exponent failed");
- ret = -1;
- goto exit;
+ ec_key = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
+ if (ec_key == NULL)
+ {
+ log_ssl_errors(LOG_LEVEL_ERROR, "EC key creation failed.");
+ ret = -1;
+ goto exit;
+ }
+ if (!EC_KEY_generate_key(ec_key))
+ {
+ log_ssl_errors(LOG_LEVEL_ERROR, "EC key generation failed.");
+ ret = -1;
+ goto exit;
+ }
+ if (!EVP_PKEY_set1_EC_KEY(key, ec_key))
+ {
+ log_ssl_errors(LOG_LEVEL_ERROR,
+ "Error assigning EC key pair to PKEY structure");
+ ret = -1;
+ goto exit;
+ }
}
-
- ret = RSA_generate_key_ex(rsa, RSA_KEYSIZE, exp, NULL);
- if (ret == 0)
+ else
{
- log_ssl_errors(LOG_LEVEL_ERROR, "RSA key generation failure");
- ret = -1;
- goto exit;
- }
+ exp = BN_new();
+ rsa = RSA_new();
+ if (exp == NULL || rsa == NULL)
+ {
+ log_ssl_errors(LOG_LEVEL_ERROR, "RSA key memory allocation failure");
+ ret = -1;
+ goto exit;
+ }
- if (!EVP_PKEY_set1_RSA(key, rsa))
- {
- log_ssl_errors(LOG_LEVEL_ERROR,
- "Error assigning RSA key pair to PKEY structure");
- ret = -1;
- goto exit;
+ if (BN_set_word(exp, RSA_KEY_PUBLIC_EXPONENT) != 1)
+ {
+ log_ssl_errors(LOG_LEVEL_ERROR, "Setting RSA key exponent failed");
+ ret = -1;
+ goto exit;
+ }
+
+ ret = RSA_generate_key_ex(rsa, RSA_KEYSIZE, exp, NULL);
+ if (ret == 0)
+ {
+ log_ssl_errors(LOG_LEVEL_ERROR, "RSA key generation failure");
+ ret = -1;
+ goto exit;
+ }
+
+ if (!EVP_PKEY_set1_RSA(key, rsa))
+ {
+ log_ssl_errors(LOG_LEVEL_ERROR,
+ "Error assigning RSA key pair to PKEY structure");
+ ret = -1;
+ goto exit;
+ }
}
#else
- key = EVP_RSA_gen(RSA_KEYSIZE);
- if (key == NULL)
+ if (csp->config->elliptic_curve_keys)
{
- log_error(LOG_LEVEL_ERROR, "EVP_RSA_gen() failed");
- ret = -1;
- goto exit;
+ key = EVP_EC_gen(SN_X9_62_prime256v1);
+ if (key == NULL)
+ {
+ log_ssl_errors(LOG_LEVEL_ERROR, "EC key generation error");
+ ret = -1;
+ goto exit;
+ }
+ }
+ else
+ {
+ key = EVP_RSA_gen(RSA_KEYSIZE);
+ if (key == NULL)
+ {
+ log_ssl_errors(LOG_LEVEL_ERROR, "EVP_RSA_gen() failed");
+ ret = -1;
+ goto exit;
+ }
}
#endif
@@ -1526,13 +1572,23 @@ exit:
* Freeing used variables
*/
#if (OPENSSL_VERSION_NUMBER < 0x30000000L)
- if (exp)
+ if (csp->config->elliptic_curve_keys)
{
- BN_free(exp);
+ if (ec_key)
+ {
+ EC_KEY_free(ec_key);
+ }
}
- if (rsa)
+ else
{
- RSA_free(rsa);
+ if (exp)
+ {
+ BN_free(exp);
+ }
+ if (rsa)
+ {
+ RSA_free(rsa);
+ }
}
#endif
if (key)
diff --git a/project.h b/project.h
index 3c516602..9f3c36ef 100644
--- a/project.h
+++ b/project.h
@@ -1616,6 +1616,8 @@ struct configuration_spec
/** Filename of trusted CAs certificates **/
char *trusted_cas_file;
+
+ int elliptic_curve_keys;
#endif
};
diff --git a/ssl.c b/ssl.c
index 37d7756c..6950caae 100644
--- a/ssl.c
+++ b/ssl.c
@@ -7,7 +7,7 @@
* using mbedTLS.
*
* Copyright : Written by and Copyright (c) 2017-2020 Vaclav Svec. FIT CVUT.
- * Copyright (C) 2018-2024 by Fabian Keil <fk at fabiankeil.de>
+ * Copyright (C) 2018-2026 by Fabian Keil <fk at fabiankeil.de>
*
* This program is free software; you can redistribute it
* and/or modify it under the terms of the GNU General
@@ -75,7 +75,7 @@
*/
typedef struct {
mbedtls_pk_type_t type; /* type of key to generate */
- int rsa_keysize; /* length of key in bits */
+ int keysize; /* length of key in bits */
char *key_file_path; /* filename of the key file */
} key_options;
@@ -1002,8 +1002,16 @@ static int generate_key(struct client_state *csp, unsigned char **key_buf)
/*
* Preparing path for key file and other properties for generating key
*/
- key_opt.type = MBEDTLS_PK_RSA;
- key_opt.rsa_keysize = RSA_KEYSIZE;
+ if (csp->config->elliptic_curve_keys)
+ {
+ key_opt.type = MBEDTLS_PK_ECKEY;
+ key_opt.keysize = 32;
+ }
+ else
+ {
+ key_opt.type = MBEDTLS_PK_RSA;
+ key_opt.keysize = RSA_KEYSIZE;
+ }
key_opt.key_file_path = make_certs_path(csp->config->certificate_directory,
(char *)csp->http->hash_of_host_hex, KEY_FILE_TYPE);
@@ -1044,16 +1052,30 @@ static int generate_key(struct client_state *csp, unsigned char **key_buf)
goto exit;
}
- ret = mbedtls_rsa_gen_key(mbedtls_pk_rsa(key), mbedtls_ctr_drbg_random,
- &ctr_drbg, (unsigned)key_opt.rsa_keysize, RSA_KEY_PUBLIC_EXPONENT);
- if (ret != 0)
+ if (csp->config->elliptic_curve_keys)
{
- mbedtls_strerror(ret, err_buf, sizeof(err_buf));
- log_error(LOG_LEVEL_ERROR, "Key generating failed: %s", err_buf);
- ret = -1;
- goto exit;
+ ret = mbedtls_ecp_gen_key(MBEDTLS_ECP_DP_SECP256R1,
+ mbedtls_pk_ec(key), mbedtls_ctr_drbg_random, &ctr_drbg);
+ if (ret != 0)
+ {
+ mbedtls_strerror(ret, err_buf, sizeof(err_buf));
+ log_error(LOG_LEVEL_ERROR, "ECC Key generation failed: %s", err_buf);
+ ret = -1;
+ goto exit;
+ }
+ }
+ else
+ {
+ ret = mbedtls_rsa_gen_key(mbedtls_pk_rsa(key), mbedtls_ctr_drbg_random,
+ &ctr_drbg, (unsigned)key_opt.keysize, RSA_KEY_PUBLIC_EXPONENT);
+ if (ret != 0)
+ {
+ mbedtls_strerror(ret, err_buf, sizeof(err_buf));
+ log_error(LOG_LEVEL_ERROR, "Key generating failed: %s", err_buf);
+ ret = -1;
+ goto exit;
+ }
}
-
/*
* Exporting private key into file
*/
diff --git a/wolfssl.c b/wolfssl.c
index 40a1a46f..12b4c441 100644
--- a/wolfssl.c
+++ b/wolfssl.c
@@ -6,7 +6,7 @@
* creating, using and closing TLS/SSL connections
* using wolfSSL.
*
- * Copyright : Copyright (C) 2018-2025 by Fabian Keil <fk at fabiankeil.de>
+ * Copyright : Copyright (C) 2018-2026 by Fabian Keil <fk at fabiankeil.de>
* Copyright (C) 2020 Maxim Antonov <mantonov at gmail.com>
* Copyright (C) 2017 Vaclav Svec. FIT CVUT.
*
@@ -1512,6 +1512,89 @@ exit:
}
+/*********************************************************************
+ *
+ * Function : generate_ecc_key
+ *
+ * Description : Generates a new ECC key and saves it in a file.
+ *
+ * Parameters :
+ * 1 : ecc_key_path = Path to the key that should be written.
+ *
+ * Returns : -1 => Error while generating private key
+ * 0 => Success.
+ *
+ *********************************************************************/
+static int generate_ecc_key(const char *ecc_key_path)
+{
+ ecc_key ecc_key;
+ byte ecc_key_der[4096];
+ int ret;
+ byte key_pem[4096];
+ int der_key_size;
+ int pem_key_size;
+ FILE *f = NULL;
+
+ assert(file_exists(ecc_key_path) != 1);
+
+ wc_ecc_init(&ecc_key);
+
+ ret = wc_ecc_make_key(&wolfssl_rng, 32, &ecc_key);
+ if (ret != 0)
+ {
+ log_error(LOG_LEVEL_ERROR, "ECC key generation failed");
+ ret = -1;
+ goto exit;
+ }
+
+ der_key_size = wc_EccKeyToDer(&ecc_key, ecc_key_der, sizeof(ecc_key_der));
+ wc_ecc_free(&ecc_key);
+ if (der_key_size < 0)
+ {
+ log_error(LOG_LEVEL_ERROR, "ECC key conversion to DER format failed");
+ ret = -1;
+ goto exit;
+ }
+ pem_key_size = wc_DerToPem(ecc_key_der, (word32)der_key_size,
+ key_pem, sizeof(key_pem), ECC_PRIVATEKEY_TYPE);
+ if (pem_key_size < 0)
+ {
+ log_error(LOG_LEVEL_ERROR, "ECC key conversion to PEM format failed");
+ ret = -1;
+ goto exit;
+ }
+
+ /*
+ * Saving key into file
+ */
+ if ((f = fopen(ecc_key_path, "wb")) == NULL)
+ {
+ log_error(LOG_LEVEL_ERROR,
+ "Opening file %s to save private key failed: %E",
+ ecc_key_path);
+ ret = -1;
+ goto exit;
+ }
+
+ if (fwrite(key_pem, 1, (size_t)pem_key_size, f) != pem_key_size)
+ {
+ log_error(LOG_LEVEL_ERROR,
+ "Writing private key into file %s failed",
+ ecc_key_path);
+ close_file_stream(f, ecc_key_path);
+ ret = -1;
+ goto exit;
+ }
+
+ close_file_stream(f, ecc_key_path);
+
+exit:
+
+ return ret;
+
+}
+
+
/*********************************************************************
*
* Function : ssl_certificate_load
@@ -1714,6 +1797,106 @@ static int load_rsa_key(const char *rsa_key_path, const char *password, RsaKey *
return 1;
}
+
+/*********************************************************************
+ *
+ * Function : load_ecc_key
+ *
+ * Description : Load a PEM-encoded ECC file into memory.
+ *
+ * Parameters :
+ * 1 : ecc_key_path = Path to the file that holds the key.
+ * 2 : ecc_key = Initialized ECC key storage.
+ *
+ * Returns : 0 => Error while creating the key.
+ * 1 => It worked
+ *
+ *********************************************************************/
+static int load_ecc_key(const char *ecc_key_path, ecc_key *ecc_key)
+{
+ FILE *fp;
+ size_t length;
+ long ret;
+ unsigned char *key_pem;
+ DerBuffer *der_buffer;
+ word32 der_index = 0;
+
+ fp = fopen(ecc_key_path, "rb");
+ if (NULL == fp)
+ {
+ log_error(LOG_LEVEL_ERROR, "Failed to open %s: %E", ecc_key_path);
+ return 0;
+ }
+
+ /* Get file length */
+ if (fseek(fp, 0, SEEK_END))
+ {
+ log_error(LOG_LEVEL_ERROR,
+ "Unexpected error while fseek()ing to the end of %s: %E",
+ ecc_key_path);
+ fclose(fp);
+ return 0;
+ }
+ ret = ftell(fp);
+ if (-1 == ret)
+ {
+ log_error(LOG_LEVEL_ERROR,
+ "Unexpected ftell() error while loading %s: %E",
+ ecc_key_path);
+ fclose(fp);
+ return 0;
+ }
+ length = (size_t)ret;
+
+ /* Go back to the beginning. */
+ if (fseek(fp, 0, SEEK_SET))
+ {
+ log_error(LOG_LEVEL_ERROR,
+ "Unexpected error while fseek()ing to the beginning of %s: %E",
+ ecc_key_path);
+ fclose(fp);
+ return 0;
+ }
+
+ key_pem = malloc_or_die(length);
+
+ if (1 != fread(key_pem, length, 1, fp))
+ {
+ log_error(LOG_LEVEL_ERROR,
+ "Couldn't completely read file %s.", ecc_key_path);
+ fclose(fp);
+ freez(key_pem);
+ return 0;
+ }
+
+ fclose(fp);
+
+ ret = wc_PemToDer(key_pem, (long)length, ECC_PRIVATEKEY_TYPE,
+ &der_buffer, NULL, NULL, NULL);
+ freez(key_pem);
+ if (ret < 0)
+ {
+ log_error(LOG_LEVEL_ERROR,
+ "Failed to convert buffer into DER format for file %s. Error = %ld",
+ ecc_key_path, ret);
+ return 0;
+ }
+
+ ret = wc_EccPrivateKeyDecode(der_buffer->buffer, &der_index, ecc_key,
+ der_buffer->length);
+ freez(der_buffer);
+ if (ret < 0)
+ {
+ log_error(LOG_LEVEL_ERROR,
+ "Failed to decode DER buffer into ECC key structure for %s",
+ ecc_key_path);
+ return 0;
+ }
+
+ return 1;
+}
+
+
#ifndef WOLFSSL_ALT_NAMES
#error wolfSSL lacks Subject Alternative Name support (WOLFSSL_ALT_NAMES) which is mandatory
#endif
@@ -1773,7 +1956,7 @@ static int set_subject_alternative_name(struct Cert *certificate, const char *ho
* Parameters :
* 1 : csp = Current client state (buffers, headers, etc...)
* 2 : certificate_path = Path to the certificate to generate.
- * 3 : rsa_key_path = Path to the key to generate for the
+ * 3 : key_path = Path to the key to generate for the
* certificate.
*
* Returns : -1 => Error while creating certificate.
@@ -1782,11 +1965,12 @@ static int set_subject_alternative_name(struct Cert *certificate, const char *ho
*
*********************************************************************/
static int generate_host_certificate(struct client_state *csp,
- const char *certificate_path, const char *rsa_key_path)
+ const char *certificate_path, const char *key_path)
{
struct Cert certificate;
RsaKey ca_key;
RsaKey rsa_key;
+ ecc_key ecc_key;
int ret;
byte certificate_der[4096];
int der_certificate_length;
@@ -1807,10 +1991,10 @@ static int generate_host_certificate(struct client_state *csp,
certificate_path);
return -1;
}
- if (unlink(rsa_key_path))
+ if (unlink(key_path))
{
log_error(LOG_LEVEL_ERROR, "Failed to unlink %s: %E",
- rsa_key_path);
+ key_path);
return -1;
}
}
@@ -1824,18 +2008,28 @@ static int generate_host_certificate(struct client_state *csp,
log_error(LOG_LEVEL_CONNECT, "Creating new certificate %s",
certificate_path);
}
- if (enforce_sane_certificate_state(certificate_path, rsa_key_path))
+ if (enforce_sane_certificate_state(certificate_path, key_path))
{
return -1;
}
- wc_InitRsaKey(&rsa_key, NULL);
- wc_InitRsaKey(&ca_key, NULL);
-
- if (generate_rsa_key(rsa_key_path) == -1)
+ if (csp->config->elliptic_curve_keys)
{
- return -1;
+ wc_ecc_init(&ecc_key);
+ if (generate_ecc_key(key_path) == -1)
+ {
+ return -1;
+ }
}
+ else
+ {
+ wc_InitRsaKey(&rsa_key, NULL);
+ if (generate_rsa_key(key_path) == -1)
+ {
+ return -1;
+ }
+ }
+ wc_InitRsaKey(&ca_key, NULL);
wc_InitCert(&certificate);
@@ -1862,22 +2056,35 @@ static int generate_host_certificate(struct client_state *csp,
goto exit;
}
- if (load_rsa_key(rsa_key_path, NULL, &rsa_key) != 1)
+ if (csp->config->elliptic_curve_keys)
{
- log_error(LOG_LEVEL_ERROR,
- "Failed to load RSA key %s", rsa_key_path);
- ret = -1;
- goto exit;
+ if (load_ecc_key(key_path, &ecc_key) != 1)
+ {
+ log_error(LOG_LEVEL_ERROR,
+ "Failed to load ECC key %s", key_path);
+ ret = -1;
+ goto exit;
+ }
+ der_certificate_length = wc_MakeCert(&certificate, certificate_der,
+ sizeof(certificate_der), NULL, &ecc_key, &wolfssl_rng);
+ }
+ else
+ {
+ if (load_rsa_key(key_path, NULL, &rsa_key) != 1)
+ {
+ log_error(LOG_LEVEL_ERROR,
+ "Failed to load RSA key %s", key_path);
+ ret = -1;
+ goto exit;
+ }
+ der_certificate_length = wc_MakeCert(&certificate, certificate_der,
+ sizeof(certificate_der), &rsa_key, NULL, &wolfssl_rng);
}
-
- /* wolfSSL_Debugging_ON(); */
- der_certificate_length = wc_MakeCert(&certificate, certificate_der,
- sizeof(certificate_der), &rsa_key, NULL, &wolfssl_rng);
- /* wolfSSL_Debugging_OFF(); */
if (der_certificate_length < 0)
{
- log_error(LOG_LEVEL_ERROR, "Failed to make certificate");
+ log_error(LOG_LEVEL_ERROR, "Failed to make certificate. "
+ "wc_MakeCert() return code: %d", der_certificate_length);
ret = -1;
goto exit;
}
@@ -1922,7 +2129,14 @@ static int generate_host_certificate(struct client_state *csp,
ret = 1;
exit:
- wc_FreeRsaKey(&rsa_key);
+ if (csp->config->elliptic_curve_keys)
+ {
+ wc_ecc_free(&ecc_key);
+ }
+ else
+ {
+ wc_FreeRsaKey(&rsa_key);
+ }
wc_FreeRsaKey(&ca_key);
return 1;
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the Privoxy-commits
mailing list