nginx-util: fix deprecated openssl 3.0 functions
authorSean Khan <datapronix@protonmail.com>
Mon, 15 Apr 2024 00:07:30 +0000 (20:07 -0400)
committerRosen Penev <rosenp@gmail.com>
Sun, 23 Jun 2024 18:27:05 +0000 (11:27 -0700)
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 <peter.stadler@student.uibk.ac.at>
Compile tested: aarch64, qualcommax, Master Branch
Run tested: aarch64, Dynalink DL-WRX36, Master Branch

Signed-off-by: Sean Khan <datapronix@protonmail.com>
net/nginx-util/Makefile
net/nginx-util/src/px5g-openssl.hpp

index 8b189aeda0b5bfc804aa53e4c3f2056927787221..d52ca5423195e903bd13a800162938b8214e20b0 100644 (file)
@@ -1,8 +1,8 @@
 include $(TOPDIR)/rules.mk
 
 PKG_NAME:=nginx-util
-PKG_VERSION:=1.6
-PKG_RELEASE:=21
+PKG_VERSION:=1.7
+PKG_RELEASE:=1
 PKG_MAINTAINER:=Peter Stadler <peter.stadler@student.uibk.ac.at>
 
 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
index 7c79bad979140871fb0bc9047526f9258c89ca6e..3dab5891ca0cefa6d35dc328de1c47fdbdbe2486 100644 (file)
@@ -7,6 +7,7 @@
 #include <openssl/err.h>
 #include <openssl/pem.h>
 #include <openssl/rsa.h>
+#include <openssl/evp.h>
 #include <unistd.h>
 #include <memory>
 #include <stdexcept>
@@ -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");
     }
 
-    EC_GROUP_free(group);
+    EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx, curve);
 
-    if (eckey == nullptr) {
-        std::string errmsg{"gen_eckey error: cannot build key with curve id "};
-        errmsg += std::to_string(curve) + "\n";
+    EVP_PKEY* params = nullptr;
+    EVP_PKEY_paramgen(ctx, &params);
+
+    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_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"};
+    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);
     }
 
-    return pkey;
+    EVP_PKEY_CTX_free(ctx);
+    EC_GROUP_free(group);
+
+    EVP_PKEY_ptr pkey_ptr{pkey, ::EVP_PKEY_free};
+
+    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);
-    }
-
-    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_ptr pkey = {EVP_RSA_gen(keysize), 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