From efa1f22483ee43d84e1aee01b08c0bda04060c1c Mon Sep 17 00:00:00 2001 From: Orr Toledano Date: Wed, 19 May 2021 18:54:20 +0000 Subject: [PATCH] Add Arm Assembly (aarch64) support for RNG Include aarch64 asm instructions for random number generation using the RNDR and RNDRRS instructions. Provide detection functions for RNDR and RNDRRS getauxval. Reviewed-by: Paul Dale Reviewed-by: Tomas Mraz (Merged from https://github.com/openssl/openssl/pull/15361) --- crypto/arm64cpuid.pl | 60 ++++++++++++++++++++++++++++++++++++++++++++ crypto/arm_arch.h | 1 + crypto/armcap.c | 45 +++++++++++++++++++++++++++++++++ 3 files changed, 106 insertions(+) diff --git a/crypto/arm64cpuid.pl b/crypto/arm64cpuid.pl index 11f0e502794..a86fa6073a1 100755 --- a/crypto/arm64cpuid.pl +++ b/crypto/arm64cpuid.pl @@ -161,7 +161,67 @@ CRYPTO_memcmp: lsr w0,w0,#31 ret .size CRYPTO_memcmp,.-CRYPTO_memcmp + +.globl _armv8_rng_probe +.type _armv8_rng_probe,%function +_armv8_rng_probe: + mrs x0, s3_3_c2_c4_0 // rndr + mrs x0, s3_3_c2_c4_1 // rndrrs + ret +.size _armv8_rng_probe,.-_armv8_rng_probe +___ + +sub gen_random { +my $rdop = shift; +my $rand_reg = $rdop eq "rndr" ? "s3_3_c2_c4_0" : "s3_3_c2_c4_1"; + +print<<___; +// Fill buffer with Randomly Generated Bytes +// inputs: char * in x0 - Pointer to buffer +// size_t in x1 - Number of bytes to write to buffer +// outputs: size_t in x0 - Number of bytes successfully written to buffer +.globl OPENSSL_${rdop}_asm +.type OPENSSL_${rdop}_asm,%function +.align 4 +OPENSSL_${rdop}_asm: + mov x2,xzr + mov x3,xzr + +.align 4 +.Loop_${rdop}: + cmp x1,#0 + b.eq .${rdop}_done + mov x3,xzr + mrs x3,$rand_reg + b.eq .${rdop}_done + + cmp x1,#8 + b.lt .Loop_single_byte_${rdop} + + str x3,[x0] + add x0,x0,#8 + add x2,x2,#8 + subs x1,x1,#8 + b.ge .Loop_${rdop} + +.align 4 +.Loop_single_byte_${rdop}: + strb w3,[x0] + lsr x3,x3,#8 + add x2,x2,#1 + add x0,x0,#1 + subs x1,x1,#1 + b.gt .Loop_single_byte_${rdop} + +.align 4 +.${rdop}_done: + mov x0,x2 + ret +.size OPENSSL_${rdop}_asm,.-OPENSSL_${rdop}_asm ___ +} +gen_random("rndr"); +gen_random("rndrrs"); print $code; close STDOUT or die "error closing STDOUT: $!"; diff --git a/crypto/arm_arch.h b/crypto/arm_arch.h index aa380acce03..ca480456708 100644 --- a/crypto/arm_arch.h +++ b/crypto/arm_arch.h @@ -83,6 +83,7 @@ extern unsigned int OPENSSL_armv8_rsa_neonized; # define ARMV8_PMULL (1<<5) # define ARMV8_SHA512 (1<<6) # define ARMV8_CPUID (1<<7) +# define ARMV8_RNG (1<<8) /* * MIDR_EL1 system register diff --git a/crypto/armcap.c b/crypto/armcap.c index 5b45a9d0f40..117c57efe42 100644 --- a/crypto/armcap.c +++ b/crypto/armcap.c @@ -17,6 +17,7 @@ #include #endif #include "internal/cryptlib.h" +#include #include "arm_arch.h" @@ -54,6 +55,37 @@ void _armv8_pmull_probe(void); # ifdef __aarch64__ void _armv8_sha512_probe(void); unsigned int _armv8_cpuid_probe(void); +void _armv8_rng_probe(void); + +size_t OPENSSL_rndr_asm(unsigned char *buf, size_t len); +size_t OPENSSL_rndrrs_asm(unsigned char *buf, size_t len); + +size_t OPENSSL_rndr_bytes(unsigned char *buf, size_t len); +size_t OPENSSL_rndrrs_bytes(unsigned char *buf, size_t len); + +static size_t OPENSSL_rndr_wrapper(size_t (*func)(unsigned char *, size_t), unsigned char *buf, size_t len) +{ + size_t buffer_size; + int i; + + for (i = 0; i < 8; i++) { + buffer_size = func(buf, len); + if (buffer_size == len) + break; + usleep(5000); /* 5000 microseconds (5 milliseconds) */ + } + return buffer_size; +} + +size_t OPENSSL_rndr_bytes(unsigned char *buf, size_t len) +{ + return OPENSSL_rndr_wrapper(OPENSSL_rndr_asm, buf, len); +} + +size_t OPENSSL_rndrrs_bytes(unsigned char *buf, size_t len) +{ + return OPENSSL_rndr_wrapper(OPENSSL_rndrrs_asm, buf, len); +} # endif uint32_t _armv7_tick(void); @@ -138,6 +170,9 @@ static unsigned long getauxval(unsigned long key) # define HWCAP_CE_SHA256 (1 << 6) # define HWCAP_CPUID (1 << 11) # define HWCAP_CE_SHA512 (1 << 21) + /* AT_HWCAP2 */ +# define HWCAP2 26 +# define HWCAP2_RNG (1 << 16) # endif void OPENSSL_cpuid_setup(void) @@ -212,6 +247,10 @@ void OPENSSL_cpuid_setup(void) OPENSSL_armcap_P |= ARMV8_CPUID; # endif } +# ifdef __aarch64__ + if (getauxval(HWCAP2) & HWCAP2_RNG) + OPENSSL_armcap_P |= ARMV8_RNG; +# endif # endif sigfillset(&all_masked); @@ -255,6 +294,12 @@ void OPENSSL_cpuid_setup(void) } # endif } +# ifdef __aarch64__ + if (sigsetjmp(ill_jmp, 1) == 0) { + _armv8_rng_probe(); + OPENSSL_armcap_P |= ARMV8_RNG; + } +# endif # endif /* Things that getauxval didn't tell us */ -- 2.47.2