diff --git a/doc/dox_comments/header_files/cryptocb.h b/doc/dox_comments/header_files/cryptocb.h index c0cd035eda..95fb22e078 100644 --- a/doc/dox_comments/header_files/cryptocb.h +++ b/doc/dox_comments/header_files/cryptocb.h @@ -13,6 +13,10 @@ \return CRYPTOCB_UNAVAILABLE to fallback to using software crypto \return 0 for success + \return ALREADY_E if devId is already registered. A devId must be + un-registered with wc_CryptoCb_UnRegisterDevice before it can be + registered again; re-registering an active devId is not an in-place update. + \return BAD_FUNC_ARG if devId is INVALID_DEVID (-2) \return negative value for failure \param devId any unique value, not -2 (INVALID_DEVID) @@ -98,6 +102,32 @@ */ int wc_CryptoCb_RegisterDevice(int devId, CryptoDevCallbackFunc cb, void* ctx); +/*! + \ingroup CryptoCb + + \brief This function reports whether a crypto callback device identifier + (devID) is currently registered. It is useful for checking registration + state before calling wc_CryptoCb_RegisterDevice, which now rejects an + already-registered devID with ALREADY_E. + + \return 1 if the device ID is registered + \return 0 if the device ID is not registered, or if devId is + INVALID_DEVID (-2) + + \param devId the device identifier to query + + _Example_ + \code + if (!wc_CryptoCb_IsDeviceRegistered(devId)) { + wc_CryptoCb_RegisterDevice(devId, myCryptoCb_Func, &myCtx); + } + \endcode + + \sa wc_CryptoCb_RegisterDevice + \sa wc_CryptoCb_UnRegisterDevice +*/ +int wc_CryptoCb_IsDeviceRegistered(int devId); + /*! \ingroup CryptoCb diff --git a/tests/api.c b/tests/api.c index 957dd445b3..1fa3636d95 100644 --- a/tests/api.c +++ b/tests/api.c @@ -30143,13 +30143,81 @@ static int test_wc_CryptoCb(void) (!defined(WOLF_CRYPTO_CB_ONLY_SHA256) && !defined(WOLF_CRYPTO_CB_ONLY_AES) && \ !defined(WOLF_CRYPTO_CB_ONLY_ECC) && !defined(WOLF_CRYPTO_CB_ONLY_RSA) && \ !defined(WOLF_CRYPTO_CB_ONLY_SHA512)) - /* TODO: Add crypto callback API tests */ - -#ifdef HAVE_IO_TESTS_DEPENDENCIES - #if !defined(NO_RSA) || defined(HAVE_ECC) || defined(HAVE_ED25519) +#if defined(HAVE_IO_TESTS_DEPENDENCIES) && \ + (!defined(NO_RSA) || defined(HAVE_ECC) || defined(HAVE_ED25519)) int tlsVer; +#endif + /* Exercise the exposed CryptoCb device-management API: + * wc_CryptoCb_RegisterDevice / UnRegisterDevice / IsDeviceRegistered / + * DefaultDevID (and InfoString when DEBUG_CRYPTOCB is enabled). */ + { + int getDevId = 1234; + int getDevCtx = 0; + int i, n, rc; + + /* Unregistered devId is not reported as registered. */ + ExpectIntEQ(wc_CryptoCb_IsDeviceRegistered(getDevId), 0); + + /* Registering with INVALID_DEVID is rejected. */ + ExpectIntEQ(wc_CryptoCb_RegisterDevice(INVALID_DEVID, NULL, &getDevCtx), + WC_NO_ERR_TRACE(BAD_FUNC_ARG)); + ExpectIntEQ(wc_CryptoCb_IsDeviceRegistered(INVALID_DEVID), 0); + + /* After registering, the device is reported registered. */ + ExpectIntEQ(wc_CryptoCb_RegisterDevice(getDevId, NULL, &getDevCtx), 0); + ExpectIntEQ(wc_CryptoCb_IsDeviceRegistered(getDevId), 1); + + /* A different, unregistered devId is still not reported registered. */ + ExpectIntEQ(wc_CryptoCb_IsDeviceRegistered(getDevId + 1), 0); + + /* Re-registering an already-registered devId is rejected. */ + ExpectIntEQ(wc_CryptoCb_RegisterDevice(getDevId, NULL, &getDevCtx), + WC_NO_ERR_TRACE(ALREADY_E)); + + /* wc_CryptoCb_DefaultDevID behavior depends on the build config. */ + #ifdef WC_NO_DEFAULT_DEVID + ExpectIntEQ(wc_CryptoCb_DefaultDevID(), INVALID_DEVID); + #elif !defined(WOLFSSL_CAAM_DEVID) && !defined(HAVE_ARIA) && \ + !defined(WC_USE_DEVID) + /* "first available" mode: a device is registered, so one is returned. */ + ExpectIntNE(wc_CryptoCb_DefaultDevID(), INVALID_DEVID); #endif + /* After unregistering, the device is no longer registered. */ + wc_CryptoCb_UnRegisterDevice(getDevId); + ExpectIntEQ(wc_CryptoCb_IsDeviceRegistered(getDevId), 0); + + /* Unregistering is a harmless no-op for unknown or invalid devIds. */ + wc_CryptoCb_UnRegisterDevice(getDevId); /* already removed */ + wc_CryptoCb_UnRegisterDevice(INVALID_DEVID); /* never a real devId */ + ExpectIntEQ(wc_CryptoCb_IsDeviceRegistered(getDevId), 0); + + /* The device table is finite: once full, registration returns + * BUFFER_E. Registering MAX_CRYPTO_DEVID_CALLBACKS + 1 unique devIds is + * guaranteed to fill the table and hit BUFFER_E regardless of how many + * slots were already in use. Then unregister every id we tried + * (UnRegister is a no-op for the final failed attempt). */ + rc = 0; + for (i = 0; rc == 0 && i <= MAX_CRYPTO_DEVID_CALLBACKS; i++) { + rc = wc_CryptoCb_RegisterDevice(0x5000 + i, NULL, NULL); + } + ExpectIntEQ(rc, WC_NO_ERR_TRACE(BUFFER_E)); + for (n = 0; n < i; n++) { + wc_CryptoCb_UnRegisterDevice(0x5000 + n); + } + + #ifdef DEBUG_CRYPTOCB + /* wc_CryptoCb_InfoString smoke test: must not dereference bad memory. */ + { + wc_CryptoInfo info; + XMEMSET(&info, 0, sizeof(info)); + info.algo_type = WC_ALGO_TYPE_NONE; + wc_CryptoCb_InfoString(&info); + } + #endif + } + +#ifdef HAVE_IO_TESTS_DEPENDENCIES #ifndef NO_RSA for (tlsVer = WOLFSSL_SSLV3; tlsVer <= WOLFSSL_DTLSV1; tlsVer++) { ExpectIntEQ(test_wc_CryptoCb_TLS(tlsVer, diff --git a/wolfcrypt/src/cryptocb.c b/wolfcrypt/src/cryptocb.c index 8230a343f2..c3067b97b8 100644 --- a/wolfcrypt/src/cryptocb.c +++ b/wolfcrypt/src/cryptocb.c @@ -80,9 +80,6 @@ Crypto Callback Build Options: #include #endif /* TODO: Consider linked list with mutex */ -#ifndef MAX_CRYPTO_DEVID_CALLBACKS -#define MAX_CRYPTO_DEVID_CALLBACKS 8 -#endif typedef struct CryptoCb { int devId; @@ -372,6 +369,15 @@ static CryptoCb* wc_CryptoCb_GetDevice(int devId) return NULL; } +/* Returns 1 if the given device ID is currently registered, 0 otherwise. + * INVALID_DEVID marks free table slots, so it is never reported registered. */ +int wc_CryptoCb_IsDeviceRegistered(int devId) +{ + if (devId == INVALID_DEVID) + return 0; + return wc_CryptoCb_GetDevice(devId) != NULL; +} + /* Filters through find callback set when trying to get the device, * returns the device found on success and null if not found. */ @@ -458,12 +464,18 @@ void wc_CryptoCb_SetDeviceFindCb(CryptoDevCallbackFind cb) int wc_CryptoCb_RegisterDevice(int devId, CryptoDevCallbackFunc cb, void* ctx) { int rc = 0; + CryptoCb* dev; - /* find existing or new */ - CryptoCb* dev = wc_CryptoCb_GetDevice(devId); - if (dev == NULL) - dev = wc_CryptoCb_GetDevice(INVALID_DEVID); + /* INVALID_DEVID marks a free slot and cannot be registered as a device. */ + if (devId == INVALID_DEVID) + return BAD_FUNC_ARG; + /* Reject re-registration of an already-registered device ID. */ + if (wc_CryptoCb_GetDevice(devId) != NULL) + return ALREADY_E; + + /* find a free slot */ + dev = wc_CryptoCb_GetDevice(INVALID_DEVID); if (dev == NULL) return BUFFER_E; /* out of devices */ diff --git a/wolfssl/wolfcrypt/cryptocb.h b/wolfssl/wolfcrypt/cryptocb.h index 9e75db3014..3de89680e6 100644 --- a/wolfssl/wolfcrypt/cryptocb.h +++ b/wolfssl/wolfcrypt/cryptocb.h @@ -725,12 +725,18 @@ typedef struct wc_CryptoInfo { typedef int (*CryptoDevCallbackFunc)(int devId, struct wc_CryptoInfo* info, void* ctx); +/* Maximum number of crypto callback devices that can be registered. */ +#ifndef MAX_CRYPTO_DEVID_CALLBACKS +#define MAX_CRYPTO_DEVID_CALLBACKS 8 +#endif + WOLFSSL_LOCAL void wc_CryptoCb_Init(void); WOLFSSL_LOCAL void wc_CryptoCb_Cleanup(void); WOLFSSL_LOCAL int wc_CryptoCb_GetDevIdAtIndex(int startIdx); WOLFSSL_API int wc_CryptoCb_RegisterDevice(int devId, CryptoDevCallbackFunc cb, void* ctx); WOLFSSL_API void wc_CryptoCb_UnRegisterDevice(int devId); WOLFSSL_API int wc_CryptoCb_DefaultDevID(void); +WOLFSSL_API int wc_CryptoCb_IsDeviceRegistered(int devId); #ifdef WOLF_CRYPTO_CB_FIND typedef int (*CryptoDevCallbackFind)(int devId, int algoType);