diff --git a/drivers/crypto/rockchip/Makefile b/drivers/crypto/rockchip/Makefile index 53e34aa47bc1..f11277ee6c00 100644 --- a/drivers/crypto/rockchip/Makefile +++ b/drivers/crypto/rockchip/Makefile @@ -11,12 +11,19 @@ rk_crypto-$(CONFIG_CRYPTO_DEV_ROCKCHIP_V1) += \ rk_crypto_v1_ahash.o \ rk_crypto_v1_skcipher.o +$(obj)/rk_sm2signature.asn1.o: $(obj)/rk_sm2signature.asn1.c $(obj)/rk_sm2signature.asn1.h +$(obj)/rk_ecdsasignature.asn1.o: $(obj)/rk_ecdsasignature.asn1.c $(obj)/rk_ecdsasignature.asn1.h +$(obj)/rk_crypto_ecc.o: $(obj)/rk_sm2signature.asn1.h $(obj)/rk_ecdsasignature.asn1.h + rk_crypto-$(CONFIG_CRYPTO_DEV_ROCKCHIP_V2) += \ rk_crypto_v2.o \ rk_crypto_v2_ahash.o \ rk_crypto_v2_skcipher.o \ rk_crypto_v2_akcipher.o \ rk_crypto_v2_pka.o \ + rk_crypto_ecc.o \ + rk_sm2signature.asn1.o \ + rk_ecdsasignature.asn1.o \ rk_crypto_bignum.o rk_crypto-$(CONFIG_CRYPTO_DEV_ROCKCHIP_V3) += \ @@ -25,6 +32,9 @@ rk_crypto-$(CONFIG_CRYPTO_DEV_ROCKCHIP_V3) += \ rk_crypto_v3_skcipher.o \ rk_crypto_v2_akcipher.o \ rk_crypto_v2_pka.o \ + rk_crypto_ecc.o \ + rk_sm2signature.asn1.o \ + rk_ecdsasignature.asn1.o \ rk_crypto_bignum.o obj-$(CONFIG_CRYPTO_DEV_ROCKCHIP_DEV) += cryptodev_linux/ diff --git a/drivers/crypto/rockchip/rk_crypto_bignum.c b/drivers/crypto/rockchip/rk_crypto_bignum.c index 690c2fdf58ba..6ff1808974d2 100644 --- a/drivers/crypto/rockchip/rk_crypto_bignum.c +++ b/drivers/crypto/rockchip/rk_crypto_bignum.c @@ -128,3 +128,91 @@ int rk_bn_highest_bit(const struct rk_bignum *bn) return (int)(bn->n_words - 1) * RK_WORD_SIZE + b; } + +void rk_ecc_free_point(struct rk_ecp_point *point) +{ + if (!point) + return; + + rk_bn_free(point->x); + rk_bn_free(point->y); + + kfree(point); +} + +struct rk_ecp_point *rk_ecc_alloc_point_zero(u32 max_size) +{ + struct rk_ecp_point *point = NULL; + + point = kzalloc(sizeof(*point), GFP_KERNEL); + if (!point) + return NULL; + + point->x = rk_bn_alloc(max_size); + if (!point->x) + goto error; + + point->y = rk_bn_alloc(max_size); + if (!point->y) + goto error; + + return point; + +error: + rk_ecc_free_point(point); + + return NULL; +} + +struct rk_ecp_point *rk_ecc_alloc_point(const uint8_t *x, uint32_t x_len, + const uint8_t *y, uint32_t y_len, + enum bignum_endian endian, u32 max_size) +{ + struct rk_ecp_point *point = NULL; + + point = kzalloc(sizeof(*point), GFP_KERNEL); + if (!point) + return NULL; + + point->x = rk_bn_alloc(max_size); + if (!point->x) + goto error; + + if (rk_bn_set_data(point->x, x, x_len, endian) != 0) + goto error; + + point->y = rk_bn_alloc(max_size); + if (!point->y) + goto error; + + if (rk_bn_set_data(point->y, y, y_len, endian) != 0) + goto error; + + return point; + +error: + rk_ecc_free_point(point); + + return NULL; +} + +bool rk_ecp_point_is_zero(struct rk_ecp_point *point) +{ + uint32_t i; + bool ret = true; + + if (!point || !point->x || !point->y) + return false; + + for (i = 0; i < point->x->n_words; i++) { + if (point->x->data[i] != 0) + ret = false; + } + + for (i = 0; i < point->y->n_words; i++) { + if (point->y->data[i] != 0) + ret = false; + } + + return ret; +} diff --git a/drivers/crypto/rockchip/rk_crypto_bignum.h b/drivers/crypto/rockchip/rk_crypto_bignum.h index 780aa87661eb..845eeddc5d84 100644 --- a/drivers/crypto/rockchip/rk_crypto_bignum.h +++ b/drivers/crypto/rockchip/rk_crypto_bignum.h @@ -17,6 +17,11 @@ struct rk_bignum { u32 *data; }; +struct rk_ecp_point { + struct rk_bignum *x; /*!< the point's X coordinate */ + struct rk_bignum *y; /*!< the point's Y coordinate */ +}; + struct rk_bignum *rk_bn_alloc(u32 max_size); void rk_bn_free(struct rk_bignum *bn); int rk_bn_set_data(struct rk_bignum *bn, const u8 *data, u32 size, enum bignum_endian endian); @@ -24,4 +29,11 @@ int rk_bn_get_data(const struct rk_bignum *bn, u8 *data, u32 size, enum bignum_e u32 rk_bn_get_size(const struct rk_bignum *bn); int rk_bn_highest_bit(const struct rk_bignum *src); +struct rk_ecp_point *rk_ecc_alloc_point_zero(u32 max_size); +struct rk_ecp_point *rk_ecc_alloc_point(const uint8_t *x, uint32_t x_len, + const uint8_t *y, uint32_t y_len, + enum bignum_endian endian, u32 max_size); +void rk_ecc_free_point(struct rk_ecp_point *point); +bool rk_ecp_point_is_zero(struct rk_ecp_point *point); + #endif diff --git a/drivers/crypto/rockchip/rk_crypto_core.c b/drivers/crypto/rockchip/rk_crypto_core.c index 7b1c6ed81c45..4a75519d214f 100644 --- a/drivers/crypto/rockchip/rk_crypto_core.c +++ b/drivers/crypto/rockchip/rk_crypto_core.c @@ -672,7 +672,7 @@ static char *crypto_full_algs_name[] = { "ecb(des3_ede)", "cbc(des3_ede)", "cfb(des3_ede)", "ofb(des3_ede)", "sha1", "sha224", "sha256", "sha384", "sha512", "md5", "sm3", "hmac(sha1)", "hmac(sha256)", "hmac(sha512)", "hmac(md5)", "hmac(sm3)", - "rsa" + "rsa", "ecc-192", "ecc-224", "ecc-256", "sm2", }; static const struct rk_crypto_soc_data px30_soc_data = diff --git a/drivers/crypto/rockchip/rk_crypto_core.h b/drivers/crypto/rockchip/rk_crypto_core.h index a2d4fbd14f78..aba37a9cc1b0 100644 --- a/drivers/crypto/rockchip/rk_crypto_core.h +++ b/drivers/crypto/rockchip/rk_crypto_core.h @@ -213,9 +213,19 @@ struct rk_cipher_ctx { struct rk_rsa_ctx { struct rk_alg_ctx algs_ctx; - struct rk_bignum *n; - struct rk_bignum *e; - struct rk_bignum *d; + struct rk_bignum *n; + struct rk_bignum *e; + struct rk_bignum *d; + + struct rk_crypto_dev *rk_dev; +}; + +struct rk_ecc_ctx { + struct rk_alg_ctx algs_ctx; + uint32_t group_id; + uint32_t nbits; + bool pub_key_set; + struct rk_ecp_point *point_Q; struct rk_crypto_dev *rk_dev; }; @@ -245,6 +255,15 @@ struct rk_crypto_algt { bool valid_flag; }; +enum rk_asym_algo { + ASYM_ALGO_RSA, + ASYM_ALGO_ECC_P192, + ASYM_ALGO_ECC_P224, + ASYM_ALGO_ECC_P256, + ASYM_ALGO_SM2, + ASYM_ALGO_MAX, +}; + enum rk_hash_algo { HASH_ALGO_MD5, HASH_ALGO_SHA1, @@ -439,6 +458,27 @@ enum rk_cipher_mode { } \ } +#define RK_ASYM_ECC_INIT(key_bits) {\ + .name = "ecc-" #key_bits, \ + .type = ALG_TYPE_ASYM, \ + .algo = ASYM_ALGO_ECC_P##key_bits, \ + .alg.asym = { \ + .verify = rk_ecc_verify, \ + .set_pub_key = rk_ecc_set_pub_key, \ + .max_size = rk_ecc_max_size, \ + .init = rk_ecc_init_tfm, \ + .exit = rk_ecc_exit_tfm, \ + .reqsize = 64, \ + .base = { \ + .cra_name = "ecdsa-nist-p" #key_bits, \ + .cra_driver_name = "ecdsa-nist-p" #key_bits "-rk", \ + .cra_priority = RK_CRYPTO_PRIORITY, \ + .cra_module = THIS_MODULE, \ + .cra_ctxsize = sizeof(struct rk_ecc_ctx), \ + },\ + } \ +} + #define CRYPTO_MAJOR_VER(ver) ((ver) & 0x0f000000) #define CRYPTO_MAJOR_VER_3 0x03000000 diff --git a/drivers/crypto/rockchip/rk_crypto_ecc.c b/drivers/crypto/rockchip/rk_crypto_ecc.c new file mode 100644 index 000000000000..050df55882e7 --- /dev/null +++ b/drivers/crypto/rockchip/rk_crypto_ecc.c @@ -0,0 +1,469 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2024 Rockchip Electronics Co., Ltd. + * + * Author: Lin Jinhan + * + */ + +#include + +#include "rk_crypto_core.h" +#include "rk_crypto_v2.h" +#include "rk_crypto_v2_reg.h" +#include "rk_crypto_ecc.h" + +static void __iomem *ecc_base; + +#define WORDS2BYTES(words) ((words) * 4) + +#define RK_ECP_POLL_PERIOD_US 10000 +#define RK_ECP_POLL_TIMEOUT_US 500000 + +#define RK_LOAD_GROUP_A(G) do { \ + grp->curve_name = #G; \ + grp->wide = G ## _wide;\ + grp->p = G ## _p; \ + grp->p_len = sizeof(G ## _p); \ + grp->a = G ## _a; \ + grp->a_len = sizeof(G ## _a); \ + grp->n = G ## _n; \ + grp->n_len = sizeof(G ## _n); \ + grp->gx = G ## _gx; \ + grp->gx_len = sizeof(G ## _gx); \ + grp->gy = G ## _gy; \ + grp->gy_len = sizeof(G ## _gy); \ + } while (0) + +/* + * Domain parameters for secp192r1 + */ +static const uint32_t secp192r1_wide = RK_ECC_CURVE_WIDE_192; + +static const uint8_t secp192r1_p[] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +}; + +static const uint8_t secp192r1_a[] = { + 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +}; + +static const uint8_t secp192r1_gx[] = { + 0x12, 0x10, 0xFF, 0x82, 0xFD, 0x0A, 0xFF, 0xF4, + 0x00, 0x88, 0xA1, 0x43, 0xEB, 0x20, 0xBF, 0x7C, + 0xF6, 0x90, 0x30, 0xB0, 0x0E, 0xA8, 0x8D, 0x18, +}; + +static const uint8_t secp192r1_gy[] = { + 0x11, 0x48, 0x79, 0x1E, 0xA1, 0x77, 0xF9, 0x73, + 0xD5, 0xCD, 0x24, 0x6B, 0xED, 0x11, 0x10, 0x63, + 0x78, 0xDA, 0xC8, 0xFF, 0x95, 0x2B, 0x19, 0x07, +}; + +static const uint8_t secp192r1_n[] = { + 0x31, 0x28, 0xD2, 0xB4, 0xB1, 0xC9, 0x6B, 0x14, + 0x36, 0xF8, 0xDE, 0x99, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +}; + +/* + * Domain parameters for secp224r1 + */ +static const uint32_t secp224r1_wide = RK_ECC_CURVE_WIDE_224; + +static const uint8_t secp224r1_p[] = { + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, +}; + +static const uint8_t secp224r1_a[] = { + 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, +}; + +static const uint8_t secp224r1_gx[] = { + 0x21, 0x1D, 0x5C, 0x11, 0xD6, 0x80, 0x32, 0x34, + 0x22, 0x11, 0xC2, 0x56, 0xD3, 0xC1, 0x03, 0x4A, + 0xB9, 0x90, 0x13, 0x32, 0x7F, 0xBF, 0xB4, 0x6B, + 0xBD, 0x0C, 0x0E, 0xB7, +}; + +static const uint8_t secp224r1_gy[] = { + 0x34, 0x7E, 0x00, 0x85, 0x99, 0x81, 0xD5, 0x44, + 0x64, 0x47, 0x07, 0x5A, 0xA0, 0x75, 0x43, 0xCD, + 0xE6, 0xDF, 0x22, 0x4C, 0xFB, 0x23, 0xF7, 0xB5, + 0x88, 0x63, 0x37, 0xBD, +}; + +static const uint8_t secp224r1_n[] = { + 0x3D, 0x2A, 0x5C, 0x5C, 0x45, 0x29, 0xDD, 0x13, + 0x3E, 0xF0, 0xB8, 0xE0, 0xA2, 0x16, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, +}; + +/* + * Domain parameters for secp256r1 + */ +static const uint32_t secp256r1_wide = RK_ECC_CURVE_WIDE_256; + +static const uint8_t secp256r1_p[] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, +}; + +static const uint8_t secp256r1_a[] = { + 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, +}; + +static const uint8_t secp256r1_gx[] = { + 0x96, 0xC2, 0x98, 0xD8, 0x45, 0x39, 0xA1, 0xF4, + 0xA0, 0x33, 0xEB, 0x2D, 0x81, 0x7D, 0x03, 0x77, + 0xF2, 0x40, 0xA4, 0x63, 0xE5, 0xE6, 0xBC, 0xF8, + 0x47, 0x42, 0x2C, 0xE1, 0xF2, 0xD1, 0x17, 0x6B, +}; + +static const uint8_t secp256r1_gy[] = { + 0xF5, 0x51, 0xBF, 0x37, 0x68, 0x40, 0xB6, 0xCB, + 0xCE, 0x5E, 0x31, 0x6B, 0x57, 0x33, 0xCE, 0x2B, + 0x16, 0x9E, 0x0F, 0x7C, 0x4A, 0xEB, 0xE7, 0x8E, + 0x9B, 0x7F, 0x1A, 0xFE, 0xE2, 0x42, 0xE3, 0x4F, +}; + +static const uint8_t secp256r1_n[] = { + 0x51, 0x25, 0x63, 0xFC, 0xC2, 0xCA, 0xB9, 0xF3, + 0x84, 0x9E, 0x17, 0xA7, 0xAD, 0xFA, 0xE6, 0xBC, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, +}; + +/* + * Domain parameters for sm2p256v1_p + */ +static const uint32_t sm2p256v1_wide = RK_ECC_CURVE_WIDE_256; + +static const uint8_t sm2p256v1_p[] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, +}; + +static const uint8_t sm2p256v1_a[] = { + 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, +}; + +static const uint8_t sm2p256v1_gx[] = { + 0xC7, 0x74, 0x4C, 0x33, 0x89, 0x45, 0x5A, 0x71, + 0xE1, 0x0B, 0x66, 0xF2, 0xBF, 0x0B, 0xE3, 0x8F, + 0x94, 0xC9, 0x39, 0x6A, 0x46, 0x04, 0x99, 0x5F, + 0x19, 0x81, 0x19, 0x1F, 0x2C, 0xAE, 0xC4, 0x32, +}; + +static const uint8_t sm2p256v1_gy[] = { + 0xA0, 0xF0, 0x39, 0x21, 0xE5, 0x32, 0xDF, 0x02, + 0x40, 0x47, 0x2A, 0xC6, 0x7C, 0x87, 0xA9, 0xD0, + 0x53, 0x21, 0x69, 0x6B, 0xE3, 0xCE, 0xBD, 0x59, + 0x9C, 0x77, 0xF6, 0xF4, 0xA2, 0x36, 0x37, 0xBC, +}; + +static const uint8_t sm2p256v1_n[] = { + 0x23, 0x41, 0xD5, 0x39, 0x09, 0xF4, 0xBB, 0x53, + 0x2B, 0x05, 0xC6, 0x21, 0x6B, 0xDF, 0x03, 0x72, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, +}; + +static void dump_ecc_sram(void) +{ +#ifdef DEBUG + int i; + uint32_t len = 0x300; + uint32_t *buffer; + + buffer = kzalloc(len, GFP_KERNEL); + + for (i = 0; i < len / 4; i++) + buffer[i] = ((uint32_t *)SM2_RAM_BASE)[i]; + + CRYPTO_DUMPHEX("ECC SRAM ", buffer, len); + + kfree(buffer); +#endif +} + +static void ecc_word_memcpy(uint32_t *dst, uint32_t *src, uint32_t size) +{ + uint32_t i; + + for (i = 0; i < size; i++, dst++) + writel_relaxed(src[i], (void *)dst); +} + +static void ecc_word_memset(uint32_t *buff, uint32_t val, uint32_t size) +{ + uint32_t i; + + for (i = 0; i < size; i++, buff++) + writel_relaxed(val, (void *)buff); +} + +static void rk_reverse_buf(uint8_t *buff, uint32_t size) +{ + uint8_t *buf_h_swap, *buf_l_swap; + uint32_t i; + uint32_t temp; + + buf_h_swap = buff + size - 1; + buf_l_swap = buff; + + for (i = 0 ; i < (size / 2) ; i++) { + temp = *buf_h_swap; + *(buf_h_swap--) = *buf_l_swap; + *(buf_l_swap++) = temp; + } +} + +static int rk_word_cmp_zero(uint32_t *buf1, uint32_t n_words) +{ + int ret = 0; + uint32_t i; + + for (i = 0 ; i < n_words; i++) { + if (buf1[i] != 0) + ret = -EINVAL; + } + + return ret; +} + +static int rk_load_hash_bn(struct rk_ecp_group *grp, struct rk_bignum *bn, + uint8_t *hash, uint32_t hash_len) +{ + if (grp == NULL || RK_ECP_IS_BIGNUM_INVALID(bn)) + return -EINVAL; + + hash_len = hash_len > grp->p_len ? grp->p_len : hash_len; + + memset(bn->data, 0x00, WORDS2BYTES(bn->n_words)); + memcpy(bn->data, hash, hash_len); + + rk_reverse_buf((void *)bn->data, hash_len); + + return 0; +} + +/* + * Set a group using well-known domain parameters + */ +static int rk_ecp_group_load(struct rk_ecp_group *grp, enum rk_ecp_group_id id) +{ + memset(grp, 0x00, sizeof(*grp)); + + grp->id = id; + grp->endian = RK_BG_LITTILE_ENDIAN; + + switch (id) { + case RK_ECP_DP_SECP192R1: + RK_LOAD_GROUP_A(secp192r1); + return 0; + + case RK_ECP_DP_SECP224R1: + RK_LOAD_GROUP_A(secp224r1); + return 0; + + case RK_ECP_DP_SECP256R1: + RK_LOAD_GROUP_A(secp256r1); + return 0; + + case RK_ECP_DP_SM2P256V1: + RK_LOAD_GROUP_A(sm2p256v1); + return 0; + + default: + return -EINVAL; + } +} + +static int rockchip_ecc_request_set(uint32_t ecc_ctl, uint32_t wide) +{ + RK_ECP_WRITE_REG(RK_ECC_CURVE_WIDE, wide); + + RK_ECP_WRITE_REG(RK_ECC_INT_EN, 0); + RK_ECP_WRITE_REG(RK_ECC_INT_ST, RK_ECP_READ_REG(RK_ECC_INT_ST)); + RK_ECP_WRITE_REG(RK_ECC_CTL, ecc_ctl); + + return 0; +} + +static int rockchip_ecc_request_wait_done(void) +{ + int ret; + u32 reg_val = 0; + + ret = readx_poll_timeout(RK_ECP_READ_REG, RK_ECC_INT_ST, reg_val, + reg_val != 0, RK_ECP_POLL_PERIOD_US, RK_ECP_POLL_TIMEOUT_US); + if (ret) { + CRYPTO_TRACE("rk ecp poll RK_ECC_INT_ST timeout.\ns"); + goto exit; + } + + if (RK_ECP_READ_REG(RK_ECC_ABN_ST)) { + ret = -EFAULT; + goto exit; + } + +exit: + if (ret) { + CRYPTO_TRACE("RK_ECC_CTL = %08x\n", RK_ECP_READ_REG(RK_ECC_CTL)); + CRYPTO_TRACE("RK_ECC_INT_EN = %08x\n", RK_ECP_READ_REG(RK_ECC_INT_EN)); + CRYPTO_TRACE("RK_ECC_CURVE_WIDE = %08x\n", RK_ECP_READ_REG(RK_ECC_CURVE_WIDE)); + CRYPTO_TRACE("RK_ECC_RAM_CTL = %08x\n", RK_ECP_READ_REG(RK_ECC_RAM_CTL)); + CRYPTO_TRACE("RK_ECC_INT_ST = %08x\n", RK_ECP_READ_REG(RK_ECC_INT_ST)); + CRYPTO_TRACE("RK_ECC_ABN_ST = %08x\n", RK_ECP_READ_REG(RK_ECC_ABN_ST)); + } + + RK_ECP_WRITE_REG(RK_ECC_CTL, 0); + RK_ECP_RAM_FOR_CPU(); + + return ret; +} + +static int rockchip_ecc_request_trigger(void) +{ + uint32_t ecc_ctl = RK_ECP_READ_REG(RK_ECC_CTL); + + RK_ECP_RAM_FOR_ECC(); + + RK_ECP_WRITE_REG(RK_ECC_CTL, ecc_ctl | RK_ECC_CTL_REQ_ECC); + + return rockchip_ecc_request_wait_done(); +} + +int rockchip_ecc_verify(int group_id, uint8_t *hash, uint32_t hash_len, + struct rk_ecp_point *point_P, struct rk_ecp_point *point_sign) +{ + int ret; + uint32_t curve_sel = 0; + struct rk_bignum *bn_hash = NULL; + struct rk_ecp_group grp; + struct rk_ecc_verify *ecc_st = (struct rk_ecc_verify *)SM2_RAM_BASE; + + CRYPTO_TRACE("ecc_st = %p, ecc_base = %p\n", ecc_st, ecc_base); + + if (!hash || + RK_ECP_IS_POINT_INVALID(point_P) || + RK_ECP_IS_POINT_INVALID(point_sign)) { + ret = -EINVAL; + goto exit; + } + + ret = rk_ecp_group_load(&grp, group_id); + if (ret) + goto exit; + + bn_hash = rk_bn_alloc(RK_ECP_MAX_BYTES); + if (!bn_hash) { + ret = -ENOMEM; + goto exit; + } + + curve_sel = group_id == RK_ECP_DP_SM2P256V1 ? + RK_ECC_CTL_FUNC_SM2_CURVER : RK_ECC_CTL_FUNC_ECC_CURVER; + + rk_load_hash_bn(&grp, bn_hash, hash, hash_len); + + RK_ECP_LOAD_DATA(ecc_st->e, bn_hash); + RK_ECP_LOAD_DATA(ecc_st->r_, point_sign->x); + RK_ECP_LOAD_DATA(ecc_st->s_, point_sign->y); + RK_ECP_LOAD_DATA(ecc_st->p_x, point_P->x); + RK_ECP_LOAD_DATA(ecc_st->p_y, point_P->y); + + RK_ECP_LOAD_DATA_EXT(ecc_st->A, grp.a, grp.a_len); + RK_ECP_LOAD_DATA_EXT(ecc_st->P, grp.p, grp.p_len); + RK_ECP_LOAD_DATA_EXT(ecc_st->N, grp.n, grp.n_len); + + RK_ECP_LOAD_DATA_EXT(ecc_st->G_x, grp.gx, grp.gx_len); + RK_ECP_LOAD_DATA_EXT(ecc_st->G_y, grp.gy, grp.gy_len); + + rockchip_ecc_request_set(curve_sel | RK_ECC_CTL_FUNC_SEL_VERIFY, grp.wide); + + ret = rockchip_ecc_request_trigger(); +exit: + if (ret || rk_word_cmp_zero(ecc_st->v, RK_ECP_MAX_WORDS)) { + ret = -EKEYREJECTED; + dump_ecc_sram(); + } + + rk_bn_free(bn_hash); + + return ret; +} + +void rockchip_ecc_init(void __iomem *base) +{ + ecc_base = base - RK_ECC_BASE_OFFSET; + + RK_ECP_WRITE_REG(RK_ECC_DATA_ENDIAN, RK_ECC_DATA_ENDIAN_LITTLE); +} + +void rockchip_ecc_deinit(void) +{ + +} + +uint32_t rockchip_ecc_get_max_size(void) +{ + return RK_ECP_MAX_BYTES; +} + +uint32_t rockchip_ecc_get_curve_nbits(uint32_t group_id) +{ + switch (group_id) { + case RK_ECP_DP_SECP192R1: + return 192; + + case RK_ECP_DP_SECP224R1: + return 224; + + case RK_ECP_DP_SECP256R1: + case RK_ECP_DP_SM2P256V1: + return 256; + + default: + return 0; + } +} + +uint32_t rockchip_ecc_get_group_id(uint32_t asym_algo) +{ + + switch (asym_algo) { + case ASYM_ALGO_ECC_P192: + return RK_ECP_DP_SECP192R1; + case ASYM_ALGO_ECC_P224: + return RK_ECP_DP_SECP224R1; + case ASYM_ALGO_ECC_P256: + return RK_ECP_DP_SECP256R1; + case ASYM_ALGO_SM2: + return RK_ECP_DP_SM2P256V1; + default: + return RK_ECP_DP_NONE; + } +} diff --git a/drivers/crypto/rockchip/rk_crypto_ecc.h b/drivers/crypto/rockchip/rk_crypto_ecc.h new file mode 100644 index 000000000000..645c160cf8e9 --- /dev/null +++ b/drivers/crypto/rockchip/rk_crypto_ecc.h @@ -0,0 +1,152 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/* Copyright (c) 2024 Rockchip Electronics Co. Ltd. */ + +#ifndef __RK_CRYPTO_ECC_H__ +#define __RK_CRYPTO_ECC_H__ + +#include "rk_crypto_bignum.h" + +#define RK_ECP_MAX_BITS 256 +#define RK_ECP_MAX_BYTES ((RK_ECP_MAX_BITS) / 8) +#define RK_ECP_MAX_WORDS ((RK_ECP_MAX_BITS) / 32) +#define RK_ECP_MAX_WORDS_ALL (512 / 32) + +/*************************************************************/ +/* Macros for waiting PKA machine ready states */ +/*************************************************************/ +#define RK_ECP_WRITE_REG(offset, val) writel_relaxed((val), (ecc_base) + (offset)) +#define RK_ECP_READ_REG(offset) readl_relaxed((ecc_base) + (offset)) + +#define RK_ECP_RAM_FOR_ECC() \ + RK_ECP_WRITE_REG(RK_ECC_RAM_CTL, RK_ECC_RAM_CTL_SEL_MASK | RK_ECC_RAM_CTL_ECC) + +#define RK_ECP_RAM_FOR_CPU() \ + RK_ECP_WRITE_REG(RK_ECC_RAM_CTL, RK_ECC_RAM_CTL_SEL_MASK | RK_ECC_RAM_CTL_CPU) + +#define RK_ECP_LOAD_DATA(dst, big_src) \ + do { \ + ecc_word_memset((dst), 0, RK_ECP_MAX_WORDS);\ + ecc_word_memcpy((dst), (big_src->data), (big_src->n_words)); \ + } while (0) + +#define RK_ECP_LOAD_DATA_EXT(dst, src, n_bytes) \ + do { \ + ecc_word_memset((void *)(dst), 0, RK_ECP_MAX_WORDS);\ + ecc_word_memcpy((void *)(dst), (void *)(src), (n_bytes) / 4); \ + } while (0) + +#define RK_ECC_BASE_OFFSET 0x0480 + +#define RK_ECC_CTL 0x03F0 +#define RK_ECC_CTL_RAND_K_SRC_SOFT _SBF(12, 0) +#define RK_ECC_CTL_RAND_K_SRC_HARD _SBF(12, 1) +#define RK_ECC_CTL_FUNC_SM2_CURVER _SBF(8, 0x0) +#define RK_ECC_CTL_FUNC_ECC_CURVER _SBF(8, 0x1) + +#define RK_ECC_CTL_FUNC_SEL_MUL _SBF(4, 0x0) +#define RK_ECC_CTL_FUNC_SEL_KG _SBF(4, 0x1) +#define RK_ECC_CTL_FUNC_SEL_SIGN _SBF(4, 0x2) +#define RK_ECC_CTL_FUNC_SEL_VERIFY _SBF(4, 0x3) +#define RK_ECC_CTL_FUNC_SEL_MUL_MOD _SBF(4, 0x4) +#define RK_ECC_CTL_FUNC_SEL_ADD_MOD _SBF(4, 0x5) +#define RK_ECC_CTL_FUNC_SEL_DOUBLE_POINT _SBF(4, 0x6) +#define RK_ECC_CTL_FUNC_SEL_ADD_POINT _SBF(4, 0x7) +#define RK_ECC_CTL_FUNC_SEL_KP _SBF(4, 0x8) +#define RK_ECC_CTL_FUNC_SEL_KP_KG _SBF(4, 0xa) +#define RK_ECC_CTL_REQ_ECC _SBF(0, 1) + +#define RK_ECC_INT_EN 0x03F4 +#define RK_ECC_INT_EN_DONE _BIT(0) + +#define RK_ECC_INT_ST 0x03F8 +#define RK_ECC_INT_ST_DONE _BIT(0) + +#define RK_ECC_ABN_ST 0x03FC +#define RK_ECC_ABN_ST_BAD_INV_OUT _BIT(8) +#define RK_ECC_ABN_ST_BAD_K_IN _BIT(7) +#define RK_ECC_ABN_ST_BAD_R_IN _BIT(6) +#define RK_ECC_ABN_ST_BAD_S_IN _BIT(5) +#define RK_ECC_ABN_ST_BAD_R_K_MID _BIT(4) +#define RK_ECC_ABN_ST_BAD_R_OUT _BIT(3) +#define RK_ECC_ABN_ST_BAD_S_OUT _BIT(2) +#define RK_ECC_ABN_ST_BAD_T_OUT _BIT(1) +#define RK_ECC_ABN_ST_BAD_POINT_OUT _BIT(0) + +#define RK_ECC_CURVE_WIDE 0x0400 +#define RK_ECC_CURVE_WIDE_192 192 +#define RK_ECC_CURVE_WIDE_224 224 +#define RK_ECC_CURVE_WIDE_256 256 + +#define RK_ECC_MAX_CURVE_WIDE 0x0404 + +#define RK_ECC_DATA_ENDIAN 0x0408 +#define RK_ECC_DATA_ENDIAN_LITTLE 0x0 +#define RK_ECC_DATA_ENDIAN_BIG 0x1 + +#define RK_ECC_RAM_CTL 0x0480 +#define RK_ECC_RAM_CTL_SEL_MASK _SBF(16, 3) +#define RK_ECC_RAM_CTL_CPU _SBF(0, 0) +#define RK_ECC_RAM_CTL_PKA _SBF(0, 1) +#define RK_ECC_RAM_CTL_ECC _SBF(0, 2) + +#define SM2_RAM_BASE ((ecc_base) + 0x1000) + +enum rk_ecp_group_id { + RK_ECP_DP_NONE = 0, + RK_ECP_DP_SECP192R1, /*!< 192-bits NIST curve */ + RK_ECP_DP_SECP224R1, /*!< 224-bits NIST curve */ + RK_ECP_DP_SECP256R1, /*!< 256-bits NIST curve */ + RK_ECP_DP_SM2P256V1, /*!< */ +}; + +#define RK_ECP_IS_BIGNUM_INVALID(b) (!b || !b->data || b->n_words < RK_ECP_MAX_WORDS) +#define RK_ECP_IS_POINT_INVALID(p) (RK_ECP_IS_BIGNUM_INVALID(p->x) && \ + RK_ECP_IS_BIGNUM_INVALID(p->y)) + +struct rk_ecp_group { + enum rk_ecp_group_id id; /*!< internal group identifier */ + const char *curve_name; + uint32_t wide; + const uint8_t *p; /*!< prime modulus of the base field */ + const uint8_t *a; /*!< 1. A in the equation, or 2. (A + 2) / 4 */ + const uint8_t *n; + const uint8_t *gx; + const uint8_t *gy; + size_t p_len; + size_t a_len; + size_t n_len; + size_t gx_len; + size_t gy_len; + enum bignum_endian endian; +}; + +struct rk_ecc_verify { + uint32_t e[RK_ECP_MAX_WORDS_ALL]; // 0x00 + uint32_t r_[RK_ECP_MAX_WORDS_ALL]; // 0x40 + uint32_t s_[RK_ECP_MAX_WORDS_ALL]; // 0x80 + uint32_t p_x[RK_ECP_MAX_WORDS_ALL]; // 0xC0 + uint32_t p_y[RK_ECP_MAX_WORDS_ALL]; // 0x100 + uint32_t A[RK_ECP_MAX_WORDS_ALL]; // 0x140 + uint32_t P[RK_ECP_MAX_WORDS_ALL]; // 0x180 + uint32_t N[RK_ECP_MAX_WORDS_ALL]; // 0x1C0 + uint32_t G_x[RK_ECP_MAX_WORDS_ALL]; // 0x200 + uint32_t G_y[RK_ECP_MAX_WORDS_ALL]; // 0x240 + uint32_t r[RK_ECP_MAX_WORDS_ALL]; // 0x280 + uint32_t v[RK_ECP_MAX_WORDS_ALL]; // 0x2C0 +}; + +int rockchip_ecc_verify(int group_id, uint8_t *hash, uint32_t hash_len, + struct rk_ecp_point *point_P, struct rk_ecp_point *point_sign); + +void rockchip_ecc_init(void __iomem *base); + +void rockchip_ecc_deinit(void); + +uint32_t rockchip_ecc_get_max_size(void); + +uint32_t rockchip_ecc_get_curve_nbits(uint32_t group_id); + +uint32_t rockchip_ecc_get_group_id(uint32_t asym_algo); + +#endif diff --git a/drivers/crypto/rockchip/rk_crypto_v2_akcipher.c b/drivers/crypto/rockchip/rk_crypto_v2_akcipher.c index 1311ea3d4eac..bea5e3f006d3 100644 --- a/drivers/crypto/rockchip/rk_crypto_v2_akcipher.c +++ b/drivers/crypto/rockchip/rk_crypto_v2_akcipher.c @@ -8,13 +8,18 @@ * * Some ideas are from marvell/cesa.c and s5p-sss.c driver. */ - +#include +#include #include +#include #include "rk_crypto_core.h" #include "rk_crypto_v2.h" #include "rk_crypto_v2_reg.h" #include "rk_crypto_v2_pka.h" +#include "rk_crypto_ecc.h" +#include "rk_sm2signature.asn1.h" +#include "rk_ecdsasignature.asn1.h" #define BG_WORDS2BYTES(words) ((words) * sizeof(u32)) #define BG_BYTES2WORDS(bytes) (((bytes) + sizeof(u32) - 1) / sizeof(u32)) @@ -294,12 +299,16 @@ static void rk_rsa_exit_tfm(struct crypto_akcipher *tfm) rk_rsa_clear_ctx(ctx); - ctx->rk_dev->release_crypto(ctx->rk_dev, "rsa"); + if (ctx->rk_dev && ctx->rk_dev->release_crypto) + ctx->rk_dev->release_crypto(ctx->rk_dev, "rsa"); + + memset(ctx, 0x00, sizeof(*ctx)); } struct rk_crypto_algt rk_v2_asym_rsa = { .name = "rsa", .type = ALG_TYPE_ASYM, + .algo = ASYM_ALGO_RSA, .alg.asym = { .encrypt = rk_rsa_enc, .decrypt = rk_rsa_dec, @@ -319,3 +328,241 @@ struct rk_crypto_algt rk_v2_asym_rsa = { }, }; +int rk_ecc_get_signature_r(void *context, size_t hdrlen, unsigned char tag, + const void *value, size_t vlen) +{ + struct rk_ecp_point *sig = context; + const uint8_t *tmp_value = value; + + if (!value || !vlen) + return -EINVAL; + + /* skip first zero */ + if (tmp_value[0] == 0x00) { + tmp_value += 1; + vlen -= 1; + } + + return rk_bn_set_data(sig->x, tmp_value, vlen, RK_BG_BIG_ENDIAN); +} + +int rk_ecc_get_signature_s(void *context, size_t hdrlen, unsigned char tag, + const void *value, size_t vlen) +{ + struct rk_ecp_point *sig = context; + const uint8_t *tmp_value = value; + + if (!value || !vlen) + return -EINVAL; + + /* skip first zero */ + if (tmp_value[0] == 0x00) { + tmp_value += 1; + vlen -= 1; + } + + return rk_bn_set_data(sig->y, tmp_value, vlen, RK_BG_BIG_ENDIAN); +} + +static int rk_ecc_verify(struct akcipher_request *req) +{ + struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); + struct rk_ecc_ctx *ctx = akcipher_tfm_ctx(tfm); + size_t keylen = ctx->nbits / 8; + struct rk_ecp_point *sig_point = NULL; + u8 rawhash[RK_ECP_MAX_BYTES]; + unsigned char *buffer; + ssize_t diff; + int ret; + + if (unlikely(!ctx->pub_key_set)) + return -EINVAL; + + buffer = kmalloc(req->src_len + req->dst_len, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + sig_point = rk_ecc_alloc_point_zero(RK_ECP_MAX_BYTES); + if (!sig_point) { + ret = -ENOMEM; + goto exit; + } + + sg_pcopy_to_buffer(req->src, sg_nents_for_len(req->src, req->src_len + req->dst_len), + buffer, req->src_len + req->dst_len, 0); + + CRYPTO_DUMPHEX("total signture:", buffer, req->src_len); + + if (ctx->group_id == RK_ECP_DP_SM2P256V1) + ret = asn1_ber_decoder(&rk_sm2signature_decoder, sig_point, buffer, req->src_len); + else + ret = asn1_ber_decoder(&rk_ecdsasignature_decoder, sig_point, buffer, req->src_len); + if (ret < 0) + goto exit; + + CRYPTO_DUMPHEX("bn r value = ", sig_point->x->data, BG_WORDS2BYTES(sig_point->x->n_words)); + CRYPTO_DUMPHEX("bn s value = ", sig_point->y->data, BG_WORDS2BYTES(sig_point->y->n_words)); + + /* if the hash is shorter then we will add leading zeros to fit to ndigits */ + memset(rawhash, 0x00, sizeof(rawhash)); + diff = keylen - req->dst_len; + if (diff >= 0) { + if (diff) + memset(rawhash, 0, diff); + memcpy(&rawhash[diff], buffer + req->src_len, req->dst_len); + } else if (diff < 0) { + /* given hash is longer, we take the left-most bytes */ + memcpy(&rawhash, buffer + req->src_len, keylen); + } + + CRYPTO_DUMPHEX("rawhash:", rawhash, sizeof(rawhash)); + + mutex_lock(&akcipher_mutex); + + ret = rockchip_ecc_verify(ctx->group_id, rawhash, keylen, ctx->point_Q, sig_point); + + mutex_unlock(&akcipher_mutex); +exit: + kfree(buffer); + rk_ecc_free_point(sig_point); + + CRYPTO_TRACE("ret = %d\n", ret); + + return ret; +} + +/* + * Set the public key given the raw uncompressed key data from an X509 + * certificate. The key data contain the concatenated X and Y coordinates of + * the public key. + */ +static int rk_ecc_set_pub_key(struct crypto_akcipher *tfm, const void *key, unsigned int keylen) +{ + struct rk_ecc_ctx *ctx = akcipher_tfm_ctx(tfm); + struct rk_ecp_point *pub_Q = ctx->point_Q; + const unsigned char *d = key; + uint32_t nbytes; + + CRYPTO_TRACE(); + + CRYPTO_DUMPHEX("key = ", key, keylen); + + if (keylen < 1 || (((keylen - 1) >> 1) % sizeof(u32)) != 0) + return -EINVAL; + + /* we only accept uncompressed format indicated by '4' */ + if (d[0] != 4) + return -EINVAL; + + keylen--; + d++; + + nbytes = keylen / 2; + + CRYPTO_TRACE("keylen = %u, nbytes = %u, group_id = %u, curve_byte = %u\n", + keylen, nbytes, ctx->group_id, + rockchip_ecc_get_curve_nbits(ctx->group_id) / 8); + + if (nbytes != rockchip_ecc_get_curve_nbits(ctx->group_id) / 8) + return -EINVAL; + + rk_bn_set_data(pub_Q->x, d, nbytes, RK_BG_BIG_ENDIAN); + rk_bn_set_data(pub_Q->y, d + nbytes, nbytes, RK_BG_BIG_ENDIAN); + + CRYPTO_DUMPHEX("Qx = ", pub_Q->x->data, BG_WORDS2BYTES(pub_Q->x->n_words)); + CRYPTO_DUMPHEX("Qy = ", pub_Q->y->data, BG_WORDS2BYTES(pub_Q->y->n_words)); + + if (rk_ecp_point_is_zero(pub_Q)) + return -EINVAL; + + ctx->pub_key_set = true; + + return 0; +} + +static unsigned int rk_ecc_max_size(struct crypto_akcipher *tfm) +{ + CRYPTO_TRACE(); + + return rockchip_ecc_get_max_size(); +} + +static int rk_ecc_init_tfm(struct crypto_akcipher *tfm) +{ + struct rk_ecc_ctx *ctx = akcipher_tfm_ctx(tfm); + struct akcipher_alg *alg = __crypto_akcipher_alg(tfm->base.__crt_alg); + struct rk_crypto_algt *algt; + struct rk_crypto_dev *rk_dev; + + CRYPTO_TRACE(); + + if (!ctx) + return -EINVAL; + + memset(ctx, 0x00, sizeof(*ctx)); + + algt = container_of(alg, struct rk_crypto_algt, alg.asym); + rk_dev = algt->rk_dev; + + if (!rk_dev->request_crypto) + return -EFAULT; + + rk_dev->request_crypto(rk_dev, algt->name); + + ctx->rk_dev = rk_dev; + ctx->group_id = rockchip_ecc_get_group_id(algt->algo); + ctx->nbits = rockchip_ecc_get_curve_nbits(ctx->group_id); + ctx->point_Q = rk_ecc_alloc_point_zero(RK_ECP_MAX_BYTES); + + rockchip_ecc_init(ctx->rk_dev->pka_reg); + + return 0; +} + +static void rk_ecc_exit_tfm(struct crypto_akcipher *tfm) +{ + struct rk_ecc_ctx *ctx = akcipher_tfm_ctx(tfm); + struct akcipher_alg *alg = __crypto_akcipher_alg(tfm->base.__crt_alg); + struct rk_crypto_algt *algt; + + CRYPTO_TRACE(); + + if (!ctx) + return; + + rk_ecc_free_point(ctx->point_Q); + + rockchip_ecc_deinit(); + + algt = container_of(alg, struct rk_crypto_algt, alg.asym); + + if (ctx->rk_dev && ctx->rk_dev->release_crypto) + ctx->rk_dev->release_crypto(ctx->rk_dev, algt->name); + + memset(ctx, 0x00, sizeof(*ctx)); +} + +struct rk_crypto_algt rk_asym_ecc_p192 = RK_ASYM_ECC_INIT(192); +struct rk_crypto_algt rk_asym_ecc_p224 = RK_ASYM_ECC_INIT(224); +struct rk_crypto_algt rk_asym_ecc_p256 = RK_ASYM_ECC_INIT(256); + +struct rk_crypto_algt rk_asym_sm2 = { + .name = "sm2", + .type = ALG_TYPE_ASYM, + .algo = ASYM_ALGO_SM2, + .alg.asym = { + .verify = rk_ecc_verify, + .set_pub_key = rk_ecc_set_pub_key, + .max_size = rk_ecc_max_size, + .init = rk_ecc_init_tfm, + .exit = rk_ecc_exit_tfm, + .reqsize = 64, + .base = { + .cra_name = "sm2", + .cra_driver_name = "sm2-rk", + .cra_priority = RK_CRYPTO_PRIORITY, + .cra_module = THIS_MODULE, + .cra_ctxsize = sizeof(struct rk_ecc_ctx), + }, + } +}; diff --git a/drivers/crypto/rockchip/rk_crypto_v2_pka.c b/drivers/crypto/rockchip/rk_crypto_v2_pka.c index d2c0a265b3ad..569800857f75 100644 --- a/drivers/crypto/rockchip/rk_crypto_v2_pka.c +++ b/drivers/crypto/rockchip/rk_crypto_v2_pka.c @@ -434,6 +434,7 @@ exit: static void pka_finish(void) { RK_PKA_TERMINATE(); + PKA_RAM_FOR_CPU(); PKA_CLK_DISABLE(); } diff --git a/drivers/crypto/rockchip/rk_crypto_v3.c b/drivers/crypto/rockchip/rk_crypto_v3.c index 7cd728599d88..eb7d4e0a5e20 100644 --- a/drivers/crypto/rockchip/rk_crypto_v3.c +++ b/drivers/crypto/rockchip/rk_crypto_v3.c @@ -94,6 +94,10 @@ static struct rk_crypto_algt *crypto_v3_algs[] = { /* Shared v2 version implementation */ &rk_v2_asym_rsa, /* rsa */ + &rk_asym_ecc_p192, /* ecc nist p192 */ + &rk_asym_ecc_p224, /* ecc nist p224 */ + &rk_asym_ecc_p256, /* ecc nist p256 */ + &rk_asym_sm2, /* sm2 */ }; static bool rk_is_cipher_support(struct rk_crypto_dev *rk_dev, u32 algo, u32 mode, u32 key_len) @@ -161,6 +165,21 @@ static bool rk_is_hash_support(struct rk_crypto_dev *rk_dev, u32 algo, u32 type) return version & mask; } +static bool rk_is_asym_support(struct rk_crypto_dev *rk_dev, u32 algo) +{ + switch (algo) { + case ASYM_ALGO_RSA: + return !!CRYPTO_READ(rk_dev, CRYPTO_PKA_VERSION); + case ASYM_ALGO_ECC_P192: + case ASYM_ALGO_ECC_P224: + case ASYM_ALGO_ECC_P256: + case ASYM_ALGO_SM2: + return !!CRYPTO_READ(rk_dev, CRYPTO_ECC_MAX_CURVE_WIDE); + default: + return false; + } +} + int rk_hw_crypto_v3_init(struct device *dev, void *hw_info) { struct rk_hw_crypto_v3_info *info = @@ -208,8 +227,8 @@ bool rk_hw_crypto_v3_algo_valid(struct rk_crypto_dev *rk_dev, struct rk_crypto_a CRYPTO_TRACE("HASH/HMAC"); return rk_is_hash_support(rk_dev, aglt->algo, aglt->type); } else if (aglt->type == ALG_TYPE_ASYM) { - CRYPTO_TRACE("RSA"); - return true; + CRYPTO_TRACE("ASYM"); + return rk_is_asym_support(rk_dev, aglt->algo); } else { return false; } diff --git a/drivers/crypto/rockchip/rk_crypto_v3.h b/drivers/crypto/rockchip/rk_crypto_v3.h index a4b181416300..bc75c1bf99b2 100644 --- a/drivers/crypto/rockchip/rk_crypto_v3.h +++ b/drivers/crypto/rockchip/rk_crypto_v3.h @@ -72,6 +72,10 @@ extern struct rk_crypto_algt rk_v3_hmac_sm3; /* Shared v2 version implementation */ extern struct rk_crypto_algt rk_v2_asym_rsa; +extern struct rk_crypto_algt rk_asym_ecc_p192; +extern struct rk_crypto_algt rk_asym_ecc_p224; +extern struct rk_crypto_algt rk_asym_ecc_p256; +extern struct rk_crypto_algt rk_asym_sm2; int rk_hw_crypto_v3_init(struct device *dev, void *hw_info); void rk_hw_crypto_v3_deinit(struct device *dev, void *hw_info); diff --git a/drivers/crypto/rockchip/rk_crypto_v3_reg.h b/drivers/crypto/rockchip/rk_crypto_v3_reg.h index 1c4c45317a28..d271ed81eb47 100644 --- a/drivers/crypto/rockchip/rk_crypto_v3_reg.h +++ b/drivers/crypto/rockchip/rk_crypto_v3_reg.h @@ -20,6 +20,8 @@ #define CRYPTO_BC_MID_IS_VALID BIT(0) #define CRYPTO_HASH_MID_IS_VALID BIT(1) +#define CRYPTO_ECC_MAX_CURVE_WIDE 0x0404 + #define CRYPTO_KEY_SEL 0x0610 #define CRYPTO_MID_VALID_SWITCH 0x0630 diff --git a/drivers/crypto/rockchip/rk_ecdsasignature.asn1 b/drivers/crypto/rockchip/rk_ecdsasignature.asn1 new file mode 100644 index 000000000000..aef4ac16985d --- /dev/null +++ b/drivers/crypto/rockchip/rk_ecdsasignature.asn1 @@ -0,0 +1,8 @@ +-- SPDX-License-Identifier: BSD-3-Clause +-- +-- Copyright (c) 2024 Rockchip Electronics Co., Ltd. + +ECDSASignature ::= SEQUENCE { + x INTEGER ({ rk_ecc_get_signature_r }), + y INTEGER ({ rk_ecc_get_signature_s }) +} diff --git a/drivers/crypto/rockchip/rk_sm2signature.asn1 b/drivers/crypto/rockchip/rk_sm2signature.asn1 new file mode 100644 index 000000000000..49d1178d713d --- /dev/null +++ b/drivers/crypto/rockchip/rk_sm2signature.asn1 @@ -0,0 +1,8 @@ +-- SPDX-License-Identifier: BSD-3-Clause +-- +-- Copyright (c) 2024 Rockchip Electronics Co., Ltd. + +Sm2Signature ::= SEQUENCE { + x INTEGER ({ rk_ecc_get_signature_r }), + y INTEGER ({ rk_ecc_get_signature_s }) +}