diff --git a/SOURCES/opencryptoki-v3.21.0-CVE-2024-0914-part01.patch b/SOURCES/opencryptoki-v3.21.0-CVE-2024-0914-part01.patch new file mode 100644 index 0000000..7e07e1b --- /dev/null +++ b/SOURCES/opencryptoki-v3.21.0-CVE-2024-0914-part01.patch @@ -0,0 +1,153 @@ +commit 47c55113f81794408a0afda2e19e1a5aa40d2212 +Author: Ingo Franzki +Date: Tue Dec 12 17:16:56 2023 +0100 + + COMMON: Update rsa_parse_block_type_2() to not leak the message length + + Take the implementation of OpenSSL function RSA_padding_check_PKCS1_type_2() + in crypto/rsa/rsa_pk1.c instead of ossl_rsa_padding_check_PKCS1_type_2(), since + the latter leaks the message size. + + Signed-off-by: Ingo Franzki + +diff --git a/usr/lib/common/mech_rsa.c b/usr/lib/common/mech_rsa.c +index 326c5795..7bab1a84 100644 +--- a/usr/lib/common/mech_rsa.c ++++ b/usr/lib/common/mech_rsa.c +@@ -29,6 +29,7 @@ + #include "constant_time.h" + + #include ++#include + + CK_BBOOL is_rsa_mechanism(CK_MECHANISM_TYPE mech) + { +@@ -293,13 +294,16 @@ static CK_RV rsa_parse_block_type_2(CK_BYTE *in_data, + CK_BYTE *out_data, + CK_ULONG *out_data_len) + { +- unsigned int ok = 0, found, zero; +- size_t zero_index = 0, msg_index, mlen; +- size_t i, j; ++ int i; ++ unsigned char *em = NULL; ++ unsigned int good, found_zero_byte, mask, equals0; ++ int zero_index = 0, msg_index, mlen = -1; ++ int out_len = *out_data_len; ++ int rsa_size = in_data_len; + + /* + * The implementation of this function is copied from OpenSSL's function +- * ossl_rsa_padding_check_PKCS1_type_2() in crypto/rsa/rsa_pk1.c ++ * RSA_padding_check_PKCS1_type_2() in crypto/rsa/rsa_pk1.c + * and is slightly modified to fit to the OpenCryptoki environment. + * + * The OpenSSL code is licensed under the Apache License 2.0. +@@ -324,55 +328,86 @@ static CK_RV rsa_parse_block_type_2(CK_BYTE *in_data, + * PKCS#1 v1.5 decryption. See "PKCS #1 v2.2: RSA Cryptography Standard", + * section 7.2.2. + */ +- if (in_data_len < 11) { ++ if (rsa_size < RSA_PKCS1_PADDING_SIZE) { + TRACE_DEVEL("%s\n", ock_err(ERR_FUNCTION_FAILED)); + return CKR_FUNCTION_FAILED; + } + +- ok = constant_time_is_zero(in_data[0]); +- ok &= constant_time_eq(in_data[1], 2); ++ em = malloc(rsa_size); ++ if (em == NULL) { ++ TRACE_DEVEL("%s\n", ock_err(ERR_HOST_MEMORY)); ++ return CKR_HOST_MEMORY; ++ } ++ ++ /* in_data_len is always equal to rsa_size */ ++ memcpy(em, in_data, rsa_size); ++ ++ good = constant_time_is_zero(em[0]); ++ good &= constant_time_eq(em[1], 2); + + /* scan over padding data */ +- found = 0; +- for (i = 2; i < in_data_len; i++) { +- zero = constant_time_is_zero(in_data[i]); ++ found_zero_byte = 0; ++ for (i = 2; i < rsa_size; i++) { ++ equals0 = constant_time_is_zero(em[i]); + +- zero_index = constant_time_select_int(~found & zero, i, zero_index); +- found |= zero; ++ zero_index = constant_time_select_int(~found_zero_byte & equals0, ++ i, zero_index); ++ found_zero_byte |= equals0; + } + + /* +- * PS must be at least 8 bytes long, and it starts two bytes into |enc_msg|. ++ * PS must be at least 8 bytes long, and it starts two bytes into |em|. + * If we never found a 0-byte, then |zero_index| is 0 and the check + * also fails. + */ +- ok &= constant_time_ge(zero_index, 2 + 8); ++ good &= constant_time_ge(zero_index, 2 + 8); + + /* + * Skip the zero byte. This is incorrect if we never found a zero-byte + * but in this case we also do not copy the message out. + */ + msg_index = zero_index + 1; +- mlen = in_data_len - msg_index; ++ mlen = rsa_size - msg_index; + + /* + * For good measure, do this check in constant time as well. + */ +- ok &= constant_time_ge(*out_data_len, mlen); ++ good &= constant_time_ge(out_len, mlen); + + /* +- * since at this point the |msg_index| does not provide the signal +- * indicating if the padding check failed or not, we don't have to worry +- * about leaking the length of returned message, we still need to ensure +- * that we read contents of both buffers so that cache accesses don't leak +- * the value of |good| ++ * Move the result in-place by |rsa_size|-RSA_PKCS1_PADDING_SIZE-|mlen| ++ * bytes to the left. ++ * Then if |good| move |mlen| bytes from |em|+RSA_PKCS1_PADDING_SIZE to ++ * |out_data|. Otherwise leave |out_data| unchanged. ++ * Copy the memory back in a way that does not reveal the size of ++ * the data being copied via a timing side channel. This requires copying ++ * parts of the buffer multiple times based on the bits set in the real ++ * length. Clear bits do a non-copy with identical access pattern. ++ * The loop below has overall complexity of O(N*log(N)). + */ +- for (i = msg_index, j = 0; i < in_data_len && j < *out_data_len; i++, j++) +- out_data[j] = constant_time_select_8(ok, in_data[i], out_data[j]); ++ out_len = constant_time_select_int( ++ constant_time_lt(rsa_size - RSA_PKCS1_PADDING_SIZE, out_len), ++ rsa_size - RSA_PKCS1_PADDING_SIZE, ++ out_len); ++ for (msg_index = 1; msg_index < rsa_size - RSA_PKCS1_PADDING_SIZE; ++ msg_index <<= 1) { ++ mask = ~constant_time_eq( ++ msg_index & (rsa_size - RSA_PKCS1_PADDING_SIZE - mlen), 0); ++ for (i = RSA_PKCS1_PADDING_SIZE; i < rsa_size - msg_index; i++) ++ em[i] = constant_time_select_8(mask, em[i + msg_index], em[i]); ++ } ++ for (i = 0; i < out_len; i++) { ++ mask = good & constant_time_lt(i, mlen); ++ out_data[i] = constant_time_select_8( ++ mask, em[i + RSA_PKCS1_PADDING_SIZE], out_data[i]); ++ } ++ ++ OPENSSL_cleanse(em, rsa_size); ++ free(em); + +- *out_data_len = j; ++ *out_data_len = constant_time_select_int(good, mlen, 0); + +- return constant_time_select_int(ok, CKR_OK, CKR_ENCRYPTED_DATA_INVALID); ++ return constant_time_select_int(good, CKR_OK, CKR_ENCRYPTED_DATA_INVALID); + } + + CK_RV rsa_parse_block(CK_BYTE *in_data, diff --git a/SOURCES/opencryptoki-v3.21.0-CVE-2024-0914-part02.patch b/SOURCES/opencryptoki-v3.21.0-CVE-2024-0914-part02.patch new file mode 100644 index 0000000..74687ef --- /dev/null +++ b/SOURCES/opencryptoki-v3.21.0-CVE-2024-0914-part02.patch @@ -0,0 +1,387 @@ +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); + } diff --git a/SOURCES/opencryptoki-v3.21.0-CVE-2024-0914-part03.patch b/SOURCES/opencryptoki-v3.21.0-CVE-2024-0914-part03.patch new file mode 100644 index 0000000..54f7c48 --- /dev/null +++ b/SOURCES/opencryptoki-v3.21.0-CVE-2024-0914-part03.patch @@ -0,0 +1,737 @@ +commit 034d70ec4cfde81ea71cf8acbe9097fa15e49a02 +Author: Ingo Franzki +Date: Mon Jan 15 12:53:37 2024 +0100 + + common: Add support for implicit rejection for RSA PKCS#1 v1.5 de-padding + + Implicit rejection returns a pseudo random message in case the RSA PKCS#1 v1.5 + padding is incorrect, but returns no error. The pseudo random message is based + on static secret data (the private exponent) and the provided ciphertext, so + that the attacker cannot determine that the returned value is randomly generated + instead of the result of decryption and de-padding. + + The implicit rejection algorithm is the same as used by OpenSSL. + + Signed-off-by: Ingo Franzki + +diff --git a/COPYRIGHTS b/COPYRIGHTS +index 2bb3dffe..21b6b702 100644 +--- a/COPYRIGHTS ++++ b/COPYRIGHTS +@@ -12,19 +12,29 @@ For code originating from OpenSSL: + * Note that in OpenSSL the file crypto/bn/rsa_sup_mul.c does no longer + * exist, it was removed with commit https://github.com/openssl/openssl/commit/4209ce68d8fe8b1506494efa03d378d05baf9ff8 + * - usr/lib/common/constant_time.h: Copied unchanged from OpenSSL from +- include/internal/constant_time.h ++ * include/internal/constant_time.h + * - The implementation of function rsa_parse_block_type_2() in + * usr/lib/common/mech_rsa.c is copied from OpenSSL's function + * ossl_rsa_padding_check_PKCS1_type_2() in crypto/rsa/rsa_pk1.c + * and is slightly modified to fit to the OpenCryptoki environment. + * See comment in function rsa_parse_block_type_2() for a list of changes. ++ * - The implementation of function openssl_specific_rsa_derive_kdk() in ++ * usr/lib/common/mech_openssl.c is copied from OpenSSL's function ++ * derive_kdk() in crypto/rsa/rsa_ossl.c and is slightly modified to fit to ++ * the OpenCryptoki environment. See comment in function ++ * openssl_specific_rsa_derive_kdk() for a list of changes. ++ * - The implementation of function openssl_specific_rsa_prf() in ++ * usr/lib/common/mech_openssl.c is copied from OpenSSL's function ++ * ossl_rsa_prf() in crypto/rsa/rsapk1.c and is slightly modified to fit to ++ * the OpenCryptoki environment. See comment in function ++ * openssl_specific_rsa_prf() for a list of changes. + * - The implementation of function decode_eme_oaep() in + * usr/lib/common/mech_rsa.c is copied from OpenSSL's function + * RSA_padding_check_PKCS1_OAEP_mgf1() in crypto/rsa/rsa_oaep.c and is + * slightly modified to fit to the OpenCryptoki environment. See comment in + * function decode_eme_oaep() for a list of changes. + * +- * Copyright 1999-2023 The OpenSSL Project Authors. All Rights Reserved. ++ * Copyright 1999-2024 The OpenSSL Project Authors. All Rights Reserved. + * + * The OpenSSL code is licensed under the Apache License 2.0 (the "License"). + * You can obtain a copy in the file LICENSE in the OpenSSL source distribution +diff --git a/usr/lib/common/h_extern.h b/usr/lib/common/h_extern.h +index a14542fa..a6ee4c33 100644 +--- a/usr/lib/common/h_extern.h ++++ b/usr/lib/common/h_extern.h +@@ -731,7 +731,8 @@ CK_RV rsa_format_block(STDLL_TokData_t *tokdata, + CK_RV rsa_parse_block(CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, +- CK_ULONG *out_data_len, CK_ULONG type); ++ CK_ULONG *out_data_len, CK_ULONG type, ++ CK_BYTE *kdk, CK_ULONG kdklen); + + CK_RV get_mgf_mech(CK_RSA_PKCS_MGF_TYPE mgf, CK_MECHANISM_TYPE *mech); + +@@ -3179,6 +3180,14 @@ CK_RV openssl_specific_hmac_update(SIGN_VERIFY_CONTEXT *ctx, CK_BYTE *in_data, + CK_RV openssl_specific_hmac_final(SIGN_VERIFY_CONTEXT *ctx, CK_BYTE *signature, + CK_ULONG *sig_len, CK_BBOOL sign); + ++CK_RV openssl_specific_rsa_derive_kdk(STDLL_TokData_t *tokdata, OBJECT *key_obj, ++ const CK_BYTE *in, CK_ULONG inlen, ++ CK_BYTE *kdk, CK_ULONG kdklen); ++CK_RV openssl_specific_rsa_prf(CK_BYTE *out, CK_ULONG outlen, ++ const char *label, CK_ULONG labellen, ++ const CK_BYTE *kdk, CK_ULONG kdklen, ++ uint16_t bitlen); ++ + #include "tok_spec_struct.h" + extern token_spec_t token_specific; + +diff --git a/usr/lib/common/mech_openssl.c b/usr/lib/common/mech_openssl.c +index 9983fcb3..da515289 100644 +--- a/usr/lib/common/mech_openssl.c ++++ b/usr/lib/common/mech_openssl.c +@@ -1154,6 +1154,7 @@ CK_RV openssl_specific_rsa_pkcs_decrypt(STDLL_TokData_t *tokdata, + CK_RV rc; + CK_BYTE out[MAX_RSA_KEYLEN]; + CK_ULONG modulus_bytes; ++ unsigned char kdk[SHA256_HASH_SIZE] = { 0 }; + + modulus_bytes = in_data_len; + +@@ -1163,7 +1164,16 @@ CK_RV openssl_specific_rsa_pkcs_decrypt(STDLL_TokData_t *tokdata, + goto done; + } + +- rc = rsa_parse_block(out, modulus_bytes, out_data, out_data_len, PKCS_BT_2); ++ rc = openssl_specific_rsa_derive_kdk(tokdata, key_obj, ++ in_data, in_data_len, ++ kdk, sizeof(kdk)); ++ if (rc != CKR_OK) { ++ TRACE_DEVEL("openssl_specific_rsa_derive_kdk failed\n"); ++ goto done; ++ } ++ ++ rc = rsa_parse_block(out, modulus_bytes, out_data, out_data_len, PKCS_BT_2, ++ kdk, sizeof(kdk)); + + done: + OPENSSL_cleanse(out, sizeof(out)); +@@ -1254,7 +1264,7 @@ CK_RV openssl_specific_rsa_pkcs_verify(STDLL_TokData_t *tokdata, SESSION *sess, + } + + rc = rsa_parse_block(out, modulus_bytes, out_data, &out_data_len, +- PKCS_BT_1); ++ PKCS_BT_1, NULL, 0); + if (rc == CKR_ENCRYPTED_DATA_INVALID) { + TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_INVALID)); + return CKR_SIGNATURE_INVALID; +@@ -1318,7 +1328,8 @@ CK_RV openssl_specific_rsa_pkcs_verify_recover(STDLL_TokData_t *tokdata, + return rc; + } + +- rc = rsa_parse_block(out, modulus_bytes, out_data, out_data_len, PKCS_BT_1); ++ rc = rsa_parse_block(out, modulus_bytes, out_data, out_data_len, PKCS_BT_1, ++ NULL, 0); + if (rc == CKR_ENCRYPTED_DATA_INVALID) { + TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_INVALID)); + return CKR_SIGNATURE_INVALID; +@@ -4983,3 +4994,388 @@ done: + ctx->context = NULL; + return rv; + } ++ ++static CK_RV calc_rsa_priv_exp(STDLL_TokData_t *tokdata, OBJECT *key_obj, ++ CK_BYTE *priv_exp, CK_ULONG priv_exp_len) ++{ ++ CK_ATTRIBUTE *modulus = NULL, *pub_exp = NULL; ++ CK_ATTRIBUTE *prime1 = NULL, *prime2 = NULL; ++ BN_CTX *bn_ctx; ++ BIGNUM *n, *e, *p, *q, *d; ++ CK_RV rc; ++ ++ UNUSED(tokdata); ++ ++ bn_ctx = BN_CTX_secure_new(); ++ if (bn_ctx == NULL) { ++ TRACE_ERROR("BN_CTX_secure_new failed\n"); ++ return CKR_FUNCTION_FAILED; ++ } ++ ++ /* Get modulus a BIGNUM */ ++ rc = template_attribute_get_non_empty(key_obj->template, CKA_MODULUS, ++ &modulus); ++ if (rc != CKR_OK) { ++ TRACE_ERROR("Failed to get CKA_MODULUS\n"); ++ goto done; ++ } ++ ++ n = BN_CTX_get(bn_ctx); ++ if (n == NULL || ++ BN_bin2bn(modulus->pValue, modulus->ulValueLen, n) == NULL) { ++ TRACE_ERROR("BN_CTX_get/BN_bin2bn failed for modulus\n"); ++ rc = CKR_FUNCTION_FAILED; ++ goto done; ++ } ++ BN_set_flags(n, BN_FLG_CONSTTIME); ++ ++ /* Get public exponent a BIGNUM */ ++ rc = template_attribute_get_non_empty(key_obj->template, ++ CKA_PUBLIC_EXPONENT, &pub_exp); ++ if (rc != CKR_OK) { ++ TRACE_ERROR("Failed to get CKA_PUBLIC_EXPONENT\n"); ++ goto done; ++ } ++ ++ e = BN_CTX_get(bn_ctx); ++ if (e == NULL || ++ BN_bin2bn(pub_exp->pValue, pub_exp->ulValueLen, e) == NULL) { ++ TRACE_ERROR("BN_CTX_get/BN_bin2bn failed for public exponent\n"); ++ rc = CKR_FUNCTION_FAILED; ++ goto done; ++ } ++ BN_set_flags(e, BN_FLG_CONSTTIME); ++ ++ /* Get prime1 a BIGNUM */ ++ rc = template_attribute_get_non_empty(key_obj->template, CKA_PRIME_1, ++ &prime1); ++ if (rc != CKR_OK) { ++ TRACE_ERROR("Failed to get CKA_PRIME_1\n"); ++ goto done; ++ } ++ ++ p = BN_CTX_get(bn_ctx); ++ if (p == NULL || ++ BN_bin2bn(prime1->pValue, prime1->ulValueLen, p) == NULL) { ++ TRACE_ERROR("BN_CTX_get/BN_bin2bn failed for prime1\n"); ++ rc = CKR_FUNCTION_FAILED; ++ goto done; ++ } ++ BN_set_flags(p, BN_FLG_CONSTTIME); ++ ++ /* Get prime2 a BIGNUM */ ++ rc = template_attribute_get_non_empty(key_obj->template, CKA_PRIME_2, ++ &prime2); ++ if (rc != CKR_OK) { ++ TRACE_ERROR("Failed to get CKA_PRIME_2\n"); ++ goto done; ++ } ++ ++ q = BN_CTX_get(bn_ctx); ++ if (q == NULL || ++ BN_bin2bn(prime2->pValue, prime2->ulValueLen, q) == NULL) { ++ TRACE_ERROR("BN_CTX_get/BN_bin2bn failed for prime2\n"); ++ rc = CKR_FUNCTION_FAILED; ++ goto done; ++ } ++ BN_set_flags(q, BN_FLG_CONSTTIME); ++ ++ d = BN_CTX_get(bn_ctx); ++ if (d == NULL) { ++ TRACE_ERROR("BN_CTX_get failed to get d\n"); ++ rc = CKR_FUNCTION_FAILED; ++ goto done; ++ } ++ BN_set_flags(d, BN_FLG_CONSTTIME); ++ ++ /* ++ * phi(n) = (p - 1 )(q - 1) = n - p - q + 1 ++ * d = e ^{-1} mod phi(n). ++ */ ++ if (BN_copy(d, n) == NULL || ++ BN_sub(d, d, p) == 0 || ++ BN_sub(d, d, q) == 0 || ++ BN_add_word(d, 1) == 0 || ++ BN_mod_inverse(d, e, d, bn_ctx) == NULL) { ++ TRACE_ERROR("Failed to calculate private key part d\n"); ++ rc = CKR_FUNCTION_FAILED; ++ goto done; ++ } ++ ++ if (BN_bn2binpad(d, priv_exp, priv_exp_len) <= 0) { ++ TRACE_ERROR("BN_bn2binpad failed\n"); ++ rc = CKR_FUNCTION_FAILED; ++ goto done; ++ } ++ ++done: ++ BN_CTX_free(bn_ctx); ++ ++ return rc; ++} ++ ++CK_RV openssl_specific_rsa_derive_kdk(STDLL_TokData_t *tokdata, OBJECT *key_obj, ++ const CK_BYTE *in, CK_ULONG inlen, ++ CK_BYTE *kdk, CK_ULONG kdklen) ++{ ++ CK_ATTRIBUTE *priv_exp_attr = NULL, *modulus = NULL; ++ CK_BYTE *priv_exp = NULL, *buf = NULL; ++ EVP_PKEY *pkey = NULL; ++ EVP_MD_CTX *mdctx = NULL; ++ const EVP_MD *md = NULL; ++ size_t md_len; ++ unsigned char d_hash[SHA256_HASH_SIZE] = { 0 }; ++ CK_RV rc; ++ ++ /* ++ * The implementation of this function is copied from OpenSSL's function ++ * derive_kdk() in crypto/rsa/rsa_ossl.c and is slightly modified to fit to ++ * the OpenCryptoki environment. ++ * Changes include: ++ * - Different variable and define names. ++ * - Usage of TRACE_ERROR to report errors and issue debug messages. ++ * - Different return codes. ++ * - Different code to get the private key component 'd'. ++ * - Use of the EVP APIs instead of the internal APIs for Digest and HMAC ++ * operations. ++ */ ++ ++ if (kdklen != SHA256_HASH_SIZE) { ++ TRACE_ERROR("KDK length is wrong\n"); ++ return CKR_ARGUMENTS_BAD; ++ } ++ ++ rc = template_attribute_get_non_empty(key_obj->template, CKA_MODULUS, ++ &modulus); ++ if (rc != CKR_OK) { ++ TRACE_ERROR("Failed to get CKA_MODULUS\n"); ++ return rc; ++ } ++ ++ buf = calloc(1, modulus->ulValueLen); ++ if (buf == NULL) { ++ TRACE_ERROR("Failed to allocate a buffer for private exponent\n"); ++ return CKR_HOST_MEMORY; ++ } ++ ++ rc = template_attribute_get_non_empty(key_obj->template, ++ CKA_PRIVATE_EXPONENT, &priv_exp_attr); ++ if (rc != CKR_OK && rc != CKR_TEMPLATE_INCOMPLETE) { ++ TRACE_ERROR("Failed to get CKA_PRIVATE_EXPONENT\n"); ++ goto out; ++ } ++ ++ if (priv_exp_attr == NULL) { ++ rc = calc_rsa_priv_exp(tokdata, key_obj, buf, modulus->ulValueLen); ++ if (rc != CKR_OK) { ++ TRACE_ERROR("calc_rsa_priv_exp failed\n"); ++ goto out; ++ } ++ priv_exp = buf; ++ } else { ++ if (priv_exp_attr->ulValueLen < modulus->ulValueLen) { ++ memcpy(buf + modulus->ulValueLen - priv_exp_attr->ulValueLen, ++ priv_exp_attr->pValue, priv_exp_attr->ulValueLen); ++ priv_exp = buf; ++ } else { ++ priv_exp = (CK_BYTE *)priv_exp_attr->pValue + ++ priv_exp_attr->ulValueLen - modulus->ulValueLen; ++ } ++ } ++ ++ /* ++ * we use hardcoded hash so that migrating between versions that use ++ * different hash doesn't provide a Bleichenbacher oracle: ++ * if the attacker can see that different versions return different ++ * messages for the same ciphertext, they'll know that the message is ++ * synthetically generated, which means that the padding check failed ++ */ ++ md = EVP_sha256(); ++ if (md == NULL) { ++ TRACE_ERROR("EVP_sha256 failed\n"); ++ rc = CKR_FUNCTION_FAILED; ++ goto out; ++ } ++ ++ if (EVP_Digest(priv_exp, modulus->ulValueLen, d_hash, NULL, ++ md, NULL) <= 0) { ++ TRACE_ERROR("EVP_Digest failed\n"); ++ rc = CKR_FUNCTION_FAILED; ++ goto out; ++ } ++ ++ pkey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL, d_hash, sizeof(d_hash)); ++ if (pkey == NULL) { ++ TRACE_ERROR("EVP_PKEY_new_mac_key() failed.\n"); ++ rc = CKR_FUNCTION_FAILED; ++ goto out; ++ } ++ ++ mdctx = EVP_MD_CTX_create(); ++ if (mdctx == NULL) { ++ TRACE_ERROR("EVP_MD_CTX_create() failed.\n"); ++ rc = CKR_FUNCTION_FAILED; ++ goto out; ++ } ++ ++ if (EVP_DigestSignInit(mdctx, NULL, md, NULL, pkey) != 1) { ++ TRACE_ERROR("EVP_DigestSignInit failed\n"); ++ rc = CKR_FUNCTION_FAILED; ++ goto out; ++ } ++ ++ if (inlen < modulus->ulValueLen) { ++ memset(buf, 0, modulus->ulValueLen - inlen); ++ if (EVP_DigestSignUpdate(mdctx, buf, modulus->ulValueLen - inlen)!= 1) { ++ TRACE_ERROR("EVP_DigestSignUpdate failed\n"); ++ rc = CKR_FUNCTION_FAILED; ++ goto out; ++ } ++ } ++ if (EVP_DigestSignUpdate(mdctx, in, inlen) != 1) { ++ TRACE_ERROR("EVP_DigestSignUpdate failed\n"); ++ rc = CKR_FUNCTION_FAILED; ++ goto out; ++ } ++ ++ md_len = kdklen; ++ if (EVP_DigestSignFinal(mdctx, kdk, &md_len) != 1 || ++ md_len != kdklen) { ++ TRACE_ERROR("EVP_DigestSignFinal failed\n"); ++ rc = CKR_FUNCTION_FAILED; ++ goto out; ++ } ++ ++ rc = CKR_OK; ++ ++out: ++ if (buf != NULL) ++ free(buf); ++ if (pkey != NULL) ++ EVP_PKEY_free(pkey); ++ if (mdctx != NULL) ++ EVP_MD_CTX_free(mdctx); ++ ++ return rc; ++} ++ ++CK_RV openssl_specific_rsa_prf(CK_BYTE *out, CK_ULONG outlen, ++ const char *label, CK_ULONG labellen, ++ const CK_BYTE *kdk, CK_ULONG kdklen, ++ uint16_t bitlen) ++{ ++ CK_RV rc; ++ CK_ULONG pos; ++ uint16_t iter = 0; ++ unsigned char be_iter[sizeof(iter)]; ++ unsigned char be_bitlen[sizeof(bitlen)]; ++ EVP_PKEY *pkey = NULL; ++ EVP_MD_CTX *mdctx = NULL; ++ unsigned char hmac_out[SHA256_HASH_SIZE]; ++ size_t md_len; ++ ++ /* ++ * The implementation of this function is copied from OpenSSL's function ++ * ossl_rsa_prf() in crypto/rsa/rsapk1.c and is slightly modified to fit to ++ * the providers environment. ++ * Changes include: ++ * - Different variable and define names. ++ * - Usage of TRACE_ERROR report errors and issue debug messages. ++ * - Different return codes. ++ * - Use of the EVP API instead of the internal APIs for HMAC operations. ++ */ ++ ++ if (kdklen != SHA256_HASH_SIZE) { ++ TRACE_ERROR("invalid kdklen\n"); ++ return CKR_ARGUMENTS_BAD; ++ } ++ if (outlen * 8 != bitlen) { ++ TRACE_ERROR("invalid outlen\n"); ++ return CKR_ARGUMENTS_BAD; ++ } ++ ++ be_bitlen[0] = (bitlen >> 8) & 0xff; ++ be_bitlen[1] = bitlen & 0xff; ++ ++ pkey = EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, NULL, kdk, kdklen); ++ if (pkey == NULL) { ++ TRACE_ERROR("EVP_PKEY_new_mac_key() failed.\n"); ++ rc = CKR_FUNCTION_FAILED; ++ goto out; ++ } ++ ++ mdctx = EVP_MD_CTX_create(); ++ if (mdctx == NULL) { ++ TRACE_ERROR("EVP_MD_CTX_create() failed.\n"); ++ rc = CKR_FUNCTION_FAILED; ++ goto out; ++ } ++ ++ /* ++ * we use hardcoded hash so that migrating between versions that use ++ * different hash doesn't provide a Bleichenbacher oracle: ++ * if the attacker can see that different versions return different ++ * messages for the same ciphertext, they'll know that the message is ++ * synthetically generated, which means that the padding check failed ++ */ ++ for (pos = 0; pos < outlen; pos += SHA256_HASH_SIZE, iter++) { ++ if (EVP_DigestSignInit(mdctx, NULL, EVP_sha256(), NULL, pkey) != 1) { ++ TRACE_ERROR("EVP_DigestSignInit failed\n"); ++ rc = CKR_FUNCTION_FAILED; ++ goto out; ++ } ++ ++ be_iter[0] = (iter >> 8) & 0xff; ++ be_iter[1] = iter & 0xff; ++ ++ if (EVP_DigestSignUpdate(mdctx, be_iter, sizeof(be_iter)) != 1) { ++ TRACE_ERROR("EVP_DigestSignUpdate failed\n"); ++ rc = CKR_FUNCTION_FAILED; ++ goto out; ++ } ++ if (EVP_DigestSignUpdate(mdctx, (unsigned char *)label, labellen) != 1) { ++ TRACE_ERROR("EVP_DigestSignUpdate failed\n"); ++ rc = CKR_FUNCTION_FAILED; ++ goto out; ++ } ++ if (EVP_DigestSignUpdate(mdctx, be_bitlen, sizeof(be_bitlen)) != 1) { ++ TRACE_ERROR("EVP_DigestSignUpdate failed\n"); ++ rc = CKR_FUNCTION_FAILED; ++ goto out; ++ } ++ ++ /* ++ * HMAC_Final requires the output buffer to fit the whole MAC ++ * value, so we need to use the intermediate buffer for the last ++ * unaligned block ++ */ ++ md_len = SHA256_HASH_SIZE; ++ if (pos + SHA256_HASH_SIZE > outlen) { ++ md_len = sizeof(hmac_out); ++ if (EVP_DigestSignFinal(mdctx, hmac_out, &md_len) != 1) { ++ TRACE_ERROR("EVP_DigestSignFinal failed\n"); ++ rc = CKR_FUNCTION_FAILED; ++ goto out; ++ } ++ memcpy(out + pos, hmac_out, outlen - pos); ++ } else { ++ md_len = outlen - pos; ++ if (EVP_DigestSignFinal(mdctx, out + pos, &md_len) != 1) { ++ TRACE_ERROR("EVP_DigestSignFinal failed\n"); ++ rc = CKR_FUNCTION_FAILED; ++ goto out; ++ } ++ } ++ } ++ ++ rc = CKR_OK; ++ ++out: ++ if (pkey != NULL) ++ EVP_PKEY_free(pkey); ++ if (mdctx != NULL) ++ EVP_MD_CTX_free(mdctx); ++ ++ return rc; ++} ++ +diff --git a/usr/lib/common/mech_rsa.c b/usr/lib/common/mech_rsa.c +index 7bab1a84..7dc9589a 100644 +--- a/usr/lib/common/mech_rsa.c ++++ b/usr/lib/common/mech_rsa.c +@@ -289,21 +289,34 @@ static CK_RV rsa_parse_block_type_1(CK_BYTE *in_data, + return rc; + } + ++#define MAX_LEN_GEN_TRIES 128 ++ + static CK_RV rsa_parse_block_type_2(CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, +- CK_ULONG *out_data_len) ++ CK_ULONG *out_data_len, ++ CK_BYTE *kdk, CK_ULONG kdklen) + { +- int i; +- unsigned char *em = NULL; +- unsigned int good, found_zero_byte, mask, equals0; +- int zero_index = 0, msg_index, mlen = -1; +- int out_len = *out_data_len; +- int rsa_size = in_data_len; ++ unsigned int good = 0, found_zero_byte, equals0; ++ size_t zero_index = 0, msg_index; ++ unsigned char *synthetic = NULL; ++ int synthetic_length; ++ uint16_t len_candidate; ++ unsigned char candidate_lengths[MAX_LEN_GEN_TRIES * sizeof(len_candidate)]; ++ uint16_t len_mask; ++ uint16_t max_sep_offset; ++ int synth_msg_index = 0; ++ size_t i, j; ++ CK_RV rc; ++ ++ if (kdk == NULL || kdklen == 0) { ++ TRACE_DEVEL("%s\n", ock_err(ERR_ARGUMENTS_BAD)); ++ return CKR_ARGUMENTS_BAD; ++ } + + /* + * The implementation of this function is copied from OpenSSL's function +- * RSA_padding_check_PKCS1_type_2() in crypto/rsa/rsa_pk1.c ++ * ossl_rsa_padding_check_PKCS1_type_2() in crypto/rsa/rsa_pk1.c + * and is slightly modified to fit to the OpenCryptoki environment. + * + * The OpenSSL code is licensed under the Apache License 2.0. +@@ -328,27 +341,67 @@ static CK_RV rsa_parse_block_type_2(CK_BYTE *in_data, + * PKCS#1 v1.5 decryption. See "PKCS #1 v2.2: RSA Cryptography Standard", + * section 7.2.2. + */ +- if (rsa_size < RSA_PKCS1_PADDING_SIZE) { ++ if (in_data_len < RSA_PKCS1_PADDING_SIZE) { + TRACE_DEVEL("%s\n", ock_err(ERR_FUNCTION_FAILED)); + return CKR_FUNCTION_FAILED; + } + +- em = malloc(rsa_size); +- if (em == NULL) { +- TRACE_DEVEL("%s\n", ock_err(ERR_HOST_MEMORY)); ++ /* Generate a random message to return in case the padding checks fail. */ ++ synthetic = calloc(1, in_data_len); ++ if (synthetic == NULL) { ++ TRACE_ERROR("Failed to allocate synthetic buffer"); + return CKR_HOST_MEMORY; + } + +- /* in_data_len is always equal to rsa_size */ +- memcpy(em, in_data, rsa_size); ++ rc = openssl_specific_rsa_prf(synthetic, in_data_len, "message", 7, ++ kdk, kdklen, in_data_len * 8); ++ if (rc != CKR_OK) ++ goto out; ++ ++ /* decide how long the random message should be */ ++ rc = openssl_specific_rsa_prf(candidate_lengths, ++ sizeof(candidate_lengths), ++ "length", 6, kdk, kdklen, ++ MAX_LEN_GEN_TRIES * ++ sizeof(len_candidate) * 8); ++ if (rc != CKR_OK) ++ goto out; + +- good = constant_time_is_zero(em[0]); +- good &= constant_time_eq(em[1], 2); ++ /* ++ * max message size is the size of the modulus size minus 2 bytes for ++ * version and padding type and a minimum of 8 bytes padding ++ */ ++ len_mask = max_sep_offset = in_data_len - 2 - 8; ++ /* ++ * we want a mask so let's propagate the high bit to all positions less ++ * significant than it ++ */ ++ len_mask |= len_mask >> 1; ++ len_mask |= len_mask >> 2; ++ len_mask |= len_mask >> 4; ++ len_mask |= len_mask >> 8; ++ ++ synthetic_length = 0; ++ for (i = 0; i < MAX_LEN_GEN_TRIES * (int)sizeof(len_candidate); ++ i += sizeof(len_candidate)) { ++ len_candidate = (candidate_lengths[i] << 8) | ++ candidate_lengths[i + 1]; ++ len_candidate &= len_mask; ++ ++ synthetic_length = constant_time_select_int( ++ constant_time_lt(len_candidate, max_sep_offset), ++ len_candidate, synthetic_length); ++ } ++ ++ synth_msg_index = in_data_len - synthetic_length; ++ ++ good = constant_time_is_zero(in_data[0]); ++ good &= constant_time_eq(in_data[1], 2); + + /* scan over padding data */ + found_zero_byte = 0; +- for (i = 2; i < rsa_size; i++) { +- equals0 = constant_time_is_zero(em[i]); ++ for (i = 2; i < in_data_len; i++) { ++ equals0 = constant_time_is_zero(in_data[i]); + + zero_index = constant_time_select_int(~found_zero_byte & equals0, + i, zero_index); +@@ -356,7 +409,7 @@ static CK_RV rsa_parse_block_type_2(CK_BYTE *in_data, + } + + /* +- * PS must be at least 8 bytes long, and it starts two bytes into |em|. ++ * PS must be at least 8 bytes long, and it starts two bytes into |in_data|. + * If we never found a 0-byte, then |zero_index| is 0 and the check + * also fails. + */ +@@ -367,53 +420,41 @@ static CK_RV rsa_parse_block_type_2(CK_BYTE *in_data, + * but in this case we also do not copy the message out. + */ + msg_index = zero_index + 1; +- mlen = rsa_size - msg_index; + + /* +- * For good measure, do this check in constant time as well. ++ * old code returned an error in case the decrypted message wouldn't fit ++ * into the |out_data|, since that would leak information, return the ++ * synthetic message instead + */ +- good &= constant_time_ge(out_len, mlen); ++ good &= constant_time_ge(*out_data_len, in_data_len - msg_index); ++ ++ msg_index = constant_time_select_int(good, msg_index, synth_msg_index); + + /* +- * Move the result in-place by |rsa_size|-RSA_PKCS1_PADDING_SIZE-|mlen| +- * bytes to the left. +- * Then if |good| move |mlen| bytes from |em|+RSA_PKCS1_PADDING_SIZE to +- * |out_data|. Otherwise leave |out_data| unchanged. +- * Copy the memory back in a way that does not reveal the size of +- * the data being copied via a timing side channel. This requires copying +- * parts of the buffer multiple times based on the bits set in the real +- * length. Clear bits do a non-copy with identical access pattern. +- * The loop below has overall complexity of O(N*log(N)). ++ * since at this point the |msg_index| does not provide the signal ++ * indicating if the padding check failed or not, we don't have to worry ++ * about leaking the length of returned message, we still need to ensure ++ * that we read contents of both buffers so that cache accesses don't leak ++ * the value of |good| + */ +- out_len = constant_time_select_int( +- constant_time_lt(rsa_size - RSA_PKCS1_PADDING_SIZE, out_len), +- rsa_size - RSA_PKCS1_PADDING_SIZE, +- out_len); +- for (msg_index = 1; msg_index < rsa_size - RSA_PKCS1_PADDING_SIZE; +- msg_index <<= 1) { +- mask = ~constant_time_eq( +- msg_index & (rsa_size - RSA_PKCS1_PADDING_SIZE - mlen), 0); +- for (i = RSA_PKCS1_PADDING_SIZE; i < rsa_size - msg_index; i++) +- em[i] = constant_time_select_8(mask, em[i + msg_index], em[i]); +- } +- for (i = 0; i < out_len; i++) { +- mask = good & constant_time_lt(i, mlen); +- out_data[i] = constant_time_select_8( +- mask, em[i + RSA_PKCS1_PADDING_SIZE], out_data[i]); +- } ++ for (i = msg_index, j = 0; i < in_data_len && j < *out_data_len; ++ i++, j++) ++ out_data[j] = constant_time_select_8(good, in_data[i], synthetic[i]); + +- OPENSSL_cleanse(em, rsa_size); +- free(em); ++ *out_data_len = j; + +- *out_data_len = constant_time_select_int(good, mlen, 0); ++out: ++ if (synthetic != NULL) ++ free(synthetic); + +- return constant_time_select_int(good, CKR_OK, CKR_ENCRYPTED_DATA_INVALID); ++ return rc; + } + + CK_RV rsa_parse_block(CK_BYTE *in_data, + CK_ULONG in_data_len, + CK_BYTE *out_data, +- CK_ULONG *out_data_len, CK_ULONG type) ++ CK_ULONG *out_data_len, CK_ULONG type, ++ CK_BYTE *kdk, CK_ULONG kdklen) + { + switch (type) { + case PKCS_BT_1: +@@ -421,7 +462,7 @@ CK_RV rsa_parse_block(CK_BYTE *in_data, + out_data, out_data_len); + case PKCS_BT_2: + return rsa_parse_block_type_2(in_data, in_data_len, +- out_data, out_data_len); ++ out_data, out_data_len, kdk, kdklen); + } + + return CKR_ARGUMENTS_BAD; diff --git a/SOURCES/opencryptoki-v3.21.0-CVE-2024-0914-part04.patch b/SOURCES/opencryptoki-v3.21.0-CVE-2024-0914-part04.patch new file mode 100644 index 0000000..0c8bbac --- /dev/null +++ b/SOURCES/opencryptoki-v3.21.0-CVE-2024-0914-part04.patch @@ -0,0 +1,1013 @@ +commit bc06acfb6c5e7a0fb4a384084b04404414360eaa +Author: Ingo Franzki +Date: Tue Jan 16 10:01:20 2024 +0100 + + testcases: Add RSA implicit rejection test cases + + Signed-off-by: Ingo Franzki + +diff --git a/testcases/crypto/rsa.h b/testcases/crypto/rsa.h +index 7ed70262..6281d982 100644 +--- a/testcases/crypto/rsa.h ++++ b/testcases/crypto/rsa.h +@@ -8977,3 +8977,817 @@ struct PUBLISHED_TEST_SUITE_INFO rsa_encdec_import_test_suites[] = { + .mech = {CKM_RSA_X_509, 0, 0}, + }, + }; ++ ++struct RSA_PUBLISHED_TEST_VECTOR rsa_imp_rejection_tv[] = { ++ { // 0 - good case ++ .mod = {0xc8, 0xcc, 0x83, 0x97, 0x14, 0x09, 0x8d, 0xa5, ++ 0x6c, 0xaa, 0x23, 0x64, 0x0f, 0x93, 0xdc, 0x89, ++ 0x97, 0xc1, 0x63, 0x72, 0x96, 0x8f, 0xc1, 0xb0, ++ 0xc6, 0xdf, 0x51, 0x13, 0xc1, 0xc9, 0x4e, 0x8b, ++ 0x21, 0xe4, 0x8a, 0xd2, 0x29, 0x7e, 0x65, 0x41, ++ 0x90, 0x11, 0xb4, 0xe6, 0xd8, 0xf5, 0xe7, 0x3b, ++ 0x1b, 0x78, 0xb2, 0x57, 0x40, 0x03, 0x21, 0xd1, ++ 0xef, 0x6b, 0x60, 0x2d, 0x4e, 0xc8, 0xce, 0x8d, ++ 0x14, 0x1c, 0x94, 0x90, 0x5e, 0xb4, 0xad, 0x30, ++ 0x66, 0x39, 0xa4, 0x92, 0x06, 0x53, 0x4b, 0x6e, ++ 0x7f, 0x26, 0x07, 0x42, 0x3e, 0x97, 0xdf, 0xfd, ++ 0x13, 0x3c, 0x88, 0xd7, 0x21, 0x39, 0x9d, 0xef, ++ 0xbc, 0x7e, 0x96, 0xcc, 0xdc, 0xbd, 0x7f, 0x3a, ++ 0xae, 0x1f, 0xe8, 0x92, 0x71, 0x2b, 0xfb, 0x49, ++ 0x29, 0x81, 0x7d, 0x51, 0x16, 0x66, 0x44, 0x0a, ++ 0x1f, 0xac, 0xb7, 0xa2, 0x08, 0xf5, 0xea, 0x16, ++ 0x59, 0x10, 0xad, 0xd8, 0xa3, 0xf2, 0xd4, 0x97, ++ 0x20, 0x23, 0x60, 0xcc, 0xb6, 0x32, 0x02, 0x4f, ++ 0x0d, 0x07, 0x16, 0x9c, 0x19, 0x18, 0xf3, 0x16, ++ 0xf7, 0x94, 0xb1, 0x43, 0xae, 0xf5, 0x4e, 0xc8, ++ 0x75, 0x22, 0xa4, 0xc0, 0x29, 0x78, 0xf9, 0x68, ++ 0x99, 0x80, 0xbf, 0xfb, 0xf6, 0x49, 0xc3, 0x07, ++ 0xe8, 0x18, 0x19, 0xbf, 0xf8, 0x84, 0x09, 0x63, ++ 0x8d, 0x48, 0xbd, 0x94, 0xbe, 0x15, 0x2b, 0x59, ++ 0xff, 0x64, 0x9f, 0xa0, 0xbd, 0x62, 0x9d, 0x0f, ++ 0xfa, 0x18, 0x13, 0xc3, 0xab, 0xf4, 0xb5, 0x6b, ++ 0xd3, 0xc2, 0xea, 0x54, 0x65, 0xdf, 0xfa, 0x14, ++ 0x58, 0x92, 0x92, 0xa9, 0xd8, 0xa2, 0x4a, 0xd2, ++ 0x6b, 0xe7, 0xee, 0x05, 0x10, 0x74, 0x1b, 0x63, ++ 0x82, 0xd4, 0x3c, 0x83, 0xd5, 0xbf, 0xa4, 0x0a, ++ 0x46, 0x61, 0x3d, 0x06, 0x2b, 0xe4, 0x45, 0x51, ++ 0x7d, 0xbc, 0xaf, 0x0c, 0xb4, 0xe1, 0xa7, 0x69}, ++ .mod_len = 256, ++ .pub_exp = {0x01, 0x00, 0x01}, ++ .pubexp_len = 3, ++ .priv_exp = {0x14, 0x55, 0x01, 0x0e, 0x0f, 0x2d, 0x58, 0x76, ++ 0x63, 0xa6, 0x66, 0xa6, 0xff, 0x1c, 0xcd, 0xbb, ++ 0xf0, 0xed, 0xd8, 0x10, 0x06, 0x46, 0xd0, 0x2a, ++ 0x02, 0x39, 0x22, 0x90, 0x89, 0x92, 0xc4, 0xad, ++ 0x39, 0xe5, 0x56, 0x59, 0x29, 0x72, 0x6e, 0xf6, ++ 0x50, 0x8c, 0x3a, 0x71, 0x15, 0x8e, 0xf0, 0xb6, ++ 0xff, 0x75, 0x1d, 0x39, 0xd0, 0x75, 0x80, 0xbb, ++ 0x2d, 0x2f, 0x06, 0x32, 0x10, 0x44, 0x2d, 0x06, ++ 0x03, 0xff, 0x50, 0xdb, 0xbd, 0x7b, 0x35, 0xfe, ++ 0x2c, 0x9b, 0xb1, 0x9a, 0x47, 0xa1, 0xaf, 0x85, ++ 0xa4, 0xc2, 0x49, 0x01, 0xe0, 0x2c, 0xa8, 0xb5, ++ 0x8b, 0x79, 0x19, 0xb2, 0x0e, 0xdf, 0x32, 0xaa, ++ 0xcf, 0xbf, 0x51, 0xad, 0xb4, 0xbc, 0x4b, 0x61, ++ 0xb9, 0xb7, 0xe9, 0x68, 0xca, 0xa4, 0xd5, 0x70, ++ 0xf7, 0x0e, 0xf1, 0x8d, 0x80, 0x63, 0x22, 0x88, ++ 0x93, 0xe4, 0x7d, 0x43, 0x9e, 0xfc, 0xa7, 0x93, ++ 0x25, 0x9b, 0xcf, 0x2c, 0xd1, 0x08, 0xa3, 0xd8, ++ 0x68, 0x8c, 0xdf, 0x07, 0x8e, 0x7a, 0xc7, 0x99, ++ 0x96, 0x9f, 0x23, 0x39, 0xd2, 0xc1, 0xf5, 0x22, ++ 0xb9, 0x69, 0x68, 0x46, 0x29, 0xa9, 0x33, 0xba, ++ 0xae, 0xc2, 0x68, 0x16, 0x25, 0xea, 0xb8, 0x4f, ++ 0x4e, 0x56, 0xf4, 0x44, 0x7e, 0x9d, 0x88, 0xfb, ++ 0x9a, 0x19, 0x9c, 0xf7, 0x10, 0x23, 0xe0, 0xe2, ++ 0x57, 0xb1, 0x44, 0x41, 0xb3, 0x3c, 0x84, 0xd3, ++ 0xbc, 0x67, 0xca, 0x80, 0x31, 0xd2, 0x61, 0x26, ++ 0x18, 0x10, 0x3a, 0x7a, 0x0a, 0x40, 0x84, 0x42, ++ 0x62, 0xf7, 0x5d, 0x88, 0x90, 0xcd, 0x61, 0x6e, ++ 0x51, 0xf9, 0x03, 0x54, 0x88, 0xfd, 0x6e, 0x09, ++ 0x9d, 0xe8, 0xff, 0x6d, 0x65, 0xa4, 0xff, 0x11, ++ 0x82, 0x54, 0x80, 0x7c, 0x9f, 0x58, 0xd2, 0xfb, ++ 0xba, 0x8b, 0xa1, 0x51, 0xdc, 0x8c, 0x68, 0xbe, ++ 0x34, 0x9c, 0x97, 0x7a, 0x20, 0x4e, 0x04, 0xc1}, ++ .privexp_len = 256, ++ .prime1 = {0xf8, 0xf5, 0xad, 0x6b, 0xa8, 0x28, 0x93, 0x1b, ++ 0xea, 0x45, 0x9b, 0x8a, 0x3f, 0x6d, 0xc0, 0x41, ++ 0xd2, 0x34, 0x82, 0x40, 0x9c, 0x25, 0x71, 0xe9, ++ 0x63, 0xf3, 0x1f, 0x74, 0x86, 0x02, 0xa2, 0x56, ++ 0x37, 0x1b, 0x38, 0x83, 0xed, 0x45, 0x9e, 0xcf, ++ 0x97, 0x05, 0x26, 0x45, 0x9e, 0xdd, 0x16, 0xe0, ++ 0x55, 0x22, 0xf5, 0xa4, 0x5d, 0x94, 0x75, 0x1b, ++ 0x2e, 0xc2, 0xda, 0xf2, 0x72, 0xc7, 0xf8, 0x81, ++ 0x6a, 0x52, 0xc0, 0x0d, 0x18, 0x08, 0x01, 0x71, ++ 0x63, 0x4d, 0xa8, 0x99, 0xd7, 0x97, 0x32, 0x22, ++ 0xf5, 0x1b, 0x93, 0x76, 0x30, 0x54, 0x86, 0x96, ++ 0xa9, 0xf7, 0xd8, 0xc2, 0x4a, 0x59, 0x49, 0x7c, ++ 0x1e, 0xfc, 0xd4, 0x55, 0xcf, 0xb9, 0x7e, 0xe8, ++ 0x6d, 0x2b, 0x6d, 0x34, 0x97, 0x2b, 0x33, 0x2f, ++ 0xda, 0x30, 0x3f, 0x04, 0x99, 0x9b, 0x4e, 0xb6, ++ 0xb5, 0xcc, 0x0b, 0xb3, 0x3e, 0x77, 0x61, 0xdd}, ++ .prime1_len = 128, ++ .prime2 = {0xce, 0x7a, 0x2e, 0x3b, 0x49, 0xa9, 0x0b, 0x96, ++ 0x33, 0x0a, 0x12, 0xdc, 0x68, 0x2b, 0xdf, 0xbd, ++ 0xfb, 0xae, 0x8d, 0xd6, 0xdc, 0x03, 0xb6, 0x14, ++ 0x7a, 0xef, 0xbd, 0x57, 0x57, 0x43, 0xf0, 0xf6, ++ 0xda, 0x4d, 0x86, 0x23, 0x50, 0x61, 0xb7, 0x1a, ++ 0xfd, 0x9c, 0xad, 0x2d, 0x34, 0x02, 0x5e, 0x56, ++ 0xac, 0x86, 0xb0, 0xf7, 0x74, 0x3e, 0xb3, 0x5e, ++ 0x1a, 0xcb, 0xca, 0x23, 0x78, 0x95, 0x42, 0x44, ++ 0x65, 0xb7, 0x06, 0xed, 0x22, 0x17, 0x5e, 0x57, ++ 0x18, 0xc8, 0xc7, 0x0b, 0x67, 0x03, 0xea, 0x8f, ++ 0x6b, 0x51, 0x0f, 0x94, 0x5b, 0xe4, 0x8e, 0x5a, ++ 0x36, 0xbb, 0x3c, 0x3c, 0x91, 0x73, 0x2b, 0x58, ++ 0x9d, 0xfc, 0x05, 0xd7, 0x2d, 0x80, 0x90, 0x31, ++ 0x94, 0x45, 0x2b, 0xda, 0x21, 0x34, 0x86, 0x47, ++ 0xec, 0x72, 0x94, 0x3f, 0x11, 0xa8, 0x46, 0xe6, ++ 0x2f, 0xae, 0xbe, 0x8e, 0xb5, 0x36, 0xb0, 0xfd}, ++ .prime2_len = 128, ++ .exp1 = {0x76, 0xfe, 0x15, 0xf1, 0x8a, 0xe2, 0x39, 0xcd, ++ 0xf1, 0xdf, 0x6b, 0x44, 0x5c, 0xa4, 0xbc, 0x6b, ++ 0xb9, 0x68, 0xd7, 0x88, 0xc2, 0x19, 0x33, 0xa4, ++ 0xf5, 0xdc, 0xd2, 0x80, 0x03, 0x3d, 0x67, 0x12, ++ 0x06, 0x2c, 0xc0, 0x8a, 0x6d, 0xf2, 0x04, 0xc1, ++ 0xfb, 0xd0, 0xbe, 0x46, 0x30, 0x74, 0x43, 0xe6, ++ 0xdd, 0x4a, 0x64, 0x56, 0x37, 0x54, 0x29, 0xd4, ++ 0xe0, 0x38, 0xca, 0x25, 0x6f, 0xaf, 0x1c, 0x9b, ++ 0xde, 0x91, 0xc6, 0xb1, 0x7b, 0x76, 0xf8, 0x19, ++ 0x95, 0xf9, 0x1c, 0x48, 0xcb, 0xbe, 0xbc, 0x7b, ++ 0xf0, 0xe3, 0x49, 0x4c, 0x08, 0x35, 0x9e, 0x4e, ++ 0x8c, 0xd6, 0xa5, 0x87, 0xd7, 0xb9, 0x6d, 0x62, ++ 0x21, 0xfd, 0x7e, 0x0f, 0xb5, 0xc5, 0x57, 0x5f, ++ 0x08, 0x2e, 0xe5, 0x77, 0x69, 0x79, 0x80, 0x71, ++ 0xb2, 0xbb, 0xb4, 0xa3, 0x22, 0x38, 0x15, 0x1b, ++ 0x47, 0x31, 0x4b, 0xb6, 0x54, 0x79, 0x03, 0x11}, ++ .exp1_len = 128, ++ .exp2 = {0x99, 0x88, 0x48, 0xb0, 0x55, 0x49, 0x9a, 0x10, ++ 0x09, 0xcb, 0xc7, 0xd2, 0x94, 0xb3, 0x6b, 0x1f, ++ 0xfd, 0xf2, 0x02, 0x0e, 0x6e, 0x73, 0x64, 0x05, ++ 0x3e, 0x94, 0xde, 0x1a, 0x00, 0x0d, 0xc9, 0x34, ++ 0x05, 0x87, 0xf7, 0xe2, 0x72, 0x76, 0xf6, 0x8c, ++ 0xdf, 0x60, 0x8d, 0x75, 0x3b, 0x63, 0x37, 0x7b, ++ 0x03, 0xb6, 0xf4, 0x08, 0x4d, 0x2c, 0x02, 0x7c, ++ 0x4b, 0x38, 0x96, 0x0a, 0x62, 0x33, 0xba, 0x9e, ++ 0xd9, 0x73, 0x8b, 0x76, 0xf1, 0x0e, 0xa7, 0x5b, ++ 0xe4, 0x56, 0x07, 0x8b, 0xf7, 0x01, 0xf6, 0x7c, ++ 0xc6, 0xb3, 0xf3, 0xfd, 0xc1, 0x86, 0xe6, 0x43, ++ 0x36, 0xc7, 0x6b, 0x37, 0x2e, 0x80, 0x91, 0x0e, ++ 0xc8, 0x0b, 0x0a, 0xdc, 0xc2, 0x3d, 0x02, 0xfb, ++ 0x9a, 0xe1, 0x04, 0x86, 0xa2, 0x82, 0x48, 0x07, ++ 0x5b, 0x4e, 0xa7, 0xe5, 0x6d, 0xdf, 0xcf, 0x38, ++ 0x82, 0xe4, 0x51, 0x56, 0x14, 0x71, 0xa2, 0x91}, ++ .exp2_len = 128, ++ .coef = {0x64, 0x3b, 0xf7, 0x46, 0x42, 0x9f, 0x7d, 0x83, ++ 0x66, 0x7a, 0x06, 0x53, 0x02, 0x13, 0x47, 0xef, ++ 0xbf, 0xc0, 0x5e, 0x63, 0x51, 0xf8, 0x21, 0xa9, ++ 0xde, 0xbb, 0x60, 0xe0, 0xec, 0xcd, 0xe5, 0x00, ++ 0x5a, 0xd9, 0xe9, 0xec, 0x31, 0xe5, 0x58, 0xf7, ++ 0xe9, 0x2c, 0x29, 0x32, 0x8e, 0x74, 0x56, 0x9d, ++ 0x7c, 0xef, 0x7c, 0x74, 0xca, 0xbc, 0x2b, 0x35, ++ 0x5e, 0xd4, 0x01, 0xa1, 0xa0, 0x91, 0x4b, 0x4e, ++ 0x3c, 0xbb, 0x06, 0x48, 0x4e, 0x58, 0x19, 0x60, ++ 0x51, 0x16, 0x9e, 0xd1, 0x4c, 0xaa, 0x2e, 0xfa, ++ 0x6e, 0xa0, 0x44, 0xe0, 0x54, 0xd2, 0x61, 0x44, ++ 0xcc, 0x16, 0x29, 0xc5, 0x50, 0x10, 0x55, 0x8a, ++ 0x04, 0xe1, 0x33, 0xf4, 0x4b, 0x7c, 0x24, 0x4d, ++ 0xac, 0x25, 0xbf, 0x91, 0x3c, 0x57, 0xb8, 0x90, ++ 0xee, 0x49, 0xf5, 0x48, 0x25, 0x9c, 0xd6, 0x34, ++ 0x04, 0xfe, 0xf6, 0x85, 0x9d, 0xcf, 0x97, 0x5a}, ++ .coef_len = 128, ++ // msg is encrypted message ++ .msg = {0x8b, 0xfe, 0x26, 0x4e, 0x85, 0xd3, 0xbd, 0xea, ++ 0xa6, 0xb8, 0x85, 0x1b, 0x8e, 0x3b, 0x95, 0x6e, ++ 0xe3, 0xd2, 0x26, 0xfd, 0x3f, 0x69, 0x06, 0x3a, ++ 0x86, 0x88, 0x01, 0x73, 0xa2, 0x73, 0xd9, 0xf2, ++ 0x83, 0xb2, 0xee, 0xbd, 0xd1, 0xed, 0x35, 0xf7, ++ 0xe0, 0x2d, 0x91, 0xc5, 0x71, 0x98, 0x1b, 0x67, ++ 0x37, 0xd5, 0x32, 0x0b, 0xd8, 0x39, 0x6b, 0x0f, ++ 0x3a, 0xd5, 0xb0, 0x19, 0xda, 0xec, 0x1b, 0x0a, ++ 0xab, 0x3c, 0xbb, 0xc0, 0x26, 0x39, 0x5f, 0x4f, ++ 0xd1, 0x4f, 0x13, 0x67, 0x3f, 0x2d, 0xfc, 0x81, ++ 0xf9, 0xb6, 0x60, 0xec, 0x26, 0xac, 0x38, 0x1e, ++ 0x6d, 0xb3, 0x29, 0x9b, 0x4e, 0x46, 0x0b, 0x43, ++ 0xfa, 0xb9, 0x95, 0x5d, 0xf2, 0xb3, 0xcf, 0xaa, ++ 0x20, 0xe9, 0x00, 0xe1, 0x9c, 0x85, 0x62, 0x38, ++ 0xfd, 0x37, 0x18, 0x99, 0xc2, 0xbf, 0x2c, 0xe8, ++ 0xc8, 0x68, 0xb7, 0x67, 0x54, 0xe5, 0xdb, 0x3b, ++ 0x03, 0x65, 0x33, 0xfd, 0x60, 0x37, 0x46, 0xbe, ++ 0x13, 0xc1, 0x0d, 0x4e, 0x3e, 0x60, 0x22, 0xeb, ++ 0xc9, 0x05, 0xd2, 0x0c, 0x2a, 0x7f, 0x32, 0xb2, ++ 0x15, 0xa4, 0xcd, 0x53, 0xb3, 0xf4, 0x4c, 0xa1, ++ 0xc3, 0x27, 0xd2, 0xc2, 0xb6, 0x51, 0x14, 0x58, ++ 0x21, 0xc0, 0x83, 0x96, 0xc8, 0x90, 0x71, 0xf6, ++ 0x65, 0x34, 0x9c, 0x25, 0xe4, 0x4d, 0x27, 0x33, ++ 0xcd, 0x93, 0x05, 0x98, 0x5c, 0xee, 0xf6, 0x43, ++ 0x0c, 0x3c, 0xf5, 0x7a, 0xf5, 0xfa, 0x22, 0x40, ++ 0x89, 0x22, 0x12, 0x18, 0xfa, 0x34, 0x73, 0x7c, ++ 0x79, 0xc4, 0x46, 0xd2, 0x8a, 0x94, 0xc4, 0x1c, ++ 0x96, 0xe4, 0xe9, 0x2a, 0xc5, 0x3f, 0xbc, 0xf3, ++ 0x84, 0xde, 0xa8, 0x41, 0x9e, 0xa0, 0x89, 0xf8, ++ 0x78, 0x44, 0x45, 0xa4, 0x92, 0xc8, 0x12, 0xeb, ++ 0x0d, 0x40, 0x94, 0x67, 0xf7, 0x5a, 0xfd, 0x7d, ++ 0x4d, 0x10, 0x78, 0x88, 0x62, 0x05, 0xa0, 0x66}, ++ .msg_len = 256, ++ // sig is decrypted message ++ .sig = { 0x6c, 0x6f, 0x72, 0x65, 0x6d, 0x20, 0x69, 0x70, ++ 0x73, 0x75, 0x6d, 0x20, 0x64, 0x6f, 0x6c, 0x6f, ++ 0x72, 0x20, 0x73, 0x69, 0x74, 0x20, 0x61, 0x6d, ++ 0x65, 0x74}, ++ .sig_len = 26, ++ }, ++ { // 1 - bad, empty input ++ .mod = {0xc8, 0xcc, 0x83, 0x97, 0x14, 0x09, 0x8d, 0xa5, ++ 0x6c, 0xaa, 0x23, 0x64, 0x0f, 0x93, 0xdc, 0x89, ++ 0x97, 0xc1, 0x63, 0x72, 0x96, 0x8f, 0xc1, 0xb0, ++ 0xc6, 0xdf, 0x51, 0x13, 0xc1, 0xc9, 0x4e, 0x8b, ++ 0x21, 0xe4, 0x8a, 0xd2, 0x29, 0x7e, 0x65, 0x41, ++ 0x90, 0x11, 0xb4, 0xe6, 0xd8, 0xf5, 0xe7, 0x3b, ++ 0x1b, 0x78, 0xb2, 0x57, 0x40, 0x03, 0x21, 0xd1, ++ 0xef, 0x6b, 0x60, 0x2d, 0x4e, 0xc8, 0xce, 0x8d, ++ 0x14, 0x1c, 0x94, 0x90, 0x5e, 0xb4, 0xad, 0x30, ++ 0x66, 0x39, 0xa4, 0x92, 0x06, 0x53, 0x4b, 0x6e, ++ 0x7f, 0x26, 0x07, 0x42, 0x3e, 0x97, 0xdf, 0xfd, ++ 0x13, 0x3c, 0x88, 0xd7, 0x21, 0x39, 0x9d, 0xef, ++ 0xbc, 0x7e, 0x96, 0xcc, 0xdc, 0xbd, 0x7f, 0x3a, ++ 0xae, 0x1f, 0xe8, 0x92, 0x71, 0x2b, 0xfb, 0x49, ++ 0x29, 0x81, 0x7d, 0x51, 0x16, 0x66, 0x44, 0x0a, ++ 0x1f, 0xac, 0xb7, 0xa2, 0x08, 0xf5, 0xea, 0x16, ++ 0x59, 0x10, 0xad, 0xd8, 0xa3, 0xf2, 0xd4, 0x97, ++ 0x20, 0x23, 0x60, 0xcc, 0xb6, 0x32, 0x02, 0x4f, ++ 0x0d, 0x07, 0x16, 0x9c, 0x19, 0x18, 0xf3, 0x16, ++ 0xf7, 0x94, 0xb1, 0x43, 0xae, 0xf5, 0x4e, 0xc8, ++ 0x75, 0x22, 0xa4, 0xc0, 0x29, 0x78, 0xf9, 0x68, ++ 0x99, 0x80, 0xbf, 0xfb, 0xf6, 0x49, 0xc3, 0x07, ++ 0xe8, 0x18, 0x19, 0xbf, 0xf8, 0x84, 0x09, 0x63, ++ 0x8d, 0x48, 0xbd, 0x94, 0xbe, 0x15, 0x2b, 0x59, ++ 0xff, 0x64, 0x9f, 0xa0, 0xbd, 0x62, 0x9d, 0x0f, ++ 0xfa, 0x18, 0x13, 0xc3, 0xab, 0xf4, 0xb5, 0x6b, ++ 0xd3, 0xc2, 0xea, 0x54, 0x65, 0xdf, 0xfa, 0x14, ++ 0x58, 0x92, 0x92, 0xa9, 0xd8, 0xa2, 0x4a, 0xd2, ++ 0x6b, 0xe7, 0xee, 0x05, 0x10, 0x74, 0x1b, 0x63, ++ 0x82, 0xd4, 0x3c, 0x83, 0xd5, 0xbf, 0xa4, 0x0a, ++ 0x46, 0x61, 0x3d, 0x06, 0x2b, 0xe4, 0x45, 0x51, ++ 0x7d, 0xbc, 0xaf, 0x0c, 0xb4, 0xe1, 0xa7, 0x69}, ++ .mod_len = 256, ++ .pub_exp = {0x01, 0x00, 0x01}, ++ .pubexp_len = 3, ++ .priv_exp = {0x14, 0x55, 0x01, 0x0e, 0x0f, 0x2d, 0x58, 0x76, ++ 0x63, 0xa6, 0x66, 0xa6, 0xff, 0x1c, 0xcd, 0xbb, ++ 0xf0, 0xed, 0xd8, 0x10, 0x06, 0x46, 0xd0, 0x2a, ++ 0x02, 0x39, 0x22, 0x90, 0x89, 0x92, 0xc4, 0xad, ++ 0x39, 0xe5, 0x56, 0x59, 0x29, 0x72, 0x6e, 0xf6, ++ 0x50, 0x8c, 0x3a, 0x71, 0x15, 0x8e, 0xf0, 0xb6, ++ 0xff, 0x75, 0x1d, 0x39, 0xd0, 0x75, 0x80, 0xbb, ++ 0x2d, 0x2f, 0x06, 0x32, 0x10, 0x44, 0x2d, 0x06, ++ 0x03, 0xff, 0x50, 0xdb, 0xbd, 0x7b, 0x35, 0xfe, ++ 0x2c, 0x9b, 0xb1, 0x9a, 0x47, 0xa1, 0xaf, 0x85, ++ 0xa4, 0xc2, 0x49, 0x01, 0xe0, 0x2c, 0xa8, 0xb5, ++ 0x8b, 0x79, 0x19, 0xb2, 0x0e, 0xdf, 0x32, 0xaa, ++ 0xcf, 0xbf, 0x51, 0xad, 0xb4, 0xbc, 0x4b, 0x61, ++ 0xb9, 0xb7, 0xe9, 0x68, 0xca, 0xa4, 0xd5, 0x70, ++ 0xf7, 0x0e, 0xf1, 0x8d, 0x80, 0x63, 0x22, 0x88, ++ 0x93, 0xe4, 0x7d, 0x43, 0x9e, 0xfc, 0xa7, 0x93, ++ 0x25, 0x9b, 0xcf, 0x2c, 0xd1, 0x08, 0xa3, 0xd8, ++ 0x68, 0x8c, 0xdf, 0x07, 0x8e, 0x7a, 0xc7, 0x99, ++ 0x96, 0x9f, 0x23, 0x39, 0xd2, 0xc1, 0xf5, 0x22, ++ 0xb9, 0x69, 0x68, 0x46, 0x29, 0xa9, 0x33, 0xba, ++ 0xae, 0xc2, 0x68, 0x16, 0x25, 0xea, 0xb8, 0x4f, ++ 0x4e, 0x56, 0xf4, 0x44, 0x7e, 0x9d, 0x88, 0xfb, ++ 0x9a, 0x19, 0x9c, 0xf7, 0x10, 0x23, 0xe0, 0xe2, ++ 0x57, 0xb1, 0x44, 0x41, 0xb3, 0x3c, 0x84, 0xd3, ++ 0xbc, 0x67, 0xca, 0x80, 0x31, 0xd2, 0x61, 0x26, ++ 0x18, 0x10, 0x3a, 0x7a, 0x0a, 0x40, 0x84, 0x42, ++ 0x62, 0xf7, 0x5d, 0x88, 0x90, 0xcd, 0x61, 0x6e, ++ 0x51, 0xf9, 0x03, 0x54, 0x88, 0xfd, 0x6e, 0x09, ++ 0x9d, 0xe8, 0xff, 0x6d, 0x65, 0xa4, 0xff, 0x11, ++ 0x82, 0x54, 0x80, 0x7c, 0x9f, 0x58, 0xd2, 0xfb, ++ 0xba, 0x8b, 0xa1, 0x51, 0xdc, 0x8c, 0x68, 0xbe, ++ 0x34, 0x9c, 0x97, 0x7a, 0x20, 0x4e, 0x04, 0xc1}, ++ .privexp_len = 256, ++ .prime1 = {0xf8, 0xf5, 0xad, 0x6b, 0xa8, 0x28, 0x93, 0x1b, ++ 0xea, 0x45, 0x9b, 0x8a, 0x3f, 0x6d, 0xc0, 0x41, ++ 0xd2, 0x34, 0x82, 0x40, 0x9c, 0x25, 0x71, 0xe9, ++ 0x63, 0xf3, 0x1f, 0x74, 0x86, 0x02, 0xa2, 0x56, ++ 0x37, 0x1b, 0x38, 0x83, 0xed, 0x45, 0x9e, 0xcf, ++ 0x97, 0x05, 0x26, 0x45, 0x9e, 0xdd, 0x16, 0xe0, ++ 0x55, 0x22, 0xf5, 0xa4, 0x5d, 0x94, 0x75, 0x1b, ++ 0x2e, 0xc2, 0xda, 0xf2, 0x72, 0xc7, 0xf8, 0x81, ++ 0x6a, 0x52, 0xc0, 0x0d, 0x18, 0x08, 0x01, 0x71, ++ 0x63, 0x4d, 0xa8, 0x99, 0xd7, 0x97, 0x32, 0x22, ++ 0xf5, 0x1b, 0x93, 0x76, 0x30, 0x54, 0x86, 0x96, ++ 0xa9, 0xf7, 0xd8, 0xc2, 0x4a, 0x59, 0x49, 0x7c, ++ 0x1e, 0xfc, 0xd4, 0x55, 0xcf, 0xb9, 0x7e, 0xe8, ++ 0x6d, 0x2b, 0x6d, 0x34, 0x97, 0x2b, 0x33, 0x2f, ++ 0xda, 0x30, 0x3f, 0x04, 0x99, 0x9b, 0x4e, 0xb6, ++ 0xb5, 0xcc, 0x0b, 0xb3, 0x3e, 0x77, 0x61, 0xdd}, ++ .prime1_len = 128, ++ .prime2 = {0xce, 0x7a, 0x2e, 0x3b, 0x49, 0xa9, 0x0b, 0x96, ++ 0x33, 0x0a, 0x12, 0xdc, 0x68, 0x2b, 0xdf, 0xbd, ++ 0xfb, 0xae, 0x8d, 0xd6, 0xdc, 0x03, 0xb6, 0x14, ++ 0x7a, 0xef, 0xbd, 0x57, 0x57, 0x43, 0xf0, 0xf6, ++ 0xda, 0x4d, 0x86, 0x23, 0x50, 0x61, 0xb7, 0x1a, ++ 0xfd, 0x9c, 0xad, 0x2d, 0x34, 0x02, 0x5e, 0x56, ++ 0xac, 0x86, 0xb0, 0xf7, 0x74, 0x3e, 0xb3, 0x5e, ++ 0x1a, 0xcb, 0xca, 0x23, 0x78, 0x95, 0x42, 0x44, ++ 0x65, 0xb7, 0x06, 0xed, 0x22, 0x17, 0x5e, 0x57, ++ 0x18, 0xc8, 0xc7, 0x0b, 0x67, 0x03, 0xea, 0x8f, ++ 0x6b, 0x51, 0x0f, 0x94, 0x5b, 0xe4, 0x8e, 0x5a, ++ 0x36, 0xbb, 0x3c, 0x3c, 0x91, 0x73, 0x2b, 0x58, ++ 0x9d, 0xfc, 0x05, 0xd7, 0x2d, 0x80, 0x90, 0x31, ++ 0x94, 0x45, 0x2b, 0xda, 0x21, 0x34, 0x86, 0x47, ++ 0xec, 0x72, 0x94, 0x3f, 0x11, 0xa8, 0x46, 0xe6, ++ 0x2f, 0xae, 0xbe, 0x8e, 0xb5, 0x36, 0xb0, 0xfd}, ++ .prime2_len = 128, ++ .exp1 = {0x76, 0xfe, 0x15, 0xf1, 0x8a, 0xe2, 0x39, 0xcd, ++ 0xf1, 0xdf, 0x6b, 0x44, 0x5c, 0xa4, 0xbc, 0x6b, ++ 0xb9, 0x68, 0xd7, 0x88, 0xc2, 0x19, 0x33, 0xa4, ++ 0xf5, 0xdc, 0xd2, 0x80, 0x03, 0x3d, 0x67, 0x12, ++ 0x06, 0x2c, 0xc0, 0x8a, 0x6d, 0xf2, 0x04, 0xc1, ++ 0xfb, 0xd0, 0xbe, 0x46, 0x30, 0x74, 0x43, 0xe6, ++ 0xdd, 0x4a, 0x64, 0x56, 0x37, 0x54, 0x29, 0xd4, ++ 0xe0, 0x38, 0xca, 0x25, 0x6f, 0xaf, 0x1c, 0x9b, ++ 0xde, 0x91, 0xc6, 0xb1, 0x7b, 0x76, 0xf8, 0x19, ++ 0x95, 0xf9, 0x1c, 0x48, 0xcb, 0xbe, 0xbc, 0x7b, ++ 0xf0, 0xe3, 0x49, 0x4c, 0x08, 0x35, 0x9e, 0x4e, ++ 0x8c, 0xd6, 0xa5, 0x87, 0xd7, 0xb9, 0x6d, 0x62, ++ 0x21, 0xfd, 0x7e, 0x0f, 0xb5, 0xc5, 0x57, 0x5f, ++ 0x08, 0x2e, 0xe5, 0x77, 0x69, 0x79, 0x80, 0x71, ++ 0xb2, 0xbb, 0xb4, 0xa3, 0x22, 0x38, 0x15, 0x1b, ++ 0x47, 0x31, 0x4b, 0xb6, 0x54, 0x79, 0x03, 0x11}, ++ .exp1_len = 128, ++ .exp2 = {0x99, 0x88, 0x48, 0xb0, 0x55, 0x49, 0x9a, 0x10, ++ 0x09, 0xcb, 0xc7, 0xd2, 0x94, 0xb3, 0x6b, 0x1f, ++ 0xfd, 0xf2, 0x02, 0x0e, 0x6e, 0x73, 0x64, 0x05, ++ 0x3e, 0x94, 0xde, 0x1a, 0x00, 0x0d, 0xc9, 0x34, ++ 0x05, 0x87, 0xf7, 0xe2, 0x72, 0x76, 0xf6, 0x8c, ++ 0xdf, 0x60, 0x8d, 0x75, 0x3b, 0x63, 0x37, 0x7b, ++ 0x03, 0xb6, 0xf4, 0x08, 0x4d, 0x2c, 0x02, 0x7c, ++ 0x4b, 0x38, 0x96, 0x0a, 0x62, 0x33, 0xba, 0x9e, ++ 0xd9, 0x73, 0x8b, 0x76, 0xf1, 0x0e, 0xa7, 0x5b, ++ 0xe4, 0x56, 0x07, 0x8b, 0xf7, 0x01, 0xf6, 0x7c, ++ 0xc6, 0xb3, 0xf3, 0xfd, 0xc1, 0x86, 0xe6, 0x43, ++ 0x36, 0xc7, 0x6b, 0x37, 0x2e, 0x80, 0x91, 0x0e, ++ 0xc8, 0x0b, 0x0a, 0xdc, 0xc2, 0x3d, 0x02, 0xfb, ++ 0x9a, 0xe1, 0x04, 0x86, 0xa2, 0x82, 0x48, 0x07, ++ 0x5b, 0x4e, 0xa7, 0xe5, 0x6d, 0xdf, 0xcf, 0x38, ++ 0x82, 0xe4, 0x51, 0x56, 0x14, 0x71, 0xa2, 0x91}, ++ .exp2_len = 128, ++ .coef = {0x64, 0x3b, 0xf7, 0x46, 0x42, 0x9f, 0x7d, 0x83, ++ 0x66, 0x7a, 0x06, 0x53, 0x02, 0x13, 0x47, 0xef, ++ 0xbf, 0xc0, 0x5e, 0x63, 0x51, 0xf8, 0x21, 0xa9, ++ 0xde, 0xbb, 0x60, 0xe0, 0xec, 0xcd, 0xe5, 0x00, ++ 0x5a, 0xd9, 0xe9, 0xec, 0x31, 0xe5, 0x58, 0xf7, ++ 0xe9, 0x2c, 0x29, 0x32, 0x8e, 0x74, 0x56, 0x9d, ++ 0x7c, 0xef, 0x7c, 0x74, 0xca, 0xbc, 0x2b, 0x35, ++ 0x5e, 0xd4, 0x01, 0xa1, 0xa0, 0x91, 0x4b, 0x4e, ++ 0x3c, 0xbb, 0x06, 0x48, 0x4e, 0x58, 0x19, 0x60, ++ 0x51, 0x16, 0x9e, 0xd1, 0x4c, 0xaa, 0x2e, 0xfa, ++ 0x6e, 0xa0, 0x44, 0xe0, 0x54, 0xd2, 0x61, 0x44, ++ 0xcc, 0x16, 0x29, 0xc5, 0x50, 0x10, 0x55, 0x8a, ++ 0x04, 0xe1, 0x33, 0xf4, 0x4b, 0x7c, 0x24, 0x4d, ++ 0xac, 0x25, 0xbf, 0x91, 0x3c, 0x57, 0xb8, 0x90, ++ 0xee, 0x49, 0xf5, 0x48, 0x25, 0x9c, 0xd6, 0x34, ++ 0x04, 0xfe, 0xf6, 0x85, 0x9d, 0xcf, 0x97, 0x5a}, ++ .coef_len = 128, ++ // msg is encrypted message ++ .msg = {0x20, 0xaa, 0xa8, 0xad, 0xbb, 0xc5, 0x93, 0xa9, ++ 0x24, 0xba, 0x1c, 0x5c, 0x79, 0x90, 0xb5, 0xc2, ++ 0x24, 0x2a, 0xe4, 0xb9, 0x9d, 0x0f, 0xe6, 0x36, ++ 0xa1, 0x9a, 0x4c, 0xf7, 0x54, 0xed, 0xbc, 0xee, ++ 0x77, 0x4e, 0x47, 0x2f, 0xe0, 0x28, 0x16, 0x0e, ++ 0xd4, 0x26, 0x34, 0xf8, 0x86, 0x49, 0x00, 0xcb, ++ 0x51, 0x40, 0x06, 0xda, 0x64, 0x2c, 0xae, 0x6a, ++ 0xe8, 0xc7, 0xd0, 0x87, 0xca, 0xeb, 0xcf, 0xa6, ++ 0xda, 0xd1, 0x55, 0x13, 0x01, 0xe1, 0x30, 0x34, ++ 0x49, 0x89, 0xa1, 0xd4, 0x62, 0xd4, 0x16, 0x45, ++ 0x05, 0xf6, 0x39, 0x39, 0x33, 0x45, 0x0c, 0x67, ++ 0xbc, 0x6d, 0x39, 0xd8, 0xf5, 0x16, 0x09, 0x07, ++ 0xca, 0xbc, 0x25, 0x1b, 0x73, 0x79, 0x25, 0xa1, ++ 0xcf, 0x21, 0xe5, 0xc6, 0xaa, 0x57, 0x81, 0xb7, ++ 0x76, 0x9f, 0x6a, 0x2a, 0x58, 0x3d, 0x97, 0xcc, ++ 0xe0, 0x08, 0xc0, 0xf8, 0xb6, 0xad, 0xd5, 0xf0, ++ 0xb2, 0xbd, 0x80, 0xbe, 0xe6, 0x02, 0x37, 0xaa, ++ 0x39, 0xbb, 0x20, 0x71, 0x9f, 0xe7, 0x57, 0x49, ++ 0xf4, 0xbc, 0x4e, 0x42, 0x46, 0x6e, 0xf5, 0xa8, ++ 0x61, 0xae, 0x3a, 0x92, 0x39, 0x5c, 0x7d, 0x85, ++ 0x8d, 0x43, 0x0b, 0xfe, 0x38, 0x04, 0x0f, 0x44, ++ 0x5e, 0xa9, 0x3f, 0xa2, 0x95, 0x8b, 0x50, 0x35, ++ 0x39, 0x80, 0x0f, 0xfa, 0x5c, 0xe5, 0xf8, 0xcf, ++ 0x51, 0xfa, 0x81, 0x71, 0xa9, 0x1f, 0x36, 0xcb, ++ 0x4f, 0x45, 0x75, 0xe8, 0xde, 0x6b, 0x4d, 0x3f, ++ 0x09, 0x6e, 0xe1, 0x40, 0xb9, 0x38, 0xfd, 0x2f, ++ 0x50, 0xee, 0x13, 0xf0, 0xd0, 0x50, 0x22, 0x2e, ++ 0x2a, 0x72, 0xb0, 0xa3, 0x06, 0x9f, 0xf3, 0xa6, ++ 0x73, 0x8e, 0x82, 0xc8, 0x70, 0x90, 0xca, 0xa5, ++ 0xae, 0xd4, 0xfc, 0xbe, 0x88, 0x2c, 0x49, 0x64, ++ 0x6a, 0xa2, 0x50, 0xb9, 0x8f, 0x12, 0xf8, 0x3c, ++ 0x8d, 0x52, 0x81, 0x13, 0x61, 0x4a, 0x29, 0xe7}, ++ .msg_len = 256, ++ // sig is decrypted message ++ .sig = { 0x00 }, ++ .sig_len = 0, ++ }, ++ { // 2 - bad, max ++ .mod = {0xc8, 0xcc, 0x83, 0x97, 0x14, 0x09, 0x8d, 0xa5, ++ 0x6c, 0xaa, 0x23, 0x64, 0x0f, 0x93, 0xdc, 0x89, ++ 0x97, 0xc1, 0x63, 0x72, 0x96, 0x8f, 0xc1, 0xb0, ++ 0xc6, 0xdf, 0x51, 0x13, 0xc1, 0xc9, 0x4e, 0x8b, ++ 0x21, 0xe4, 0x8a, 0xd2, 0x29, 0x7e, 0x65, 0x41, ++ 0x90, 0x11, 0xb4, 0xe6, 0xd8, 0xf5, 0xe7, 0x3b, ++ 0x1b, 0x78, 0xb2, 0x57, 0x40, 0x03, 0x21, 0xd1, ++ 0xef, 0x6b, 0x60, 0x2d, 0x4e, 0xc8, 0xce, 0x8d, ++ 0x14, 0x1c, 0x94, 0x90, 0x5e, 0xb4, 0xad, 0x30, ++ 0x66, 0x39, 0xa4, 0x92, 0x06, 0x53, 0x4b, 0x6e, ++ 0x7f, 0x26, 0x07, 0x42, 0x3e, 0x97, 0xdf, 0xfd, ++ 0x13, 0x3c, 0x88, 0xd7, 0x21, 0x39, 0x9d, 0xef, ++ 0xbc, 0x7e, 0x96, 0xcc, 0xdc, 0xbd, 0x7f, 0x3a, ++ 0xae, 0x1f, 0xe8, 0x92, 0x71, 0x2b, 0xfb, 0x49, ++ 0x29, 0x81, 0x7d, 0x51, 0x16, 0x66, 0x44, 0x0a, ++ 0x1f, 0xac, 0xb7, 0xa2, 0x08, 0xf5, 0xea, 0x16, ++ 0x59, 0x10, 0xad, 0xd8, 0xa3, 0xf2, 0xd4, 0x97, ++ 0x20, 0x23, 0x60, 0xcc, 0xb6, 0x32, 0x02, 0x4f, ++ 0x0d, 0x07, 0x16, 0x9c, 0x19, 0x18, 0xf3, 0x16, ++ 0xf7, 0x94, 0xb1, 0x43, 0xae, 0xf5, 0x4e, 0xc8, ++ 0x75, 0x22, 0xa4, 0xc0, 0x29, 0x78, 0xf9, 0x68, ++ 0x99, 0x80, 0xbf, 0xfb, 0xf6, 0x49, 0xc3, 0x07, ++ 0xe8, 0x18, 0x19, 0xbf, 0xf8, 0x84, 0x09, 0x63, ++ 0x8d, 0x48, 0xbd, 0x94, 0xbe, 0x15, 0x2b, 0x59, ++ 0xff, 0x64, 0x9f, 0xa0, 0xbd, 0x62, 0x9d, 0x0f, ++ 0xfa, 0x18, 0x13, 0xc3, 0xab, 0xf4, 0xb5, 0x6b, ++ 0xd3, 0xc2, 0xea, 0x54, 0x65, 0xdf, 0xfa, 0x14, ++ 0x58, 0x92, 0x92, 0xa9, 0xd8, 0xa2, 0x4a, 0xd2, ++ 0x6b, 0xe7, 0xee, 0x05, 0x10, 0x74, 0x1b, 0x63, ++ 0x82, 0xd4, 0x3c, 0x83, 0xd5, 0xbf, 0xa4, 0x0a, ++ 0x46, 0x61, 0x3d, 0x06, 0x2b, 0xe4, 0x45, 0x51, ++ 0x7d, 0xbc, 0xaf, 0x0c, 0xb4, 0xe1, 0xa7, 0x69}, ++ .mod_len = 256, ++ .pub_exp = {0x01, 0x00, 0x01}, ++ .pubexp_len = 3, ++ .priv_exp = {0x14, 0x55, 0x01, 0x0e, 0x0f, 0x2d, 0x58, 0x76, ++ 0x63, 0xa6, 0x66, 0xa6, 0xff, 0x1c, 0xcd, 0xbb, ++ 0xf0, 0xed, 0xd8, 0x10, 0x06, 0x46, 0xd0, 0x2a, ++ 0x02, 0x39, 0x22, 0x90, 0x89, 0x92, 0xc4, 0xad, ++ 0x39, 0xe5, 0x56, 0x59, 0x29, 0x72, 0x6e, 0xf6, ++ 0x50, 0x8c, 0x3a, 0x71, 0x15, 0x8e, 0xf0, 0xb6, ++ 0xff, 0x75, 0x1d, 0x39, 0xd0, 0x75, 0x80, 0xbb, ++ 0x2d, 0x2f, 0x06, 0x32, 0x10, 0x44, 0x2d, 0x06, ++ 0x03, 0xff, 0x50, 0xdb, 0xbd, 0x7b, 0x35, 0xfe, ++ 0x2c, 0x9b, 0xb1, 0x9a, 0x47, 0xa1, 0xaf, 0x85, ++ 0xa4, 0xc2, 0x49, 0x01, 0xe0, 0x2c, 0xa8, 0xb5, ++ 0x8b, 0x79, 0x19, 0xb2, 0x0e, 0xdf, 0x32, 0xaa, ++ 0xcf, 0xbf, 0x51, 0xad, 0xb4, 0xbc, 0x4b, 0x61, ++ 0xb9, 0xb7, 0xe9, 0x68, 0xca, 0xa4, 0xd5, 0x70, ++ 0xf7, 0x0e, 0xf1, 0x8d, 0x80, 0x63, 0x22, 0x88, ++ 0x93, 0xe4, 0x7d, 0x43, 0x9e, 0xfc, 0xa7, 0x93, ++ 0x25, 0x9b, 0xcf, 0x2c, 0xd1, 0x08, 0xa3, 0xd8, ++ 0x68, 0x8c, 0xdf, 0x07, 0x8e, 0x7a, 0xc7, 0x99, ++ 0x96, 0x9f, 0x23, 0x39, 0xd2, 0xc1, 0xf5, 0x22, ++ 0xb9, 0x69, 0x68, 0x46, 0x29, 0xa9, 0x33, 0xba, ++ 0xae, 0xc2, 0x68, 0x16, 0x25, 0xea, 0xb8, 0x4f, ++ 0x4e, 0x56, 0xf4, 0x44, 0x7e, 0x9d, 0x88, 0xfb, ++ 0x9a, 0x19, 0x9c, 0xf7, 0x10, 0x23, 0xe0, 0xe2, ++ 0x57, 0xb1, 0x44, 0x41, 0xb3, 0x3c, 0x84, 0xd3, ++ 0xbc, 0x67, 0xca, 0x80, 0x31, 0xd2, 0x61, 0x26, ++ 0x18, 0x10, 0x3a, 0x7a, 0x0a, 0x40, 0x84, 0x42, ++ 0x62, 0xf7, 0x5d, 0x88, 0x90, 0xcd, 0x61, 0x6e, ++ 0x51, 0xf9, 0x03, 0x54, 0x88, 0xfd, 0x6e, 0x09, ++ 0x9d, 0xe8, 0xff, 0x6d, 0x65, 0xa4, 0xff, 0x11, ++ 0x82, 0x54, 0x80, 0x7c, 0x9f, 0x58, 0xd2, 0xfb, ++ 0xba, 0x8b, 0xa1, 0x51, 0xdc, 0x8c, 0x68, 0xbe, ++ 0x34, 0x9c, 0x97, 0x7a, 0x20, 0x4e, 0x04, 0xc1}, ++ .privexp_len = 256, ++ .prime1 = {0xf8, 0xf5, 0xad, 0x6b, 0xa8, 0x28, 0x93, 0x1b, ++ 0xea, 0x45, 0x9b, 0x8a, 0x3f, 0x6d, 0xc0, 0x41, ++ 0xd2, 0x34, 0x82, 0x40, 0x9c, 0x25, 0x71, 0xe9, ++ 0x63, 0xf3, 0x1f, 0x74, 0x86, 0x02, 0xa2, 0x56, ++ 0x37, 0x1b, 0x38, 0x83, 0xed, 0x45, 0x9e, 0xcf, ++ 0x97, 0x05, 0x26, 0x45, 0x9e, 0xdd, 0x16, 0xe0, ++ 0x55, 0x22, 0xf5, 0xa4, 0x5d, 0x94, 0x75, 0x1b, ++ 0x2e, 0xc2, 0xda, 0xf2, 0x72, 0xc7, 0xf8, 0x81, ++ 0x6a, 0x52, 0xc0, 0x0d, 0x18, 0x08, 0x01, 0x71, ++ 0x63, 0x4d, 0xa8, 0x99, 0xd7, 0x97, 0x32, 0x22, ++ 0xf5, 0x1b, 0x93, 0x76, 0x30, 0x54, 0x86, 0x96, ++ 0xa9, 0xf7, 0xd8, 0xc2, 0x4a, 0x59, 0x49, 0x7c, ++ 0x1e, 0xfc, 0xd4, 0x55, 0xcf, 0xb9, 0x7e, 0xe8, ++ 0x6d, 0x2b, 0x6d, 0x34, 0x97, 0x2b, 0x33, 0x2f, ++ 0xda, 0x30, 0x3f, 0x04, 0x99, 0x9b, 0x4e, 0xb6, ++ 0xb5, 0xcc, 0x0b, 0xb3, 0x3e, 0x77, 0x61, 0xdd}, ++ .prime1_len = 128, ++ .prime2 = {0xce, 0x7a, 0x2e, 0x3b, 0x49, 0xa9, 0x0b, 0x96, ++ 0x33, 0x0a, 0x12, 0xdc, 0x68, 0x2b, 0xdf, 0xbd, ++ 0xfb, 0xae, 0x8d, 0xd6, 0xdc, 0x03, 0xb6, 0x14, ++ 0x7a, 0xef, 0xbd, 0x57, 0x57, 0x43, 0xf0, 0xf6, ++ 0xda, 0x4d, 0x86, 0x23, 0x50, 0x61, 0xb7, 0x1a, ++ 0xfd, 0x9c, 0xad, 0x2d, 0x34, 0x02, 0x5e, 0x56, ++ 0xac, 0x86, 0xb0, 0xf7, 0x74, 0x3e, 0xb3, 0x5e, ++ 0x1a, 0xcb, 0xca, 0x23, 0x78, 0x95, 0x42, 0x44, ++ 0x65, 0xb7, 0x06, 0xed, 0x22, 0x17, 0x5e, 0x57, ++ 0x18, 0xc8, 0xc7, 0x0b, 0x67, 0x03, 0xea, 0x8f, ++ 0x6b, 0x51, 0x0f, 0x94, 0x5b, 0xe4, 0x8e, 0x5a, ++ 0x36, 0xbb, 0x3c, 0x3c, 0x91, 0x73, 0x2b, 0x58, ++ 0x9d, 0xfc, 0x05, 0xd7, 0x2d, 0x80, 0x90, 0x31, ++ 0x94, 0x45, 0x2b, 0xda, 0x21, 0x34, 0x86, 0x47, ++ 0xec, 0x72, 0x94, 0x3f, 0x11, 0xa8, 0x46, 0xe6, ++ 0x2f, 0xae, 0xbe, 0x8e, 0xb5, 0x36, 0xb0, 0xfd}, ++ .prime2_len = 128, ++ .exp1 = {0x76, 0xfe, 0x15, 0xf1, 0x8a, 0xe2, 0x39, 0xcd, ++ 0xf1, 0xdf, 0x6b, 0x44, 0x5c, 0xa4, 0xbc, 0x6b, ++ 0xb9, 0x68, 0xd7, 0x88, 0xc2, 0x19, 0x33, 0xa4, ++ 0xf5, 0xdc, 0xd2, 0x80, 0x03, 0x3d, 0x67, 0x12, ++ 0x06, 0x2c, 0xc0, 0x8a, 0x6d, 0xf2, 0x04, 0xc1, ++ 0xfb, 0xd0, 0xbe, 0x46, 0x30, 0x74, 0x43, 0xe6, ++ 0xdd, 0x4a, 0x64, 0x56, 0x37, 0x54, 0x29, 0xd4, ++ 0xe0, 0x38, 0xca, 0x25, 0x6f, 0xaf, 0x1c, 0x9b, ++ 0xde, 0x91, 0xc6, 0xb1, 0x7b, 0x76, 0xf8, 0x19, ++ 0x95, 0xf9, 0x1c, 0x48, 0xcb, 0xbe, 0xbc, 0x7b, ++ 0xf0, 0xe3, 0x49, 0x4c, 0x08, 0x35, 0x9e, 0x4e, ++ 0x8c, 0xd6, 0xa5, 0x87, 0xd7, 0xb9, 0x6d, 0x62, ++ 0x21, 0xfd, 0x7e, 0x0f, 0xb5, 0xc5, 0x57, 0x5f, ++ 0x08, 0x2e, 0xe5, 0x77, 0x69, 0x79, 0x80, 0x71, ++ 0xb2, 0xbb, 0xb4, 0xa3, 0x22, 0x38, 0x15, 0x1b, ++ 0x47, 0x31, 0x4b, 0xb6, 0x54, 0x79, 0x03, 0x11}, ++ .exp1_len = 128, ++ .exp2 = {0x99, 0x88, 0x48, 0xb0, 0x55, 0x49, 0x9a, 0x10, ++ 0x09, 0xcb, 0xc7, 0xd2, 0x94, 0xb3, 0x6b, 0x1f, ++ 0xfd, 0xf2, 0x02, 0x0e, 0x6e, 0x73, 0x64, 0x05, ++ 0x3e, 0x94, 0xde, 0x1a, 0x00, 0x0d, 0xc9, 0x34, ++ 0x05, 0x87, 0xf7, 0xe2, 0x72, 0x76, 0xf6, 0x8c, ++ 0xdf, 0x60, 0x8d, 0x75, 0x3b, 0x63, 0x37, 0x7b, ++ 0x03, 0xb6, 0xf4, 0x08, 0x4d, 0x2c, 0x02, 0x7c, ++ 0x4b, 0x38, 0x96, 0x0a, 0x62, 0x33, 0xba, 0x9e, ++ 0xd9, 0x73, 0x8b, 0x76, 0xf1, 0x0e, 0xa7, 0x5b, ++ 0xe4, 0x56, 0x07, 0x8b, 0xf7, 0x01, 0xf6, 0x7c, ++ 0xc6, 0xb3, 0xf3, 0xfd, 0xc1, 0x86, 0xe6, 0x43, ++ 0x36, 0xc7, 0x6b, 0x37, 0x2e, 0x80, 0x91, 0x0e, ++ 0xc8, 0x0b, 0x0a, 0xdc, 0xc2, 0x3d, 0x02, 0xfb, ++ 0x9a, 0xe1, 0x04, 0x86, 0xa2, 0x82, 0x48, 0x07, ++ 0x5b, 0x4e, 0xa7, 0xe5, 0x6d, 0xdf, 0xcf, 0x38, ++ 0x82, 0xe4, 0x51, 0x56, 0x14, 0x71, 0xa2, 0x91}, ++ .exp2_len = 128, ++ .coef = {0x64, 0x3b, 0xf7, 0x46, 0x42, 0x9f, 0x7d, 0x83, ++ 0x66, 0x7a, 0x06, 0x53, 0x02, 0x13, 0x47, 0xef, ++ 0xbf, 0xc0, 0x5e, 0x63, 0x51, 0xf8, 0x21, 0xa9, ++ 0xde, 0xbb, 0x60, 0xe0, 0xec, 0xcd, 0xe5, 0x00, ++ 0x5a, 0xd9, 0xe9, 0xec, 0x31, 0xe5, 0x58, 0xf7, ++ 0xe9, 0x2c, 0x29, 0x32, 0x8e, 0x74, 0x56, 0x9d, ++ 0x7c, 0xef, 0x7c, 0x74, 0xca, 0xbc, 0x2b, 0x35, ++ 0x5e, 0xd4, 0x01, 0xa1, 0xa0, 0x91, 0x4b, 0x4e, ++ 0x3c, 0xbb, 0x06, 0x48, 0x4e, 0x58, 0x19, 0x60, ++ 0x51, 0x16, 0x9e, 0xd1, 0x4c, 0xaa, 0x2e, 0xfa, ++ 0x6e, 0xa0, 0x44, 0xe0, 0x54, 0xd2, 0x61, 0x44, ++ 0xcc, 0x16, 0x29, 0xc5, 0x50, 0x10, 0x55, 0x8a, ++ 0x04, 0xe1, 0x33, 0xf4, 0x4b, 0x7c, 0x24, 0x4d, ++ 0xac, 0x25, 0xbf, 0x91, 0x3c, 0x57, 0xb8, 0x90, ++ 0xee, 0x49, 0xf5, 0x48, 0x25, 0x9c, 0xd6, 0x34, ++ 0x04, 0xfe, 0xf6, 0x85, 0x9d, 0xcf, 0x97, 0x5a}, ++ .coef_len = 128, ++ // msg is encrypted message ++ .msg = {0x48, 0xcc, 0xea, 0xb1, 0x0f, 0x39, 0xa4, 0xdb, ++ 0x32, 0xf6, 0x00, 0x74, 0xfe, 0xea, 0x47, 0x3c, ++ 0xbc, 0xdb, 0x7a, 0xcc, 0xf9, 0x2e, 0x15, 0x04, ++ 0x17, 0xf7, 0x6b, 0x44, 0x75, 0x6b, 0x19, 0x0e, ++ 0x84, 0x3e, 0x79, 0xec, 0x12, 0xaa, 0x85, 0x08, ++ 0x3a, 0x21, 0xf5, 0x43, 0x7e, 0x7b, 0xad, 0x0a, ++ 0x60, 0x48, 0x2e, 0x60, 0x11, 0x98, 0xf9, 0xd8, ++ 0x69, 0x23, 0x23, 0x9c, 0x87, 0x86, 0xee, 0x72, ++ 0x82, 0x85, 0xaf, 0xd0, 0x93, 0x7f, 0x7d, 0xde, ++ 0x12, 0x71, 0x7f, 0x28, 0x38, 0x98, 0x43, 0xd7, ++ 0x37, 0x59, 0x12, 0xb0, 0x7b, 0x99, 0x1f, 0x4f, ++ 0xdb, 0x01, 0x90, 0xfc, 0xed, 0x8b, 0xa6, 0x65, ++ 0x31, 0x43, 0x67, 0xe8, 0xc5, 0xf9, 0xd2, 0x98, ++ 0x1d, 0x0f, 0x51, 0x28, 0xfe, 0xeb, 0x46, 0xcb, ++ 0x50, 0xfc, 0x23, 0x7e, 0x64, 0x43, 0x8a, 0x86, ++ 0xdf, 0x19, 0x8d, 0xd0, 0x20, 0x93, 0x64, 0xae, ++ 0x3a, 0x84, 0x2d, 0x77, 0x53, 0x2b, 0x66, 0xb7, ++ 0xef, 0x26, 0x3b, 0x83, 0xb1, 0x54, 0x1e, 0xd6, ++ 0x71, 0xb1, 0x20, 0xdf, 0xd6, 0x60, 0x46, 0x2e, ++ 0x21, 0x07, 0xa4, 0xee, 0x7b, 0x96, 0x4e, 0x73, ++ 0x4a, 0x7b, 0xd6, 0x8d, 0x90, 0xdd, 0xa6, 0x17, ++ 0x70, 0x65, 0x8a, 0x3c, 0x24, 0x29, 0x48, 0x53, ++ 0x2d, 0xa3, 0x26, 0x48, 0x68, 0x7e, 0x03, 0x18, ++ 0x28, 0x64, 0x73, 0xf6, 0x75, 0xb4, 0x12, 0xd6, ++ 0x46, 0x8f, 0x01, 0x3f, 0x14, 0xd7, 0x60, 0xa3, ++ 0x58, 0xdf, 0xca, 0xd3, 0xcd, 0xa2, 0xaf, 0xee, ++ 0xc5, 0xe2, 0x68, 0xa3, 0x7d, 0x25, 0x0c, 0x37, ++ 0xf7, 0x22, 0xf4, 0x68, 0xa7, 0x0d, 0xfd, 0x92, ++ 0xd7, 0x29, 0x4c, 0x3c, 0x1e, 0xe1, 0xe7, 0xf8, ++ 0x84, 0x3b, 0x7d, 0x16, 0xf9, 0xf3, 0x7e, 0xf3, ++ 0x57, 0x48, 0xc3, 0xae, 0x93, 0xaa, 0x15, 0x5c, ++ 0xdc, 0xdf, 0xeb, 0x4e, 0x78, 0x56, 0x73, 0x03}, ++ .msg_len = 256, ++ // sig is decrypted message ++ .sig = { 0x22, 0xd8, 0x50, 0x13, 0x7b, 0x9e, 0xeb, 0xe0, ++ 0x92, 0xb2, 0x4f, 0x60, 0x2d, 0xc5, 0xbb, 0x79, ++ 0x18, 0xc1, 0x6b, 0xd8, 0x9d, 0xdb, 0xf2, 0x04, ++ 0x67, 0xb1, 0x19, 0xd2, 0x05, 0xf9, 0xc2, 0xe4, ++ 0xbd, 0x7d, 0x25, 0x92, 0xcf, 0x1e, 0x53, 0x21, ++ 0x06, 0xe0, 0xf3, 0x35, 0x57, 0x56, 0x59, 0x23, ++ 0xc7, 0x3a, 0x02, 0xd4, 0xf0, 0x9c, 0x0c, 0x22, ++ 0xbe, 0xa8, 0x91, 0x48, 0x18, 0x3e, 0x60, 0x31, ++ 0x7f, 0x70, 0x28, 0xb3, 0xaa, 0x1f, 0x26, 0x1f, ++ 0x91, 0xc9, 0x79, 0x39, 0x31, 0x01, 0xd7, 0xe1, ++ 0x5f, 0x40, 0x67, 0xe6, 0x39, 0x79, 0xb3, 0x27, ++ 0x51, 0x65, 0x8e, 0xf7, 0x69, 0x61, 0x0f, 0xe9, ++ 0x7c, 0xf9, 0xce, 0xf3, 0x27, 0x8b, 0x31, 0x17, ++ 0xd3, 0x84, 0x05, 0x1c, 0x3b, 0x1d, 0x82, 0xc2, ++ 0x51, 0xc2, 0x30, 0x54, 0x18, 0xc8, 0xf6, 0x84, ++ 0x05, 0x30, 0xe6, 0x31, 0xaa, 0xd6, 0x3e, 0x70, ++ 0xe2, 0x0e, 0x02, 0x5b, 0xcd, 0x8e, 0xfb, 0x54, ++ 0xc9, 0x2e, 0xc6, 0xd3, 0xb1, 0x06, 0xa2, 0xf8, ++ 0xe6, 0x4e, 0xef, 0xf7, 0xd3, 0x84, 0x95, 0xb0, ++ 0xfc, 0x50, 0xc9, 0x71, 0x38, 0xaf, 0x4b, 0x1c, ++ 0x0a, 0x67, 0xa1, 0xc4, 0xe2, 0x7b, 0x07, 0x7b, ++ 0x84, 0x39, 0x33, 0x2e, 0xdf, 0xa8, 0x60, 0x8d, ++ 0xfe, 0xae, 0x65, 0x3c, 0xd6, 0xa6, 0x28, 0xac, ++ 0x55, 0x03, 0x95, 0xf7, 0xe7, 0x43, 0x90, 0xe4, ++ 0x2c, 0x11, 0x68, 0x22, 0x34, 0x87, 0x09, 0x25, ++ 0xee, 0xaa, 0x1f, 0xa7, 0x1b, 0x76, 0xcf, 0x1f, ++ 0x2e, 0xe3, 0xbd, 0xa6, 0x9f, 0x67, 0x17, 0x03, ++ 0x3f, 0xf8, 0xb7, 0xc9, 0x5c, 0x97, 0x99, 0xe7, ++ 0xa3, 0xbe, 0xa5, 0xe7, 0xe4, 0xa1, 0xc3, 0x59, ++ 0x77, 0x2f, 0xb6, 0xb1, 0xc6, 0xe6, 0xc5, 0x16, ++ 0x66, 0x1d, 0xfe, 0x30, 0xc3}, ++ .sig_len = 245, ++ }, ++ { // 3 bad, prf ++ .mod = {0xc8, 0xcc, 0x83, 0x97, 0x14, 0x09, 0x8d, 0xa5, ++ 0x6c, 0xaa, 0x23, 0x64, 0x0f, 0x93, 0xdc, 0x89, ++ 0x97, 0xc1, 0x63, 0x72, 0x96, 0x8f, 0xc1, 0xb0, ++ 0xc6, 0xdf, 0x51, 0x13, 0xc1, 0xc9, 0x4e, 0x8b, ++ 0x21, 0xe4, 0x8a, 0xd2, 0x29, 0x7e, 0x65, 0x41, ++ 0x90, 0x11, 0xb4, 0xe6, 0xd8, 0xf5, 0xe7, 0x3b, ++ 0x1b, 0x78, 0xb2, 0x57, 0x40, 0x03, 0x21, 0xd1, ++ 0xef, 0x6b, 0x60, 0x2d, 0x4e, 0xc8, 0xce, 0x8d, ++ 0x14, 0x1c, 0x94, 0x90, 0x5e, 0xb4, 0xad, 0x30, ++ 0x66, 0x39, 0xa4, 0x92, 0x06, 0x53, 0x4b, 0x6e, ++ 0x7f, 0x26, 0x07, 0x42, 0x3e, 0x97, 0xdf, 0xfd, ++ 0x13, 0x3c, 0x88, 0xd7, 0x21, 0x39, 0x9d, 0xef, ++ 0xbc, 0x7e, 0x96, 0xcc, 0xdc, 0xbd, 0x7f, 0x3a, ++ 0xae, 0x1f, 0xe8, 0x92, 0x71, 0x2b, 0xfb, 0x49, ++ 0x29, 0x81, 0x7d, 0x51, 0x16, 0x66, 0x44, 0x0a, ++ 0x1f, 0xac, 0xb7, 0xa2, 0x08, 0xf5, 0xea, 0x16, ++ 0x59, 0x10, 0xad, 0xd8, 0xa3, 0xf2, 0xd4, 0x97, ++ 0x20, 0x23, 0x60, 0xcc, 0xb6, 0x32, 0x02, 0x4f, ++ 0x0d, 0x07, 0x16, 0x9c, 0x19, 0x18, 0xf3, 0x16, ++ 0xf7, 0x94, 0xb1, 0x43, 0xae, 0xf5, 0x4e, 0xc8, ++ 0x75, 0x22, 0xa4, 0xc0, 0x29, 0x78, 0xf9, 0x68, ++ 0x99, 0x80, 0xbf, 0xfb, 0xf6, 0x49, 0xc3, 0x07, ++ 0xe8, 0x18, 0x19, 0xbf, 0xf8, 0x84, 0x09, 0x63, ++ 0x8d, 0x48, 0xbd, 0x94, 0xbe, 0x15, 0x2b, 0x59, ++ 0xff, 0x64, 0x9f, 0xa0, 0xbd, 0x62, 0x9d, 0x0f, ++ 0xfa, 0x18, 0x13, 0xc3, 0xab, 0xf4, 0xb5, 0x6b, ++ 0xd3, 0xc2, 0xea, 0x54, 0x65, 0xdf, 0xfa, 0x14, ++ 0x58, 0x92, 0x92, 0xa9, 0xd8, 0xa2, 0x4a, 0xd2, ++ 0x6b, 0xe7, 0xee, 0x05, 0x10, 0x74, 0x1b, 0x63, ++ 0x82, 0xd4, 0x3c, 0x83, 0xd5, 0xbf, 0xa4, 0x0a, ++ 0x46, 0x61, 0x3d, 0x06, 0x2b, 0xe4, 0x45, 0x51, ++ 0x7d, 0xbc, 0xaf, 0x0c, 0xb4, 0xe1, 0xa7, 0x69}, ++ .mod_len = 256, ++ .pub_exp = {0x01, 0x00, 0x01}, ++ .pubexp_len = 3, ++ .priv_exp = {0x14, 0x55, 0x01, 0x0e, 0x0f, 0x2d, 0x58, 0x76, ++ 0x63, 0xa6, 0x66, 0xa6, 0xff, 0x1c, 0xcd, 0xbb, ++ 0xf0, 0xed, 0xd8, 0x10, 0x06, 0x46, 0xd0, 0x2a, ++ 0x02, 0x39, 0x22, 0x90, 0x89, 0x92, 0xc4, 0xad, ++ 0x39, 0xe5, 0x56, 0x59, 0x29, 0x72, 0x6e, 0xf6, ++ 0x50, 0x8c, 0x3a, 0x71, 0x15, 0x8e, 0xf0, 0xb6, ++ 0xff, 0x75, 0x1d, 0x39, 0xd0, 0x75, 0x80, 0xbb, ++ 0x2d, 0x2f, 0x06, 0x32, 0x10, 0x44, 0x2d, 0x06, ++ 0x03, 0xff, 0x50, 0xdb, 0xbd, 0x7b, 0x35, 0xfe, ++ 0x2c, 0x9b, 0xb1, 0x9a, 0x47, 0xa1, 0xaf, 0x85, ++ 0xa4, 0xc2, 0x49, 0x01, 0xe0, 0x2c, 0xa8, 0xb5, ++ 0x8b, 0x79, 0x19, 0xb2, 0x0e, 0xdf, 0x32, 0xaa, ++ 0xcf, 0xbf, 0x51, 0xad, 0xb4, 0xbc, 0x4b, 0x61, ++ 0xb9, 0xb7, 0xe9, 0x68, 0xca, 0xa4, 0xd5, 0x70, ++ 0xf7, 0x0e, 0xf1, 0x8d, 0x80, 0x63, 0x22, 0x88, ++ 0x93, 0xe4, 0x7d, 0x43, 0x9e, 0xfc, 0xa7, 0x93, ++ 0x25, 0x9b, 0xcf, 0x2c, 0xd1, 0x08, 0xa3, 0xd8, ++ 0x68, 0x8c, 0xdf, 0x07, 0x8e, 0x7a, 0xc7, 0x99, ++ 0x96, 0x9f, 0x23, 0x39, 0xd2, 0xc1, 0xf5, 0x22, ++ 0xb9, 0x69, 0x68, 0x46, 0x29, 0xa9, 0x33, 0xba, ++ 0xae, 0xc2, 0x68, 0x16, 0x25, 0xea, 0xb8, 0x4f, ++ 0x4e, 0x56, 0xf4, 0x44, 0x7e, 0x9d, 0x88, 0xfb, ++ 0x9a, 0x19, 0x9c, 0xf7, 0x10, 0x23, 0xe0, 0xe2, ++ 0x57, 0xb1, 0x44, 0x41, 0xb3, 0x3c, 0x84, 0xd3, ++ 0xbc, 0x67, 0xca, 0x80, 0x31, 0xd2, 0x61, 0x26, ++ 0x18, 0x10, 0x3a, 0x7a, 0x0a, 0x40, 0x84, 0x42, ++ 0x62, 0xf7, 0x5d, 0x88, 0x90, 0xcd, 0x61, 0x6e, ++ 0x51, 0xf9, 0x03, 0x54, 0x88, 0xfd, 0x6e, 0x09, ++ 0x9d, 0xe8, 0xff, 0x6d, 0x65, 0xa4, 0xff, 0x11, ++ 0x82, 0x54, 0x80, 0x7c, 0x9f, 0x58, 0xd2, 0xfb, ++ 0xba, 0x8b, 0xa1, 0x51, 0xdc, 0x8c, 0x68, 0xbe, ++ 0x34, 0x9c, 0x97, 0x7a, 0x20, 0x4e, 0x04, 0xc1}, ++ .privexp_len = 256, ++ .prime1 = {0xf8, 0xf5, 0xad, 0x6b, 0xa8, 0x28, 0x93, 0x1b, ++ 0xea, 0x45, 0x9b, 0x8a, 0x3f, 0x6d, 0xc0, 0x41, ++ 0xd2, 0x34, 0x82, 0x40, 0x9c, 0x25, 0x71, 0xe9, ++ 0x63, 0xf3, 0x1f, 0x74, 0x86, 0x02, 0xa2, 0x56, ++ 0x37, 0x1b, 0x38, 0x83, 0xed, 0x45, 0x9e, 0xcf, ++ 0x97, 0x05, 0x26, 0x45, 0x9e, 0xdd, 0x16, 0xe0, ++ 0x55, 0x22, 0xf5, 0xa4, 0x5d, 0x94, 0x75, 0x1b, ++ 0x2e, 0xc2, 0xda, 0xf2, 0x72, 0xc7, 0xf8, 0x81, ++ 0x6a, 0x52, 0xc0, 0x0d, 0x18, 0x08, 0x01, 0x71, ++ 0x63, 0x4d, 0xa8, 0x99, 0xd7, 0x97, 0x32, 0x22, ++ 0xf5, 0x1b, 0x93, 0x76, 0x30, 0x54, 0x86, 0x96, ++ 0xa9, 0xf7, 0xd8, 0xc2, 0x4a, 0x59, 0x49, 0x7c, ++ 0x1e, 0xfc, 0xd4, 0x55, 0xcf, 0xb9, 0x7e, 0xe8, ++ 0x6d, 0x2b, 0x6d, 0x34, 0x97, 0x2b, 0x33, 0x2f, ++ 0xda, 0x30, 0x3f, 0x04, 0x99, 0x9b, 0x4e, 0xb6, ++ 0xb5, 0xcc, 0x0b, 0xb3, 0x3e, 0x77, 0x61, 0xdd}, ++ .prime1_len = 128, ++ .prime2 = {0xce, 0x7a, 0x2e, 0x3b, 0x49, 0xa9, 0x0b, 0x96, ++ 0x33, 0x0a, 0x12, 0xdc, 0x68, 0x2b, 0xdf, 0xbd, ++ 0xfb, 0xae, 0x8d, 0xd6, 0xdc, 0x03, 0xb6, 0x14, ++ 0x7a, 0xef, 0xbd, 0x57, 0x57, 0x43, 0xf0, 0xf6, ++ 0xda, 0x4d, 0x86, 0x23, 0x50, 0x61, 0xb7, 0x1a, ++ 0xfd, 0x9c, 0xad, 0x2d, 0x34, 0x02, 0x5e, 0x56, ++ 0xac, 0x86, 0xb0, 0xf7, 0x74, 0x3e, 0xb3, 0x5e, ++ 0x1a, 0xcb, 0xca, 0x23, 0x78, 0x95, 0x42, 0x44, ++ 0x65, 0xb7, 0x06, 0xed, 0x22, 0x17, 0x5e, 0x57, ++ 0x18, 0xc8, 0xc7, 0x0b, 0x67, 0x03, 0xea, 0x8f, ++ 0x6b, 0x51, 0x0f, 0x94, 0x5b, 0xe4, 0x8e, 0x5a, ++ 0x36, 0xbb, 0x3c, 0x3c, 0x91, 0x73, 0x2b, 0x58, ++ 0x9d, 0xfc, 0x05, 0xd7, 0x2d, 0x80, 0x90, 0x31, ++ 0x94, 0x45, 0x2b, 0xda, 0x21, 0x34, 0x86, 0x47, ++ 0xec, 0x72, 0x94, 0x3f, 0x11, 0xa8, 0x46, 0xe6, ++ 0x2f, 0xae, 0xbe, 0x8e, 0xb5, 0x36, 0xb0, 0xfd}, ++ .prime2_len = 128, ++ .exp1 = {0x76, 0xfe, 0x15, 0xf1, 0x8a, 0xe2, 0x39, 0xcd, ++ 0xf1, 0xdf, 0x6b, 0x44, 0x5c, 0xa4, 0xbc, 0x6b, ++ 0xb9, 0x68, 0xd7, 0x88, 0xc2, 0x19, 0x33, 0xa4, ++ 0xf5, 0xdc, 0xd2, 0x80, 0x03, 0x3d, 0x67, 0x12, ++ 0x06, 0x2c, 0xc0, 0x8a, 0x6d, 0xf2, 0x04, 0xc1, ++ 0xfb, 0xd0, 0xbe, 0x46, 0x30, 0x74, 0x43, 0xe6, ++ 0xdd, 0x4a, 0x64, 0x56, 0x37, 0x54, 0x29, 0xd4, ++ 0xe0, 0x38, 0xca, 0x25, 0x6f, 0xaf, 0x1c, 0x9b, ++ 0xde, 0x91, 0xc6, 0xb1, 0x7b, 0x76, 0xf8, 0x19, ++ 0x95, 0xf9, 0x1c, 0x48, 0xcb, 0xbe, 0xbc, 0x7b, ++ 0xf0, 0xe3, 0x49, 0x4c, 0x08, 0x35, 0x9e, 0x4e, ++ 0x8c, 0xd6, 0xa5, 0x87, 0xd7, 0xb9, 0x6d, 0x62, ++ 0x21, 0xfd, 0x7e, 0x0f, 0xb5, 0xc5, 0x57, 0x5f, ++ 0x08, 0x2e, 0xe5, 0x77, 0x69, 0x79, 0x80, 0x71, ++ 0xb2, 0xbb, 0xb4, 0xa3, 0x22, 0x38, 0x15, 0x1b, ++ 0x47, 0x31, 0x4b, 0xb6, 0x54, 0x79, 0x03, 0x11}, ++ .exp1_len = 128, ++ .exp2 = {0x99, 0x88, 0x48, 0xb0, 0x55, 0x49, 0x9a, 0x10, ++ 0x09, 0xcb, 0xc7, 0xd2, 0x94, 0xb3, 0x6b, 0x1f, ++ 0xfd, 0xf2, 0x02, 0x0e, 0x6e, 0x73, 0x64, 0x05, ++ 0x3e, 0x94, 0xde, 0x1a, 0x00, 0x0d, 0xc9, 0x34, ++ 0x05, 0x87, 0xf7, 0xe2, 0x72, 0x76, 0xf6, 0x8c, ++ 0xdf, 0x60, 0x8d, 0x75, 0x3b, 0x63, 0x37, 0x7b, ++ 0x03, 0xb6, 0xf4, 0x08, 0x4d, 0x2c, 0x02, 0x7c, ++ 0x4b, 0x38, 0x96, 0x0a, 0x62, 0x33, 0xba, 0x9e, ++ 0xd9, 0x73, 0x8b, 0x76, 0xf1, 0x0e, 0xa7, 0x5b, ++ 0xe4, 0x56, 0x07, 0x8b, 0xf7, 0x01, 0xf6, 0x7c, ++ 0xc6, 0xb3, 0xf3, 0xfd, 0xc1, 0x86, 0xe6, 0x43, ++ 0x36, 0xc7, 0x6b, 0x37, 0x2e, 0x80, 0x91, 0x0e, ++ 0xc8, 0x0b, 0x0a, 0xdc, 0xc2, 0x3d, 0x02, 0xfb, ++ 0x9a, 0xe1, 0x04, 0x86, 0xa2, 0x82, 0x48, 0x07, ++ 0x5b, 0x4e, 0xa7, 0xe5, 0x6d, 0xdf, 0xcf, 0x38, ++ 0x82, 0xe4, 0x51, 0x56, 0x14, 0x71, 0xa2, 0x91}, ++ .exp2_len = 128, ++ .coef = {0x64, 0x3b, 0xf7, 0x46, 0x42, 0x9f, 0x7d, 0x83, ++ 0x66, 0x7a, 0x06, 0x53, 0x02, 0x13, 0x47, 0xef, ++ 0xbf, 0xc0, 0x5e, 0x63, 0x51, 0xf8, 0x21, 0xa9, ++ 0xde, 0xbb, 0x60, 0xe0, 0xec, 0xcd, 0xe5, 0x00, ++ 0x5a, 0xd9, 0xe9, 0xec, 0x31, 0xe5, 0x58, 0xf7, ++ 0xe9, 0x2c, 0x29, 0x32, 0x8e, 0x74, 0x56, 0x9d, ++ 0x7c, 0xef, 0x7c, 0x74, 0xca, 0xbc, 0x2b, 0x35, ++ 0x5e, 0xd4, 0x01, 0xa1, 0xa0, 0x91, 0x4b, 0x4e, ++ 0x3c, 0xbb, 0x06, 0x48, 0x4e, 0x58, 0x19, 0x60, ++ 0x51, 0x16, 0x9e, 0xd1, 0x4c, 0xaa, 0x2e, 0xfa, ++ 0x6e, 0xa0, 0x44, 0xe0, 0x54, 0xd2, 0x61, 0x44, ++ 0xcc, 0x16, 0x29, 0xc5, 0x50, 0x10, 0x55, 0x8a, ++ 0x04, 0xe1, 0x33, 0xf4, 0x4b, 0x7c, 0x24, 0x4d, ++ 0xac, 0x25, 0xbf, 0x91, 0x3c, 0x57, 0xb8, 0x90, ++ 0xee, 0x49, 0xf5, 0x48, 0x25, 0x9c, 0xd6, 0x34, ++ 0x04, 0xfe, 0xf6, 0x85, 0x9d, 0xcf, 0x97, 0x5a}, ++ .coef_len = 128, ++ // msg is encrypted message ++ .msg = {0x14, 0x39, 0xe0, 0x8c, 0x3f, 0x84, 0xc1, 0xa7, ++ 0xfe, 0xc7, 0x4c, 0xe0, 0x76, 0x14, 0xb2, 0x0e, ++ 0x01, 0xf6, 0xfa, 0x4e, 0x8c, 0x2a, 0x6c, 0xff, ++ 0xdc, 0x35, 0x20, 0xd8, 0x88, 0x9e, 0x5d, 0x9a, ++ 0x95, 0x0c, 0x64, 0x25, 0x79, 0x8f, 0x85, 0xd4, ++ 0xbe, 0x38, 0xd3, 0x00, 0xea, 0x56, 0x95, 0xf1, ++ 0x3e, 0xcd, 0x4c, 0xb3, 0x89, 0xd1, 0xff, 0x5b, ++ 0x82, 0x48, 0x4b, 0x49, 0x4d, 0x62, 0x80, 0xab, ++ 0x7f, 0xa7, 0x8e, 0x64, 0x59, 0x33, 0x98, 0x1c, ++ 0xb9, 0x34, 0xcc, 0xe8, 0xbf, 0xcd, 0x11, 0x4c, ++ 0xc0, 0xe6, 0x81, 0x1e, 0xef, 0xa4, 0x7a, 0xae, ++ 0x20, 0xaf, 0x63, 0x8a, 0x1c, 0xd1, 0x63, 0xd2, ++ 0xd3, 0x36, 0x61, 0x86, 0xd0, 0xa0, 0x7d, 0xf0, ++ 0xc8, 0x1f, 0x6c, 0x9f, 0x31, 0x71, 0xcf, 0x35, ++ 0x61, 0x47, 0x2e, 0x98, 0xa6, 0x00, 0x6b, 0xf7, ++ 0x5d, 0xdb, 0x45, 0x7b, 0xed, 0x03, 0x6d, 0xcc, ++ 0xe1, 0x99, 0x36, 0x9d, 0xe7, 0xd9, 0x4e, 0xf2, ++ 0xc6, 0x8e, 0x84, 0x67, 0xee, 0x06, 0x04, 0xee, ++ 0xa2, 0xb3, 0x00, 0x94, 0x79, 0x16, 0x2a, 0x78, ++ 0x91, 0xba, 0x5c, 0x40, 0xca, 0xb1, 0x7f, 0x49, ++ 0xe1, 0xc4, 0x38, 0xcb, 0x6e, 0xae, 0xa4, 0xf7, ++ 0x6c, 0xe2, 0x3c, 0xce, 0x0e, 0x48, 0x3f, 0xf0, ++ 0xe9, 0x6f, 0xa7, 0x90, 0xea, 0x15, 0xbe, 0x67, ++ 0x67, 0x18, 0x14, 0x34, 0x2d, 0x0a, 0x23, 0xf4, ++ 0xa2, 0x02, 0x62, 0xb6, 0x18, 0x2e, 0x72, 0xf3, ++ 0xa6, 0x7c, 0xd2, 0x89, 0x71, 0x15, 0x03, 0xc8, ++ 0x55, 0x16, 0xa9, 0xed, 0x22, 0x54, 0x22, 0xf9, ++ 0x8b, 0x11, 0x6f, 0x1a, 0xb0, 0x80, 0xa8, 0x0a, ++ 0xbd, 0x6f, 0x02, 0x16, 0xdf, 0x88, 0xd8, 0xcf, ++ 0xd6, 0x7c, 0x13, 0x92, 0x43, 0xbe, 0x8d, 0xd7, ++ 0x85, 0x02, 0xa7, 0xaa, 0xf6, 0xbc, 0x99, 0xd7, ++ 0xda, 0x71, 0xbc, 0xdf, 0x62, 0x7e, 0x73, 0x54}, ++ .msg_len = 256, ++ // sig is decrypted message ++ .sig = { 0x0f, 0x9b}, ++ .sig_len = 2, ++ }, ++}; ++ ++#define NUM_OF_IMPLICIT_REJECTION_TESTSUITES 1 ++struct PUBLISHED_TEST_SUITE_INFO rsa_implicit_rejection_test_suites[] = { ++ { ++ .name = "RSA PKCS v1.5", ++ .tvcount = 4, ++ .tv = rsa_imp_rejection_tv, ++ .mech = {CKM_RSA_PKCS, 0, 0}, ++ }, ++}; +diff --git a/testcases/crypto/rsa_func.c b/testcases/crypto/rsa_func.c +index d9f4ebaf..cb7bf491 100644 +--- a/testcases/crypto/rsa_func.c ++++ b/testcases/crypto/rsa_func.c +@@ -1963,6 +1963,164 @@ testcase_cleanup: + return rc; + } + ++CK_RV do_RSAImplicitRejection(struct PUBLISHED_TEST_SUITE_INFO *tsuite) ++{ ++ unsigned int i; ++ CK_BYTE decrypt[BIG_REQUEST]; ++ CK_ULONG decrypt_len; ++ CK_MECHANISM mech; ++ CK_OBJECT_HANDLE priv_key = CK_INVALID_HANDLE; ++ CK_SLOT_ID slot_id = SLOT_ID; ++ CK_SESSION_HANDLE session; ++ CK_FLAGS flags; ++ CK_BYTE user_pin[PKCS11_MAX_PIN_LEN]; ++ CK_ULONG user_pin_len; ++ CK_RV rc, loc_rc; ++ ++ char *s; ++ ++ // begin testsuite ++ testsuite_begin("%s Implicit Rejection.", tsuite->name); ++ testcase_rw_session(); ++ testcase_user_login(); ++ ++ if (!is_ica_token(slot_id) && !is_soft_token(slot_id)) { ++ testsuite_skip(tsuite->tvcount, ++ "Slot %u doesn't support Implicit Rejection", ++ (unsigned int) slot_id); ++ goto testcase_cleanup; ++ } ++ // skip tests if the slot doesn't support this mechanism ++ if (!mech_supported(slot_id, tsuite->mech.mechanism)) { ++ testsuite_skip(tsuite->tvcount, ++ "Slot %u doesn't support %s (0x%x)", ++ (unsigned int) slot_id, ++ mech_to_str(tsuite->mech.mechanism), ++ (unsigned int) tsuite->mech.mechanism); ++ goto testcase_cleanup; ++ } ++ ++ // iterate over test vectors ++ for (i = 0; i < tsuite->tvcount; i++) { ++ ++ // get public exponent from test vector ++ if (p11_ahex_dump(&s, tsuite->tv[i].pub_exp, ++ tsuite->tv[i].pubexp_len) == NULL) { ++ testcase_error("p11_ahex_dump() failed"); ++ rc = -1; ++ goto testcase_cleanup; ++ } ++ // begin testcase ++ testcase_begin("%s Implicit Rejection with test vector %u." ++ "\npubl_exp='%s', modbits=%lu, publ_exp_len=%lu.", ++ tsuite->name, i, s, ++ tsuite->tv[i].mod_len * 8, ++ tsuite->tv[i].pubexp_len); ++ ++ rc = CKR_OK; ++ ++ if (!keysize_supported(slot_id, tsuite->mech.mechanism, ++ tsuite->tv[i].mod_len * 8)) { ++ testcase_skip("Token in slot %lu cannot be used with modbits='%lu'", ++ SLOT_ID, tsuite->tv[i].mod_len * 8); ++ free(s); ++ continue; ++ } ++ ++ free(s); ++ ++ // clear buffers ++ memset(decrypt, 0, BIG_REQUEST); ++ ++ // create (private) key handle ++ rc = create_RSAPrivateKey(session, ++ tsuite->tv[i].mod, ++ tsuite->tv[i].pub_exp, ++ tsuite->tv[i].priv_exp, ++ tsuite->tv[i].prime1, ++ tsuite->tv[i].prime2, ++ tsuite->tv[i].exp1, ++ tsuite->tv[i].exp2, ++ tsuite->tv[i].coef, ++ tsuite->tv[i].mod_len, ++ tsuite->tv[i].pubexp_len, ++ tsuite->tv[i].privexp_len, ++ tsuite->tv[i].prime1_len, ++ tsuite->tv[i].prime2_len, ++ tsuite->tv[i].exp1_len, ++ tsuite->tv[i].exp2_len, ++ tsuite->tv[i].coef_len, &priv_key); ++ if (rc != CKR_OK) { ++ if (rc == CKR_POLICY_VIOLATION) { ++ testcase_skip("RSA key import is not allowed by policy"); ++ continue; ++ } ++ ++ testcase_error("create_RSAPrivateKey(), rc=%s", p11_get_ckr(rc)); ++ goto error; ++ } ++ ++ // set cipher buffer length ++ decrypt_len = BIG_REQUEST; ++ ++ // get mech ++ mech = tsuite->mech; ++ ++ // initialize (private key) decryption ++ rc = funcs->C_DecryptInit(session, &mech, priv_key); ++ if (rc != CKR_OK) { ++ testcase_error("C_DecryptInit, rc=%s", p11_get_ckr(rc)); ++ goto tv_cleanup; ++ } ++ // do (private key) decryption ++ rc = funcs->C_Decrypt(session, tsuite->tv[i].msg, tsuite->tv[i].msg_len, ++ decrypt, &decrypt_len); ++ if (rc != CKR_OK) { ++ testcase_error("C_Decrypt, rc=%s", p11_get_ckr(rc)); ++ goto tv_cleanup; ++ } ++ ++ // check results ++ testcase_new_assertion(); ++ ++ if (decrypt_len != tsuite->tv[i].sig_len) { ++ testcase_fail("decrypted length does not match" ++ "expected data length.\n expected length = %lu, " ++ "but found length=%lu.\n", ++ tsuite->tv[i].sig_len, decrypt_len); ++ } else if (memcmp(decrypt, tsuite->tv[i].sig, tsuite->tv[i].sig_len)) { ++ testcase_fail("decrypted data does not match expected data."); ++ } else { ++ testcase_pass("Implicit Rejection."); ++ } ++ ++ // clean up ++tv_cleanup: ++ ++ rc = funcs->C_DestroyObject(session, priv_key); ++ if (rc != CKR_OK) { ++ testcase_error("C_DestroyObject(), rc=%s.", p11_get_ckr(rc)); ++ goto error; ++ } ++ } ++ ++ goto testcase_cleanup; ++error: ++ loc_rc = funcs->C_DestroyObject(session, priv_key); ++ if (loc_rc != CKR_OK) { ++ testcase_error("C_DestroyObject(), rc=%s.", p11_get_ckr(loc_rc)); ++ } ++ ++testcase_cleanup: ++ testcase_user_logout(); ++ loc_rc = funcs->C_CloseAllSessions(slot_id); ++ if (loc_rc != CKR_OK) { ++ testcase_error("C_CloseAllSessions, rc=%s", p11_get_ckr(loc_rc)); ++ } ++ ++ return rc; ++} ++ + CK_RV rsa_funcs(void) + { + unsigned int i; +@@ -2032,6 +2190,13 @@ CK_RV rsa_funcs(void) + break; + } + ++ // Implicit rejection tests ++ for (i = 0; i < NUM_OF_IMPLICIT_REJECTION_TESTSUITES; i++) { ++ rv = do_RSAImplicitRejection(&rsa_implicit_rejection_test_suites[i]); ++ if (rv != CKR_OK && (!no_stop)) ++ break; ++ } ++ + return rv; + } + diff --git a/SOURCES/opencryptoki-v3.21.0-CVE-2024-0914-part05.patch b/SOURCES/opencryptoki-v3.21.0-CVE-2024-0914-part05.patch new file mode 100644 index 0000000..a321646 --- /dev/null +++ b/SOURCES/opencryptoki-v3.21.0-CVE-2024-0914-part05.patch @@ -0,0 +1,31 @@ +commit c859ed40828bf808e83a3f437c2e34c9c843a4c3 +Author: Ingo Franzki +Date: Fri Feb 9 14:07:34 2024 +0100 + + COMMON: Fix implicit rejection with RSA keys with empty CKA_PRIVATE_EXPONENT + + An RSA key object that has no CKA_PRIVATE_EXPONENT may either don't have that + attribute at all, or may have an empty CKA_PRIVATE_EXPONENT attribute. + Both situations should be handed the same, and the private exponent of the + key needs to be calculated from the other key components. + + Note that RSA key objects generated with a current soft or ICA token will + always have a valid CKA_PRIVATE_EXPONENT attribute, since this is provided + during key generation. + + Signed-off-by: Ingo Franzki + +diff --git a/usr/lib/common/mech_openssl.c b/usr/lib/common/mech_openssl.c +index da515289..14c82e2d 100644 +--- a/usr/lib/common/mech_openssl.c ++++ b/usr/lib/common/mech_openssl.c +@@ -5160,7 +5160,8 @@ CK_RV openssl_specific_rsa_derive_kdk(STDLL_TokData_t *tokdata, OBJECT *key_obj, + + rc = template_attribute_get_non_empty(key_obj->template, + CKA_PRIVATE_EXPONENT, &priv_exp_attr); +- if (rc != CKR_OK && rc != CKR_TEMPLATE_INCOMPLETE) { ++ if (rc != CKR_OK && rc != CKR_TEMPLATE_INCOMPLETE && ++ rc != CKR_ATTRIBUTE_VALUE_INVALID) { + TRACE_ERROR("Failed to get CKA_PRIVATE_EXPONENT\n"); + goto out; + } diff --git a/SPECS/opencryptoki.spec b/SPECS/opencryptoki.spec index 1f2b0ac..7f9a064 100644 --- a/SPECS/opencryptoki.spec +++ b/SPECS/opencryptoki.spec @@ -1,7 +1,7 @@ Name: opencryptoki Summary: Implementation of the PKCS#11 (Cryptoki) specification v3.0 Version: 3.21.0 -Release: 8%{?dist} +Release: 9%{?dist} License: CPL URL: https://github.com/opencryptoki/opencryptoki Source0: https://github.com/opencryptoki/%{name}/archive/v%{version}/%{name}-%{version}.tar.gz @@ -11,6 +11,13 @@ Patch1: opencryptoki-3.11.0-lockdir.patch Patch2: opencryptoki-3.21.0-p11sak.patch # upstream patches +# CVE-2024-0914 opencryptoki: timing side-channel in handling of RSA PKCS#1 v1.5 padded ciphertexts +Patch20: opencryptoki-v3.21.0-CVE-2024-0914-part01.patch +Patch21: opencryptoki-v3.21.0-CVE-2024-0914-part02.patch +Patch22: opencryptoki-v3.21.0-CVE-2024-0914-part03.patch +Patch23: opencryptoki-v3.21.0-CVE-2024-0914-part04.patch +Patch24: opencryptoki-v3.21.0-CVE-2024-0914-part05.patch + # pkcsstats: Fix handling of user name Patch100: opencryptoki-3.21.0-f4166214552a92d8d66de8011ab11c9c2c6bb0a4.patch # p11sak: Fix user confirmation prompt behavior when stdin is closed @@ -353,6 +360,10 @@ fi %changelog +* Wed Feb 07 2024 Than Ngo - 3.21.0-9 +- timing side-channel in handling of RSA PKCS#1 v1.5 padded ciphertexts (Marvin) +Resolves: RHEL-23490 + * Fri Jul 14 2023 Than Ngo - 3.21.0-8 - Resolves: #2222592, p11sak tool: slot option does not accept argument 0 for slot index 0 - Resolves: #2222596, p11sak fails as soon as there reside non-key objects