--- fsl_caam.c 2023-01-12 23:39:04.000000000 -0800 +++ fsl_caam-expanded.c 2023-06-23 00:18:14.395128903 -0700 @@ -7872,3 +7872,476 @@ } return status; } + + +#define CAAM_ECDSA_PD 0x00400000 +#define CAAM_ECDSA_KEYGEN_PD 0x02000000 + +static const uint32_t templateKeyPairECC[] = { + /* 00 */ 0xB0840000u, /* HEADER */ + /* 01 */ 0x00000000u, /* ECDSEL */ + /* 02 */ 0x00000000u, /* Private Key Address */ + /* 03 */ 0x00000000u, /* Public Key Address */ + /* 04 */ 0x80140002u, /* Operation */ +}; + + +static const uint32_t templateSignECC[] = { + /* 00 */ 0xB0870000u, /* HEADER */ + /* 01 */ 0x00000000u, /* ECDSEL */ + /* 02 */ 0x00000000u, /* Private Key Address */ + /* 03 */ 0x00000000u, /* Message Address */ + /* 04 */ 0x00000000u, /* R of signature */ + /* 05 */ 0x00000000u, /* S of signature */ + /* 06 */ 0x00000000u, /* Message Size */ + /* 07 */ 0x80150802u, /* Operation */ +}; + + +static const uint32_t templateVerifyECC[] = { + /* 00 */ 0xB0880000u, /* HEADER */ + /* 01 */ 0x00000000u, /* ECDSEL */ + /* 02 */ 0x00000000u, /* Public Key Address (X,Y) */ + /* 03 */ 0x00000000u, /* Message Address */ + /* 04 */ 0x00000000u, /* R of signature */ + /* 05 */ 0x00000000u, /* S of signature */ + /* 06 */ 0x00000000u, /* tmp buffer */ + /* 07 */ 0x00000000u, /* Message Size */ + /* 08 */ 0x80160802u, /* Operation */ +}; + + +static const uint32_t templateAgreeECC[] = { + /* 00 */ 0xB0850000u, /* HEADER */ + /* 01 */ 0x00000000u, /* ECDSEL */ + /* 02 */ 0x00000000u, /* Public Key Address */ + /* 03 */ 0x00000000u, /* Private Key Address */ + /* 04 */ 0x00000000u, /* Shared Output */ + /* 07 */ 0x80170002u, /* Operation */ +}; + + +static int CheckSupportedKeyType(int keyType) +{ + int ret = 0; + + switch (keyType) { + case CAAM_ECDSA_P256: + ret = 32; + break; + + case CAAM_ECDSA_P384: + ret = 48; + break; + + case CAAM_ECDSA_P521: + ret = 66; + break; + } + return ret; +} + + +/*! + * brief generate ECC Keypair. + * + * This function generates ECC private/public key pair. + * + * param base CAAM peripheral base address + * param[out] k private key + * param[in,out] sizeK pointer to size variable. On input it holds size of input k in bytes. On output it holds size of + * of generated private key k in bytes. + * param[out] p public key + * param[in,out] sizeP pointer to size variable. On input it holds size of input p in bytes. On output it holds size of + * of generated public key p in bytes. + * param keyType type of ECC key, i.e P256 / P384 + * param enc option to create black key + * return Operation status. + */ +status_t CAAM_ECC_Keygen(CAAM_Type *base, + caam_handle_t *handle, + uint8_t *k, + size_t *sizeK, + uint8_t *p, + size_t *sizeP, + int keyType, + uint32_t enc) +{ + caam_desc_pkha_ecc_t descriptor; + status_t status = kStatus_InvalidArgument; + uint32_t descriptorSize = ARRAY_SIZE(templateKeyPairECC); + BUILD_ASSURE(sizeof(caam_desc_pkha_ecc_t) >= sizeof(templateKeyPairECC), caam_desc_pkha_ecc_t_size_too_low); + + /* check if known type of key encryption */ + if (enc != 0 && enc != CAAM_PKHA_ENC_PRI_AESECB) { + return status; + } + + /* check is supported key type */ + if (CheckSupportedKeyType(keyType) == 0) { + return status; + } + + /* initialize descriptor from template */ + (void)caam_memcpy(descriptor, templateKeyPairECC, sizeof(templateKeyPairECC)); + + /* add descriptor length in bytes to HEADER descriptor command */ + DESC_HEADER_ADD_DESCLEN(descriptor[0], descriptorSize); + + DESC_SET_ADDR(descriptor[1], (CAAM_ECDSA_KEYGEN_PD | keyType)); + DESC_SET_ADDR(descriptor[2], k); + DESC_SET_ADDR(descriptor[3], p); + + /* add in if is encrypted */ + descriptor[4] |= enc; + + /* schedule the job */ + do { + status = caam_in_job_ring_add(base, handle->jobRing, &descriptor[0]); + } while (status == kStatus_CAAM_Again); + if (status == kStatus_Success) { + status = CAAM_Wait(base, handle, descriptor, kCAAM_Blocking); + } + +#if defined(CAAM_OUT_INVALIDATE) && (CAAM_OUT_INVALIDATE > 0u) + /* NOTE: DCACHE must be set to write-trough mode to safely invalidate cache!! */ + /* Invalidate unaligned data can cause memory corruption in write-back mode */ + DCACHE_InvalidateByRange((uint32_t)k, *sizeK); + DCACHE_InvalidateByRange((uint32_t)p, *sizeP); +#endif /* CAAM_OUT_INVALIDATE */ + return status; +} + + +/*! + * brief generate ECC signature. + * + * This function creates an ECC signature. + * + * param base CAAM peripheral base address + * param[in] k private key + * param[in] sizeK holds size of input k in bytes. + * param[in] hash contains the hash to sign + * param[in] sizeHash is the size of 'hash' in bytes. + * param[out] sig signature output + * param[in,out] sizeSig pointer to size variable. On input it holds size of input sig in bytes. On output it holds size of + * of generated signature in bytes. + * param keyType type of ECC key i.e P256 / P384 + * param enc option to use black key + * return Operation status. + */ +status_t CAAM_ECC_Sign(CAAM_Type *base, + caam_handle_t *handle, + const uint8_t *k, + size_t sizeK, + const uint8_t *hash, + size_t sizeHash, + uint8_t *r, + size_t sizeR, + uint8_t *s, + size_t sizeS, + int keyType, + uint32_t enc) +{ + size_t keySz = 0; + caam_desc_pkha_ecc_t descriptor; + status_t status = kStatus_InvalidArgument; + uint32_t descriptorSize = ARRAY_SIZE(templateSignECC); + BUILD_ASSURE(sizeof(caam_desc_pkha_ecc_t) >= sizeof(templateSignECC), caam_desc_pkha_ecc_t_size_too_low); + + /* check if known type of key encryption */ + if (enc != 0 && enc != CAAM_PKHA_ENC_PRI_AESECB) { + return status; + } + + /* check is supported key type */ + keySz = CheckSupportedKeyType(keyType); + if (keySz == 0) { + return status; + } + + /* sanity check on size of buffers passed in */ + if (sizeR < keySz || sizeS < keySz) { + return status; + } + + /* initialize descriptor from template */ + (void)caam_memcpy(descriptor, templateSignECC, sizeof(templateSignECC)); + + /* add descriptor length in bytes to HEADER descriptor command */ + DESC_HEADER_ADD_DESCLEN(descriptor[0], descriptorSize); + + DESC_SET_ADDR(descriptor[1], (CAAM_ECDSA_PD | keyType)); + DESC_SET_ADDR(descriptor[2], k); + DESC_SET_ADDR(descriptor[3], hash); + DESC_SET_ADDR(descriptor[4], r); + DESC_SET_ADDR(descriptor[5], s); + DESC_ADD_LEN(descriptor[6], sizeHash); + + /* add in if is encrypted */ + descriptor[7] |= enc; + + /* schedule the job */ + do { + status = caam_in_job_ring_add(base, handle->jobRing, &descriptor[0]); + } while (status == kStatus_CAAM_Again); + if (status == kStatus_Success) { + status = CAAM_Wait(base, handle, descriptor, kCAAM_Blocking); + } +#if defined(CAAM_OUT_INVALIDATE) && (CAAM_OUT_INVALIDATE > 0u) + /* NOTE: DCACHE must be set to write-trough mode to safely invalidate cache!! */ + /* Invalidate unaligned data can cause memory corruption in write-back mode */ + DCACHE_InvalidateByRange((uint32_t)r, sizeR); + DCACHE_InvalidateByRange((uint32_t)s, sizeS); +#endif /* CAAM_OUT_INVALIDATE */ + return status; +} + + +/*! + * brief do an ECC verify. + * + * This function verifies an ECC signature. + * + * param base CAAM peripheral base address + * param[in] p public key + * param[in] sizeP pointer to size variable. On input it holds size of input k in bytes. On output it holds size of + * of generated private key k in bytes. + * param[in] sig signature to verify + * param[in] sizeSig size of signature in bytes + * param[in] hash contains the hash to sign + * param[in] sizeHash is the size of 'hash' in bytes. + * param keyType type of ECC key i.e P256 / P384 + * param enc option to use black key + * return Operation status. + */ +status_t CAAM_ECC_Verify(CAAM_Type *base, + caam_handle_t *handle, + const uint8_t *p, + size_t sizeP, + const uint8_t *r, + size_t sizeR, + const uint8_t *s, + size_t sizeS, + const uint8_t *hash, + size_t sizeHash, + int keyType) +{ + size_t keySz = 0; + caam_desc_pkha_ecc_t descriptor; + status_t status = kStatus_InvalidArgument; + uint8_t tmp[256]; + uint32_t descriptorSize = ARRAY_SIZE(templateVerifyECC); + BUILD_ASSURE(sizeof(caam_desc_pkha_ecc_t) >= sizeof(templateVerifyECC), caam_desc_pkha_ecc_t_size_too_low); + + /* check is supported key type */ + keySz = CheckSupportedKeyType(keyType); + if (keySz == 0 || sizeR < keySz || sizeS < keySz) { + return status; + } + + /* initialize descriptor from template */ + (void)caam_memcpy(descriptor, templateVerifyECC, sizeof(templateVerifyECC)); + + /* add descriptor length in bytes to HEADER descriptor command */ + DESC_HEADER_ADD_DESCLEN(descriptor[0], descriptorSize); + + DESC_SET_ADDR(descriptor[1], (CAAM_ECDSA_PD | keyType)); + DESC_SET_ADDR(descriptor[2], p); + DESC_SET_ADDR(descriptor[3], hash); + DESC_SET_ADDR(descriptor[4], r); + DESC_SET_ADDR(descriptor[5], s); + DESC_SET_ADDR(descriptor[6], tmp); + DESC_ADD_LEN(descriptor[7], sizeHash); + + /* schedule the job */ + do { + status = caam_in_job_ring_add(base, handle->jobRing, &descriptor[0]); + } while (status == kStatus_CAAM_Again); + if (status == kStatus_Success) { + status = CAAM_Wait(base, handle, descriptor, kCAAM_Blocking); + } + return status; +} + + +/*! + * brief generate ECC shared secret. + * + * This function creates an ECC shared secret. + * + * param base CAAM peripheral base address + * param[in] k private key + * param[in] sizeK holds size of input k in bytes. + * param[in] pub contains the public key (x,y) + * param[in] sizePub is the size of 'pub' in bytes. + * param[out] out output buffer to hold shared secret + * param[in] sizeOut size of out buffer + * param keyType type of ECC key i.e P256 / P384 + * param enc option to use black key + * return Operation status. + */ +status_t CAAM_ECC_ECDH(CAAM_Type *base, + caam_handle_t *handle, + const uint8_t *k, + size_t sizeK, + const uint8_t *pub, + size_t sizePub, + uint8_t *out, + size_t sizeOut, + int keyType, + uint32_t enc) +{ + size_t keySz = 0; + caam_desc_pkha_ecc_t descriptor; + status_t status = kStatus_InvalidArgument; + uint32_t descriptorSize = ARRAY_SIZE(templateAgreeECC); + BUILD_ASSURE(sizeof(caam_desc_pkha_ecc_t) >= sizeof(templateAgreeECC), caam_desc_pkha_ecc_t_size_too_low); + + /* check if known type of key encryption */ + if (enc != 0 && enc != CAAM_PKHA_ENC_PRI_AESECB) { + return status; + } + + /* check is supported key type */ + keySz = CheckSupportedKeyType(keyType); + if (keySz == 0 || sizeK > keySz || sizeOut != keySz) { + return status; + } + + /* initialize descriptor from template */ + (void)caam_memcpy(descriptor, templateAgreeECC, sizeof(templateAgreeECC)); + + /* add descriptor length in bytes to HEADER descriptor command */ + DESC_HEADER_ADD_DESCLEN(descriptor[0], descriptorSize); + + DESC_SET_ADDR(descriptor[1], (CAAM_ECDSA_KEYGEN_PD | keyType)); + DESC_SET_ADDR(descriptor[2], pub); + DESC_SET_ADDR(descriptor[3], k); + DESC_SET_ADDR(descriptor[4], out); + + /* add in if is encrypted */ + descriptor[5] |= enc; + + /* schedule the job */ + do { + status = caam_in_job_ring_add(base, handle->jobRing, &descriptor[0]); + } while (status == kStatus_CAAM_Again); + if (status == kStatus_Success) { + status = CAAM_Wait(base, handle, descriptor, kCAAM_Blocking); + } + +#if defined(CAAM_OUT_INVALIDATE) && (CAAM_OUT_INVALIDATE > 0u) + /* NOTE: DCACHE must be set to write-trough mode to safely invalidate cache!! */ + /* Invalidate unaligned data can cause memory corruption in write-back mode */ + DCACHE_InvalidateByRange((uint32_t)out, sizeOut); +#endif /* CAAM_OUT_INVALIDATE */ + return status; +} + + +/* Handle BLOB create and open */ +static const uint32_t templateBlob[] = { + /* 00 */ 0xB0800000u, /* HEADER */ + /* 01 */ 0x04000000u, /* class */ + /* 02 */ 0x00000000u, /* key mod */ + /* 03 */ 0xF0000000u, /* SEQ input size */ + /* 04 */ 0x00000000u, /* input */ + /* 05 */ 0xF8000000u, /* SEQ output size */ + /* 06 */ 0x00000000u, /* output */ + /* 07 */ 0x800D0000u, /* Operation */ +}; + + +/*! + * brief generate ECC Keypair. + * + * This function generates ECC private/public key pair. + * + * param base CAAM peripheral base address + * param[out] k private key + * param[in,out] sizeK pointer to size variable. On input it holds size of input k in bytes. On output it holds size of + * of generated private key k in bytes. + * param[out] p public key + * param[in,out] sizeP pointer to size variable. On input it holds size of input p in bytes. On output it holds size of + * of generated public key p in bytes. + * param keyType type of ECC key, i.e P256 / P384 + * param enc option to create black key + * return Operation status. + */ +status_t CAAM_Blob(CAAM_Type *base, + caam_handle_t *handle, + uint8_t *in, + size_t sizeIn, + uint8_t *out, + size_t sizeOut, + uint8_t *keyMod, + size_t keyModSz, + uint32_t dir, + uint32_t color) +{ + caam_desc_pkha_ecc_t descriptor; + status_t status = kStatus_InvalidArgument; + uint32_t descriptorSize = ARRAY_SIZE(templateBlob); + BUILD_ASSURE(sizeof(caam_desc_pkha_ecc_t) >= sizeof(templateBlob), caam_desc_pkha_ecc_t_size_too_low); + + /* check if known type of key encryption */ + if (color != CAAM_RED_BLOB && color != CAAM_BLACK_BLOB) { + return status; + } + + if (dir != CAAM_ENCAP_BLOB && dir != CAAM_DECAP_BLOB) { + return status; + } + + /* simple sanity check on output size to avoid invalidating more + * than wanted */ + if (dir == CAAM_ENCAP_BLOB && + (sizeOut > sizeIn + CAAM_PADDING_SIZE_BLOB)) { + return status; + } + + if (keyModSz != CAAM_SM_KEYMODSZ && keyModSz != CAAM_KEYMODSZ) { + return status; + } + + if (dir == CAAM_DECAP_BLOB && + (sizeOut > sizeIn - CAAM_PADDING_SIZE_BLOB)) { + return status; + } + + /* initialize descriptor from template */ + (void)caam_memcpy(descriptor, templateBlob, sizeof(templateBlob)); + + /* add descriptor length in bytes to HEADER descriptor command */ + DESC_HEADER_ADD_DESCLEN(descriptor[0], descriptorSize); + descriptor[1] |= keyModSz; + DESC_SET_ADDR(descriptor[2], keyMod); + DESC_ADD_LEN(descriptor[3], sizeIn); + DESC_SET_ADDR(descriptor[4], in); + DESC_ADD_LEN(descriptor[5], sizeOut); + DESC_SET_ADDR(descriptor[6], out); + descriptor[7] |= dir; /* add in direction of blob (encap / decap) */ + + /* set black key flag */ + if (color == CAAM_BLACK_BLOB) { + descriptor[7] |= 0x4; /* ECB black key */ + /* additionally AES-CCM would have EXT (bit 8) hot */ + } + + /* schedule the job */ + do { + status = caam_in_job_ring_add(base, handle->jobRing, &descriptor[0]); + } while (status == kStatus_CAAM_Again); + if (status == kStatus_Success) { + status = CAAM_Wait(base, handle, descriptor, kCAAM_Blocking); + } + +#if defined(CAAM_OUT_INVALIDATE) && (CAAM_OUT_INVALIDATE > 0u) + /* NOTE: DCACHE must be set to write-trough mode to safely invalidate cache!! */ + /* Invalidate unaligned data can cause memory corruption in write-back mode */ + DCACHE_InvalidateByRange((uint32_t)out, sizeOut); +#endif /* CAAM_OUT_INVALIDATE */ + return status; +} +