diff --git a/src/crypto/clu_evp_crypto.c b/src/crypto/clu_evp_crypto.c index 745878eb..81a772d3 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..c6245b0a 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; + long inSz = 0; word32 idx = 0; inSz = wolfSSL_BIO_get_len(bioIn); @@ -489,7 +489,7 @@ int wolfCLU_DhParamSetup(int argc, char** argv) } if (ret == WOLFCLU_SUCCESS && - wolfSSL_BIO_read(bioIn, in, inSz) <= 0) { + wolfSSL_BIO_read(bioIn, in, (int)inSz) <= 0) { 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..725df628 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[65]; 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_dgst_setup.c b/src/sign-verify/clu_dgst_setup.c index 2ddc095d..ebc75cbe 100644 --- a/src/sign-verify/clu_dgst_setup.c +++ b/src/sign-verify/clu_dgst_setup.c @@ -19,6 +19,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA */ +#include "wolfclu/clu_error_codes.h" #include #include #include @@ -202,7 +203,7 @@ int wolfCLU_dgst_setup(int argc, char** argv) opterr = 0; /* do not display unrecognized options */ optind = 0; /* start at indent 0 */ - while ((option = wolfCLU_GetOpt(argc, argv, "", + while (ret == WOLFCLU_SUCCESS && (option = wolfCLU_GetOpt(argc-1, argv, "", dgst_options, &longIndex )) != -1) { switch (option) { @@ -273,6 +274,16 @@ int wolfCLU_dgst_setup(int argc, char** argv) } } + /* Detect malformed arguments: if the trailing positional data file was + * instead consumed as the value of a required-argument option, optarg will + * string-match argv[argc-1]. The argc >= 2 guard keeps the argv[argc-2] + * access in bounds. */ + if (argc >= 2 && optarg != NULL && XSTRCMP(optarg, argv[argc-1]) == 0) { + wolfCLU_LogError("Malformed arguments last argument read as value for " + "%s", argv[argc-2]); + ret = WOLFCLU_FATAL_ERROR; + } + if (ret == WOLFCLU_SUCCESS) { if (dataBio == NULL || sigFile == NULL) { wolfCLU_LogError("error with reading signature or data"); diff --git a/src/sign-verify/clu_verify.c b/src/sign-verify/clu_verify.c index 3eb0c872..89ce5bfe 100644 --- a/src/sign-verify/clu_verify.c +++ b/src/sign-verify/clu_verify.c @@ -31,8 +31,8 @@ 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 +51,20 @@ 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; + } 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 +73,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 +86,15 @@ 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; + } hash = (byte*)XMALLOC(hSz, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); if (hash == NULL) { @@ -95,8 +110,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 +124,16 @@ 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; + } hash = (byte*)XMALLOC(hSz, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); if (hash == NULL) { @@ -125,8 +149,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 +166,15 @@ 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; + } /* hash means msg */ hash = (byte*)XMALLOC(hSz, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); @@ -160,7 +192,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 +209,16 @@ 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; + } /* hash means msg */ hash = (byte*)XMALLOC(hSz, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); @@ -194,7 +236,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 +251,15 @@ 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; + } /* hash means msg */ hash = (byte*)XMALLOC(hSz, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); @@ -226,7 +277,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 +301,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 +327,13 @@ 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; + } + } + if (ret == 0) { keyBuf = (byte*)XMALLOC(keyFileSz+1, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); if (keyBuf == NULL) { ret = MEMORY_E; @@ -291,7 +349,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 +362,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 +372,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 +447,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 +475,13 @@ 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; + } + } + if (ret == 0) { keyBuf = (byte*)XMALLOC(keyFileSz+1, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); if (keyBuf == NULL) { ret = MEMORY_E; @@ -431,7 +497,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 +510,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 +519,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); } @@ -547,7 +613,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; @@ -571,7 +637,13 @@ 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; + } + } + if (ret == 0) { keyBuf = (byte*)XMALLOC(keyFileSz+1, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); if (keyBuf == NULL) { ret = MEMORY_E; @@ -587,7 +659,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); } @@ -607,7 +679,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); } @@ -625,7 +698,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); } @@ -680,7 +754,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; @@ -721,7 +795,16 @@ 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; + } keyBuf = (byte*)XMALLOC(keyFileSz, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); if (keyBuf == NULL) { wolfCLU_LogError("Failed to malloc key buffer."); @@ -750,7 +833,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); @@ -822,7 +905,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 */ @@ -856,7 +939,14 @@ 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."); + } + } + + if (ret == 0) { keyBuf = (byte*)XMALLOC(keyFileSz, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); if (keyBuf == NULL) { ret = MEMORY_E; @@ -925,7 +1015,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); @@ -978,7 +1068,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 */ @@ -1012,7 +1102,14 @@ 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."); + } + } + + if (ret == 0) { keyBuf = (byte*)XMALLOC(keyFileSz, HEAP_HINT, DYNAMIC_TYPE_TMP_BUFFER); if (keyBuf == NULL) { ret = MEMORY_E; @@ -1095,7 +1192,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..6e960eeb 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 @@ -155,12 +156,30 @@ int wolfCLU_x509Verify(int argc, char** argv) } } - cert = load_cert_from_file(verifyCert); - if (!cert) { - wolfCLU_LogError("Failed to load cert: %s\n", verifyCert); + + /* Detect malformed arguments: if the trailing positional argument (the + * cert to verify) was instead consumed as the value of a required-argument + * option, optarg will string-match argv[argc-1]. The argc >= 2 guard keeps + * the argv[argc-2] access in bounds. With -partial_chain the CA file may + * legitimately equal the verify cert, so that case is not treated as an + * error. */ + if (argc >= 2 && optarg != NULL && XSTRCMP(optarg, argv[argc-1]) == 0 && + (partialChain == 0 || caCert == NULL || + XSTRCMP(caCert, argv[argc-1]) != 0) && + (intermCert == NULL || XSTRCMP(intermCert, argv[argc-1]) != 0)) { + wolfCLU_LogError("Malformed arguments last argument read as value for " + "%s", argv[argc-2]); 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 47377d66..66d9bd82 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.assertNotEqual(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..5afd2c4f 100644 --- a/tests/x509/x509-verify-test.py +++ b/tests/x509/x509-verify-test.py @@ -102,6 +102,25 @@ 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): + r = run_wolfssl("verify", "-partial_chain", "-CAfile", + os.path.join(CERTS_DIR, "server-cert.pem"), + "-untrusted", os.path.join(CERTS_DIR, "random.pem") + ) + self.assertNotEqual(r.returncode, 0, 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."""