diff options
Diffstat (limited to 'crypto')
-rw-r--r-- | crypto/Kconfig | 31 | ||||
-rw-r--r-- | crypto/Makefile | 4 | ||||
-rw-r--r-- | crypto/crc32.c | 174 | ||||
-rw-r--r-- | crypto/digest.c | 11 | ||||
-rw-r--r-- | crypto/jwt.c | 240 | ||||
-rw-r--r-- | crypto/rsa.c | 4 |
6 files changed, 330 insertions, 134 deletions
diff --git a/crypto/Kconfig b/crypto/Kconfig index f32accb3d0..d1360a2101 100644 --- a/crypto/Kconfig +++ b/crypto/Kconfig @@ -86,6 +86,27 @@ config DIGEST_SHA256_ARM SHA-256 secure hash standard (DFIPS 180-2) implemented using optimized ARM assembler and NEON, when available. +config DIGEST_SHA1_ARM64_CE + tristate "SHA-1 digest algorithm (ARMv8 Crypto Extensions)" + depends on CPU_V8 + select HAVE_DIGEST_SHA1 + help + SHA-1 secure hash algorithm (FIPS 180) + + Architecture: arm64 using: + - ARMv8 Crypto Extensions + +config DIGEST_SHA256_ARM64_CE + tristate "SHA-224/256 digest algorithm (ARMv8 Crypto Extensions)" + depends on CPU_V8 + select HAVE_DIGEST_SHA256 + select HAVE_DIGEST_SHA224 + help + SHA-224 and SHA-256 secure hash algorithms (FIPS 180) + + Architecture: arm64 using: + - ARMv8 Crypto Extensions + endif config CRYPTO_PBKDF2 @@ -100,6 +121,7 @@ config CRYPTO_RSA config CRYPTO_RSA_BUILTIN_KEYS bool default y if CRYPTO_RSA_KEY != "" + select RSATOC config CRYPTO_RSA_KEY depends on CRYPTO_RSA @@ -109,6 +131,9 @@ config CRYPTO_RSA_KEY X.509 certificates to be included into barebox. If the string starts with "pkcs11:" it is interpreted as a PKCS#11 URI rather than a file. + This avoids the mkimage dependency of CONFIG_BOOTM_FITIMAGE_PUBKEY + at the cost of an openssl build-time dependency. + config CRYPTO_RSA_KEY_NAME_HINT depends on CRYPTO_RSA string "FIT image key name hint" @@ -122,4 +147,10 @@ config CRYPTO_KEYSTORE This is a simple keystore, which can be used to pass keys between several components via simple interface. +config JWT + bool "JSON Web Token support" if COMPILE_TEST + select JSMN + select BASE64 + select CRYPTO_RSA + endmenu diff --git a/crypto/Makefile b/crypto/Makefile index 22035d4f69..cf041dd6b3 100644 --- a/crypto/Makefile +++ b/crypto/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only -obj-$(CONFIG_CRC32) += crc32.o +obj-pbl-$(CONFIG_CRC32) += crc32.o obj-pbl-$(CONFIG_CRC_ITU_T) += crc-itu-t.o obj-$(CONFIG_CRC7) += crc7.o obj-$(CONFIG_DIGEST) += digest.o @@ -19,6 +19,8 @@ obj-$(CONFIG_CRYPTO_PBKDF2) += pbkdf2.o obj-$(CONFIG_CRYPTO_RSA) += rsa.o obj-$(CONFIG_CRYPTO_KEYSTORE) += keystore.o +obj-$(CONFIG_JWT) += jwt.o + extra-$(CONFIG_CRYPTO_RSA_BUILTIN_KEYS) += rsa-keys.h ifdef CONFIG_CRYPTO_RSA_BUILTIN_KEYS diff --git a/crypto/crc32.c b/crypto/crc32.c index 998cbc9de2..5013556c0b 100644 --- a/crypto/crc32.c +++ b/crypto/crc32.c @@ -8,7 +8,7 @@ * For conditions of distribution and use, see copyright notice in zlib.h */ -#ifdef __BAREBOX__ /* Shut down "ANSI does not permit..." warnings */ +#ifdef __BAREBOX__ /* Shut down "ANSI does not permit..." warnings */ #include <common.h> #include <xfuncs.h> #include <fs.h> @@ -22,9 +22,7 @@ #define STATIC static inline #endif -#ifdef CONFIG_DYNAMIC_CRC_TABLE - -static ulong *crc_table; +static uint32_t crc_table[sizeof(uint32_t) * 256]; /* Generate a table for a byte-wise 32-bit CRC calculation on the polynomial: @@ -52,145 +50,68 @@ static ulong *crc_table; */ static void make_crc_table(void) { - ulong c; - int n, k; - ulong poly; /* polynomial exclusive-or pattern */ - /* terms of polynomial defining this crc (except x^32): */ - static const char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; - - /* make exclusive-or pattern from polynomial (0xedb88320L) */ - poly = 0L; - for (n = 0; n < sizeof(p)/sizeof(char); n++) - poly |= 1L << (31 - p[n]); - - crc_table = xmalloc(sizeof(ulong) * 256); - - for (n = 0; n < 256; n++) - { - c = (ulong)n; - for (k = 0; k < 8; k++) - c = c & 1 ? poly ^ (c >> 1) : c >> 1; - crc_table[n] = c; - } + uint32_t c; + int n, k; + uint32_t poly; /* polynomial exclusive-or pattern */ + /* terms of polynomial defining this crc (except x^32): */ + static const char p[] = { 0, 1, 2, 4, 5, 7, 8, 10, 11, 12, 16, 22, 23, 26 }; + + if (crc_table[1]) + return; + + /* make exclusive-or pattern from polynomial (0xedb88320L) */ + poly = 0; + for (n = 0; n < sizeof(p) / sizeof(char); n++) + poly |= 1U << (31 - p[n]); + + for (n = 0; n < 256; n++) { + c = (uint32_t) n; + for (k = 0; k < 8; k++) + c = c & 1 ? poly ^ (c >> 1) : c >> 1; + crc_table[n] = c; + } } -#else -/* ======================================================================== - * Table of CRC-32's of all single-byte values (made by make_crc_table) - */ -static const ulong crc_table[256] = { - 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, - 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, - 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, - 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, - 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, - 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, - 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, - 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, - 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, - 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, - 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, - 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, - 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, - 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, - 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, - 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, - 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, - 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, - 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, - 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, - 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, - 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, - 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, - 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, - 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, - 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, - 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, - 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, - 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, - 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, - 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, - 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, - 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, - 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, - 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, - 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, - 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, - 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, - 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, - 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, - 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, - 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, - 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, - 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, - 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, - 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, - 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, - 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, - 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, - 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, - 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, - 0x2d02ef8dL -}; -#endif - -/* ========================================================================= */ #define DO1(buf) crc = crc_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8); #define DO2(buf) DO1(buf); DO1(buf); #define DO4(buf) DO2(buf); DO2(buf); #define DO8(buf) DO4(buf); DO4(buf); -/* ========================================================================= */ -STATIC uint32_t crc32(uint32_t crc, const void *_buf, unsigned int len) -{ - const unsigned char *buf = _buf; - -#ifdef CONFIG_DYNAMIC_CRC_TABLE - if (!crc_table) - make_crc_table(); -#endif - crc = crc ^ 0xffffffffL; - while (len >= 8) - { - DO8(buf); - len -= 8; - } - if (len) do { - DO1(buf); - } while (--len); - return crc ^ 0xffffffffL; -} -#ifdef __BAREBOX__ -EXPORT_SYMBOL(crc32); -#endif - /* No ones complement version. JFFS2 (and other things ?) * don't use ones compliment in their CRC calculations. */ STATIC uint32_t crc32_no_comp(uint32_t crc, const void *_buf, unsigned int len) { - const unsigned char *buf = _buf; + const unsigned char *buf = _buf; -#ifdef CONFIG_DYNAMIC_CRC_TABLE - if (!crc_table) - make_crc_table(); -#endif - while (len >= 8) - { - DO8(buf); - len -= 8; - } - if (len) do { - DO1(buf); - } while (--len); - - return crc; + make_crc_table(); + + while (len >= 8) { + DO8(buf); + len -= 8; + } + if (len) + do { + DO1(buf); + } while (--len); + + return crc; +} + +STATIC uint32_t crc32(uint32_t crc, const void *buf, unsigned int len) +{ + return ~crc32_no_comp(~crc, buf, len); } +#ifdef __BAREBOX__ +EXPORT_SYMBOL(crc32); +#endif + STATIC uint32_t crc32_be(uint32_t crc, const void *_buf, unsigned int len) { const unsigned char *buf = _buf; int i; + while (len--) { crc ^= *buf++ << 24; for (i = 0; i < 8; i++) @@ -199,8 +120,8 @@ STATIC uint32_t crc32_be(uint32_t crc, const void *_buf, unsigned int len) return crc; } -STATIC int file_crc(char *filename, ulong start, ulong size, ulong *crc, - ulong *total) +STATIC int file_crc(char *filename, ulong start, ulong size, ulong * crc, + ulong * total) { int fd, now; int ret = 0; @@ -250,6 +171,7 @@ out: return ret; } + #ifdef __BAREBOX__ EXPORT_SYMBOL(file_crc); #endif diff --git a/crypto/digest.c b/crypto/digest.c index 621d384168..dd2c2ee317 100644 --- a/crypto/digest.c +++ b/crypto/digest.c @@ -27,8 +27,6 @@ static LIST_HEAD(digests); -static struct digest_algo *digest_algo_get_by_name(const char *name); - static int dummy_init(struct digest *d) { return 0; @@ -106,7 +104,7 @@ EXPORT_SYMBOL(digest_algo_unregister); static struct digest_algo *digest_algo_get_by_name(const char *name) { - struct digest_algo *d = NULL; + struct digest_algo *d_by_name = NULL, *d_by_driver = NULL; struct digest_algo *tmp; int priority = -1; @@ -114,17 +112,20 @@ static struct digest_algo *digest_algo_get_by_name(const char *name) return NULL; list_for_each_entry(tmp, &digests, list) { + if (strcmp(tmp->base.driver_name, name) == 0) + d_by_driver = tmp; + if (strcmp(tmp->base.name, name) != 0) continue; if (tmp->base.priority <= priority) continue; - d = tmp; + d_by_name = tmp; priority = tmp->base.priority; } - return d; + return d_by_name ?: d_by_driver; } static struct digest_algo *digest_algo_get_by_algo(enum hash_algo algo) diff --git a/crypto/jwt.c b/crypto/jwt.c new file mode 100644 index 0000000000..f8d678718a --- /dev/null +++ b/crypto/jwt.c @@ -0,0 +1,240 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#define pr_fmt(fmt) "jwt: " fmt + +#include <crypto/jwt.h> +#include <rsa.h> +#include <errno.h> +#include <linux/printk.h> +#include <base64.h> +#include <jsmn.h> +#include <linux/ctype.h> + +#define JP(...) (const char *[]) { __VA_ARGS__, NULL } + +static enum hash_algo digest_algo_by_jwt_alg(enum jwt_alg alg) +{ + switch (alg) { + case JWT_ALG_RS256: + return HASH_ALGO_SHA256; + case JWT_ALG_RS384: + return HASH_ALGO_SHA384; + case JWT_ALG_RS512: + return HASH_ALGO_SHA512; + default: + BUG(); + } +} + +static u8 *do_hash(const u8 *buf, size_t len, enum hash_algo algo) +{ + struct digest *digest; + int ret = 0; + u8 *hash; + + digest = digest_alloc_by_algo(algo); + if (!digest) { + pr_err("signature algorithm not supported\n"); + return ERR_PTR(-ENOSYS); + } + + hash = xzalloc(digest_length(digest)); + ret = digest_digest(digest, buf, len, hash); + digest_free(digest); + + if (ret) { + free(hash); + return ERR_PTR(ret); + } + + return hash; +} + +static int jwt_part_parse(struct jwt_part *part, const char *content, size_t len) +{ + size_t decoded_len; + + part->content = xmalloc(len); + decoded_len = decode_base64url(part->content, len, content); + part->content[decoded_len] = '\0'; + part->tokens = jsmn_parse_alloc(part->content, decoded_len, &part->token_count); + if (!part->tokens) { + free(part->content); + return -EILSEQ; + } + + return 0; +} + +static void jwt_part_free(struct jwt_part *part) +{ + free(part->tokens); + free(part->content); +} + +static const char *jwt_alg_names[] = { + [JWT_ALG_NONE] = "none", + [JWT_ALG_HS256] = "HS256", + [JWT_ALG_HS384] = "HS384", + [JWT_ALG_HS512] = "HS512", + [JWT_ALG_PS256] = "PS256", + [JWT_ALG_PS384] = "PS384", + [JWT_ALG_PS512] = "PS512", + [JWT_ALG_RS256] = "RS256", + [JWT_ALG_RS384] = "RS384", + [JWT_ALG_RS512] = "RS512", + [JWT_ALG_ES256] = "ES256", + [JWT_ALG_ES256K] = "ES256K", + [JWT_ALG_ES384] = "ES384", + [JWT_ALG_ES512] = "ES512", + [JWT_ALG_EDDSA] = "EDDSA", +}; + +static bool jwt_header_ok(struct jwt *jwt, enum jwt_alg alg) +{ + struct jwt_part *header = &jwt->header; + const jsmntok_t *token; + + token = jsmn_locate(JP("typ"), header->content, header->tokens); + if (!token) + return false; + + if (!jsmn_strcase_eq("JWT", header->content, token)) + return false; + + if (alg >= ARRAY_SIZE(jwt_alg_names)) + return false; + + token = jsmn_locate(JP("alg"), header->content, header->tokens); + if (!token) + return false; + + return jsmn_strcase_eq(jwt_alg_names[alg], header->content, token); +} + +void jwt_free(struct jwt *jwt) +{ + jwt_part_free(&jwt->payload); + jwt_part_free(&jwt->header); + free(jwt); +} + +const char *jwt_split(const char *token, + const char **payload, const char **signature, const char **end) +{ + const char *p, *p_end; + + token = skip_spaces(token); + + p = strchr(token, '.'); + if (!p) + return ERR_PTR(-EINVAL); + if (payload) + *payload = ++p; + + p = strchr(p, '.'); + if (!p) + return ERR_PTR(-EINVAL); + if (signature) + *signature = ++p; + + /* seek to first space or '\0' */ + for (p_end = p; *p_end && !isspace(*p_end); p_end++) + ; + + /* ensure the trailing spaces aren't followed by anything */ + if (*skip_spaces(p_end) != '\0') + return ERR_PTR(-EINVAL); + + *end = p_end; + + return token; +} + +struct jwt *jwt_decode(const char *token, const struct jwt_key *key) +{ + const char *alg_name = jwt_alg_names[key->alg]; + enum hash_algo hash_algo; + const char *payload, *signature, *end; + u8 *sigbin; + size_t sig_len, sigbin_len; + struct jwt *jwt; + u8 *hash; + int ret; + + token = jwt_split(token, &payload, &signature, &end); + if (IS_ERR(token)) + return ERR_CAST(token); + + sig_len = end - signature; + + switch (key->alg) { + case JWT_ALG_RS256: + case JWT_ALG_RS384: + case JWT_ALG_RS512: + if (sig_len == 0) + return ERR_PTR(-EILSEQ); + + sigbin = xzalloc(sig_len); + sigbin_len = decode_base64url(sigbin, sig_len, signature); + + hash_algo = digest_algo_by_jwt_alg(key->alg); + hash = do_hash(token, signature - token - 1, hash_algo); + if (IS_ERR(hash)) { + free(sigbin); + return ERR_CAST(hash); + } + + ret = rsa_verify(key->material.rsa_pub, sigbin, sigbin_len, hash, + hash_algo); + free(hash); + free(sigbin); + if (ret < 0) { + pr_debug("%s signature does not match: %pe\n", + alg_name, ERR_PTR(ret)); + return ERR_PTR(ret); + } + + break; + default: + return ERR_PTR(-ENOSYS); + } + + pr_debug("verification for algo %s ok\n", alg_name); + + jwt = xzalloc(sizeof(*jwt)); + + ret = jwt_part_parse(&jwt->header, token, payload - token - 1); + if (ret || !jwt_header_ok(jwt, key->alg)) { + ret = ret ?: -EINVAL; + pr_debug("failed to parse header: %pe\n", ERR_PTR(ret)); + goto err; + } + + ret = jwt_part_parse(&jwt->payload, payload, signature - payload - 1); + if (ret) { + pr_debug("failed to parse payload: %pe\n", ERR_PTR(ret)); + goto err; + } + + return jwt; + +err: + jwt_free(jwt); + return ERR_PTR(ret); +} + +const char *jwt_get_payload(const struct jwt *t) +{ + return t->payload.content; +} + +const jsmntok_t *jwt_get_claim(const struct jwt *t, const char *claim) +{ + return jsmn_locate(JP(claim), t->payload.content, t->payload.tokens); +} + +char *jwt_get_claim_str(const struct jwt *t, const char *claim) +{ + return jsmn_strdup(JP(claim), t->payload.content, t->payload.tokens); +} diff --git a/crypto/rsa.c b/crypto/rsa.c index fc21efdb6d..b798badce0 100644 --- a/crypto/rsa.c +++ b/crypto/rsa.c @@ -507,8 +507,8 @@ static void rsa_init_keys_of(void) for_each_child_of_node(sigs, sig) { key = rsa_of_read_key(sig); if (IS_ERR(key)) { - pr_err("Cannot read rsa key from %s: %pe\n", - sig->full_name, key); + pr_err("Cannot read rsa key from %pOF: %pe\n", + sig, key); continue; } |