commit 2fb51b9e4d390f889c109e1765c3284b5d6f5fb8 Author: Ingo Franzki Date: Fri Jan 12 09:36:27 2024 +0100 Constant time fixes for C_Decrypt return code handling Return code handling of C_Decrypt, C_DecryptUpdate, and C_DecryptFinal must be performed in a constant time manner for RSA mechanisms. Otherwise it may cause a timing side channel that may be used to perform a Bleichenbacher style attack. Handling of error situations with CKR_BUFFER_TOO_SMALL or size-query calls, where the output buffer is NULL and the required size of the output buffer is to be returned, do not need to be performed in constant time, since these cases are shortcut anyway, and the result is only dependent on the modulus size of the RSA key (which is public information anyway). Signed-off-by: Ingo Franzki diff --git a/usr/lib/common/new_host.c b/usr/lib/common/new_host.c index 8a1e8723..bbb0f601 100644 --- a/usr/lib/common/new_host.c +++ b/usr/lib/common/new_host.c @@ -47,6 +47,7 @@ #include "trace.h" #include "slotmgr.h" #include "attributes.h" +#include "constant_time.h" #include "../api/apiproto.h" #include "../api/policy.h" @@ -2345,6 +2346,7 @@ CK_RV SC_Decrypt(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, SESSION *sess = NULL; CK_BBOOL length_only = FALSE; CK_RV rc = CKR_OK; + unsigned int mask; if (tokdata->initialized == FALSE) { TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); @@ -2377,11 +2379,19 @@ CK_RV SC_Decrypt(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, rc = decr_mgr_decrypt(tokdata, sess, length_only, &sess->decr_ctx, pEncryptedData, ulEncryptedDataLen, pData, pulDataLen); - if (!is_rsa_mechanism(sess->decr_ctx.mech.mechanism) && rc != CKR_OK) + /* (!is_rsa_mechanism(sess->decr_ctx.mech.mechanism) && rc != CKR_OK) */ + mask = ~constant_time_is_zero( + is_rsa_mechanism(sess->decr_ctx.mech.mechanism)); + mask &= ~constant_time_eq(rc, CKR_OK); + if (mask) TRACE_DEVEL("decr_mgr_decrypt() failed.\n"); done: - if (rc != CKR_BUFFER_TOO_SMALL && (rc != CKR_OK || length_only != TRUE)) { + /* (rc != CKR_BUFFER_TOO_SMALL && (rc != CKR_OK || length_only != TRUE)) */ + mask = ~constant_time_eq(rc, CKR_OK); + mask |= constant_time_is_zero(length_only); + mask &= ~constant_time_eq(rc, CKR_BUFFER_TOO_SMALL); + if (mask) { if (sess) decr_mgr_cleanup(tokdata, sess, &sess->decr_ctx); } @@ -2404,6 +2414,7 @@ CK_RV SC_DecryptUpdate(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, SESSION *sess = NULL; CK_BBOOL length_only = FALSE; CK_RV rc = CKR_OK; + unsigned int mask; if (tokdata->initialized == FALSE) { TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); @@ -2436,11 +2447,18 @@ CK_RV SC_DecryptUpdate(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, rc = decr_mgr_decrypt_update(tokdata, sess, length_only, &sess->decr_ctx, pEncryptedPart, ulEncryptedPartLen, pPart, pulPartLen); - if (!is_rsa_mechanism(sess->decr_ctx.mech.mechanism) && rc != CKR_OK) + /* (!is_rsa_mechanism(sess->decr_ctx.mech.mechanism) && rc != CKR_OK) */ + mask = ~constant_time_is_zero( + is_rsa_mechanism(sess->decr_ctx.mech.mechanism)); + mask &= ~constant_time_eq(rc, CKR_OK); + if (mask) TRACE_DEVEL("decr_mgr_decrypt_update() failed.\n"); done: - if (rc != CKR_OK && rc != CKR_BUFFER_TOO_SMALL && sess != NULL) { + /* (rc != CKR_OK && rc != CKR_BUFFER_TOO_SMALL */ + mask = ~constant_time_eq(rc, CKR_OK); + mask &= ~constant_time_eq(rc, CKR_BUFFER_TOO_SMALL); + if (mask) { if (sess) decr_mgr_cleanup(tokdata, sess, &sess->decr_ctx); } @@ -2462,6 +2480,7 @@ CK_RV SC_DecryptFinal(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, SESSION *sess = NULL; CK_BBOOL length_only = FALSE; CK_RV rc = CKR_OK; + unsigned int mask; if (tokdata->initialized == FALSE) { TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); @@ -2493,11 +2512,19 @@ CK_RV SC_DecryptFinal(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, rc = decr_mgr_decrypt_final(tokdata, sess, length_only, &sess->decr_ctx, pLastPart, pulLastPartLen); - if (!is_rsa_mechanism(sess->decr_ctx.mech.mechanism) && rc != CKR_OK) + /* (!is_rsa_mechanism(sess->decr_ctx.mech.mechanism) && rc != CKR_OK) */ + mask = ~constant_time_is_zero( + is_rsa_mechanism(sess->decr_ctx.mech.mechanism)); + mask &= ~constant_time_eq(rc, CKR_OK); + if (mask) TRACE_DEVEL("decr_mgr_decrypt_final() failed.\n"); done: - if (rc != CKR_BUFFER_TOO_SMALL && (rc != CKR_OK || length_only != TRUE)) { + /* (rc != CKR_BUFFER_TOO_SMALL && (rc != CKR_OK || length_only != TRUE)) */ + mask = ~constant_time_eq(rc, CKR_OK); + mask |= constant_time_is_zero(length_only); + mask &= ~constant_time_eq(rc, CKR_BUFFER_TOO_SMALL); + if (mask) { if (sess) decr_mgr_cleanup(tokdata, sess, &sess->decr_ctx); } diff --git a/usr/lib/ep11_stdll/ep11_specific.c b/usr/lib/ep11_stdll/ep11_specific.c index df1f68f9..42793955 100644 --- a/usr/lib/ep11_stdll/ep11_specific.c +++ b/usr/lib/ep11_stdll/ep11_specific.c @@ -10777,10 +10777,12 @@ CK_RV ep11tok_decrypt_final(STDLL_TokData_t * tokdata, SESSION * session, rc = constant_time_select(constant_time_eq(rc, CKR_OK), ep11_error_to_pkcs11_error(rc, session), rc); - if (rc != CKR_OK) { - TRACE_ERROR("%s rc=0x%lx\n", __func__, rc); - } else { - TRACE_INFO("%s rc=0x%lx\n", __func__, rc); + if (!is_rsa_mechanism(ctx->mech.mechanism)) { + if (rc != CKR_OK) { + TRACE_ERROR("%s rc=0x%lx\n", __func__, rc); + } else { + TRACE_INFO("%s rc=0x%lx\n", __func__, rc); + } } done: @@ -10836,10 +10838,12 @@ CK_RV ep11tok_decrypt(STDLL_TokData_t * tokdata, SESSION * session, rc = constant_time_select(constant_time_eq(rc, CKR_OK), ep11_error_to_pkcs11_error(rc, session), rc); - if (rc != CKR_OK) { - TRACE_ERROR("%s rc=0x%lx\n", __func__, rc); - } else { - TRACE_INFO("%s rc=0x%lx\n", __func__, rc); + if (!is_rsa_mechanism(ctx->mech.mechanism)) { + if (rc != CKR_OK) { + TRACE_ERROR("%s rc=0x%lx\n", __func__, rc); + } else { + TRACE_INFO("%s rc=0x%lx\n", __func__, rc); + } } done: @@ -10901,10 +10905,12 @@ CK_RV ep11tok_decrypt_update(STDLL_TokData_t * tokdata, SESSION * session, rc = constant_time_select(constant_time_eq(rc, CKR_OK), ep11_error_to_pkcs11_error(rc, session), rc); - if (rc != CKR_OK) { - TRACE_ERROR("%s rc=0x%lx\n", __func__, rc); - } else { - TRACE_INFO("%s rc=0x%lx\n", __func__, rc); + if (!is_rsa_mechanism(ctx->mech.mechanism)) { + if (rc != CKR_OK) { + TRACE_ERROR("%s rc=0x%lx\n", __func__, rc); + } else { + TRACE_INFO("%s rc=0x%lx\n", __func__, rc); + } } done: diff --git a/usr/lib/ep11_stdll/new_host.c b/usr/lib/ep11_stdll/new_host.c index ce18f729..f7ee0546 100644 --- a/usr/lib/ep11_stdll/new_host.c +++ b/usr/lib/ep11_stdll/new_host.c @@ -37,6 +37,7 @@ #include "slotmgr.h" #include "attributes.h" #include "ep11_specific.h" +#include "constant_time.h" #include "../api/apiproto.h" #include "../api/policy.h" @@ -2465,6 +2466,7 @@ CK_RV SC_Decrypt(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, SESSION *sess = NULL; CK_BBOOL length_only = FALSE; CK_RV rc = CKR_OK; + unsigned int mask; if (tokdata->initialized == FALSE) { TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); @@ -2512,17 +2514,29 @@ CK_RV SC_Decrypt(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, length_only, sess->decr_ctx.key, pEncryptedData, ulEncryptedDataLen, pData, pulDataLen); - if (!is_rsa_mechanism(sess->decr_ctx.mech.mechanism) && rc != CKR_OK) + /* (!is_rsa_mechanism(sess->decr_ctx.mech.mechanism) && rc != CKR_OK) */ + mask = ~constant_time_is_zero( + is_rsa_mechanism(sess->decr_ctx.mech.mechanism)); + mask &= ~constant_time_eq(rc, CKR_OK); + if (mask) TRACE_DEVEL("ep11tok_decrypt_single() failed.\n"); } else { rc = ep11tok_decrypt(tokdata, sess, pEncryptedData, ulEncryptedDataLen, pData, pulDataLen); - if (!is_rsa_mechanism(sess->decr_ctx.mech.mechanism) && rc != CKR_OK) + /* (!is_rsa_mechanism(sess->decr_ctx.mech.mechanism) && rc != CKR_OK) */ + mask = ~constant_time_is_zero( + is_rsa_mechanism(sess->decr_ctx.mech.mechanism)); + mask &= ~constant_time_eq(rc, CKR_OK); + if (mask) TRACE_DEVEL("ep11tok_decrypt() failed.\n"); } done: - if (rc != CKR_BUFFER_TOO_SMALL && (rc != CKR_OK || length_only != TRUE)) { + /* (rc != CKR_BUFFER_TOO_SMALL && (rc != CKR_OK || length_only != TRUE)) */ + mask = ~constant_time_eq(rc, CKR_OK); + mask |= constant_time_is_zero(length_only); + mask &= ~constant_time_eq(rc, CKR_BUFFER_TOO_SMALL); + if (mask) { if (sess) decr_mgr_cleanup(tokdata, sess, &sess->decr_ctx); } @@ -2544,6 +2558,7 @@ CK_RV SC_DecryptUpdate(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, { SESSION *sess = NULL; CK_RV rc = CKR_OK; + unsigned int mask; if (tokdata->initialized == FALSE) { TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); @@ -2595,11 +2610,18 @@ CK_RV SC_DecryptUpdate(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, rc = ep11tok_decrypt_update(tokdata, sess, pEncryptedPart, ulEncryptedPartLen, pPart, pulPartLen); - if (!is_rsa_mechanism(sess->decr_ctx.mech.mechanism) && rc != CKR_OK) + /* (!is_rsa_mechanism(sess->decr_ctx.mech.mechanism) && rc != CKR_OK) */ + mask = ~constant_time_is_zero( + is_rsa_mechanism(sess->decr_ctx.mech.mechanism)); + mask &= ~constant_time_eq(rc, CKR_OK); + if (mask) TRACE_DEVEL("ep11tok_decrypt_update() failed.\n"); done: - if (rc != CKR_OK && rc != CKR_BUFFER_TOO_SMALL && sess != NULL) { + /* (rc != CKR_OK && rc != CKR_BUFFER_TOO_SMALL */ + mask = ~constant_time_eq(rc, CKR_OK); + mask &= ~constant_time_eq(rc, CKR_BUFFER_TOO_SMALL); + if (mask) { if (sess) decr_mgr_cleanup(tokdata, sess, &sess->decr_ctx); } @@ -2621,6 +2643,7 @@ CK_RV SC_DecryptFinal(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, SESSION *sess = NULL; CK_BBOOL length_only = FALSE; CK_RV rc = CKR_OK; + unsigned int mask; if (tokdata->initialized == FALSE) { TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); @@ -2669,10 +2692,18 @@ CK_RV SC_DecryptFinal(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, } rc = ep11tok_decrypt_final(tokdata, sess, pLastPart, pulLastPartLen); - if (!is_rsa_mechanism(sess->decr_ctx.mech.mechanism) && rc != CKR_OK) + /* (!is_rsa_mechanism(sess->decr_ctx.mech.mechanism) && rc != CKR_OK) */ + mask = ~constant_time_is_zero( + is_rsa_mechanism(sess->decr_ctx.mech.mechanism)); + mask &= ~constant_time_eq(rc, CKR_OK); + if (mask) TRACE_DEVEL("ep11tok_decrypt_final() failed.\n"); done: - if (rc != CKR_BUFFER_TOO_SMALL && (rc != CKR_OK || length_only != TRUE)) { + /* (rc != CKR_BUFFER_TOO_SMALL && (rc != CKR_OK || length_only != TRUE)) */ + mask = ~constant_time_eq(rc, CKR_OK); + mask |= constant_time_is_zero(length_only); + mask &= ~constant_time_eq(rc, CKR_BUFFER_TOO_SMALL); + if (mask) { if (sess) decr_mgr_cleanup(tokdata, sess, &sess->decr_ctx); } diff --git a/usr/lib/icsf_stdll/new_host.c b/usr/lib/icsf_stdll/new_host.c index 115fd40b..192fe128 100644 --- a/usr/lib/icsf_stdll/new_host.c +++ b/usr/lib/icsf_stdll/new_host.c @@ -35,6 +35,8 @@ #include "slotmgr.h" #include "attributes.h" #include "icsf_specific.h" +#include "constant_time.h" + #include "../api/apiproto.h" #include "../api/policy.h" @@ -1768,6 +1770,7 @@ CK_RV SC_Decrypt(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, SESSION *sess = NULL; CK_BBOOL length_only = FALSE; CK_RV rc = CKR_OK; + unsigned int mask; if (tokdata->initialized == FALSE) { TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); @@ -1801,11 +1804,19 @@ CK_RV SC_Decrypt(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, rc = icsftok_decrypt(tokdata, sess, pEncryptedData, ulEncryptedDataLen, pData, pulDataLen); - if (!is_rsa_mechanism(sess->decr_ctx.mech.mechanism) && rc != CKR_OK) + /* (!is_rsa_mechanism(sess->decr_ctx.mech.mechanism) && rc != CKR_OK) */ + mask = ~constant_time_is_zero( + is_rsa_mechanism(sess->decr_ctx.mech.mechanism)); + mask &= ~constant_time_eq(rc, CKR_OK); + if (mask) TRACE_DEVEL("icsftok_decrypt() failed.\n"); done: - if (rc != CKR_BUFFER_TOO_SMALL && (rc != CKR_OK || length_only != TRUE)) { + /* (rc != CKR_BUFFER_TOO_SMALL && (rc != CKR_OK || length_only != TRUE)) */ + mask = ~constant_time_eq(rc, CKR_OK); + mask |= constant_time_is_zero(length_only); + mask &= ~constant_time_eq(rc, CKR_BUFFER_TOO_SMALL); + if (mask) { if (sess) decr_mgr_cleanup(tokdata, sess, &sess->decr_ctx); } @@ -1827,6 +1838,7 @@ CK_RV SC_DecryptUpdate(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, { SESSION *sess = NULL; CK_RV rc = CKR_OK; + unsigned int mask; if (tokdata->initialized == FALSE) { TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); @@ -1857,11 +1869,18 @@ CK_RV SC_DecryptUpdate(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, rc = icsftok_decrypt_update(tokdata, sess, pEncryptedPart, ulEncryptedPartLen, pPart, pulPartLen); - if (!is_rsa_mechanism(sess->decr_ctx.mech.mechanism) && rc != CKR_OK) + /* (!is_rsa_mechanism(sess->decr_ctx.mech.mechanism) && rc != CKR_OK) */ + mask = ~constant_time_is_zero( + is_rsa_mechanism(sess->decr_ctx.mech.mechanism)); + mask &= ~constant_time_eq(rc, CKR_OK); + if (mask) TRACE_DEVEL("icsftok_decrypt_update() failed.\n"); done: - if (rc != CKR_OK && rc != CKR_BUFFER_TOO_SMALL && sess != NULL) { + /* (rc != CKR_OK && rc != CKR_BUFFER_TOO_SMALL */ + mask = ~constant_time_eq(rc, CKR_OK); + mask &= ~constant_time_eq(rc, CKR_BUFFER_TOO_SMALL); + if (mask) { if (sess) decr_mgr_cleanup(tokdata, sess, &sess->decr_ctx); } @@ -1883,6 +1902,7 @@ CK_RV SC_DecryptFinal(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, SESSION *sess = NULL; CK_BBOOL length_only = FALSE; CK_RV rc = CKR_OK; + unsigned int mask; if (tokdata->initialized == FALSE) { TRACE_ERROR("%s\n", ock_err(ERR_CRYPTOKI_NOT_INITIALIZED)); @@ -1915,10 +1935,18 @@ CK_RV SC_DecryptFinal(STDLL_TokData_t *tokdata, ST_SESSION_HANDLE *sSession, length_only = TRUE; rc = icsftok_decrypt_final(tokdata, sess, pLastPart, pulLastPartLen); - if (!is_rsa_mechanism(sess->decr_ctx.mech.mechanism) && rc != CKR_OK) + /* (!is_rsa_mechanism(sess->decr_ctx.mech.mechanism) && rc != CKR_OK) */ + mask = ~constant_time_is_zero( + is_rsa_mechanism(sess->decr_ctx.mech.mechanism)); + mask &= ~constant_time_eq(rc, CKR_OK); + if (mask) TRACE_DEVEL("icsftok_decrypt_final() failed.\n"); done: - if (rc != CKR_BUFFER_TOO_SMALL && (rc != CKR_OK || length_only != TRUE)) { + /* (rc != CKR_BUFFER_TOO_SMALL && (rc != CKR_OK || length_only != TRUE)) */ + mask = ~constant_time_eq(rc, CKR_OK); + mask |= constant_time_is_zero(length_only); + mask &= ~constant_time_eq(rc, CKR_BUFFER_TOO_SMALL); + if (mask) { if (sess) decr_mgr_cleanup(tokdata, sess, &sess->decr_ctx); }