]> source.dussan.org Git - rspamd.git/commitdiff
Provided support for OpenSSL 3.0
authorLeftTry <lerest.go@gmail.com>
Wed, 24 Jul 2024 08:33:36 +0000 (13:33 +0500)
committerLeftTry <lerest.go@gmail.com>
Wed, 24 Jul 2024 08:33:36 +0000 (13:33 +0500)
src/libcryptobox/cryptobox.c

index aa093d01eb42a620540d758b5773d3ff295c5cae..3f0281e99eaffae9f389d02a7bb27357850da633 100644 (file)
@@ -1,18 +1,18 @@
 /*
- * Copyright 2024 Vsevolod Stakhov
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *    http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
+* Copyright 2024 Vsevolod Stakhov
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*    http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
 /* Workaround for memset_s */
 #ifdef __APPLE__
 #define __STDC_WANT_LIB_EXT1__ 1
@@ -38,6 +38,8 @@
 #endif
 #ifdef HAVE_OPENSSL
 #include <openssl/opensslv.h>
+#include <openssl/engine.h>
+#include <openssl/param_build.h>
 /* Openssl >= 1.0.1d is required for GCM verification */
 #if OPENSSL_VERSION_NUMBER >= 0x1000104fL
 #define HAVE_USABLE_OPENSSL 1
@@ -67,7 +69,7 @@ static const unsigned char n0[16] = {0};
 
 #define CRYPTOBOX_ALIGNMENT 16
 #define cryptobox_align_ptr(p, a) \
-       (void *) (((uintptr_t) (p) + ((uintptr_t) a - 1)) & ~((uintptr_t) a - 1))
+   (void *) (((uintptr_t) (p) + ((uintptr_t) a - 1)) & ~((uintptr_t) a - 1))
 
 static void
 rspamd_cryptobox_cpuid(int cpu[4], int info)
