diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 419c074a70..1030363238 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -182,6 +182,7 @@ jobs: - i686-unknown-linux-musl - powerpc64le-unknown-linux-gnu - riscv64gc-unknown-linux-gnu + - s390x-unknown-linux-gnu - x86_64-pc-windows-gnu - x86_64-pc-windows-msvc - x86_64-apple-darwin @@ -255,6 +256,9 @@ jobs: - target: riscv64gc-unknown-linux-gnu host_os: ubuntu-22.04 + - target: s390x-unknown-linux-gnu + host_os: ubuntu-22.04 + - target: x86_64-pc-windows-gnu host_os: windows-latest @@ -342,6 +346,7 @@ jobs: - aarch64-unknown-linux-musl - i686-pc-windows-msvc - powerpc64le-unknown-linux-gnu + - s390x-unknown-linux-gnu - x86_64-unknown-linux-gnu mode: @@ -363,6 +368,9 @@ jobs: - target: powerpc64le-unknown-linux-gnu host_os: ubuntu-22.04 + - target: s390x-unknown-linux-gnu + host_os: ubuntu-22.04 + - target: x86_64-unknown-linux-gnu host_os: ubuntu-22.04 @@ -498,6 +506,7 @@ jobs: - i686-unknown-linux-gnu - powerpc64le-unknown-linux-gnu - riscv64gc-unknown-linux-gnu + - s390x-unknown-linux-gnu - x86_64-unknown-linux-musl mode: @@ -527,6 +536,9 @@ jobs: - target: riscv64gc-unknown-linux-gnu host_os: ubuntu-22.04 + - target: s390x-unknown-linux-gnu + host_os: ubuntu-22.04 + - target: x86_64-unknown-linux-musl host_os: ubuntu-22.04 diff --git a/crypto/fipsmodule/aes/aes_nohw.c b/crypto/fipsmodule/aes/aes_nohw.c index 1b35f635a6..731178516d 100644 --- a/crypto/fipsmodule/aes/aes_nohw.c +++ b/crypto/fipsmodule/aes/aes_nohw.c @@ -273,6 +273,9 @@ static inline aes_word_t aes_nohw_delta_swap(aes_word_t a, aes_word_t mask, // http://programming.sirrida.de/calcperm.php on smaller inputs. #if defined(OPENSSL_64_BIT) static inline uint64_t aes_nohw_compact_word(uint64_t a) { +#if defined(RING_BIG_ENDIAN) + a = CRYPTO_bswap8(a); +#endif // Numbering the 64/2 = 16 4-bit chunks, least to most significant, we swap // quartets of those chunks: // 0 1 2 3 | 4 5 6 7 | 8 9 10 11 | 12 13 14 15 => @@ -294,10 +297,16 @@ static inline uint64_t aes_nohw_uncompact_word(uint64_t a) { a = aes_nohw_delta_swap(a, UINT64_C(0x00000000ffff0000), 16); a = aes_nohw_delta_swap(a, UINT64_C(0x0000ff000000ff00), 8); a = aes_nohw_delta_swap(a, UINT64_C(0x00f000f000f000f0), 4); +#if defined(RING_BIG_ENDIAN) + a = CRYPTO_bswap8(a); +#endif return a; } #else // !OPENSSL_64_BIT static inline uint32_t aes_nohw_compact_word(uint32_t a) { +#if defined(RING_BIG_ENDIAN) + a = CRYPTO_bswap4(a); +#endif // Numbering the 32/2 = 16 pairs of bits, least to most significant, we swap: // 0 1 2 3 | 4 5 6 7 | 8 9 10 11 | 12 13 14 15 => // 0 4 2 6 | 1 5 3 7 | 8 12 10 14 | 9 13 11 15 @@ -316,6 +325,9 @@ static inline uint32_t aes_nohw_uncompact_word(uint32_t a) { // Reverse the steps of |aes_nohw_uncompact_word|. a = aes_nohw_delta_swap(a, 0x0000f0f0, 12); a = aes_nohw_delta_swap(a, 0x00cc00cc, 6); +#if defined(RING_BIG_ENDIAN) + a = CRYPTO_bswap4(a); +#endif return a; } diff --git a/crypto/internal.h b/crypto/internal.h index 0de2a3e86b..5f92e34e3f 100644 --- a/crypto/internal.h +++ b/crypto/internal.h @@ -401,55 +401,77 @@ static inline void *OPENSSL_memset(void *dst, int c, size_t n) { // endianness. They use |memcpy|, and so avoid alignment or strict aliasing // requirements on the input and output pointers. +#if defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +#define RING_BIG_ENDIAN +#endif +#endif + static inline uint32_t CRYPTO_load_u32_le(const void *in) { uint32_t v; OPENSSL_memcpy(&v, in, sizeof(v)); +#if defined(RING_BIG_ENDIAN) + return CRYPTO_bswap4(v); +#else return v; +#endif } static inline void CRYPTO_store_u32_le(void *out, uint32_t v) { +#if defined(RING_BIG_ENDIAN) + v = CRYPTO_bswap4(v); +#endif OPENSSL_memcpy(out, &v, sizeof(v)); } static inline uint32_t CRYPTO_load_u32_be(const void *in) { uint32_t v; OPENSSL_memcpy(&v, in, sizeof(v)); +#if !defined(RING_BIG_ENDIAN) return CRYPTO_bswap4(v); +#else + return v; +#endif } static inline void CRYPTO_store_u32_be(void *out, uint32_t v) { +#if !defined(RING_BIG_ENDIAN) v = CRYPTO_bswap4(v); +#endif OPENSSL_memcpy(out, &v, sizeof(v)); } static inline uint64_t CRYPTO_load_u64_le(const void *in) { uint64_t v; OPENSSL_memcpy(&v, in, sizeof(v)); +#if defined(RING_BIG_ENDIAN) + return CRYPTO_bswap8(v); +#else return v; +#endif } static inline void CRYPTO_store_u64_le(void *out, uint64_t v) { +#if defined(RING_BIG_ENDIAN) + v = CRYPTO_bswap8(v); +#endif OPENSSL_memcpy(out, &v, sizeof(v)); } static inline uint64_t CRYPTO_load_u64_be(const void *ptr) { uint64_t ret; OPENSSL_memcpy(&ret, ptr, sizeof(ret)); +#if !defined(RING_BIG_ENDIAN) return CRYPTO_bswap8(ret); +#else + return ret; +#endif } static inline void CRYPTO_store_u64_be(void *out, uint64_t v) { +#if !defined(RING_BIG_ENDIAN) v = CRYPTO_bswap8(v); - OPENSSL_memcpy(out, &v, sizeof(v)); -} - -static inline crypto_word_t CRYPTO_load_word_le(const void *in) { - crypto_word_t v; - OPENSSL_memcpy(&v, in, sizeof(v)); - return v; -} - -static inline void CRYPTO_store_word_le(void *out, crypto_word_t v) { +#endif OPENSSL_memcpy(out, &v, sizeof(v)); } diff --git a/include/ring-core/target.h b/include/ring-core/target.h index 7ea6efabb8..3924e78f8d 100644 --- a/include/ring-core/target.h +++ b/include/ring-core/target.h @@ -46,6 +46,9 @@ #elif defined(__riscv) && __SIZEOF_POINTER__ == 8 #define OPENSSL_64_BIT #define OPENSSL_RISCV64 +#elif defined(__s390x__) +#define OPENSSL_64_BIT +#define OPENSSL_S390X #elif defined(__wasm__) #define OPENSSL_32_BIT #else diff --git a/mk/cargo.sh b/mk/cargo.sh index eae727a0a0..436b68eee2 100755 --- a/mk/cargo.sh +++ b/mk/cargo.sh @@ -23,6 +23,7 @@ qemu_arm="qemu-arm -L /usr/arm-linux-gnueabihf" qemu_mipsel="qemu-mipsel -L /usr/mipsel-linux-gnu" qemu_powerpc64le="qemu-ppc64le -L /usr/powerpc64le-linux-gnu" qemu_riscv64="qemu-riscv64 -L /usr/riscv64-linux-gnu" +qemu_s390x="qemu-s390x -L /usr/s390x-linux-gnu" # Avoid putting the Android tools in `$PATH` because there are tools in this # directory like `clang` that would conflict with the same-named tools that may @@ -114,6 +115,16 @@ case $target in export CARGO_TARGET_RISCV64GC_UNKNOWN_LINUX_GNU_LINKER=riscv64-linux-gnu-gcc export CARGO_TARGET_RISCV64GC_UNKNOWN_LINUX_GNU_RUNNER="$qemu_riscv64" ;; + s390x-unknown-linux-gnu) + export CC_s390x_unknown_linux_gnu=clang-$llvm_version + export AR_s390x_unknown_linux_gnu=llvm-ar-$llvm_version + # XXX: Using -march=zEC12 to work around a z13 instruction bug in + # QEMU 8.0.2 and earlier that causes `test_constant_time` to fail + # (https://lists.gnu.org/archive/html/qemu-devel/2023-05/msg06965.html). + export CFLAGS_s390x_unknown_linux_gnu="--sysroot=/usr/s390x-linux-gnu -march=zEC12" + export CARGO_TARGET_S390X_UNKNOWN_LINUX_GNU_LINKER=s390x-linux-gnu-gcc + export CARGO_TARGET_S390X_UNKNOWN_LINUX_GNU_RUNNER="$qemu_s390x" + ;; x86_64-unknown-linux-musl) export CC_x86_64_unknown_linux_musl=clang-$llvm_version export AR_x86_64_unknown_linux_musl=llvm-ar-$llvm_version diff --git a/mk/install-build-tools.sh b/mk/install-build-tools.sh index cb5b615f1c..b861041c1b 100755 --- a/mk/install-build-tools.sh +++ b/mk/install-build-tools.sh @@ -105,6 +105,14 @@ case $target in libc6-dev-riscv64-cross \ qemu-user ;; +--target=s390x-unknown-linux-gnu) + # Clang is needed for code coverage. + use_clang=1 + install_packages \ + qemu-user \ + gcc-s390x-linux-gnu \ + libc6-dev-s390x-cross + ;; --target=wasm32-unknown-unknown) cargo install wasm-bindgen-cli --bin wasm-bindgen-test-runner use_clang=1 diff --git a/src/lib.rs b/src/lib.rs index 644708c828..99e1ff3ee6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -115,5 +115,9 @@ mod sealed { pub trait Sealed {} } -// TODO: https://github.com/briansmith/ring/issues/1555. -const _LITTLE_ENDIAN_ONLY: () = assert!(cfg!(target_endian = "little")); +// XXX: 64-bit big endian is tested; 32-bit is not. +// TODO: Add 32-bit big endian test coverage to CI. +const _ENDIAN_TESTING: () = assert!(cfg!(any( + target_endian = "little", + target_pointer_width = "64" +)));