From 799541e954ae87784cb69d43d6e41a85f790c28c Mon Sep 17 00:00:00 2001 From: Prasanth Dendukuri Date: Sun, 7 Jun 2026 22:05:59 -0700 Subject: [PATCH] add AWS-LC compatibility --- cmake/findcoredeps.cmake | 10 ++ openvpn/openssl/aws-lc-compat.hpp | 122 +++++++++++++++++++++++++ openvpn/openssl/bio/bio_memq_dgram.hpp | 1 + openvpn/openssl/compat.hpp | 4 + openvpn/openssl/crypto/cipheraead.hpp | 1 + openvpn/openssl/crypto/tls1prf.hpp | 5 + openvpn/openssl/pki/extpki.hpp | 6 +- openvpn/openssl/sign/pkcs7verify.hpp | 1 + openvpn/openssl/ssl/sslctx.hpp | 7 +- openvpn/openssl/util/error.hpp | 9 ++ 10 files changed, 160 insertions(+), 6 deletions(-) create mode 100644 openvpn/openssl/aws-lc-compat.hpp diff --git a/cmake/findcoredeps.cmake b/cmake/findcoredeps.cmake index 2657aa4f3..6114ab794 100644 --- a/cmake/findcoredeps.cmake +++ b/cmake/findcoredeps.cmake @@ -8,6 +8,7 @@ set(CORE_DIR ${CMAKE_CURRENT_LIST_DIR}/..) set(DEP_DIR ${CORE_DIR}/../deps CACHE PATH "Dependencies") option(USE_MBEDTLS "Use mbed TLS instead of OpenSSL") +option(USE_AWSLC "Use AWS-LC as the crypto/SSL backend instead of the default") option(USE_WERROR "Treat compiler warnings as errors (-Werror)") option(USE_WCONVERSION "Enable -Wconversion") @@ -43,6 +44,15 @@ function(add_ssl_library target) set(SSL_LIBRARY mbedTLS::mbedTLS) endif () target_compile_definitions(${target} PRIVATE -DUSE_MBEDTLS) + elseif (${USE_AWSLC}) + if (NOT OPENSSL_ROOT_DIR) + message(FATAL_ERROR "USE_AWSLC requires -DOPENSSL_ROOT_DIR=/path/to/aws-lc/install") + endif () + find_package(OpenSSL REQUIRED) + set(SSL_LIBRARY OpenSSL::SSL OpenSSL::Crypto) + include_directories(BEFORE SYSTEM "${OPENSSL_INCLUDE_DIR}") + message(STATUS "Using AWS-LC from: ${OPENSSL_ROOT_DIR}") + target_compile_definitions(${target} PRIVATE -DUSE_OPENSSL) else () pkg_search_module(OpenSSL REQUIRED IMPORTED_TARGET openssl) SET(SSL_LIBRARY PkgConfig::OpenSSL) diff --git a/openvpn/openssl/aws-lc-compat.hpp b/openvpn/openssl/aws-lc-compat.hpp new file mode 100644 index 000000000..4772d1c16 --- /dev/null +++ b/openvpn/openssl/aws-lc-compat.hpp @@ -0,0 +1,122 @@ +// OpenVPN -- An application to securely tunnel IP networks +// over a single port, with support for SSL/TLS-based +// session authentication and key exchange, +// packet encryption, packet authentication, and +// packet compression. +// +// Copyright (C) 2012- OpenVPN Inc. +// +// SPDX-License-Identifier: MPL-2.0 OR AGPL-3.0-only WITH openvpn3-openssl-exception +// + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define BIO_F_MEM_WRITE 0 +#define BIO_F_MEM_READ 0 +#define BIOerr(f, r) ERR_put_error(ERR_LIB_BIO, (f), (r), __FILE__, __LINE__) + +#define EVP_PKEY_DSA1 (-101) +#define EVP_PKEY_DSA2 (-102) +#define EVP_PKEY_DSA3 (-103) +#define EVP_PKEY_DSA4 (-104) + +/* AWS-LC's GCM reads a NULL input as "finalize", so empty AAD/data (in=NULL, inl=0) + * would prematurely compute the tag. Substitute a valid zero length buffer so it + * stays a no-op. */ +static inline int +EVP_EncryptUpdate_wrapper(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl, const unsigned char *in, int inl) +{ + static unsigned char empty_buf[1] = {0}; + if (inl == 0 && in == nullptr) + in = empty_buf; + return EVP_EncryptUpdate(ctx, out, outl, in, inl); +} +#define EVP_EncryptUpdate EVP_EncryptUpdate_wrapper + +static inline int +EVP_DecryptUpdate_wrapper(EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl, const unsigned char *in, int inl) +{ + static unsigned char empty_buf[1] = {0}; + if (inl == 0 && in == nullptr) + in = empty_buf; + return EVP_DecryptUpdate(ctx, out, outl, in, inl); +} +#define EVP_DecryptUpdate EVP_DecryptUpdate_wrapper + + +/* AWS-LC has no RSA_set_app_data or RSA_get_app_data. Re-provide them so a + * pointer can be attached to an RSA object and read back later. */ +static inline int RSA_app_data_index() +{ + static int idx = RSA_get_ex_new_index(0, nullptr, nullptr, nullptr, nullptr); + return idx; +} + +static inline int RSA_set_app_data(RSA *rsa, void *data) +{ + return RSA_set_ex_data(rsa, RSA_app_data_index(), data); +} + +static inline void *RSA_get_app_data(const RSA *rsa) +{ + return RSA_get_ex_data(rsa, RSA_app_data_index()); +} + +/* AWS-LC defines EC_KEY_METHOD_set_sign as a macro that static_asserts + * |sign_setup| == NULL. Override it to accept and drop |sign_setup| instead. */ +static inline void +EC_KEY_METHOD_set_sign_wrapper( + EC_KEY_METHOD *meth, + int (*sign)(int type, const unsigned char *dgst, int dlen, + unsigned char *sig, unsigned int *siglen, + const BIGNUM *kinv, const BIGNUM *r, EC_KEY *eckey), + int (*)(EC_KEY *eckey, BN_CTX *ctx, BIGNUM **kinvp, BIGNUM **rp), + ECDSA_SIG *(*sign_sig)(const unsigned char *dgst, int dgst_len, + const BIGNUM *in_kinv, const BIGNUM *in_r, + EC_KEY *eckey)) +{ + EC_KEY_METHOD_set_sign_awslc(meth, sign, sign_sig); +} +#undef EC_KEY_METHOD_set_sign +#define EC_KEY_METHOD_set_sign EC_KEY_METHOD_set_sign_wrapper + +/* AWS-LC's PKCS7_verify rejects a NULL store even under PKCS7_NOVERIFY, where it + * goes unused. Pass an empty store when none is given. */ +static inline int +PKCS7_verify_wrapper(PKCS7 *p7, STACK_OF(X509) *certs, X509_STORE *store, BIO *indata, BIO *out, int flags) +{ + static X509_STORE *empty_store = X509_STORE_new(); + return PKCS7_verify(p7, certs, store ? store : empty_store, indata, out, flags); +} +#define PKCS7_verify PKCS7_verify_wrapper + +static inline bool +CRYPTO_tls1_prf_wrapper(unsigned char *out, + size_t out_len, + const unsigned char *secret, + size_t secret_len, + const unsigned char *label, + size_t label_len) +{ + return CRYPTO_tls1_prf(EVP_md5_sha1(), + out, out_len, + secret, secret_len, + reinterpret_cast(label), label_len, + nullptr, 0, + nullptr, 0) + == 1; +} diff --git a/openvpn/openssl/bio/bio_memq_dgram.hpp b/openvpn/openssl/bio/bio_memq_dgram.hpp index adda18924..9344a432c 100644 --- a/openvpn/openssl/bio/bio_memq_dgram.hpp +++ b/openvpn/openssl/bio/bio_memq_dgram.hpp @@ -20,6 +20,7 @@ #include #include +#include #include #include #include diff --git a/openvpn/openssl/compat.hpp b/openvpn/openssl/compat.hpp index 7d99559c6..2f0bfe6cf 100644 --- a/openvpn/openssl/compat.hpp +++ b/openvpn/openssl/compat.hpp @@ -20,7 +20,11 @@ #include #include #include +#include +#ifdef OPENSSL_IS_AWSLC + #include +#endif /* Note that this is not a perfect emulation of the new function but * is good enough for our case of printing certificate details during diff --git a/openvpn/openssl/crypto/cipheraead.hpp b/openvpn/openssl/crypto/cipheraead.hpp index 319d02c0e..0e255e22e 100644 --- a/openvpn/openssl/crypto/cipheraead.hpp +++ b/openvpn/openssl/crypto/cipheraead.hpp @@ -26,6 +26,7 @@ #include #include #include +#include namespace openvpn::OpenSSLCrypto { class CipherContextAEAD diff --git a/openvpn/openssl/crypto/tls1prf.hpp b/openvpn/openssl/crypto/tls1prf.hpp index b52e63788..491d13c19 100644 --- a/openvpn/openssl/crypto/tls1prf.hpp +++ b/openvpn/openssl/crypto/tls1prf.hpp @@ -20,6 +20,7 @@ #include #include +#include namespace openvpn::OpenSSLCrypto { @@ -78,6 +79,9 @@ class TLS1PRF unsigned char *out1, const size_t olen) { +#ifdef OPENSSL_IS_AWSLC + return CRYPTO_tls1_prf_wrapper(out1, olen, sec, slen, label, label_len); +#else /* TODO use EVP_PKEY_CTX_new_from_name and library context for OpenSSL 3.0 but * this needs passing the library context down here.*/ using EVP_PKEY_CTX_ptr = std::unique_ptr; @@ -108,6 +112,7 @@ class TLS1PRF return false; return true; +#endif } #endif }; diff --git a/openvpn/openssl/pki/extpki.hpp b/openvpn/openssl/pki/extpki.hpp index 94cd19f31..b0aad3a2a 100644 --- a/openvpn/openssl/pki/extpki.hpp +++ b/openvpn/openssl/pki/extpki.hpp @@ -46,7 +46,6 @@ class ExternalPKIRsaImpl : public ExternalPKIImpl RSA_meth_set_priv_dec(rsa_meth, rsa_priv_dec); RSA_meth_set_init(rsa_meth, nullptr); RSA_meth_set_finish(rsa_meth, rsa_finish); - RSA_meth_set0_app_data(rsa_meth, this); /* get the public key */ @@ -75,6 +74,7 @@ class ExternalPKIRsaImpl : public ExternalPKIImpl /* only set e and n as d (private key) is outside our control */ RSA_set0_key(rsa, BN_dup(RSA_get0_n(pub_rsa)), BN_dup(RSA_get0_e(pub_rsa)), nullptr); RSA_set_flags(rsa, RSA_FLAG_EXT_PKEY); + RSA_set_app_data(rsa, this); if (!RSA_set_method(rsa, rsa_meth)) { @@ -122,7 +122,7 @@ class ExternalPKIRsaImpl : public ExternalPKIImpl static int rsa_priv_enc(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding) { - ExternalPKIRsaImpl *self = (ExternalPKIRsaImpl *)(RSA_meth_get0_app_data(RSA_get_method(rsa))); + ExternalPKIRsaImpl *self = (ExternalPKIRsaImpl *)RSA_get_app_data(rsa); try { @@ -173,7 +173,7 @@ class ExternalPKIRsaImpl : public ExternalPKIImpl static void not_implemented(RSA *rsa) { - ExternalPKIRsaImpl *self = (ExternalPKIRsaImpl *)(RSA_meth_get0_app_data(RSA_get_method(rsa))); + ExternalPKIRsaImpl *self = (ExternalPKIRsaImpl *)RSA_get_app_data(rsa); ++self->n_errors; } diff --git a/openvpn/openssl/sign/pkcs7verify.hpp b/openvpn/openssl/sign/pkcs7verify.hpp index 783714fa3..df5a9f86b 100644 --- a/openvpn/openssl/sign/pkcs7verify.hpp +++ b/openvpn/openssl/sign/pkcs7verify.hpp @@ -23,6 +23,7 @@ #include #include #include +#include #include namespace openvpn::OpenSSLSign { diff --git a/openvpn/openssl/ssl/sslctx.hpp b/openvpn/openssl/ssl/sslctx.hpp index da8c0e452..9cce58c96 100644 --- a/openvpn/openssl/ssl/sslctx.hpp +++ b/openvpn/openssl/ssl/sslctx.hpp @@ -62,6 +62,7 @@ #include #include #include +#include #include #if ENABLE_EXTERNAL_PKI #if OPENSSL_VERSION_NUMBER >= 0x30000000L @@ -1100,7 +1101,7 @@ class OpenSSLContext : public SSLFactoryAPI const SSL_CIPHER *ciph = SSL_get_current_cipher(ssl); if (ciph) { - char *desc = SSL_CIPHER_description(ciph, nullptr, 0); + char *desc = const_cast(SSL_CIPHER_description(ciph, nullptr, 0)); if (!desc) { os << ", cipher: Error getting TLS cipher description from SSL_CIPHER_description"; @@ -1480,12 +1481,12 @@ class OpenSSLContext : public SSLFactoryAPI auto certType = EVP_PKEY_id(X509_get0_pubkey(config->cert.obj())); if (certType == EVP_PKEY_RSA) { - epki = std::make_shared(ExternalPKIRsaImpl(ctx.get(), config->cert.obj(), config->external_pki, config->external_pki_alias)); + epki = std::make_shared(ctx.get(), config->cert.obj(), config->external_pki, config->external_pki_alias); } #if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(OPENSSL_NO_EC) else if (certType == EVP_PKEY_EC) { - epki = std::make_shared(ExternalPKIECImpl(ctx.get(), config->cert.obj(), config->external_pki, config->external_pki_alias)); + epki = std::make_shared(ctx.get(), config->cert.obj(), config->external_pki, config->external_pki_alias); } #endif else diff --git a/openvpn/openssl/util/error.hpp b/openvpn/openssl/util/error.hpp index 719496689..91967afdc 100644 --- a/openvpn/openssl/util/error.hpp +++ b/openvpn/openssl/util/error.hpp @@ -22,6 +22,7 @@ #include #include #include +#include namespace openvpn { @@ -147,21 +148,27 @@ class OpenSSLException : public ExceptionCode case SSL_R_UNSUPPORTED_PROTOCOL: set_code(Error::TLS_VERSION_MIN, true); break; +#ifdef SSL_R_CA_MD_TOO_WEAK case SSL_R_CA_MD_TOO_WEAK: set_code(Error::SSL_CA_MD_TOO_WEAK, true); break; +#endif +#ifdef SSL_R_CA_KEY_TOO_SMALL case SSL_R_CA_KEY_TOO_SMALL: set_code(Error::SSL_CA_KEY_TOO_SMALL, true); break; +#endif #ifdef SSL_R_LEGACY_SIGALG_DISALLOWED_OR_UNSUPPORTED /* This error code has been added in OpenSSL 3.0.8 */ case SSL_R_LEGACY_SIGALG_DISALLOWED_OR_UNSUPPORTED: set_code(Error::TLS_SIGALG_DISALLOWED_OR_UNSUPPORTED, true); break; #endif +#ifdef SSL_R_DH_KEY_TOO_SMALL case SSL_R_DH_KEY_TOO_SMALL: set_code(Error::SSL_DH_KEY_TOO_SMALL, true); break; +#endif case SSL_R_TLSV1_ALERT_PROTOCOL_VERSION: set_code(Error::TLS_ALERT_PROTOCOL_VERSION, true); break; @@ -171,9 +178,11 @@ class OpenSSLException : public ExceptionCode case SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE: set_code(Error::TLS_ALERT_HANDSHAKE_FAILURE, true); break; +#ifdef SSL_R_TLSV13_ALERT_CERTIFICATE_REQUIRED case SSL_R_TLSV13_ALERT_CERTIFICATE_REQUIRED: set_code(Error::TLS_ALERT_CERTIFICATE_REQUIRED, true); break; +#endif case SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED: set_code(Error::TLS_ALERT_CERTIFICATE_EXPIRED, true); break;