Compare commits

2 Commits
main ... 1.1

10 changed files with 1015 additions and 165 deletions

Binary file not shown.

922
opensc-CVE-2023-5992.patch Normal file
View File

@@ -0,0 +1,922 @@
From b9e1d344df1f850a9b15bce6294f72c1620d0b45 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Veronika=20Hanul=C3=ADkov=C3=A1?= <vhanulik@redhat.com>
Date: Mon, 13 Nov 2023 13:54:54 +0100
Subject: [PATCH 1/8] Reimplement removing of PKCS#1 v1.5 padding to be time
constant
---
src/common/Makefile.am | 6 +-
src/common/constant-time.h | 128 ++++++++++++++++++++++++++++++++++++
src/libopensc/internal.h | 4 +-
src/libopensc/padding.c | 102 +++++++++++++++++++---------
src/libopensc/pkcs15-sec.c | 5 +-
src/minidriver/minidriver.c | 4 +-
6 files changed, 210 insertions(+), 39 deletions(-)
create mode 100644 src/common/constant-time.h
Index: opensc-0.24.0/src/common/Makefile.am
===================================================================
--- opensc-0.24.0.orig/src/common/Makefile.am
+++ opensc-0.24.0/src/common/Makefile.am
@@ -8,7 +8,8 @@ dist_noinst_DATA = \
LICENSE.compat_getopt compat_getopt.txt \
compat_getopt_main.c \
README.compat_strlcpy compat_strlcpy.3
-noinst_HEADERS = compat_strlcat.h compat_strlcpy.h compat_strnlen.h compat_getpass.h compat_getopt.h simclist.h libpkcs11.h libscdl.h compat_overflow.h
+noinst_HEADERS = compat_strlcat.h compat_strlcpy.h compat_strnlen.h compat_getpass.h \
+ compat_getopt.h simclist.h libpkcs11.h libscdl.h compat_overflow.h constant-time.h
AM_CPPFLAGS = -I$(top_srcdir)/src
@@ -43,7 +44,8 @@ TIDY_FILES = \
compat___iob_func.c \
compat_overflow.h compat_overflow.c \
simclist.c simclist.h \
- libpkcs11.c libscdl.c
+ libpkcs11.c libscdl.c \
+ constant-time.h
check-local:
if [ -x "$(CLANGTIDY)" ]; then clang-tidy -config='' --checks='$(TIDY_CHECKS)' --warnings-as-errors='$(TIDY_CHECKS)' -header-filter=.* $(addprefix $(srcdir)/,$(TIDY_FILES)) -- $(TIDY_FLAGS); fi
Index: opensc-0.24.0/src/common/constant-time.h
===================================================================
--- /dev/null
+++ opensc-0.24.0/src/common/constant-time.h
@@ -0,0 +1,128 @@
+/* Original source: https://github.com/openssl/openssl/blob/9890cc42daff5e2d0cad01ac4bf78c391f599a6e/include/internal/constant_time.h */
+
+#ifndef CONSTANT_TIME_H
+#define CONSTANT_TIME_H
+
+#include <stdlib.h>
+#include <string.h>
+
+#if !defined(inline)
+#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+#define constant_inline inline
+#elif defined(__GNUC__) && __GNUC__ >= 2
+#elif defined(__GNUC__) && __GNUC__ >= 2
+#elif defined(_MSC_VER)
+#define constant_inline __inline
+#else
+#define constant_inline
+#endif
+#else /* use what caller wants as inline may be from config.h */
+#define constant_inline inline /* inline */
+#endif
+
+/*-
+ * The boolean methods return a bitmask of all ones (0xff...f) for true
+ * and 0 for false. For example,
+ * if (a < b) {
+ * c = a;
+ * } else {
+ * c = b;
+ * }
+ * can be written as
+ * unsigned int lt = constant_time_lt(a, b);
+ * c = constant_time_select(lt, a, b);
+ */
+
+static constant_inline unsigned int
+value_barrier(unsigned int a)
+{
+ volatile unsigned int r = a;
+ return r;
+}
+
+static constant_inline size_t
+value_barrier_s(size_t a)
+{
+ volatile size_t r = a;
+ return r;
+}
+
+/* MSB */
+static constant_inline size_t
+constant_time_msb_s(size_t a)
+{
+ return 0 - (a >> (sizeof(a) * 8 - 1));
+}
+
+static constant_inline unsigned int
+constant_time_msb(unsigned int a)
+{
+ return 0 - (a >> (sizeof(a) * 8 - 1));
+}
+
+/* Select */
+static constant_inline unsigned int
+constant_time_select(unsigned int mask, unsigned int a, unsigned int b)
+{
+ return (value_barrier(mask) & a) | (value_barrier(~mask) & b);
+}
+
+static constant_inline unsigned char
+constant_time_select_8(unsigned char mask, unsigned char a, unsigned char b)
+{
+ return (unsigned char)constant_time_select(mask, a, b);
+}
+
+static constant_inline size_t
+constant_time_select_s(size_t mask, size_t a, size_t b)
+{
+ return (value_barrier_s(mask) & a) | (value_barrier_s(~mask) & b);
+}
+
+/* Zero */
+static constant_inline unsigned int
+constant_time_is_zero(unsigned int a)
+{
+ return constant_time_msb(~a & (a - 1));
+}
+
+static constant_inline size_t
+constant_time_is_zero_s(size_t a)
+{
+ return constant_time_msb_s(~a & (a - 1));
+}
+
+/* Comparison*/
+static constant_inline size_t
+constant_time_lt_s(size_t a, size_t b)
+{
+ return constant_time_msb_s(a ^ ((a ^ b) | ((a - b) ^ b)));
+}
+
+static constant_inline unsigned int
+constant_time_lt(unsigned int a, unsigned int b)
+{
+ return constant_time_msb(a ^ ((a ^ b) | ((a - b) ^ b)));
+}
+
+static constant_inline unsigned int
+constant_time_ge(unsigned int a, unsigned int b)
+{
+ return ~constant_time_lt(a, b);
+}
+
+/* Equality*/
+
+static constant_inline unsigned int
+constant_time_eq(unsigned int a, unsigned int b)
+{
+ return constant_time_is_zero(a ^ b);
+}
+
+static constant_inline size_t
+constant_time_eq_s(size_t a, size_t b)
+{
+ return constant_time_is_zero_s(a ^ b);
+}
+
+#endif /* CONSTANT_TIME_H */
Index: opensc-0.24.0/src/libopensc/internal.h
===================================================================
--- opensc-0.24.0.orig/src/libopensc/internal.h
+++ opensc-0.24.0/src/libopensc/internal.h
@@ -166,8 +166,8 @@ int _sc_card_add_xeddsa_alg(struct sc_ca
int sc_pkcs1_strip_01_padding(struct sc_context *ctx, const u8 *in_dat, size_t in_len,
u8 *out_dat, size_t *out_len);
-int sc_pkcs1_strip_02_padding(struct sc_context *ctx, const u8 *data, size_t len,
- u8 *out_dat, size_t *out_len);
+int sc_pkcs1_strip_02_padding_constant_time(sc_context_t *ctx, unsigned int n, const u8 *data,
+ unsigned int data_len, u8 *out, unsigned int *out_len);
int sc_pkcs1_strip_digest_info_prefix(unsigned int *algorithm,
const u8 *in_dat, size_t in_len, u8 *out_dat, size_t *out_len);
#ifdef ENABLE_OPENSSL
Index: opensc-0.24.0/src/libopensc/padding.c
===================================================================
--- opensc-0.24.0.orig/src/libopensc/padding.c
+++ opensc-0.24.0/src/libopensc/padding.c
@@ -32,10 +32,13 @@
#include <string.h>
#include <stdlib.h>
+#include "common/constant-time.h"
#include "internal.h"
#include "pkcs11/pkcs11.h"
/* TODO doxygen comments */
+#define SC_PKCS1_PADDING_MIN_SIZE 11
+
/*
* Prefixes for pkcs-v1 signatures
*/
@@ -143,45 +146,82 @@ sc_pkcs1_strip_01_padding(struct sc_cont
return SC_SUCCESS;
}
-
-/* remove pkcs1 BT02 padding (adding BT02 padding is currently not
- * needed/implemented) */
+/* Remove pkcs1 BT02 padding (adding BT02 padding is currently not
+ * needed/implemented) in constant-time.
+ * Original source: https://github.com/openssl/openssl/blob/9890cc42daff5e2d0cad01ac4bf78c391f599a6e/crypto/rsa/rsa_pk1.c#L171 */
int
-sc_pkcs1_strip_02_padding(sc_context_t *ctx, const u8 *data, size_t len, u8 *out, size_t *out_len)
+sc_pkcs1_strip_02_padding_constant_time(sc_context_t *ctx, unsigned int n, const u8 *data, unsigned int data_len, u8 *out, unsigned int *out_len)
{
- unsigned int n = 0;
-
+ unsigned int i = 0;
+ u8 *msg, *msg_orig = NULL;
+ unsigned int good, found_zero_byte, mask;
+ unsigned int zero_index = 0, msg_index, mlen = -1, len = 0;
LOG_FUNC_CALLED(ctx);
- if (data == NULL || len < 3)
+
+ if (data == NULL || data_len <= 0 || data_len > n || n < SC_PKCS1_PADDING_MIN_SIZE)
LOG_FUNC_RETURN(ctx, SC_ERROR_INTERNAL);
- /* skip leading zero byte */
- if (*data == 0) {
- data++;
- len--;
+ msg = msg_orig = calloc(n, sizeof(u8));
+ if (msg == NULL)
+ LOG_FUNC_RETURN(ctx, SC_ERROR_INTERNAL);
+
+ /*
+ * We can not check length of input data straight away and still we need to read
+ * from input even when the input is not as long as needed to keep the time constant.
+ * If data has wrong size, it is padded by zeroes from left and the following checks
+ * do not pass.
+ */
+ len = data_len;
+ for (data += len, msg += n, i = 0; i < n; i++) {
+ mask = ~constant_time_is_zero(len);
+ len -= 1 & mask;
+ data -= 1 & mask;
+ *--msg = *data & mask;
+ }
+ // check first byte to be 0x00
+ good = constant_time_is_zero(msg[0]);
+ // check second byte to be 0x02
+ good &= constant_time_eq(msg[1], 2);
+
+ // find zero byte after random data in padding
+ found_zero_byte = 0;
+ for (i = 2; i < n; i++) {
+ unsigned int equals0 = constant_time_is_zero(msg[i]);
+ zero_index = constant_time_select(~found_zero_byte & equals0, i, zero_index);
+ found_zero_byte |= equals0;
}
- if (data[0] != 0x02)
- LOG_FUNC_RETURN(ctx, SC_ERROR_WRONG_PADDING);
- /* skip over padding bytes */
- for (n = 1; n < len && data[n]; n++)
- ;
- /* Must be at least 8 pad bytes */
- if (n >= len || n < 9)
- LOG_FUNC_RETURN(ctx, SC_ERROR_WRONG_PADDING);
- n++;
- if (out == NULL)
- /* just check the padding */
- LOG_FUNC_RETURN(ctx, SC_SUCCESS);
- /* Now move decrypted contents to head of buffer */
- if (*out_len < len - n)
- LOG_FUNC_RETURN(ctx, SC_ERROR_INTERNAL);
- *out_len = len - n;
- memmove(out, data + n, *out_len);
+ // zero_index stands for index of last found zero
+ good &= constant_time_ge(zero_index, 2 + 8);
+
+ // start of the actual message in data
+ msg_index = zero_index + 1;
+
+ // length of message
+ mlen = data_len - msg_index;
+
+ // check that message fits into out buffer
+ good &= constant_time_ge(*out_len, mlen);
+
+ // move the result in-place by |num|-SC_PKCS1_PADDING_MIN_SIZE-|mlen| bytes to the left.
+ *out_len = constant_time_select(constant_time_lt(n - SC_PKCS1_PADDING_MIN_SIZE, *out_len),
+ n - SC_PKCS1_PADDING_MIN_SIZE, *out_len);
+ for (msg_index = 1; msg_index < n - SC_PKCS1_PADDING_MIN_SIZE; msg_index <<= 1) {
+ mask = ~constant_time_eq(msg_index & (n - SC_PKCS1_PADDING_MIN_SIZE - mlen), 0);
+ for (i = SC_PKCS1_PADDING_MIN_SIZE; i < n - msg_index; i++)
+ msg[i] = constant_time_select_8(mask, msg[i + msg_index], msg[i]);
+ }
+ // move message into out buffer, if good
+ for (i = 0; i < *out_len; i++) {
+ unsigned int msg_index;
+ // when out is longer than message in data, use some bogus index in msg
+ mask = good & constant_time_lt(i, mlen);
+ msg_index = constant_time_select(mask, i + SC_PKCS1_PADDING_MIN_SIZE, 0); // to now overflow msg buffer
+ out[i] = constant_time_select_8(mask, msg[msg_index], out[i]);
+ }
- sc_log(ctx, "stripped output(%"SC_FORMAT_LEN_SIZE_T"u): %s", len - n,
- sc_dump_hex(out, len - n));
- LOG_FUNC_RETURN(ctx, len - n);
+ free(msg_orig);
+ return constant_time_select(good, mlen, SC_ERROR_WRONG_PADDING);
}
#ifdef ENABLE_OPENSSL
Index: opensc-0.24.0/src/libopensc/pkcs15-sec.c
===================================================================
--- opensc-0.24.0.orig/src/libopensc/pkcs15-sec.c
+++ opensc-0.24.0/src/libopensc/pkcs15-sec.c
@@ -308,9 +308,10 @@ int sc_pkcs15_decipher(struct sc_pkcs15_
/* Strip any padding */
if (pad_flags & SC_ALGORITHM_RSA_PAD_PKCS1) {
- size_t s = r;
- r = sc_pkcs1_strip_02_padding(ctx, out, s, out, &s);
- LOG_TEST_RET(ctx, r, "Invalid PKCS#1 padding");
+ unsigned int s = r;
+ unsigned int key_size = (unsigned int)alg_info->key_length;
+ r = sc_pkcs1_strip_02_padding_constant_time(ctx, key_size / 8, out, s, out, &s);
+ /* for keeping PKCS#1 v1.5 depadding constant-time, do not log error here */
}
#ifdef ENABLE_OPENSSL
if (pad_flags & SC_ALGORITHM_RSA_PAD_OAEP)
@@ -332,7 +333,8 @@ int sc_pkcs15_decipher(struct sc_pkcs15_
LOG_TEST_RET(ctx, r, "Invalid OAEP padding");
}
#endif
- LOG_FUNC_RETURN(ctx, r);
+ /* do not log error code to prevent side channel attack */
+ return r;
}
/* derive one key from another. RSA can use decipher, so this is for only ECDH
Index: opensc-0.24.0/src/minidriver/minidriver.c
===================================================================
--- opensc-0.24.0.orig/src/minidriver/minidriver.c
+++ opensc-0.24.0/src/minidriver/minidriver.c
@@ -44,6 +44,7 @@
#endif
#include "common/compat_strlcpy.h"
+#include "common/constant-time.h"
#include "libopensc/asn1.h"
#include "libopensc/cardctl.h"
#include "libopensc/opensc.h"
@@ -4534,13 +4535,15 @@ DWORD WINAPI CardRSADecrypt(__in PCARD_D
{
DWORD dwret;
- int r, opt_crypt_flags = 0;
+ int r, opt_crypt_flags = 0, good = 0;
unsigned ui;
VENDOR_SPECIFIC *vs;
struct sc_pkcs15_prkey_info *prkey_info;
BYTE *pbuf = NULL, *pbuf2 = NULL;
struct sc_pkcs15_object *pkey = NULL;
struct sc_algorithm_info *alg_info = NULL;
+ unsigned int wrong_padding = 0;
+ unsigned int pbufLen = 0;
MD_FUNC_CALLED(pCardData, 1);
@@ -4641,11 +4644,11 @@ DWORD WINAPI CardRSADecrypt(__in PCARD_D
goto err;
}
+ pbufLen = pInfo->cbData;
if (alg_info->flags & SC_ALGORITHM_RSA_RAW) {
logprintf(pCardData, 2, "sc_pkcs15_decipher: using RSA-RAW mechanism\n");
r = sc_pkcs15_decipher(vs->p15card, pkey, opt_crypt_flags | SC_ALGORITHM_RSA_RAW, pbuf, pInfo->cbData, pbuf2, pInfo->cbData, NULL);
- logprintf(pCardData, 2, "sc_pkcs15_decipher returned %d\n", r);
-
+ /* do not log return value to not leak it */
if (r > 0) {
/* Need to handle padding */
if (pInfo->dwVersion >= CARD_RSA_KEY_DECRYPT_INFO_VERSION_TWO) {
@@ -4653,17 +4656,13 @@ DWORD WINAPI CardRSADecrypt(__in PCARD_D
"sc_pkcs15_decipher: DECRYPT-INFO dwVersion=%lu\n",
(unsigned long)pInfo->dwVersion);
if (pInfo->dwPaddingType == CARD_PADDING_PKCS1) {
- size_t temp = pInfo->cbData;
+ unsigned int temp = pInfo->cbData;
logprintf(pCardData, 2, "sc_pkcs15_decipher: stripping PKCS1 padding\n");
- r = sc_pkcs1_strip_02_padding(vs->ctx, pbuf2, pInfo->cbData, pbuf2, &temp);
+ r = sc_pkcs1_strip_02_padding_constant_time(vs->ctx, prkey_info->modulus_length / 8, pbuf2, pInfo->cbData, pbuf2, &temp);
pInfo->cbData = (DWORD) temp;
- if (r < 0) {
- logprintf(pCardData, 2, "Cannot strip PKCS1 padding: %i\n", r);
- pCardData->pfnCspFree(pbuf);
- pCardData->pfnCspFree(pbuf2);
- dwret = SCARD_F_INTERNAL_ERROR;
- goto err;
- }
+ wrong_padding = constant_time_eq_s(r, SC_ERROR_WRONG_PADDING);
+ /* continue without returning error to not leak that padding is wrong
+ to prevent time side-channel leak for Marvin attack*/
}
else if (pInfo->dwPaddingType == CARD_PADDING_OAEP) {
/* TODO: Handle OAEP padding if present - can call PFN_CSP_UNPAD_DATA */
@@ -4711,28 +4710,38 @@ DWORD WINAPI CardRSADecrypt(__in PCARD_D
goto err;
}
- if ( r < 0) {
+ good = constant_time_eq_s(r, 0);
+ /* if no error or padding error, do not return here to prevent Marvin attack */
+ if (!(good | wrong_padding) && r < 0) {
logprintf(pCardData, 2, "sc_pkcs15_decipher error(%i): %s\n", r, sc_strerror(r));
pCardData->pfnCspFree(pbuf);
pCardData->pfnCspFree(pbuf2);
dwret = md_translate_OpenSC_to_Windows_error(r, SCARD_E_INVALID_VALUE);
goto err;
}
+ dwret = constant_time_select_s(good, SCARD_S_SUCCESS, SCARD_F_INTERNAL_ERROR);
logprintf(pCardData, 2, "decrypted data(%lu):\n",
(unsigned long)pInfo->cbData);
loghex(pCardData, 7, pbuf2, pInfo->cbData);
/*inversion donnees */
- for(ui = 0; ui < pInfo->cbData; ui++)
- pInfo->pbData[ui] = pbuf2[pInfo->cbData-ui-1];
+ /* copy data in constant-time way to prevent leak */
+ for (ui = 0; ui < pbufLen; ui++) {
+ unsigned int mask, msg_index, inv_ui;
+ mask = good & constant_time_lt_s(ui, pInfo->cbData); /* ui should be in the bounds of pbuf2 */
+ inv_ui = pInfo->cbData - ui - 1;
+ msg_index = constant_time_select_s(mask, inv_ui, 0);
+ pInfo->pbData[ui] = constant_time_select_8(mask, pbuf2[msg_index], pInfo->pbData[ui]);
+ }
pCardData->pfnCspFree(pbuf);
pCardData->pfnCspFree(pbuf2);
err:
unlock(pCardData);
- MD_FUNC_RETURN(pCardData, 1, dwret);
+ /* do not log return value to not leak it */
+ return dwret;
}
Index: opensc-0.24.0/src/tests/unittests/Makefile.am
===================================================================
--- opensc-0.24.0.orig/src/tests/unittests/Makefile.am
+++ opensc-0.24.0/src/tests/unittests/Makefile.am
@@ -14,8 +14,10 @@ VALGRIND_FLAGS = --num-callers=30 -q --k
TESTS_ENVIRONMENT = LD_PRELOAD='/usr/lib/x86_64-linux-gnu/libpcsclite.so.1'
endif
-noinst_PROGRAMS = asn1 simpletlv cachedir pkcs15filter openpgp-tool hextobin decode_ecdsa_signature check_macro_reference_loop
-TESTS = asn1 simpletlv cachedir pkcs15filter openpgp-tool hextobin decode_ecdsa_signature check_macro_reference_loop
+noinst_PROGRAMS = asn1 simpletlv cachedir pkcs15filter openpgp-tool hextobin \
+ decode_ecdsa_signature check_macro_reference_loop strip_pkcs1_2_padding
+TESTS = asn1 simpletlv cachedir pkcs15filter openpgp-tool hextobin \
+ decode_ecdsa_signature check_macro_reference_loop strip_pkcs1_2_padding
noinst_HEADERS = torture.h
@@ -37,6 +39,7 @@ openpgp_tool_SOURCES = openpgp-tool.c $(
hextobin_SOURCES = hextobin.c
decode_ecdsa_signature_SOURCES = decode_ecdsa_signature.c
check_macro_reference_loop = check_macro_reference_loop.c
+strip_pkcs1_2_padding = strip_pkcs1_2_padding.c
if ENABLE_ZLIB
noinst_PROGRAMS += compression
Index: opensc-0.24.0/src/tests/unittests/Makefile.mak
===================================================================
--- opensc-0.24.0.orig/src/tests/unittests/Makefile.mak
+++ opensc-0.24.0/src/tests/unittests/Makefile.mak
@@ -1,11 +1,12 @@
TOPDIR = ..\..\..
-TARGETS = asn1 compression pkcs15filter check_macro_reference_loop
+TARGETS = asn1 compression pkcs15filter check_macro_reference_loop strip_pkcs1_2_padding
OBJECTS = asn1.obj \
compression.obj \
pkcs15-emulator-filter.obj \
- check_macro_reference_loop.obj
+ check_macro_reference_loop.obj \
+ strip_pkcs1_2_padding.obj \
$(TOPDIR)\win32\versioninfo.res
all: $(TARGETS)
Index: opensc-0.24.0/src/tests/unittests/strip_pkcs1_2_padding.c
===================================================================
--- /dev/null
+++ opensc-0.24.0/src/tests/unittests/strip_pkcs1_2_padding.c
@@ -0,0 +1,204 @@
+#include "common/compat_strlcpy.c"
+#include "libopensc/log.c"
+#include "libopensc/padding.c"
+#include "torture.h"
+#include <cmocka.h>
+
+static void
+torture_long_output_buffer(void **state)
+{
+ unsigned int n = 14;
+ unsigned int in_len = 14;
+ unsigned char in[] = {0x00, 0x02,
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ 0x00,
+ 'm', 's', 'g'};
+ unsigned int out_len = 3;
+ unsigned char *out = malloc(out_len * sizeof(unsigned char));
+ unsigned char result_msg[] = {'m', 's', 'g'};
+ int r = sc_pkcs1_strip_02_padding_constant_time(NULL, n, in, in_len, out, &out_len);
+ assert_int_equal(r, 3);
+ assert_memory_equal(out, result_msg, r);
+ free(out);
+}
+
+static void
+torture_short_output_buffer(void **state)
+{
+ unsigned int n = 14;
+ unsigned int in_len = 14;
+ unsigned char in[] = {0x00, 0x02,
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ 0x00,
+ 'm', 's', 'g'};
+ unsigned int out_len = 1;
+ unsigned char *out = malloc(out_len * sizeof(unsigned char));
+ int r = sc_pkcs1_strip_02_padding_constant_time(NULL, n, in, in_len, out, &out_len);
+ assert_int_equal(r, SC_ERROR_WRONG_PADDING);
+ free(out);
+}
+
+static void
+torture_short_message_correct_padding(void **state)
+{
+ unsigned int n = 14;
+ unsigned int in_len = 14;
+ unsigned char in[] = {0x00, 0x02,
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ 0x00,
+ 'm', 's', 'g'};
+ unsigned int out_len = 3;
+ unsigned char *out = malloc(out_len * sizeof(unsigned char));
+ unsigned char result_msg[] = {'m', 's', 'g'};
+ int r = sc_pkcs1_strip_02_padding_constant_time(NULL, n, in, in_len, out, &out_len);
+ assert_int_equal(r, 3);
+ assert_memory_equal(out, result_msg, r);
+ free(out);
+}
+
+static void
+torture_missing_first_zero(void **state)
+{
+ unsigned int n = 13;
+ unsigned int in_len = 13;
+ unsigned char in[] = {0x02,
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ 0x00,
+ 'm', 's', 'g'};
+ unsigned int out_len = 10;
+ unsigned char *out = malloc(out_len * sizeof(unsigned char));
+ int r = sc_pkcs1_strip_02_padding_constant_time(NULL, n, in, in_len, out, &out_len);
+ assert_int_equal(r, SC_ERROR_WRONG_PADDING);
+ free(out);
+}
+
+static void
+torture_missing_two(void **state)
+{
+ unsigned int n = 13;
+ unsigned int in_len = 13;
+ unsigned char in[] = {0x00,
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ 0x00,
+ 'm', 's', 'g'};
+ unsigned int out_len = 10;
+ unsigned char *out = malloc(out_len * sizeof(unsigned char));
+ int r = sc_pkcs1_strip_02_padding_constant_time(NULL, n, in, in_len, out, &out_len);
+ assert_int_equal(r, SC_ERROR_WRONG_PADDING);
+ free(out);
+}
+
+static void
+torture_short_padding(void **state)
+{
+ unsigned int n = 13;
+ unsigned int in_len = 13;
+ unsigned char in[] = {0x00, 0x02,
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x00,
+ 'm', 's', 'g'};
+ unsigned int out_len = 10;
+ unsigned char *out = malloc(out_len * sizeof(unsigned char));
+ int r = sc_pkcs1_strip_02_padding_constant_time(NULL, n, in, in_len, out, &out_len);
+ assert_int_equal(r, SC_ERROR_WRONG_PADDING);
+ free(out);
+}
+
+static void
+torture_missing_second_zero(void **state)
+{
+ unsigned int n = 13;
+ unsigned int in_len = 13;
+ unsigned char in[] = {0x00, 0x02,
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ 'm', 's', 'g'};
+ unsigned int out_len = 10;
+ unsigned char *out = malloc(out_len * sizeof(unsigned char));
+ int r = sc_pkcs1_strip_02_padding_constant_time(NULL, n, in, in_len, out, &out_len);
+ assert_int_equal(r, SC_ERROR_WRONG_PADDING);
+ free(out);
+}
+
+static void
+torture_missing_message(void **state)
+{
+ unsigned int n = 20;
+ unsigned int in_len = 11;
+ unsigned char in[] = {0x00, 0x02,
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ 0x00};
+ unsigned int out_len = 11;
+ unsigned char *out = malloc(out_len * sizeof(unsigned char));
+ int r = sc_pkcs1_strip_02_padding_constant_time(NULL, n, in, in_len, out, &out_len);
+ assert_int_equal(r, SC_ERROR_WRONG_PADDING);
+ free(out);
+}
+
+static void
+torture_one_byte_message(void **state)
+{
+ unsigned int n = 12;
+ unsigned int in_len = 12;
+ unsigned char in[] = {0x00, 0x02,
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ 0x00,
+ 'm'};
+ unsigned int out_len = 1;
+ unsigned char *out = malloc(out_len * sizeof(unsigned char));
+ unsigned char result_msg[] = {'m'};
+ int r = sc_pkcs1_strip_02_padding_constant_time(NULL, n, in, in_len, out, &out_len);
+ assert_int_equal(r, 1);
+ assert_memory_equal(out, result_msg, r);
+ free(out);
+}
+
+static void
+torture_longer_padding(void **state)
+{
+ unsigned int n = 26;
+ unsigned int in_len = 26;
+ unsigned char in[] = {0x00, 0x02,
+ 0x0e, 0x38, 0x97, 0x18, 0x16, 0x57, 0x9e, 0x30, 0xb6, 0xa5, 0x78, 0x13, 0x20, 0xca, 0x11,
+ 0x00,
+ 0x9d, 0x98, 0x3d, 0xca, 0xa9, 0xa7, 0x11, 0x0a};
+ unsigned int out_len = 8;
+ unsigned char *out = malloc(out_len * sizeof(unsigned char));
+ unsigned char result_msg[] = {0x9d, 0x98, 0x3d, 0xca, 0xa9, 0xa7, 0x11, 0x0a};
+ int r = sc_pkcs1_strip_02_padding_constant_time(NULL, n, in, in_len, out, &out_len);
+ assert_int_equal(r, 8);
+ assert_memory_equal(out, result_msg, r);
+ free(out);
+}
+
+static void
+torture_empty_message(void **state)
+{
+ unsigned int n = 18;
+ unsigned int in_len = 18;
+ unsigned char in[] = {0x00, 0x02,
+ 0x0e, 0x38, 0x97, 0x18, 0x16, 0x57, 0x9e, 0x30, 0xb6, 0xa5, 0x78, 0x13, 0x20, 0xca, 0x11,
+ 0x00};
+ unsigned int out_len = 8;
+ unsigned char *out = malloc(out_len * sizeof(unsigned char));
+ int r = sc_pkcs1_strip_02_padding_constant_time(NULL, n, in, in_len, out, &out_len);
+ assert_int_equal(r, 0);
+ free(out);
+}
+
+int
+main(void)
+{
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(torture_long_output_buffer),
+ cmocka_unit_test(torture_short_output_buffer),
+ cmocka_unit_test(torture_short_message_correct_padding),
+ cmocka_unit_test(torture_missing_first_zero),
+ cmocka_unit_test(torture_missing_two),
+ cmocka_unit_test(torture_short_padding),
+ cmocka_unit_test(torture_missing_second_zero),
+ cmocka_unit_test(torture_missing_message),
+ cmocka_unit_test(torture_one_byte_message),
+ cmocka_unit_test(torture_longer_padding),
+ cmocka_unit_test(torture_empty_message)};
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
Index: opensc-0.24.0/src/pkcs11/framework-pkcs15.c
===================================================================
--- opensc-0.24.0.orig/src/pkcs11/framework-pkcs15.c
+++ opensc-0.24.0/src/pkcs11/framework-pkcs15.c
@@ -18,6 +18,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include "common/constant-time.h"
#include "config.h"
#include <stdlib.h>
#include <string.h>
@@ -4514,7 +4515,8 @@ pkcs15_prkey_decrypt(struct sc_pkcs11_se
struct pkcs15_fw_data *fw_data = NULL;
struct pkcs15_prkey_object *prkey;
unsigned char decrypted[512]; /* FIXME: Will not work for keys above 4096 bits */
- int buff_too_small, rv, flags = 0, prkey_has_path = 0;
+ int rv, flags = 0, prkey_has_path = 0;
+ CK_ULONG mask, good, rv_pkcs11;
if (pulDataLen == NULL) {
/* This is call from the C_DecyptInit function */
@@ -4603,27 +4605,53 @@ pkcs15_prkey_decrypt(struct sc_pkcs11_se
rv = sc_pkcs15_decipher(fw_data->p15_card, prkey->prv_p15obj, flags,
pEncryptedData, ulEncryptedDataLen, decrypted, sizeof(decrypted), pMechanism);
- if (rv < 0 && !sc_pkcs11_conf.lock_login && !prkey_has_path)
+ /* skip for PKCS#1 v1.5 padding prevent side channel attack */
+ if (!(flags & SC_ALGORITHM_RSA_PAD_PKCS1) &&
+ rv < 0 && !sc_pkcs11_conf.lock_login && !prkey_has_path)
if (reselect_app_df(fw_data->p15_card) == SC_SUCCESS)
rv = sc_pkcs15_decipher(fw_data->p15_card, prkey->prv_p15obj, flags,
pEncryptedData, ulEncryptedDataLen, decrypted, sizeof(decrypted), pMechanism);
sc_unlock(p11card->card);
- sc_log(context, "Decryption complete. Result %d.", rv);
+ sc_log(context, "Decryption complete.");
- if (rv < 0)
- return sc_to_cryptoki_error(rv, "C_Decrypt");
+ /* Handle following code in constant-time
+ * to prevent Marvin attack for PKCS#1 v1.5 padding. */
- buff_too_small = (*pulDataLen < (CK_ULONG)rv);
- *pulDataLen = rv;
- if (pData == NULL_PTR)
- return CKR_OK;
- if (buff_too_small)
- return CKR_BUFFER_TOO_SMALL;
- memcpy(pData, decrypted, *pulDataLen);
+ /* only padding error must be handled in constant-time way,
+ * other error can be returned straight away */
+ if ((~constant_time_eq_s(rv, SC_ERROR_WRONG_PADDING) & constant_time_lt_s(sizeof(decrypted), rv)))
+ return sc_to_cryptoki_error(rv, "C_Decrypt");
- return CKR_OK;
+ /* check rv for padding error */
+ good = ~constant_time_eq_s(rv, SC_ERROR_WRONG_PADDING);
+ rv_pkcs11 = sc_to_cryptoki_error(SC_ERROR_WRONG_PADDING, "C_Decrypt");
+ rv_pkcs11 = constant_time_select_s(good, CKR_OK, rv_pkcs11);
+
+ if (pData == NULL_PTR) {
+ /* set length only if no error */
+ *pulDataLen = constant_time_select_s(good, rv, *pulDataLen);
+ /* return error only if original rv < 0 */
+ return rv_pkcs11;
+ }
+
+ /* check whether *pulDataLen < rv and set return value for small output buffer */
+ mask = good & constant_time_lt_s(*pulDataLen, rv);
+ rv_pkcs11 = constant_time_select_s(mask, CKR_BUFFER_TOO_SMALL, rv_pkcs11);
+ good &= ~mask;
+
+ /* move everything from decrypted into out buffer constant-time, if rv is ok */
+ for (CK_ULONG i = 0; i < *pulDataLen; i++) { /* iterate over whole pData to not disclose real depadded length */
+ CK_ULONG msg_index;
+ mask = good & constant_time_lt_s(i, sizeof(decrypted)); /* i should be in the bounds of decrypted */
+ mask &= constant_time_lt_s(i, constant_time_select_s(good, rv, 0)); /* check that is in bounds of depadded message */
+ msg_index = constant_time_select_s(mask, i, 0);
+ pData[i] = constant_time_select_8(mask, decrypted[msg_index], pData[i]);
+ }
+ *pulDataLen = constant_time_select_s(good, rv, *pulDataLen);
+ /* do not log error code to prevent side channel attack */
+ return rv_pkcs11;
}
Index: opensc-0.24.0/src/pkcs11/mechanism.c
===================================================================
--- opensc-0.24.0.orig/src/pkcs11/mechanism.c
+++ opensc-0.24.0/src/pkcs11/mechanism.c
@@ -23,8 +23,9 @@
#include <stdlib.h>
#include <string.h>
-#include "sc-pkcs11.h"
#include "common/compat_overflow.h"
+#include "common/constant-time.h"
+#include "sc-pkcs11.h"
/* Also used for verification data */
struct hash_signature_info {
@@ -1093,7 +1094,9 @@ sc_pkcs11_decr(struct sc_pkcs11_session
rv = op->type->decrypt(op, pEncryptedData, ulEncryptedDataLen,
pData, pulDataLen);
- if (rv != CKR_BUFFER_TOO_SMALL && pData != NULL)
+ /* terminate session for any return value except CKR_BUFFER_TOO_SMALL,
+ * perform check in time side-channel free way to prevent Marvin attack */
+ if (!constant_time_eq_s(rv, CKR_BUFFER_TOO_SMALL) && pData != NULL)
session_stop_operation(session, SC_PKCS11_OPERATION_DECRYPT);
return rv;
@@ -1114,10 +1117,12 @@ sc_pkcs11_decr_update(struct sc_pkcs11_s
rv = op->type->decrypt_update(op, pEncryptedData, ulEncryptedDataLen,
pData, pulDataLen);
- /* terminate session for any error except CKR_BUFFER_TOO_SMALL */
- if (rv != CKR_OK && rv != CKR_BUFFER_TOO_SMALL)
+ /* terminate session for any return value except CKR_BUFFER_TOO_SMALL,
+ * perform check in time side-channel free way to prevent Marvin attack */
+ if (~constant_time_eq_s(rv, CKR_OK) & ~constant_time_eq_s(rv, CKR_BUFFER_TOO_SMALL))
session_stop_operation(session, SC_PKCS11_OPERATION_DECRYPT);
- LOG_FUNC_RETURN(context, (int)rv);
+ /* do not log error code to prevent side channel attack */
+ return rv;
}
CK_RV
@@ -1536,6 +1541,10 @@ sc_pkcs11_decrypt(sc_pkcs11_operation_t
if (pulDataLen)
*pulDataLen = ulDataLen;
+ /* Skip DecryptFinalize for PKCS#1 v1.5 padding to prevent time side-channel leakage */
+ if (((CK_MECHANISM_PTR)&operation->mechanism)->mechanism == CKM_RSA_PKCS)
+ return rv;
+
if (rv != CKR_OK)
return rv;
Index: opensc-0.24.0/src/pkcs11/pkcs11-object.c
===================================================================
--- opensc-0.24.0.orig/src/pkcs11/pkcs11-object.c
+++ opensc-0.24.0/src/pkcs11/pkcs11-object.c
@@ -1034,7 +1034,8 @@ C_Decrypt(CK_SESSION_HANDLE hSession,
rv = reset_login_state(session->slot, rv);
}
- SC_LOG_RV("C_Decrypt() = %s", rv);
+ /* do not log error code to prevent side channel attack */
+ SC_LOG("C_Decrypt()");
sc_pkcs11_unlock();
return rv;
}
@@ -1058,7 +1059,8 @@ C_DecryptUpdate(CK_SESSION_HANDLE hSessi
rv = sc_pkcs11_decr_update(session, pEncryptedPart, ulEncryptedPartLen,
pPart, pulPartLen);
- SC_LOG_RV("C_DecryptUpdate() = %s", rv);
+ /* do not log error code to prevent side channel attack */
+ SC_LOG("C_DecryptUpdate()");
sc_pkcs11_unlock();
return rv;
}
@@ -1086,7 +1088,8 @@ C_DecryptFinal(CK_SESSION_HANDLE hSessio
rv = reset_login_state(session->slot, rv);
}
- SC_LOG_RV("C_DecryptFinal() = %s", rv);
+ /* do not log error code to prevent side channel attack */
+ SC_LOG("C_DecryptFinal()");
sc_pkcs11_unlock();
return rv;
}
Index: opensc-0.24.0/src/pkcs11/sc-pkcs11.h
===================================================================
--- opensc-0.24.0.orig/src/pkcs11/sc-pkcs11.h
+++ opensc-0.24.0/src/pkcs11/sc-pkcs11.h
@@ -246,6 +246,11 @@ do {\
}\
} while(0)
+#define SC_LOG(fmt) \
+ do { \
+ sc_log(context, (fmt)); \
+ } while (0)
+
/* Debug virtual slots. S is slot to be highlighted or NULL
* C is a comment format string and args It will be preceded by "VSS " */
#define DEBUG_VSS(S, ...) do { sc_log(context,"VSS " __VA_ARGS__); _debug_virtual_slots(S); } while (0)
Index: opensc-0.24.0/src/pkcs11/misc.c
===================================================================
--- opensc-0.24.0.orig/src/pkcs11/misc.c
+++ opensc-0.24.0/src/pkcs11/misc.c
@@ -23,6 +23,7 @@
#include <stdlib.h>
#include <string.h>
+#include "common/constant-time.h"
#include "sc-pkcs11.h"
#define DUMP_TEMPLATE_MAX 32
@@ -174,7 +175,7 @@ CK_RV reset_login_state(struct sc_pkcs11
slot->p11card->framework->logout(slot);
}
- if (rv == CKR_USER_NOT_LOGGED_IN) {
+ if (constant_time_eq_s(rv, CKR_USER_NOT_LOGGED_IN)) {
slot->login_user = -1;
pop_all_login_states(slot);
}

View File

@@ -9,10 +9,10 @@ Date: Thu Jul 11 15:27:19 2024 +0200
fuzz_card/2
Index: opensc-0.22.0/src/libopensc/card-cardos.c
Index: opensc-0.24.0/src/libopensc/card-cardos.c
===================================================================
--- opensc-0.22.0.orig/src/libopensc/card-cardos.c
+++ opensc-0.22.0/src/libopensc/card-cardos.c
--- opensc-0.24.0.orig/src/libopensc/card-cardos.c
+++ opensc-0.24.0/src/libopensc/card-cardos.c
@@ -94,14 +94,14 @@ static void fixup_transceive_length(cons
static int cardos_match_card(sc_card_t *card)
@@ -50,11 +50,11 @@ Index: opensc-0.22.0/src/libopensc/card-cardos.c
return 0;
if (apdu.resp[0] != atr[10] ||
apdu.resp[1] != atr[11])
Index: opensc-0.22.0/src/libopensc/card-cac1.c
Index: opensc-0.24.0/src/libopensc/card-cac1.c
===================================================================
--- opensc-0.22.0.orig/src/libopensc/card-cac1.c
+++ opensc-0.22.0/src/libopensc/card-cac1.c
@@ -95,12 +95,12 @@ static int cac_cac1_get_certificate(sc_c
--- opensc-0.24.0.orig/src/libopensc/card-cac1.c
+++ opensc-0.24.0/src/libopensc/card-cac1.c
@@ -92,12 +92,12 @@ static int cac_cac1_get_certificate(sc_c
if (apdu.sw1 != 0x63 || apdu.sw2 < 1) {
/* we've either finished reading, or hit an error, break */
r = sc_check_sw(card, apdu.sw1, apdu.sw2);
@@ -70,10 +70,10 @@ Index: opensc-0.22.0/src/libopensc/card-cac1.c
len = MIN(left, apdu.sw2);
}
if (r < 0) {
Index: opensc-0.22.0/src/libopensc/card-oberthur.c
Index: opensc-0.24.0/src/libopensc/card-oberthur.c
===================================================================
--- opensc-0.22.0.orig/src/libopensc/card-oberthur.c
+++ opensc-0.22.0/src/libopensc/card-oberthur.c
--- opensc-0.24.0.orig/src/libopensc/card-oberthur.c
+++ opensc-0.24.0/src/libopensc/card-oberthur.c
@@ -148,7 +148,7 @@ auth_select_aid(struct sc_card *card)
{
struct sc_apdu apdu;
@@ -93,10 +93,10 @@ Index: opensc-0.22.0/src/libopensc/card-oberthur.c
card->serialnr.len = 4;
memcpy(card->serialnr.value, apdu.resp+15, 4);
Index: opensc-0.22.0/src/libopensc/card-gids.c
Index: opensc-0.24.0/src/libopensc/card-gids.c
===================================================================
--- opensc-0.22.0.orig/src/libopensc/card-gids.c
+++ opensc-0.22.0/src/libopensc/card-gids.c
--- opensc-0.24.0.orig/src/libopensc/card-gids.c
+++ opensc-0.24.0/src/libopensc/card-gids.c
@@ -231,6 +231,7 @@ static int gids_get_DO(sc_card_t* card,
size_t datasize = 0;
const u8* p;
@@ -123,53 +123,10 @@ Index: opensc-0.22.0/src/libopensc/card-gids.c
if (!p) {
LOG_FUNC_RETURN(card->ctx, SC_ERROR_FILE_NOT_FOUND);
}
Index: opensc-0.22.0/src/libopensc/card-mcrd.c
Index: opensc-0.24.0/src/libopensc/asn1.c
===================================================================
--- opensc-0.22.0.orig/src/libopensc/card-mcrd.c
+++ opensc-0.22.0/src/libopensc/card-mcrd.c
@@ -634,23 +634,25 @@ do_select(sc_card_t * card, u8 kind,
}
}
- if (p2 == 0x04 && apdu.resp[0] == 0x62) {
- *file = sc_file_new();
- if (!*file)
- LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY);
- /* EstEID v3.0 cards are buggy and sometimes return a double 0x62 tag */
- if (card->type == SC_CARD_TYPE_MCRD_ESTEID_V30 && apdu.resp[2] == 0x62)
- process_fcp(card, *file, apdu.resp + 4, apdu.resp[3]);
- else
- process_fcp(card, *file, apdu.resp + 2, apdu.resp[1]);
- return SC_SUCCESS;
- }
+ if (p2 == 0x04 && apdu.resplen > 2 && apdu.resp[0] == 0x62) {
+ *file = sc_file_new();
+ if (!*file)
+ LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY);
+ if (apdu.resp[1] > apdu.resplen - 2)
+ LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_DATA);
+ /* EstEID v3.0 cards are buggy and sometimes return a double 0x62 tag */
+ if (card->type == SC_CARD_TYPE_MCRD_ESTEID_V30 && apdu.resp[2] == 0x62)
+ process_fcp(card, *file, apdu.resp + 4, apdu.resp[3]);
+ else
+ process_fcp(card, *file, apdu.resp + 2, apdu.resp[1]);
+ return SC_SUCCESS;
+ }
- if (p2 != 0x0C && apdu.resp[0] == 0x6F) {
+ if (p2 != 0x0C && apdu.resplen > 2 && apdu.resp[0] == 0x6F) {
*file = sc_file_new();
if (!*file)
LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY);
- if (apdu.resp[1] <= apdu.resplen)
+ if (apdu.resp[1] > apdu.resplen - 2)
process_fcp(card, *file, apdu.resp + 2, apdu.resp[1]);
return SC_SUCCESS;
}
Index: opensc-0.22.0/src/libopensc/asn1.c
===================================================================
--- opensc-0.22.0.orig/src/libopensc/asn1.c
+++ opensc-0.22.0/src/libopensc/asn1.c
--- opensc-0.24.0.orig/src/libopensc/asn1.c
+++ opensc-0.24.0/src/libopensc/asn1.c
@@ -68,7 +68,7 @@ int sc_asn1_read_tag(const u8 ** buf, si
*buf = NULL;
@@ -188,11 +145,11 @@ Index: opensc-0.22.0/src/libopensc/asn1.c
p++;
left--;
if (tag == SC_ASN1_TAG_PRIMITIVE) {
Index: opensc-0.22.0/src/libopensc/card-dnie.c
Index: opensc-0.24.0/src/libopensc/card-dnie.c
===================================================================
--- opensc-0.22.0.orig/src/libopensc/card-dnie.c
+++ opensc-0.22.0/src/libopensc/card-dnie.c
@@ -1185,12 +1185,16 @@ static int dnie_compose_and_send_apdu(sc
--- opensc-0.24.0.orig/src/libopensc/card-dnie.c
+++ opensc-0.24.0/src/libopensc/card-dnie.c
@@ -1171,12 +1171,16 @@ static int dnie_compose_and_send_apdu(sc
if (file_out) {
/* finally process FCI response */
@@ -210,7 +167,7 @@ Index: opensc-0.22.0/src/libopensc/card-dnie.c
}
LOG_FUNC_RETURN(ctx, res);
}
@@ -1949,7 +1953,7 @@ static int dnie_process_fci(struct sc_ca
@@ -1934,7 +1938,7 @@ static int dnie_process_fci(struct sc_ca
int *op = df_acl;
int n = 0;
sc_context_t *ctx = NULL;
@@ -219,40 +176,11 @@ Index: opensc-0.22.0/src/libopensc/card-dnie.c
return SC_ERROR_INVALID_ARGUMENTS;
ctx = card->ctx;
LOG_FUNC_CALLED(ctx);
Index: opensc-0.22.0/src/libopensc/muscle.c
Index: opensc-0.24.0/src/libopensc/muscle.c
===================================================================
--- opensc-0.22.0.orig/src/libopensc/muscle.c
+++ opensc-0.22.0/src/libopensc/muscle.c
@@ -94,33 +94,35 @@ int msc_partial_read_object(sc_card_t *c
apdu.resp = data;
r = sc_transmit_apdu(card, &apdu);
LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
- if(apdu.sw1 == 0x90 && apdu.sw2 == 0x00)
- return dataLength;
- if(apdu.sw1 == 0x9C) {
- if(apdu.sw2 == 0x07) {
+ if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00 && dataLength <= apdu.resplen)
+ return dataLength;
+ if (apdu.sw1 == 0x9C) {
+ if (apdu.sw2 == 0x07) {
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_FILE_NOT_FOUND);
- } else if(apdu.sw2 == 0x06) {
+ } else if (apdu.sw2 == 0x06) {
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_NOT_ALLOWED);
- } else if(apdu.sw2 == 0x0F) {
+ } else if (apdu.sw2 == 0x0F) {
/* GUESSED */
SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS);
}
}
sc_log(card->ctx,
"got strange SWs: 0x%02X 0x%02X\n", apdu.sw1, apdu.sw2);
- return dataLength;
-
-}
+
+ SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_UNKNOWN_DATA_RECEIVED);
+ }
--- opensc-0.24.0.orig/src/libopensc/muscle.c
+++ opensc-0.24.0/src/libopensc/muscle.c
@@ -112,13 +112,15 @@ int msc_partial_read_object(sc_card_t *c
int msc_read_object(sc_card_t *card, msc_id objectId, int offset, u8 *data, size_t dataLength)
{
@@ -265,16 +193,25 @@ Index: opensc-0.22.0/src/libopensc/muscle.c
+ for(i = 0; i < dataLength; i += r) {
r = msc_partial_read_object(card, objectId, offset + i, data + i, MIN(dataLength - i, max_read_unit));
LOG_TEST_RET(card->ctx, r, "Error in partial object read");
+ if (r==0)
+ if (r == 0)
+ break;
}
return dataLength;
}
Index: opensc-0.22.0/src/libopensc/card-entersafe.c
@@ -171,7 +173,7 @@ int msc_create_object(sc_card_t *card, m
apdu.sw1, apdu.sw2);
}
msc_zero_object(card, objectId, objectSize);
- return objectSize;
+ SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_UNKNOWN_DATA_RECEIVED);
}
/* Update up to MSC_MAX_READ - 9 bytes */
Index: opensc-0.24.0/src/libopensc/card-entersafe.c
===================================================================
--- opensc-0.22.0.orig/src/libopensc/card-entersafe.c
+++ opensc-0.22.0/src/libopensc/card-entersafe.c
@@ -1453,7 +1453,9 @@ static int entersafe_get_serialnr(sc_car
--- opensc-0.24.0.orig/src/libopensc/card-entersafe.c
+++ opensc-0.24.0/src/libopensc/card-entersafe.c
@@ -1482,7 +1482,9 @@ static int entersafe_get_serialnr(sc_car
r=entersafe_transmit_apdu(card, &apdu,0,0,0,0);
LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
LOG_TEST_RET(card->ctx, sc_check_sw(card,apdu.sw1,apdu.sw2),"EnterSafe get SN failed");

View File

@@ -9,11 +9,11 @@ Date: Tue Jul 16 14:05:36 2024 +0200
fuzz_pkcs11/14
Index: opensc-0.22.0/src/libopensc/card-cac.c
Index: opensc-0.24.0/src/libopensc/card-cac.c
===================================================================
--- opensc-0.22.0.orig/src/libopensc/card-cac.c
+++ opensc-0.22.0/src/libopensc/card-cac.c
@@ -1302,10 +1302,10 @@ static int cac_parse_aid(sc_card_t *card
--- opensc-0.24.0.orig/src/libopensc/card-cac.c
+++ opensc-0.24.0/src/libopensc/card-cac.c
@@ -1292,10 +1292,10 @@ static int cac_parse_aid(sc_card_t *card
/* Call without OID set will just select the AID without subsequent
* OID selection, which we need to figure out just now
*/
@@ -27,11 +27,11 @@ Index: opensc-0.22.0/src/libopensc/card-cac.c
for (i = 0; i < prop.num_objects; i++) {
/* don't fail just because we have more certs than we can support */
Index: opensc-0.22.0/src/libopensc/card-cardos.c
Index: opensc-0.24.0/src/libopensc/card-cardos.c
===================================================================
--- opensc-0.22.0.orig/src/libopensc/card-cardos.c
+++ opensc-0.22.0/src/libopensc/card-cardos.c
@@ -1277,7 +1277,7 @@ cardos_lifecycle_get(sc_card_t *card, in
--- opensc-0.24.0.orig/src/libopensc/card-cardos.c
+++ opensc-0.24.0/src/libopensc/card-cardos.c
@@ -1278,7 +1278,7 @@ cardos_lifecycle_get(sc_card_t *card, in
LOG_TEST_RET(card->ctx, r, "Card returned error");
if (apdu.resplen < 1) {
@@ -40,10 +40,10 @@ Index: opensc-0.22.0/src/libopensc/card-cardos.c
}
r = SC_SUCCESS;
Index: opensc-0.22.0/src/libopensc/card-jpki.c
Index: opensc-0.24.0/src/libopensc/card-jpki.c
===================================================================
--- opensc-0.22.0.orig/src/libopensc/card-jpki.c
+++ opensc-0.22.0/src/libopensc/card-jpki.c
--- opensc-0.24.0.orig/src/libopensc/card-jpki.c
+++ opensc-0.24.0/src/libopensc/card-jpki.c
@@ -195,6 +195,8 @@ jpki_select_file(struct sc_card *card,
u8 buf[4];
rc = sc_read_binary(card, 0, buf, 4, 0);

View File

@@ -9,11 +9,11 @@ Date: Wed Jul 17 11:18:52 2024 +0200
fuzz_pkcs15_encode/21
diff --git a/src/libopensc/pkcs15-tcos.c b/src/libopensc/pkcs15-tcos.c
index 4d02a98ee..2bd275c4f 100644
--- a/src/libopensc/pkcs15-tcos.c
+++ b/src/libopensc/pkcs15-tcos.c
@@ -531,10 +531,15 @@ int sc_pkcs15emu_tcos_init_ex(
Index: opensc-0.24.0/src/libopensc/pkcs15-tcos.c
===================================================================
--- opensc-0.24.0.orig/src/libopensc/pkcs15-tcos.c
+++ opensc-0.24.0/src/libopensc/pkcs15-tcos.c
@@ -530,10 +530,15 @@ int sc_pkcs15emu_tcos_init_ex(
/* get the card serial number */
r = sc_card_ctl(card, SC_CARDCTL_GET_SERIALNR, &serialnr);
if (r < 0) {
@@ -31,23 +31,11 @@ index 4d02a98ee..2bd275c4f 100644
serial[19] = '\0';
set_string(&p15card->tokeninfo->serial_number, serial);
commit f9d68660f032ad4d7803431d5fc7577ea8792ac3
Author: Veronika Hanulíková <vhanulik@redhat.com>
Date: Wed Jul 17 14:56:22 2024 +0200
pkcs15-lib: Report transport key error
Thanks Matteo Marini for report
https://github.com/OpenSC/OpenSC/security/advisories/GHSA-p3mx-7472-h3j8
fuzz_pkcs15init/17, fuzz_pkcs15init/18
diff --git a/src/pkcs15init/pkcs15-lib.c b/src/pkcs15init/pkcs15-lib.c
index 6574e8025..943d53e98 100644
--- a/src/pkcs15init/pkcs15-lib.c
+++ b/src/pkcs15init/pkcs15-lib.c
@@ -3831,13 +3831,15 @@ sc_pkcs15init_get_transport_key(struct sc_profile *profile, struct sc_pkcs15_car
Index: opensc-0.24.0/src/pkcs15init/pkcs15-lib.c
===================================================================
--- opensc-0.24.0.orig/src/pkcs15init/pkcs15-lib.c
+++ opensc-0.24.0/src/pkcs15init/pkcs15-lib.c
@@ -3805,13 +3805,15 @@ sc_pkcs15init_get_transport_key(struct s
if (callbacks.get_key) {
rv = callbacks.get_key(profile, type, reference, defbuf, defsize, pinbuf, pinsize);
LOG_TEST_RET(ctx, rv, "Cannot get key");

View File

@@ -154,15 +154,6 @@ Index: opensc-0.24.0/src/pkcs15init/pkcs15-setcos.c
keybits = ((raw_pubkey[0] * 256) + raw_pubkey[1]); /* modulus bit length */
if (keybits != key_info->modulus_length) {
sc_log(ctx,
@@ -505,7 +508,7 @@ setcos_generate_key(struct sc_profile *p
keybits, key_info->modulus_length);
LOG_TEST_RET(ctx, SC_ERROR_PKCS15INIT, "Failed to generate key");
}
- memcpy (pubkey->u.rsa.modulus.data, &raw_pubkey[2], pubkey->u.rsa.modulus.len);
+ memcpy(pubkey->u.rsa.modulus.data, &raw_pubkey[2], pubkey->u.rsa.modulus.len);
}
sc_file_free(file);
Index: opensc-0.24.0/src/pkcs15init/pkcs15-sc-hsm.c
===================================================================
--- opensc-0.24.0.orig/src/pkcs15init/pkcs15-sc-hsm.c

View File

@@ -40,14 +40,14 @@ Index: opensc-0.24.0/src/libopensc/iasecc-sdo.c
LOG_FUNC_CALLED(ctx);
+ if (data_len < 1)
+ LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_DATA);
+ LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_DATA);
+
if (*data == IASECC_SDO_TEMPLATE_TAG) {
size_size = iasecc_parse_size(data + 1, data_len - 1, &size);
LOG_TEST_RET(ctx, size_size, "parse error: invalid size data of IASECC_SDO_TEMPLATE");
+ if (data_len - 1 < size)
+ LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_DATA);
+ LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_DATA);
+
data += size_size + 1;
data_len = size;

View File

@@ -14,11 +14,11 @@ Date: Mon Aug 12 19:02:14 2024 +0200
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
Index: opensc-0.22.0/src/libopensc/card-openpgp.c
Index: opensc-0.24.0/src/libopensc/card-openpgp.c
===================================================================
--- opensc-0.22.0.orig/src/libopensc/card-openpgp.c
+++ opensc-0.22.0/src/libopensc/card-openpgp.c
@@ -2657,14 +2657,21 @@ pgp_calculate_and_store_fingerprint(sc_c
--- opensc-0.24.0.orig/src/libopensc/card-openpgp.c
+++ opensc-0.24.0/src/libopensc/card-openpgp.c
@@ -2769,14 +2769,21 @@ pgp_calculate_and_store_fingerprint(sc_c
/* update the blob containing fingerprints (00C5) */
sc_log(card->ctx, "Updating fingerprint blob 00C5.");
fpseq_blob = pgp_find_blob(card, 0x00C5);
@@ -45,7 +45,7 @@ Index: opensc-0.22.0/src/libopensc/card-openpgp.c
memcpy(newdata, fpseq_blob->data, fpseq_blob->len);
/* move p to the portion holding the fingerprint of the current key */
@@ -2778,6 +2785,9 @@ pgp_parse_and_set_pubkey_output(sc_card_
@@ -2891,6 +2898,9 @@ pgp_parse_and_set_pubkey_output(sc_card_
/* RSA modulus */
if (tag == 0x0081) {
@@ -55,7 +55,7 @@ Index: opensc-0.22.0/src/libopensc/card-openpgp.c
if ((BYTES4BITS(key_info->u.rsa.modulus_len) < len) /* modulus_len is in bits */
|| key_info->u.rsa.modulus == NULL) {
@@ -2793,6 +2803,9 @@ pgp_parse_and_set_pubkey_output(sc_card_
@@ -2906,6 +2916,9 @@ pgp_parse_and_set_pubkey_output(sc_card_
}
/* RSA public exponent */
else if (tag == 0x0082) {
@@ -65,7 +65,7 @@ Index: opensc-0.22.0/src/libopensc/card-openpgp.c
if ((BYTES4BITS(key_info->u.rsa.exponent_len) < len) /* exponent_len is in bits */
|| key_info->u.rsa.exponent == NULL) {
@@ -2808,6 +2821,10 @@ pgp_parse_and_set_pubkey_output(sc_card_
@@ -2921,6 +2934,10 @@ pgp_parse_and_set_pubkey_output(sc_card_
}
/* ECC public key */
else if (tag == 0x0086) {

View File

@@ -1,3 +1,10 @@
-------------------------------------------------------------------
Tue Jun 24 17:04:42 UTC 2025 - Martin Schreiner <martin.schreiner@suse.com>
- Security fix: [CVE-2023-5992, bsc#1219386]
* Add patch:
- opensc-CVE-2023-5992.patch
-------------------------------------------------------------------
Tue Oct 1 06:30:06 UTC 2024 - Angel Yankov <angel.yankov@suse.com>
@@ -27,7 +34,7 @@ Tue Oct 1 06:27:05 UTC 2024 - Angel Yankov <angel.yankov@suse.com>
- opensc-CVE-2024-45618.patch
- opensc-CVE-2024-45619.patch
- opensc-CVE-2024-45620.patch
-------------------------------------------------------------------
Sun Feb 25 20:35:05 UTC 2024 - Martin Schreiner <martin.schreiner@suse.com>

View File

@@ -31,22 +31,24 @@ Source2: %{name}-rpmlintrc
# https://web.archive.org/web/20111225073733/http://www.opensc-project.org/opensc/ticket/390
Source3: opensc.module
Patch0: opensc-gcc11.patch
# PATCH-FIX-UPSTREAM: bsc#1219386 CVE-2023-5992: Side-channel leaks while stripping encryption PKCS#1 padding
Patch1: opensc-CVE-2023-5992.patch
# PATCH-FIX-UPSTREAM martin.schreiner@suse.com CVE-2024-1454 bsc#1219868
Patch1: CVE-2024-1454.patch
# PATCH-FIX-UPSTREAM: bsc#1230364 CVE-2024-8443: heap buffer overflow in OpenPGP driver when generating key
Patch2: opensc-CVE-2024-8443.patch
Patch2: CVE-2024-1454.patch
# PATCH-FIX-UPSTREAM bsc#1230364 opensc: heap buffer overflow in OpenPGP driver when generating key
Patch3: opensc-CVE-2024-8443.patch
# PATCH-FIX-UPSTREAM: bsc#1230071 CVE-2024-45615: opensc: pkcs15init: Usage of uninitialized values in libopensc and pkcs15init
Patch3: opensc-CVE-2024-45615.patch
# PATCH-FIX-UPSTREAM: bsc#1230072 CVE-2024-45616: opensc: Uninitialized values after incorrect check or usage of APDU response values in libopensc
Patch4: opensc-CVE-2024-45616.patch
Patch4: opensc-CVE-2024-45615.patch
# PATCH-FIX-UPSTREAM: bsc#1230072 CVE-2024-45616: opensc: Uninitialized values after incorrect check or usage of APDU response values in libopensc
Patch5: opensc-CVE-2024-45616.patch
# PATCH-FIX-UPSTREAM: bsc#1230073 CVE-2024-45617: opensc: Uninitialized values after incorrect or missing checking return values of functions in libopensc
Patch5: opensc-CVE-2024-45617.patch
Patch6: opensc-CVE-2024-45617.patch
# PATCH-FIX-UPSTREAM: bsc#1230074 CVE-2024-45618: opensc: Uninitialized values after incorrect or missing checking return values of functions in pkcs15init
Patch6: opensc-CVE-2024-45618.patch
Patch7: opensc-CVE-2024-45618.patch
# PATCH-FIX-UPSTREAM: bsc#1230075 CVE-2024-45619: opensc: Incorrect handling length of buffers or files in libopensc
Patch7: opensc-CVE-2024-45619.patch
# PATCH-FIX-UPSTREAM: bsc#1230076 CVE-2024-45620: opensc: Incorrect handling of the length of buffers or files in pkcs15init
Patch8: opensc-CVE-2024-45620.patch
Patch8: opensc-CVE-2024-45619.patch
# PATCH-FIX-UPSTREAM: bsc#1230076 CVE-2024-45620: opensc: Incorrect handling of the length of buffers or files in pkcs15init
Patch9: opensc-CVE-2024-45620.patch
BuildRequires: docbook-xsl-stylesheets
BuildRequires: libxslt
@@ -56,6 +58,7 @@ BuildRequires: zlib-devel
BuildRequires: pkgconfig(bash-completion)
BuildRequires: pkgconfig(libpcsclite) >= 1.8.22
BuildRequires: pkgconfig(openssl) >= 1.0.1
BuildRequires: automake
Requires: pcsc-lite
# There is no more devel package.
Obsoletes: opensc-devel < %{version}
@@ -79,6 +82,8 @@ may require third party proprietary software.
%autosetup -p1
%build
aclocal
automake
%configure \
--docdir=%{_docdir}/%{name} \
--disable-static \