make pkcs#1 decode functions constant-time

as proposed in RFC 3447 only one error return code is used when there are
errors while decoding the pkcs#1 format.
also, all steps are executed and only the "output" is skipped if something
went wrong.

Sorry this could break backwards compatibility, since there's no more
BUFFER_OVERFLOW messaging.
Former error-handling code could also be affected because now there's only
OK as return code in cases where "res" is also set to '1'.
This commit is contained in:
Steffen Jaeckel 2014-11-13 22:26:59 +01:00
parent e57c92fd23
commit 1e9e98aa0d
2 changed files with 30 additions and 33 deletions

View File

@ -28,7 +28,7 @@
@param out [out] Destination of decoding @param out [out] Destination of decoding
@param outlen [in/out] The max size and resulting size of the decoding @param outlen [in/out] The max size and resulting size of the decoding
@param res [out] Result of decoding, 1==valid, 0==invalid @param res [out] Result of decoding, 1==valid, 0==invalid
@return CRYPT_OK if successful (even if invalid) @return CRYPT_OK if successful
*/ */
int pkcs_1_oaep_decode(const unsigned char *msg, unsigned long msglen, int pkcs_1_oaep_decode(const unsigned char *msg, unsigned long msglen,
const unsigned char *lparam, unsigned long lparamlen, const unsigned char *lparam, unsigned long lparamlen,
@ -38,7 +38,7 @@ int pkcs_1_oaep_decode(const unsigned char *msg, unsigned long msglen,
{ {
unsigned char *DB, *seed, *mask; unsigned char *DB, *seed, *mask;
unsigned long hLen, x, y, modulus_len; unsigned long hLen, x, y, modulus_len;
int err; int err, ret;
LTC_ARGCHK(msg != NULL); LTC_ARGCHK(msg != NULL);
LTC_ARGCHK(out != NULL); LTC_ARGCHK(out != NULL);
@ -85,10 +85,12 @@ int pkcs_1_oaep_decode(const unsigned char *msg, unsigned long msglen,
*/ */
err = CRYPT_OK;
ret = CRYPT_OK;
/* must have leading 0x00 byte */ /* must have leading 0x00 byte */
if (msg[0] != 0x00) { if (msg[0] != 0x00) {
err = CRYPT_OK; ret = CRYPT_INVALID_PACKET;
goto LBL_ERR;
} }
/* now read the masked seed */ /* now read the masked seed */
@ -137,8 +139,7 @@ int pkcs_1_oaep_decode(const unsigned char *msg, unsigned long msglen,
/* compare the lhash'es */ /* compare the lhash'es */
if (mem_neq(seed, DB, hLen) != 0) { if (mem_neq(seed, DB, hLen) != 0) {
err = CRYPT_OK; ret = CRYPT_INVALID_PACKET;
goto LBL_ERR;
} }
/* now zeroes before a 0x01 */ /* now zeroes before a 0x01 */
@ -146,28 +147,27 @@ int pkcs_1_oaep_decode(const unsigned char *msg, unsigned long msglen,
/* step... */ /* step... */
} }
/* error out if wasn't 0x01 */ /* error if wasn't 0x01 */
if (x == (modulus_len - hLen - 1) || DB[x] != 0x01) { if (x == (modulus_len - hLen - 1) || DB[x] != 0x01) {
err = CRYPT_INVALID_PACKET; ret = CRYPT_INVALID_PACKET;
goto LBL_ERR;
} }
/* rest is the message (and skip 0x01) */ /* rest is the message (and skip 0x01) */
if ((modulus_len - hLen - 1 - ++x) > *outlen) { if ((modulus_len - hLen - 1 - ++x) > *outlen) {
*outlen = modulus_len - hLen - 1 - x; ret = CRYPT_INVALID_PACKET;
err = CRYPT_BUFFER_OVERFLOW;
goto LBL_ERR;
} }
/* copy message */ if (ret == CRYPT_OK) {
*outlen = modulus_len - hLen - 1 - x; /* copy message */
XMEMCPY(out, DB + x, modulus_len - hLen - 1 - x); *outlen = modulus_len - hLen - 1 - x;
x += modulus_len - hLen - 1; XMEMCPY(out, DB + x, modulus_len - hLen - 1 - x);
x += modulus_len - hLen - 1;
/* valid packet */ /* valid packet */
*res = 1; *res = 1;
}
err = ret;
err = CRYPT_OK;
LBL_ERR: LBL_ERR:
#ifdef LTC_CLEAN_STACK #ifdef LTC_CLEAN_STACK
zeromem(DB, modulus_len); zeromem(DB, modulus_len);

View File

@ -27,7 +27,7 @@
* @param outlen [in/out] The max size and resulting size of the decoding * @param outlen [in/out] The max size and resulting size of the decoding
* @param is_valid [out] Boolean whether the padding was valid * @param is_valid [out] Boolean whether the padding was valid
* *
* @return CRYPT_OK if successful (even if invalid) * @return CRYPT_OK if successful
*/ */
int pkcs_1_v1_5_decode(const unsigned char *msg, int pkcs_1_v1_5_decode(const unsigned char *msg,
unsigned long msglen, unsigned long msglen,
@ -51,11 +51,12 @@ int pkcs_1_v1_5_decode(const unsigned char *msg,
return CRYPT_PK_INVALID_SIZE; return CRYPT_PK_INVALID_SIZE;
} }
result = CRYPT_OK;
/* separate encoded message */ /* separate encoded message */
if ((msg[0] != 0x00) || (msg[1] != (unsigned char)block_type)) { if ((msg[0] != 0x00) || (msg[1] != (unsigned char)block_type)) {
result = CRYPT_INVALID_PACKET; result = CRYPT_INVALID_PACKET;
goto bail;
} }
if (block_type == LTC_PKCS_1_EME) { if (block_type == LTC_PKCS_1_EME) {
@ -69,7 +70,6 @@ int pkcs_1_v1_5_decode(const unsigned char *msg,
/* There was no octet with hexadecimal value 0x00 to separate ps from m. /* There was no octet with hexadecimal value 0x00 to separate ps from m.
*/ */
result = CRYPT_INVALID_PACKET; result = CRYPT_INVALID_PACKET;
goto bail;
} }
} else { } else {
for (i = 2; i < modulus_len - 1; i++) { for (i = 2; i < modulus_len - 1; i++) {
@ -80,7 +80,6 @@ int pkcs_1_v1_5_decode(const unsigned char *msg,
if (msg[i] != 0) { if (msg[i] != 0) {
/* There was no octet with hexadecimal value 0x00 to separate ps from m. */ /* There was no octet with hexadecimal value 0x00 to separate ps from m. */
result = CRYPT_INVALID_PACKET; result = CRYPT_INVALID_PACKET;
goto bail;
} }
ps_len = i - 2; ps_len = i - 2;
@ -91,22 +90,20 @@ int pkcs_1_v1_5_decode(const unsigned char *msg,
/* The length of ps is less than 8 octets. /* The length of ps is less than 8 octets.
*/ */
result = CRYPT_INVALID_PACKET; result = CRYPT_INVALID_PACKET;
goto bail;
} }
if (*outlen < (msglen - (2 + ps_len + 1))) { if (*outlen < (msglen - (2 + ps_len + 1))) {
*outlen = msglen - (2 + ps_len + 1); result = CRYPT_INVALID_PACKET;
result = CRYPT_BUFFER_OVERFLOW;
goto bail;
} }
*outlen = (msglen - (2 + ps_len + 1)); if (result == CRYPT_OK) {
XMEMCPY(out, &msg[2 + ps_len + 1], *outlen); *outlen = (msglen - (2 + ps_len + 1));
XMEMCPY(out, &msg[2 + ps_len + 1], *outlen);
/* valid packet */
*is_valid = 1;
}
/* valid packet */
*is_valid = 1;
result = CRYPT_OK;
bail:
return result; return result;
} /* pkcs_1_v1_5_decode */ } /* pkcs_1_v1_5_decode */