diff --git a/.github/workflows/actions-ci.yml b/.github/workflows/actions-ci.yml index cbf37aa50e..4994f1a076 100644 --- a/.github/workflows/actions-ci.yml +++ b/.github/workflows/actions-ci.yml @@ -737,3 +737,46 @@ jobs: run: | sudo pkg install -y git gmake cmake go ninja tests/ci/run_bsd_tests.sh + netbsd: + if: github.repository_owner == 'aws' + needs: [sanity-test-run] + name: NetBSD ${{ matrix.version }} (${{ matrix.arch }}) test + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + arch: + - "x86-64" + - "arm64" + version: + - "10.1" + steps: + - uses: actions/checkout@v4 + with: + submodules: "recursive" + - name: Prepare VM + uses: cross-platform-actions/action@2d97d42e1972a17b045fd709a422f7e55a86230d + env: + AWS_LC_SSL_TEST_RUNNER_PEEK_ROUNDS: 5 + AWS_LC_GO_TEST_TIMEOUT: 90m + GOFLAGS: "-buildvcs=false" + with: + environment_variables: "AWS_LC_SSL_TEST_RUNNER_PEEK_ROUNDS AWS_LC_GO_TEST_TIMEOUT GOFLAGS" + operating_system: netbsd + architecture: ${{ matrix.arch }} + version: ${{ matrix.version }} + shell: bash + memory: 12G + cpu_count: 3 + run: | + set -x + export PKG_PATH="https://cdn.NetBSD.org/pub/pkgsrc/packages/NetBSD/${{ (matrix.arch == 'arm64' && 'aarch64') || 'x86_64' }}/${{ matrix.version }}/All" + sudo -E pkg_add -u curl cmake gmake perl mozilla-rootcerts + ARCH=${{ (matrix.arch == 'x86-64' && 'amd') || 'arm' }} + export PATH="/usr/pkg/bin:/usr/pkg/sbin:/usr/sbin:/usr/bin:/sbin:/bin" + curl -O https://dl.google.com/go/go1.25.2.netbsd-${ARCH}64.tar.gz + sudo mkdir -p /usr/local + sudo tar -C /usr/local -xzf go1.25.2.netbsd-${ARCH}64.tar.gz + export GOROOT=/usr/local/go + export PATH="$PATH:$GOROOT/bin" + tests/ci/run_bsd_tests.sh diff --git a/crypto/fipsmodule/bcm.c b/crypto/fipsmodule/bcm.c index 752631b53b..618704073f 100644 --- a/crypto/fipsmodule/bcm.c +++ b/crypto/fipsmodule/bcm.c @@ -78,6 +78,7 @@ #include "cpucap/cpu_aarch64_apple.c" #include "cpucap/cpu_aarch64_freebsd.c" #include "cpucap/cpu_aarch64_linux.c" +#include "cpucap/cpu_aarch64_netbsd.c" #include "cpucap/cpu_aarch64_openbsd.c" #include "cpucap/cpu_aarch64_win.c" #include "cpucap/cpu_arm_freebsd.c" diff --git a/crypto/fipsmodule/bn/exponentiation.c b/crypto/fipsmodule/bn/exponentiation.c index 8713715b03..920d8c0053 100644 --- a/crypto/fipsmodule/bn/exponentiation.c +++ b/crypto/fipsmodule/bn/exponentiation.c @@ -121,7 +121,8 @@ #if !defined(OPENSSL_NO_ASM) && \ (defined(OPENSSL_LINUX) || defined(OPENSSL_APPLE) || \ - defined(OPENSSL_OPENBSD) || defined(OPENSSL_FREEBSD)) && \ + defined(OPENSSL_OPENBSD) || defined(OPENSSL_FREEBSD) || \ + defined(OPENSSL_NETBSD)) && \ defined(OPENSSL_AARCH64) #include "../../../third_party/s2n-bignum/s2n-bignum_aws-lc.h" @@ -1296,7 +1297,7 @@ int BN_mod_exp_mont_consttime_x2(BIGNUM *rr1, const BIGNUM *a1, const BIGNUM *p1 if (!bn_wexpand(rr2, widthn)) { return ret; } - + /* Ensure that montgomery contexts are initialized */ if (in_mont1 == NULL) { return ret; diff --git a/crypto/fipsmodule/bn/montgomery.c b/crypto/fipsmodule/bn/montgomery.c index c7ac15c18d..0a67722c4c 100644 --- a/crypto/fipsmodule/bn/montgomery.c +++ b/crypto/fipsmodule/bn/montgomery.c @@ -124,7 +124,8 @@ #if !defined(OPENSSL_NO_ASM) && \ (defined(OPENSSL_LINUX) || defined(OPENSSL_APPLE) || \ - defined(OPENSSL_OPENBSD) || defined(OPENSSL_FREEBSD)) && \ + defined(OPENSSL_OPENBSD) || defined(OPENSSL_FREEBSD) || \ + defined(OPENSSL_NETBSD) ) && \ defined(OPENSSL_AARCH64) && defined(OPENSSL_BN_ASM_MONT) #include "../../../third_party/s2n-bignum/s2n-bignum_aws-lc.h" diff --git a/crypto/fipsmodule/cpucap/cpu_aarch64_freebsd.c b/crypto/fipsmodule/cpucap/cpu_aarch64_freebsd.c index 9910261abf..8e187e652a 100644 --- a/crypto/fipsmodule/cpucap/cpu_aarch64_freebsd.c +++ b/crypto/fipsmodule/cpucap/cpu_aarch64_freebsd.c @@ -56,6 +56,8 @@ void OPENSSL_cpuid_setup(void) { if (ID_AA64ISAR0_SHA2_VAL(id_aa64isar0) >= ID_AA64ISAR0_SHA2_512) { OPENSSL_armcap_P |= ARMV8_SHA512; } + + OPENSSL_cpucap_initialized = 1; } #endif // OPENSSL_AARCH64 && OPENSSL_FREEBSD && !OPENSSL_STATIC_ARMCAP diff --git a/crypto/fipsmodule/cpucap/cpu_aarch64_netbsd.c b/crypto/fipsmodule/cpucap/cpu_aarch64_netbsd.c new file mode 100644 index 0000000000..b3c4ef9b40 --- /dev/null +++ b/crypto/fipsmodule/cpucap/cpu_aarch64_netbsd.c @@ -0,0 +1,133 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 OR ISC + +#include + +#if defined(OPENSSL_AARCH64) && defined(OPENSSL_NETBSD) && \ + !defined(OPENSSL_STATIC_ARMCAP) + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "internal.h" + +// Helper function to query a specific CPU's capabilities +static int get_cpu_id(int cpu_num, struct aarch64_sysctl_cpu_id *id) { + char sysctl_name[64]; + size_t len = sizeof(*id); + + snprintf(sysctl_name, sizeof(sysctl_name), "machdep.cpu%d.cpu_id", cpu_num); + + if (sysctlbyname(sysctl_name, id, &len, NULL, 0) < 0) { + return -1; + } + + if (len != sizeof(*id)) { + return -1; + } + + return 0; +} + +void OPENSSL_cpuid_setup(void) { + struct aarch64_sysctl_cpu_id cpu_id; + + // NetBSD's machdep.cpuN.cpu_id sysctl reads each core's ID registers + // directly, so it reflects that specific core's capabilities, not a + // system-wide minimum. + + // Initialize with all features enabled (we'll AND them together) + uint64_t common_aa64isar0 = UINT64_MAX; + uint64_t common_aa64pfr0 = UINT64_MAX; + int found_cpu = 0; + + // Query up to 256 CPUs (arbitrary but reasonable upper limit) + for (size_t cpu_num = 0; cpu_num < 256; cpu_num++) { + if (get_cpu_id(cpu_num, &cpu_id) < 0) { + // Failed to read this CPU - either it doesn't exist or is offline + if (found_cpu > 0) { + // We've already found at least one CPU, so assume we've enumerated all + break; + } + // Haven't found any CPUs yet, keep trying + continue; + } + + found_cpu++; + + // Take the bitwise AND to get the intersection of capabilities + // Only features present on ALL cores will remain set + common_aa64isar0 &= cpu_id.ac_aa64isar0; + common_aa64pfr0 &= cpu_id.ac_aa64pfr0; + } + + // If we couldn't read any CPU info, return early without setting any features + if (!found_cpu) { + return; + } + + // NEON (Advanced SIMD) is mandatory on all ARMv8-A cores + OPENSSL_armcap_P |= ARMV7_NEON; + + // Inspired by the implementation of `cpu_identify2` here: + // https://github.com/NetBSD/src/blob/62c785e59d064070166dab5d2a4492055effba89/sys/arch/aarch64/aarch64/cpu.c#L363 + + // Macros below found in "armreg.h" + // https://github.com/NetBSD/src/blame/62c785e59d064070166dab5d2a4492055effba89/sys/arch/aarch64/include/armreg.h + + // Check for AES and PMULL + const uint64_t aes_detection = + __SHIFTOUT(common_aa64isar0, ID_AA64ISAR0_EL1_AES); + if (aes_detection >= ID_AA64ISAR0_EL1_AES_AES) { + OPENSSL_armcap_P |= ARMV8_AES; + } + if (aes_detection >= ID_AA64ISAR0_EL1_AES_PMUL) { + OPENSSL_armcap_P |= ARMV8_PMULL; + } + + // Check for SHA1 support across all cores + if (__SHIFTOUT(common_aa64isar0, ID_AA64ISAR0_EL1_SHA1) >= + ID_AA64ISAR0_EL1_SHA1_SHA1CPMHSU) { + OPENSSL_armcap_P |= ARMV8_SHA1; + } + + // Check for SHA256 support across all cores + const uint64_t sha2_detection = + __SHIFTOUT(common_aa64isar0, ID_AA64ISAR0_EL1_SHA2); + if (sha2_detection >= ID_AA64ISAR0_EL1_SHA2_SHA256HSU) { + OPENSSL_armcap_P |= ARMV8_SHA256; + } + if (sha2_detection >= ID_AA64ISAR0_EL1_SHA2_SHA512HSU) { + OPENSSL_armcap_P |= ARMV8_SHA512; + } + + // Check for SHA3 support across all cores + if (__SHIFTOUT(common_aa64isar0, ID_AA64ISAR0_EL1_SHA3) >= + ID_AA64ISAR0_EL1_SHA3_EOR3) { + OPENSSL_armcap_P |= ARMV8_SHA3; + } + + // Check for RNG (RNDR/RNDRRS) support across all cores + if (__SHIFTOUT(common_aa64isar0, ID_AA64ISAR0_EL1_RNDR) >= + ID_AA64ISAR0_EL1_RNDR_RNDRRS) { + OPENSSL_armcap_P |= ARMV8_RNG; + } + + // Check for DIT (Data Independent Timing) support across all cores + if (__SHIFTOUT(common_aa64pfr0, ID_AA64PFR0_EL1_DIT) >= + ID_AA64PFR0_EL1_DIT_IMPL) { + OPENSSL_armcap_P |= (ARMV8_DIT | ARMV8_DIT_ALLOWED); + } + + OPENSSL_cpucap_initialized = 1; +} + +#endif // OPENSSL_AARCH64 && OPENSSL_NETBSD && !OPENSSL_STATIC_ARMCAP diff --git a/crypto/fipsmodule/cpucap/cpu_aarch64_openbsd.c b/crypto/fipsmodule/cpucap/cpu_aarch64_openbsd.c index 6ceb636430..9dd1b11d24 100644 --- a/crypto/fipsmodule/cpucap/cpu_aarch64_openbsd.c +++ b/crypto/fipsmodule/cpucap/cpu_aarch64_openbsd.c @@ -53,6 +53,8 @@ void OPENSSL_cpuid_setup(void) { if (ID_AA64ISAR0_SHA2(cpu_id) >= ID_AA64ISAR0_SHA2_512) OPENSSL_armcap_P |= ARMV8_SHA512; + + OPENSSL_cpucap_initialized = 1; } #endif // OPENSSL_AARCH64 && OPENSSL_OPENBSD && !OPENSSL_STATIC_ARMCAP diff --git a/crypto/fipsmodule/curve25519/internal.h b/crypto/fipsmodule/curve25519/internal.h index 0a25754503..9b7bebecb4 100644 --- a/crypto/fipsmodule/curve25519/internal.h +++ b/crypto/fipsmodule/curve25519/internal.h @@ -109,7 +109,8 @@ int ED25519ph_verify_digest_no_self_test( #if ((defined(OPENSSL_X86_64) && !defined(MY_ASSEMBLER_IS_TOO_OLD_FOR_512AVX)) || \ defined(OPENSSL_AARCH64)) && \ (defined(OPENSSL_LINUX) || defined(OPENSSL_APPLE) || \ - defined(OPENSSL_OPENBSD) || defined(OPENSSL_FREEBSD)) && \ + defined(OPENSSL_OPENBSD) || defined(OPENSSL_FREEBSD) || \ + defined(OPENSSL_NETBSD)) && \ !defined(OPENSSL_NO_ASM) #define CURVE25519_S2N_BIGNUM_CAPABLE #endif diff --git a/crypto/rand_extra/internal.h b/crypto/rand_extra/internal.h index c1db16b950..8a6af5fce5 100644 --- a/crypto/rand_extra/internal.h +++ b/crypto/rand_extra/internal.h @@ -11,7 +11,8 @@ #elif defined(OPENSSL_WINDOWS) #define OPENSSL_RAND_WINDOWS #elif defined(OPENSSL_MACOS) || defined(OPENSSL_OPENBSD) || \ - defined(OPENSSL_FREEBSD) || defined(OPENSSL_SOLARIS) || \ + defined(OPENSSL_FREEBSD) || defined(OPENSSL_NETBSD) || \ + defined(OPENSSL_SOLARIS) || \ (defined(OPENSSL_LINUX) && !defined(HAVE_LINUX_RANDOM_H)) #define OPENSSL_RAND_GETENTROPY #elif defined(OPENSSL_IOS) diff --git a/crypto/rand_extra/urandom.c b/crypto/rand_extra/urandom.c index 433acffb2c..73d8196d04 100644 --- a/crypto/rand_extra/urandom.c +++ b/crypto/rand_extra/urandom.c @@ -431,7 +431,7 @@ static int fill_with_entropy(uint8_t *out, size_t len, int block, int seed) { // Hard bail. abort(); } - } + } // Clear |errno| so it has defined value if |read| or |getrandom| // "successfully" returns zero. diff --git a/crypto/ube/fork_detect.c b/crypto/ube/fork_detect.c index 2d2aba8dde..91116fe2fc 100644 --- a/crypto/ube/fork_detect.c +++ b/crypto/ube/fork_detect.c @@ -30,7 +30,7 @@ #if !defined(_GNU_SOURCE) #define _GNU_SOURCE // Needed for madvise() and MAP_ANONYMOUS. #endif -#elif defined(OPENSSL_FREEBSD) || defined(OPENSSL_OPENBSD) +#elif defined(OPENSSL_FREEBSD) || defined(OPENSSL_OPENBSD) || defined(OPENSSL_NETBSD) #define AWSLC_FORK_DETECTION_SUPPORTED // FreeBSD requires POSIX compatibility off for its syscalls // (enables __BSD_VISIBLE). Without the below line, cannot be @@ -114,7 +114,7 @@ static int init_fork_detect_wipeonfork(void *addr, long page_size) { #endif // defined(OPENSSL_LINUX) -#if defined(OPENSSL_FREEBSD) || defined(OPENSSL_OPENBSD) +#if defined(OPENSSL_FREEBSD) || defined(OPENSSL_OPENBSD) || defined(OPENSSL_NETBSD) #include #include diff --git a/include/openssl/target.h b/include/openssl/target.h index 974cd9e412..85f1bcd78a 100644 --- a/include/openssl/target.h +++ b/include/openssl/target.h @@ -174,6 +174,10 @@ #define OPENSSL_OPENBSD #endif +#if defined(__NetBSD__) +#define OPENSSL_NETBSD +#endif + #if defined(__illumos__) || (defined(__sun) && defined(__SVR4)) #define OPENSSL_SOLARIS #endif diff --git a/tests/ci/common_posix_setup.sh b/tests/ci/common_posix_setup.sh index c05a2a30f1..905dbca8ae 100644 --- a/tests/ci/common_posix_setup.sh +++ b/tests/ci/common_posix_setup.sh @@ -24,8 +24,17 @@ PLATFORM=$(uname -m) NUM_CPU_THREADS='' KERNEL_NAME=$(uname -s) if [[ "${KERNEL_NAME}" == "Darwin" || "${KERNEL_NAME}" =~ .*BSD ]]; then - # On MacOS, /proc/cpuinfo does not exist. - NUM_CPU_THREADS=$(sysctl -n hw.ncpu) + # sysctl is typically in /sbin or /usr/sbin on BSD systems + if command -v sysctl &> /dev/null; then + NUM_CPU_THREADS=$(sysctl -n hw.ncpu) + elif [[ -x /sbin/sysctl ]]; then + NUM_CPU_THREADS=$(/sbin/sysctl -n hw.ncpu) + elif [[ -x /usr/sbin/sysctl ]]; then + NUM_CPU_THREADS=$(/usr/sbin/sysctl -n hw.ncpu) + else + echo "Warning: Could not find sysctl, defaulting to 2 CPU threads" + NUM + fi else # Assume KERNEL_NAME is Linux. NUM_CPU_THREADS=$(grep -c ^processor /proc/cpuinfo) diff --git a/tests/ci/run_bsd_tests.sh b/tests/ci/run_bsd_tests.sh index b191ea9588..74e4155a8c 100755 --- a/tests/ci/run_bsd_tests.sh +++ b/tests/ci/run_bsd_tests.sh @@ -6,6 +6,11 @@ set -ex source tests/ci/common_posix_setup.sh +# Our NetBSD CI environment gives a "No route to host" error when connecting to `ocsp.sectigo.com:80`. +if [[ "$KERNEL_NAME" == "NetBSD" ]]; then + export GTEST_FILTER="-*.AmazonTrustServices*" +fi + if [ "$PLATFORM" != "amd64" ] && [ "$PLATFORM" != "x86_64" ]; then # ARM64 platforms are tested via emulation. # We narrow testing to libcrypto to avoid exceeding 1 hour duration @@ -41,8 +46,11 @@ build_and_test -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=1 echo "Testing AWS-LC static library in release mode." build_and_test -DCMAKE_BUILD_TYPE=Release -echo "Testing AWS-LC shared library in FIPS Release mode." -fips_build_and_test -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=1 +# The FIPS builds fail on NetBSD +if [[ "$KERNEL_NAME" != "NetBSD" ]]; then + echo "Testing AWS-LC shared library in FIPS Release mode." + fips_build_and_test -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=1 -echo "Testing AWS-LC static library in FIPS Release mode." -fips_build_and_test -DCMAKE_BUILD_TYPE=Release + echo "Testing AWS-LC static library in FIPS Release mode." + fips_build_and_test -DCMAKE_BUILD_TYPE=Release +fi