/* * Copyright (C) 2016 Red Hat, Inc. * * Author: Nikos Mavrogiannopoulos * * This file is part of GnuTLS. * * The GnuTLS is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see * */ /* * The following code is an implementation of the AES-128-CBC cipher * using intel's AES instruction set. */ #include "errors.h" #include "gnutls_int.h" #include #include "errors.h" #ifdef HAVE_LIBNETTLE # include /* for key generation in 192 and 256 bits */ # include "sha-aarch64.h" # include "aes-aarch64.h" #endif #include "aarch64-common.h" #ifdef HAVE_GETAUXVAL # include # ifdef AT_HWCAP # define USE_AUXVAL # endif #endif #if defined(__GNUC__) __attribute__((visibility("hidden"))) #elif defined(__SUNPRO_C) __hidden #endif unsigned int _gnutls_arm_cpuid_s = 0; /* Our internal bit-string for cpu capabilities. Should be set * in GNUTLS_CPUID_OVERRIDE */ #define EMPTY_SET 1 static void capabilities_to_cpuid(unsigned capabilities) { _gnutls_arm_cpuid_s = 0; if (capabilities & EMPTY_SET) return; _gnutls_arm_cpuid_s |= capabilities; } /* Correspond to asm/hwcap.h for aarch64 */ #ifdef USE_AUXVAL #define HWCAP_ASIMD (1 << 1) #define HWCAP_AES (1 << 3) #define HWCAP_PMULL (1 << 4) #define HWCAP_SHA1 (1 << 5) #define HWCAP_SHA2 (1 << 6) #define HWCAP_SHA3 (1 << 17) #define HWCAP_SHA512 (1 << 21) #endif static void discover_caps(unsigned int *caps) { #ifdef USE_AUXVAL unsigned long c; c = getauxval(AT_HWCAP); if (c & HWCAP_ASIMD) *caps |= ARMV7_NEON; if (c & HWCAP_AES) *caps |= ARMV8_AES; if (c & HWCAP_PMULL) *caps |= ARMV8_PMULL; if (c & HWCAP_SHA1) *caps |= ARMV8_SHA1; if (c & HWCAP_SHA2) *caps |= ARMV8_SHA256; if (c & HWCAP_SHA512) *caps |= ARMV8_SHA512; #endif } static void _register_aarch64_crypto(unsigned capabilities) { int ret; if (capabilities == 0) { discover_caps(&_gnutls_arm_cpuid_s); } else { capabilities_to_cpuid(capabilities); } if (_gnutls_arm_cpuid_s & ARMV8_SHA1) { _gnutls_debug_log("Aarch64 SHA1 was detected\n"); ret = gnutls_crypto_single_digest_register(GNUTLS_DIG_SHA1, 80, &_gnutls_sha_aarch64, 0); if (ret < 0) { gnutls_assert(); } ret = gnutls_crypto_single_mac_register (GNUTLS_MAC_SHA1, 80, &_gnutls_hmac_sha_aarch64, 0); if (ret < 0) { gnutls_assert(); } } if (_gnutls_arm_cpuid_s & ARMV8_SHA256) { _gnutls_debug_log("Aarch64 SHA2 was detected\n"); ret = gnutls_crypto_single_digest_register(GNUTLS_DIG_SHA224, 80, &_gnutls_sha_aarch64, 0); if (ret < 0) { gnutls_assert(); } ret = gnutls_crypto_single_mac_register (GNUTLS_MAC_SHA224, 80, &_gnutls_hmac_sha_aarch64, 0); if (ret < 0) { gnutls_assert(); } ret = gnutls_crypto_single_digest_register(GNUTLS_DIG_SHA256, 80, &_gnutls_sha_aarch64, 0); if (ret < 0) { gnutls_assert(); } ret = gnutls_crypto_single_mac_register (GNUTLS_MAC_SHA256, 80, &_gnutls_hmac_sha_aarch64, 0); if (ret < 0) { gnutls_assert(); } ret = gnutls_crypto_single_digest_register(GNUTLS_DIG_SHA384, 80, &_gnutls_sha_aarch64, 0); if (ret < 0) { gnutls_assert(); } ret = gnutls_crypto_single_mac_register (GNUTLS_MAC_SHA384, 80, &_gnutls_hmac_sha_aarch64, 0); if (ret < 0) { gnutls_assert(); } ret = gnutls_crypto_single_digest_register(GNUTLS_DIG_SHA512, 80, &_gnutls_sha_aarch64, 0); if (ret < 0) { gnutls_assert(); } ret = gnutls_crypto_single_mac_register (GNUTLS_MAC_SHA512, 80, &_gnutls_hmac_sha_aarch64, 0); if (ret < 0) { gnutls_assert(); } } if (_gnutls_arm_cpuid_s & ARMV8_AES) { _gnutls_debug_log("Aarch64 AES was detected\n"); if (_gnutls_arm_cpuid_s & ARMV8_PMULL) { _gnutls_debug_log("Aarch64 PMULL was detected\n"); ret = gnutls_crypto_single_cipher_register (GNUTLS_CIPHER_AES_128_GCM, 90, &_gnutls_aes_gcm_aarch64, 0); if (ret < 0) { gnutls_assert(); } ret = gnutls_crypto_single_cipher_register (GNUTLS_CIPHER_AES_256_GCM, 90, &_gnutls_aes_gcm_aarch64, 0); if (ret < 0) { gnutls_assert(); } } ret = gnutls_crypto_single_cipher_register (GNUTLS_CIPHER_AES_128_CBC, 90, &_gnutls_aes_cbc_aarch64, 0); if (ret < 0) { gnutls_assert(); } ret = gnutls_crypto_single_cipher_register (GNUTLS_CIPHER_AES_256_CBC, 90, &_gnutls_aes_cbc_aarch64, 0); if (ret < 0) { gnutls_assert(); } ret = gnutls_crypto_single_cipher_register (GNUTLS_CIPHER_AES_128_CCM, 90, &_gnutls_aes_ccm_aarch64, 0); if (ret < 0) { gnutls_assert(); } ret = gnutls_crypto_single_cipher_register (GNUTLS_CIPHER_AES_256_CCM, 90, &_gnutls_aes_ccm_aarch64, 0); if (ret < 0) { gnutls_assert(); } } return; } void register_aarch64_crypto(void) { unsigned capabilities = 0; char *p; p = secure_getenv("GNUTLS_CPUID_OVERRIDE"); if (p) { capabilities = strtol(p, NULL, 0); } _register_aarch64_crypto(capabilities); }