From 388f7605e72c34c2b2a7dfddcb118cd687641a18 Mon Sep 17 00:00:00 2001 From: Justin W Smith <103147162+justsmth@users.noreply.github.com> Date: Wed, 10 Apr 2024 14:25:46 -0400 Subject: [PATCH 1/2] CI for compiling w/ Clang on Windows (#1520) --- .../workflows/{mingw.yml => windows-alt.yml} | 30 ++++++++++++++++++- tool/bssl_bm.h | 4 ++- 2 files changed, 32 insertions(+), 2 deletions(-) rename .github/workflows/{mingw.yml => windows-alt.yml} (59%) diff --git a/.github/workflows/mingw.yml b/.github/workflows/windows-alt.yml similarity index 59% rename from .github/workflows/mingw.yml rename to .github/workflows/windows-alt.yml index 8d7075ed60..3390603c5f 100644 --- a/.github/workflows/mingw.yml +++ b/.github/workflows/windows-alt.yml @@ -1,4 +1,4 @@ -name: MinGW +name: Windows Alternative Compilers on: pull_request: branches: [ '*' ] @@ -40,3 +40,31 @@ jobs: run: cmake --build ./build --target all - name: Run tests run: cmake --build ./build --target run_tests + clang: + if: github.repository == 'aws/aws-lc' + runs-on: windows-latest + steps: + - name: Install NASM + uses: ilammy/setup-nasm@v1.5.1 + - name: Checkout + uses: actions/checkout@v4 + - name: Install LLVM and Clang + uses: KyleMayes/install-llvm-action@v2 + id: clang + with: + version: 16 + env: true + - name: Setup CMake + uses: threeal/cmake-action@v1.3.0 + with: + generator: Ninja + c-compiler: "C:/Program Files/LLVM/bin/clang.exe" + cxx-compiler: "C:/Program Files/LLVM/bin/clang++.exe" + options: | + CMAKE_SYSTEM_NAME=Windows \ + CMAKE_SYSTEM_PROCESSOR=x86_64 \ + CMAKE_BUILD_TOOL=ninja.exe \ + - name: Build Project + run: cmake --build ./build --target all + - name: Run tests + run: cmake --build ./build --target run_tests diff --git a/tool/bssl_bm.h b/tool/bssl_bm.h index 247e36886e..2671b162f6 100644 --- a/tool/bssl_bm.h +++ b/tool/bssl_bm.h @@ -30,8 +30,10 @@ #if defined(INTERNAL_TOOL) #include <../crypto/ec_extra/internal.h> #include <../crypto/trust_token/internal.h> +#if defined(FIPS_ENTROPY_SOURCE_JITTER_CPU) #include "../third_party/jitterentropy/jitterentropy.h" -#endif +#endif // FIPS_ENTROPY_SOURCE_JITTER_CPU +#endif // INTERNAL_TOOL #define BM_NAMESPACE bssl #define BM_ECDSA_size(key) ECDSA_size(key) From dd247e288de4b17825a92620232d9266e6341009 Mon Sep 17 00:00:00 2001 From: Samuel Chiang Date: Wed, 10 Apr 2024 11:59:12 -0700 Subject: [PATCH 2/2] add support for X509_get_signature_info (#1504) MySQL 8.2/8.3 depends on`X509_get_signature_info`. This symbol originated from an OpenSSL 1.1.1 commit (openssl/openssl@786dd2c) implementing support for "custom signature parameters". The commit mainly allows the user to set and retrieve information about the signature type. There's also a custom ASN1 method handler that OpenSSL implemented in this commit. We don't support custom `EVP_PKEY` ASN1 methods and setting your own signature information doesn't make much sense without the custom methods, so I've only implemented support for retrieving the signature type. MySQL only depends on retrieving the signature info, so this fits our use case. Note: `CryptoAlg-2393` was cut to track missing RSA PSS support in libssl, which was uncovered in the postgres CI. --- crypto/err/x509.errordata | 1 + crypto/x509/internal.h | 20 ++- crypto/x509/x509_set.c | 76 ++++++++++ crypto/x509/x509_test.cc | 31 +++++ crypto/x509v3/v3_purp.c | 7 +- generated-src/err_data.c | 130 +++++++++--------- include/openssl/base.h | 1 + include/openssl/x509.h | 23 +++- .../postgres_patch/aws-lc-postgres.patch | 33 +++++ .../integration/run_postgres_integration.sh | 5 + 10 files changed, 256 insertions(+), 71 deletions(-) create mode 100644 tests/ci/integration/postgres_patch/aws-lc-postgres.patch diff --git a/crypto/err/x509.errordata b/crypto/err/x509.errordata index e30d667bd7..ab886f6700 100644 --- a/crypto/err/x509.errordata +++ b/crypto/err/x509.errordata @@ -39,6 +39,7 @@ X509,137,SIGNATURE_ALGORITHM_MISMATCH X509,128,UNKNOWN_KEY_TYPE X509,129,UNKNOWN_NID X509,130,UNKNOWN_PURPOSE_ID +X509,145,UNKNOWN_SIGID_ALGS X509,131,UNKNOWN_TRUST_ID X509,132,UNSUPPORTED_ALGORITHM X509,133,WRONG_LOOKUP_TYPE diff --git a/crypto/x509/internal.h b/crypto/x509/internal.h index 5de3ed8daa..0fa48b1788 100644 --- a/crypto/x509/internal.h +++ b/crypto/x509/internal.h @@ -139,10 +139,21 @@ typedef struct { // an |X509_NAME|. DECLARE_ASN1_FUNCTIONS(X509_CINF) +struct x509_sig_info_st { + // NID of message digest. + int digest_nid; + // NID of public key algorithm. + int pubkey_nid; + // Security bits. + int sec_bits; + uint32_t flags; +} /* X509_SIG_INFO */; + struct x509_st { X509_CINF *cert_info; X509_ALGOR *sig_alg; ASN1_BIT_STRING *signature; + X509_SIG_INFO sig_info; CRYPTO_refcount_t references; CRYPTO_EX_DATA ex_data; // These contain copies of various extension values @@ -350,9 +361,9 @@ struct x509_store_ctx_st { X509_STORE_CTX_cleanup_fn cleanup; // The following is built up - int valid; // if 0, rebuild chain - int last_untrusted; // index of last untrusted cert - STACK_OF(X509) *chain; // chain of X509s - built up and trusted + int valid; // if 0, rebuild chain + int last_untrusted; // index of last untrusted cert + STACK_OF(X509) *chain; // chain of X509s - built up and trusted // When something goes wrong, this is why int error_depth; @@ -415,6 +426,9 @@ int x509_digest_sign_algorithm(EVP_MD_CTX *ctx, X509_ALGOR *algor); int x509_digest_verify_init(EVP_MD_CTX *ctx, const X509_ALGOR *sigalg, EVP_PKEY *pkey); +// x509_init_signature_info initializes the signature info for |x509|. +int x509_init_signature_info(X509 *x509); + // Path-building functions. diff --git a/crypto/x509/x509_set.c b/crypto/x509/x509_set.c index bfc3ae0152..33307896f3 100644 --- a/crypto/x509/x509_set.c +++ b/crypto/x509/x509_set.c @@ -60,7 +60,9 @@ #include #include +#include "../x509v3/internal.h" #include "internal.h" +#include "openssl/x509v3.h" long X509_get_version(const X509 *x509) { @@ -238,3 +240,77 @@ const X509_ALGOR *X509_get0_tbs_sigalg(const X509 *x) { X509_PUBKEY *X509_get_X509_PUBKEY(const X509 *x509) { return x509->cert_info->key; } + +static int X509_SIG_INFO_get(const X509_SIG_INFO *sig_info, int *digest_nid, + int *pubkey_nid, int *sec_bits, uint32_t *flags) { + if (sig_info == NULL) { + OPENSSL_PUT_ERROR(X509, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + + if (digest_nid != NULL) { + *digest_nid = sig_info->digest_nid; + } + if (pubkey_nid != NULL) { + *pubkey_nid = sig_info->pubkey_nid; + } + if (sec_bits != NULL) { + *sec_bits = sig_info->sec_bits; + } + if (flags != NULL) { + *flags = sig_info->flags; + } + return (sig_info->flags & X509_SIG_INFO_VALID) != 0; +} + +int X509_get_signature_info(X509 *x509, int *digest_nid, int *pubkey_nid, + int *sec_bits, uint32_t *flags) { + if (x509 == NULL) { + OPENSSL_PUT_ERROR(X509, ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + + // The return value of |x509v3_cache_extensions| is not checked because + // |X509_get_signature_info|'s function contract does not encapsulate failures + // if any invalid extensions do exist. + x509v3_cache_extensions(x509); + return X509_SIG_INFO_get(&x509->sig_info, digest_nid, pubkey_nid, sec_bits, + flags); +} + +int x509_init_signature_info(X509 *x509) { + int pubkey_nid, digest_nid; + const EVP_MD *md; + + x509->sig_info.digest_nid = NID_undef; + x509->sig_info.pubkey_nid = NID_undef; + x509->sig_info.sec_bits = -1; + x509->sig_info.flags = 0; + if (!OBJ_find_sigid_algs(OBJ_obj2nid(x509->sig_alg->algorithm), &digest_nid, + &pubkey_nid) || + pubkey_nid == NID_undef) { + OPENSSL_PUT_ERROR(X509, X509_R_UNKNOWN_SIGID_ALGS); + return 0; + } + x509->sig_info.pubkey_nid = pubkey_nid; + x509->sig_info.digest_nid = digest_nid; + x509->sig_info.flags |= X509_SIG_INFO_VALID; + + md = EVP_get_digestbynid(digest_nid); + if (md == NULL) { + // Some valid signature algorithms have an undefined digest. See + // crypto/obj/obj_xref.c. + return 1; + } + // Security bits: half number of bits in digest. + x509->sig_info.sec_bits = (int)EVP_MD_size(md) * 4; + + switch (digest_nid) { + case NID_sha1: + case NID_sha256: + case NID_sha384: + case NID_sha512: + x509->sig_info.flags |= X509_SIG_INFO_TLS; + } + return 1; +} diff --git a/crypto/x509/x509_test.cc b/crypto/x509/x509_test.cc index 2d4bb95e85..ea861db1c5 100644 --- a/crypto/x509/x509_test.cc +++ b/crypto/x509/x509_test.cc @@ -7062,3 +7062,34 @@ TEST(X509Test, GetTextByOBJ) { } } } + +TEST(X509Test, GetSigInfo) { + bssl::UniquePtr cert(CertFromPEM(kLeafPEM)); + ASSERT_TRUE(cert); + + int digest_nid, pubkey_nid, sec_bits; + uint32_t flags; + EXPECT_TRUE(X509_get_signature_info(cert.get(), &digest_nid, &pubkey_nid, + &sec_bits, &flags)); + + EXPECT_EQ(digest_nid, NID_sha256); + EXPECT_EQ(pubkey_nid, NID_rsaEncryption); + EXPECT_EQ(sec_bits, (int)EVP_MD_size(EVP_sha256()) * 4); + EXPECT_TRUE(flags & (X509_SIG_INFO_VALID | X509_SIG_INFO_TLS)); + + cert = CertFromPEM(kEd25519Cert); + EXPECT_TRUE(X509_get_signature_info(cert.get(), &digest_nid, &pubkey_nid, + &sec_bits, &flags)); + EXPECT_EQ(digest_nid, NID_undef); + EXPECT_EQ(pubkey_nid, NID_ED25519); + EXPECT_EQ(sec_bits, -1); + EXPECT_TRUE(flags & X509_SIG_INFO_VALID); + + cert = CertFromPEM(kExampleRsassaPssCert); + EXPECT_TRUE(X509_get_signature_info(cert.get(), &digest_nid, &pubkey_nid, + &sec_bits, &flags)); + EXPECT_EQ(digest_nid, NID_undef); + EXPECT_EQ(pubkey_nid, NID_rsaEncryption); + EXPECT_EQ(sec_bits, -1); + EXPECT_TRUE(flags & X509_SIG_INFO_VALID); +} diff --git a/crypto/x509v3/v3_purp.c b/crypto/x509v3/v3_purp.c index 1696225f53..2aa21119a7 100644 --- a/crypto/x509v3/v3_purp.c +++ b/crypto/x509v3/v3_purp.c @@ -132,7 +132,9 @@ static int xp_cmp(const X509_PURPOSE *const *a, const X509_PURPOSE *const *b) { // As much as I'd like to make X509_check_purpose use a "const" X509* I // really can't because it does recalculate hashes and do other non-const -// things. +// things. If |id| is -1 it just calls |x509v3_cache_extensions| for its +// side-effect. +// Returns 1 on success, 0 if x does not allow purpose, -1 on (internal) error. int X509_check_purpose(X509 *x, int id, int ca) { int idx; const X509_PURPOSE *pt; @@ -550,6 +552,9 @@ int x509v3_cache_extensions(X509 *x) { break; } } + if (!x509_init_signature_info(x)) { + x->ex_flags |= EXFLAG_INVALID; + } x->ex_flags |= EXFLAG_SET; CRYPTO_MUTEX_unlock_write(&x->lock); diff --git a/generated-src/err_data.c b/generated-src/err_data.c index 672078671c..957d14637c 100644 --- a/generated-src/err_data.c +++ b/generated-src/err_data.c @@ -233,9 +233,9 @@ const uint32_t kOpenSSLReasonValues[] = { 0x2c403998, 0x2c4093a9, 0x2c4139a9, - 0x2c41b9bc, + 0x2c41b9cf, 0x2c42136f, - 0x2c42b9cd, + 0x2c42b9e0, 0x2c43076d, 0x2c43b8b3, 0x2c4437fb, @@ -247,6 +247,7 @@ const uint32_t kOpenSSLReasonValues[] = { 0x2c4738ea, 0x2c47b923, 0x2c48380d, + 0x2c48b9bc, 0x30320000, 0x30328015, 0x3033001f, @@ -705,71 +706,71 @@ const uint32_t kOpenSSLReasonValues[] = { 0x4c4197bc, 0x4c421925, 0x4c429704, - 0x503239df, - 0x5032b9ee, - 0x503339f9, - 0x5033ba09, - 0x50343a22, - 0x5034ba3c, - 0x50353a4a, - 0x5035ba60, - 0x50363a72, - 0x5036ba88, - 0x50373aa1, - 0x5037bab4, - 0x50383acc, - 0x5038badd, - 0x50393af2, - 0x5039bb06, - 0x503a3b26, - 0x503abb3c, - 0x503b3b54, - 0x503bbb66, - 0x503c3b82, - 0x503cbb99, - 0x503d3bb2, - 0x503dbbc8, - 0x503e3bd5, - 0x503ebbeb, - 0x503f3bfd, + 0x503239f2, + 0x5032ba01, + 0x50333a0c, + 0x5033ba1c, + 0x50343a35, + 0x5034ba4f, + 0x50353a5d, + 0x5035ba73, + 0x50363a85, + 0x5036ba9b, + 0x50373ab4, + 0x5037bac7, + 0x50383adf, + 0x5038baf0, + 0x50393b05, + 0x5039bb19, + 0x503a3b39, + 0x503abb4f, + 0x503b3b67, + 0x503bbb79, + 0x503c3b95, + 0x503cbbac, + 0x503d3bc5, + 0x503dbbdb, + 0x503e3be8, + 0x503ebbfe, + 0x503f3c10, 0x503f83b3, - 0x50403c10, - 0x5040bc20, - 0x50413c3a, - 0x5041bc49, - 0x50423c63, - 0x5042bc80, - 0x50433c90, - 0x5043bca0, - 0x50443cbd, + 0x50403c23, + 0x5040bc33, + 0x50413c4d, + 0x5041bc5c, + 0x50423c76, + 0x5042bc93, + 0x50433ca3, + 0x5043bcb3, + 0x50443cd0, 0x50448469, - 0x50453cd1, - 0x5045bcef, - 0x50463d02, - 0x5046bd18, - 0x50473d2a, - 0x5047bd3f, - 0x50483d65, - 0x5048bd73, - 0x50493d86, - 0x5049bd9b, - 0x504a3db1, - 0x504abdc1, - 0x504b3de1, - 0x504bbdf4, - 0x504c3e17, - 0x504cbe45, - 0x504d3e72, - 0x504dbe8f, - 0x504e3eaa, - 0x504ebec6, - 0x504f3ed8, - 0x504fbeef, - 0x50503efe, + 0x50453ce4, + 0x5045bd02, + 0x50463d15, + 0x5046bd2b, + 0x50473d3d, + 0x5047bd52, + 0x50483d78, + 0x5048bd86, + 0x50493d99, + 0x5049bdae, + 0x504a3dc4, + 0x504abdd4, + 0x504b3df4, + 0x504bbe07, + 0x504c3e2a, + 0x504cbe58, + 0x504d3e85, + 0x504dbea2, + 0x504e3ebd, + 0x504ebed9, + 0x504f3eeb, + 0x504fbf02, + 0x50503f11, 0x50508729, - 0x50513f11, - 0x5051bcaf, - 0x50523e57, + 0x50513f24, + 0x5051bcc2, + 0x50523e6a, 0x583210b7, 0x5c3293b5, 0x5c3313ce, @@ -1534,6 +1535,7 @@ const char kOpenSSLReasonStringData[] = "SIGNATURE_ALGORITHM_MISMATCH\0" "UNKNOWN_KEY_TYPE\0" "UNKNOWN_PURPOSE_ID\0" + "UNKNOWN_SIGID_ALGS\0" "UNKNOWN_TRUST_ID\0" "WRONG_LOOKUP_TYPE\0" "BAD_IP_ADDRESS\0" diff --git a/include/openssl/base.h b/include/openssl/base.h index b643bfea39..6c5d0afb93 100644 --- a/include/openssl/base.h +++ b/include/openssl/base.h @@ -300,6 +300,7 @@ typedef struct X509_name_entry_st X509_NAME_ENTRY; typedef struct X509_name_st X509_NAME; typedef struct X509_pubkey_st X509_PUBKEY; typedef struct X509_req_st X509_REQ; +typedef struct x509_sig_info_st X509_SIG_INFO; typedef struct X509_sig_st X509_SIG; typedef struct bignum_ctx BN_CTX; typedef struct bignum_st BIGNUM; diff --git a/include/openssl/x509.h b/include/openssl/x509.h index 9e3091a4cf..99ae0187b3 100644 --- a/include/openssl/x509.h +++ b/include/openssl/x509.h @@ -275,6 +275,22 @@ OPENSSL_EXPORT void *X509_get_ext_d2i(const X509 *x509, int nid, // but they will be rejected when verifying. OPENSSL_EXPORT const X509_ALGOR *X509_get0_tbs_sigalg(const X509 *x509); +// X509_SIG_INFO_* are flags for |X509_get_signature_info|. +// X509_SIG_INFO_VALID means that the signature info is valid. +#define X509_SIG_INFO_VALID 0x1 +// X509_SIG_INFO_TLS means that the signature is suitable for TLS use. +#define X509_SIG_INFO_TLS 0x2 + +// X509_get_signature_info retrieves information about the signature of |x509|. +// The NID of the signing digest is written to |digest_nid|, the public key +// algorithm to |pubkey_nid|, the effective security bits to |sec_bits|, and +// flag details to |flags|. Parameters other than |x509| can be set to NULL if +// the information is not required. It is an error to pass a null pointer to +// |x509|. +OPENSSL_EXPORT int X509_get_signature_info(X509 *x509, int *digest_nid, + int *pubkey_nid, int *sec_bits, + uint32_t *flags); + // X509_get0_signature sets |*out_sig| and |*out_alg| to the signature and // signature algorithm of |x509|, respectively. Either output pointer may be // NULL to ignore the value. @@ -2279,7 +2295,8 @@ OPENSSL_EXPORT int X509_NAME_print(BIO *bp, const X509_NAME *name, int obase); // This function outputs a legacy format that does not correctly handle string // encodings and other cases. Prefer |X509_NAME_print_ex| if printing a name for // debugging purposes. -OPENSSL_EXPORT char *X509_NAME_oneline(const X509_NAME *name, char *buf, int size); +OPENSSL_EXPORT char *X509_NAME_oneline(const X509_NAME *name, char *buf, + int size); // X509_NAME_print_ex_fp behaves like |X509_NAME_print_ex| but writes to |fp|. OPENSSL_EXPORT int X509_NAME_print_ex_fp(FILE *fp, const X509_NAME *nm, @@ -3259,8 +3276,7 @@ OPENSSL_EXPORT int X509_STORE_CTX_set_default(X509_STORE_CTX *ctx, // may be |X509_LU_X509| or |X509_LU_CRL|, and the subject name from the store // in |vs|. If found and |ret| is not NULL, it increments the reference count // and stores the object in |ret|. -OPENSSL_EXPORT int X509_STORE_CTX_get_by_subject(X509_STORE_CTX *vs, - int type, +OPENSSL_EXPORT int X509_STORE_CTX_get_by_subject(X509_STORE_CTX *vs, int type, X509_NAME *name, X509_OBJECT *ret); @@ -3433,5 +3449,6 @@ BSSL_NAMESPACE_END #define X509_R_NO_CERTIFICATE_OR_CRL_FOUND 142 #define X509_R_NO_CRL_FOUND 143 #define X509_R_INVALID_POLICY_EXTENSION 144 +#define X509_R_UNKNOWN_SIGID_ALGS 145 #endif // OPENSSL_HEADER_X509_H diff --git a/tests/ci/integration/postgres_patch/aws-lc-postgres.patch b/tests/ci/integration/postgres_patch/aws-lc-postgres.patch new file mode 100644 index 0000000000..6ba8b59473 --- /dev/null +++ b/tests/ci/integration/postgres_patch/aws-lc-postgres.patch @@ -0,0 +1,33 @@ +diff --git a/src/test/ssl/t/002_scram.pl b/src/test/ssl/t/002_scram.pl +index dd93224124..44f570c8e2 100644 +--- a/src/test/ssl/t/002_scram.pl ++++ b/src/test/ssl/t/002_scram.pl +@@ -155,14 +155,18 @@ $node->connect_ok( + # Now test with a server certificate that uses the RSA-PSS algorithm. + # This checks that the certificate can be loaded and that channel binding + # works. (see bug #17760) +-if ($supports_rsapss_certs) +-{ +- switch_server_cert($node, certfile => 'server-rsapss'); +- $node->connect_ok( +- "$common_connstr user=ssltestuser channel_binding=require", +- "SCRAM with SSL and channel_binding=require, server certificate uses 'rsassaPss'", +- log_like => [ +- qr/connection authenticated: identity="ssltestuser" method=scram-sha-256/ +- ]); +-} ++# ++# AWS-LC does not support RSA-PSS certificates in libssl. If there is a relevant ++# feature request for this, cut an issue to our public repository. ++# ++# if ($supports_rsapss_certs) ++# { ++# switch_server_cert($node, certfile => 'server-rsapss'); ++# $node->connect_ok( ++# "$common_connstr user=ssltestuser channel_binding=require", ++# "SCRAM with SSL and channel_binding=require, server certificate uses 'rsassaPss'", ++# log_like => [ ++# qr/connection authenticated: identity="ssltestuser" method=scram-sha-256/ ++# ]); ++# } + done_testing(); diff --git a/tests/ci/integration/run_postgres_integration.sh b/tests/ci/integration/run_postgres_integration.sh index 20aa6f7603..506208bf48 100755 --- a/tests/ci/integration/run_postgres_integration.sh +++ b/tests/ci/integration/run_postgres_integration.sh @@ -17,6 +17,7 @@ source tests/ci/common_posix_setup.sh SCRATCH_FOLDER=${SRC_ROOT}/"POSTGRES_BUILD_ROOT" POSTGRES_SRC_FOLDER="${SCRATCH_FOLDER}/postgres" POSTGRES_BUILD_FOLDER="${SCRATCH_FOLDER}/postgres/build" +POSTGRES_PATCH_FOLDER="${SRC_ROOT}/tests/ci/integration/postgres_patch" AWS_LC_BUILD_FOLDER="${SCRATCH_FOLDER}/aws-lc-build" AWS_LC_INSTALL_FOLDER="${POSTGRES_SRC_FOLDER}/aws-lc-install" @@ -47,6 +48,10 @@ function postgres_patch() { for i in "${!POSTGRES_ERROR_STRING[@]}"; do find ./ -type f -name "001_ssltests.pl" | xargs sed -i -e "s|${POSTGRES_ERROR_STRING[$i]}|${AWS_LC_EXPECTED_ERROR_STRING[$i]}|g" done + for patchfile in $(find -L "${POSTGRES_PATCH_FOLDER}" -type f -name '*.patch'); do + echo "Apply patch $patchfile..." + patch -p1 --quiet -i "$patchfile" + done } # Get latest postgres version.