mirror of
https://github.com/wolfSSL/wolfssl.git
synced 2026-08-28 11:06:45 +02:00
@@ -1129,15 +1129,17 @@ WOLFSSL_VERSAL_GEN2_ASU
|
||||
WOLFSSL_VERSAL_GEN2_ASU_CCM_ALIGN_DECLINE
|
||||
WOLFSSL_VERSAL_GEN2_ASU_CTR_WRAP_HW_FIXED
|
||||
WOLFSSL_VERSAL_GEN2_ASU_DEBUG
|
||||
WOLFSSL_VERSAL_GEN2_ASU_ECC_P521
|
||||
WOLFSSL_VERSAL_GEN2_ASU_IPI_BASEADDR
|
||||
WOLFSSL_VERSAL_GEN2_ASU_NO_CLIENT_INIT
|
||||
WOLFSSL_VERSAL_GEN2_ASU_NO_COMP_KEY_WARN
|
||||
WOLFSSL_VERSAL_GEN2_ASU_NO_ECC_P521
|
||||
WOLFSSL_VERSAL_GEN2_ASU_NO_ECDH
|
||||
WOLFSSL_VERSAL_GEN2_ASU_NO_ECIES
|
||||
WOLFSSL_VERSAL_GEN2_ASU_NO_ED25519
|
||||
WOLFSSL_VERSAL_GEN2_ASU_NO_ED448
|
||||
WOLFSSL_VERSAL_GEN2_ASU_NO_RSA_PAD
|
||||
WOLFSSL_VERSAL_GEN2_ASU_NO_X25519
|
||||
WOLFSSL_VERSAL_GEN2_ASU_NO_X448
|
||||
WOLFSSL_VERSAL_GEN2_ASU_RTC
|
||||
WOLFSSL_VERSAL_GEN2_ASU_TRNG_DIRECT
|
||||
WOLFSSL_WC_SLHDSA_RECURSIVE
|
||||
@@ -1169,7 +1171,9 @@ WOLF_CRYPTO_DEV
|
||||
WOLF_CRYPT_FIPS_H
|
||||
WOLF_NO_TRAILING_ENUM_COMMAS
|
||||
WindowsCE
|
||||
XASU_AES_INIT
|
||||
XASU_DISABLE_CACHE
|
||||
XASU_INIT
|
||||
XGETPASSWD
|
||||
XMSS_CALL_PRF_KEYGEN
|
||||
XPAR_VERSAL_CIPS_0_PSPMC_0_PSV_CORTEXA72_0_TIMESTAMP_CLK_FREQ
|
||||
|
||||
@@ -34,6 +34,7 @@ The BSP must have the `xilasu` and `xilmailbox` libraries enabled.
|
||||
| ECDSA | NIST P-192/256/384, Brainpool P-256/320/384/512 |
|
||||
| EdDSA | plain Ed25519 and Ed448 sign and verify |
|
||||
| ECDH | the same curves as ECDSA |
|
||||
| X25519 / X448 | key agreement, Vitis 2026.1 and later |
|
||||
| ECIES | AES-GCM with HKDF-SHA256 |
|
||||
| TRNG | seed and random block |
|
||||
|
||||
@@ -70,7 +71,10 @@ Other switches:
|
||||
| `WOLFSSL_VERSAL_GEN2_ASU_IPI_BASEADDR` | IPI channel, default `XPAR_XIPIPSU_0_BASEADDR` |
|
||||
| `WOLFSSL_VERSAL_GEN2_ASU_NO_CLIENT_INIT` | the application calls `XAsu_ClientInit` itself |
|
||||
| `WOLFSSL_VERSAL_GEN2_ASU_NO_RSA_PAD` | RSA on, padding in software |
|
||||
| `WOLFSSL_VERSAL_GEN2_ASU_ECC_P521` | add P-521, off by default, see below |
|
||||
| `WOLFSSL_VERSAL_GEN2_ASU_XILASU_2026_1` | the BSP has Vitis 2026.1 xilasu |
|
||||
| `WOLFSSL_VERSAL_GEN2_ASU_NO_ECC_P521` | drop P-521, which 2026.1 offloads |
|
||||
| `WOLFSSL_VERSAL_GEN2_ASU_NO_X25519` | drop X25519, which 2026.1 offloads |
|
||||
| `WOLFSSL_VERSAL_GEN2_ASU_NO_X448` | drop X448, which 2026.1 offloads |
|
||||
| `WOLFSSL_VERSAL_GEN2_ASU_DEBUG` | print every ASU operation over the UART |
|
||||
| `WOLFSSL_VERSAL_GEN2_ASU_RTC` | supply the benchmark time source from the port |
|
||||
| `XASU_DISABLE_CACHE` | cache is off, so skip all buffer flush and reload work |
|
||||
@@ -79,11 +83,52 @@ The port sets `WOLF_CRYPTO_CB`, `WOLF_CRYPTO_CB_CMD`, `WOLF_CRYPTO_CB_COPY` and
|
||||
`WOLF_CRYPTO_CB_FREE` for you, and points `WC_USE_DEVID` at the ASU device so
|
||||
the unmodified wolfCrypt test and benchmark route through it.
|
||||
|
||||
## Which Vitis release
|
||||
|
||||
The xilasu client API changed in Vitis 2026.1: the operation flags became
|
||||
generic, several request structures moved their key fields into key objects,
|
||||
and RSA gained an output length. The port builds against either release, but it
|
||||
cannot tell them apart on its own, so name the one the BSP was built with:
|
||||
|
||||
```c
|
||||
#define WOLFSSL_VERSAL_GEN2_ASU_XILASU_2026_1
|
||||
```
|
||||
|
||||
2025.2 is assumed when neither that nor `..._XILASU_2025_2` is named, so an
|
||||
existing build keeps working untouched. Naming the wrong one stops the build
|
||||
with a message rather than failing later.
|
||||
|
||||
2026.1 also brings work the older release could not offload at all: P-521,
|
||||
X25519 and X448, RSA OAEP decrypt, SHAKE output past 64 bytes, and CCM on data
|
||||
that is not a whole number of blocks. Each turns on by itself there.
|
||||
|
||||
The X25519 and X448 offload reads the scalar and the peer point out of the
|
||||
wolfSSL key, so it needs the curve key export APIs. Naming
|
||||
`NO_CURVE25519_KEY_EXPORT` or `NO_CURVE448_KEY_EXPORT` alongside it stops the
|
||||
build with a message from `asu_ecdh.c` rather than failing at link: drop
|
||||
the macro, or turn the offload off with `WOLFSSL_VERSAL_GEN2_ASU_NO_X25519` /
|
||||
`..._NO_X448`.
|
||||
|
||||
## Known limits
|
||||
|
||||
**P-521 is off by default.** Stock ASU firmware pads the digest wrong and the
|
||||
client caps it at 64 bytes, which is short of the 66 P-521 needs. Turn it on
|
||||
only with firmware that front-pads.
|
||||
**P-521 needs Vitis 2026.1 firmware.** The client still caps the digest at 64
|
||||
bytes, short of the 66 P-521 uses, so the firmware has to front-pad it. 2026.1
|
||||
does, and `WOLFSSL_VERSAL_GEN2_ASU_ECC_P521` turns on there by itself for both
|
||||
ECDSA and ECDH; `WOLFSSL_VERSAL_GEN2_ASU_NO_ECC_P521` opts back out. Earlier
|
||||
firmware padded it wrong, so the curve stays in software on 2025.2.
|
||||
|
||||
**CCM block alignment is a 2025.2 limit.** That AES-CCM engine only took data
|
||||
and AAD in whole 16-byte blocks, so
|
||||
`WOLFSSL_VERSAL_GEN2_ASU_CCM_ALIGN_DECLINE` sends anything else to software -
|
||||
the RFC 3610 vectors in the wolfCrypt self-test among them. 2026.1 accepts
|
||||
unaligned lengths, so leave the macro undefined there and keep the work on
|
||||
hardware.
|
||||
|
||||
The benchmark trips over the same limit. It authenticates `AES_AUTH_ADD_SZ`
|
||||
bytes of extra data, which defaults to 13, so on 2025.2 every AES-CCM row
|
||||
declines to software however long the message is. Build the benchmark with
|
||||
`AES_AUTH_ADD_SZ` set to 16 to keep those rows on hardware; wolfSSL already
|
||||
does that for the first-generation Versal port for the same reason.
|
||||
|
||||
**ECIES needs the KDF context path.** See below.
|
||||
|
||||
@@ -175,7 +220,7 @@ asu_cipher.c AES
|
||||
asu_cmac.c AES-CMAC
|
||||
asu_rsa.c RSA
|
||||
asu_ecc.c ECDSA, Ed25519, Ed448
|
||||
asu_ecdh.c ECDH
|
||||
asu_ecdh.c ECDH, X25519, X448
|
||||
asu_ecies.c ECIES
|
||||
asu_rng.c TRNG
|
||||
```
|
||||
|
||||
@@ -48,10 +48,11 @@
|
||||
#include "xasu_status.h"
|
||||
#include "xstatus.h"
|
||||
|
||||
/* One ASU AES request: the params block and the key object it points at. */
|
||||
/* One ASU AES request: the params block and the key object it points at. The
|
||||
* key object is read by DMA, so keep it on a cache line of its own. */
|
||||
typedef struct {
|
||||
XAsu_AesParams params;
|
||||
XAsu_AesKeyObject keyObj;
|
||||
XAsu_AesParams params;
|
||||
WC_ASU_ALIGN64 XAsu_AesKeyObject keyObj;
|
||||
} AsuCipherReq;
|
||||
|
||||
/* Queue one ASU AES operation. The lock is held here, so only queue it. */
|
||||
@@ -121,7 +122,8 @@ static int wc_AsuCipherOneShot(Aes* aes, byte* out, const byte* in, word32 sz,
|
||||
req.params.DataLen = sz;
|
||||
req.params.EngineMode = engineMode;
|
||||
req.params.OperationFlags =
|
||||
(u8)(XASU_AES_INIT | XASU_AES_UPDATE | XASU_AES_FINAL);
|
||||
(u8)(WC_ASU_AES_OP_INIT | WC_ASU_AES_OP_UPDATE |
|
||||
WC_ASU_AES_OP_FINAL);
|
||||
req.params.IsLast = (u8)XASU_TRUE;
|
||||
if (enc) {
|
||||
req.params.OperationType = (u8)XASU_AES_ENCRYPT_OPERATION;
|
||||
@@ -463,7 +465,8 @@ static int wc_AsuCipherGcm(wc_CryptoInfo* info)
|
||||
req.params.TagLen = info->cipher.aesgcm_enc.authTagSz;
|
||||
req.params.EngineMode = (u8)XASU_AES_GCM_MODE;
|
||||
req.params.OperationFlags =
|
||||
(u8)(XASU_AES_INIT | XASU_AES_UPDATE | XASU_AES_FINAL);
|
||||
(u8)(WC_ASU_AES_OP_INIT | WC_ASU_AES_OP_UPDATE |
|
||||
WC_ASU_AES_OP_FINAL);
|
||||
req.params.IsLast = (u8)XASU_TRUE;
|
||||
if (info->cipher.enc) {
|
||||
req.params.OperationType = (u8)XASU_AES_ENCRYPT_OPERATION;
|
||||
@@ -620,7 +623,8 @@ static int wc_AsuCipherCcm(wc_CryptoInfo* info)
|
||||
req.params.TagLen = info->cipher.aesccm_enc.authTagSz;
|
||||
req.params.EngineMode = (u8)XASU_AES_CCM_MODE;
|
||||
req.params.OperationFlags =
|
||||
(u8)(XASU_AES_INIT | XASU_AES_UPDATE | XASU_AES_FINAL);
|
||||
(u8)(WC_ASU_AES_OP_INIT | WC_ASU_AES_OP_UPDATE |
|
||||
WC_ASU_AES_OP_FINAL);
|
||||
req.params.IsLast = (u8)XASU_TRUE;
|
||||
if (info->cipher.enc) {
|
||||
req.params.OperationType = (u8)XASU_AES_ENCRYPT_OPERATION;
|
||||
|
||||
@@ -64,10 +64,11 @@ typedef struct {
|
||||
word32 keyLen;
|
||||
} AsuCmacKeep;
|
||||
|
||||
/* One ASU AES request: the params block and the key object it points at. */
|
||||
/* One ASU AES request: the params block and the key object it points at. The
|
||||
* key object is read by DMA, so keep it on a cache line of its own. */
|
||||
typedef struct {
|
||||
XAsu_AesParams params;
|
||||
XAsu_AesKeyObject keyObj;
|
||||
XAsu_AesParams params;
|
||||
WC_ASU_ALIGN64 XAsu_AesKeyObject keyObj;
|
||||
} AsuCmacReq;
|
||||
|
||||
/* Hands one CMAC request to the ASU queue. wc_AsuTransact calls this while it
|
||||
@@ -149,7 +150,8 @@ static int wc_AsuCmacHw(const byte* key, word32 keyLen, u32 keySize,
|
||||
req.params.TagLen = XASU_AES_MAX_TAG_LENGTH_IN_BYTES;
|
||||
req.params.EngineMode = (u8)XASU_AES_CMAC_MODE;
|
||||
req.params.OperationFlags =
|
||||
(u8)(XASU_AES_INIT | XASU_AES_UPDATE | XASU_AES_FINAL);
|
||||
(u8)(WC_ASU_AES_OP_INIT | WC_ASU_AES_OP_UPDATE |
|
||||
WC_ASU_AES_OP_FINAL);
|
||||
req.params.IsLast = (u8)XASU_TRUE;
|
||||
req.params.OperationType = (u8)XASU_AES_ENCRYPT_OPERATION;
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@
|
||||
#define WC_ASU_ECC_OP_VERIFY 1 /* XAsu_EccVerifySign */
|
||||
|
||||
/* Biggest curve we support, P-521 at 66 bytes. */
|
||||
#define WC_ASU_ECC_MAX_KEYLEN XASU_ECC_P521_SIZE_IN_BYTES
|
||||
#define WC_ASU_ECC_MAX_KEYLEN WC_ASU_ECC_P521_LEN
|
||||
|
||||
/* One ASU ECC request. The buffers live on the heap so the ASU can reach them. */
|
||||
typedef struct {
|
||||
@@ -166,41 +166,41 @@ static int wc_AsuEccCurve(ecc_key* key, u32* curveType, u32* keyLen)
|
||||
switch (key->dp->id) {
|
||||
case ECC_SECP192R1:
|
||||
type = (u32)XASU_ECC_NIST_P192;
|
||||
len = (u32)XASU_ECC_P192_SIZE_IN_BYTES;
|
||||
len = (u32)WC_ASU_ECC_P192_LEN;
|
||||
break;
|
||||
case ECC_SECP256R1:
|
||||
type = (u32)XASU_ECC_NIST_P256;
|
||||
len = (u32)XASU_ECC_P256_SIZE_IN_BYTES;
|
||||
len = (u32)WC_ASU_ECC_P256_LEN;
|
||||
break;
|
||||
case ECC_SECP384R1:
|
||||
type = (u32)XASU_ECC_NIST_P384;
|
||||
len = (u32)XASU_ECC_P384_SIZE_IN_BYTES;
|
||||
len = (u32)WC_ASU_ECC_P384_LEN;
|
||||
break;
|
||||
#ifdef WOLFSSL_VERSAL_GEN2_ASU_ECC_P521
|
||||
/* Off by default. Stock firmware pads the digest wrong and caps it at
|
||||
* 64 bytes, which is too small for P-521. */
|
||||
/* On from Vitis 2026.1, whose firmware front-pads the digest. Earlier
|
||||
* firmware padded it wrong, so the curve stayed in software. */
|
||||
case ECC_SECP521R1:
|
||||
type = (u32)XASU_ECC_NIST_P521;
|
||||
len = (u32)XASU_ECC_P521_SIZE_IN_BYTES;
|
||||
len = (u32)WC_ASU_ECC_P521_LEN;
|
||||
break;
|
||||
#endif
|
||||
#ifdef HAVE_ECC_BRAINPOOL
|
||||
/* Brainpool curves work like the NIST ones and all fit in 64 bytes. */
|
||||
case ECC_BRAINPOOLP256R1:
|
||||
type = (u32)XASU_ECC_BRAINPOOL_P256;
|
||||
len = (u32)XASU_ECC_P256_SIZE_IN_BYTES;
|
||||
len = (u32)WC_ASU_ECC_P256_LEN;
|
||||
break;
|
||||
case ECC_BRAINPOOLP320R1:
|
||||
type = (u32)XASU_ECC_BRAINPOOL_P320;
|
||||
len = (u32)XASU_ECC_P320_SIZE_IN_BYTES;
|
||||
len = (u32)WC_ASU_ECC_P320_LEN;
|
||||
break;
|
||||
case ECC_BRAINPOOLP384R1:
|
||||
type = (u32)XASU_ECC_BRAINPOOL_P384;
|
||||
len = (u32)XASU_ECC_P384_SIZE_IN_BYTES;
|
||||
len = (u32)WC_ASU_ECC_P384_LEN;
|
||||
break;
|
||||
case ECC_BRAINPOOLP512R1:
|
||||
type = (u32)XASU_ECC_BRAINPOOL_P512;
|
||||
len = (u32)XASU_ECC_P512_SIZE_IN_BYTES;
|
||||
len = (u32)WC_ASU_ECC_P512_LEN;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
@@ -322,9 +322,8 @@ static int wc_AsuEccSign(wc_CryptoInfo* info)
|
||||
|
||||
mem.req->op = WC_ASU_ECC_OP_SIGN;
|
||||
mem.req->params.CurveType = curveType;
|
||||
mem.req->params.KeyLen = keyLen;
|
||||
mem.req->params.DigestLen = digLen;
|
||||
mem.req->params.KeyAddr = (u64)(UINTPTR)mem.req->key;
|
||||
wc_AsuEccSetKey(&mem.req->params, mem.req->key, keyLen);
|
||||
mem.req->params.DigestAddr = (u64)(UINTPTR)mem.req->digest;
|
||||
mem.req->params.SignAddr = (u64)(UINTPTR)mem.req->sign;
|
||||
|
||||
@@ -443,9 +442,8 @@ static int wc_AsuEccVerify(wc_CryptoInfo* info)
|
||||
|
||||
mem.req->op = WC_ASU_ECC_OP_VERIFY;
|
||||
mem.req->params.CurveType = curveType;
|
||||
mem.req->params.KeyLen = keyLen;
|
||||
mem.req->params.DigestLen = digLen;
|
||||
mem.req->params.KeyAddr = (u64)(UINTPTR)mem.req->key;
|
||||
wc_AsuEccSetKey(&mem.req->params, mem.req->key, keyLen);
|
||||
mem.req->params.DigestAddr = (u64)(UINTPTR)mem.req->digest;
|
||||
mem.req->params.SignAddr = (u64)(UINTPTR)mem.req->sign;
|
||||
|
||||
@@ -538,9 +536,8 @@ static int wc_AsuEd25519Sign(wc_CryptoInfo* info)
|
||||
|
||||
mem.req->op = WC_ASU_ECC_OP_SIGN;
|
||||
mem.req->params.CurveType = (u32)XASU_ECC_NIST_ED25519;
|
||||
mem.req->params.KeyLen = (u32)ED25519_KEY_SIZE;
|
||||
mem.req->params.DigestLen = msgLen;
|
||||
mem.req->params.KeyAddr = (u64)(UINTPTR)mem.req->key;
|
||||
wc_AsuEccSetKey(&mem.req->params, mem.req->key, (u32)ED25519_KEY_SIZE);
|
||||
mem.req->params.DigestAddr = (u64)(UINTPTR)msg;
|
||||
mem.req->params.SignAddr = (u64)(UINTPTR)mem.req->sign;
|
||||
|
||||
@@ -654,9 +651,8 @@ static int wc_AsuEd25519Verify(wc_CryptoInfo* info)
|
||||
|
||||
mem.req->op = WC_ASU_ECC_OP_VERIFY;
|
||||
mem.req->params.CurveType = (u32)XASU_ECC_NIST_ED25519;
|
||||
mem.req->params.KeyLen = (u32)ED25519_KEY_SIZE;
|
||||
mem.req->params.DigestLen = msgLen;
|
||||
mem.req->params.KeyAddr = (u64)(UINTPTR)mem.req->key;
|
||||
wc_AsuEccSetKey(&mem.req->params, mem.req->key, (u32)ED25519_KEY_SIZE);
|
||||
mem.req->params.DigestAddr = (u64)(UINTPTR)msg;
|
||||
mem.req->params.SignAddr = (u64)(UINTPTR)mem.req->sign;
|
||||
|
||||
@@ -755,9 +751,8 @@ static int wc_AsuEd448Sign(wc_CryptoInfo* info)
|
||||
|
||||
mem.req->op = WC_ASU_ECC_OP_SIGN;
|
||||
mem.req->params.CurveType = (u32)XASU_ECC_NIST_ED448;
|
||||
mem.req->params.KeyLen = (u32)ED448_KEY_SIZE;
|
||||
mem.req->params.DigestLen = msgLen;
|
||||
mem.req->params.KeyAddr = (u64)(UINTPTR)mem.req->key;
|
||||
wc_AsuEccSetKey(&mem.req->params, mem.req->key, (u32)ED448_KEY_SIZE);
|
||||
mem.req->params.DigestAddr = (u64)(UINTPTR)msg;
|
||||
mem.req->params.SignAddr = (u64)(UINTPTR)mem.req->sign;
|
||||
|
||||
@@ -875,9 +870,8 @@ static int wc_AsuEd448Verify(wc_CryptoInfo* info)
|
||||
|
||||
mem.req->op = WC_ASU_ECC_OP_VERIFY;
|
||||
mem.req->params.CurveType = (u32)XASU_ECC_NIST_ED448;
|
||||
mem.req->params.KeyLen = (u32)ED448_KEY_SIZE;
|
||||
mem.req->params.DigestLen = msgLen;
|
||||
mem.req->params.KeyAddr = (u64)(UINTPTR)mem.req->key;
|
||||
wc_AsuEccSetKey(&mem.req->params, mem.req->key, (u32)ED448_KEY_SIZE);
|
||||
mem.req->params.DigestAddr = (u64)(UINTPTR)msg;
|
||||
mem.req->params.SignAddr = (u64)(UINTPTR)mem.req->sign;
|
||||
|
||||
|
||||
@@ -49,8 +49,29 @@
|
||||
#include "xasu_status.h"
|
||||
#include "xstatus.h"
|
||||
|
||||
/* X25519 and X448 ride the same ECDH command with a Montgomery curve id. */
|
||||
#if defined(WOLFSSL_VERSAL_GEN2_ASU_X25519) && defined(HAVE_CURVE25519)
|
||||
#include <wolfssl/wolfcrypt/curve25519.h>
|
||||
#define WC_ASU_X25519_ENABLED
|
||||
/* The scalar and peer point are read out of the key, so declining the
|
||||
* export API and asking for the offload is a contradiction, not a
|
||||
* choice. */
|
||||
#ifdef NO_CURVE25519_KEY_EXPORT
|
||||
#error "ASU X25519 needs the curve25519 key export API: drop \
|
||||
NO_CURVE25519_KEY_EXPORT or name WOLFSSL_VERSAL_GEN2_ASU_NO_X25519"
|
||||
#endif
|
||||
#endif
|
||||
#if defined(WOLFSSL_VERSAL_GEN2_ASU_X448) && defined(HAVE_CURVE448)
|
||||
#include <wolfssl/wolfcrypt/curve448.h>
|
||||
#define WC_ASU_X448_ENABLED
|
||||
#ifdef NO_CURVE448_KEY_EXPORT
|
||||
#error "ASU X448 needs the curve448 key export API: drop \
|
||||
NO_CURVE448_KEY_EXPORT or name WOLFSSL_VERSAL_GEN2_ASU_NO_X448"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Biggest curve we support, P-521 at 66 bytes. */
|
||||
#define WC_ASU_ECDH_MAX_KEYLEN XASU_ECC_P521_SIZE_IN_BYTES
|
||||
#define WC_ASU_ECDH_MAX_KEYLEN WC_ASU_ECC_P521_LEN
|
||||
|
||||
/* One ASU ECDH request. The buffers live on the heap so the ASU can reach
|
||||
* them. */
|
||||
@@ -132,40 +153,39 @@ static int wc_AsuEcdhCurve(ecc_key* key, u32* curveType, u32* keyLen)
|
||||
switch (key->dp->id) {
|
||||
case ECC_SECP192R1:
|
||||
type = (u32)XASU_ECC_NIST_P192;
|
||||
len = (u32)XASU_ECC_P192_SIZE_IN_BYTES;
|
||||
len = (u32)WC_ASU_ECC_P192_LEN;
|
||||
break;
|
||||
case ECC_SECP256R1:
|
||||
type = (u32)XASU_ECC_NIST_P256;
|
||||
len = (u32)XASU_ECC_P256_SIZE_IN_BYTES;
|
||||
len = (u32)WC_ASU_ECC_P256_LEN;
|
||||
break;
|
||||
case ECC_SECP384R1:
|
||||
type = (u32)XASU_ECC_NIST_P384;
|
||||
len = (u32)XASU_ECC_P384_SIZE_IN_BYTES;
|
||||
len = (u32)WC_ASU_ECC_P384_LEN;
|
||||
break;
|
||||
#ifdef WOLFSSL_VERSAL_GEN2_ASU_ECC_P521
|
||||
/* Uses the same P-521 switch as ECDSA. ECDH has no digest, so the
|
||||
* firmware padding bug does not apply, but it stays off until tested. */
|
||||
/* Uses the same P-521 switch as ECDSA, on from Vitis 2026.1. */
|
||||
case ECC_SECP521R1:
|
||||
type = (u32)XASU_ECC_NIST_P521;
|
||||
len = (u32)XASU_ECC_P521_SIZE_IN_BYTES;
|
||||
len = (u32)WC_ASU_ECC_P521_LEN;
|
||||
break;
|
||||
#endif
|
||||
#ifdef HAVE_ECC_BRAINPOOL
|
||||
case ECC_BRAINPOOLP256R1:
|
||||
type = (u32)XASU_ECC_BRAINPOOL_P256;
|
||||
len = (u32)XASU_ECC_P256_SIZE_IN_BYTES;
|
||||
len = (u32)WC_ASU_ECC_P256_LEN;
|
||||
break;
|
||||
case ECC_BRAINPOOLP320R1:
|
||||
type = (u32)XASU_ECC_BRAINPOOL_P320;
|
||||
len = (u32)XASU_ECC_P320_SIZE_IN_BYTES;
|
||||
len = (u32)WC_ASU_ECC_P320_LEN;
|
||||
break;
|
||||
case ECC_BRAINPOOLP384R1:
|
||||
type = (u32)XASU_ECC_BRAINPOOL_P384;
|
||||
len = (u32)XASU_ECC_P384_SIZE_IN_BYTES;
|
||||
len = (u32)WC_ASU_ECC_P384_LEN;
|
||||
break;
|
||||
case ECC_BRAINPOOLP512R1:
|
||||
type = (u32)XASU_ECC_BRAINPOOL_P512;
|
||||
len = (u32)XASU_ECC_P512_SIZE_IN_BYTES;
|
||||
len = (u32)WC_ASU_ECC_P512_LEN;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
@@ -180,6 +200,13 @@ static int wc_AsuEcdhCurve(ecc_key* key, u32* curveType, u32* keyLen)
|
||||
}
|
||||
|
||||
/* ECDH shared secret. Both keys must be on the same supported curve. */
|
||||
#ifdef WC_ASU_X25519_ENABLED
|
||||
static int wc_AsuX25519(wc_CryptoInfo* info);
|
||||
#endif
|
||||
#ifdef WC_ASU_X448_ENABLED
|
||||
static int wc_AsuX448(wc_CryptoInfo* info);
|
||||
#endif
|
||||
|
||||
int wc_AsuEcdh(wc_CryptoInfo* info)
|
||||
{
|
||||
AsuEcdhMem mem;
|
||||
@@ -194,8 +221,20 @@ int wc_AsuEcdh(wc_CryptoInfo* info)
|
||||
if (info == NULL) {
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
if (info->algo_type != WC_ALGO_TYPE_PK ||
|
||||
info->pk.type != WC_PK_TYPE_ECDH) {
|
||||
if (info->algo_type != WC_ALGO_TYPE_PK) {
|
||||
return CRYPTOCB_UNAVAILABLE;
|
||||
}
|
||||
#ifdef WC_ASU_X25519_ENABLED
|
||||
if (info->pk.type == WC_PK_TYPE_CURVE25519) {
|
||||
return wc_AsuX25519(info);
|
||||
}
|
||||
#endif
|
||||
#ifdef WC_ASU_X448_ENABLED
|
||||
if (info->pk.type == WC_PK_TYPE_CURVE448) {
|
||||
return wc_AsuX448(info);
|
||||
}
|
||||
#endif
|
||||
if (info->pk.type != WC_PK_TYPE_ECDH) {
|
||||
return CRYPTOCB_UNAVAILABLE;
|
||||
}
|
||||
|
||||
@@ -254,9 +293,8 @@ int wc_AsuEcdh(wc_CryptoInfo* info)
|
||||
}
|
||||
|
||||
mem.req->params.CurveType = curveType;
|
||||
mem.req->params.KeyLen = keyLen;
|
||||
mem.req->params.PvtKeyAddr = (u64)(UINTPTR)mem.req->privKey;
|
||||
mem.req->params.PubKeyAddr = (u64)(UINTPTR)mem.req->pubKey;
|
||||
wc_AsuEcdhSetKeys(&mem.req->params, mem.req->privKey, mem.req->pubKey,
|
||||
keyLen);
|
||||
mem.req->params.SharedSecretAddr = (u64)(UINTPTR)mem.req->secret;
|
||||
mem.req->params.SharedSecretObjIdAddr = 0;
|
||||
|
||||
@@ -287,4 +325,157 @@ int wc_AsuEcdh(wc_CryptoInfo* info)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(WC_ASU_X25519_ENABLED) || defined(WC_ASU_X448_ENABLED)
|
||||
/* One X25519 or X448 agreement. Both are a scalar, a u coordinate and a shared
|
||||
* secret of one curve width, so only the curve id and the length differ. */
|
||||
static int wc_AsuMontgomeryEcdh(u32 curveType, u32 keyLen, const byte* pvt,
|
||||
const byte* peer, byte* out, word32* outLen, int bigEndian)
|
||||
{
|
||||
AsuEcdhMem mem;
|
||||
word32 status;
|
||||
word32 addl = 0;
|
||||
int ret;
|
||||
|
||||
ret = wc_AsuEcdhReqNew(&mem);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
XMEMSET(mem.req, 0, sizeof(*mem.req));
|
||||
XMEMCPY(mem.req->privKey, pvt, keyLen);
|
||||
XMEMCPY(mem.req->pubKey, peer, keyLen);
|
||||
|
||||
mem.req->params.CurveType = curveType;
|
||||
wc_AsuEcdhSetKeys(&mem.req->params, mem.req->privKey, mem.req->pubKey,
|
||||
keyLen);
|
||||
mem.req->params.SharedSecretAddr = (u64)(UINTPTR)mem.req->secret;
|
||||
mem.req->params.SharedSecretObjIdAddr = 0;
|
||||
|
||||
WC_ASU_PRINTF("[ASU] ecdh curve=%u keyLen=%u montgomery\r\n",
|
||||
(unsigned int)curveType, (unsigned int)keyLen);
|
||||
|
||||
wc_AsuCacheFlush(mem.req->privKey, keyLen);
|
||||
/* A Montgomery public key is only the u coordinate, so one key length
|
||||
* here, not the two a Weierstrass x||y point needs. */
|
||||
wc_AsuCacheFlush(mem.req->pubKey, keyLen);
|
||||
/* Flush the output first, or old cache lines could overwrite the secret
|
||||
* the ASU writes and we would read zeros. */
|
||||
wc_AsuCacheFlush(mem.req->secret, keyLen);
|
||||
|
||||
status = wc_AsuTransact(wc_AsuEcdhSubmit, mem.req, &addl);
|
||||
|
||||
wc_AsuCacheInvalidate(mem.req->secret, keyLen);
|
||||
|
||||
WC_ASU_PRINTF("[ASU] ecdh st=%u addl=0x%x\r\n",
|
||||
(unsigned int)status, (unsigned int)addl);
|
||||
|
||||
if (status != XST_SUCCESS) {
|
||||
wc_AsuEcdhReqFree(&mem);
|
||||
return WC_HW_E;
|
||||
}
|
||||
/* No zero shared secret test needed: the ASU refuses a low order point
|
||||
* itself (measured, XASUFW_ECDH_GEN_SECRET_OPERATION_FAIL). */
|
||||
/* The curve works little endian and so does the ASU; a caller that asked
|
||||
* for big endian gets the same reversal software would have done. */
|
||||
if (bigEndian) {
|
||||
u32 i;
|
||||
for (i = 0; i < keyLen; i++) {
|
||||
out[i] = mem.req->secret[keyLen - i - 1U];
|
||||
}
|
||||
}
|
||||
else {
|
||||
XMEMCPY(out, mem.req->secret, keyLen);
|
||||
}
|
||||
*outLen = keyLen;
|
||||
wc_AsuEcdhReqFree(&mem);
|
||||
return 0;
|
||||
}
|
||||
#endif /* WC_ASU_X25519_ENABLED || WC_ASU_X448_ENABLED */
|
||||
|
||||
#ifdef WC_ASU_X25519_ENABLED
|
||||
/* X25519 shared secret on the ASU. */
|
||||
static int wc_AsuX25519(wc_CryptoInfo* info)
|
||||
{
|
||||
byte pvt[CURVE25519_KEYSIZE];
|
||||
byte peer[CURVE25519_KEYSIZE];
|
||||
word32 pvtLen = (word32)sizeof(pvt);
|
||||
word32 peerLen = (word32)sizeof(peer);
|
||||
int ret;
|
||||
|
||||
if (info->pk.curve25519.private_key == NULL ||
|
||||
info->pk.curve25519.public_key == NULL ||
|
||||
info->pk.curve25519.out == NULL ||
|
||||
info->pk.curve25519.outlen == NULL) {
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
if (*info->pk.curve25519.outlen < (word32)CURVE25519_KEYSIZE) {
|
||||
return BUFFER_E;
|
||||
}
|
||||
|
||||
ret = wc_curve25519_export_private_raw_ex(info->pk.curve25519.private_key,
|
||||
pvt, &pvtLen, EC25519_LITTLE_ENDIAN);
|
||||
if (ret == 0) {
|
||||
/* Exported as stored, not masked: the ASU clears the RFC 7748 reserved
|
||||
* high bit itself, measured to match what software returns. */
|
||||
ret = wc_curve25519_export_public_ex(info->pk.curve25519.public_key,
|
||||
peer, &peerLen, EC25519_LITTLE_ENDIAN);
|
||||
}
|
||||
/* No usable key material is a reason to use software, not an error. */
|
||||
if (ret != 0 || pvtLen != (word32)CURVE25519_KEYSIZE ||
|
||||
peerLen != (word32)CURVE25519_KEYSIZE) {
|
||||
ForceZero(pvt, sizeof(pvt));
|
||||
return CRYPTOCB_UNAVAILABLE;
|
||||
}
|
||||
|
||||
ret = wc_AsuMontgomeryEcdh((u32)XASU_ECC_CURVE25519,
|
||||
(u32)CURVE25519_KEYSIZE, pvt, peer, info->pk.curve25519.out,
|
||||
info->pk.curve25519.outlen,
|
||||
info->pk.curve25519.endian == EC25519_BIG_ENDIAN);
|
||||
|
||||
ForceZero(pvt, sizeof(pvt));
|
||||
return ret;
|
||||
}
|
||||
#endif /* WC_ASU_X25519_ENABLED */
|
||||
|
||||
#ifdef WC_ASU_X448_ENABLED
|
||||
/* X448 shared secret on the ASU. */
|
||||
static int wc_AsuX448(wc_CryptoInfo* info)
|
||||
{
|
||||
byte pvt[CURVE448_KEY_SIZE];
|
||||
byte peer[CURVE448_KEY_SIZE];
|
||||
word32 pvtLen = (word32)sizeof(pvt);
|
||||
word32 peerLen = (word32)sizeof(peer);
|
||||
int ret;
|
||||
|
||||
if (info->pk.curve448.private_key == NULL ||
|
||||
info->pk.curve448.public_key == NULL ||
|
||||
info->pk.curve448.out == NULL ||
|
||||
info->pk.curve448.outlen == NULL) {
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
if (*info->pk.curve448.outlen < (word32)CURVE448_KEY_SIZE) {
|
||||
return BUFFER_E;
|
||||
}
|
||||
|
||||
ret = wc_curve448_export_private_raw_ex(info->pk.curve448.private_key,
|
||||
pvt, &pvtLen, EC448_LITTLE_ENDIAN);
|
||||
if (ret == 0) {
|
||||
ret = wc_curve448_export_public_ex(info->pk.curve448.public_key,
|
||||
peer, &peerLen, EC448_LITTLE_ENDIAN);
|
||||
}
|
||||
if (ret != 0 || pvtLen != (word32)CURVE448_KEY_SIZE ||
|
||||
peerLen != (word32)CURVE448_KEY_SIZE) {
|
||||
ForceZero(pvt, sizeof(pvt));
|
||||
return CRYPTOCB_UNAVAILABLE;
|
||||
}
|
||||
|
||||
ret = wc_AsuMontgomeryEcdh((u32)XASU_ECC_CURVE448,
|
||||
(u32)CURVE448_KEY_SIZE, pvt, peer, info->pk.curve448.out,
|
||||
info->pk.curve448.outlen,
|
||||
info->pk.curve448.endian == EC448_BIG_ENDIAN);
|
||||
|
||||
ForceZero(pvt, sizeof(pvt));
|
||||
return ret;
|
||||
}
|
||||
#endif /* WC_ASU_X448_ENABLED */
|
||||
|
||||
#endif /* WC_ASU_ECDH_ENABLED */
|
||||
|
||||
@@ -66,8 +66,13 @@
|
||||
#define WC_ASU_ECIES_NONCE_SZ 12
|
||||
#define WC_ASU_ECIES_TAG_SZ 16
|
||||
|
||||
/* Biggest curve we support here, Brainpool P-512 at 64 bytes. */
|
||||
#define WC_ASU_ECIES_MAX_KEYLEN XASU_ECC_P512_SIZE_IN_BYTES
|
||||
/* Biggest curve we support here. P-521 joins only where the firmware handles
|
||||
* it, so the buffers follow the same switch. */
|
||||
#ifdef WOLFSSL_VERSAL_GEN2_ASU_ECC_P521
|
||||
#define WC_ASU_ECIES_MAX_KEYLEN WC_ASU_ECC_P521_LEN
|
||||
#else
|
||||
#define WC_ASU_ECIES_MAX_KEYLEN WC_ASU_ECC_P512_LEN
|
||||
#endif
|
||||
|
||||
/* One ASU ECIES request. The fixed size fields live on the heap so the ASU
|
||||
* can reach them. The message stays in the caller buffers. */
|
||||
@@ -158,32 +163,39 @@ static int wc_AsuEciesCurve(ecc_key* key, u8* curveType, u8* keyLen)
|
||||
switch (key->dp->id) {
|
||||
case ECC_SECP192R1:
|
||||
*curveType = (u8)XASU_ECC_NIST_P192;
|
||||
*keyLen = (u8)XASU_ECC_P192_SIZE_IN_BYTES;
|
||||
*keyLen = (u8)WC_ASU_ECC_P192_LEN;
|
||||
break;
|
||||
case ECC_SECP256R1:
|
||||
*curveType = (u8)XASU_ECC_NIST_P256;
|
||||
*keyLen = (u8)XASU_ECC_P256_SIZE_IN_BYTES;
|
||||
*keyLen = (u8)WC_ASU_ECC_P256_LEN;
|
||||
break;
|
||||
case ECC_SECP384R1:
|
||||
*curveType = (u8)XASU_ECC_NIST_P384;
|
||||
*keyLen = (u8)XASU_ECC_P384_SIZE_IN_BYTES;
|
||||
*keyLen = (u8)WC_ASU_ECC_P384_LEN;
|
||||
break;
|
||||
#ifdef WOLFSSL_VERSAL_GEN2_ASU_ECC_P521
|
||||
/* Same P-521 switch as ECDSA and ECDH, on from Vitis 2026.1. */
|
||||
case ECC_SECP521R1:
|
||||
*curveType = (u8)XASU_ECC_NIST_P521;
|
||||
*keyLen = (u8)WC_ASU_ECC_P521_LEN;
|
||||
break;
|
||||
#endif
|
||||
#ifdef HAVE_ECC_BRAINPOOL
|
||||
case ECC_BRAINPOOLP256R1:
|
||||
*curveType = (u8)XASU_ECC_BRAINPOOL_P256;
|
||||
*keyLen = (u8)XASU_ECC_P256_SIZE_IN_BYTES;
|
||||
*keyLen = (u8)WC_ASU_ECC_P256_LEN;
|
||||
break;
|
||||
case ECC_BRAINPOOLP320R1:
|
||||
*curveType = (u8)XASU_ECC_BRAINPOOL_P320;
|
||||
*keyLen = (u8)XASU_ECC_P320_SIZE_IN_BYTES;
|
||||
*keyLen = (u8)WC_ASU_ECC_P320_LEN;
|
||||
break;
|
||||
case ECC_BRAINPOOLP384R1:
|
||||
*curveType = (u8)XASU_ECC_BRAINPOOL_P384;
|
||||
*keyLen = (u8)XASU_ECC_P384_SIZE_IN_BYTES;
|
||||
*keyLen = (u8)WC_ASU_ECC_P384_LEN;
|
||||
break;
|
||||
case ECC_BRAINPOOLP512R1:
|
||||
*curveType = (u8)XASU_ECC_BRAINPOOL_P512;
|
||||
*keyLen = (u8)XASU_ECC_P512_SIZE_IN_BYTES;
|
||||
*keyLen = (u8)WC_ASU_ECC_P512_LEN;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
|
||||
@@ -70,6 +70,7 @@ typedef struct {
|
||||
typedef struct {
|
||||
XAsu_ShaOperationCmd cmd;
|
||||
int isSha3;
|
||||
WC_ASU_ALIGN64 byte hash[WC_ASU_SHAKE_MAX_HASH_LEN]; /* DMA out */
|
||||
} AsuHashReq;
|
||||
|
||||
/* Free a saved message. It holds the data we hashed, so wipe it first. */
|
||||
@@ -260,35 +261,38 @@ static int wc_AsuHashOneShot(u8 shaType, u8 shaMode, const byte* data,
|
||||
{
|
||||
AsuHashReq req;
|
||||
word32 status;
|
||||
byte* outAddr = digest;
|
||||
word32 outLen = hashLen;
|
||||
byte xofTmp[XASU_SHAKE_256_MAX_HASH_LEN];
|
||||
word32 outLen = hashLen;
|
||||
|
||||
if (digest == NULL || (data == NULL && dataLen > 0)) {
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
if (hashLen > (word32)sizeof(req.hash)) {
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
|
||||
/* The ASU reads the digest 4 bytes at a time, so round the length up into
|
||||
* a temporary buffer and copy back only what was asked for. */
|
||||
if ((shaMode == XASU_SHA_MODE_SHAKE256) && ((hashLen % 4u) != 0u) &&
|
||||
(hashLen <= XASU_SHAKE_256_MAX_HASH_LEN)) {
|
||||
outLen = (hashLen + 3u) & ~3u;
|
||||
outAddr = xofTmp;
|
||||
/* The ASU writes the digest 4 bytes at a time, so round the length up. */
|
||||
outLen = (hashLen + 3u) & ~3u;
|
||||
if (outLen > (word32)sizeof(req.hash)) {
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
|
||||
XMEMSET(&req, 0, sizeof(req));
|
||||
req.cmd.DataAddr = (u64)(UINTPTR)data;
|
||||
req.cmd.DataSize = dataLen;
|
||||
req.cmd.HashAddr = (u64)(UINTPTR)outAddr;
|
||||
/* Always land the digest in our own aligned buffer, never the caller's:
|
||||
* the ASU writes it by DMA and the cache maintenance below is by line. */
|
||||
req.cmd.HashAddr = (u64)(UINTPTR)req.hash;
|
||||
req.cmd.HashBufSize = outLen;
|
||||
req.cmd.ShaMode = shaMode;
|
||||
req.cmd.IsLast = (u8)XASU_TRUE;
|
||||
if (dataLen > 0) {
|
||||
req.cmd.OperationFlags =
|
||||
(u8)(XASU_SHA_START | XASU_SHA_UPDATE | XASU_SHA_FINISH);
|
||||
(u8)(WC_ASU_SHA_OP_START | WC_ASU_SHA_OP_UPDATE |
|
||||
WC_ASU_SHA_OP_FINISH);
|
||||
}
|
||||
else {
|
||||
req.cmd.OperationFlags = (u8)(XASU_SHA_START | XASU_SHA_FINISH);
|
||||
req.cmd.OperationFlags =
|
||||
(u8)(WC_ASU_SHA_OP_START | WC_ASU_SHA_OP_FINISH);
|
||||
}
|
||||
if (shaType == XASU_SHA3_TYPE) {
|
||||
req.isSha3 = 1;
|
||||
@@ -300,29 +304,31 @@ static int wc_AsuHashOneShot(u8 shaType, u8 shaMode, const byte* data,
|
||||
WC_ASU_PRINTF("[ASU] hash type=%d mode=%d dataLen=%u hashLen=%u\r\n",
|
||||
(int)shaType, (int)shaMode, (unsigned int)dataLen, (unsigned int)hashLen);
|
||||
|
||||
/* The ASU reads the message from memory, so push it out first. The digest
|
||||
* comes back another way and needs nothing here. */
|
||||
/* The ASU reads the message from memory, so push it out first. */
|
||||
if (dataLen > 0) {
|
||||
wc_AsuCacheFlush(data, dataLen);
|
||||
}
|
||||
#ifdef WOLFSSL_VERSAL_GEN2_ASU_XILASU_2026_1
|
||||
/* 2026.1 returns the digest by DMA; 2025.2 sent it back in the mailbox. */
|
||||
wc_AsuCacheFlush(req.hash, outLen);
|
||||
#endif
|
||||
|
||||
status = wc_AsuTransact(wc_AsuHashSubmit, &req, NULL);
|
||||
if (status != XST_SUCCESS) {
|
||||
return WC_HW_E;
|
||||
}
|
||||
|
||||
/* Copy back only the bytes asked for when a temp buffer was used. */
|
||||
if (outAddr != digest) {
|
||||
XMEMCPY(digest, xofTmp, hashLen);
|
||||
}
|
||||
#ifdef WOLFSSL_VERSAL_GEN2_ASU_XILASU_2026_1
|
||||
/* Reload the digest the ASU wrote, or the read returns stale data. */
|
||||
wc_AsuCacheInvalidate(req.hash, outLen);
|
||||
#endif
|
||||
|
||||
/* Hand back only the bytes asked for, dropping any round-up padding. */
|
||||
XMEMCPY(digest, req.hash, hashLen);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* The ASU sends the hash back in a 64 byte slot. A SHAKE output that fits goes
|
||||
* to the ASU, and anything longer is done in software. */
|
||||
#define WC_ASU_SHAKE_HW_MAX_BYTES 64
|
||||
|
||||
#ifdef WOLFSSL_SHAKE256
|
||||
/* Do SHAKE256 in software for long outputs. The private context uses an
|
||||
* invalid device id so this does not come back through the callback. */
|
||||
@@ -407,7 +413,7 @@ static int wc_AsuHashCompute(wc_CryptoInfo* info)
|
||||
* Everything else is one ASU operation. */
|
||||
#ifdef WOLFSSL_SHAKE256
|
||||
if ((shaMode == XASU_SHA_MODE_SHAKE256) &&
|
||||
(hashLen > WC_ASU_SHAKE_HW_MAX_BYTES)) {
|
||||
(hashLen > WC_ASU_SHAKE_MAX_HASH_LEN)) {
|
||||
ret = wc_AsuShakeSoftware(data, dataLen, info->hash.digest, hashLen);
|
||||
}
|
||||
else
|
||||
|
||||
@@ -162,18 +162,19 @@ static int wc_AsuHmacOneShot(u8 shaType, u8 shaMode, const byte* key,
|
||||
req.params.ShaType = shaType;
|
||||
req.params.ShaMode = shaMode;
|
||||
req.params.IsLast = (u8)XASU_TRUE;
|
||||
req.params.KeyLen = keyLen;
|
||||
req.params.MsgLen = msgLen;
|
||||
req.params.HmacLen = macLen;
|
||||
req.params.KeyAddr = (u64)(UINTPTR)key;
|
||||
req.params.MsgBufferAddr = (u64)(UINTPTR)msg;
|
||||
req.params.HmacAddr = (u64)(UINTPTR)mac;
|
||||
wc_AsuHmacSetKey(&req.params, key, keyLen);
|
||||
if (msgLen > 0) {
|
||||
req.params.OperationFlags =
|
||||
(u8)(XASU_HMAC_INIT | XASU_HMAC_UPDATE | XASU_HMAC_FINAL);
|
||||
(u8)(WC_ASU_HMAC_OP_INIT | WC_ASU_HMAC_OP_UPDATE |
|
||||
WC_ASU_HMAC_OP_FINAL);
|
||||
}
|
||||
else {
|
||||
req.params.OperationFlags = (u8)(XASU_HMAC_INIT | XASU_HMAC_FINAL);
|
||||
req.params.OperationFlags =
|
||||
(u8)(WC_ASU_HMAC_OP_INIT | WC_ASU_HMAC_OP_FINAL);
|
||||
}
|
||||
|
||||
WC_ASU_PRINTF("[ASU] hmac type=%d mode=%d keyLen=%u msgLen=%u macLen=%u\r\n",
|
||||
@@ -181,7 +182,7 @@ static int wc_AsuHmacOneShot(u8 shaType, u8 shaMode, const byte* key,
|
||||
(unsigned int)macLen);
|
||||
|
||||
/* The ASU reads the key and message from memory, so push them out first.
|
||||
* The MAC comes back another way and needs nothing here. */
|
||||
* The MAC returns in the mailbox response, so it needs no cache work. */
|
||||
wc_AsuCacheFlush(key, keyLen);
|
||||
if (msgLen > 0) {
|
||||
wc_AsuCacheFlush(msg, msgLen);
|
||||
@@ -216,11 +217,16 @@ static int wc_AsuHmacCompute(wc_CryptoInfo* info)
|
||||
|
||||
ret = wc_AsuHmacResolve(info->hmac.macType, &shaType, &shaMode, &hmacLen);
|
||||
if (ret != 0) {
|
||||
WC_ASU_PRINTF("[ASU] hmac decline: macType=%d unsupported\r\n",
|
||||
(int)info->hmac.macType);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* The ASU needs the raw key. If wolfSSL did not keep one, use software. */
|
||||
if ((hmac->keyRaw == NULL) || (hmac->keyLen == 0)) {
|
||||
WC_ASU_PRINTF("[ASU] hmac decline: no raw key "
|
||||
"(keyRaw=%p keyLen=%u)\r\n",
|
||||
(void*)hmac->keyRaw, (unsigned int)hmac->keyLen);
|
||||
return CRYPTOCB_UNAVAILABLE;
|
||||
}
|
||||
|
||||
|
||||
@@ -32,10 +32,10 @@
|
||||
* example).
|
||||
*
|
||||
* OAEP encrypt is full hardware (ASU does the SHA/MGF encode and the RSA math).
|
||||
* OAEP decrypt is NOT offloaded here: the ASU OAEP-decode command returns no
|
||||
* recovered-message length, which wolfSSL requires, so it declines to software
|
||||
* (the private RSA math is still offloaded through the raw WC_PK_TYPE_RSA
|
||||
* path).
|
||||
* OAEP decrypt is full hardware from Vitis 2026.1, which returns the recovered
|
||||
* message length the decode needs; before that the length was lost, so it
|
||||
* declined to software with only the private RSA math offloaded through the raw
|
||||
* WC_PK_TYPE_RSA path, and it still does on 2025.2.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
@@ -74,12 +74,24 @@
|
||||
#define WC_ASU_RSA_PAD
|
||||
#endif
|
||||
|
||||
/* OAEP decrypt needs the recovered-message length back, which only the 2026.1
|
||||
* client returns (through OutputLenAddr). Before that the decode ran on the
|
||||
* ASU but the length was lost, so wolfSSL could not use the result. */
|
||||
/* It also needs the private exponent, which RsaKey does not carry under
|
||||
* WOLFSSL_RSA_PUBLIC_ONLY, so the offload stays out of that build. */
|
||||
#if defined(WC_ASU_RSA_PAD) && \
|
||||
defined(WOLFSSL_VERSAL_GEN2_ASU_XILASU_2026_1) && \
|
||||
!defined(WOLFSSL_RSA_PUBLIC_ONLY)
|
||||
#define WC_ASU_RSA_OAEP_DEC
|
||||
#endif
|
||||
|
||||
/* Submit-thunk op selector. */
|
||||
#define WC_ASU_RSA_OP_PUB 0 /* XAsu_RsaEnc: public m^e mod n */
|
||||
#define WC_ASU_RSA_OP_PVT 1 /* XAsu_RsaDec: private c^d mod n */
|
||||
#define WC_ASU_RSA_OP_PSS_SIGN 2 /* XAsu_RsaPssSignGen */
|
||||
#define WC_ASU_RSA_OP_PSS_VERIFY 3 /* XAsu_RsaPssSignVer */
|
||||
#define WC_ASU_RSA_OP_OAEP_ENC 4 /* XAsu_RsaOaepEnc */
|
||||
#define WC_ASU_RSA_OP_OAEP_DEC 5 /* XAsu_RsaOaepDec */
|
||||
|
||||
/* Everything one RSA request needs: the operation/padding info plus the key.
|
||||
* Public-key operations (encrypt, verify) use only the public part. */
|
||||
@@ -93,6 +105,9 @@ typedef struct {
|
||||
* CPU-owned data and stamps stale bytes over the DMA result. */
|
||||
WC_ASU_ALIGN64 byte out[XRSA_4096_KEY_SIZE]; /* DMA result, copied out */
|
||||
WC_ASU_ALIGN64 byte scratch[XRSA_4096_KEY_SIZE]; /* PSS sig/OAEP label */
|
||||
/* 2026.1 returns the produced length here through the mailbox, and the
|
||||
* client refuses a request that does not offer somewhere to put it. */
|
||||
u32 outLen;
|
||||
int op;
|
||||
} AsuRsaReq;
|
||||
|
||||
@@ -159,6 +174,10 @@ static int wc_AsuRsaSubmit(XAsu_ClientParams* params, void* ctx)
|
||||
return XAsu_RsaPssSignVer(params, &req->pad);
|
||||
case WC_ASU_RSA_OP_OAEP_ENC:
|
||||
return XAsu_RsaOaepEnc(params, &req->oaep);
|
||||
#ifdef WC_ASU_RSA_OAEP_DEC
|
||||
case WC_ASU_RSA_OP_OAEP_DEC:
|
||||
return XAsu_RsaOaepDec(params, &req->oaep);
|
||||
#endif
|
||||
default:
|
||||
return XST_FAILURE;
|
||||
}
|
||||
@@ -224,7 +243,7 @@ static int wc_AsuRsaShaMap(enum wc_HashType hash, int mgf, u8* shaType,
|
||||
case WC_HASH_TYPE_SHA256:
|
||||
*shaType = (u8)XASU_SHA2_TYPE;
|
||||
*shaMode = (u8)XASU_SHA_MODE_256;
|
||||
*hashLen = XASU_SHA_256_HASH_LEN;
|
||||
*hashLen = WC_ASU_SHA_256_HASH_LEN;
|
||||
if (mgf != WC_MGF1SHA256) {
|
||||
return CRYPTOCB_UNAVAILABLE;
|
||||
}
|
||||
@@ -248,7 +267,7 @@ static int wc_AsuRsaShaMap(enum wc_HashType hash, int mgf, u8* shaType,
|
||||
case WC_HASH_TYPE_SHA3_256:
|
||||
*shaType = (u8)XASU_SHA3_TYPE;
|
||||
*shaMode = (u8)XASU_SHA_MODE_256;
|
||||
*hashLen = XASU_SHA_256_HASH_LEN;
|
||||
*hashLen = WC_ASU_SHA_256_HASH_LEN;
|
||||
if (mgf != WC_MGF1SHA3_256) {
|
||||
return CRYPTOCB_UNAVAILABLE;
|
||||
}
|
||||
@@ -323,6 +342,8 @@ static int wc_AsuRsaRaw(wc_CryptoInfo* info, RsaKey* key, u32 keySize, int op)
|
||||
mem.req->pad.XAsu_RsaOpComp.ExpoCompAddr = 0U;
|
||||
mem.req->pad.XAsu_RsaOpComp.Len = keySize;
|
||||
mem.req->pad.XAsu_RsaOpComp.KeySize = keySize;
|
||||
wc_AsuRsaSetOutLen(&mem.req->pad.XAsu_RsaOpComp, keySize,
|
||||
&mem.req->outLen);
|
||||
|
||||
WC_ASU_PRINTF("[ASU] rsa raw op=%d keySize=%u\r\n",
|
||||
op, (unsigned int)keySize);
|
||||
@@ -492,6 +513,8 @@ static int wc_AsuRsaPssSign(wc_CryptoInfo* info)
|
||||
mem.req->pad.XAsu_RsaOpComp.KeyCompAddr = (u64)(UINTPTR)&mem.req->key;
|
||||
mem.req->pad.XAsu_RsaOpComp.Len = hashLen;
|
||||
mem.req->pad.XAsu_RsaOpComp.KeySize = keySize;
|
||||
wc_AsuRsaSetOutLen(&mem.req->pad.XAsu_RsaOpComp, keySize,
|
||||
&mem.req->outLen);
|
||||
mem.req->pad.SignatureDataAddr = (u64)(UINTPTR)mem.req->scratch;
|
||||
mem.req->pad.SignatureLen = keySize;
|
||||
mem.req->pad.SaltLen = (u32)saltLen;
|
||||
@@ -544,6 +567,25 @@ static int wc_AsuRsaPssIsReject(word32 status)
|
||||
(second >= 0xC4U && second <= 0xCAU));
|
||||
}
|
||||
|
||||
#ifdef WC_ASU_RSA_OAEP_DEC
|
||||
/* Same packing. Measured 0x4002F0BC, 0xBC OAEP_DECODE_ERROR, on a tampered
|
||||
* ciphertext; 0xBD is its hash compare. Anything else is a fault, not a
|
||||
* verdict. */
|
||||
static int wc_AsuRsaOaepStatusIsPadding(word32 status)
|
||||
{
|
||||
word32 first = status & 0x3FFU;
|
||||
word32 second = (status >> 10) & 0x3FFU;
|
||||
|
||||
if (first == 0xBCU || first == 0xBDU) {
|
||||
return 1;
|
||||
}
|
||||
if (second == 0xBCU || second == 0xBDU) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif /* WC_ASU_RSA_OAEP_DEC */
|
||||
|
||||
/* Decode an ASU RSA verify into a verdict: *res = 1 verified / 0 rejected,
|
||||
* return 0 when the ASU gave a verdict, WC_HW_E only on transport fault. */
|
||||
static int wc_AsuRsaVerifyResult(word32 status, word32 addl,
|
||||
@@ -632,6 +674,8 @@ static int wc_AsuRsaPssVerify(wc_CryptoInfo* info)
|
||||
mem.req->pad.XAsu_RsaOpComp.KeyCompAddr = (u64)(UINTPTR)&mem.req->key;
|
||||
mem.req->pad.XAsu_RsaOpComp.Len = hashLen;
|
||||
mem.req->pad.XAsu_RsaOpComp.KeySize = keySize;
|
||||
wc_AsuRsaSetOutLen(&mem.req->pad.XAsu_RsaOpComp, keySize,
|
||||
&mem.req->outLen);
|
||||
mem.req->pad.SignatureDataAddr =
|
||||
(u64)(UINTPTR)info->pk.rsa_pss_verify.sig;
|
||||
mem.req->pad.SignatureLen = keySize;
|
||||
@@ -685,7 +729,6 @@ static int wc_AsuRsaOaepEnc(wc_CryptoInfo* info)
|
||||
info->pk.rsa.out == NULL) {
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
/* Only encrypt is offloaded; ASU OAEP-decode returns no message length. */
|
||||
if (info->pk.rsa.type != RSA_PUBLIC_ENCRYPT) {
|
||||
return CRYPTOCB_UNAVAILABLE;
|
||||
}
|
||||
@@ -744,6 +787,8 @@ static int wc_AsuRsaOaepEnc(wc_CryptoInfo* info)
|
||||
mem.req->oaep.XAsu_RsaOpComp.KeyCompAddr = (u64)(UINTPTR)&mem.req->key;
|
||||
mem.req->oaep.XAsu_RsaOpComp.Len = info->pk.rsa.inLen;
|
||||
mem.req->oaep.XAsu_RsaOpComp.KeySize = keySize;
|
||||
wc_AsuRsaSetOutLen(&mem.req->oaep.XAsu_RsaOpComp, keySize,
|
||||
&mem.req->outLen);
|
||||
mem.req->oaep.OptionalLabelAddr = (u64)(UINTPTR)label;
|
||||
mem.req->oaep.OptionalLabelSize = labelSz;
|
||||
mem.req->oaep.ShaType = shaType;
|
||||
@@ -773,6 +818,139 @@ static int wc_AsuRsaOaepEnc(wc_CryptoInfo* info)
|
||||
wc_AsuRsaReqFree(&mem);
|
||||
return 0;
|
||||
}
|
||||
#ifdef WC_ASU_RSA_OAEP_DEC
|
||||
/* OAEP decrypt: the ASU does the private math and the OAEP decode, and reports
|
||||
* how many message bytes it recovered. */
|
||||
static int wc_AsuRsaOaepDec(wc_CryptoInfo* info)
|
||||
{
|
||||
AsuRsaMem mem;
|
||||
RsaKey* key = info->pk.rsa.key;
|
||||
RsaPadding* padding = info->pk.rsa.padding;
|
||||
u32 keySize = 0;
|
||||
u8 shaType = 0;
|
||||
u8 shaMode = 0;
|
||||
word32 hashLen = 0;
|
||||
word32 recovered;
|
||||
const byte* label;
|
||||
word32 labelSz;
|
||||
word32 status;
|
||||
word32 addl = 0;
|
||||
int ret = 0;
|
||||
|
||||
if (key == NULL || padding == NULL || info->pk.rsa.in == NULL ||
|
||||
info->pk.rsa.out == NULL) {
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
if (info->pk.rsa.type != RSA_PRIVATE_DECRYPT) {
|
||||
return CRYPTOCB_UNAVAILABLE;
|
||||
}
|
||||
/* Private op needs the private exponent, same as the raw and PSS paths. */
|
||||
if (mp_unsigned_bin_size(&key->d) == 0) {
|
||||
return CRYPTOCB_UNAVAILABLE;
|
||||
}
|
||||
|
||||
ret = wc_AsuRsaKeySize(key, &keySize);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
/* The ciphertext is one modulus wide; anything else is not ours. */
|
||||
if (info->pk.rsa.inLen != keySize) {
|
||||
return CRYPTOCB_UNAVAILABLE;
|
||||
}
|
||||
if (info->pk.rsa.outLen == NULL) {
|
||||
return BAD_FUNC_ARG;
|
||||
}
|
||||
ret = wc_AsuRsaShaMap(padding->hash, padding->mgf, &shaType, &shaMode,
|
||||
&hashLen);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = wc_AsuRsaReqNew(&mem);
|
||||
if (ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
XMEMSET(mem.req, 0, sizeof(*mem.req));
|
||||
ret = wc_AsuRsaPubComp(key, keySize, &mem.req->key.PubKeyComp);
|
||||
if (ret != 0) {
|
||||
wc_AsuRsaReqFree(&mem);
|
||||
return ret;
|
||||
}
|
||||
mem.req->key.PrimeCompOrTotientPrsnt = 0U;
|
||||
if (mp_to_unsigned_bin_len_ct(&key->d, (byte*)mem.req->key.PvtExp,
|
||||
(int)keySize) < 0) {
|
||||
wc_AsuRsaReqFree(&mem);
|
||||
return WC_HW_E;
|
||||
}
|
||||
|
||||
/* Same empty-label rule as encrypt: a valid address with size 0. */
|
||||
label = padding->label;
|
||||
labelSz = padding->labelSz;
|
||||
if (label == NULL && labelSz > 0) {
|
||||
wc_AsuRsaReqFree(&mem);
|
||||
return BUFFER_E;
|
||||
}
|
||||
if (label == NULL) {
|
||||
label = mem.req->scratch;
|
||||
labelSz = 0;
|
||||
}
|
||||
|
||||
mem.req->op = WC_ASU_RSA_OP_OAEP_DEC;
|
||||
mem.req->oaep.XAsu_RsaOpComp.InputDataAddr = (u64)(UINTPTR)info->pk.rsa.in;
|
||||
/* Recover into our own buffer: the message is shorter than the modulus and
|
||||
* the caller's buffer may be smaller than what the ASU is told it has. */
|
||||
mem.req->oaep.XAsu_RsaOpComp.OutputDataAddr = (u64)(UINTPTR)mem.req->out;
|
||||
mem.req->oaep.XAsu_RsaOpComp.KeyCompAddr = (u64)(UINTPTR)&mem.req->key;
|
||||
mem.req->oaep.XAsu_RsaOpComp.Len = info->pk.rsa.inLen;
|
||||
mem.req->oaep.XAsu_RsaOpComp.KeySize = keySize;
|
||||
wc_AsuRsaSetOutLen(&mem.req->oaep.XAsu_RsaOpComp,
|
||||
(u32)sizeof(mem.req->out), &mem.req->outLen);
|
||||
mem.req->oaep.OptionalLabelAddr = (u64)(UINTPTR)label;
|
||||
mem.req->oaep.OptionalLabelSize = labelSz;
|
||||
mem.req->oaep.ShaType = shaType;
|
||||
mem.req->oaep.ShaMode = shaMode;
|
||||
|
||||
WC_ASU_PRINTF("[ASU] rsa oaep-dec keySize=%u shaMode=%u labelSz=%u\r\n",
|
||||
(unsigned int)keySize, (unsigned int)shaMode, (unsigned int)labelSz);
|
||||
|
||||
wc_AsuCacheFlush(info->pk.rsa.in, info->pk.rsa.inLen);
|
||||
if (labelSz > 0) {
|
||||
wc_AsuCacheFlush(label, labelSz);
|
||||
}
|
||||
wc_AsuCacheFlush(&mem.req->key, sizeof(mem.req->key));
|
||||
/* out is a DMA target so it is flushed and invalidated; outLen is not one,
|
||||
* it arrives in the mailbox response - see wc_AsuRsaSetOutLen. */
|
||||
wc_AsuCacheFlush(mem.req->out, sizeof(mem.req->out));
|
||||
|
||||
status = wc_AsuTransact(wc_AsuRsaSubmit, mem.req, &addl);
|
||||
|
||||
wc_AsuCacheInvalidate(mem.req->out, sizeof(mem.req->out));
|
||||
|
||||
/* A decode failure is an answer, the padding is valid for this key or it
|
||||
* is not. A transport or argument fault is not, so keep the two apart. */
|
||||
if (status != XST_SUCCESS) {
|
||||
int isPadding = wc_AsuRsaOaepStatusIsPadding((word32)status);
|
||||
|
||||
wc_AsuRsaReqFree(&mem);
|
||||
if (isPadding) {
|
||||
return RSA_PAD_E;
|
||||
}
|
||||
return WC_HW_E;
|
||||
}
|
||||
|
||||
/* Trust the reported length only as far as both buffers allow. */
|
||||
recovered = mem.req->outLen;
|
||||
if (recovered > sizeof(mem.req->out) || recovered > *info->pk.rsa.outLen) {
|
||||
wc_AsuRsaReqFree(&mem);
|
||||
return RSA_BUFFER_E;
|
||||
}
|
||||
XMEMCPY(info->pk.rsa.out, mem.req->out, recovered);
|
||||
*info->pk.rsa.outLen = recovered;
|
||||
wc_AsuRsaReqFree(&mem);
|
||||
return 0;
|
||||
}
|
||||
#endif /* WC_ASU_RSA_OAEP_DEC */
|
||||
|
||||
#endif /* WC_ASU_RSA_PAD (OAEP encrypt) */
|
||||
|
||||
/* WC_ALGO_TYPE_PK entry: dispatch on RSA pk sub-type. Raw always offloaded;
|
||||
@@ -797,6 +975,11 @@ int wc_AsuRsa(wc_CryptoInfo* info)
|
||||
case WC_PK_TYPE_RSA_PSS_VERIFY:
|
||||
return wc_AsuRsaPssVerify(info);
|
||||
case WC_PK_TYPE_RSA_OAEP:
|
||||
#ifdef WC_ASU_RSA_OAEP_DEC
|
||||
if (info->pk.rsa.type == RSA_PRIVATE_DECRYPT) {
|
||||
return wc_AsuRsaOaepDec(info);
|
||||
}
|
||||
#endif
|
||||
return wc_AsuRsaOaepEnc(info);
|
||||
#endif /* WC_ASU_RSA_PAD */
|
||||
default:
|
||||
|
||||
@@ -107,6 +107,7 @@ noinst_HEADERS+= \
|
||||
wolfssl/wolfcrypt/port/xilinx/xil-versal-trng.h \
|
||||
wolfssl/wolfcrypt/port/xilinx/versal_gen2_asu/asu_cipher.h \
|
||||
wolfssl/wolfcrypt/port/xilinx/versal_gen2_asu/asu_cmac.h \
|
||||
wolfssl/wolfcrypt/port/xilinx/versal_gen2_asu/asu_compat.h \
|
||||
wolfssl/wolfcrypt/port/xilinx/versal_gen2_asu/asu_cryptocb.h \
|
||||
wolfssl/wolfcrypt/port/xilinx/versal_gen2_asu/asu_ecc.h \
|
||||
wolfssl/wolfcrypt/port/xilinx/versal_gen2_asu/asu_ecdh.h \
|
||||
|
||||
@@ -0,0 +1,203 @@
|
||||
/* asu_compat.h
|
||||
*
|
||||
* Copyright (C) 2006-2026 wolfSSL Inc.
|
||||
*
|
||||
* This file is part of wolfSSL.
|
||||
*
|
||||
* wolfSSL is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* wolfSSL 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
|
||||
*/
|
||||
|
||||
/* Names that moved between the Vitis 2025.2 and 2026.1 xilasu client APIs.
|
||||
* The rest of the port uses the WC_ASU_ names from here so the engine files
|
||||
* read the same against either release.
|
||||
*
|
||||
* Set WOLFSSL_VERSAL_GEN2_ASU_XILASU_2026_1 in user_settings.h for a 2026.1
|
||||
* BSP; asu_settings.h assumes 2025.2 otherwise.
|
||||
*
|
||||
* The xilasu names are only read here, never redefined: AMD is free to bring
|
||||
* an old spelling back, and a #define of theirs would then collide.
|
||||
*/
|
||||
|
||||
#ifndef WOLFSSL_VERSAL_GEN2_ASU_COMPAT_H
|
||||
#define WOLFSSL_VERSAL_GEN2_ASU_COMPAT_H
|
||||
|
||||
#include <wolfssl/wolfcrypt/settings.h>
|
||||
|
||||
#ifdef WOLFSSL_VERSAL_GEN2_ASU
|
||||
|
||||
#include <wolfssl/wolfcrypt/types.h> /* WC_INLINE */
|
||||
|
||||
/* Every header the names below come from, so this one stands on its own and
|
||||
* does not depend on what an engine file happened to include first. 2026.1
|
||||
* moved the operation flags into xasu_def.h; before that each engine carried
|
||||
* its own set. All five ship in both releases. */
|
||||
#include "xasu_def.h"
|
||||
#include "xasu_aesinfo.h"
|
||||
#include "xasu_hmacinfo.h"
|
||||
#include "xasu_shainfo.h"
|
||||
#include "xasu_eccinfo.h"
|
||||
#include "xasu_rsainfo.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Catch a BSP that does not match what the build was told to expect. Without
|
||||
* this the mismatch surfaces as a wall of undeclared-identifier errors from
|
||||
* whichever engine file happens to compile first. */
|
||||
#if defined(WOLFSSL_VERSAL_GEN2_ASU_XILASU_2026_1) && !defined(XASU_INIT)
|
||||
#error "WOLFSSL_VERSAL_GEN2_ASU_XILASU_2026_1 named but the BSP xilasu \
|
||||
predates 2026.1: name WOLFSSL_VERSAL_GEN2_ASU_XILASU_2025_2 instead"
|
||||
#endif
|
||||
#if defined(WOLFSSL_VERSAL_GEN2_ASU_XILASU_2025_2) && !defined(XASU_AES_INIT)
|
||||
#error "WOLFSSL_VERSAL_GEN2_ASU_XILASU_2025_2 named but the BSP xilasu \
|
||||
looks newer than 2025.2: name WOLFSSL_VERSAL_GEN2_ASU_XILASU_2026_1 instead"
|
||||
#endif
|
||||
|
||||
#ifdef WOLFSSL_VERSAL_GEN2_ASU_XILASU_2026_1
|
||||
|
||||
/* 2026.1 drives every engine from one set of operation flags. */
|
||||
#define WC_ASU_AES_OP_INIT XASU_INIT
|
||||
#define WC_ASU_AES_OP_UPDATE XASU_UPDATE
|
||||
#define WC_ASU_AES_OP_FINAL XASU_FINISH
|
||||
|
||||
#define WC_ASU_HMAC_OP_INIT XASU_INIT
|
||||
#define WC_ASU_HMAC_OP_UPDATE XASU_UPDATE
|
||||
#define WC_ASU_HMAC_OP_FINAL XASU_FINISH
|
||||
|
||||
#define WC_ASU_SHA_OP_START XASU_INIT
|
||||
#define WC_ASU_SHA_OP_UPDATE XASU_UPDATE
|
||||
#define WC_ASU_SHA_OP_FINISH XASU_FINISH
|
||||
|
||||
/* Curve sizes gained a private and a public form. The public one is twice the
|
||||
* private, and every use in the port is a curve length, so they all map to the
|
||||
* private form. The values themselves did not change. */
|
||||
#define WC_ASU_ECC_P192_LEN XASU_ECC_P192_PVT_KEY_SIZE_IN_BYTES
|
||||
#define WC_ASU_ECC_P256_LEN XASU_ECC_P256_PVT_KEY_SIZE_IN_BYTES
|
||||
#define WC_ASU_ECC_P320_LEN XASU_ECC_P320_PVT_KEY_SIZE_IN_BYTES
|
||||
#define WC_ASU_ECC_P384_LEN XASU_ECC_P384_PVT_KEY_SIZE_IN_BYTES
|
||||
#define WC_ASU_ECC_P512_LEN XASU_ECC_P512_PVT_KEY_SIZE_IN_BYTES
|
||||
#define WC_ASU_ECC_P521_LEN XASU_ECC_P521_PVT_KEY_SIZE_IN_BYTES
|
||||
|
||||
/* SHA-256 and SHAKE-256 share one length define now. Both are 32. */
|
||||
#define WC_ASU_SHA_256_HASH_LEN XASU_SHA_SHAKE_256_HASH_LEN
|
||||
|
||||
/* The digest comes back by DMA, so the engine's own limit is the only one. */
|
||||
#define WC_ASU_SHAKE_MAX_HASH_LEN XASU_SHAKE_256_MAX_HASH_LEN
|
||||
|
||||
#else /* Vitis 2025.2 */
|
||||
|
||||
#define WC_ASU_AES_OP_INIT XASU_AES_INIT
|
||||
#define WC_ASU_AES_OP_UPDATE XASU_AES_UPDATE
|
||||
#define WC_ASU_AES_OP_FINAL XASU_AES_FINAL
|
||||
|
||||
#define WC_ASU_HMAC_OP_INIT XASU_HMAC_INIT
|
||||
#define WC_ASU_HMAC_OP_UPDATE XASU_HMAC_UPDATE
|
||||
#define WC_ASU_HMAC_OP_FINAL XASU_HMAC_FINAL
|
||||
|
||||
#define WC_ASU_SHA_OP_START XASU_SHA_START
|
||||
#define WC_ASU_SHA_OP_UPDATE XASU_SHA_UPDATE
|
||||
#define WC_ASU_SHA_OP_FINISH XASU_SHA_FINISH
|
||||
|
||||
#define WC_ASU_ECC_P192_LEN XASU_ECC_P192_SIZE_IN_BYTES
|
||||
#define WC_ASU_ECC_P256_LEN XASU_ECC_P256_SIZE_IN_BYTES
|
||||
#define WC_ASU_ECC_P320_LEN XASU_ECC_P320_SIZE_IN_BYTES
|
||||
#define WC_ASU_ECC_P384_LEN XASU_ECC_P384_SIZE_IN_BYTES
|
||||
#define WC_ASU_ECC_P512_LEN XASU_ECC_P512_SIZE_IN_BYTES
|
||||
#define WC_ASU_ECC_P521_LEN XASU_ECC_P521_SIZE_IN_BYTES
|
||||
|
||||
#define WC_ASU_SHA_256_HASH_LEN XASU_SHA_256_HASH_LEN
|
||||
|
||||
/* The digest came back in the 64 byte mailbox response slot, so that is the
|
||||
* longest SHAKE the ASU could return however much the engine itself allows. */
|
||||
#define WC_ASU_SHAKE_MAX_HASH_LEN 64
|
||||
|
||||
#endif /* WOLFSSL_VERSAL_GEN2_ASU_XILASU_2026_1 */
|
||||
|
||||
/* 2026.1 moved the HMAC key into a key object so it can name a key vault
|
||||
* entry instead. A zero KeyId keeps the key coming from KeyInAddr. */
|
||||
static WC_INLINE void wc_AsuHmacSetKey(XAsu_HmacParams* p, const void* key,
|
||||
u32 keyLen)
|
||||
{
|
||||
#ifdef WOLFSSL_VERSAL_GEN2_ASU_XILASU_2026_1
|
||||
p->KeyObject.KeyInAddr = (u64)(UINTPTR)key;
|
||||
p->KeyObject.KeyInLen = keyLen;
|
||||
p->KeyObject.KeyId = 0U;
|
||||
#else
|
||||
p->KeyAddr = (u64)(UINTPTR)key;
|
||||
p->KeyLen = keyLen;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* 2026.1 moved the ECC key into a key object so it can name a key vault entry
|
||||
* instead. KeyLen stays the curve length for both a private scalar and a public
|
||||
* point; the firmware knows a point is twice that. */
|
||||
static WC_INLINE void wc_AsuEccSetKey(XAsu_EccParams* p, const void* key,
|
||||
u32 keyLen)
|
||||
{
|
||||
#ifdef WOLFSSL_VERSAL_GEN2_ASU_XILASU_2026_1
|
||||
p->Key.KeyAddr = (u64)(UINTPTR)key;
|
||||
p->Key.KeyLen = keyLen;
|
||||
p->Key.KeyId = 0U;
|
||||
#else
|
||||
p->KeyAddr = (u64)(UINTPTR)key;
|
||||
p->KeyLen = keyLen;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Same move for ECDH, which gains a key object per side. 2025.2 carried one
|
||||
* KeyLen for both keys, so the single length feeds both objects here. */
|
||||
static WC_INLINE void wc_AsuEcdhSetKeys(XAsu_EcdhParams* p, const void* pvt,
|
||||
const void* pub, u32 keyLen)
|
||||
{
|
||||
#ifdef WOLFSSL_VERSAL_GEN2_ASU_XILASU_2026_1
|
||||
p->PvtKey.KeyAddr = (u64)(UINTPTR)pvt;
|
||||
p->PvtKey.KeyLen = keyLen;
|
||||
p->PvtKey.KeyId = 0U;
|
||||
p->PubKey.KeyAddr = (u64)(UINTPTR)pub;
|
||||
p->PubKey.KeyLen = keyLen;
|
||||
p->PubKey.KeyId = 0U;
|
||||
#else
|
||||
p->PvtKeyAddr = (u64)(UINTPTR)pvt;
|
||||
p->PubKeyAddr = (u64)(UINTPTR)pub;
|
||||
p->KeyLen = keyLen;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* 2026.1 wants the size of the caller's output buffer up front, and somewhere
|
||||
* to report how much was produced. The client rejects the request when either
|
||||
* is missing, so both have to be set even though 2025.2 had neither. outLen
|
||||
* points at a 4-byte slot the mailbox response fills in.
|
||||
* Not a DMA target, so it takes no cache maintenance: the client CPU-copies
|
||||
* the value in, and invalidating the line would throw that write away. */
|
||||
static WC_INLINE void wc_AsuRsaSetOutLen(XAsu_RsaParams* op, u32 bufSize,
|
||||
u32* outLen)
|
||||
{
|
||||
#ifdef WOLFSSL_VERSAL_GEN2_ASU_XILASU_2026_1
|
||||
op->OutputDataLen = bufSize;
|
||||
op->OutputLenAddr = (u64)(UINTPTR)outLen;
|
||||
op->KeyId = 0U;
|
||||
#else
|
||||
(void)op; (void)bufSize; (void)outLen;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* WOLFSSL_VERSAL_GEN2_ASU */
|
||||
|
||||
#endif /* WOLFSSL_VERSAL_GEN2_ASU_COMPAT_H */
|
||||
@@ -37,6 +37,11 @@
|
||||
* WOLFSSL_VERSAL_GEN2_ASU_NO_RSA_PAD - RSA on, padding in software
|
||||
* WOLFSSL_VERSAL_GEN2_ASU_IPI_BASEADDR - IPI channel to use
|
||||
* WOLFSSL_VERSAL_GEN2_ASU_NO_CLIENT_INIT - app starts the client itself
|
||||
*
|
||||
* The xilasu client API changed in Vitis 2026.1. Name the release the BSP was
|
||||
* built with; 2025.2 is assumed when neither is given:
|
||||
* WOLFSSL_VERSAL_GEN2_ASU_XILASU_2026_1
|
||||
* WOLFSSL_VERSAL_GEN2_ASU_XILASU_2025_2
|
||||
*/
|
||||
|
||||
#ifndef WOLFSSL_VERSAL_GEN2_ASU_SETTINGS_H
|
||||
@@ -54,6 +59,22 @@
|
||||
#define WOLF_CRYPTO_CB_CMD
|
||||
#endif
|
||||
|
||||
/* Which xilasu the BSP carries. 2026.1 renamed the operation flags and moved
|
||||
* the key fields of several request structures into key objects, so the port
|
||||
* has to be told which one it is building against. Unlike the engine switches
|
||||
* there is no software fallback for guessing wrong: the two APIs are not
|
||||
* source compatible, so a conflict is an error rather than an #undef. */
|
||||
#if defined(WOLFSSL_VERSAL_GEN2_ASU_XILASU_2026_1) && \
|
||||
defined(WOLFSSL_VERSAL_GEN2_ASU_XILASU_2025_2)
|
||||
#error "Name only one of WOLFSSL_VERSAL_GEN2_ASU_XILASU_2026_1 or _2025_2"
|
||||
#endif
|
||||
|
||||
/* Assume 2025.2, so a build that predates this switch keeps working. */
|
||||
#if !defined(WOLFSSL_VERSAL_GEN2_ASU_XILASU_2026_1) && \
|
||||
!defined(WOLFSSL_VERSAL_GEN2_ASU_XILASU_2025_2)
|
||||
#define WOLFSSL_VERSAL_GEN2_ASU_XILASU_2025_2
|
||||
#endif
|
||||
|
||||
/* No engine was named, so turn them all on. */
|
||||
#if !defined(WOLFSSL_VERSAL_GEN2_ASU_TRNG) && \
|
||||
!defined(WOLFSSL_VERSAL_GEN2_ASU_HASH) && \
|
||||
@@ -85,6 +106,28 @@
|
||||
#define WOLF_CRYPTO_CB_RSA_PAD
|
||||
#endif
|
||||
|
||||
/* P-521 needs the firmware to front-pad the digest, which it does from Vitis
|
||||
* 2026.1. Before that the curve stayed off because the padding was wrong. */
|
||||
#if defined(WOLFSSL_VERSAL_GEN2_ASU_ECC) && \
|
||||
defined(WOLFSSL_VERSAL_GEN2_ASU_XILASU_2026_1) && \
|
||||
!defined(WOLFSSL_VERSAL_GEN2_ASU_NO_ECC_P521)
|
||||
#define WOLFSSL_VERSAL_GEN2_ASU_ECC_P521
|
||||
#endif
|
||||
|
||||
/* X25519 and X448 key agreement: Curve25519 and Curve448 joined the ASU curve
|
||||
* list in Vitis 2026.1, so there is nothing to offload before that. */
|
||||
#if defined(WOLFSSL_VERSAL_GEN2_ASU_ECC) && \
|
||||
defined(WOLFSSL_VERSAL_GEN2_ASU_XILASU_2026_1)
|
||||
#ifndef WOLFSSL_VERSAL_GEN2_ASU_NO_X25519
|
||||
#define WOLFSSL_VERSAL_GEN2_ASU_X25519
|
||||
#endif
|
||||
#ifndef WOLFSSL_VERSAL_GEN2_ASU_NO_X448
|
||||
#define WOLFSSL_VERSAL_GEN2_ASU_X448
|
||||
#endif
|
||||
/* The key export APIs these need are checked in asu_ecdh.c, where the
|
||||
* offload actually compiles: this macro alone does not mean it is built. */
|
||||
#endif
|
||||
|
||||
/* ECDH and ECIES come along with ECC when their features are built. */
|
||||
#ifdef WOLFSSL_VERSAL_GEN2_ASU_ECC
|
||||
/* Those feature macros are decided later, so check user macros here. */
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
|
||||
#include <wolfssl/wolfcrypt/types.h>
|
||||
#include "xasu_client.h"
|
||||
#include <wolfssl/wolfcrypt/port/xilinx/versal_gen2_asu/asu_compat.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
||||
Reference in New Issue
Block a user