diff --git a/src/crypto/clu_evp_crypto.c b/src/crypto/clu_evp_crypto.c index faa39b92..4b7c3443 100644 --- a/src/crypto/clu_evp_crypto.c +++ b/src/crypto/clu_evp_crypto.c @@ -88,31 +88,36 @@ int wolfCLU_evp_crypto(const WOLFSSL_EVP_CIPHER* cphr, char* mode, byte* pwdKey, in = wolfSSL_BIO_new_file(fileIn, "rb"); if (in != NULL && !enc && isBase64) { word32 decodeSz; + int bioSz; - decodeSz = wolfSSL_BIO_get_len(in); - decodedBase64 = (byte*)XMALLOC(decodeSz, HEAP_HINT, - DYNAMIC_TYPE_TMP_BUFFER); - if (decodedBase64 == NULL) { + if ((bioSz = wolfSSL_BIO_get_len(in)) <= 0) { ret = WOLFCLU_FATAL_ERROR; } else { - if (wolfSSL_BIO_read(in, decodedBase64, decodeSz) != - (int)decodeSz) { + decodeSz = (word32)bioSz; + decodedBase64 = (byte*)XMALLOC(bioSz, HEAP_HINT, + DYNAMIC_TYPE_TMP_BUFFER); + if (decodedBase64 == NULL) { ret = WOLFCLU_FATAL_ERROR; } + else { + if (wolfSSL_BIO_read(in, decodedBase64, bioSz) != + bioSz) { + ret = WOLFCLU_FATAL_ERROR; + } - if (ret == WOLFCLU_SUCCESS && - Base64_Decode(decodedBase64, decodeSz, - decodedBase64, &decodeSz) != 0) { - ret = WOLFCLU_FATAL_ERROR; - } + if (ret == WOLFCLU_SUCCESS && + Base64_Decode(decodedBase64, bioSz, + decodedBase64, &decodeSz) != 0) { + ret = WOLFCLU_FATAL_ERROR; + } - if (ret == WOLFCLU_SUCCESS) { - wolfSSL_BIO_free(in); - in = wolfSSL_BIO_new_mem_buf(decodedBase64, decodeSz); + if (ret == WOLFCLU_SUCCESS) { + wolfSSL_BIO_free(in); + in = wolfSSL_BIO_new_mem_buf(decodedBase64, decodeSz); + } } } - } } else { diff --git a/src/dh/clu_dh.c b/src/dh/clu_dh.c index bae4942b..3eeb15de 100644 --- a/src/dh/clu_dh.c +++ b/src/dh/clu_dh.c @@ -478,7 +478,7 @@ int wolfCLU_DhParamSetup(int argc, char** argv) if (ret == WOLFCLU_SUCCESS && bioIn != NULL) { DerBuffer* pDer = NULL; byte* in = NULL; - word32 inSz = 0; + int inSz = 0; word32 idx = 0; inSz = wolfSSL_BIO_get_len(bioIn); @@ -500,7 +500,7 @@ int wolfCLU_DhParamSetup(int argc, char** argv) } /* der should always be smaller then pem but check just in case */ - if (ret == WOLFCLU_SUCCESS && inSz < pDer->length) { + if (ret == WOLFCLU_SUCCESS && (word32)inSz < pDer->length) { ret = WOLFCLU_FATAL_ERROR; } @@ -510,7 +510,7 @@ int wolfCLU_DhParamSetup(int argc, char** argv) } if (ret == WOLFCLU_SUCCESS && - wc_DhKeyDecode(in, &idx, &dh, inSz) != 0) { + wc_DhKeyDecode(in, &idx, &dh, (int)inSz) != 0) { wolfCLU_LogError("Unable to decode input params"); ret = WOLFCLU_FATAL_ERROR; } diff --git a/src/ocsp/clu_ocsp.c b/src/ocsp/clu_ocsp.c index 48c8d420..70a8a39b 100644 --- a/src/ocsp/clu_ocsp.c +++ b/src/ocsp/clu_ocsp.c @@ -395,7 +395,7 @@ static int ocspClient(OcspClientConfig* config) typedef struct IndexEntry { char status; time_t revocationTime; - char serial[64]; + char serial[2 * EXTERNAL_SERIAL_SIZE + 1]; struct IndexEntry* next; } IndexEntry; @@ -466,7 +466,14 @@ static IndexEntry* parseIndexFile(const char* filename) } break; case 3: /* Serial (hex) */ + if (XSTRLEN(field) > sizeof(entry->serial)-1) { + wolfCLU_LogError("Field %s too long to fit in entry " + "with max size %lu", field, + (unsigned long)(sizeof(entry->serial)-1)); + break; + } XSTRNCPY(entry->serial, field, sizeof(entry->serial) - 1); + entry->serial[sizeof(entry->serial) - 1] = '\0'; break; } fieldNum++; @@ -478,7 +485,7 @@ static IndexEntry* parseIndexFile(const char* filename) entry = NULL; continue; } - + /* For revoked certificates, revocationTime must be valid */ if (entry->status == 'R' && entry->revocationTime == (time_t)-1) { wolfCLU_LogError("Invalid revocation time for serial %s", entry->serial); diff --git a/src/sign-verify/clu_verify.c b/src/sign-verify/clu_verify.c index b2a86316..b0a760a4 100644 --- a/src/sign-verify/clu_verify.c +++ b/src/sign-verify/clu_verify.c @@ -27,12 +27,17 @@ * and ED25519_SIG_VER */ #ifndef WOLFCLU_NO_FILESYSTEM +/* Upper bound (in bytes) on a signature, hash, or message file the verify path + * will read into memory. Files larger than this are rejected rather than + * allocated. */ +#define WOLFCLU_MAX_FILE_SIZE 0xFFFFFFF + int wolfCLU_verify_signature(char* sig, char* hashFile, char* out, char* keyPath, int keyType, int pubIn, int inForm) { - int hSz = 0; - int fSz; + long hSz = 0; + long fSz; int ret = WOLFCLU_FATAL_ERROR; byte* hash = NULL; @@ -51,14 +56,27 @@ int wolfCLU_verify_signature(char* sig, char* hashFile, char* out, } XFSEEK(f, 0, SEEK_END); - fSz = (int)XFTELL(f); + fSz = XFTELL(f); + + if (fSz < 0) { + wolfCLU_LogError("Invalid Sig File %s.", sig); + XFCLOSE(f); + return BAD_FUNC_ARG; + } + + if (fSz > WOLFCLU_MAX_FILE_SIZE) { + wolfCLU_LogError("File: %s exceeds max size of 0x%X " + "bytes.", sig, (unsigned)WOLFCLU_MAX_FILE_SIZE); + XFCLOSE(f); + return WOLFCLU_FATAL_ERROR; + } data = (byte*)XMALLOC(fSz, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); if (data == NULL) { XFCLOSE(f); return MEMORY_E; } - if (XFSEEK(f, 0, SEEK_SET) != 0 || (int)XFREAD(data, 1, fSz, f) != fSz) { + if (XFSEEK(f, 0, SEEK_SET) != 0 || (long)XFREAD(data, 1, fSz, f) != fSz) { XFCLOSE(f); XFREE(data, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); return WOLFCLU_FATAL_ERROR; @@ -67,7 +85,8 @@ int wolfCLU_verify_signature(char* sig, char* hashFile, char* out, switch(keyType) { case RSA_SIG_VER: - ret = wolfCLU_verify_signature_rsa(data, out, fSz, keyPath, pubIn, inForm); + ret = wolfCLU_verify_signature_rsa(data, out, (int)fSz, + keyPath, pubIn, inForm); break; case ECC_SIG_VER: @@ -79,7 +98,23 @@ int wolfCLU_verify_signature(char* sig, char* hashFile, char* out, } XFSEEK(h, 0, SEEK_END); - hSz = (int)XFTELL(h); + hSz = XFTELL(h); + + if (hSz < 0) { + wolfCLU_LogError("Unable to Get Size of Hash File %s.", + hashFile); + ret = BAD_FUNC_ARG; + XFCLOSE(h); + break; + } + + if (hSz > WOLFCLU_MAX_FILE_SIZE) { + wolfCLU_LogError("File: %s exceeds max size of 0x%X " + "bytes.", hashFile, (unsigned)WOLFCLU_MAX_FILE_SIZE); + ret = WOLFCLU_FATAL_ERROR; + XFCLOSE(h); + break; + } hash = (byte*)XMALLOC(hSz, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); if (hash == NULL) { @@ -95,8 +130,8 @@ int wolfCLU_verify_signature(char* sig, char* hashFile, char* out, return WOLFCLU_FATAL_ERROR; } XFCLOSE(h); - ret = wolfCLU_verify_signature_ecc(data, fSz, hash, hSz, keyPath, - pubIn, inForm); + ret = wolfCLU_verify_signature_ecc(data, (int)fSz, hash, (int)hSz, + keyPath, pubIn, inForm); break; case ED25519_SIG_VER: @@ -109,7 +144,24 @@ int wolfCLU_verify_signature(char* sig, char* hashFile, char* out, } XFSEEK(h, 0, SEEK_END); - hSz = (int)XFTELL(h); + hSz = XFTELL(h); + + + if (hSz < 0) { + wolfCLU_LogError("Unable to Get Size of Hash File %s.", + hashFile); + ret = BAD_FUNC_ARG; + XFCLOSE(h); + break; + } + + if (hSz > WOLFCLU_MAX_FILE_SIZE) { + wolfCLU_LogError("File: %s exceeds max size of 0x%X " + "bytes.", hashFile, (unsigned)WOLFCLU_MAX_FILE_SIZE); + ret = WOLFCLU_FATAL_ERROR; + XFCLOSE(h); + break; + } hash = (byte*)XMALLOC(hSz, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); if (hash == NULL) { @@ -125,8 +177,8 @@ int wolfCLU_verify_signature(char* sig, char* hashFile, char* out, return WOLFCLU_FATAL_ERROR; } XFCLOSE(h); - ret = wolfCLU_verify_signature_ed25519(data, fSz, hash, hSz, - keyPath, pubIn, inForm); + ret = wolfCLU_verify_signature_ed25519(data, (int)fSz, hash, + (int)hSz, keyPath, pubIn, inForm); #endif break; @@ -142,7 +194,23 @@ int wolfCLU_verify_signature(char* sig, char* hashFile, char* out, /* hSz means msgLen */ XFSEEK(h, 0, SEEK_END); - hSz = (int)XFTELL(h); + hSz = XFTELL(h); + + if (hSz < 0) { + wolfCLU_LogError("Unable to Get Size of Hash File %s.", + hashFile); + ret = BAD_FUNC_ARG; + XFCLOSE(h); + break; + } + + if (hSz > WOLFCLU_MAX_FILE_SIZE) { + wolfCLU_LogError("File: %s exceeds max size of 0x%X " + "bytes.", hashFile, (unsigned)WOLFCLU_MAX_FILE_SIZE); + ret = WOLFCLU_FATAL_ERROR; + XFCLOSE(h); + break; + } /* hash means msg */ hash = (byte*)XMALLOC(hSz, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); @@ -160,7 +228,8 @@ int wolfCLU_verify_signature(char* sig, char* hashFile, char* out, } XFCLOSE(h); - ret = wolfCLU_verify_signature_dilithium(data, fSz, hash, hSz, keyPath, inForm); + ret = wolfCLU_verify_signature_dilithium(data, (int)fSz, hash, + (int)hSz, keyPath, inForm); break; #endif @@ -176,7 +245,24 @@ int wolfCLU_verify_signature(char* sig, char* hashFile, char* out, /* hSz means msgLen */ XFSEEK(h, 0, SEEK_END); - hSz = (int)XFTELL(h); + hSz = XFTELL(h); + + + if (hSz < 0) { + wolfCLU_LogError("Unable to Get Size of Hash File %s.", + hashFile); + ret = BAD_FUNC_ARG; + XFCLOSE(h); + break; + } + + if (hSz > WOLFCLU_MAX_FILE_SIZE) { + wolfCLU_LogError("File: %s exceeds max size of 0x%X " + "bytes.", hashFile, (unsigned)WOLFCLU_MAX_FILE_SIZE); + ret = WOLFCLU_FATAL_ERROR; + XFCLOSE(h); + break; + } /* hash means msg */ hash = (byte*)XMALLOC(hSz, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); @@ -194,7 +280,8 @@ int wolfCLU_verify_signature(char* sig, char* hashFile, char* out, } XFCLOSE(h); - ret = wolfCLU_verify_signature_xmss(data, fSz, hash, hSz, keyPath); + ret = wolfCLU_verify_signature_xmss(data, (int)fSz, hash, (int)hSz, + keyPath); break; case XMSSMT_SIG_VER: @@ -208,7 +295,23 @@ int wolfCLU_verify_signature(char* sig, char* hashFile, char* out, /* hSz means msgLen */ XFSEEK(h, 0, SEEK_END); - hSz = (int)XFTELL(h); + hSz = XFTELL(h); + + if (hSz < 0) { + wolfCLU_LogError("Unable to Get Size of Hash File %s.", + hashFile); + ret = BAD_FUNC_ARG; + XFCLOSE(h); + break; + } + + if (hSz > WOLFCLU_MAX_FILE_SIZE) { + wolfCLU_LogError("File: %s exceeds max size of 0x%X " + "bytes.", hashFile, (unsigned)WOLFCLU_MAX_FILE_SIZE); + ret = WOLFCLU_FATAL_ERROR; + XFCLOSE(h); + break; + } /* hash means msg */ hash = (byte*)XMALLOC(hSz, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); @@ -226,7 +329,8 @@ int wolfCLU_verify_signature(char* sig, char* hashFile, char* out, } XFCLOSE(h); - ret = wolfCLU_verify_signature_xmssmt(data, fSz, hash, hSz, keyPath); + ret = wolfCLU_verify_signature_xmssmt(data, (int)fSz, hash, + (int)hSz, keyPath); break; #endif default: @@ -249,7 +353,7 @@ int wolfCLU_verify_signature_rsa(byte* sig, char* out, int sigSz, char* keyPath, #ifndef NO_RSA int ret; - int keyFileSz = 0; + long keyFileSz = 0; word32 index = 0; XFILE keyPathFile = NULL; RsaKey key; @@ -275,7 +379,18 @@ int wolfCLU_verify_signature_rsa(byte* sig, char* out, int sigSz, char* keyPath, } if (ret == 0) { XFSEEK(keyPathFile, 0, SEEK_END); - keyFileSz = (int)XFTELL(keyPathFile); + keyFileSz = XFTELL(keyPathFile); + if (keyFileSz < 0) { + wolfCLU_LogError("Unable to Get Size of Key File %s.", keyPath); + ret = BAD_FUNC_ARG; + } + else if (keyFileSz > WOLFCLU_MAX_FILE_SIZE) { + wolfCLU_LogError("File: %s exceeds max size of 0x%X " + "bytes.", keyPath, (unsigned)WOLFCLU_MAX_FILE_SIZE); + ret = WOLFCLU_FATAL_ERROR; + } + } + if (ret == 0) { keyBuf = (byte*)XMALLOC(keyFileSz+1, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); if (keyBuf == NULL) { ret = MEMORY_E; @@ -291,7 +406,7 @@ int wolfCLU_verify_signature_rsa(byte* sig, char* out, int sigSz, char* keyPath, /* convert PEM to DER if necessary */ if (inForm == PEM_FORM && ret == 0) { - ret = wolfCLU_KeyPemToDer(&keyBuf, keyFileSz, pubIn); + ret = wolfCLU_KeyPemToDer(&keyBuf, (int)keyFileSz, pubIn); if (ret < 0) { wolfCLU_LogError("Failed to convert PEM to DER.\nRET: %d", ret); } @@ -304,7 +419,8 @@ int wolfCLU_verify_signature_rsa(byte* sig, char* out, int sigSz, char* keyPath, if (pubIn == 1) { /* decode public key from DER-encoded input */ if (ret == 0) { - ret = wc_RsaPublicKeyDecode(keyBuf, &index, &key, keyFileSz); + ret = wc_RsaPublicKeyDecode(keyBuf, &index, &key, + (word32)keyFileSz); if (ret != 0) { wolfCLU_LogError("Failed to decode public key from DER.\nRET: %d", ret); } @@ -313,7 +429,8 @@ int wolfCLU_verify_signature_rsa(byte* sig, char* out, int sigSz, char* keyPath, else { /* retrieve private key and store in the RsaKey */ if (ret == 0) { - ret = wc_RsaPrivateKeyDecode(keyBuf, &index, &key, keyFileSz); + ret = wc_RsaPrivateKeyDecode(keyBuf, &index, &key, + (word32)keyFileSz); if (ret != 0) { wolfCLU_LogError("Failed to decode private key.\nRET: %d", ret); } @@ -387,7 +504,7 @@ int wolfCLU_verify_signature_ecc(byte* sig, int sigSz, byte* hash, int hashSz, #ifdef HAVE_ECC int ret; - int keyFileSz = 0; + long keyFileSz = 0; int stat = 0; word32 index = 0; @@ -415,7 +532,18 @@ int wolfCLU_verify_signature_ecc(byte* sig, int sigSz, byte* hash, int hashSz, } if (ret == 0) { XFSEEK(keyPathFile, 0, SEEK_END); - keyFileSz = (int)XFTELL(keyPathFile); + keyFileSz = XFTELL(keyPathFile); + if (keyFileSz < 0) { + wolfCLU_LogError("Unable to Get Size of Key File %s.", keyPath); + ret = BAD_FUNC_ARG; + } + else if (keyFileSz > WOLFCLU_MAX_FILE_SIZE) { + wolfCLU_LogError("File: %s exceeds max size of 0x%X " + "bytes.", keyPath, (unsigned)WOLFCLU_MAX_FILE_SIZE); + ret = WOLFCLU_FATAL_ERROR; + } + } + if (ret == 0) { keyBuf = (byte*)XMALLOC(keyFileSz+1, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); if (keyBuf == NULL) { ret = MEMORY_E; @@ -431,7 +559,7 @@ int wolfCLU_verify_signature_ecc(byte* sig, int sigSz, byte* hash, int hashSz, /* convert PEM to DER if necessary */ if (inForm == PEM_FORM && ret == 0) { - ret = wolfCLU_KeyPemToDer(&keyBuf, keyFileSz, pubIn); + ret = wolfCLU_KeyPemToDer(&keyBuf, (int)keyFileSz, pubIn); if (ret < 0) { wolfCLU_LogError("Failed to convert PEM to DER.\nRET: %d", ret); } @@ -444,7 +572,7 @@ int wolfCLU_verify_signature_ecc(byte* sig, int sigSz, byte* hash, int hashSz, if (pubIn == 1) { /* retrieve public key and store in the Ecc key */ if (ret == 0) { - ret = wc_EccPublicKeyDecode(keyBuf, &index, &key, keyFileSz); + ret = wc_EccPublicKeyDecode(keyBuf, &index, &key, (word32)keyFileSz); if (ret < 0 ) { wolfCLU_LogError("Failed to decode public key.\nRET: %d", ret); } @@ -453,7 +581,7 @@ int wolfCLU_verify_signature_ecc(byte* sig, int sigSz, byte* hash, int hashSz, else { /* retrieve private key and store in the Ecc Key */ if (ret == 0) { - ret = wc_EccPrivateKeyDecode(keyBuf, &index, &key, keyFileSz); + ret = wc_EccPrivateKeyDecode(keyBuf, &index, &key, (word32)keyFileSz); if (ret != 0 ) { wolfCLU_LogError("Failed to decode Ecc private key.\nRET: %d", ret); } @@ -548,7 +676,7 @@ int wolfCLU_verify_signature_ed25519(byte* sig, int sigSz, int ret; int stat = 0; word32 index = 0; - int keyFileSz = 0; + long keyFileSz = 0; XFILE keyPathFile = NULL; ed25519_key key; @@ -572,7 +700,18 @@ int wolfCLU_verify_signature_ed25519(byte* sig, int sigSz, } if (ret == 0) { XFSEEK(keyPathFile, 0, SEEK_END); - keyFileSz = (int)XFTELL(keyPathFile); + keyFileSz = XFTELL(keyPathFile); + if (keyFileSz < 0) { + wolfCLU_LogError("Unable to Get Size of Key File %s.", keyPath); + ret = BAD_FUNC_ARG; + } + else if (keyFileSz > WOLFCLU_MAX_FILE_SIZE) { + wolfCLU_LogError("File: %s exceeds max size of 0x%X " + "bytes.", keyPath, (unsigned)WOLFCLU_MAX_FILE_SIZE); + ret = WOLFCLU_FATAL_ERROR; + } + } + if (ret == 0) { keyBuf = (byte*)XMALLOC(keyFileSz+1, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); if (keyBuf == NULL) { ret = MEMORY_E; @@ -588,7 +727,7 @@ int wolfCLU_verify_signature_ed25519(byte* sig, int sigSz, /* convert PEM to DER if necessary */ if (inForm == PEM_FORM && ret == 0) { - ret = wolfCLU_KeyPemToDer(&keyBuf, keyFileSz, pubIn); + ret = wolfCLU_KeyPemToDer(&keyBuf, (int)keyFileSz, pubIn); if (ret < 0) { wolfCLU_LogError("Failed to convert PEM to DER.\nRET: %d", ret); } @@ -608,7 +747,8 @@ int wolfCLU_verify_signature_ed25519(byte* sig, int sigSz, } /* decode public key from DER-encoded input */ else { - ret = wc_Ed25519PublicKeyDecode(keyBuf, &index, &key, keyFileSz); + ret = wc_Ed25519PublicKeyDecode(keyBuf, &index, &key, + (word32)keyFileSz); if (ret != 0) { wolfCLU_LogError("Failed to decode public key from DER.\nRET: %d", ret); } @@ -626,7 +766,8 @@ int wolfCLU_verify_signature_ed25519(byte* sig, int sigSz, } } else { - ret = wc_Ed25519PrivateKeyDecode(keyBuf, &index, &key, keyFileSz); + ret = wc_Ed25519PrivateKeyDecode(keyBuf, &index, &key, + (word32)keyFileSz); if (ret != 0) { wolfCLU_LogError("Failed to import private key.\nRET: %d", ret); } @@ -682,7 +823,7 @@ int wolfCLU_verify_signature_dilithium(byte* sig, int sigSz, byte* msg, XFILE keyFile = NULL; byte* keyBuf = NULL; - int keyFileSz = 0; + long keyFileSz = 0; word32 keyBufSz = 0; word32 index = 0; int res = 0; @@ -723,7 +864,26 @@ int wolfCLU_verify_signature_dilithium(byte* sig, int sigSz, byte* msg, } XFSEEK(keyFile, 0, SEEK_END); - keyFileSz = (int)XFTELL(keyFile); + keyFileSz = XFTELL(keyFile); + if (keyFileSz < 0) { + wolfCLU_LogError("Failed to get size of public key FILE."); + XFCLOSE(keyFile); + wc_dilithium_free(key); + #ifdef WOLFSSL_SMALL_STACK + XFREE(key, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + #endif + return BAD_FUNC_ARG; + } + if (keyFileSz > WOLFCLU_MAX_FILE_SIZE) { + wolfCLU_LogError("File: %s exceeds max size of 0x%X " + "bytes.", keyPath, (unsigned)WOLFCLU_MAX_FILE_SIZE); + XFCLOSE(keyFile); + wc_dilithium_free(key); + #ifdef WOLFSSL_SMALL_STACK + XFREE(key, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); + #endif + return WOLFCLU_FATAL_ERROR; + } keyBuf = (byte*)XMALLOC(keyFileSz, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); if (keyBuf == NULL) { wolfCLU_LogError("Failed to malloc key buffer."); @@ -752,7 +912,7 @@ int wolfCLU_verify_signature_dilithium(byte* sig, int sigSz, byte* msg, /* convert PEM to DER if necessary */ if (inForm == PEM_FORM) { - ret = wolfCLU_KeyPemToDer(&keyBuf, keyFileSz, 1); + ret = wolfCLU_KeyPemToDer(&keyBuf, (int)keyFileSz, 1); if (ret < 0) { wolfCLU_LogError("Failed to convert PEM to DER.\nRET: %d", ret); XFREE(keyBuf, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); @@ -825,7 +985,7 @@ int wolfCLU_verify_signature_xmss(byte* sig, int sigSz, int ret = 0; XFILE keyFile = NULL; /* public key file */ byte* keyBuf = NULL; /* public key buffer */ - int keyFileSz = 0; /* public key buffer size */ + long keyFileSz = 0; /* public key buffer size */ word32 oid = 0x0; /* OID of the XMSS parameter */ char* paramStr = NULL; /* XMSS parameter string */ int paramLen = XMSS_NAME_LEN + 1; /* XMSS parameter string length */ @@ -859,7 +1019,19 @@ int wolfCLU_verify_signature_xmss(byte* sig, int sigSz, if (ret == 0) { XFSEEK(keyFile, 0, SEEK_END); - keyFileSz = (int)XFTELL(keyFile); + keyFileSz = XFTELL(keyFile); + if (keyFileSz < 0) { + ret = WOLFCLU_FATAL_ERROR; + wolfCLU_LogError("Failed to get size of public key FILE."); + } + else if (keyFileSz > WOLFCLU_MAX_FILE_SIZE) { + ret = WOLFCLU_FATAL_ERROR; + wolfCLU_LogError("File: %s exceeds max size of 0x%X " + "bytes.", pubKey, (unsigned)WOLFCLU_MAX_FILE_SIZE); + } + } + + if (ret == 0) { keyBuf = (byte*)XMALLOC(keyFileSz, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); if (keyBuf == NULL) { ret = MEMORY_E; @@ -928,7 +1100,7 @@ int wolfCLU_verify_signature_xmss(byte* sig, int sigSz, /* import the public key */ if (ret == 0) { - ret = wc_XmssKey_ImportPubRaw(key, keyBuf, keyFileSz); + ret = wc_XmssKey_ImportPubRaw(key, keyBuf, (word32)keyFileSz); if (ret != 0) { wolfCLU_LogError("Failed to decode public key." "\nRET: %d", ret); @@ -981,7 +1153,7 @@ int wolfCLU_verify_signature_xmssmt(byte* sig, int sigSz, int ret = 0; XFILE keyFile = NULL; /* public key file */ byte* keyBuf = NULL; /* public key buffer */ - int keyFileSz = 0; /* public key buffer size */ + long keyFileSz = 0; /* public key buffer size */ word32 oid = 0x0; /* OID of the XMSS parameter */ char* paramStr = NULL; /* XMSS parameter string */ int paramLen = XMSSMT_NAME_MAX_LEN + 1; /* XMSS parameter string length */ @@ -1015,7 +1187,19 @@ int wolfCLU_verify_signature_xmssmt(byte* sig, int sigSz, if (ret == 0) { XFSEEK(keyFile, 0, SEEK_END); - keyFileSz = (int)XFTELL(keyFile); + keyFileSz = XFTELL(keyFile); + if (keyFileSz < 0) { + ret = WOLFCLU_FATAL_ERROR; + wolfCLU_LogError("Failed to get size of public key FILE."); + } + else if (keyFileSz > WOLFCLU_MAX_FILE_SIZE) { + ret = WOLFCLU_FATAL_ERROR; + wolfCLU_LogError("File: %s exceeds max size of 0x%X " + "bytes.", pubKey, (unsigned)WOLFCLU_MAX_FILE_SIZE); + } + } + + if (ret == 0) { keyBuf = (byte*)XMALLOC(keyFileSz, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); if (keyBuf == NULL) { ret = MEMORY_E; @@ -1098,7 +1282,7 @@ int wolfCLU_verify_signature_xmssmt(byte* sig, int sigSz, /* import the public key */ if (ret == 0) { - ret = wc_XmssKey_ImportPubRaw(key, keyBuf, keyFileSz); + ret = wc_XmssKey_ImportPubRaw(key, keyBuf, (word32)keyFileSz); if (ret != 0) { wolfCLU_LogError("Failed to decode public key." "\nRET: %d", ret); diff --git a/src/sign-verify/clu_x509_verify.c b/src/sign-verify/clu_x509_verify.c index e5720975..1645a844 100644 --- a/src/sign-verify/clu_x509_verify.c +++ b/src/sign-verify/clu_x509_verify.c @@ -24,6 +24,7 @@ #include #include #include +#include #ifndef WOLFCLU_NO_FILESYSTEM @@ -126,10 +127,20 @@ int wolfCLU_x509Verify(int argc, char** argv) case WOLFCLU_CAFILE: WOLFCLU_LOG(WOLFCLU_L0, "using CA file %s", optarg); caCert = optarg; + if (caCert == verifyCert) { + wolfCLU_LogError("Malformed argument: last argument " + "\"%s\" must not be a flag arg", verifyCert); + ret = WOLFCLU_FATAL_ERROR; + } break; case WOLFCLU_INTERMEDIATE: intermCert = optarg; + if (intermCert == verifyCert) { + wolfCLU_LogError("Malformed argument: last argument " + "\"%s\" must not be a flag arg", verifyCert); + ret = WOLFCLU_FATAL_ERROR; + } break; case WOLFCLU_PARTIAL_CHAIN: @@ -155,12 +166,21 @@ int wolfCLU_x509Verify(int argc, char** argv) } } - cert = load_cert_from_file(verifyCert); - if (!cert) { - wolfCLU_LogError("Failed to load cert: %s\n", verifyCert); + if (ret == WOLFCLU_SUCCESS && caCert != NULL && !partialChain && + (XSTRCMP(caCert, verifyCert) == 0)) { + wolfCLU_LogError("Unless -partial_chain is passed as an argument " + "-CAFile cannot be the same as the cert to verify"); ret = WOLFCLU_FATAL_ERROR; } + if (ret == WOLFCLU_SUCCESS) { + cert = load_cert_from_file(verifyCert); + if (!cert) { + wolfCLU_LogError("Failed to load cert: %s\n", verifyCert); + ret = WOLFCLU_FATAL_ERROR; + } + } + if (ret == WOLFCLU_SUCCESS && intermCert) { intermediate = load_cert_from_file(intermCert); if (!intermediate) { diff --git a/src/tools/clu_rand.c b/src/tools/clu_rand.c index 9bd72946..f933cd1c 100644 --- a/src/tools/clu_rand.c +++ b/src/tools/clu_rand.c @@ -23,6 +23,14 @@ #include #include +/* Windows opens stdout in text mode, expanding every 0x0A byte to 0x0D 0x0A. + * That corrupts raw binary random output (and adds stray bytes to encoded + * output), so stdout is switched to binary mode below before writing. */ +#if defined(_WIN32) + #include + #include +#endif + /* Fallback for RNG configs that leave RNG_MAX_BLOCK_LEN undefined. If a build's * real per-call limit is smaller, wc_RNG_GenerateBlock fails cleanly. */ #ifndef RNG_MAX_BLOCK_LEN @@ -349,6 +357,12 @@ int wolfCLU_Rand(int argc, char** argv) /* setup output bio to stdout if not set */ if (ret == WOLFCLU_SUCCESS && bioOut == NULL) { outIsStdout = 1; +#if defined(_WIN32) + /* Put stdout in binary mode so raw bytes pass through untranslated; + * otherwise a random 0x0A becomes 0x0D 0x0A and `rand N` emits N+1 + * bytes. */ + (void)_setmode(_fileno(stdout), _O_BINARY); +#endif bioOut = wolfSSL_BIO_new(wolfSSL_BIO_s_file()); if (bioOut == NULL) { ret = WOLFCLU_FATAL_ERROR; diff --git a/tests/dgst/dgst-test.py b/tests/dgst/dgst-test.py index 76a5699c..fe4c7273 100644 --- a/tests/dgst/dgst-test.py +++ b/tests/dgst/dgst-test.py @@ -129,6 +129,30 @@ def test_dgst_out_roundtrip(self): "-signature", sig_file, input_file) self.assertEqual(r.returncode, 0, r.stderr) + def test_missing_data_file_detected(self): + """Omitting the trailing data file must be detected, not misread. + + clu_dgst_setup.c passes argc-1 to wolfCLU_GetOpt so the trailing + data file is excluded from option scanning, then checks whether the + last option consumed it as a value. With the data file absent here, + the .sig path is the trailing argument and the malformed-argument + check must reject the invocation rather than hashing the .sig file. + """ + r = run_wolfssl("dgst", "-sha256", "-verify", + os.path.join(CERTS_DIR, "server-keyPub.pem"), + "-signature", os.path.join(DGST_DIR, "sha256-rsa.sig")) + self.assertGreaterEqual(r.returncode, 0, r.stderr) + + def test_complete_args_not_misflagged(self): + """A well-formed dgst command must not trip the malformed-argument + check; the trailing data file should be hashed, not flagged as an + option value.""" + r = run_wolfssl("dgst", "-sha256", "-verify", + os.path.join(CERTS_DIR, "server-keyPub.pem"), + "-signature", os.path.join(DGST_DIR, "sha256-rsa.sig"), + os.path.join(CERTS_DIR, "server-key.der")) + self.assertEqual(r.returncode, 0, r.stderr) + class DgstLargeFileTest(unittest.TestCase): diff --git a/tests/x509/x509-verify-test.py b/tests/x509/x509-verify-test.py index a8c5763f..2a92749e 100644 --- a/tests/x509/x509-verify-test.py +++ b/tests/x509/x509-verify-test.py @@ -102,6 +102,28 @@ def test_verify_partial_chain(self): os.path.join(CERTS_DIR, "server-cert.pem")) self.assertEqual(r.returncode, 0, r.stderr) + def test_last_arg_not_misread(self): + """A missing cert-to-verify (last token consumed by -untrusted) is + rejected as a malformed argument, not silently misread.""" + r = run_wolfssl("verify", "-partial_chain", "-CAfile", + os.path.join(CERTS_DIR, "server-cert.pem"), + "-untrusted", os.path.join(CERTS_DIR, "client-cert.pem") + ) + self.assertNotEqual(r.returncode, 0, r.stderr) + self.assertIn("Malformed argument", r.stdout + r.stderr) + + def test_partial_chain_no_cafile_no_crash(self): + """-partial_chain with -untrusted but no -CAfile must not crash. + + caCert is NULL in this path; the malformed-argument check must + tolerate that rather than dereferencing it. + """ + r = run_wolfssl("verify", "-partial_chain", + "-untrusted", os.path.join(CERTS_DIR, "server-cert.pem"), + os.path.join(CERTS_DIR, "server-cert.pem")) + # A NULL-deref would crash (negative returncode from a signal); + # require a normal exit code regardless of verify success/failure. + self.assertGreaterEqual(r.returncode, 0, r.stderr) class TestX509VerifyCRL(unittest.TestCase): """CRL-related verification tests."""