// SPDX-License-Identifier: BSD-2-Clause /* * Copyright (C) Foundries Ltd. 2022. * Author: Jorge Ramirez */ #include #include #include #include #include #include #include #include #include #include #include /* Software based ECDSA operations */ static const struct crypto_ecc_keypair_ops *pair_ops; static const struct crypto_ecc_public_ops *pub_ops; static TEE_Result shared_secret(struct ecc_keypair *private_key, struct ecc_public_key *public_key, void *secret, size_t *secret_len) { return pair_ops->shared_secret(private_key, public_key, secret, secret_len); } static TEE_Result do_shared_secret(struct drvcrypt_secret_data *sdata) { return shared_secret(sdata->key_priv, sdata->key_pub, sdata->secret.data, &sdata->secret.length); } static TEE_Result do_sign(struct drvcrypt_sign_data *sdata) { TEE_Result ret = TEE_SUCCESS; ret = versal_ecc_sign(sdata->algo, sdata->key, sdata->message.data, sdata->message.length, sdata->signature.data, &sdata->signature.length); if (ret == TEE_ERROR_NOT_SUPPORTED) { /* Fallback to software */ return pair_ops->sign(sdata->algo, sdata->key, sdata->message.data, sdata->message.length, sdata->signature.data, &sdata->signature.length); } return ret; } static TEE_Result do_verify(struct drvcrypt_sign_data *sdata) { TEE_Result ret = TEE_SUCCESS; ret = versal_ecc_verify(sdata->algo, sdata->key, sdata->message.data, sdata->message.length, sdata->signature.data, sdata->signature.length); if (ret == TEE_ERROR_NOT_SUPPORTED) { /* Fallback to software */ return pub_ops->verify(sdata->algo, sdata->key, sdata->message.data, sdata->message.length, sdata->signature.data, sdata->signature.length); } return ret; } static TEE_Result do_gen_keypair(struct ecc_keypair *s, size_t size_bits) { TEE_Result ret = TEE_SUCCESS; /* * Versal requires little endian so need to versal_memcpy_swp on Versal * IP ops. We chose not to do it here because some tests might be using * their own keys */ ret = versal_ecc_gen_keypair(s); if (ret == TEE_ERROR_NOT_SUPPORTED) /* Fallback to software */ return pair_ops->generate(s, size_bits); #ifdef CFG_VERSAL_PKI_PWCT if (ret) return ret; /* Perform a pairwise consistencty test on the generated key pair */ ret = versal_ecc_keypair_pwct(s); if (ret) DMSG("Pair-wise consistency test failed (0x%" PRIx32 ")", ret); #endif return ret; } static TEE_Result do_alloc_keypair(struct ecc_keypair *s, uint32_t type, size_t size_bits) { TEE_Result ret = TEE_SUCCESS; /* This driver only supports ECDH/ECDSA */ if (type != TEE_TYPE_ECDSA_KEYPAIR && type != TEE_TYPE_ECDH_KEYPAIR) return TEE_ERROR_NOT_IMPLEMENTED; ret = crypto_asym_alloc_ecc_keypair(s, TEE_TYPE_ECDSA_KEYPAIR, size_bits); if (ret) return TEE_ERROR_NOT_IMPLEMENTED; /* * Ignore the software operations, the crypto API will populate * this interface. */ s->ops = NULL; return TEE_SUCCESS; } static TEE_Result do_alloc_publickey(struct ecc_public_key *s, uint32_t type, size_t size_bits) { TEE_Result ret = TEE_SUCCESS; /* This driver only supports ECDH/ECDSA */ if (type != TEE_TYPE_ECDSA_PUBLIC_KEY && type != TEE_TYPE_ECDH_PUBLIC_KEY) return TEE_ERROR_NOT_IMPLEMENTED; ret = crypto_asym_alloc_ecc_public_key(s, TEE_TYPE_ECDSA_PUBLIC_KEY, size_bits); if (ret) return TEE_ERROR_NOT_IMPLEMENTED; /* * Ignore the software operations, the crypto API will populate * this interface. */ s->ops = NULL; return TEE_SUCCESS; } static void do_free_publickey(struct ecc_public_key *s) { return pub_ops->free(s); } static struct drvcrypt_ecc driver_ecc = { .shared_secret = do_shared_secret, .alloc_publickey = do_alloc_publickey, .free_publickey = do_free_publickey, .alloc_keypair = do_alloc_keypair, .gen_keypair = do_gen_keypair, .verify = do_verify, .sign = do_sign, }; static TEE_Result ecc_init(void) { TEE_Result ret = TEE_SUCCESS; /* HW initialization if needed */ ret = versal_ecc_hw_init(); if (ret) return ret; /* Run KAT self-tests */ ret = versal_ecc_kat_test(); if (ret) return ret; /* Initialize fallback to software implementations, if needed later */ pair_ops = crypto_asym_get_ecc_keypair_ops(TEE_TYPE_ECDSA_KEYPAIR); if (!pair_ops) return TEE_ERROR_GENERIC; pub_ops = crypto_asym_get_ecc_public_ops(TEE_TYPE_ECDSA_PUBLIC_KEY); if (!pub_ops) return TEE_ERROR_GENERIC; /* This driver supports both ECDH and ECDSA */ assert((pub_ops == crypto_asym_get_ecc_public_ops(TEE_TYPE_ECDH_PUBLIC_KEY)) && (pair_ops == crypto_asym_get_ecc_keypair_ops(TEE_TYPE_ECDH_KEYPAIR))); return drvcrypt_register_ecc(&driver_ecc); } driver_init(ecc_init);