From 47f7dfaf574fa433c9169b7cb541143b77159315 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Tue, 14 Nov 2023 12:56:23 -0500 Subject: [PATCH] Side-channel proofing PKCS#1 1.5 paths Fixes CVE-2023-6258 (Marvin) Signed-off-by: Simo Sorce --- src/asymmetric_cipher.c | 16 +++++++++++++++- src/interface.c | 19 +++++++++++++++++++ src/interface.h | 6 ++++++ src/util.h | 14 ++++++++++++++ 4 files changed, 54 insertions(+), 1 deletion(-) diff --git a/src/asymmetric_cipher.c b/src/asymmetric_cipher.c index a4f33083..7af90bed 100644 --- a/src/asymmetric_cipher.c +++ b/src/asymmetric_cipher.c @@ -296,12 +296,26 @@ static int p11prov_rsaenc_decrypt(void *ctx, unsigned char *out, size_t *outlen, goto endsess; } + /* Special handling against PKCS#1 1.5 side channel leaking */ + if (mechanism.mechanism == CKM_RSA_PKCS) { + CK_ULONG cond; + ret = side_channel_free_Decrypt(encctx->provctx, sess, (void *)in, + inlen, out, &out_size); + /* the error case need to be handled in a side-channel free way, so + * conditionals need to be constant time. Always setting outlen is + * fine because out_size is initialized to the value of outlen + * and the value should not matter in an error condition anyway */ + *outlen = out_size; + cond = constant_equal(ret, CKR_OK); + result = constant_select_int(cond, RET_OSSL_OK, RET_OSSL_ERR); + goto endsess; + } + ret = p11prov_Decrypt(encctx->provctx, sess, (void *)in, inlen, out, &out_size); if (ret != CKR_OK) { goto endsess; } - *outlen = out_size; result = RET_OSSL_OK; diff --git a/src/interface.c b/src/interface.c index 6efa3173..77ef943a 100644 --- a/src/interface.c +++ b/src/interface.c @@ -450,3 +450,22 @@ CK_RV p11prov_module_reinit(P11PROV_MODULE *mctx) /* ------------- LOCKED SECTION */ return ret; } + +/* This is needed to avoid side channels in the PKCS 1.5 decryption case */ +CK_RV side_channel_free_Decrypt(P11PROV_CTX *ctx, CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pEncryptedData, + CK_ULONG ulEncryptedDataLen, CK_BYTE_PTR pData, + CK_ULONG_PTR pulDataLen) +{ + P11PROV_INTERFACE *intf = p11prov_ctx_get_interface(ctx); + CK_RV ret = CKR_GENERAL_ERROR; + if (!intf) { + P11PROV_raise(ctx, ret, "Can't get module interfaces"); + return ret; + } + P11PROV_debug("Calling C_Decrypt"); + /* Must not add any conditionals based on return value, so we just return + * straight */ + return intf->Decrypt(hSession, pEncryptedData, ulEncryptedDataLen, pData, + pulDataLen); +} diff --git a/src/interface.h b/src/interface.h index 535b885f..37e835cf 100644 --- a/src/interface.h +++ b/src/interface.h @@ -127,4 +127,10 @@ CK_RV p11prov_SeedRandom(P11PROV_CTX *ctx, CK_SESSION_HANDLE hSession, CK_RV p11prov_GenerateRandom(P11PROV_CTX *ctx, CK_SESSION_HANDLE hSession, CK_BYTE_PTR RandomData, CK_ULONG ulRandomLen); +/* Special side-channel free path against PKCS#1 1.5 side channel leaking */ +CK_RV side_channel_free_Decrypt(P11PROV_CTX *ctx, CK_SESSION_HANDLE hSession, + CK_BYTE_PTR pEncryptedData, + CK_ULONG ulEncryptedDataLen, CK_BYTE_PTR pData, + CK_ULONG_PTR pulDataLen); + #endif /* _INTERFACE_H */ diff --git a/src/util.h b/src/util.h index c225216d..8443747a 100644 --- a/src/util.h +++ b/src/util.h @@ -100,4 +100,18 @@ CK_RV p11prov_mutex_destroy(P11PROV_CTX *provctx, pthread_mutex_t *lock, void p11prov_force_rwlock_reinit(pthread_rwlock_t *lock); +static inline CK_ULONG constant_equal(CK_ULONG a, CK_ULONG b) +{ + return ((a ^ b) - 1U) >> (sizeof(CK_ULONG) * 8 - 1); +} + +static inline int constant_select_int(CK_ULONG cond, int a, int b) +{ + volatile unsigned int A = (unsigned int)a; + volatile unsigned int B = (unsigned int)b; + volatile unsigned int mask = -(unsigned int)cond; + + return (int)((A & mask) | (B & ~mask)); +} + #endif /* _UTIL_H */