Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
260 changes: 68 additions & 192 deletions wolfcrypt/src/asn.c
Original file line number Diff line number Diff line change
Expand Up @@ -3756,11 +3756,18 @@ int TraditionalEnc(byte* key, word32 keySz, byte* out, word32* outSz,
#endif /* HAVE_PKCS8 */

#if defined(HAVE_PKCS8) || defined(HAVE_PKCS12)

/* Remove Encrypted PKCS8 header, move beginning of traditional to beginning
of input */
int ToTraditionalEnc(byte* input, word32 sz,const char* password,
int passwordSz, word32* algId)
/* decrypt PKCS
*
* NOTE: input buffer is overwritten with decrypted data!
*
* input[in/out] data to decrypt and results are written to
* sz size of input buffer
* password password if used. Can be NULL for no password
* passwordSz size of password buffer
*
* returns the total size of decrypted content on success.
*/
int DecryptContent(byte* input, word32 sz, const char* password, int passwordSz)
{
word32 inOutIdx = 0, seqEnd, oid, shaOid = 0;
int ret = 0, first, second, length = 0, version, saltSz, id;
Expand All @@ -3772,89 +3779,85 @@ int ToTraditionalEnc(byte* input, word32 sz,const char* password,
byte salt[MAX_SALT_SIZE];
byte cbcIv[MAX_IV_SIZE];
#endif
byte tag;

if (passwordSz < 0) {
WOLFSSL_MSG("Bad password size");
return BAD_FUNC_ARG;
}

if (GetSequence(input, &inOutIdx, &length, sz) < 0) {
ERROR_OUT(ASN_PARSE_E, exit_tte);
}

if (GetAlgoId(input, &inOutIdx, &oid, oidIgnoreType, sz) < 0) {
ERROR_OUT(ASN_PARSE_E, exit_tte);
ERROR_OUT(ASN_PARSE_E, exit_dc);
}

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, NULL) < 0) {
ERROR_OUT(ASN_INPUT_E, exit_tte); /* Algo ID error */
ERROR_OUT(ASN_INPUT_E, exit_dc); /* Algo ID error */
}

if (version == PKCS5v2) {
if (GetSequence(input, &inOutIdx, &length, sz) < 0) {
ERROR_OUT(ASN_PARSE_E, exit_tte);
ERROR_OUT(ASN_PARSE_E, exit_dc);
}

if (GetAlgoId(input, &inOutIdx, &oid, oidKdfType, sz) < 0) {
ERROR_OUT(ASN_PARSE_E, exit_tte);
ERROR_OUT(ASN_PARSE_E, exit_dc);
}

if (oid != PBKDF2_OID) {
ERROR_OUT(ASN_PARSE_E, exit_tte);
ERROR_OUT(ASN_PARSE_E, exit_dc);
}
}

if (GetSequence(input, &inOutIdx, &length, sz) <= 0) {
ERROR_OUT(ASN_PARSE_E, exit_tte);
ERROR_OUT(ASN_PARSE_E, exit_dc);
}
/* Find the end of this SEQUENCE so we can check for the OPTIONAL and
* DEFAULT items. */
seqEnd = inOutIdx + length;

ret = GetOctetString(input, &inOutIdx, &saltSz, sz);
if (ret < 0)
goto exit_tte;
goto exit_dc;

if (saltSz > MAX_SALT_SIZE) {
ERROR_OUT(ASN_PARSE_E, exit_tte);
ERROR_OUT(ASN_PARSE_E, exit_dc);
}

#ifdef WOLFSSL_SMALL_STACK
salt = (byte*)XMALLOC(MAX_SALT_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (salt == NULL) {
ERROR_OUT(MEMORY_E, exit_tte);
ERROR_OUT(MEMORY_E, exit_dc);
}
#endif

XMEMCPY(salt, &input[inOutIdx], saltSz);
inOutIdx += saltSz;

if (GetShortInt(input, &inOutIdx, &iterations, sz) < 0) {
ERROR_OUT(ASN_PARSE_E, exit_tte);
ERROR_OUT(ASN_PARSE_E, exit_dc);
}

/* OPTIONAL key length */
if (seqEnd > inOutIdx) {
word32 localIdx = inOutIdx;
byte tag;

if (GetASNTag(input, &localIdx, &tag, sz) < 0) {
ERROR_OUT(ASN_PARSE_E, exit_tte);
ERROR_OUT(ASN_PARSE_E, exit_dc);
}

if (tag == ASN_INTEGER &&
GetShortInt(input, &inOutIdx, &keySz, sz) < 0) {
ERROR_OUT(ASN_PARSE_E, exit_tte);
ERROR_OUT(ASN_PARSE_E, exit_dc);
}
}

/* DEFAULT HMAC is SHA-1 */
if (seqEnd > inOutIdx) {
if (GetAlgoId(input, &inOutIdx, &oid, oidHmacType, sz) < 0) {
ERROR_OUT(ASN_PARSE_E, exit_tte);
ERROR_OUT(ASN_PARSE_E, exit_dc);
}

shaOid = oid;
Expand All @@ -3863,51 +3866,83 @@ int ToTraditionalEnc(byte* input, word32 sz,const char* password,
#ifdef WOLFSSL_SMALL_STACK
cbcIv = (byte*)XMALLOC(MAX_IV_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (cbcIv == NULL) {
ERROR_OUT(MEMORY_E, exit_tte);
ERROR_OUT(MEMORY_E, exit_dc);
}
#endif

if (version == PKCS5v2) {
/* get encryption algo */
if (GetAlgoId(input, &inOutIdx, &oid, oidBlkType, sz) < 0) {
ERROR_OUT(ASN_PARSE_E, exit_tte);
ERROR_OUT(ASN_PARSE_E, exit_dc);
}

if (CheckAlgoV2(oid, &id, NULL) < 0) {
ERROR_OUT(ASN_PARSE_E, exit_tte); /* PKCS v2 algo id error */
ERROR_OUT(ASN_PARSE_E, exit_dc); /* PKCS v2 algo id error */
}

if (shaOid == 0)
shaOid = oid;

ret = GetOctetString(input, &inOutIdx, &length, sz);
if (ret < 0)
goto exit_tte;
goto exit_dc;

if (length > MAX_IV_SIZE) {
ERROR_OUT(ASN_PARSE_E, exit_tte);
ERROR_OUT(ASN_PARSE_E, exit_dc);
}

XMEMCPY(cbcIv, &input[inOutIdx], length);
inOutIdx += length;
}

ret = GetOctetString(input, &inOutIdx, &length, sz);
if (ret < 0)
goto exit_tte;
if (GetASNTag(input, &inOutIdx, &tag, sz) < 0) {
ERROR_OUT(ASN_PARSE_E, exit_dc);
}

if (tag != (ASN_CONTEXT_SPECIFIC | 0) && tag != ASN_OCTET_STRING) {
ERROR_OUT(ASN_PARSE_E, exit_dc);
}

if (GetLength(input, &inOutIdx, &length, sz) < 0) {
ERROR_OUT(ASN_PARSE_E, exit_dc);
}

ret = wc_CryptKey(password, passwordSz, salt, saltSz, iterations, id,
input + inOutIdx, length, version, cbcIv, 0, shaOid);

exit_tte:
exit_dc:
#ifdef WOLFSSL_SMALL_STACK
XFREE(salt, NULL, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(cbcIv, NULL, DYNAMIC_TYPE_TMP_BUFFER);
#endif

if (ret == 0) {
XMEMMOVE(input, input + inOutIdx, length);
ret = ToTraditional_ex(input, length, algId);
ret = length;
}

return ret;
}


/* Remove Encrypted PKCS8 header, move beginning of traditional to beginning
of input */
int ToTraditionalEnc(byte* input, word32 sz,const char* password,
int passwordSz, word32* algId)
{
int ret, length;
word32 inOutIdx = 0;

if (GetSequence(input, &inOutIdx, &length, sz) < 0) {
ret = ASN_PARSE_E;
}
else {
ret = DecryptContent(input + inOutIdx, sz - inOutIdx, password,
passwordSz);
if (ret > 0) {
XMEMMOVE(input, input + inOutIdx, ret);
ret = ToTraditional_ex(input, ret, algId);
}
}

return ret;
Expand Down Expand Up @@ -4124,165 +4159,6 @@ int EncryptContent(byte* input, word32 inputSz, byte* out, word32* outSz,
}


/* decrypt PKCS
*
* NOTE: input buffer is overwritten with decrypted data!
*
* input[in/out] data to decrypt and results are written to
* sz size of input buffer
* password password if used. Can be NULL for no password
* passwordSz size of password buffer
*
* returns the total size of decrypted content on success.
*/
int DecryptContent(byte* input, word32 sz,const char* password, int passwordSz)
{
word32 inOutIdx = 0, seqEnd, oid;
int ret = 0;
int first, second, length = 0, version, saltSz, id;
int iterations = 0, keySz = 0;
#ifdef WOLFSSL_SMALL_STACK
byte* salt = NULL;
byte* cbcIv = NULL;
#else
byte salt[MAX_SALT_SIZE];
byte cbcIv[MAX_IV_SIZE];
#endif
byte tag;

if (GetAlgoId(input, &inOutIdx, &oid, oidIgnoreType, sz) < 0) {
ERROR_OUT(ASN_PARSE_E, exit_dc);
}

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, NULL) < 0) {
ERROR_OUT(ASN_INPUT_E, exit_dc); /* Algo ID error */
}

if (version == PKCS5v2) {
if (GetSequence(input, &inOutIdx, &length, sz) < 0) {
ERROR_OUT(ASN_PARSE_E, exit_dc);
}

if (GetAlgoId(input, &inOutIdx, &oid, oidKdfType, sz) < 0) {
ERROR_OUT(ASN_PARSE_E, exit_dc);
}

if (oid != PBKDF2_OID) {
ERROR_OUT(ASN_PARSE_E, exit_dc);
}
}

if (GetSequence(input, &inOutIdx, &length, sz) <= 0) {
ERROR_OUT(ASN_PARSE_E, exit_dc);
}
/* Find the end of this SEQUENCE so we can check for the OPTIONAL and
* DEFAULT items. */
seqEnd = inOutIdx + length;

ret = GetOctetString(input, &inOutIdx, &saltSz, sz);
if (ret < 0)
goto exit_dc;

if (saltSz > MAX_SALT_SIZE) {
ERROR_OUT(ASN_PARSE_E, exit_dc);
}

#ifdef WOLFSSL_SMALL_STACK
salt = (byte*)XMALLOC(MAX_SALT_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (salt == NULL) {
ERROR_OUT(MEMORY_E, exit_dc);
}
#endif

XMEMCPY(salt, &input[inOutIdx], saltSz);
inOutIdx += saltSz;

if (GetShortInt(input, &inOutIdx, &iterations, sz) < 0) {
ERROR_OUT(ASN_PARSE_E, exit_dc);
}

/* OPTIONAL key length */
if (seqEnd > inOutIdx) {
word32 localIdx = inOutIdx;

if (GetASNTag(input, &localIdx, &tag, sz) < 0) {
ERROR_OUT(ASN_PARSE_E, exit_dc);
}

if (tag == ASN_INTEGER &&
GetShortInt(input, &inOutIdx, &keySz, sz) < 0) {
ERROR_OUT(ASN_PARSE_E, exit_dc);
}
}

/* DEFAULT HMAC is SHA-1 */
if (seqEnd > inOutIdx) {
if (GetAlgoId(input, &inOutIdx, &oid, oidHmacType, sz) < 0) {
ERROR_OUT(ASN_PARSE_E, exit_dc);
}
}

#ifdef WOLFSSL_SMALL_STACK
cbcIv = (byte*)XMALLOC(MAX_IV_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (cbcIv == NULL) {
ERROR_OUT(MEMORY_E, exit_dc);
}
#endif

if (version == PKCS5v2) {
/* get encryption algo */
if (GetAlgoId(input, &inOutIdx, &oid, oidBlkType, sz) < 0) {
ERROR_OUT(ASN_PARSE_E, exit_dc);
}

if (CheckAlgoV2(oid, &id, NULL) < 0) {
ERROR_OUT(ASN_PARSE_E, exit_dc); /* PKCS v2 algo id error */
}

ret = GetOctetString(input, &inOutIdx, &length, sz);
if (ret < 0)
goto exit_dc;

if (length > MAX_IV_SIZE) {
ERROR_OUT(ASN_PARSE_E, exit_dc);
}

XMEMCPY(cbcIv, &input[inOutIdx], length);
inOutIdx += length;
}

if (GetASNTag(input, &inOutIdx, &tag, sz) < 0) {
ERROR_OUT(ASN_PARSE_E, exit_dc);
}

if (tag != (ASN_CONTEXT_SPECIFIC | 0)) {
ERROR_OUT(ASN_PARSE_E, exit_dc);
}

if (GetLength(input, &inOutIdx, &length, sz) < 0) {
ERROR_OUT(ASN_PARSE_E, exit_dc);
}

ret = wc_CryptKey(password, passwordSz, salt, saltSz, iterations, id,
input + inOutIdx, length, version, cbcIv, 0, 0);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For reference the bug was here on the last arg of wc_CryptKey call, which was not providing shaOid on the last arg.


exit_dc:

#ifdef WOLFSSL_SMALL_STACK
XFREE(salt, NULL, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(cbcIv, NULL, DYNAMIC_TYPE_TMP_BUFFER);
#endif

if (ret == 0) {
XMEMMOVE(input, input + inOutIdx, length);
ret = length;
}

return ret;
}
#endif /* HAVE_PKCS12 */
#endif /* NO_PWDBASED */

Expand Down