F-1715 F-2114 F-3224 F-3690 F-4120 F-4123 F-4124 F-5614 F-5615: replace hardcoded/UAF-prone secrets and keys with RNG-generated values, zeroize key material before free, and flag non-constant-time secret comparisons

pull/593/head
Emma Stensland 2026-07-02 09:45:17 -06:00 committed by Paul Adelsbach
parent 717e52d02b
commit 210e9caf3e
17 changed files with 615 additions and 249 deletions

View File

@ -87,6 +87,7 @@
/* wolfcrypt includes */
#include "wolfssl/wolfcrypt/types.h" /* types and X-defines */
#include "wolfssl/wolfcrypt/memory.h" /* For wc_ForceZero */
#ifndef CCBVAULTIC_NO_SHA
#include "wolfssl/wolfcrypt/hash.h" /* For HASH_FLAGS and types */
@ -156,6 +157,31 @@ static void hexdump(const unsigned char* p, size_t len)
}
#endif
#ifdef WOLF_CRYPTO_CB
/* Constant-time buffer compare for secret material.
*
* wolfSSL's own constant-time compare (ConstantCompare() in
* wolfcrypt/src/misc.c) is WOLFSSL_LOCAL and not exported, so it can't be
* called from application code. Every byte is compared regardless of where
* a mismatch occurs, so the runtime doesn't leak position information via
* early-exit timing.
*
* Returns 0 if the buffers are equal, non-zero otherwise. */
static int const_time_memcmp(const void* a, const void* b, size_t len)
{
const byte* pa = (const byte*)a;
const byte* pb = (const byte*)b;
byte diff = 0;
size_t i;
for (i = 0; i < len; i++) {
diff |= (byte)(pa[i] ^ pb[i]);
}
return (int)diff;
}
#endif /* WOLF_CRYPTO_CB */
/* Helper to translate vlt return codes to wolfSSL code */
static int translateError(int vlt_rc)
{
@ -231,10 +257,14 @@ void ccbVaultIc_Cleanup(ccbVaultIc_Context *c)
return;
/* Free allocated buffers */
if (c->m != NULL)
if (c->m != NULL) {
wc_ForceZero(c->m, c->m_len);
XFREE(c->m, NULL, NULL);
if (c->aescbc_key != NULL)
}
if (c->aescbc_key != NULL) {
wc_ForceZero(c->aescbc_key, c->aescbc_keylen);
XFREE(c->aescbc_key, NULL, NULL);
}
clearContext(c);
@ -975,10 +1005,12 @@ static int HandleCipherCallback(int devId, wc_CryptoInfo* info,
vlt_mode = VLT_DECRYPT_MODE;
}
/* Check if key is not the same as last time */
/* Check if key is not the same as last time. Uses a constant-time
* compare since this is secret key material, even though this
* check only gates a cache refresh (not authentication). */
if ((c->aescbc_key == NULL) ||
(c->aescbc_keylen != aes->keylen) ||
(XMEMCMP(c->aescbc_key, aes->devKey, aes->keylen))) {
(const_time_memcmp(c->aescbc_key, aes->devKey, aes->keylen))) {
#if defined(CCBVAULTIC_DEBUG_ALL)
XPRINTF(" New AES Key: ckey:%p clen:%lu akey:%p alen:%u\n",
c->aescbc_key,c->aescbc_keylen, aes->devKey, aes->keylen);
@ -986,6 +1018,7 @@ static int HandleCipherCallback(int devId, wc_CryptoInfo* info,
#endif
/* Free the current key buffer if necessary */
if (c->aescbc_key != NULL) {
wc_ForceZero(c->aescbc_key, c->aescbc_keylen);
XFREE(c->aescbc_key, NULL, NULL);
c->aescbc_key = NULL;
c->aescbc_keylen = 0;

View File

@ -218,6 +218,7 @@ static int init_pk_key(Cert* req, void** keyPtr, WC_RNG* rng, byte* der,
ret = wc_ecc_init((ecc_key*)*keyPtr);
if (ret != 0) {
XFREE(*keyPtr, NULL, DYNAMIC_TYPE_ECC);
*keyPtr = NULL;
break;
}
ret = wc_ecc_make_key_ex(rng, 32, (ecc_key*)*keyPtr, ECC_SECP256R1);
@ -249,6 +250,7 @@ static int init_pk_key(Cert* req, void** keyPtr, WC_RNG* rng, byte* der,
ret = wc_InitRsaKey((RsaKey*)*keyPtr, NULL);
if (ret != 0) {
XFREE(*keyPtr, NULL, DYNAMIC_TYPE_RSA);
*keyPtr = NULL;
break;
}
ret = wc_MakeRsaKey((RsaKey*)*keyPtr, 2048, WC_RSA_EXPONENT, rng);
@ -280,6 +282,7 @@ static int init_pk_key(Cert* req, void** keyPtr, WC_RNG* rng, byte* der,
ret = wc_ed25519_init((ed25519_key*)*keyPtr);
if (ret != 0) {
XFREE(*keyPtr, NULL, DYNAMIC_TYPE_ED25519);
*keyPtr = NULL;
break;
}
ret = wc_ed25519_make_key(rng, ED25519_KEY_SIZE,

View File

@ -192,7 +192,6 @@ int Des3Encrypt(Des3* des3, byte* key, int size, FILE* inFile, FILE* outFile)
*/
int Des3Decrypt(Des3* des3, byte* key, int size, FILE* inFile, FILE* outFile)
{
WC_RNG rng;
byte iv[DES3_BLOCK_SIZE];
byte* input = NULL;
byte* output = NULL;
@ -202,7 +201,6 @@ int Des3Decrypt(Des3* des3, byte* key, int size, FILE* inFile, FILE* outFile)
int ret = 0;
int length;
int aSize;
int rngInit = 0;
int des3Init = 0;
fseek(inFile, 0, SEEK_END);
@ -228,14 +226,6 @@ int Des3Decrypt(Des3* des3, byte* key, int size, FILE* inFile, FILE* outFile)
}
}
if (ret == 0) {
ret = wc_InitRng(&rng);
if (ret != 0)
XPRINTF("Failed to initialize random number generator\n");
else
rngInit = 1;
}
/* reads from inFile and writes whatever is there to the input array */
if (ret == 0) {
ret = fread(input, 1, length, inFile);
@ -332,8 +322,6 @@ int Des3Decrypt(Des3* des3, byte* key, int size, FILE* inFile, FILE* outFile)
fclose(outFile);
if (des3Init)
wc_Des3Free(des3);
if (rngInit)
wc_FreeRng(&rng);
return ret;
}
@ -460,15 +448,19 @@ int main(int argc, char** argv)
}
if (inCheck == 0 || outCheck == 0) {
XPRINTF("Must have both input and output file");
XPRINTF(": -i filename -o filename\n");
XPRINTF("Must have both input and output file");
XPRINTF(": -i filename -o filename\n");
if (inFile != NULL) fclose(inFile);
if (outFile != NULL) fclose(outFile);
}
else if (ret == 0 && choice != 'n' && inFile != NULL) {
else if (ret == 0 && choice != 'n' && inFile != NULL && outFile != NULL) {
key = (byte*)XMALLOC(size, NULL, DYNAMIC_TYPE_TMP_BUFFER); /* sets size memory of key */
if (key == NULL) {
XPRINTF("Failed to allocate memory for key\n");
ret = -1050;
fclose(inFile);
if (outFile != NULL)
fclose(outFile);
}
else {
ret = NoEcho((char*)key, size);
@ -481,12 +473,23 @@ int main(int argc, char** argv)
else {
wc_ForceZero(key, size);
XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER);
fclose(inFile);
if (outFile != NULL)
fclose(outFile);
}
}
}
else if (choice == 'n') {
XPRINTF("Must select either -e[56,112,168] or -d[56,112,168] for \
else {
if (choice == 'n') {
XPRINTF("Must select either -e[56,112,168] or -d[56,112,168] for \
encryption and decryption\n");
}
if (inFile != NULL) {
fclose(inFile);
}
if (outFile != NULL) {
fclose(outFile);
}
}
return ret;

View File

@ -202,7 +202,6 @@ int AesEncrypt(Aes* aes, byte* key, int size, FILE* inFile, FILE* outFile)
*/
int AesDecrypt(Aes* aes, byte* key, int size, FILE* inFile, FILE* outFile)
{
WC_RNG rng;
byte iv[AES_BLOCK_SIZE];
byte* input = NULL;
byte* output = NULL;
@ -212,7 +211,6 @@ int AesDecrypt(Aes* aes, byte* key, int size, FILE* inFile, FILE* outFile)
int ret = 0;
int length;
int aSize;
int rngInit = 0;
int aesInit = 0;
fseek(inFile, 0, SEEK_END);
@ -236,14 +234,6 @@ int AesDecrypt(Aes* aes, byte* key, int size, FILE* inFile, FILE* outFile)
}
}
if (ret == 0) {
ret = wc_InitRng(&rng);
if (ret != 0)
XPRINTF("Failed to initialize random number generator\n");
else
rngInit = 1;
}
/* reads from inFile and writes whatever is there to the input array */
if (ret == 0) {
ret = fread(input, 1, length, inFile);
@ -344,8 +334,6 @@ int AesDecrypt(Aes* aes, byte* key, int size, FILE* inFile, FILE* outFile)
fclose(outFile);
if (aesInit)
wc_AesFree(aes);
if (rngInit)
wc_FreeRng(&rng);
return ret;
}
@ -482,14 +470,19 @@ int main(int argc, char** argv)
}
}
if (inCheck == 0 || outCheck == 0) {
XPRINTF("Must have both input and output file");
XPRINTF(": -i filename -o filename\n");
XPRINTF("Must have both input and output file");
XPRINTF(": -i filename -o filename\n");
if (inFile != NULL) fclose(inFile);
if (outFile != NULL) fclose(outFile);
}
else if (ret == 0 && choice != 'n' && inFile != NULL) {
else if (ret == 0 && choice != 'n' && inFile != NULL && outFile != NULL) {
key = (byte*)XMALLOC(size, NULL, DYNAMIC_TYPE_TMP_BUFFER); /* sets size memory of key */
if (key == NULL) {
XPRINTF("Failed to allocate memory for key\n");
ret = -1050;
fclose(inFile);
if (outFile != NULL)
fclose(outFile);
}
else {
ret = NoEcho((char*)key, size);
@ -502,13 +495,24 @@ int main(int argc, char** argv)
else {
wc_ForceZero(key, size);
XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER);
fclose(inFile);
if (outFile != NULL)
fclose(outFile);
}
}
}
else if (choice == 'n') {
XPRINTF("Must select either -e[128, 192, 256] or -d[128, 192, 256] \
else {
if (choice == 'n') {
XPRINTF("Must select either -e[128, 192, 256] or -d[128, 192, 256] \
for encryption and decryption\n");
ret = -110;
ret = -110;
}
if (inFile != NULL) {
fclose(inFile);
}
if (outFile != NULL) {
fclose(outFile);
}
}
return ret;

View File

@ -195,7 +195,6 @@ int AesEncrypt(Aes* aes, byte* key, int size, FILE* inFile, FILE* outFile)
*/
int AesDecrypt(Aes* aes, byte* key, int size, FILE* inFile, FILE* outFile)
{
WC_RNG rng;
byte iv[AES_BLOCK_SIZE];
byte* input = NULL;
byte* output = NULL;
@ -205,7 +204,6 @@ int AesDecrypt(Aes* aes, byte* key, int size, FILE* inFile, FILE* outFile)
int ret = 0;
int length;
int aSize;
int rngInit = 0;
int aesInit = 0;
fseek(inFile, 0, SEEK_END);
@ -230,14 +228,6 @@ int AesDecrypt(Aes* aes, byte* key, int size, FILE* inFile, FILE* outFile)
}
}
if (ret == 0) {
ret = wc_InitRng(&rng);
if (ret != 0)
XPRINTF("Failed to initialize random number generator\n");
else
rngInit = 1;
}
/* reads from inFile and writes whatever is there to the input array */
if (ret == 0) {
ret = fread(input, 1, length, inFile);
@ -337,8 +327,6 @@ int AesDecrypt(Aes* aes, byte* key, int size, FILE* inFile, FILE* outFile)
fclose(outFile);
if (aesInit)
wc_AesFree(aes);
if (rngInit)
wc_FreeRng(&rng);
return ret;
}
@ -475,14 +463,19 @@ int main(int argc, char** argv)
}
}
if (inCheck == 0 || outCheck == 0) {
XPRINTF("Must have both input and output file");
XPRINTF(": -i filename -o filename\n");
XPRINTF("Must have both input and output file");
XPRINTF(": -i filename -o filename\n");
if (inFile != NULL) fclose(inFile);
if (outFile != NULL) fclose(outFile);
}
else if (ret == 0 && choice != 'n' && inFile != NULL) {
else if (ret == 0 && choice != 'n' && inFile != NULL && outFile != NULL) {
key = (byte*)XMALLOC(size, NULL, DYNAMIC_TYPE_TMP_BUFFER); /* sets size memory of key */
if (key == NULL) {
XPRINTF("Failed to allocate memory for key\n");
ret = -1050;
fclose(inFile);
if (outFile != NULL)
fclose(outFile);
}
else {
ret = NoEcho((char*)key, size);
@ -495,13 +488,24 @@ int main(int argc, char** argv)
else {
wc_ForceZero(key, size);
XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER);
fclose(inFile);
if (outFile != NULL)
fclose(outFile);
}
}
}
else if (choice == 'n') {
XPRINTF("Must select either -e[128, 192, 256] or -d[128, 192, 256] \
else {
if (choice == 'n') {
XPRINTF("Must select either -e[128, 192, 256] or -d[128, 192, 256] \
for encryption and decryption\n");
ret = -110;
ret = -110;
}
if (inFile != NULL) {
fclose(inFile);
}
if (outFile != NULL) {
fclose(outFile);
}
}
return ret;

View File

@ -416,14 +416,19 @@ int main(int argc, char** argv)
}
}
if (inCheck == 0 || outCheck == 0) {
XPRINTF("Must have both input and output file");
XPRINTF(": -i filename -o filename\n");
XPRINTF("Must have both input and output file");
XPRINTF(": -i filename -o filename\n");
if (inFile != NULL) fclose(inFile);
if (outFile != NULL) fclose(outFile);
}
else if (ret == 0 && choice != 'n' && inFile != NULL) {
else if (ret == 0 && choice != 'n' && inFile != NULL && outFile != NULL) {
key = (byte*)XMALLOC(size, NULL, DYNAMIC_TYPE_TMP_BUFFER); /* sets size memory of key */
if (key == NULL) {
XPRINTF("Failed to allocate memory for key\n");
ret = -1050;
fclose(inFile);
if (outFile != NULL)
fclose(outFile);
}
else {
ret = NoEcho((char*)key, size);
@ -436,13 +441,24 @@ int main(int argc, char** argv)
else {
wc_ForceZero(key, size);
XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER);
fclose(inFile);
if (outFile != NULL)
fclose(outFile);
}
}
}
else if (choice == 'n') {
XPRINTF("Must select either -e[128, 192, 256] or -d[128, 192, 256] \
else {
if (choice == 'n') {
XPRINTF("Must select either -e[128, 192, 256] or -d[128, 192, 256] \
for encryption and decryption\n");
ret = -110;
ret = -110;
}
if (inFile != NULL) {
fclose(inFile);
}
if (outFile != NULL) {
fclose(outFile);
}
}
return ret;

View File

@ -180,6 +180,7 @@ int encrypt_file_AesGCM(const char *in_file, const char *out_file,
byte key[AES_KEY_SIZE];
byte tag_enc[AESGCM_TAG_SIZE];
Aes gcm;
int aes_initialized = 0;
if (!in_file || !out_file || !key_str || !iv_str) {
return BAD_FUNC_ARG;
@ -242,6 +243,7 @@ int encrypt_file_AesGCM(const char *in_file, const char *out_file,
printf("AesInit returned: %d\n", ret);
goto exit;
}
aes_initialized = 1;
ret = wc_AesGcmEncryptInit(&gcm, key, AES_KEY_SIZE, iv, AES_IV_SIZE);
if (ret == 0) {
@ -304,6 +306,9 @@ int encrypt_file_AesGCM(const char *in_file, const char *out_file,
}
printf("File encryption with AES GCM complete.\n");
exit:
if (aes_initialized) {
wc_AesFree(&gcm);
}
wc_ForceZero(key, AES_KEY_SIZE);
wc_ForceZero(iv, AES_IV_SIZE);
wc_ForceZero(tag_enc, AESGCM_TAG_SIZE);
@ -352,6 +357,7 @@ int decrypt_file_AesGCM(const char *in_file, const char *out_file,
byte key[AES_KEY_SIZE];
byte tag[AESGCM_TAG_SIZE];
Aes gcm;
int aes_initialized = 0;
if (!in_file || !out_file || !key_str) {
return BAD_FUNC_ARG;
@ -434,6 +440,14 @@ int decrypt_file_AesGCM(const char *in_file, const char *out_file,
goto exit;
}
/* inits aes structure */
ret = wc_AesInit(&gcm, NULL, INVALID_DEVID);
if (ret != 0) {
printf("AesInit returned: %d\n", ret);
goto exit;
}
aes_initialized = 1;
ret = wc_AesGcmDecryptInit(&gcm, key, AES_KEY_SIZE, iv, AES_IV_SIZE);
while (ret == 0) {
@ -457,6 +471,9 @@ int decrypt_file_AesGCM(const char *in_file, const char *out_file,
ret = wc_AesGcmDecryptFinal(&gcm, tag, AESGCM_TAG_SIZE);
}
exit:
if (aes_initialized) {
wc_AesFree(&gcm);
}
wc_ForceZero(key, AES_KEY_SIZE);
wc_ForceZero(iv, AES_IV_SIZE);
wc_ForceZero(tag, AESGCM_TAG_SIZE);

View File

@ -175,7 +175,6 @@ int CamelliaEncrypt(Camellia* cam, byte* key, int size, FILE* inFile,
int CamelliaDecrypt(Camellia* cam, byte* key, int size, FILE* inFile,
FILE* outFile)
{
WC_RNG rng;
byte iv[CAMELLIA_BLOCK_SIZE];
byte* input = NULL;
byte* output = NULL;
@ -185,7 +184,6 @@ int CamelliaDecrypt(Camellia* cam, byte* key, int size, FILE* inFile,
int ret = 0;
int length;
int aSize;
int rngInit = 0;
fseek(inFile, 0, SEEK_END);
length = ftell(inFile);
@ -209,14 +207,6 @@ int CamelliaDecrypt(Camellia* cam, byte* key, int size, FILE* inFile,
}
}
if (ret == 0) {
ret = wc_InitRng(&rng);
if (ret != 0)
XPRINTF("Failed to initialize random number generator\n");
else
rngInit = 1;
}
/* reads from inFile and writes whatever is there to the input array */
if (ret == 0) {
ret = fread(input, 1, length, inFile);
@ -297,8 +287,6 @@ int CamelliaDecrypt(Camellia* cam, byte* key, int size, FILE* inFile,
XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER);
fclose(inFile);
fclose(outFile);
if (rngInit)
wc_FreeRng(&rng);
return ret;
}
@ -425,15 +413,19 @@ int main(int argc, char** argv)
}
}
if (inCheck == 0 || outCheck == 0) {
XPRINTF("Must have both input and output file");
XPRINTF(": -i filename -o filename\n");
XPRINTF("Must have both input and output file");
XPRINTF(": -i filename -o filename\n");
if (inFile != NULL) fclose(inFile);
if (outFile != NULL) fclose(outFile);
}
else if (ret == 0 && choice != 'n' && inFile != NULL) {
else if (ret == 0 && choice != 'n' && inFile != NULL && outFile != NULL) {
key = (byte*)XMALLOC(size, NULL, DYNAMIC_TYPE_TMP_BUFFER); /* sets size memory of key */
if (key == NULL) {
XPRINTF("Failed to allocate memory for key\n");
ret = -1050;
fclose(inFile);
if (outFile != NULL)
fclose(outFile);
}
else {
ret = NoEcho((char*)key, size);
@ -446,12 +438,23 @@ int main(int argc, char** argv)
else {
wc_ForceZero(key, size);
XFREE(key, NULL, DYNAMIC_TYPE_TMP_BUFFER);
fclose(inFile);
if (outFile != NULL)
fclose(outFile);
}
}
}
else if (choice == 'n') {
XPRINTF("Must select either -e[128,192,256] or -d[128,192,256] for \
else {
if (choice == 'n') {
XPRINTF("Must select either -e[128,192,256] or -d[128,192,256] for \
encryption and decryption\n");
}
if (inFile != NULL) {
fclose(inFile);
}
if (outFile != NULL) {
fclose(outFile);
}
}
return ret;

View File

@ -32,6 +32,9 @@
#include <wolfssl/options.h>
#include <wolfssl/ssl.h>
#include <wolfssl/error-ssl.h>
#include <wolfssl/wolfcrypt/random.h>
#include <wolfssl/wolfcrypt/pwdbased.h>
#include <wolfssl/wolfcrypt/memory.h>
#include <stdio.h>
#include <stdlib.h>
@ -61,7 +64,8 @@
/* Epoch for the multicast session */
#define MCAST_EPOCH 1
#if defined(WOLFSSL_DTLS) && defined(WOLFSSL_MULTICAST)
#if defined(WOLFSSL_DTLS) && defined(WOLFSSL_MULTICAST) && \
defined(HAVE_PBKDF2) && !defined(NO_PWDBASED)
/* Global flag for clean shutdown */
static volatile sig_atomic_t running = 1;
@ -230,14 +234,83 @@ int main(int argc, char** argv)
#endif
/* Initialize the pre-shared secrets (same for all peers) */
memset(pms, 0x23, sizeof(pms));
memset(clientRandom, 0xA5, sizeof(clientRandom));
memset(serverRandom, 0x5A, sizeof(serverRandom));
{
const char* envSecret = getenv("DTLS_MCAST_SECRET");
char genSecret[2 * PMS_SIZE + 1];
const char* secret;
size_t len;
if (envSecret != NULL) {
secret = envSecret;
}
else {
byte secretBytes[PMS_SIZE];
WC_RNG rng;
printf("WARNING: DTLS_MCAST_SECRET not set. Generating a random "
"multicast secret for this run.\n"
" Export the printed value as DTLS_MCAST_SECRET "
"on ALL peers so they can share the same secret.\n");
ret = wc_InitRng(&rng);
if (ret != 0) {
fprintf(stderr, "Error: wc_InitRng failed: %d\n", ret);
return 1;
}
ret = wc_RNG_GenerateBlock(&rng, secretBytes, sizeof(secretBytes));
wc_FreeRng(&rng);
if (ret != 0) {
fprintf(stderr, "Error: Failed to generate random multicast "
"secret: %d\n", ret);
wc_ForceZero(secretBytes, sizeof(secretBytes));
return 1;
}
for (i = 0; i < (int)sizeof(secretBytes); i++)
snprintf(&genSecret[i * 2], 3, "%02x", secretBytes[i]);
wc_ForceZero(secretBytes, sizeof(secretBytes));
printf("Generated multicast secret (hex): %s\n"
"Export this value as DTLS_MCAST_SECRET on ALL peers.\n",
genSecret);
secret = genSecret;
}
len = strlen(secret);
/* PBKDF2 guards against a weak DTLS_MCAST_SECRET; distinct salts
* keep pms/clientRandom/serverRandom independent yet peer-shared. */
ret = wc_PBKDF2(pms, (byte*)secret, (int)len,
(byte*)"mcast-pms", 9, 4096, sizeof(pms), WC_SHA256);
if (ret == 0)
ret = wc_PBKDF2(clientRandom, (byte*)secret, (int)len,
(byte*)"mcast-client-random", 19, 4096,
sizeof(clientRandom), WC_SHA256);
if (ret == 0)
ret = wc_PBKDF2(serverRandom, (byte*)secret, (int)len,
(byte*)"mcast-server-random", 19, 4096,
sizeof(serverRandom), WC_SHA256);
wc_ForceZero(genSecret, sizeof(genSecret));
if (ret != 0) {
fprintf(stderr, "Error: Failed to derive multicast secret: %d\n",
ret);
wc_ForceZero(pms, sizeof(pms));
wc_ForceZero(clientRandom, sizeof(clientRandom));
wc_ForceZero(serverRandom, sizeof(serverRandom));
return 1;
}
}
/* Initialize wolfSSL */
ret = wolfSSL_Init();
if (ret != WOLFSSL_SUCCESS) {
fprintf(stderr, "Error: wolfSSL_Init failed: %d\n", ret);
wc_ForceZero(pms, sizeof(pms));
wc_ForceZero(clientRandom, sizeof(clientRandom));
wc_ForceZero(serverRandom, sizeof(serverRandom));
return 1;
}
@ -423,6 +496,9 @@ int main(int argc, char** argv)
printf("\nNode %d: Shutting down...\n", myId);
cleanup:
wc_ForceZero(pms, sizeof(pms));
wc_ForceZero(clientRandom, sizeof(clientRandom));
wc_ForceZero(serverRandom, sizeof(serverRandom));
if (sslTx != NULL) {
wolfSSL_free(sslTx);
}
@ -451,7 +527,8 @@ cleanup:
#else
int main()
{
fprintf(stderr, "Please configure the wolfssl library with --enable-dtls --enable-mcast.\n");
fprintf(stderr, "Please configure the wolfssl library with "
"--enable-dtls --enable-mcast --enable-pwdbased.\n");
return EXIT_FAILURE;
}
#endif /* WOLFSSL_DTLS && WOLFSSL_MULTICAST */
#endif /* WOLFSSL_DTLS && WOLFSSL_MULTICAST && HAVE_PBKDF2 && !NO_PWDBASED */

View File

@ -208,8 +208,10 @@ int main(int argc, char** argv)
ret = 0; /* Success */
cleanup:
wolfSSL_shutdown(ssl);
if (ssl) wolfSSL_free(ssl);
if (ssl) {
wolfSSL_shutdown(ssl);
wolfSSL_free(ssl);
}
if (session) wolfSSL_SESSION_free(session);
if (ctx) wolfSSL_CTX_free(ctx);
if (sockfd >= 0) close(sockfd);

View File

@ -33,6 +33,8 @@
#include <wolfssl/wolfcrypt/memory.h>
#include <wolfssl/wolfcrypt/aes.h>
#include <wolfssl/wolfcrypt/random.h>
#include <wolfssl/wolfcrypt/pwdbased.h>
#include <wolfssl/wolfcrypt/sha256.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -48,23 +50,52 @@
#define DEFAULT_CLIENT_SESSION_FILE "dtls_client_session.bin"
#define DEFAULT_SERVER_SESSION_FILE "dtls_server_session.bin"
/* AES-256-CBC key (32 bytes) - In production, use a securely generated key.*/
static const unsigned char AES_KEY[32] = {
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10,
0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20
};
/* Passphrase source for session-file encryption; falls back to a demo
* value if unset. Set this for anything beyond local demos. */
#define SESSION_PASSPHRASE_ENV "DTLS_SESSION_PASSPHRASE"
#define DEMO_SESSION_PASSPHRASE "dtls-example-demo-passphrase-change-me"
/* AES block size */
#define AES_BLOCK_SZ 16
/* AES block size / PBKDF2 salt size / AES-256 key size */
#define GCM_IV_SZ 12
#define GCM_TAG_SZ 16
#define SESSION_SALT_SZ 16
#define SESSION_KEY_SZ 32
#define SESSION_PBKDF2_ITERATIONS 100000
/* File format:
* [4 bytes: original data length]
* [16 bytes: IV]
* [N bytes: encrypted data (padded to AES_BLOCK_SZ)]
* [16 bytes: PBKDF2 salt]
* [12 bytes: IV]
* [16 bytes: auth tag]
* [N bytes: encrypted data]
*/
static const char* GetSessionPassphrase(void)
{
const char* passphrase = getenv(SESSION_PASSPHRASE_ENV);
if (passphrase == NULL || passphrase[0] == '\0') {
XFPRINTF(stderr,
"Warning: %s not set, using demo passphrase. "
"Set %s to a real secret for anything beyond local demos.\n",
SESSION_PASSPHRASE_ENV, SESSION_PASSPHRASE_ENV);
passphrase = DEMO_SESSION_PASSPHRASE;
}
return passphrase;
}
/*
* Derive an AES-256 key from a passphrase and salt using PBKDF2-HMAC-SHA256.
* Returns 0 on success, negative on error.
*/
static int DeriveSessionKey(const char* passphrase,
const unsigned char* salt, unsigned int saltSz,
unsigned char* key, unsigned int keySz)
{
return wc_PBKDF2(key, (const byte*)passphrase, (int)strlen(passphrase),
salt, (int)saltSz, SESSION_PBKDF2_ITERATIONS,
(int)keySz, WC_SHA256);
}
/*
* Encrypt session data and save to file
* Returns 0 on success, negative on error
@ -76,20 +107,17 @@ int SaveEncryptedSession(const char* filename,
FILE* fp = NULL;
Aes aes;
WC_RNG rng;
unsigned char iv[AES_BLOCK_SZ];
unsigned char* paddedData = NULL;
unsigned char iv[GCM_IV_SZ];
unsigned char tag[GCM_TAG_SZ];
unsigned char salt[SESSION_SALT_SZ];
unsigned char key[SESSION_KEY_SZ];
unsigned char* encryptedData = NULL;
unsigned int paddedSz;
unsigned int padding;
unsigned char sizeBuf[4];
int ret = 0;
int aesInit = 0;
int rngInit = 0;
/* Calculate padded size (must be multiple of AES_BLOCK_SZ) */
padding = AES_BLOCK_SZ - (sessionSz % AES_BLOCK_SZ);
paddedSz = sessionSz + padding;
/* Initialize RNG for IV generation */
/* Initialize RNG for IV/salt generation */
ret = wc_InitRng(&rng);
if (ret != 0) {
XPRINTF("Error: wc_InitRng failed: %d\n", ret);
@ -98,25 +126,34 @@ int SaveEncryptedSession(const char* filename,
rngInit = 1;
/* Generate random IV */
ret = wc_RNG_GenerateBlock(&rng, iv, AES_BLOCK_SZ);
ret = wc_RNG_GenerateBlock(&rng, iv, GCM_IV_SZ);
if (ret != 0) {
XPRINTF("Error: Failed to generate IV: %d\n", ret);
goto cleanup;
}
/* Allocate buffers */
paddedData = (unsigned char*)XMALLOC(paddedSz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
encryptedData = (unsigned char*)XMALLOC(paddedSz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (paddedData == NULL || encryptedData == NULL) {
/* Derive AES key from passphrase */
ret = wc_RNG_GenerateBlock(&rng, salt, SESSION_SALT_SZ);
if (ret != 0) {
XPRINTF("Error: Failed to generate salt: %d\n", ret);
goto cleanup;
}
ret = DeriveSessionKey(GetSessionPassphrase(), salt, SESSION_SALT_SZ,
key, SESSION_KEY_SZ);
if (ret != 0) {
XPRINTF("Error: Failed to derive session key: %d\n", ret);
goto cleanup;
}
/* Allocate buffer for encrypted data */
encryptedData = (unsigned char*)XMALLOC(sessionSz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (encryptedData == NULL && sessionSz > 0) {
XPRINTF("Error: Memory allocation failed\n");
ret = -1;
goto cleanup;
}
/* Copy data and add PKCS#7 padding */
memcpy(paddedData, sessionData, sessionSz);
memset(paddedData + sessionSz, (int)padding, padding);
/* Initialize AES */
ret = wc_AesInit(&aes, NULL, INVALID_DEVID);
if (ret != 0) {
@ -125,17 +162,24 @@ int SaveEncryptedSession(const char* filename,
}
aesInit = 1;
/* Set AES key for encryption */
ret = wc_AesSetKey(&aes, AES_KEY, sizeof(AES_KEY), iv, AES_ENCRYPTION);
/* Set AES key for GCM */
ret = wc_AesGcmSetKey(&aes, key, sizeof(key));
if (ret != 0) {
XPRINTF("Error: wc_AesSetKey failed: %d\n", ret);
XPRINTF("Error: wc_AesGcmSetKey failed: %d\n", ret);
goto cleanup;
}
/* Encrypt the data */
ret = wc_AesCbcEncrypt(&aes, encryptedData, paddedData, paddedSz);
/* Prepare AAD: original data length (4 bytes) */
sizeBuf[0] = (sessionSz >> 24) & 0xFF;
sizeBuf[1] = (sessionSz >> 16) & 0xFF;
sizeBuf[2] = (sessionSz >> 8) & 0xFF;
sizeBuf[3] = sessionSz & 0xFF;
/* Encrypt the data with GCM */
ret = wc_AesGcmEncrypt(&aes, encryptedData, sessionData, sessionSz,
iv, GCM_IV_SZ, tag, GCM_TAG_SZ, sizeBuf, 4);
if (ret != 0) {
XPRINTF("Error: wc_AesCbcEncrypt failed: %d\n", ret);
XPRINTF("Error: wc_AesGcmEncrypt failed: %d\n", ret);
goto cleanup;
}
@ -147,49 +191,53 @@ int SaveEncryptedSession(const char* filename,
goto cleanup;
}
/* Write original size (4 bytes, big-endian) */
{
unsigned char sizeBuf[4];
sizeBuf[0] = (sessionSz >> 24) & 0xFF;
sizeBuf[1] = (sessionSz >> 16) & 0xFF;
sizeBuf[2] = (sessionSz >> 8) & 0xFF;
sizeBuf[3] = sessionSz & 0xFF;
if (fwrite(sizeBuf, 1, 4, fp) != 4) {
XPRINTF("Error: Failed to write size to file\n");
ret = -1;
goto cleanup;
}
/* Write size */
if (fwrite(sizeBuf, 1, 4, fp) != 4) {
XPRINTF("Error: Failed to write size to file\n");
ret = -1;
goto cleanup;
}
/* Write salt */
if (fwrite(salt, 1, SESSION_SALT_SZ, fp) != SESSION_SALT_SZ) {
XPRINTF("Error: Failed to write salt to file\n");
ret = -1;
goto cleanup;
}
/* Write IV */
if (fwrite(iv, 1, AES_BLOCK_SZ, fp) != AES_BLOCK_SZ) {
if (fwrite(iv, 1, GCM_IV_SZ, fp) != GCM_IV_SZ) {
XPRINTF("Error: Failed to write IV to file\n");
ret = -1;
goto cleanup;
}
/* Write tag */
if (fwrite(tag, 1, GCM_TAG_SZ, fp) != GCM_TAG_SZ) {
XPRINTF("Error: Failed to write tag to file\n");
ret = -1;
goto cleanup;
}
/* Write encrypted data */
if (fwrite(encryptedData, 1, paddedSz, fp) != paddedSz) {
if (sessionSz > 0 && fwrite(encryptedData, 1, sessionSz, fp) != sessionSz) {
XPRINTF("Error: Failed to write encrypted data to file\n");
ret = -1;
goto cleanup;
}
XPRINTF("Session saved to %s (%u bytes encrypted)\n", filename, paddedSz);
XPRINTF("Session saved to %s (%u bytes encrypted)\n", filename, sessionSz);
ret = 0;
cleanup:
if (fp != NULL) fclose(fp);
if (paddedData != NULL) {
wc_ForceZero(paddedData, paddedSz);
XFREE(paddedData, NULL, DYNAMIC_TYPE_TMP_BUFFER);
}
if (encryptedData != NULL) {
wc_ForceZero(encryptedData, paddedSz);
wc_ForceZero(encryptedData, sessionSz);
XFREE(encryptedData, NULL, DYNAMIC_TYPE_TMP_BUFFER);
}
if (aesInit) wc_AesFree(&aes);
if (rngInit) wc_FreeRng(&rng);
wc_ForceZero(key, sizeof(key));
return ret;
}
@ -208,12 +256,14 @@ unsigned char* LoadEncryptedSession(const char* filename,
{
FILE* fp = NULL;
Aes aes;
unsigned char iv[AES_BLOCK_SZ];
unsigned char iv[GCM_IV_SZ];
unsigned char tag[GCM_TAG_SZ];
unsigned char salt[SESSION_SALT_SZ];
unsigned char key[SESSION_KEY_SZ];
unsigned char sizeBuf[4];
unsigned char* encryptedData = NULL;
unsigned char* decryptedData = NULL;
unsigned int originalSz;
unsigned int encryptedSz;
long fileSize;
int ret = 0;
int aesInit = 0;
@ -230,13 +280,13 @@ unsigned char* LoadEncryptedSession(const char* filename,
fileSize = ftell(fp);
fseek(fp, 0, SEEK_SET);
if (fileSize < (4 + AES_BLOCK_SZ + AES_BLOCK_SZ)) {
if (fileSize < (4 + SESSION_SALT_SZ + GCM_IV_SZ + GCM_TAG_SZ)) {
XPRINTF("Error: File too small to contain valid session data\n");
fclose(fp);
return NULL;
}
/* Read original size */
/* Read size */
if (fread(sizeBuf, 1, 4, fp) != 4) {
XPRINTF("Error: Failed to read size from file\n");
fclose(fp);
@ -247,28 +297,59 @@ unsigned char* LoadEncryptedSession(const char* filename,
((unsigned int)sizeBuf[2] << 8) |
(unsigned int)sizeBuf[3];
/* Read IV */
if (fread(iv, 1, AES_BLOCK_SZ, fp) != AES_BLOCK_SZ) {
XPRINTF("Error: Failed to read IV from file\n");
/* Read salt */
if (fread(salt, 1, SESSION_SALT_SZ, fp) != SESSION_SALT_SZ) {
XPRINTF("Error: Failed to read salt from file\n");
fclose(fp);
return NULL;
}
/* Calculate encrypted data size */
encryptedSz = (unsigned int)(fileSize - 4 - AES_BLOCK_SZ);
/* Read IV */
if (fread(iv, 1, GCM_IV_SZ, fp) != GCM_IV_SZ) {
XPRINTF("Error: Failed to read IV from file\n");
fclose(fp);
return NULL;
}
/* Read tag */
if (fread(tag, 1, GCM_TAG_SZ, fp) != GCM_TAG_SZ) {
XPRINTF("Error: Failed to read tag from file\n");
fclose(fp);
return NULL;
}
/* Allocate buffers */
encryptedData = (unsigned char*)XMALLOC(encryptedSz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
decryptedData = (unsigned char*)XMALLOC(encryptedSz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
/* Derive AES key from passphrase */
ret = DeriveSessionKey(GetSessionPassphrase(), salt, SESSION_SALT_SZ,
key, SESSION_KEY_SZ);
if (ret != 0) {
XPRINTF("Error: Failed to derive session key: %d\n", ret);
goto cleanup;
}
if ((fileSize - 4 - SESSION_SALT_SZ - GCM_IV_SZ - GCM_TAG_SZ) !=
(long)originalSz) {
XPRINTF("Error: File size does not match expected encrypted data size\n");
goto cleanup;
}
/* Allocate buffers. Always allocate at least 1 byte so a legitimate
* zero-length session is returned as a non-NULL pointer, distinct
* from a NULL/failure return. */
encryptedData = (unsigned char*)XMALLOC(originalSz > 0 ? originalSz : 1,
NULL, DYNAMIC_TYPE_TMP_BUFFER);
decryptedData = (unsigned char*)XMALLOC(originalSz > 0 ? originalSz : 1,
NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (encryptedData == NULL || decryptedData == NULL) {
XPRINTF("Error: Memory allocation failed\n");
goto cleanup;
}
/* Read encrypted data */
if (fread(encryptedData, 1, encryptedSz, fp) != encryptedSz) {
XPRINTF("Error: Failed to read encrypted data from file\n");
goto cleanup;
if (originalSz > 0) {
/* Read encrypted data */
if (fread(encryptedData, 1, originalSz, fp) != originalSz) {
XPRINTF("Error: Failed to read encrypted data from file\n");
goto cleanup;
}
}
fclose(fp);
fp = NULL;
@ -281,52 +362,49 @@ unsigned char* LoadEncryptedSession(const char* filename,
}
aesInit = 1;
/* Set AES key for decryption */
ret = wc_AesSetKey(&aes, AES_KEY, sizeof(AES_KEY), iv, AES_DECRYPTION);
/* Set AES key */
ret = wc_AesGcmSetKey(&aes, key, sizeof(key));
if (ret != 0) {
XPRINTF("Error: wc_AesSetKey failed: %d\n", ret);
XPRINTF("Error: wc_AesGcmSetKey failed: %d\n", ret);
goto cleanup;
}
/* Decrypt the data */
ret = wc_AesCbcDecrypt(&aes, decryptedData, encryptedData, encryptedSz);
/* Decrypt and authenticate the data */
ret = wc_AesGcmDecrypt(&aes, decryptedData, encryptedData, originalSz,
iv, GCM_IV_SZ, tag, GCM_TAG_SZ, sizeBuf, 4);
if (ret != 0) {
XPRINTF("Error: wc_AesCbcDecrypt failed: %d\n", ret);
goto cleanup;
}
/* Verify padding and original size */
if (originalSz > encryptedSz) {
XPRINTF("Error: Invalid original size in file\n");
XPRINTF("Error: wc_AesGcmDecrypt failed (authentication error): %d\n", ret);
goto cleanup;
}
*sessionSz = originalSz;
if (bufSz != NULL) {
*bufSz = encryptedSz;
*bufSz = originalSz > 0 ? originalSz : 1;
}
XPRINTF("Session loaded from %s (%u bytes)\n", filename, originalSz);
/* Clean up and return decrypted data */
if (encryptedData != NULL) {
wc_ForceZero(encryptedData, encryptedSz);
wc_ForceZero(encryptedData, originalSz);
XFREE(encryptedData, NULL, DYNAMIC_TYPE_TMP_BUFFER);
}
if (aesInit) wc_AesFree(&aes);
wc_ForceZero(key, sizeof(key));
return decryptedData;
cleanup:
if (fp != NULL) fclose(fp);
if (encryptedData != NULL) {
wc_ForceZero(encryptedData, encryptedSz);
wc_ForceZero(encryptedData, originalSz);
XFREE(encryptedData, NULL, DYNAMIC_TYPE_TMP_BUFFER);
}
if (decryptedData != NULL) {
wc_ForceZero(decryptedData, encryptedSz);
wc_ForceZero(decryptedData, originalSz);
XFREE(decryptedData, NULL, DYNAMIC_TYPE_TMP_BUFFER);
}
if (aesInit) wc_AesFree(&aes);
wc_ForceZero(key, sizeof(key));
return NULL;
}

View File

@ -413,13 +413,26 @@ WOLFSSL_CTX* newCTX(void)
return ctx;
}
/* Stateless cookie secret, generated once per run. Must stay stable across
* newSSL() calls so in-flight cookie retries from other clients still
* validate. Applications should rotate it periodically (e.g. on a timer),
* not on every call. */
static byte cookieSecret[32];
static int cookieSecretSet = 0;
WOLFSSL* newSSL(WOLFSSL_CTX* ctx, int fd, WC_RNG* rng, struct ConnList* connList)
{
WOLFSSL* ssl = NULL;
/* Applications should update this secret periodically */
char *secret = "My secret";
byte newCid[CID_SIZE];
if (!cookieSecretSet) {
if (wc_RNG_GenerateBlock(rng, cookieSecret, sizeof(cookieSecret)) != 0) {
fprintf(stderr, "wc_RNG_GenerateBlock error.\n");
return NULL;
}
cookieSecretSet = 1;
}
/* Create the WOLFSSL Object */
if ((ssl = wolfSSL_new(ctx)) == NULL) {
fprintf(stderr, "wolfSSL_new error.\n");
@ -427,13 +440,13 @@ WOLFSSL* newSSL(WOLFSSL_CTX* ctx, int fd, WC_RNG* rng, struct ConnList* connList
}
/* Set the secret for cookie creation */
#if defined(WOLFSSL_SEND_HRR_COOKIE)
if (wolfSSL_send_hrr_cookie(ssl, (byte*)secret, strlen(secret)) != WOLFSSL_SUCCESS) {
if (wolfSSL_send_hrr_cookie(ssl, cookieSecret, sizeof(cookieSecret)) != WOLFSSL_SUCCESS) {
fprintf(stderr, "wolfSSL_send_hrr_cookie error.\n");
wolfSSL_free(ssl);
return NULL;
}
#endif
if (wolfSSL_DTLS_SetCookieSecret(ssl, (byte*)secret, strlen(secret)) != 0) {
if (wolfSSL_DTLS_SetCookieSecret(ssl, cookieSecret, sizeof(cookieSecret)) != 0) {
fprintf(stderr, "wolfSSL_DTLS_SetCookieSecret error.\n");
wolfSSL_free(ssl);
return NULL;

View File

@ -44,6 +44,7 @@
#include <arpa/inet.h>
#include <wolfssl/ssl.h>
#include <wolfssl/error-ssl.h>
#include <wolfssl/wolfcrypt/random.h>
#include <errno.h>
#include <signal.h>
#include <unistd.h>
@ -217,6 +218,15 @@ cleanup:
return INVALID_SOCKET;
}
/* Stateless HRR cookie secret, generated once per run. Must stay stable
* across newPendingSSL() calls so in-flight cookie retries from other
* clients still validate. Applications should rotate it periodically
* (e.g. on a timer), not on every call. */
#if !defined(USE_DTLS12) && defined(WOLFSSL_SEND_HRR_COOKIE)
static byte cookieSecret[32];
static int cookieSecretSet = 0;
#endif
static int newPendingSSL(void)
{
WOLFSSL* ssl;
@ -248,15 +258,28 @@ static int newPendingSSL(void)
}
#if !defined(USE_DTLS12) && defined(WOLFSSL_SEND_HRR_COOKIE)
{
/* Applications should update this secret periodically */
char *secret = "My secret";
if (wolfSSL_send_hrr_cookie(ssl, (byte*)secret, strlen(secret))
!= WOLFSSL_SUCCESS) {
fprintf(stderr, "wolfSSL_send_hrr_cookie error.\n");
if (!cookieSecretSet) {
WC_RNG rng;
int rngRet;
rngRet = wc_InitRng(&rng);
if (rngRet == 0) {
rngRet = wc_RNG_GenerateBlock(&rng, cookieSecret, sizeof(cookieSecret));
wc_FreeRng(&rng);
}
if (rngRet != 0) {
fprintf(stderr, "Failed to generate cookie secret: %d\n", rngRet);
wolfSSL_free(ssl);
return 0;
}
cookieSecretSet = 1;
}
if (wolfSSL_send_hrr_cookie(ssl, cookieSecret, sizeof(cookieSecret))
!= WOLFSSL_SUCCESS) {
fprintf(stderr, "wolfSSL_send_hrr_cookie error.\n");
wolfSSL_free(ssl);
return 0;
}
#endif

View File

@ -32,6 +32,29 @@
#define DEF_KA_CHECKS 512
#define DEF_PARAMS_GEN 8
/* Constant-time buffer compare for secret material.
*
* wolfSSL's own constant-time compare (ConstantCompare() in
* wolfcrypt/src/misc.c) is WOLFSSL_LOCAL and not exported, so it can't be
* called from application code. Every byte is compared regardless of where
* a mismatch occurs, so the runtime doesn't leak position information via
* early-exit timing.
*
* Returns 0 if the buffers are equal, non-zero otherwise. */
static int const_time_memcmp(const void* a, const void* b, size_t len)
{
const unsigned char* pa = (const unsigned char*)a;
const unsigned char* pb = (const unsigned char*)b;
unsigned char diff = 0;
size_t i;
for (i = 0; i < len; i++) {
diff |= (unsigned char)(pa[i] ^ pb[i]);
}
return (int)diff;
}
int load_dh_params(DhKey* key1, DhKey* key2, WC_RNG* rng)
{
int ret;
@ -412,8 +435,8 @@ int main(int argc, char *argv[])
}
/* Secret's should be the same */
if ((secret1_len != secret2_len) || (XMEMCMP(secret1, secret2,
secret1_len) != 0)) {
if ((secret1_len != secret2_len) || (const_time_memcmp(secret1,
secret2, secret1_len) != 0)) {
fprintf(stderr, "Secrets different\n");
print_dh(&key1);
ec = 1;

View File

@ -37,6 +37,32 @@ int do_ecc(void);
int do_25519(void);
int do_448(void);
/* Constant-time buffer compare for secret material.
*
* wolfSSL's own constant-time compare (ConstantCompare() in
* wolfcrypt/src/misc.c) is WOLFSSL_LOCAL and not exported, so it can't be
* called from application code. This is the pattern to use instead of
* XMEMCMP/memcmp whenever comparing secrets, MACs, or derived key material:
* every byte is compared regardless of where a mismatch occurs, so the
* runtime doesn't leak position information via early-exit timing.
*
* Returns 0 if the buffers are equal, non-zero otherwise. */
#if defined(HAVE_ECC) || defined(HAVE_CURVE25519) || defined(HAVE_CURVE448)
static int const_time_memcmp(const void* a, const void* b, size_t len)
{
const byte* pa = (const byte*)a;
const byte* pb = (const byte*)b;
byte diff = 0;
size_t i;
for (i = 0; i < len; i++) {
diff |= (byte)(pa[i] ^ pb[i]);
}
return (int)diff;
}
#endif /* HAVE_ECC || HAVE_CURVE25519 || HAVE_CURVE448 */
int main(int argc, char** argv)
{
int curveChoice = 0;
@ -111,7 +137,9 @@ int do_ecc(void)
wc_ecc_set_rng(&BobKey, &rng);
ret = wc_ecc_shared_secret(&BobKey, &AliceKey, BobSecret, &secretLen);
if (ret == 0) {
if (XMEMCMP(AliceSecret, BobSecret, secretLen))
/* Use a constant-time compare (not XMEMCMP) since these buffers
* hold secret key material. See const_time_memcmp() above. */
if (const_time_memcmp(AliceSecret, BobSecret, secretLen))
printf("Failed to generate a common secret\n");
} else {
goto all_three;
@ -172,7 +200,9 @@ int do_25519(void)
secretLen = ECC_256_BIT_FIELD; /* explicit reset for best practice */
ret = wc_curve25519_shared_secret(&BobKey, &AliceKey, BobSecret, &secretLen);
if (ret == 0) {
if (XMEMCMP(AliceSecret, BobSecret, secretLen))
/* Use a constant-time compare (not XMEMCMP) since these buffers
* hold secret key material. See const_time_memcmp() above. */
if (const_time_memcmp(AliceSecret, BobSecret, secretLen))
printf("Failed to generate a common secret\n");
} else {
goto all_three;
@ -233,7 +263,9 @@ int do_448(void)
secretLen = ECC_448_BIT_FIELD; /* explicit reset for best practice */
ret = wc_curve448_shared_secret(&BobKey, &AliceKey, BobSecret, &secretLen);
if (ret == 0) {
if (XMEMCMP(AliceSecret, BobSecret, secretLen))
/* Use a constant-time compare (not XMEMCMP) since these buffers
* hold secret key material. See const_time_memcmp() above. */
if (const_time_memcmp(AliceSecret, BobSecret, secretLen))
printf("Failed to generate a common secret\n");
} else {
goto all_three;
@ -285,7 +317,10 @@ void Usage(int* curveChoice)
if (answer == 'y') {
printf("\nEnter an option from the above curve list > ");
scanf("%s", input);
if (scanf("%9s", input) != 1) {
printf("Invalid input\n");
exit(-1);
}
printf("You entered: %s\n", input);
sscanf(input, "%d", curveChoice);
if (*curveChoice != 1 && *curveChoice != 2) {

View File

@ -98,7 +98,7 @@ static int load_file(const char* fname, byte** buf, size_t* bufLen)
rewind(lFile);
if (fileSz > 0) {
*bufLen = (size_t)fileSz;
*buf = (byte*)malloc(*bufLen);
*buf = (byte*)XMALLOC(*bufLen, NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (*buf == NULL) {
ret = MEMORY_E;
printf("Error allocating %lu bytes\n", (unsigned long)*bufLen);
@ -128,20 +128,24 @@ static int load_key_file(const char* fname, byte** derBuf, word32* derLen)
if (ret != 0)
return ret;
*derBuf = (byte*)malloc(bufLen);
*derBuf = (byte*)XMALLOC(bufLen, NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (*derBuf == NULL) {
free(buf);
wc_ForceZero(buf, bufLen);
XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
return MEMORY_E;
}
ret = wc_KeyPemToDer(buf, (word32)bufLen, *derBuf, (word32)bufLen, NULL);
if (ret < 0) {
free(buf);
free(*derBuf);
wc_ForceZero(buf, bufLen);
XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
wc_ForceZero(*derBuf, bufLen);
XFREE(*derBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
return ret;
}
*derLen = ret;
free(buf);
wc_ForceZero(buf, bufLen);
XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
return 0;
}
@ -168,22 +172,28 @@ static int myEccSign(WOLFSSL* ssl, const byte* in, word32 inSz,
#endif
ret = load_key_file(cbInfo->keyFile, &keyBuf, &keySz);
if (ret == 0) {
ret = wc_ecc_init(&cbInfo->keyEcc);
if (ret == 0) {
word32 idx = 0;
ret = wc_EccPrivateKeyDecode(keyBuf, &idx, &cbInfo->keyEcc, keySz);
if (ret == 0) {
WC_RNG *rng = wolfSSL_GetRNG(ssl);
printf("PK ECC Sign: Curve ID %d\n", cbInfo->keyEcc.dp->id);
ret = wc_ecc_sign_hash(in, inSz, out, outSz, rng,
&cbInfo->keyEcc);
}
wc_ecc_free(&cbInfo->keyEcc);
}
if (ret != 0) {
#ifdef WOLFSSL_ASYNC_CRYPT
cbInfo->state = 0;
#endif
return ret;
}
free(keyBuf);
ret = wc_ecc_init(&cbInfo->keyEcc);
if (ret == 0) {
word32 idx = 0;
ret = wc_EccPrivateKeyDecode(keyBuf, &idx, &cbInfo->keyEcc, keySz);
if (ret == 0) {
WC_RNG *rng = wolfSSL_GetRNG(ssl);
printf("PK ECC Sign: Curve ID %d\n", cbInfo->keyEcc.dp->id);
ret = wc_ecc_sign_hash(in, inSz, out, outSz, rng,
&cbInfo->keyEcc);
}
wc_ecc_free(&cbInfo->keyEcc);
}
wc_ForceZero(keyBuf, keySz);
XFREE(keyBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
#ifdef WOLFSSL_ASYNC_CRYPT
cbInfo->state = 0;
@ -218,8 +228,12 @@ static int myRsaSign(WOLFSSL* ssl, const byte* in, word32 inSz,
#endif
ret = load_key_file(cbInfo->keyFile, &keyBuf, &keySz);
if (ret != 0)
if (ret != 0) {
#ifdef WOLFSSL_ASYNC_CRYPT
cbInfo->state = 0;
#endif
return ret;
}
ret = wc_InitRsaKey(&cbInfo->keyRsa, NULL);
if (ret == 0) {
@ -234,7 +248,8 @@ static int myRsaSign(WOLFSSL* ssl, const byte* in, word32 inSz,
}
wc_FreeRsaKey(&cbInfo->keyRsa);
}
free(keyBuf);
wc_ForceZero(keyBuf, keySz);
XFREE(keyBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
#ifdef WOLFSSL_ASYNC_CRYPT
cbInfo->state = 0;
#endif
@ -300,7 +315,8 @@ static int myRsaPssSign(WOLFSSL* ssl, const byte* in, word32 inSz,
}
wc_FreeRsaKey(&cbInfo->keyRsa);
}
free(keyBuf);
wc_ForceZero(keyBuf, keySz);
XFREE(keyBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
printf("PK RSA PSS Sign: ret %d, outSz %u\n", ret, *outSz);
@ -325,7 +341,7 @@ int main(int argc, char** argv)
/* PK callback context */
PkCbInfo myCtx;
memset(&myCtx, 0, sizeof(myCtx));
XMEMSET(&myCtx, 0, sizeof(myCtx));
myCtx.keyFile = KEY_FILE;
/* Check for proper calling convention */
@ -351,7 +367,7 @@ int main(int argc, char** argv)
}
/* Initialize the server address struct with zeros */
memset(&servAddr, 0, sizeof(servAddr));
XMEMSET(&servAddr, 0, sizeof(servAddr));
/* Fill in the server address */
servAddr.sin_family = AF_INET; /* using IPv4 */
@ -477,7 +493,7 @@ int main(int argc, char** argv)
/* Get a message for the server from stdin */
printf("Message for server: ");
memset(buff, 0, sizeof(buff));
XMEMSET(buff, 0, sizeof(buff));
if (fgets(buff, sizeof(buff), stdin) == NULL) {
fprintf(stderr, "ERROR: failed to get message for server\n");
ret = -1;
@ -493,7 +509,7 @@ int main(int argc, char** argv)
}
/* Read the server data into our buff array */
memset(buff, 0, sizeof(buff));
XMEMSET(buff, 0, sizeof(buff));
if ((ret = wolfSSL_read(ssl, buff, sizeof(buff)-1)) == -1) {
fprintf(stderr, "ERROR: failed to read\n");
goto exit;

View File

@ -98,7 +98,7 @@ static int load_file(const char* fname, byte** buf, size_t* bufLen)
rewind(lFile);
if (fileSz > 0) {
*bufLen = (size_t)fileSz;
*buf = (byte*)malloc(*bufLen);
*buf = (byte*)XMALLOC(*bufLen, NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (*buf == NULL) {
ret = MEMORY_E;
printf("Error allocating %lu bytes\n", (unsigned long)*bufLen);
@ -128,20 +128,24 @@ static int load_key_file(const char* fname, byte** derBuf, word32* derLen)
if (ret != 0)
return ret;
*derBuf = (byte*)malloc(bufLen);
*derBuf = (byte*)XMALLOC(bufLen, NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (*derBuf == NULL) {
free(buf);
wc_ForceZero(buf, bufLen);
XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
return MEMORY_E;
}
ret = wc_KeyPemToDer(buf, (word32)bufLen, *derBuf, (word32)bufLen, NULL);
if (ret < 0) {
free(buf);
free(*derBuf);
wc_ForceZero(buf, bufLen);
XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
wc_ForceZero(*derBuf, bufLen);
XFREE(*derBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
return ret;
}
*derLen = ret;
free(buf);
wc_ForceZero(buf, bufLen);
XFREE(buf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
return 0;
}
@ -168,22 +172,28 @@ static int myEccSign(WOLFSSL* ssl, const byte* in, word32 inSz,
#endif
ret = load_key_file(cbInfo->keyFile, &keyBuf, &keySz);
if (ret == 0) {
ret = wc_ecc_init(&cbInfo->keyEcc);
if (ret == 0) {
word32 idx = 0;
ret = wc_EccPrivateKeyDecode(keyBuf, &idx, &cbInfo->keyEcc, keySz);
if (ret == 0) {
WC_RNG *rng = wolfSSL_GetRNG(ssl);
printf("PK ECC Sign: Curve ID %d\n", cbInfo->keyEcc.dp->id);
ret = wc_ecc_sign_hash(in, inSz, out, outSz, rng,
&cbInfo->keyEcc);
}
wc_ecc_free(&cbInfo->keyEcc);
}
if (ret != 0) {
#ifdef WOLFSSL_ASYNC_CRYPT
cbInfo->state = 0;
#endif
return ret;
}
free(keyBuf);
ret = wc_ecc_init(&cbInfo->keyEcc);
if (ret == 0) {
word32 idx = 0;
ret = wc_EccPrivateKeyDecode(keyBuf, &idx, &cbInfo->keyEcc, keySz);
if (ret == 0) {
WC_RNG *rng = wolfSSL_GetRNG(ssl);
printf("PK ECC Sign: Curve ID %d\n", cbInfo->keyEcc.dp->id);
ret = wc_ecc_sign_hash(in, inSz, out, outSz, rng,
&cbInfo->keyEcc);
}
wc_ecc_free(&cbInfo->keyEcc);
}
wc_ForceZero(keyBuf, keySz);
XFREE(keyBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
#ifdef WOLFSSL_ASYNC_CRYPT
cbInfo->state = 0;
#endif
@ -217,8 +227,12 @@ static int myRsaSign(WOLFSSL* ssl, const byte* in, word32 inSz,
#endif
ret = load_key_file(cbInfo->keyFile, &keyBuf, &keySz);
if (ret != 0)
if (ret != 0) {
#ifdef WOLFSSL_ASYNC_CRYPT
cbInfo->state = 0;
#endif
return ret;
}
ret = wc_InitRsaKey(&cbInfo->keyRsa, NULL);
if (ret == 0) {
@ -233,7 +247,8 @@ static int myRsaSign(WOLFSSL* ssl, const byte* in, word32 inSz,
}
wc_FreeRsaKey(&cbInfo->keyRsa);
}
free(keyBuf);
wc_ForceZero(keyBuf, keySz);
XFREE(keyBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
#ifdef WOLFSSL_ASYNC_CRYPT
cbInfo->state = 0;
#endif
@ -299,7 +314,8 @@ static int myRsaPssSign(WOLFSSL* ssl, const byte* in, word32 inSz,
}
wc_FreeRsaKey(&cbInfo->keyRsa);
}
free(keyBuf);
wc_ForceZero(keyBuf, keySz);
XFREE(keyBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
printf("PK RSA PSS Sign: ret %d, outSz %u\n", ret, *outSz);
@ -326,7 +342,7 @@ int main(int argc, char** argv)
/* PK callback context */
PkCbInfo myCtx;
memset(&myCtx, 0, sizeof(myCtx));
XMEMSET(&myCtx, 0, sizeof(myCtx));
myCtx.keyFile = KEY_FILE;
/* declare wolfSSL objects */
@ -341,7 +357,7 @@ int main(int argc, char** argv)
#endif
/* Initialize the server address struct with zeros */
memset(&servAddr, 0, sizeof(servAddr));
XMEMSET(&servAddr, 0, sizeof(servAddr));
/* Fill in the server address */
servAddr.sin_family = AF_INET; /* using IPv4 */
@ -497,7 +513,7 @@ int main(int argc, char** argv)
/* Read the client data into our buff array */
memset(buff, 0, sizeof(buff));
XMEMSET(buff, 0, sizeof(buff));
if ((ret = wolfSSL_read(ssl, buff, sizeof(buff)-1)) == -1) {
fprintf(stderr, "ERROR: failed to read\n");
goto exit;
@ -514,7 +530,7 @@ int main(int argc, char** argv)
/* Write our reply into buff */
memset(buff, 0, sizeof(buff));
XMEMSET(buff, 0, sizeof(buff));
memcpy(buff, reply, strlen(reply));
len = strnlen(buff, sizeof(buff));