From 51121dcf374aff9cbd5a4a715359186e35ec0ce6 Mon Sep 17 00:00:00 2001 From: Sean Khan Date: Sun, 14 Apr 2024 20:07:30 -0400 Subject: [PATCH] nginx-util: fix deprecated openssl 3.0 functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since upstream openwrt has been using openssl 3.0 for quite some time, figured we could clean up some of the legacy code. This PR updates the code for EC/RSA key generation. nginx-util currently only generates 'ecc' keys, even though the framework is there for rsa as well. In order properly test the changes, I created two binaries: 'nginx-util-ssl' (generates ec keys) 'nginx-util-ssl-rsa' (generates rsa keys) where I would change line:455 in `src/nginx-ssl-util.hpp` `auto pkey = gen_eckey(NID_secp384r1)` to `auto pkey = gen_rsakey(2048)` Example with UCI config ``` config server '_rsa' list listen '443 ssl default_server' list listen '[::]:443 ssl default_server' option server_name '_rsa' list include 'restrict_locally' list include 'conf.d/*.locations' option uci_manage_ssl 'self-signed' option key_type 'rsa' option ssl_certificate '/etc/nginx/conf.d/_rsa.crt' option ssl_certificate_key '/etc/nginx/conf.d/_rsa.key' option ssl_session_cache 'shared:SSL:32k' option ssl_session_timeout '64m' option access_log 'off; # logd openwrt' ``` ➤ /opt/bin/nginx-ssl-util-rsa add_ssl _rsa Adding SSL directives to UCI server: nginx._rsa uci_manage_ssl='self-signed' Created self-signed SSL certificate '/etc/nginx/conf.d/_rsa.crt' with key '/etc/nginx/conf.d/_rsa.key'. [04/14/24 18:37:15](K-6.6.27) root@WRX36 ~ ➤ openssl x509 -in /etc/nginx/conf.d/_rsa.crt -text -noout Certificate: Data: Version: 3 (0x2) Serial Number: 6d:55:a6:cd:52:25:31:fd:3c:78:66:24:82:5f:bb:b6:a6:fe:8f:c7 Signature Algorithm: sha256WithRSAEncryption Issuer: C = ZZ, ST = Somewhere, L = None, CN = OpenWrt, O = OpenWrtBF399B64ACF71BC3 Validity Not Before: Apr 14 22:37:15 2024 GMT Not After : Jul 16 22:37:15 2027 GMT Subject: C = ZZ, ST = Somewhere, L = None, CN = OpenWrt, O = OpenWrtBF399B64ACF71BC3 Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (2048 bit) Modulus: 00:ac:52:71:af:25:e9:05:0a:a5:d7:86:d3:8d:0b: 66:e0:09:cf:2a:cd:a1:63:57:36:46:61:04:16:fe: 94:84:d0:20:ab:01:15:55:aa:a1:89:c2:85:a9:84: 47:ba:84:d7:1f:a9:0c:c0:f0:67:2f:81:1d:1b:3b: 31:d5:94:6e:a0:f0:e6:ec:26:91:4a:e2:fd:58:4c: ac:b5:9e:a1:cd:7d:91:51:29:81:1d:3e:4a:d9:d1: d5:f1:2f:34:2f:ca:95:dc:42:d5:c4:d3:d6:b2:91: d5:19:61:a2:b5:b1:90:f0:83:88:ef:92:c9:bf:a4: 59:a9:d6:00:6f:1c:0d:70:16:40:cc:cb:c0:de:c4: 8f:00:83:a3:2f:77:ca:18:cd:7b:d4:77:96:47:78: 1b:c1:ff:08:86:93:79:91:8f:a7:95:71:46:06:69: fc:cc:65:64:e7:99:11:cc:82:bb:39:6b:12:27:73: 0e:d1:e7:65:51:9e:ad:dc:b3:ff:3f:ba:b0:72:4f: 22:ad:7e:41:bb:3c:c7:80:30:81:5f:8b:32:f4:7f: 22:48:3f:3d:a9:eb:28:27:12:db:a9:63:c9:7e:e2: ed:36:de:e7:68:31:4e:9c:c0:36:e8:f2:d9:3f:50: 09:50:a3:e8:7a:03:00:4f:8d:e1:10:eb:a1:87:44: be:23 Exponent: 65537 (0x10001) Signature Algorithm: sha256WithRSAEncryption Signature Value: 06:7d:84:00:ac:8f:8b:a6:b6:b7:b5:ed:ee:7f:61:76:6d:ee: 11:53:f6:d1:f8:95:ad:6c:d7:d0:3e:01:ac:bb:d7:7a:8d:59: 80:ec:ba:b2:7b:78:5c:4f:5e:3f:f1:74:ad:d9:8c:a2:6b:08: 9c:bf:b1:42:fd:8d:a6:35:48:4d:a7:2d:92:c9:45:66:77:32: a4:e0:ea:eb:e0:4a:42:f5:dd:ea:a2:c0:0a:66:5a:32:03:1d: e7:87:3a:7f:1e:00:ed:d0:21:01:d5:f9:e2:b1:e6:b7:cb:1c: 67:11:de:69:7f:a2:ce:d0:fc:2d:f2:6c:33:84:4c:3d:f4:f6: 60:6b:2e:31:b7:0c:41:2c:73:31:7e:94:19:a2:2b:6a:56:3f: 07:37:71:97:28:58:91:63:b2:58:97:b2:aa:1e:d5:d9:6d:af: 6f:a0:02:e0:06:39:b0:c9:f5:50:41:b5:58:41:6a:30:72:89: 9a:67:7e:a1:7a:a5:02:b9:2a:f3:f8:93:4f:59:6e:b1:27:54: 86:d1:ec:96:7a:dd:d1:44:6b:1e:3b:17:cf:15:64:ad:83:6b: 63:20:2d:42:c3:28:68:14:de:12:4e:8a:c3:f3:10:c8:4b:4f: c7:d8:2b:a8:45:fb:3a:bd:9d:bd:08:71:08:09:ed:ea:9b:b9: 3b:33:a6:a6 [04/14/24 18:37:27](K-6.6.27) root@WRX36 ~ ➤ /opt/bin/nginx-ssl-util add_ssl _ec Adding SSL directives to UCI server: nginx._ec uci_manage_ssl='self-signed' Created self-signed SSL certificate '/etc/nginx/conf.d/_ec.crt' with key '/etc/nginx/conf.d/_ec.key'. [04/14/24 18:37:43](K-6.6.27) root@WRX36 ~ ➤ openssl x509 -in /etc/nginx/conf.d/_ec.crt -text -noout Certificate: Data: Version: 3 (0x2) Serial Number: 55:32:fe:07:09:79:d1:40:d7:43:2e:45:3d:98:4a:77:65:d0:29:41 Signature Algorithm: ecdsa-with-SHA256 Issuer: C = ZZ, ST = Somewhere, L = None, CN = OpenWrt, O = OpenWrt2EDD40F41960C8C1 Validity Not Before: Apr 14 22:37:43 2024 GMT Not After : Jul 16 22:37:43 2027 GMT Subject: C = ZZ, ST = Somewhere, L = None, CN = OpenWrt, O = OpenWrt2EDD40F41960C8C1 Subject Public Key Info: Public Key Algorithm: id-ecPublicKey Public-Key: (384 bit) pub: 04:97:d2:b2:f0:c9:60:60:89:7e:ea:6f:48:1c:90: 8e:6d:1d:d8:58:46:8c:de:e9:50:e2:74:ea:d8:dd: 8c:d9:ed:f4:4c:b7:41:95:55:98:38:5a:9e:66:83: b9:7c:79:71:9b:ec:18:ed:d9:09:3c:f7:64:32:ae: 59:ad:92:de:d7:c4:15:2e:e5:89:65:f4:29:8a:62: a0:85:21:95:22:3a:38:e3:11:e6:f2:01:f6:50:62: 01:ed:68:0d:d0:0c:d4 ASN1 OID: secp384r1 NIST CURVE: P-384 Signature Algorithm: ecdsa-with-SHA256 Signature Value: 30:65:02:30:78:af:d1:4f:57:b1:97:2b:87:aa:7f:a2:26:39: 19:30:5c:4f:9c:f0:d7:ee:24:8e:a2:39:ec:70:af:16:eb:a6: 72:96:d4:a7:2f:c1:38:f4:65:ed:ed:bf:22:c6:a4:6d:02:31: 00:bc:ec:19:0e:3d:6a:d1:5a:ae:6d:5c:a3:ec:96:60:32:f9: 6a:88:06:92:ed:c1:a7:44:2c:33:7a:22:72:0f:2a:ce:83:f0: f2:04:9e:49:60:ef:83:b4:7f:8b:af:61:c9 ``` Maintainer: Peter Stadler Compile tested: aarch64, qualcommax, Master Branch Run tested: aarch64, Dynalink DL-WRX36, Master Branch Signed-off-by: Sean Khan --- net/nginx-util/Makefile | 6 +- net/nginx-util/src/px5g-openssl.hpp | 168 ++++++++++------------------ 2 files changed, 59 insertions(+), 115 deletions(-) diff --git a/net/nginx-util/Makefile b/net/nginx-util/Makefile index b4f06aaae0..d52ca54231 100644 --- a/net/nginx-util/Makefile +++ b/net/nginx-util/Makefile @@ -1,8 +1,8 @@ include $(TOPDIR)/rules.mk PKG_NAME:=nginx-util -PKG_VERSION:=1.6 -PKG_RELEASE:=20 +PKG_VERSION:=1.7 +PKG_RELEASE:=1 PKG_MAINTAINER:=Peter Stadler include $(INCLUDE_DIR)/package.mk @@ -11,8 +11,6 @@ include $(INCLUDE_DIR)/cmake.mk CMAKE_OPTIONS+= -DUBUS=y CMAKE_OPTIONS+= -DVERSION=$(PKG_VERSION) -TARGET_CFLAGS+= -Wno-error=deprecated-declarations - define Package/nginx-ssl-util/default SECTION:=net CATEGORY:=Network diff --git a/net/nginx-util/src/px5g-openssl.hpp b/net/nginx-util/src/px5g-openssl.hpp index 7c79bad979..3dab5891ca 100644 --- a/net/nginx-util/src/px5g-openssl.hpp +++ b/net/nginx-util/src/px5g-openssl.hpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -22,7 +23,7 @@ auto checkend(const std::string& crtpath, time_t seconds = 0, bool use_pem = tru auto gen_eckey(int curve) -> EVP_PKEY_ptr; -auto gen_rsakey(int keysize, BN_ULONG exponent = RSA_F4) -> EVP_PKEY_ptr; +auto gen_rsakey(int keysize) -> EVP_PKEY_ptr; void write_key(const EVP_PKEY_ptr& pkey, const std::string& keypath = "", bool use_pem = true); @@ -88,42 +89,45 @@ auto gen_eckey(const int curve) -> EVP_PKEY_ptr } EC_GROUP_set_asn1_flag(group, OPENSSL_EC_NAMED_CURVE); - EC_GROUP_set_point_conversion_form(group, POINT_CONVERSION_UNCOMPRESSED); - auto* eckey = EC_KEY_new(); + EVP_PKEY_CTX* ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, nullptr); - if (eckey != nullptr) { - if ((EC_KEY_set_group(eckey, group) == 0) || (EC_KEY_generate_key(eckey) == 0)) { - EC_KEY_free(eckey); - eckey = nullptr; - } + if (!EVP_PKEY_paramgen_init(ctx)) { + throw std::runtime_error("Could not init paramgen"); } + EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx, curve); + + EVP_PKEY* params = nullptr; + EVP_PKEY_paramgen(ctx, ¶ms); + + EVP_PKEY_CTX* key_gen_ctx = EVP_PKEY_CTX_new(params, nullptr); + + if (EVP_PKEY_keygen_init(key_gen_ctx) <= 0) { + std::string errmsg{"gen_eckey error: cannot initialize key generation context\n"}; + ERR_print_errors_cb(print_error, &errmsg); + throw std::runtime_error(errmsg); + } + + EVP_PKEY* pkey = nullptr; + if (!EVP_PKEY_keygen(key_gen_ctx, &pkey)) { + EVP_PKEY_CTX_free(key_gen_ctx); + EC_GROUP_free(group); + std::string errmsg{"gen_eckey error: cannot generate key pair\n"}; + ERR_print_errors_cb(print_error, &errmsg); + throw std::runtime_error(errmsg); + } + + EVP_PKEY_CTX_free(ctx); EC_GROUP_free(group); - if (eckey == nullptr) { - std::string errmsg{"gen_eckey error: cannot build key with curve id "}; - errmsg += std::to_string(curve) + "\n"; - ERR_print_errors_cb(print_error, &errmsg); - throw std::runtime_error(errmsg); - } + EVP_PKEY_ptr pkey_ptr{pkey, ::EVP_PKEY_free}; - EVP_PKEY_ptr pkey{EVP_PKEY_new(), ::EVP_PKEY_free}; - - // EVP_PKEY_assign_EC_KEY is a macro casting eckey to char *: - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast) - if (!EVP_PKEY_assign_EC_KEY(pkey.get(), eckey)) { - EC_KEY_free(eckey); - std::string errmsg{"gen_eckey error: cannot assign EC key to EVP\n"}; - ERR_print_errors_cb(print_error, &errmsg); - throw std::runtime_error(errmsg); - } - - return pkey; + return pkey_ptr; } -auto gen_rsakey(const int keysize, const BN_ULONG exponent) -> EVP_PKEY_ptr +auto gen_rsakey(const int keysize) -> EVP_PKEY_ptr { if (keysize < rsa_min_modulus_bits || keysize > OPENSSL_RSA_MAX_MODULUS_BITS) { std::string errmsg{"gen_rsakey error: RSA keysize ("}; @@ -131,42 +135,12 @@ auto gen_rsakey(const int keysize, const BN_ULONG exponent) -> EVP_PKEY_ptr errmsg += std::to_string(OPENSSL_RSA_MAX_MODULUS_BITS) + "]"; throw std::runtime_error(errmsg); } - auto* bignum = BN_new(); - if (bignum == nullptr) { - std::string errmsg{"gen_rsakey error: cannot get big number struct\n"}; - ERR_print_errors_cb(print_error, &errmsg); - throw std::runtime_error(errmsg); - } + EVP_PKEY_ptr pkey = {EVP_RSA_gen(keysize), EVP_PKEY_free}; - auto* rsa = RSA_new(); - - if (rsa != nullptr) { - if ((BN_set_word(bignum, exponent) == 0) || - (RSA_generate_key_ex(rsa, keysize, bignum, nullptr) == 0)) - { - RSA_free(rsa); - rsa = nullptr; - } - } - - BN_free(bignum); - - if (rsa == nullptr) { - std::string errmsg{"gen_rsakey error: cannot create RSA key with size"}; - errmsg += std::to_string(keysize) + " and exponent "; - errmsg += std::to_string(exponent) + "\n"; - ERR_print_errors_cb(print_error, &errmsg); - throw std::runtime_error(errmsg); - } - - EVP_PKEY_ptr pkey{EVP_PKEY_new(), ::EVP_PKEY_free}; - - // EVP_PKEY_assign_RSA is a macro casting rsa to char *: - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast) - if (!EVP_PKEY_assign_RSA(pkey.get(), rsa)) { - RSA_free(rsa); - std::string errmsg{"gen_rsakey error: cannot assign RSA key to EVP\n"}; + if (!pkey) { + std::string errmsg{"gen_rsakey error: unable to generate RSA key with size: "}; + errmsg += std::to_string(keysize); ERR_print_errors_cb(print_error, &errmsg); throw std::runtime_error(errmsg); } @@ -179,31 +153,10 @@ void write_key(const EVP_PKEY_ptr& pkey, const std::string& keypath, const bool BIO* bio = nullptr; if (keypath.empty()) { - bio = _BIO_new_fp(stdout, use_pem); + bio = BIO_new_fp(stdout, BIO_NOCLOSE); } - - else { // BIO_new_file(keypath.c_str(), (use_pem ? "w" : "wb") ); - - static constexpr auto mask = 0600; - // auto fd = open(keypath.c_str(), O_WRONLY | O_CREAT | O_TRUNC, mask); - // creat has no cloexec, alt. triggers cppcoreguidelines-pro-type-vararg - // NOLINTNEXTLINE(android-cloexec-creat) - auto fd = creat(keypath.c_str(), mask); // the same without va_args. - - if (fd >= 0) { - auto* fp = fdopen(fd, (use_pem ? "w" : "wb")); - - if (fp != nullptr) { - bio = _BIO_new_fp(fp, use_pem, true); - if (bio == nullptr) { - // NOLINTNEXTLINE(cppcoreguidelines-owning-memory) fp owns fd: - fclose(fp); - } - } - else { - close(fd); - } - } + else { + bio = BIO_new_file(keypath.c_str(), use_pem ? "w" : "wb"); } if (bio == nullptr) { @@ -214,35 +167,28 @@ void write_key(const EVP_PKEY_ptr& pkey, const std::string& keypath, const bool throw std::runtime_error(errmsg); } - int len = 0; - - auto* key = pkey.get(); - switch (EVP_PKEY_base_id(key)) { // use same format as px5g: - case EVP_PKEY_EC: - len = use_pem ? PEM_write_bio_ECPrivateKey(bio, EVP_PKEY_get0_EC_KEY(key), nullptr, - nullptr, 0, nullptr, nullptr) - : i2d_ECPrivateKey_bio(bio, EVP_PKEY_get0_EC_KEY(key)); - break; - case EVP_PKEY_RSA: - len = use_pem ? PEM_write_bio_RSAPrivateKey(bio, EVP_PKEY_get0_RSA(key), nullptr, - nullptr, 0, nullptr, nullptr) - : i2d_RSAPrivateKey_bio(bio, EVP_PKEY_get0_RSA(key)); - break; - default: - len = use_pem - ? PEM_write_bio_PrivateKey(bio, key, nullptr, nullptr, 0, nullptr, nullptr) - : i2d_PrivateKey_bio(bio, key); + if (use_pem) { + if (PEM_write_bio_PrivateKey(bio, pkey.get(), nullptr, nullptr, 0, nullptr, nullptr) != 1) { + BIO_free_all(bio); + std::string errmsg{"write_key error: cannot write EVP pkey to "}; + errmsg += keypath.empty() ? "stdout" : keypath; + errmsg += "\n"; + ERR_print_errors_cb(print_error, &errmsg); + throw std::runtime_error(errmsg); + } + } + else { + if (i2d_PrivateKey_bio(bio, pkey.get()) != 1) { + BIO_free_all(bio); + std::string errmsg{"write_key error: cannot write EVP pkey to "}; + errmsg += keypath.empty() ? "stdout" : keypath; + errmsg += "\n"; + ERR_print_errors_cb(print_error, &errmsg); + throw std::runtime_error(errmsg); + } } BIO_free_all(bio); - - if (len == 0) { - std::string errmsg{"write_key error: cannot write EVP pkey to "}; - errmsg += keypath.empty() ? "stdout" : keypath; - errmsg += "\n"; - ERR_print_errors_cb(print_error, &errmsg); - throw std::runtime_error(errmsg); - } } auto subject2name(const std::string& subject) -> X509_NAME_ptr