diff --git a/wolfcrypt/src/asn.c b/wolfcrypt/src/asn.c index fa725a66b..587d1eacd 100644 --- a/wolfcrypt/src/asn.c +++ b/wolfcrypt/src/asn.c @@ -2522,10 +2522,11 @@ int wc_CheckPrivateKey(byte* key, word32 keySz, DecodedCert* der) /* Check To see if PKCS version algo is supported, set id if it is return 0 < 0 on error */ -static int CheckAlgo(int first, int second, int* id, int* version) +static int CheckAlgo(int first, int second, int* id, int* version, int* blockSz) { *id = ALGO_ID_E; *version = PKCS5; /* default */ + if (blockSz) *blockSz = 8; /* default */ if (first == 1) { switch (second) { @@ -2540,6 +2541,7 @@ static int CheckAlgo(int first, int second, int* id, int* version) case PBE_SHA1_DES3: *id = PBE_SHA1_DES3; *version = PKCS12v1; + if (blockSz) *blockSz = DES_BLOCK_SIZE; return 0; #endif #endif /* !NO_SHA */ @@ -2561,11 +2563,13 @@ static int CheckAlgo(int first, int second, int* id, int* version) #ifndef NO_MD5 case 3: /* see RFC 2898 for ids */ *id = PBE_MD5_DES; + if (blockSz) *blockSz = DES_BLOCK_SIZE; return 0; #endif #ifndef NO_SHA case 10: *id = PBE_SHA1_DES; + if (blockSz) *blockSz = DES_BLOCK_SIZE; return 0; #endif #endif /* !NO_DES3 */ @@ -2578,21 +2582,25 @@ static int CheckAlgo(int first, int second, int* id, int* version) /* Check To see if PKCS v2 algo is supported, set id if it is return 0 < 0 on error */ -static int CheckAlgoV2(int oid, int* id) +static int CheckAlgoV2(int oid, int* id, int* blockSz) { + if (blockSz) *blockSz = 8; /* default */ (void)id; /* not used if AES and DES3 disabled */ switch (oid) { #if !defined(NO_DES3) && !defined(NO_SHA) case DESb: *id = PBE_SHA1_DES; + if (blockSz) *blockSz = DES_BLOCK_SIZE; return 0; case DES3b: *id = PBE_SHA1_DES3; + if (blockSz) *blockSz = DES_BLOCK_SIZE; return 0; #endif #ifdef WOLFSSL_AES_256 case AES256CBCb: *id = PBE_AES256_CBC; + if (blockSz) *blockSz = AES_BLOCK_SIZE; return 0; #endif default: @@ -2682,6 +2690,24 @@ int wc_GetKeyOID(byte* key, word32 keySz, const byte** curveOID, word32* oidSz, return 1; } +#define PKCS8_MIN_BLOCK_SIZE 8 +static int Pkcs8Pad(byte* buf, int sz, int blockSz) +{ + int i, padSz; + + /* calculate pad size */ + padSz = (sz % blockSz); + + /* pad with padSz value */ + if (buf) { + for (i = 0; i < padSz; i++) { + buf[sz+i] = padSz; + } + } + + /* return adjusted length */ + return sz + padSz; +} /* * Used when creating PKCS12 shrouded key bags @@ -2705,6 +2731,7 @@ int UnTraditionalEnc(byte* key, word32 keySz, byte* out, word32* outSz, word32 totalSz = 0; int version, id; int ret; + int blockSz = 0; const byte* curveOID = NULL; word32 oidSz = 0; @@ -2724,7 +2751,7 @@ int UnTraditionalEnc(byte* key, word32 keySz, byte* out, word32* outSz, inOutIdx += MAX_SEQ_SZ; /* leave room for size of finished shroud */ - if (CheckAlgo(vPKCS, vAlgo, &id, &version) < 0) { + if (CheckAlgo(vPKCS, vAlgo, &id, &version, &blockSz) < 0) { WOLFSSL_MSG("Bad/Unsupported algorithm ID"); return ASN_INPUT_E; /* Algo ID error */ } @@ -2824,7 +2851,8 @@ int UnTraditionalEnc(byte* key, word32 keySz, byte* out, word32* outSz, return LENGTH_ONLY_E; } - tmp = (byte*)XMALLOC(tmpSz, heap, DYNAMIC_TYPE_TMP_BUFFER); + /* reserve buffer for crypto and make sure it supports full blocks */ + tmp = (byte*)XMALLOC(tmpSz + (blockSz-1), heap, DYNAMIC_TYPE_TMP_BUFFER); if (tmp == NULL) { #ifdef WOLFSSL_SMALL_STACK if (saltTmp != NULL) @@ -2845,6 +2873,9 @@ int UnTraditionalEnc(byte* key, word32 keySz, byte* out, word32* outSz, } tmpSz = ret; + /* adjust size to pad */ + tmpSz = Pkcs8Pad(tmp, tmpSz, blockSz); + #ifdef WOLFSSL_SMALL_STACK cbcIv = (byte*)XMALLOC(MAX_IV_SIZE, heap, DYNAMIC_TYPE_TMP_BUFFER); if (cbcIv == NULL) { @@ -2888,7 +2919,7 @@ int UnTraditionalEnc(byte* key, word32 keySz, byte* out, word32* outSz, XMEMCPY(out + inOutIdx, tmp, tmpSz); XFREE(tmp, heap, DYNAMIC_TYPE_TMP_BUFFER); - /* set total size at begining */ + /* set total size at beginning */ sz = SetSequence(totalSz, out); XMEMMOVE(out + sz, out + MAX_SEQ_SZ, totalSz); @@ -2927,7 +2958,7 @@ int ToTraditionalEnc(byte* input, word32 sz,const char* password,int passwordSz) first = input[inOutIdx - 2]; /* PKCS version always 2nd to last byte */ second = input[inOutIdx - 1]; /* version.algo, algo id last byte */ - if (CheckAlgo(first, second, &id, &version) < 0) { + if (CheckAlgo(first, second, &id, &version, NULL) < 0) { ERROR_OUT(ASN_INPUT_E, exit_tte); /* Algo ID error */ } @@ -3001,7 +3032,7 @@ int ToTraditionalEnc(byte* input, word32 sz,const char* password,int passwordSz) ERROR_OUT(ASN_PARSE_E, exit_tte); } - if (CheckAlgoV2(oid, &id) < 0) { + if (CheckAlgoV2(oid, &id, NULL) < 0) { ERROR_OUT(ASN_PARSE_E, exit_tte); /* PKCS v2 algo id error */ } @@ -3070,7 +3101,7 @@ int EncryptContent(byte* input, word32 inputSz, byte* out, word32* outSz, word32 totalSz = 0; word32 seqSz; int ret; - int version, id; + int version, id, blockSz = 0; #ifdef WOLFSSL_SMALL_STACK byte* saltTmp = NULL; byte* cbcIv = NULL; @@ -3083,7 +3114,7 @@ int EncryptContent(byte* input, word32 inputSz, byte* out, word32* outSz, WOLFSSL_ENTER("EncryptContent()"); - if (CheckAlgo(vPKCS, vAlgo, &id, &version) < 0) + if (CheckAlgo(vPKCS, vAlgo, &id, &version, &blockSz) < 0) return ASN_INPUT_E; /* Algo ID error */ if (version == PKCS5v2) { @@ -3106,7 +3137,7 @@ int EncryptContent(byte* input, word32 inputSz, byte* out, word32* outSz, case PBE_SHA1_DES: case PBE_SHA1_DES3: /* set to block size of 8 for DES operations. This rounds up - * to the nearset multiple of 8 */ + * to the nearest multiple of 8 */ sz &= 0xfffffff8; sz += 8; break; @@ -3130,9 +3161,15 @@ int EncryptContent(byte* input, word32 inputSz, byte* out, word32* outSz, } /* add 2 for tags */ - *outSz = sz + MAX_ALGO_SZ + MAX_SEQ_SZ + MAX_LENGTH_SZ + + totalSz = sz + MAX_ALGO_SZ + MAX_SEQ_SZ + MAX_LENGTH_SZ + MAX_LENGTH_SZ + MAX_LENGTH_SZ + MAX_SHORT_SZ + 2; + /* adjust size to pad */ + totalSz = Pkcs8Pad(NULL, totalSz, blockSz); + + /* return result */ + *outSz = totalSz; + return LENGTH_ONLY_E; } @@ -3177,7 +3214,7 @@ int EncryptContent(byte* input, word32 inputSz, byte* out, word32* outSz, XMEMCPY(out + tmpIdx, salt, saltSz); tmpIdx += saltSz; - /* place itteration setting in buffer */ + /* place iteration setting in buffer */ ret = SetShortInt(out, &tmpIdx, itt, *outSz); if (ret < 0) { #ifdef WOLFSSL_SMALL_STACK @@ -3201,8 +3238,21 @@ int EncryptContent(byte* input, word32 inputSz, byte* out, word32* outSz, } #endif + if (inOutIdx + 1 + MAX_LENGTH_SZ + inputSz > *outSz) + return BUFFER_E; + + out[inOutIdx++] = ASN_LONG_LENGTH; totalSz++; + sz = SetLength(inputSz, out + inOutIdx); + inOutIdx += sz; totalSz += sz; + + /* adjust size to pad */ + sz = Pkcs8Pad(out + inOutIdx, inputSz, blockSz); + if (sz + inOutIdx > *outSz) + return BUFFER_E; + + XMEMCPY(out + inOutIdx, input, inputSz); if ((ret = wc_CryptKey(password, passwordSz, salt, saltSz, itt, id, - input, inputSz, version, cbcIv, 1)) < 0) { + out + inOutIdx, sz, version, cbcIv, 1)) < 0) { #ifdef WOLFSSL_SMALL_STACK XFREE(cbcIv, heap, DYNAMIC_TYPE_TMP_BUFFER); @@ -3215,15 +3265,7 @@ int EncryptContent(byte* input, word32 inputSz, byte* out, word32* outSz, XFREE(cbcIv, heap, DYNAMIC_TYPE_TMP_BUFFER); XFREE(saltTmp, heap, DYNAMIC_TYPE_TMP_BUFFER); #endif - - if (inOutIdx + 1 + MAX_LENGTH_SZ + inputSz > *outSz) - return BUFFER_E; - - out[inOutIdx++] = ASN_LONG_LENGTH; totalSz++; - sz = SetLength(inputSz, out + inOutIdx); - inOutIdx += sz; totalSz += sz; - XMEMCPY(out + inOutIdx, input, inputSz); - totalSz += inputSz; + totalSz += sz; return totalSz; } @@ -3261,7 +3303,7 @@ int DecryptContent(byte* input, word32 sz,const char* password,int passwordSz) first = input[inOutIdx - 2]; /* PKCS version always 2nd to last byte */ second = input[inOutIdx - 1]; /* version.algo, algo id last byte */ - if (CheckAlgo(first, second, &id, &version) < 0) { + if (CheckAlgo(first, second, &id, &version, NULL) < 0) { ERROR_OUT(ASN_INPUT_E, exit_dc); /* Algo ID error */ } @@ -3335,7 +3377,7 @@ int DecryptContent(byte* input, word32 sz,const char* password,int passwordSz) ERROR_OUT(ASN_PARSE_E, exit_dc); } - if (CheckAlgoV2(oid, &id) < 0) { + if (CheckAlgoV2(oid, &id, NULL) < 0) { ERROR_OUT(ASN_PARSE_E, exit_dc); /* PKCS v2 algo id error */ }