mirror of https://github.com/wolfSSL/wolfssl.git
Simulate pending for all supported ops in async TLS example
parent
1ed9f2c02c
commit
58445f6372
|
|
@ -29,7 +29,14 @@ make -C examples/async ASYNC_MODE=sw
|
|||
|
||||
### Crypto Callback Mode
|
||||
Uses `WOLF_CRYPTO_CB` with the `AsyncTlsCryptoCb` callback that simulates hardware
|
||||
crypto delays by returning `WC_PENDING_E` for a configurable number of iterations:
|
||||
crypto delays by returning `WC_PENDING_E` for a configurable number of iterations.
|
||||
The simulated device keeps a job table keyed by the request, like a hardware
|
||||
crypto manager: a request pends `TEST_PEND_COUNT` times (default 2) and the
|
||||
next re-invocation with identical arguments completes it. On TLS 1.3 every supported
|
||||
operation class pends (HKDF, AES-GCM, ECC/X25519 key generation and shared
|
||||
secret, ECDSA/Ed25519 sign and verify), including mutual authentication. On
|
||||
TLS 1.2 (`--tls12`) only the RSA and ECDSA signing set pends; the TLS 1.2 state
|
||||
machines do not resume the other classes.
|
||||
```
|
||||
make -C examples/async ASYNC_MODE=cryptocb
|
||||
```
|
||||
|
|
@ -68,7 +75,7 @@ Define `NET_USER_HEADER` to include your network shim and provide the
|
|||
|
||||
## Asynchronous Cryptography Design
|
||||
|
||||
When a cryptographic call is handed off to hardware it return `WC_PENDING_E` up to caller. Then it can keep calling until the operation completes. For some platforms it is required to call `wolfSSL_AsyncPoll`. At the TLS layer a "devId" (Device ID) must be set using `wolfSSL_CTX_SetDevId` to indicate desire to offload cryptography.
|
||||
When a cryptographic call is handed off to hardware, `WC_PENDING_E` is returned up to the caller, which keeps calling until the operation completes. For some platforms it is required to call `wolfSSL_AsyncPoll`. At the TLS layer a "devId" (Device ID) must be set using `wolfSSL_CTX_SetDevId` to indicate the desire to offload cryptography.
|
||||
|
||||
For further design details please see: https://github.com/wolfSSL/wolfAsyncCrypt#design
|
||||
|
||||
|
|
|
|||
|
|
@ -252,8 +252,11 @@ int client_async_test(int argc, char** argv)
|
|||
AsyncTlsCryptoCbCtx cryptoCbCtx;
|
||||
#endif
|
||||
#ifdef WOLFSSL_STATIC_MEMORY
|
||||
static byte memory[300000];
|
||||
static byte memoryIO[34500];
|
||||
/* Sized for a TLS 1.3 mutual-auth handshake with every supported
|
||||
* operation class pending: suspended verifies during mutual auth raise
|
||||
* the bucket high-water mark well above the synchronous footprint. */
|
||||
static byte memory[800000];
|
||||
static byte memoryIO[64000];
|
||||
#if !defined(WOLFSSL_STATIC_MEMORY_LEAN)
|
||||
WOLFSSL_MEM_CONN_STATS ssl_stats;
|
||||
#endif
|
||||
|
|
@ -304,6 +307,7 @@ int client_async_test(int argc, char** argv)
|
|||
if (devId == INVALID_DEVID)
|
||||
devId = 1;
|
||||
XMEMSET(&cryptoCbCtx, 0, sizeof(cryptoCbCtx));
|
||||
cryptoCbCtx.tls12 = tls12;
|
||||
if (wc_CryptoCb_RegisterDevice(devId, AsyncTlsCryptoCb, &cryptoCbCtx) != 0) {
|
||||
fprintf(stderr, "ERROR: wc_CryptoCb_RegisterDevice failed\n");
|
||||
goto out;
|
||||
|
|
@ -567,6 +571,10 @@ int client_async_test(int argc, char** argv)
|
|||
#ifdef WOLFSSL_DEBUG_NONBLOCK
|
||||
printf("WANT_READ/WRITE count: %d\n", wouldblock_count);
|
||||
printf("WC_PENDING_E count: %d\n", pending_count);
|
||||
#ifdef WOLF_CRYPTO_CB
|
||||
printf("Device WC_PENDING_E returns: %d (table-full completions: %d)\n",
|
||||
cryptoCbCtx.pendingCount, cryptoCbCtx.jobFullCount);
|
||||
#endif
|
||||
#endif
|
||||
ret = 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -212,8 +212,11 @@ int server_async_test(int argc, char** argv)
|
|||
AsyncTlsCryptoCbCtx cryptoCbCtx;
|
||||
#endif
|
||||
#ifdef WOLFSSL_STATIC_MEMORY
|
||||
static byte memory[300000];
|
||||
static byte memoryIO[34500];
|
||||
/* Sized for a TLS 1.3 mutual-auth handshake with every supported
|
||||
* operation class pending: suspended verifies during mutual auth raise
|
||||
* the bucket high-water mark well above the synchronous footprint. */
|
||||
static byte memory[800000];
|
||||
static byte memoryIO[64000];
|
||||
#if !defined(WOLFSSL_STATIC_MEMORY_LEAN)
|
||||
WOLFSSL_MEM_CONN_STATS ssl_stats;
|
||||
#endif
|
||||
|
|
@ -311,6 +314,7 @@ int server_async_test(int argc, char** argv)
|
|||
if (devId == INVALID_DEVID)
|
||||
devId = 1;
|
||||
XMEMSET(&cryptoCbCtx, 0, sizeof(cryptoCbCtx));
|
||||
cryptoCbCtx.tls12 = tls12;
|
||||
if (wc_CryptoCb_RegisterDevice(devId, AsyncTlsCryptoCb, &cryptoCbCtx) != 0) {
|
||||
fprintf(stderr, "ERROR: wc_CryptoCb_RegisterDevice failed\n");
|
||||
goto exit;
|
||||
|
|
@ -666,6 +670,10 @@ int server_async_test(int argc, char** argv)
|
|||
#ifdef WOLFSSL_DEBUG_NONBLOCK
|
||||
printf("WANT_READ/WRITE count: %d\n", wouldblock_count);
|
||||
printf("WC_PENDING_E count: %d\n", pending_count);
|
||||
#ifdef WOLF_CRYPTO_CB
|
||||
printf("Device WC_PENDING_E returns: %d (table-full completions: %d)\n",
|
||||
cryptoCbCtx.pendingCount, cryptoCbCtx.jobFullCount);
|
||||
#endif
|
||||
#endif
|
||||
ret = 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -162,6 +162,78 @@ int posix_getdevrandom(unsigned char *out, unsigned int sz)
|
|||
#define TEST_PEND_COUNT 2
|
||||
#endif
|
||||
|
||||
#ifdef WOLFSSL_ASYNC_CRYPT
|
||||
/* Return 1 to simulate WC_PENDING_E. A request (hash of wc_CryptoInfo)
|
||||
* pends TEST_PEND_COUNT times and completes on re-invocation, like a
|
||||
* hardware crypto manager job table. A full table completes requests
|
||||
* synchronously (jobFullCount records the degradation). */
|
||||
static int AsyncTlsCryptoCbPend(AsyncTlsCryptoCbCtx* myCtx,
|
||||
wc_CryptoInfo* info)
|
||||
{
|
||||
unsigned long h = 5381;
|
||||
const unsigned char* b = (const unsigned char*)info;
|
||||
size_t i;
|
||||
int simulate = 0;
|
||||
|
||||
/* TLS 1.3 resumes every class below; TLS 1.2 only retries the
|
||||
* signing set, so restrict when the app selected TLS 1.2. */
|
||||
if (myCtx->tls12) {
|
||||
if (info->algo_type == WC_ALGO_TYPE_PK) {
|
||||
simulate = (info->pk.type == WC_PK_TYPE_RSA ||
|
||||
info->pk.type == WC_PK_TYPE_ECDSA_SIGN);
|
||||
}
|
||||
}
|
||||
else if (info->algo_type == WC_ALGO_TYPE_PK) {
|
||||
simulate = (info->pk.type == WC_PK_TYPE_RSA ||
|
||||
info->pk.type == WC_PK_TYPE_EC_KEYGEN ||
|
||||
info->pk.type == WC_PK_TYPE_ECDSA_SIGN ||
|
||||
info->pk.type == WC_PK_TYPE_ECDSA_VERIFY ||
|
||||
info->pk.type == WC_PK_TYPE_ECDH ||
|
||||
info->pk.type == WC_PK_TYPE_CURVE25519_KEYGEN ||
|
||||
info->pk.type == WC_PK_TYPE_CURVE25519 ||
|
||||
info->pk.type == WC_PK_TYPE_ED25519_SIGN ||
|
||||
info->pk.type == WC_PK_TYPE_ED25519_VERIFY);
|
||||
}
|
||||
else if (info->algo_type == WC_ALGO_TYPE_KDF) {
|
||||
simulate = 1; /* TLS 1.3 HKDF key schedule */
|
||||
}
|
||||
else if (info->algo_type == WC_ALGO_TYPE_CIPHER) {
|
||||
simulate = (info->cipher.type == WC_CIPHER_AES_GCM);
|
||||
}
|
||||
if (!simulate)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < sizeof(*info); i++)
|
||||
h = (h * 33) + b[i];
|
||||
|
||||
for (i = 0; i < (size_t)myCtx->jobCount; i++) {
|
||||
if (myCtx->jobHash[i] == h) {
|
||||
myCtx->jobTries[i]++;
|
||||
if (myCtx->jobTries[i] <= TEST_PEND_COUNT) {
|
||||
myCtx->pendingCount++;
|
||||
return 1; /* still pending */
|
||||
}
|
||||
/* complete: remove job and run the operation below */
|
||||
myCtx->jobCount--;
|
||||
myCtx->jobHash[i] = myCtx->jobHash[myCtx->jobCount];
|
||||
myCtx->jobTries[i] = myCtx->jobTries[myCtx->jobCount];
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (myCtx->jobCount >= ASYNC_TLS_PEND_JOBS) {
|
||||
/* Full (non-identical retries strand entries): complete
|
||||
* synchronously and count the degradation. */
|
||||
myCtx->jobFullCount++;
|
||||
return 0;
|
||||
}
|
||||
myCtx->jobHash[myCtx->jobCount] = h;
|
||||
myCtx->jobTries[myCtx->jobCount] = 1;
|
||||
myCtx->jobCount++;
|
||||
myCtx->pendingCount++;
|
||||
return 1;
|
||||
}
|
||||
#endif /* WOLFSSL_ASYNC_CRYPT */
|
||||
|
||||
/* Example crypto dev callback function that calls software version */
|
||||
/* This is where you would plug-in calls to your own hardware crypto */
|
||||
int AsyncTlsCryptoCb(int devIdArg, wc_CryptoInfo* info, void* ctx)
|
||||
|
|
@ -169,32 +241,20 @@ int AsyncTlsCryptoCb(int devIdArg, wc_CryptoInfo* info, void* ctx)
|
|||
int ret = WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE); /* bypass HW by default */
|
||||
AsyncTlsCryptoCbCtx* myCtx = (AsyncTlsCryptoCbCtx*)ctx;
|
||||
|
||||
if (info == NULL)
|
||||
if (info == NULL || myCtx == NULL)
|
||||
return BAD_FUNC_ARG;
|
||||
|
||||
#ifdef DEBUG_CRYPTOCB
|
||||
wc_CryptoCb_InfoString(info);
|
||||
#endif
|
||||
|
||||
if (info->algo_type == WC_ALGO_TYPE_PK) {
|
||||
#ifdef WOLFSSL_ASYNC_CRYPT
|
||||
/* Simulate async pending for RSA and ECC signing operations.
|
||||
* This matches a typical hardware crypto scenario (e.g., TPM) where
|
||||
* only signing is offloaded to hardware. Keygen, verify, and ECDH
|
||||
* are performed synchronously in software.
|
||||
* Note: WOLFSSL_ASYNC_CRYPT + WOLF_CRYPTO_CB pending simulation
|
||||
* requires operations whose TLS state machines properly handle retry
|
||||
* via wolfSSL_AsyncPop. ECC keygen in TLSX_KeyShare_GenEccKey does
|
||||
* not support this because the keygen call is inside the key
|
||||
* allocation guard (kse->key == NULL) which is skipped on retry. */
|
||||
if (info->pk.type == WC_PK_TYPE_RSA ||
|
||||
info->pk.type == WC_PK_TYPE_ECDSA_SIGN)
|
||||
{
|
||||
if (myCtx->pendingCount++ < TEST_PEND_COUNT) return WC_PENDING_E;
|
||||
myCtx->pendingCount = 0;
|
||||
}
|
||||
if (AsyncTlsCryptoCbPend(myCtx, info)) {
|
||||
return WC_PENDING_E;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (info->algo_type == WC_ALGO_TYPE_PK) {
|
||||
#ifndef NO_RSA
|
||||
if (info->pk.type == WC_PK_TYPE_RSA) {
|
||||
/* set devId to invalid, so software is used */
|
||||
|
|
|
|||
|
|
@ -46,8 +46,23 @@ typedef struct wc_CryptoInfo wc_CryptoInfo;
|
|||
|
||||
#ifdef WOLF_CRYPTO_CB
|
||||
/* Example custom context for crypto callback */
|
||||
/* Max simultaneous simulated pending requests (device job table) */
|
||||
#ifndef ASYNC_TLS_PEND_JOBS
|
||||
#define ASYNC_TLS_PEND_JOBS 64
|
||||
#endif
|
||||
typedef struct {
|
||||
int pendingCount; /* track pending tries test count */
|
||||
int pendingCount; /* total WC_PENDING_E returns (statistic) */
|
||||
/* Simulated device job table. A pended request is identified by a
|
||||
* hash of its wc_CryptoInfo so the re-invocation with identical
|
||||
* arguments can be matched and completed. */
|
||||
unsigned long jobHash[ASYNC_TLS_PEND_JOBS];
|
||||
int jobTries[ASYNC_TLS_PEND_JOBS];
|
||||
int jobCount;
|
||||
int jobFullCount; /* requests completed synchronously: table full */
|
||||
/* Set by the application when TLS 1.2 was selected: restricts the
|
||||
* simulated pending to the operations the TLS 1.2 state machines can
|
||||
* retry. TLS 1.3 (0, the default) pends every supported class. */
|
||||
int tls12;
|
||||
} AsyncTlsCryptoCbCtx;
|
||||
int AsyncTlsCryptoCb(int devIdArg, wc_CryptoInfo* info, void* ctx);
|
||||
#endif /* WOLF_CRYPTO_CB */
|
||||
|
|
|
|||
Loading…
Reference in New Issue