Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Constant time RSA PKCS#1 v1.5 depadding #2948

Merged
merged 8 commits into from
Feb 5, 2024
Prev Previous commit
Next Next commit
framework-pkcs15.c: Handle PKCS#1 v1.5 depadding constant-time
In order to not disclose time side-channel when the depadding
fails, do the same operations as for case when depadding ends
with success.
  • Loading branch information
xhanulik committed Jan 31, 2024
commit a8ac5930ab8f2da5cb93793d05389761c342f995
54 changes: 41 additions & 13 deletions src/pkcs11/framework-pkcs15.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/

#include "common/constant-time.h"
#include "config.h"
#include <stdlib.h>
#include <string.h>
Expand Down Expand Up @@ -4520,7 +4521,8 @@ pkcs15_prkey_decrypt(struct sc_pkcs11_session *session, void *obj,
struct pkcs15_fw_data *fw_data = NULL;
struct pkcs15_prkey_object *prkey;
unsigned char decrypted[512]; /* FIXME: Will not work for keys above 4096 bits */
int buff_too_small, rv, flags = 0, prkey_has_path = 0;
int rv, flags = 0, prkey_has_path = 0;
CK_ULONG mask, good, rv_pkcs11;

if (pulDataLen == NULL) {
/* This is call from the C_DecyptInit function */
Expand Down Expand Up @@ -4609,27 +4611,53 @@ pkcs15_prkey_decrypt(struct sc_pkcs11_session *session, void *obj,
rv = sc_pkcs15_decipher(fw_data->p15_card, prkey->prv_p15obj, flags,
pEncryptedData, ulEncryptedDataLen, decrypted, sizeof(decrypted), pMechanism);

if (rv < 0 && !sc_pkcs11_conf.lock_login && !prkey_has_path)
/* skip for PKCS#1 v1.5 padding prevent side channel attack */
if (!(flags & SC_ALGORITHM_RSA_PAD_PKCS1) &&
rv < 0 && !sc_pkcs11_conf.lock_login && !prkey_has_path)
if (reselect_app_df(fw_data->p15_card) == SC_SUCCESS)
rv = sc_pkcs15_decipher(fw_data->p15_card, prkey->prv_p15obj, flags,
pEncryptedData, ulEncryptedDataLen, decrypted, sizeof(decrypted), pMechanism);

sc_unlock(p11card->card);

sc_log(context, "Decryption complete. Result %d.", rv);
sc_log(context, "Decryption complete.");

if (rv < 0)
return sc_to_cryptoki_error(rv, "C_Decrypt");
/* Handle following code in constant-time
* to prevent Marvin attack for PKCS#1 v1.5 padding. */

buff_too_small = (*pulDataLen < (CK_ULONG)rv);
*pulDataLen = rv;
if (pData == NULL_PTR)
return CKR_OK;
if (buff_too_small)
return CKR_BUFFER_TOO_SMALL;
memcpy(pData, decrypted, *pulDataLen);
/* only padding error must be handled in constant-time way,
* other error can be returned straight away */
if ((~constant_time_eq_s(rv, SC_ERROR_WRONG_PADDING) & constant_time_lt_s(sizeof(decrypted), rv)))
return sc_to_cryptoki_error(rv, "C_Decrypt");

return CKR_OK;
/* check rv for padding error */
good = ~constant_time_eq_s(rv, SC_ERROR_WRONG_PADDING);
rv_pkcs11 = sc_to_cryptoki_error(SC_ERROR_WRONG_PADDING, "C_Decrypt");
rv_pkcs11 = constant_time_select_s(good, CKR_OK, rv_pkcs11);

if (pData == NULL_PTR) {
/* set length only if no error */
*pulDataLen = constant_time_select_s(good, rv, *pulDataLen);
/* return error only if original rv < 0 */
return rv_pkcs11;
}

/* check whether *pulDataLen < rv and set return value for small output buffer */
mask = good & constant_time_lt_s(*pulDataLen, rv);
rv_pkcs11 = constant_time_select_s(mask, CKR_BUFFER_TOO_SMALL, rv_pkcs11);
good &= ~mask;

/* move everything from decrypted into out buffer constant-time, if rv is ok */
for (CK_ULONG i = 0; i < *pulDataLen; i++) { /* iterate over whole pData to not disclose real depadded length */
CK_ULONG msg_index;
mask = good & constant_time_lt_s(i, sizeof(decrypted)); /* i should be in the bounds of decrypted */
mask &= constant_time_lt_s(i, constant_time_select_s(good, rv, 0)); /* check that is in bounds of depadded message */
msg_index = constant_time_select_s(mask, i, 0);
pData[i] = constant_time_select_8(mask, decrypted[msg_index], pData[i]);
}
*pulDataLen = constant_time_select_s(good, rv, *pulDataLen);
/* do not log error code to prevent side channel attack */
return rv_pkcs11;
}


Expand Down