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 <pauli@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/15361)
This commit is contained in:
Orr Toledano 2021-05-19 18:54:20 +00:00 committed by Tomas Mraz
parent a56bb5d64e
commit efa1f22483
3 changed files with 106 additions and 0 deletions

View File

@ -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: $!";

View File

@ -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

View File

@ -17,6 +17,7 @@
#include <sys/sysctl.h>
#endif
#include "internal/cryptlib.h"
#include <unistd.h>
#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 */