@@ -339,11 +341,34 @@ void rspamd_cryptobox_keypair(rspamd_pk_t pk, rspamd_sk_t sk,
 #ifndef HAVE_USABLE_OPENSSL
                g_assert(0);
 #else
-               EC_KEY *ec_sec;
-               const BIGNUM *bn_sec;
 
-               const EC_POINT *ec_pub;
                gsize len;
+#if OPENSSL_VERSION_MAJOR >= 3
+               OSSL_LIB_CTX *libctx = OSSL_LIB_CTX_new();
+               EVP_PKEY *pkey = EVP_PKEY_Q_keygen(libctx, NULL, "EC", EC_curve_nid2nist(CRYPTOBOX_CURVE_NID));
+               g_assert(pkey != NULL);
+
+               BIGNUM *bn_sec = NULL;
+               g_assert(EVP_PKEY_get_bn_param(pkey, "priv", &bn_sec) == 1);
+
+               len = BN_num_bytes(bn_sec);
+               g_assert(len <= (int) sizeof(rspamd_sk_t));
+               BN_bn2bin(bn_sec, sk);
+
+               g_assert(EVP_PKEY_get_octet_string_param(pkey, "pub", pk,
+                                                                                                sizeof(rspamd_pk_t), &len) == 1);
+
+               g_assert(len <= (int) sizeof(rspamd_pk_t));
+
+               BN_free(bn_sec);
+               EVP_PKEY_free(pkey);
+               OSSL_LIB_CTX_free(libctx);
+#else
+               const EC_POINT *ec_pub;
+               EC_GROUP *group;
+               const BIGNUM *bn_sec;
+
+               EC_KEY *ec_sec;
 
                ec_sec = EC_KEY_new_by_curve_name(CRYPTOBOX_CURVE_NID);
                g_assert(ec_sec != NULL);
@@ -353,14 +378,8 @@ void rspamd_cryptobox_keypair(rspamd_pk_t pk, rspamd_sk_t sk,
                g_assert(bn_sec != NULL);
                ec_pub = EC_KEY_get0_public_key(ec_sec);
                g_assert(ec_pub != NULL);
-#if OPENSSL_VERSION_MAJOR >= 3
-               unsigned char *buf = NULL; /* Thanks openssl for this API (no) */
-               len = EC_POINT_point2buf(EC_KEY_get0_group(ec_sec), ec_pub,
-                                                                POINT_CONVERSION_UNCOMPRESSED, &buf, NULL);
-               g_assert(len <= (int) rspamd_cryptobox_pk_bytes(mode));
-               memcpy(pk, buf, len);
-               OPENSSL_free(buf);
-#else
+
+               group = EC_KEY_get0_group(ec_sec);
                BIGNUM *bn_pub;
                bn_pub = EC_POINT_point2bn(EC_KEY_get0_group(ec_sec),
                                                                   ec_pub, POINT_CONVERSION_UNCOMPRESSED, NULL, NULL);
@@ -368,13 +387,14 @@ void rspamd_cryptobox_keypair(rspamd_pk_t pk, rspamd_sk_t sk,
                g_assert(len <= (int) rspamd_cryptobox_pk_bytes(mode));
                BN_bn2bin(bn_pub, pk);
                BN_free(bn_pub);
-#endif
+               EC_KEY_free(ec_sec);
 
                len = BN_num_bytes(bn_sec);
                g_assert(len <= (int) sizeof(rspamd_sk_t));
                BN_bn2bin(bn_sec, sk);
 
-               EC_KEY_free(ec_sec);
+               EC_GROUP_free(group);
+#endif
 #endif
        }
 }
@@ -389,10 +409,33 @@ void rspamd_cryptobox_keypair_sig(rspamd_sig_pk_t pk, rspamd_sig_sk_t sk,
 #ifndef HAVE_USABLE_OPENSSL
                g_assert(0);
 #else
-               EC_KEY *ec_sec;
-               const BIGNUM *bn_sec;
+
                const EC_POINT *ec_pub;
+               EC_GROUP *group;
                gsize len;
+#if OPENSSL_VERSION_MAJOR >= 3
+               OSSL_LIB_CTX *libctx = OSSL_LIB_CTX_new();
+               EVP_PKEY *pkey = EVP_PKEY_Q_keygen(libctx, NULL, "EC", EC_curve_nid2nist(CRYPTOBOX_CURVE_NID));
+               g_assert(pkey != NULL);
+
+               BIGNUM *bn_sec = NULL;
+               g_assert(EVP_PKEY_get_bn_param(pkey, "priv", &bn_sec) == 1);
+
+               len = BN_num_bytes(bn_sec);
+               g_assert(len <= (int) sizeof(rspamd_sk_t));
+               BN_bn2bin(bn_sec, sk);
+
+               EVP_PKEY_get_octet_string_param(pkey, "pub", pk,
+                                                                               sizeof(rspamd_pk_t), &len);
+
+               g_assert(len <= (int) sizeof(rspamd_pk_t));
+
+               BN_free(bn_sec);
+               EVP_PKEY_free(pkey);
+               OSSL_LIB_CTX_free(libctx);
+#else
+               EC_KEY *ec_sec;
+               const BIGNUM *bn_sec;
 
                ec_sec = EC_KEY_new_by_curve_name(CRYPTOBOX_CURVE_NID);
                g_assert(ec_sec != NULL);
@@ -403,14 +446,8 @@ void rspamd_cryptobox_keypair_sig(rspamd_sig_pk_t pk, rspamd_sig_sk_t sk,
                ec_pub = EC_KEY_get0_public_key(ec_sec);
                g_assert(ec_pub != NULL);
 
-#if OPENSSL_VERSION_MAJOR >= 3
-               unsigned char *buf = NULL; /* Thanks openssl for this API (no) */
-               len = EC_POINT_point2buf(EC_KEY_get0_group(ec_sec), ec_pub,
-                                                                POINT_CONVERSION_UNCOMPRESSED, &buf, NULL);
-               g_assert(len <= (int) rspamd_cryptobox_pk_bytes(mode));
-               memcpy(pk, buf, len);
-               OPENSSL_free(buf);
-#else
+               group = EC_KEY_get0_group(ec_sec);
+
                BIGNUM *bn_pub;
                bn_pub = EC_POINT_point2bn(EC_KEY_get0_group(ec_sec),
                                                                   ec_pub, POINT_CONVERSION_UNCOMPRESSED, NULL, NULL);
@@ -418,12 +455,13 @@ void rspamd_cryptobox_keypair_sig(rspamd_sig_pk_t pk, rspamd_sig_sk_t sk,
                g_assert(len <= (int) rspamd_cryptobox_pk_bytes(mode));
                BN_bn2bin(bn_pub, pk);
                BN_free(bn_pub);
-#endif
-
+               EC_KEY_free(ec_sec);
                len = BN_num_bytes(bn_sec);
                g_assert(len <= (int) sizeof(rspamd_sk_t));
                BN_bn2bin(bn_sec, sk);
-               EC_KEY_free(ec_sec);
+#endif
+
+               EC_GROUP_free(group);
 #endif
        }
 }
@@ -494,11 +532,67 @@ void rspamd_cryptobox_nm(rspamd_nm_t nm,
 #ifndef HAVE_USABLE_OPENSSL
                g_assert(0);
 #else
+               int len;
+               unsigned char s[32];
+
+#if OPENSSL_VERSION_MAJOR >= 3
+               EVP_PKEY *sec_pkey = NULL;
+               EVP_PKEY *pub_pkey = NULL;
+               OSSL_LIB_CTX *libctx = OSSL_LIB_CTX_new();
+               EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_from_name(libctx, "EC", NULL);
+               EVP_PKEY_CTX *dctx = EVP_PKEY_CTX_new_from_name(libctx, "EC", NULL);
+               OSSL_PARAM_BLD *param_bld;
+               OSSL_PARAM *params = NULL;
+               BIGNUM *bn_sec;
+
+               param_bld = OSSL_PARAM_BLD_new();
+               g_assert(OSSL_PARAM_BLD_push_utf8_string(param_bld, "group",
+                                                                                                EC_curve_nid2nist(CRYPTOBOX_CURVE_NID), 0) == 1);
+
+               bn_sec = BN_bin2bn(sk, sizeof(rspamd_sk_t), NULL);
+               g_assert(bn_sec != NULL);
+
+               g_assert(OSSL_PARAM_BLD_push_BN(param_bld, "priv", bn_sec) == 1);
+               params = OSSL_PARAM_BLD_to_param(param_bld);
+
+               g_assert(EVP_PKEY_fromdata_init(pctx) == 1);
+               g_assert(EVP_PKEY_fromdata(pctx, &sec_pkey, EVP_PKEY_KEYPAIR, params) == 1);
+               EVP_PKEY_CTX_free(pctx);
+               pctx = EVP_PKEY_CTX_new_from_pkey(libctx, sec_pkey, NULL);
+
+               OSSL_PARAM_free(params);
+               OSSL_PARAM_BLD_free(param_bld);
+               param_bld = OSSL_PARAM_BLD_new();
+
+               g_assert(OSSL_PARAM_BLD_push_utf8_string(param_bld, "group",
+                                                                                                EC_curve_nid2nist(CRYPTOBOX_CURVE_NID), 0) == 1);
+
+               g_assert(OSSL_PARAM_BLD_push_octet_string(param_bld, "pub", pk, sizeof(rspamd_pk_t)) == 1);
+               params = OSSL_PARAM_BLD_to_param(param_bld);
+               g_assert(params != NULL);
+
+               g_assert(EVP_PKEY_fromdata_init(dctx) == 1);
+               g_assert(EVP_PKEY_fromdata(dctx, &pub_pkey, EVP_PKEY_KEYPAIR, params) == 1);
+
+               g_assert(EVP_PKEY_derive_init(pctx) == 1);
+
+               EVP_PKEY_derive_set_peer(pctx, pub_pkey);
+
+               size_t s_len = sizeof(s);
+               g_assert(EVP_PKEY_derive(pctx, s, &s_len) == 1);
+
+               EVP_PKEY_CTX_free(pctx);
+               OSSL_PARAM_BLD_free(param_bld);
+               OSSL_PARAM_free(params);
+               BN_free(bn_sec);
+               EVP_PKEY_free(pub_pkey);
+               EVP_PKEY_free(sec_pkey);
+               OSSL_LIB_CTX_free(libctx);
+#else
+
                EC_KEY *lk;
                EC_POINT *ec_pub;
                BIGNUM *bn_pub, *bn_sec;
-               int len;
-               unsigned char s[32];
 
                lk = EC_KEY_new_by_curve_name(CRYPTOBOX_CURVE_NID);
                g_assert(lk != NULL);
@@ -511,16 +605,19 @@ void rspamd_cryptobox_nm(rspamd_nm_t nm,
                g_assert(EC_KEY_set_private_key(lk, bn_sec) == 1);
                ec_pub = ec_point_bn2point_compat(EC_KEY_get0_group(lk), bn_pub, NULL, NULL);
                g_assert(ec_pub != NULL);
+
                len = ECDH_compute_key(s, sizeof(s), ec_pub, lk, NULL);
                g_assert(len == sizeof(s));
 
-               /* Still do hchacha iteration since we are not using SHA1 KDF */
-               hchacha(s, n0, nm, 20);
-
                EC_KEY_free(lk);
+
                EC_POINT_free(ec_pub);
                BN_free(bn_sec);
                BN_free(bn_pub);
+#endif
+               /* Still do hchacha iteration since we are not using SHA1 KDF */
+               hchacha(s, n0, nm, 20);
+
 #endif
        }
 }
@@ -537,8 +634,6 @@ void rspamd_cryptobox_sign(unsigned char *sig, unsigned long long *siglen_p,
 #ifndef HAVE_USABLE_OPENSSL
                g_assert(0);
 #else
-               EC_KEY *lk;
-               BIGNUM *bn_sec;
                EVP_MD_CTX *sha_ctx;
                unsigned char h[64];
                unsigned int diglen = rspamd_cryptobox_signature_bytes(mode);
@@ -549,6 +644,46 @@ void rspamd_cryptobox_sign(unsigned char *sig, unsigned long long *siglen_p,
                EVP_DigestUpdate(sha_ctx, m, mlen);
                EVP_DigestFinal(sha_ctx, h, NULL);
 
+               /* ECDSA */
+#if OPENSSL_VERSION_MAJOR >= 3
+               EVP_PKEY *pkey = NULL;
+               OSSL_LIB_CTX *libctx = OSSL_LIB_CTX_new();
+               EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_from_name(libctx, "EC", NULL);
+               OSSL_PARAM_BLD *param_bld;
+               OSSL_PARAM *params = NULL;
+               BIGNUM *bn_sec;
+
+               param_bld = OSSL_PARAM_BLD_new();
+               g_assert(OSSL_PARAM_BLD_push_utf8_string(param_bld, "group",
+                                                                                                EC_curve_nid2nist(CRYPTOBOX_CURVE_NID), 0) == 1);
+
+               bn_sec = BN_bin2bn(sk, sizeof(rspamd_sk_t), NULL);
+               g_assert(bn_sec != NULL);
+
+               g_assert(OSSL_PARAM_BLD_push_BN(param_bld, "priv", bn_sec) == 1);
+
+               params = OSSL_PARAM_BLD_to_param(param_bld);
+               g_assert(EVP_PKEY_fromdata_init(pctx) == 1);
+               g_assert(EVP_PKEY_fromdata(pctx, &pkey, EVP_PKEY_KEYPAIR, params) == 1);
+
+               g_assert(pkey != NULL);
+
+               g_assert(EVP_DigestSignInit(sha_ctx, NULL, EVP_sha512(), NULL, pkey) == 1);
+
+               size_t diglen_size_t = diglen;\
+               EVP_DigestSign(sha_ctx, sig, &diglen_size_t, m, mlen);
+               diglen = diglen_size_t;
+
+               EVP_PKEY_CTX_free(pctx);
+               OSSL_PARAM_BLD_free(param_bld);
+               OSSL_PARAM_free(params);
+               BN_free(bn_sec);
+               EVP_PKEY_free(pkey);
+               OSSL_LIB_CTX_free(libctx);
+#else
+               EC_KEY *lk;
+               BIGNUM *bn_sec;
+
                /* Key setup */
                lk = EC_KEY_new_by_curve_name(CRYPTOBOX_CURVE_NID);
                g_assert(lk != NULL);
@@ -556,19 +691,185 @@ void rspamd_cryptobox_sign(unsigned char *sig, unsigned long long *siglen_p,
                g_assert(bn_sec != NULL);
                g_assert(EC_KEY_set_private_key(lk, bn_sec) == 1);
 
+               g_assert(ECDSA_sign(0, h, sizeof(h), sig, &diglen, lk) == 1);
+               EC_KEY_free(lk);
+               BN_free(bn_sec);
+#endif
+               g_assert(diglen <= sizeof(rspamd_signature_t));
+
+               if (siglen_p) {
+                       *siglen_p = diglen;
+               }
+
+               EVP_MD_CTX_destroy(sha_ctx);
+#endif
+       }
+}
+
+void rspamd_cryptobox_sign_compat(int nid, unsigned char *sig, unsigned long long *siglen_p,
+                                                                 const unsigned char *m, gsize mlen,
+                                                                 struct evp_pkey_st *sec_key,
+                                                                 enum rspamd_cryptobox_mode mode)
+{
+       if (G_LIKELY(mode == RSPAMD_CRYPTOBOX_MODE_25519)) {
+               rspamd_sk_t sk;
+               size_t sk_len = sizeof(rspamd_sk_t);
+               EVP_PKEY_get_raw_private_key(sec_key, sk, &sk_len);
+               crypto_sign_detached(sig, siglen_p, m, mlen, sk);
+       }
+       else {
+#ifndef HAVE_USABLE_OPENSSL
+               g_assert(0);
+#else
+               EVP_MD_CTX *sha_ctx;
+               unsigned char h[64];
+               unsigned int diglen = rspamd_cryptobox_signature_bytes(mode);
+
+               /* Prehash */
+               sha_ctx = EVP_MD_CTX_create();
+               EVP_MD *type = NULL;
+               switch(nid)
+               {
+               case NID_sha1:
+                       type = EVP_sha1();
+                       break;
+               case NID_sha256:
+                       type = EVP_sha256();
+                       break;
+               case NID_sha512:
+                       type = EVP_sha512();
+                       break;
+               default:
+                       type = NULL;
+               }
+               g_assert(EVP_DigestInit(sha_ctx, type) == 1);
+               EVP_DigestUpdate(sha_ctx, m, mlen);
+               EVP_DigestFinal(sha_ctx, h, NULL);
+
                /* ECDSA */
+#if OPENSSL_VERSION_MAJOR >= 3
+               EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new(sec_key, NULL);
+
+               EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PADDING);
+
+               g_assert(EVP_DigestSignInit(sha_ctx, NULL, type, NULL, sec_key) == 1);
+
+               size_t diglen_size_t = diglen;
+               EVP_DigestSign(sha_ctx, sig, &diglen_size_t, m, mlen);
+               diglen = diglen_size_t;
+
+               EVP_PKEY_CTX_free(pctx);
+               EVP_PKEY_free(sec_key);
+#else
+               EC_KEY *lk;
+               BIGNUM *bn_sec;
+
+               /* Key setup */
+               lk = EC_KEY_new_by_curve_name(CRYPTOBOX_CURVE_NID);
+               g_assert(lk != NULL);
+               bn_sec = BN_bin2bn(sk, sizeof(rspamd_sk_t), NULL);
+               g_assert(bn_sec != NULL);
+               g_assert(EC_KEY_set_private_key(lk, bn_sec) == 1);
+
                g_assert(ECDSA_sign(0, h, sizeof(h), sig, &diglen, lk) == 1);
+               EC_KEY_free(lk);
+               BN_free(bn_sec);
+#endif
                g_assert(diglen <= sizeof(rspamd_signature_t));
 
                if (siglen_p) {
                        *siglen_p = diglen;
                }
 
+               EVP_MD_CTX_destroy(sha_ctx);
+#endif
+       }
+}
+
+bool rspamd_cryptobox_verify_compat(int nid,
+                                                                       const unsigned char *sig,
+                                                                       gsize siglen,
+                                                                       const unsigned char *m,
+                                                                       gsize mlen,
+                                                                       struct evp_pkey_st *pub_key,
+                                                                       enum rspamd_cryptobox_mode mode)
+{
+       bool ret = false;
+
+       if (G_LIKELY(mode == RSPAMD_CRYPTOBOX_MODE_25519)) {
+               if (siglen == rspamd_cryptobox_signature_bytes(RSPAMD_CRYPTOBOX_MODE_25519)) {
+                       rspamd_pk_t pk;
+                       size_t len_pk = sizeof(rspamd_pk_t);
+                       EVP_PKEY_get_raw_public_key(pub_key, pk, &len_pk);
+                       ret = (crypto_sign_verify_detached(sig, m, mlen, pk) == 0);
+               }
+       }
+       else {
+#ifndef HAVE_USABLE_OPENSSL
+               g_assert(0);
+#else
+               EVP_MD_CTX *sha_ctx;
+               unsigned char h[64];
+
+               /* Prehash */
+               sha_ctx = EVP_MD_CTX_create();
+               EVP_MD *type = NULL;
+               switch(nid)
+               {
+               case NID_sha1:
+                       type = EVP_sha1();
+                       break;
+               case NID_sha256:
+                       type = EVP_sha256();
+                       break;
+               case NID_sha512:
+                       type = EVP_sha512();
+                       break;
+               default:
+                       type = NULL;
+               }
+               g_assert(EVP_DigestInit(sha_ctx, type) == 1);
+               EVP_DigestUpdate(sha_ctx, m, mlen);
+               EVP_DigestFinal(sha_ctx, h, NULL);
+
+
+#if OPENSSL_VERSION_MAJOR >= 3
+               EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new(pub_key, NULL);
+
+               g_assert(EVP_DigestVerifyInit(sha_ctx, NULL, type, NULL, pub_key) == 1);
+
+               ret = (EVP_DigestVerify(sha_ctx, sig, siglen, m, mlen) == 1);
+
+               EVP_PKEY_free(pub_key);
+               EVP_PKEY_CTX_free(pctx);
+#else
+               EC_KEY *lk;
+               EC_POINT *ec_pub;
+               BIGNUM *bn_pub;
+
+               /* Key setup */
+               lk = EC_KEY_new_by_curve_name(CRYPTOBOX_CURVE_NID);
+               g_assert(lk != NULL);
+               bn_pub = BN_bin2bn(pk, rspamd_cryptobox_pk_bytes(mode), NULL);
+               g_assert(bn_pub != NULL);
+               ec_pub = ec_point_bn2point_compat(EC_KEY_get0_group(lk), bn_pub, NULL, NULL);
+               g_assert(ec_pub != NULL);
+               g_assert(EC_KEY_set_public_key(lk, ec_pub) == 1);
+
+               /* ECDSA */
+               ret = ECDSA_verify(0, h, sizeof(h), sig, siglen, lk) == 1;
+
                EC_KEY_free(lk);
+
+               BN_free(bn_pub);
+               EC_POINT_free(ec_pub);
+#endif
+
                EVP_MD_CTX_destroy(sha_ctx);
-               BN_free(bn_sec);
 #endif
        }
+
+       return ret;
 }
 
 bool rspamd_cryptobox_verify(const unsigned char *sig,
@@ -589,9 +890,6 @@ bool rspamd_cryptobox_verify(const unsigned char *sig,
 #ifndef HAVE_USABLE_OPENSSL
                g_assert(0);
 #else
-               EC_KEY *lk;
-               EC_POINT *ec_pub;
-               BIGNUM *bn_pub;
                EVP_MD_CTX *sha_ctx;
                unsigned char h[64];
 
@@ -601,6 +899,41 @@ bool rspamd_cryptobox_verify(const unsigned char *sig,
                EVP_DigestUpdate(sha_ctx, m, mlen);
                EVP_DigestFinal(sha_ctx, h, NULL);
 
+
+#if OPENSSL_VERSION_MAJOR >= 3
+               EVP_PKEY *pkey = NULL;
+               OSSL_LIB_CTX *libctx = OSSL_LIB_CTX_new();
+               EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_from_name(libctx, "EC", NULL);
+               OSSL_PARAM_BLD *param_bld;
+               OSSL_PARAM *params = NULL;
+
+               param_bld = OSSL_PARAM_BLD_new();
+               g_assert(OSSL_PARAM_BLD_push_utf8_string(param_bld, "group",
+                                                                                                EC_curve_nid2nist(CRYPTOBOX_CURVE_NID), 0) == 1);
+
+               g_assert(OSSL_PARAM_BLD_push_octet_string(param_bld, "pub", pk, sizeof(rspamd_pk_t)) == 1);
+
+               params = OSSL_PARAM_BLD_to_param(param_bld);
+               g_assert(EVP_PKEY_fromdata_init(pctx) == 1);
+               g_assert(EVP_PKEY_fromdata(pctx, &pkey, EVP_PKEY_PUBLIC_KEY, params) == 1);
+
+               g_assert(pkey != NULL);
+
+               g_assert(EVP_DigestVerifyInit(sha_ctx, NULL, EVP_sha512(), NULL, pkey) == 1);
+
+               if(EVP_DigestVerify(sha_ctx, sig, siglen, m, mlen) == 1)
+                       ret = true;
+
+               EVP_PKEY_free(pkey);
+               EVP_PKEY_CTX_free(pctx);
+               OSSL_PARAM_free(params);
+               OSSL_PARAM_BLD_free(param_bld);
+               OSSL_LIB_CTX_free(libctx);
+#else
+               EC_KEY *lk;
+               EC_POINT *ec_pub;
+               BIGNUM *bn_pub;
+
                /* Key setup */
                lk = EC_KEY_new_by_curve_name(CRYPTOBOX_CURVE_NID);
                g_assert(lk != NULL);
@@ -614,10 +947,13 @@ bool rspamd_cryptobox_verify(const unsigned char *sig,
                ret = ECDSA_verify(0, h, sizeof(h), sig, siglen, lk) == 1;
 
                EC_KEY_free(lk);
-               EVP_MD_CTX_destroy(sha_ctx);
+
                BN_free(bn_pub);
                EC_POINT_free(ec_pub);
 #endif
+
+               EVP_MD_CTX_destroy(sha_ctx);
+#endif
        }
 
        return ret;
@@ -1288,9 +1624,9 @@ void rspamd_cryptobox_siphash(unsigned char *out, const unsigned char *in,
 }
 
 /*
- * Password-Based Key Derivation Function 2 (PKCS #5 v2.0).
- * Code based on IEEE Std 802.11-2007, Annex H.4.2.
- */
+* Password-Based Key Derivation Function 2 (PKCS #5 v2.0).
+* Code based on IEEE Std 802.11-2007, Annex H.4.2.
+*/
 static gboolean
 rspamd_cryptobox_pbkdf2(const char *pass, gsize pass_len,
                                                const uint8_t *salt, gsize salt_len, uint8_t *key, gsize key_len,
@@ -1327,9 +1663,9 @@ rspamd_cryptobox_pbkdf2(const char *pass, gsize pass_len,
                        uint8_t k[crypto_generichash_blake2b_BYTES_MAX];
 
                        /*
-                        * We use additional blake2 iteration to store large key
-                        * XXX: it is not compatible with the original implementation but safe
-                        */
+                       * We use additional blake2 iteration to store large key
+                       * XXX: it is not compatible with the original implementation but safe
+                       */
                        crypto_generichash_blake2b(k, sizeof(k), pass, pass_len,
                                                                           NULL, 0);
                        crypto_generichash_blake2b(d1, sizeof(d1), asalt, salt_len + 4,
@@ -1347,9 +1683,9 @@ rspamd_cryptobox_pbkdf2(const char *pass, gsize pass_len,
                                uint8_t k[crypto_generichash_blake2b_BYTES_MAX];
 
                                /*
-                                * We use additional blake2 iteration to store large key
-                                * XXX: it is not compatible with the original implementation but safe
-                                */
+                               * We use additional blake2 iteration to store large key
+                               * XXX: it is not compatible with the original implementation but safe
+                               */
                                crypto_generichash_blake2b(k, sizeof(k), pass, pass_len,
                                                                                   NULL, 0);
                                crypto_generichash_blake2b(d2, sizeof(d2), d1, sizeof(d1),
@@ -1458,6 +1794,26 @@ unsigned int rspamd_cryptobox_signature_bytes(enum rspamd_cryptobox_mode mode)
        else {
 #ifndef HAVE_USABLE_OPENSSL
                g_assert(0);
+#else
+#if OPENSSL_VERSION_MAJOR >= 3
+               if (ssl_keylen == 0) {
+                       OSSL_LIB_CTX *libctx = OSSL_LIB_CTX_new();
+                       EVP_MD_CTX *sha_ctx = EVP_MD_CTX_new();
+                       EVP_PKEY *pkey = EVP_PKEY_Q_keygen(libctx, NULL, "EC", "prime256v1");
+                       g_assert(pkey != NULL);
+
+                       g_assert(EVP_DigestSignInit(sha_ctx, NULL, EVP_sha512(), NULL, pkey) == 1);
+
+                       size_t keylen = 0;
+                       const unsigned char data[] = "data to be signed";
+                       size_t datalen = sizeof(data) - 1;
+                       g_assert(EVP_DigestSign(sha_ctx, NULL, &keylen, data, datalen) == 1);
+                       ssl_keylen = keylen;
+
+                       OSSL_LIB_CTX_free(libctx);
+                       EVP_PKEY_free(pkey);
+                       EVP_MD_CTX_free(sha_ctx);
+               }
 #else
                if (ssl_keylen == 0) {
                        EC_KEY *lk;
@@ -1465,6 +1821,7 @@ unsigned int rspamd_cryptobox_signature_bytes(enum rspamd_cryptobox_mode mode)
                        ssl_keylen = ECDSA_size(lk);
                        EC_KEY_free(lk);
                }
+#endif
 #endif
                return ssl_keylen;
        }
@@ -1489,8 +1846,8 @@ void rspamd_cryptobox_hash_init(rspamd_cryptobox_hash_state_t *p, const unsigned
 }
 
 /**
- * Update hash with data portion
- */
+* Update hash with data portion
+*/
 void rspamd_cryptobox_hash_update(rspamd_cryptobox_hash_state_t *p, const unsigned char *data, gsize len)
 {
        crypto_generichash_blake2b_state *st = cryptobox_align_ptr(p,
@@ -1499,8 +1856,8 @@ void rspamd_cryptobox_hash_update(rspamd_cryptobox_hash_state_t *p, const unsign
 }
 
 /**
- * Output hash to the buffer of rspamd_cryptobox_HASHBYTES length
- */
+* Output hash to the buffer of rspamd_cryptobox_HASHBYTES length
+*/
 void rspamd_cryptobox_hash_final(rspamd_cryptobox_hash_state_t *p, unsigned char *out)
 {
        crypto_generichash_blake2b_state *st = cryptobox_align_ptr(p,
@@ -1509,8 +1866,8 @@ void rspamd_cryptobox_hash_final(rspamd_cryptobox_hash_state_t *p, unsigned char
 }
 
 /**
- * One in all function
- */
+* One in all function
+*/
 void rspamd_cryptobox_hash(unsigned char *out,
                                                   const unsigned char *data,
                                                   gsize len,
@@ -1729,8 +2086,8 @@ rspamd_cryptobox_fast_hash_final(rspamd_cryptobox_fast_hash_state_t *st)
 }
 
 /**
- * One in all function
- */
+* One in all function
+*/
 static inline uint64_t
 rspamd_cryptobox_fast_hash_machdep(const void *data,
                                                                   gsize len, uint64_t seed)
@@ -1775,4 +2132,4 @@ rspamd_cryptobox_fast_hash_specific(
        default:
                return rspamd_cryptobox_fast_hash_machdep(data, len, seed);
        }
-}
+}
\ No newline at end of file