Add Arm Assembly (aarch64) support for RNG
authorOrr Toledano <otoledan@amazon.com>
Wed, 19 May 2021 18:54:20 +0000 (18:54 +0000)
committerTomas Mraz <tomas@openssl.org>
Thu, 16 Dec 2021 11:38:09 +0000 (12:38 +0100)
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)

crypto/arm64cpuid.pl
crypto/arm_arch.h
crypto/armcap.c

index 11f0e5027942ecff6b8b8d3eea98ca6a4aa0509a..a86fa6073a1fd58b8f4a0f742666445946bc01d3 100755 (executable)
@@ -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: $!";
index aa380acce03c191bce8e750ba89a8294ccf05287..ca48045670812426e3250e227e130ca822e9bc6c 100644 (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
index 5b45a9d0f40c7dab80ab8632582a73ffc8d1c9cc..117c57efe4232a707e0ce802dc47fa59003b7113 100644 (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 */