import CS opensc-0.23.0-5.el9

This commit is contained in:
eabdullin 2025-03-11 07:53:55 +00:00
parent 873535e9e3
commit 76917519d5
7 changed files with 2644 additions and 1 deletions

View File

@ -0,0 +1,96 @@
From bff98ff078a99e6864ba1a598fd7dc9af4a9476b Mon Sep 17 00:00:00 2001
From: Jakub Jelen <jjelen@redhat.com>
Date: Thu, 7 Sep 2023 13:23:04 +0200
Subject: [PATCH] cache: Honor the file offset when writing cache
When the reads are not consecutive, avoid caching anything after the gaps.
Signed-off-by: Jakub Jelen <jjelen@redhat.com>
---
src/libopensc/pkcs15-cache.c | 18 +++++++++++++++---
1 file changed, 15 insertions(+), 3 deletions(-)
diff --git a/src/libopensc/pkcs15-cache.c b/src/libopensc/pkcs15-cache.c
index 6ebe35a8af..61af35fc5a 100644
--- a/src/libopensc/pkcs15-cache.c
+++ b/src/libopensc/pkcs15-cache.c
@@ -195,6 +195,7 @@ int sc_pkcs15_cache_file(struct sc_pkcs15_card *p15card,
{
char fname[PATH_MAX];
int r;
+ long len;
FILE *f;
size_t c;
@@ -202,22 +203,33 @@ int sc_pkcs15_cache_file(struct sc_pkcs15_card *p15card,
if (r != 0)
return r;
- f = fopen(fname, "wb");
+ f = fopen(fname, "ab");
/* If the open failed because the cache directory does
* not exist, create it and a re-try the fopen() call.
*/
if (f == NULL && errno == ENOENT) {
if ((r = sc_make_cache_dir(p15card->card->ctx)) < 0)
return r;
- f = fopen(fname, "wb");
+ f = fopen(fname, "ab");
}
if (f == NULL)
return 0;
+ /* we opened the file for appending so we should be at the end of file.
+ * The ftell() will give use the length of the file */
+ len = ftell(f);
+ if (len > path->index) {
+ /* override previous cache records on this location */
+ fseek(f, path->index, SEEK_SET);
+ } else if (path->index > len) {
+ /* We miss some bytes so we will not cache this chunk */
+ return 0;
+ }
+
c = fwrite(buf, 1, bufsize, f);
fclose(f);
if (c != bufsize) {
- sc_log(p15card->card->ctx,
+ sc_log(p15card->card->ctx,
"fwrite() wrote only %"SC_FORMAT_LEN_SIZE_T"u bytes",
c);
unlink(fname);
From 0875c69295ef28b45fb682b37cede58fc36b7a1a Mon Sep 17 00:00:00 2001
From: Jakub Jelen <jjelen@redhat.com>
Date: Fri, 15 Sep 2023 19:17:53 +0200
Subject: [PATCH] pkcs15-cache: Avoid fd leaks and check return values
CID 401725
CID 401726
Thanks coverity
---
src/libopensc/pkcs15-cache.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/src/libopensc/pkcs15-cache.c b/src/libopensc/pkcs15-cache.c
index 61af35fc5a..bae5797fe2 100644
--- a/src/libopensc/pkcs15-cache.c
+++ b/src/libopensc/pkcs15-cache.c
@@ -220,9 +220,14 @@ int sc_pkcs15_cache_file(struct sc_pkcs15_card *p15card,
len = ftell(f);
if (len > path->index) {
/* override previous cache records on this location */
- fseek(f, path->index, SEEK_SET);
+ r = fseek(f, path->index, SEEK_SET);
+ if (r != 0) {
+ fclose(f);
+ return 0;
+ }
} else if (path->index > len) {
/* We miss some bytes so we will not cache this chunk */
+ fclose(f);
return 0;
}

View File

@ -0,0 +1,824 @@
diff --git a/src/common/Makefile.am b/src/common/Makefile.am
index 5153428dce..9ecbffe8fd 100644
--- a/src/common/Makefile.am
+++ b/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
+noinst_HEADERS = compat_strlcat.h compat_strlcpy.h compat_strnlen.h compat_getpass.h \
+ compat_getopt.h simclist.h libpkcs11.h libscdl.h constant-time.h
AM_CPPFLAGS = -I$(top_srcdir)/src
@@ -43,7 +44,8 @@ TIDY_FILES = \
compat_report_rangecheckfailure.c \
compat___iob_func.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)' -header-filter=.* $(addprefix $(srcdir)/,$(TIDY_FILES)) -- $(TIDY_FLAGS); fi
diff --git a/src/common/constant-time.h b/src/common/constant-time.h
new file mode 100644
index 0000000000..40c3e500c2
--- /dev/null
+++ b/src/common/constant-time.h
@@ -0,0 +1,134 @@
+/* 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);
+}
+
+static constant_inline unsigned int
+constant_time_eq_i(int a, int b)
+{
+ return constant_time_eq((unsigned int)a, (unsigned int)b);
+}
+
+#endif /* CONSTANT_TIME_H */
diff --git a/src/libopensc/internal.h b/src/libopensc/internal.h
index 7531260c14..2a98f0e966 100644
--- a/src/libopensc/internal.h
+++ b/src/libopensc/internal.h
@@ -175,8 +175,8 @@ int _sc_card_add_xeddsa_alg(struct sc_card *card, size_t key_length,
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
diff --git a/src/libopensc/padding.c b/src/libopensc/padding.c
index ca47733a4e..ddb3061134 100644
--- a/src/libopensc/padding.c
+++ b/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
*/
@@ -144,44 +147,82 @@ sc_pkcs1_strip_01_padding(struct sc_cont
}
-/* 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
diff --git a/src/minidriver/minidriver.c b/src/minidriver/minidriver.c
index 3391994abe..5248d9758a 100644
--- a/src/minidriver/minidriver.c
+++ b/src/minidriver/minidriver.c
@@ -4653,9 +4653,9 @@ DWORD WINAPI CardRSADecrypt(__in PCARD_DATA pCardData,
"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);
diff --git a/src/tests/unittests/Makefile.am b/src/tests/unittests/Makefile.am
index 7019ca7ba8..4c73911e48 100644
--- a/src/tests/unittests/Makefile.am
+++ b/src/tests/unittests/Makefile.am
@@ -6,8 +6,10 @@ include $(top_srcdir)/aminclude_static.a
clean-local: code-coverage-clean
distclean-local: code-coverage-dist-clean
-noinst_PROGRAMS = asn1 simpletlv cachedir pkcs15filter openpgp-tool hextobin decode_ecdsa_signature
-TESTS = asn1 simpletlv cachedir pkcs15filter openpgp-tool hextobin decode_ecdsa_signature
+noinst_PROGRAMS = asn1 simpletlv cachedir pkcs15filter openpgp-tool hextobin \
+ decode_ecdsa_signature strip_pkcs1_2_padding
+TESTS = asn1 simpletlv cachedir pkcs15filter openpgp-tool hextobin \
+ decode_ecdsa_signature strip_pkcs1_2_padding
noinst_HEADERS = torture.h
@@ -28,6 +30,7 @@ pkcs15filter_SOURCES = pkcs15-emulator-f
openpgp_tool_SOURCES = openpgp-tool.c $(top_builddir)/src/tools/openpgp-tool-helpers.c
hextobin_SOURCES = hextobin.c
decode_ecdsa_signature_SOURCES = decode_ecdsa_signature.c
+strip_pkcs1_2_paddingSOURCES = strip_pkcs1_2_padding.c
if ENABLE_ZLIB
noinst_PROGRAMS += compression
diff --git a/src/tests/unittests/Makefile.mak b/src/tests/unittests/Makefile.mak
index 2607546f57..6284b51af9 100644
--- a/src/tests/unittests/Makefile.mak
+++ b/src/tests/unittests/Makefile.mak
@@ -1,10 +1,11 @@
TOPDIR = ..\..\..
-TARGETS = asn1 compression pkcs15filter
+TARGETS = asn1 compression pkcs15filter strip_pkcs1_2_padding
OBJECTS = asn1.obj \
compression.obj \
- pkcs15-emulator-filter.obj
+ pkcs15-emulator-filter.obj \
+ strip_pkcs1_2_padding.obj \
$(TOPDIR)\win32\versioninfo.res
all: $(TARGETS)
diff --git a/src/tests/unittests/strip_pkcs1_2_padding.c b/src/tests/unittests/strip_pkcs1_2_padding.c
new file mode 100644
index 0000000000..f9561b936d
--- /dev/null
+++ b/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 = calloc(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 = calloc(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 = calloc(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 = calloc(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 = calloc(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 = calloc(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 = calloc(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 = calloc(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 = calloc(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 = calloc(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 = calloc(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);
+}
diff --git a/src/libopensc/pkcs15-sec.c b/src/libopensc/pkcs15-sec.c
index a019af460f..f7ee819d65 100644
--- a/src/libopensc/pkcs15-sec.c
+++ b/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
diff --git a/src/pkcs11/framework-pkcs15.c b/src/pkcs11/framework-pkcs15.c
index f75a3dbaec..632681df63 100644
--- a/src/pkcs11/framework-pkcs15.c
+++ b/src/pkcs11/framework-pkcs15.c
@@ -18,6 +18,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#include "common/constant-time.h"
#include "config.h"
#include <stdlib.h>
#include <string.h>
@@ -4395,7 +4396,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 */
@@ -4484,27 +4486,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_i(rv, SC_ERROR_WRONG_PADDING) & constant_time_lt_s(sizeof(decrypted), (size_t)rv)))
+ return sc_to_cryptoki_error(rv, "C_Decrypt");
- return CKR_OK;
+ /* check rv for padding error */
+ good = ~constant_time_eq_i(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;
}
diff --git a/src/pkcs11/mechanism.c b/src/pkcs11/mechanism.c
index 03495265a4..d3f0434231 100644
--- a/src/pkcs11/mechanism.c
+++ b/src/pkcs11/mechanism.c
@@ -23,6 +23,7 @@
#include <stdlib.h>
#include <string.h>
+#include "common/constant-time.h"
#include "sc-pkcs11.h"
/* Also used for verification data */
@@ -1089,7 +1090,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;
@@ -1110,10 +1113,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
@@ -1530,6 +1535,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;
diff --git a/src/pkcs11/pkcs11-object.c b/src/pkcs11/pkcs11-object.c
index f04c0b4c56..b023911213 100644
--- a/src/pkcs11/pkcs11-object.c
+++ b/src/pkcs11/pkcs11-object.c
@@ -1034,7 +1034,8 @@ C_Decrypt(CK_SESSION_HANDLE hSession, /* the session's handle */
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 hSession, /* the session's handle */
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 hSession, /* the session's handle */
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;
}
diff --git a/src/pkcs11/sc-pkcs11.h b/src/pkcs11/sc-pkcs11.h
index 66dfcdde67..510017ed2a 100644
--- a/src/pkcs11/sc-pkcs11.h
+++ b/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)
diff --git a/src/pkcs11/misc.c b/src/pkcs11/misc.c
index 5ca1176b1d..1d893d6181 100644
--- a/src/pkcs11/misc.c
+++ b/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 *slot, CK_RV rv)
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

@ -0,0 +1,99 @@
From cde2e050ec4f2f1b7db38429aa4e9c0f4656308c Mon Sep 17 00:00:00 2001
From: Peter Popovec <popovec.peter@gmail.com>
Date: Wed, 26 Apr 2023 13:22:09 +0200
Subject: [PATCH] NULL pointer fix
Thanks to the clang analyzer:
Null pointer passed to 2nd parameter expecting 'nonnull'
[clang-analyzer-core.NonNullParamChecker]
modified: src/libopensc/card-myeid.c
---
src/libopensc/card-myeid.c | 15 ++++++++++-----
1 file changed, 10 insertions(+), 5 deletions(-)
diff --git a/src/libopensc/card-myeid.c b/src/libopensc/card-myeid.c
index 31dd209f3..951c179f1 100644
--- a/src/libopensc/card-myeid.c
+++ b/src/libopensc/card-myeid.c
@@ -1973,6 +1973,9 @@ myeid_enc_dec_sym(struct sc_card *card, const u8 *data, size_t datalen,
return_len = block_size - pad_byte;
}
*outlen = return_len;
+ /* application can request buffer size or actual buffer size is too small */
+ if (out == NULL)
+ LOG_FUNC_RETURN(ctx, SC_SUCCESS);
if (return_len > *outlen)
LOG_FUNC_RETURN(ctx, SC_ERROR_BUFFER_TOO_SMALL);
memcpy(out, priv->sym_plain_buffer, return_len);
@@ -2042,10 +2045,11 @@ myeid_enc_dec_sym(struct sc_card *card, const u8 *data, size_t datalen,
priv->sym_crypt_buffer_len = 0;
rest_len = 0;
}
- memcpy(sdata, data, apdu_datalen);
- data += apdu_datalen;
- datalen -= apdu_datalen;
-
+ if (data) {
+ memcpy(sdata, data, apdu_datalen);
+ data += apdu_datalen;
+ datalen -= apdu_datalen;
+ }
r = sc_transmit_apdu(card, &apdu);
LOG_TEST_RET(ctx, r, "APDU transmit failed");
r = sc_check_sw(card, apdu.sw1, apdu.sw2);
@@ -2084,7 +2088,8 @@ myeid_enc_dec_sym(struct sc_card *card, const u8 *data, size_t datalen,
/* save rest of data for next run */
priv->sym_crypt_buffer_len = datalen;
sc_log(ctx, "rest data len = %zu", datalen);
- memcpy(priv->sym_crypt_buffer, data, datalen);
+ if (data)
+ memcpy(priv->sym_crypt_buffer, data, datalen);
sc_log(ctx, "return data len = %zu", return_len);
*outlen = return_len;
return SC_SUCCESS;
--
2.41.0
From f1993dc4e0b33050b8f72a3558ee88b24c4063b2 Mon Sep 17 00:00:00 2001
From: Peter Popovec <popovec.peter@gmail.com>
Date: Tue, 27 Jun 2023 09:50:42 +0200
Subject: [PATCH] myeid: fixed CID 380538 Out-of-bounds read (OVERRUN)
also fixes output buffer size checking
---
src/libopensc/card-myeid.c | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/src/libopensc/card-myeid.c b/src/libopensc/card-myeid.c
index 4ee424684..50e78ff1d 100644
--- a/src/libopensc/card-myeid.c
+++ b/src/libopensc/card-myeid.c
@@ -1986,18 +1986,20 @@ myeid_enc_dec_sym(struct sc_card *card, const u8 *data, size_t datalen,
sc_log(ctx, "Found padding byte %02x", pad_byte);
if (pad_byte == 0 || pad_byte > block_size)
LOG_FUNC_RETURN(ctx, SC_ERROR_WRONG_PADDING);
- sdata = priv->sym_plain_buffer + block_size - pad_byte;
+ sdata = priv->sym_plain_buffer + block_size;
for (i = 0; i < pad_byte; i++)
- if (sdata[i] != pad_byte)
+ if (*(--sdata) != pad_byte)
LOG_FUNC_RETURN(ctx, SC_ERROR_WRONG_PADDING);
return_len = block_size - pad_byte;
}
- *outlen = return_len;
/* application can request buffer size or actual buffer size is too small */
- if (out == NULL)
+ if (out == NULL) {
+ *outlen = return_len;
LOG_FUNC_RETURN(ctx, SC_SUCCESS);
+ }
if (return_len > *outlen)
LOG_FUNC_RETURN(ctx, SC_ERROR_BUFFER_TOO_SMALL);
+ *outlen = return_len;
memcpy(out, priv->sym_plain_buffer, return_len);
sc_log(ctx, "C_DecryptFinal %zu bytes", *outlen);
return SC_SUCCESS;
--
2.41.0

View File

@ -0,0 +1,107 @@
From 868f76fb31255fd3fdacfc3e476452efeb61c3e7 Mon Sep 17 00:00:00 2001
From: Frank Morgner <frankmorgner@gmail.com>
Date: Wed, 21 Jun 2023 12:27:23 +0200
Subject: [PATCH] Fixed PIN authentication bypass
If two processes are accessing a token, then one process may leave the
card usable with an authenticated PIN so that a key may sign/decrypt any
data. This is especially the case if the token does not support a way of
resetting the authentication status (logout).
We have some tracking of the authentication status in software via
PKCS#11, Minidriver (os-wise) and CryptoTokenKit, which is why a
PIN-prompt will appear even though the card may technically be unlocked
as described in the above example. However, before this change, an empty
PIN was not verified (likely yielding an error during PIN-verification),
but it was just checked whether the PIN is authenticated. This defeats
the purpose of the PIN verification, because an empty PIN is not the
correct one. Especially during OS Logon, we don't want that kind of
shortcut, but we want the user to verify the correct PIN (even though
the token was left unattended and authentication at the computer).
This essentially reverts commit e6f7373ef066cfab6e3162e8b5f692683db23864.
---
src/libopensc/pkcs15-pin.c | 13 -------------
1 file changed, 13 deletions(-)
diff --git a/src/libopensc/pkcs15-pin.c b/src/libopensc/pkcs15-pin.c
index 80a185fecd..393234efe4 100644
--- a/src/libopensc/pkcs15-pin.c
+++ b/src/libopensc/pkcs15-pin.c
@@ -307,19 +307,6 @@ sc_pkcs15_verify_pin(struct sc_pkcs15_card *p15card, struct sc_pkcs15_object *pi
LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_PIN_REFERENCE);
auth_info = (struct sc_pkcs15_auth_info *)pin_obj->data;
- /*
- * if pin cache is disabled, we can get here with no PIN data.
- * in this case, to avoid error or unnecessary pin prompting on pinpad,
- * check if the PIN has been already verified and the access condition
- * is still open on card.
- */
- if (pinlen == 0) {
- r = sc_pkcs15_get_pin_info(p15card, pin_obj);
-
- if (r == SC_SUCCESS && auth_info->logged_in == SC_PIN_STATE_LOGGED_IN)
- LOG_FUNC_RETURN(ctx, r);
- }
-
r = _validate_pin(p15card, auth_info, pinlen);
if (r)
From 80cc5d30635f0d2c92b5099c0f9dc680d0ffce2f Mon Sep 17 00:00:00 2001
From: Jakub Jelen <jjelen@redhat.com>
Date: Tue, 24 Oct 2023 11:13:08 +0200
Subject: [PATCH] pkcs15init: Check login status before asking for a pin
The original code block from e6f7373 is still needed when pkcs15init
layer checks ACLs for PKCS#15 objects, but it should be kept out of
the libopensc, which is used for more authentication code paths
and can be used for PIN bypass.
---
src/libopensc/pkcs15-pin.c | 1 +
src/pkcs15init/pkcs15-lib.c | 16 ++++++++++++++++
2 files changed, 17 insertions(+)
diff --git a/src/libopensc/pkcs15-pin.c b/src/libopensc/pkcs15-pin.c
index 393234efe..b26e57236 100644
--- a/src/libopensc/pkcs15-pin.c
+++ b/src/libopensc/pkcs15-pin.c
@@ -307,6 +307,7 @@ sc_pkcs15_verify_pin(struct sc_pkcs15_card *p15card, struct sc_pkcs15_object *pi
LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_PIN_REFERENCE);
auth_info = (struct sc_pkcs15_auth_info *)pin_obj->data;
+ /* Check the provided pin matches pin requirements */
r = _validate_pin(p15card, auth_info, pinlen);
if (r)
diff --git a/src/pkcs15init/pkcs15-lib.c b/src/pkcs15init/pkcs15-lib.c
index 9148b83b5..cca11d1f1 100644
--- a/src/pkcs15init/pkcs15-lib.c
+++ b/src/pkcs15init/pkcs15-lib.c
@@ -3958,6 +3958,22 @@ sc_pkcs15init_verify_secret(struct sc_profile *profile, struct sc_pkcs15_card *p
found:
if (pin_obj) {
+ /*
+ * If pin cache is disabled or the reader is using pinpad, we can get here
+ * with no PIN data. This is ok as we can not asynchronously invoke the prompt
+ * (unless the pinpad is in use).
+ * In this case, check if the PIN has been already verified and
+ * the access condition is still open on card.
+ */
+ if (pinsize == 0) {
+ r = sc_pkcs15_get_pin_info(p15card, pin_obj);
+ /* update local copy of auth info */
+ memcpy(&auth_info, pin_obj->data, sizeof(auth_info));
+
+ if (r == SC_SUCCESS && auth_info.logged_in == SC_PIN_STATE_LOGGED_IN)
+ LOG_FUNC_RETURN(ctx, r);
+ }
+
r = sc_pkcs15_verify_pin(p15card, pin_obj, use_pinpad || pinsize == 0 ? NULL : pinbuf, use_pinpad ? 0 : pinsize);
LOG_TEST_RET(ctx, r, "Cannot validate pkcs15 PIN");
}
--
2.43.0

View File

@ -0,0 +1,446 @@
From 700b6e767391fdec3e9ed3865780f6bf7828ac85 Mon Sep 17 00:00:00 2001
From: Sergio Arroutbi <sarroutb@redhat.com>
Date: Fri, 19 Apr 2024 16:02:13 +0200
Subject: [PATCH 1/2] Include uri in pkcs11-tool -L option
Fixes: #3123
Signed-off-by: Sergio Arroutbi <sarroutb@redhat.com>
---
src/tools/pkcs11-tool.c | 66 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 66 insertions(+)
diff --git a/src/tools/pkcs11-tool.c b/src/tools/pkcs11-tool.c
index 5b2abf590c..c165945872 100644
--- a/src/tools/pkcs11-tool.c
+++ b/src/tools/pkcs11-tool.c
@@ -621,6 +621,7 @@ static void generate_random(CK_SESSION_HANDLE session);
static CK_RV find_object_with_attributes(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE *out,
CK_ATTRIBUTE *attrs, CK_ULONG attrsLen, CK_ULONG obj_index);
static CK_ULONG get_private_key_length(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE prkey);
+static const char *percent_encode(CK_UTF8CHAR *, size_t);
/* win32 needs this in open(2) */
#ifndef O_BINARY
@@ -1681,6 +1682,15 @@ static void show_token(CK_SLOT_ID slot)
printf(" serial num : %s\n", p11_utf8_to_local(info.serialNumber,
sizeof(info.serialNumber)));
printf(" pin min/max : %lu/%lu\n", info.ulMinPinLen, info.ulMaxPinLen);
+ printf(" uri : pkcs11:model=");
+ printf("%s", percent_encode(info.model, sizeof(info.model)));
+ printf(";manufacturer=");
+ printf("%s", percent_encode(info.manufacturerID, sizeof(info.manufacturerID)));
+ printf(";serial=");
+ printf("%s", percent_encode(info.serialNumber, sizeof(info.serialNumber)));
+ printf(";token=");
+ printf("%s", percent_encode(info.label, sizeof(info.label)));
+ printf("\n");
}
static void list_mechs(CK_SLOT_ID slot)
@@ -8293,6 +8303,62 @@ static const char *p11_utf8_to_local(CK_UTF8CHAR *string, size_t len)
return buffer;
}
+static CK_BBOOL
+p11_is_percent_format_reserved_char(CK_UTF8CHAR c)
+{
+ switch (c) {
+ case ' ':
+ case '!':
+ case '"':
+ case '#':
+ case '$':
+ case '%':
+ case '&':
+ case '\'':
+ case '(':
+ case ')':
+ case '*':
+ case '+':
+ case ',':
+ case '/':
+ case ':':
+ case ';':
+ case '=':
+ case '?':
+ case '@':
+ case '[':
+ case ']':
+ return CK_TRUE;
+ }
+ return CK_FALSE;
+}
+
+static const char *
+percent_encode(CK_UTF8CHAR *string, size_t len)
+{
+ static char buffer[1024];
+ size_t output_index, input_index;
+
+ while (len && string[len - 1] == ' ')
+ len--;
+
+ for (output_index = input_index = 0; output_index < sizeof(buffer) - 3;
+ output_index++) {
+ if (input_index >= len) {
+ break;
+ }
+ if (p11_is_percent_format_reserved_char(string[input_index])) {
+ snprintf(&buffer[output_index], 4, "%%%x", string[input_index]);
+ output_index += 2;
+ } else {
+ buffer[output_index] = string[input_index];
+ }
+ input_index++;
+ }
+ buffer[output_index] = '\0';
+ return buffer;
+}
+
static void p11_fatal(const char *func, CK_RV rv)
{
if (p11)
From d9119d0695ea207dca50d651f78ec5fd0a9023ba Mon Sep 17 00:00:00 2001
From: Sergio Arroutbi <sarroutb@redhat.com>
Date: Thu, 25 Apr 2024 13:42:14 +0200
Subject: [PATCH 2/2] Update src/tools/pkcs11-tool.c
Co-authored-by: Jakub Jelen <jakuje@gmail.com>
---
src/tools/pkcs11-tool.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/tools/pkcs11-tool.c b/src/tools/pkcs11-tool.c
index c165945872..46f8b735e5 100644
--- a/src/tools/pkcs11-tool.c
+++ b/src/tools/pkcs11-tool.c
@@ -1682,8 +1682,8 @@ static void show_token(CK_SLOT_ID slot)
printf(" serial num : %s\n", p11_utf8_to_local(info.serialNumber,
sizeof(info.serialNumber)));
printf(" pin min/max : %lu/%lu\n", info.ulMinPinLen, info.ulMaxPinLen);
- printf(" uri : pkcs11:model=");
- printf("%s", percent_encode(info.model, sizeof(info.model)));
+ printf(" uri : pkcs11:");
+ printf("model=%s", percent_encode(info.model, sizeof(info.model)));
printf(";manufacturer=");
printf("%s", percent_encode(info.manufacturerID, sizeof(info.manufacturerID)));
printf(";serial=");
From 5289269d4a57563bdcd604ec091e6eda0f0547fd Mon Sep 17 00:00:00 2001
From: Sergio Arroutbi <sarroutb@redhat.com>
Date: Tue, 30 Apr 2024 18:30:16 +0200
Subject: [PATCH] Include URIs for PKCS#11 objects
Fixes: #3129
Signed-off-by: Sergio Arroutbi <sarroutb@redhat.com>
---
src/tests/fuzzing/fuzz_pkcs15init.c | 7 +-
src/tools/pkcs11-tool.c | 119 ++++++++++++++++++++++------
tests/test-pkcs11-tool-test.sh | 20 ++++-
3 files changed, 116 insertions(+), 30 deletions(-)
diff --git a/src/tests/fuzzing/fuzz_pkcs15init.c b/src/tests/fuzzing/fuzz_pkcs15init.c
index e44e3aae35..85810ded77 100644
--- a/src/tests/fuzzing/fuzz_pkcs15init.c
+++ b/src/tests/fuzzing/fuzz_pkcs15init.c
@@ -109,7 +109,7 @@ int fuzz_get_reader_data(const uint8_t *from, size_t from_size, const uint8_t **
size_t i = 0;
while(i < from_size - 1 && from[i] != '\0')
i++;
-
+
if (from[i] != '\0')
return 0;
@@ -126,6 +126,7 @@ void do_init_app(struct sc_profile *profile, struct sc_pkcs15_card *p15card, sc_
int so_puk_disabled = 0;
memset(&init_args, 0, sizeof(init_args));
+ memset(&info, 0, sizeof(info));
sc_pkcs15init_get_pin_info(profile, SC_PKCS15INIT_SO_PIN, &info);
if ((info.attrs.pin.flags & SC_PKCS15_PIN_FLAG_UNBLOCK_DISABLED) &&
(info.attrs.pin.flags & SC_PKCS15_PIN_FLAG_SO_PIN))
@@ -150,7 +151,7 @@ void do_store_pin(struct sc_profile *profile, struct sc_pkcs15_card *p15card, sc
struct sc_pkcs15init_pinargs pin_args;
char pin_id[SC_PKCS15_MAX_ID_SIZE] = "1\0";
sc_pkcs15init_set_p15card(profile, p15card);
-
+
memcpy(pin, "1234555678\0", 11); /* Set new pin */
memset(&pin_args, 0, sizeof(pin_args));
@@ -363,6 +364,6 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
if (card)
sc_disconnect_card(card);
sc_release_context(ctx);
-
+
return 0;
}
diff --git a/src/tools/pkcs11-tool.c b/src/tools/pkcs11-tool.c
index 46f8b735e5..4e1668290f 100644
--- a/src/tools/pkcs11-tool.c
+++ b/src/tools/pkcs11-tool.c
@@ -1648,6 +1648,43 @@ static void list_slots(int tokens, int refresh, int print)
}
}
+static const char *
+copy_key_value_to_uri(const char *key, const char *value, CK_BBOOL last)
+{
+ static char URI[1024];
+ static size_t shift = 0;
+ if (key && (shift + strlen(key) < sizeof(URI))) {
+ strcpy(&URI[shift], key);
+ shift += strlen(key);
+ }
+ if (value && (shift + strlen(value) < sizeof(URI))) {
+ strcpy(&URI[shift], value);
+ shift += strlen(value);
+ }
+ if (key && value && !last && shift < sizeof(URI)) {
+ URI[shift++] = ';';
+ }
+ if (last && shift < sizeof(URI)) {
+ URI[shift] = '\0';
+ shift = 0;
+ }
+ return URI;
+}
+
+static const char *
+get_uri(CK_TOKEN_INFO_PTR info)
+{
+ copy_key_value_to_uri("pkcs11:", NULL, CK_FALSE);
+ const char *model = percent_encode(info->model, sizeof(info->model));
+ copy_key_value_to_uri("model=", model, CK_FALSE);
+ const char *manufacturer = percent_encode(info->manufacturerID, sizeof(info->manufacturerID));
+ copy_key_value_to_uri("manufacturer=", manufacturer, CK_FALSE);
+ const char *serial = percent_encode(info->serialNumber, sizeof(info->serialNumber));
+ copy_key_value_to_uri("serial=", serial, CK_FALSE);
+ const char *token = percent_encode(info->label, sizeof(info->label));
+ return copy_key_value_to_uri("token=", token, CK_TRUE);
+}
+
static void show_token(CK_SLOT_ID slot)
{
CK_TOKEN_INFO info;
@@ -1682,14 +1719,7 @@ static void show_token(CK_SLOT_ID slot)
printf(" serial num : %s\n", p11_utf8_to_local(info.serialNumber,
sizeof(info.serialNumber)));
printf(" pin min/max : %lu/%lu\n", info.ulMinPinLen, info.ulMaxPinLen);
- printf(" uri : pkcs11:");
- printf("model=%s", percent_encode(info.model, sizeof(info.model)));
- printf(";manufacturer=");
- printf("%s", percent_encode(info.manufacturerID, sizeof(info.manufacturerID)));
- printf(";serial=");
- printf("%s", percent_encode(info.serialNumber, sizeof(info.serialNumber)));
- printf(";token=");
- printf("%s", percent_encode(info.label, sizeof(info.label)));
+ printf(" uri : %s", get_uri(&info));
printf("\n");
}
@@ -5045,13 +5075,14 @@ show_key(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj)
{
CK_MECHANISM_TYPE_PTR mechs = NULL;
CK_KEY_TYPE key_type = getKEY_TYPE(sess, obj);
- CK_ULONG size = 0;
+ CK_ULONG size, idsize = 0;
unsigned char *id, *oid, *value;
const char *sepa;
char *label;
char *unique_id;
int pub = 1;
int sec = 0;
+ CK_TOKEN_INFO info;
switch(getCLASS(sess, obj)) {
case CKO_PRIVATE_KEY:
@@ -5243,17 +5274,15 @@ show_key(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj)
if ((label = getLABEL(sess, obj, NULL)) != NULL) {
printf(" label: %s\n", label);
- free(label);
}
- if ((id = getID(sess, obj, &size)) != NULL && size) {
+ if ((id = getID(sess, obj, &idsize)) != NULL && idsize) {
unsigned int n;
printf(" ID: ");
- for (n = 0; n < size; n++)
+ for (n = 0; n < idsize; n++)
printf("%02x", id[n]);
printf("\n");
- free(id);
}
printf(" Usage: ");
@@ -5355,7 +5384,26 @@ show_key(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj)
printf(" Unique ID: %s\n", unique_id);
free(unique_id);
}
-
+ get_token_info(opt_slot, &info);
+ printf(" uri: %s", get_uri(&info));
+ if (id != NULL && idsize) {
+ printf(";id=%%");
+ for (unsigned int n = 0; n < idsize; n++)
+ printf("%02x", id[n]);
+ free(id);
+ }
+ if (label != NULL) {
+ const char *pelabel = percent_encode((unsigned char *)label, strlen(label));
+ printf(";object=%s", pelabel);
+ free(label);
+ }
+ if (sec) {
+ printf(";type=secret-key\n");
+ } else if (pub) {
+ printf(";type=public\n");
+ } else {
+ printf(";type=private\n");
+ }
suppress_warn = 0;
}
@@ -5363,6 +5411,7 @@ static void show_cert(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj)
{
CK_CERTIFICATE_TYPE cert_type = getCERTIFICATE_TYPE(sess, obj);
CK_ULONG size;
+ CK_TOKEN_INFO info;
unsigned char *id;
char *label;
char *unique_id;
@@ -5389,7 +5438,6 @@ static void show_cert(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj)
if ((label = getLABEL(sess, obj, NULL)) != NULL) {
printf(" label: %s\n", label);
- free(label);
}
#if defined(ENABLE_OPENSSL)
@@ -5433,37 +5481,49 @@ static void show_cert(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj)
for (n = 0; n < size; n++)
printf("%02x", id[n]);
printf("\n");
- free(id);
}
if ((unique_id = getUNIQUE_ID(sess, obj, NULL)) != NULL) {
printf(" Unique ID: %s\n", unique_id);
free(unique_id);
}
+ get_token_info(opt_slot, &info);
+ printf(" uri: %s", get_uri(&info));
+ if (id != NULL && size) {
+ printf(";id=%%");
+ for (unsigned int n = 0; n < size; n++)
+ printf("%02x", id[n]);
+ free(id);
+ }
+ if (label != NULL) {
+ const char *pelabel = percent_encode((unsigned char *)label, strlen(label));
+ printf(";object=%s", pelabel);
+ free(label);
+ }
+ printf(";type=cert\n");
}
static void show_dobj(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj)
{
unsigned char *oid_buf;
char *label;
+ char *application;
CK_ULONG size = 0;
+ CK_TOKEN_INFO info;
suppress_warn = 1;
printf("Data object %u\n", (unsigned int) obj);
printf(" label: ");
if ((label = getLABEL(sess, obj, NULL)) != NULL) {
printf("'%s'\n", label);
- free(label);
- }
- else {
+ } else {
printf("<empty>\n");
}
printf(" application: ");
- if ((label = getAPPLICATION(sess, obj, NULL)) != NULL) {
- printf("'%s'\n", label);
- free(label);
- }
- else {
+ if ((application = getAPPLICATION(sess, obj, NULL)) != NULL) {
+ printf("'%s'\n", application);
+ free(application);
+ } else {
printf("<empty>\n");
}
@@ -5494,8 +5554,16 @@ static void show_dobj(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj)
printf(" private");
if (!getMODIFIABLE(sess, obj) && !getPRIVATE(sess, obj))
printf("<empty>");
+ printf("\n");
- printf ("\n");
+ get_token_info(opt_slot, &info);
+ printf(" uri: %s", get_uri(&info));
+ if (label != NULL) {
+ const char *pelabel = percent_encode((unsigned char *)label, strlen(label));
+ printf(";object=%s", pelabel);
+ free(label);
+ }
+ printf(";type=data\n");
suppress_warn = 0;
}
@@ -8337,6 +8405,7 @@ static const char *
percent_encode(CK_UTF8CHAR *string, size_t len)
{
static char buffer[1024];
+ memset(buffer, 0, 1024);
size_t output_index, input_index;
while (len && string[len - 1] == ' ')
diff --git a/tests/test-pkcs11-tool-test.sh b/tests/test-pkcs11-tool-test.sh
index 2a1f43b8bc..1a96cbd754 100755
--- a/tests/test-pkcs11-tool-test.sh
+++ b/tests/test-pkcs11-tool-test.sh
@@ -20,12 +20,28 @@ assert $? "Failed to set up card"
echo "======================================================="
echo "Test"
echo "======================================================="
-$PKCS11_TOOL --test -p $PIN --module $P11LIB
+$PKCS11_TOOL --test -p "${PIN}" --module "${P11LIB}"
assert $? "Failed running tests"
+echo "======================================================="
+echo "Test objects URI"
+echo "======================================================="
+$PKCS11_TOOL -O 2>/dev/null | grep 'uri:' 2>/dev/null >/dev/null
+assert $? "Failed running objects URI tests"
+$PKCS11_TOOL -O 2>/dev/null | grep 'uri:' | awk -F 'uri:' '{print $2}' | tr -d ' ' | grep ^"pkcs11:" 2>/dev/null >/dev/null
+assert $? "Failed running objects URI tests"
+
+echo "======================================================="
+echo "Test slots URI"
+echo "======================================================="
+$PKCS11_TOOL -L 2>/dev/null | grep 'uri' 2>/dev/null >/dev/null
+assert $? "Failed running slots URI tests"
+$PKCS11_TOOL -O 2>/dev/null | grep 'uri' | awk -F 'uri*:' '{print $2}' | tr -d ' ' | grep ^"pkcs11:" 2>/dev/null >/dev/null
+assert $? "Failed running slots URI tests"
+
echo "======================================================="
echo "Cleanup"
echo "======================================================="
card_cleanup
-exit $ERRORS
+exit "${ERRORS}"

File diff suppressed because it is too large Load Diff

View File

@ -3,7 +3,7 @@
Name: opensc
Version: 0.23.0
Release: 2%{?dist}
Release: 5%{?dist}
Summary: Smart card library and applications
License: LGPLv2+
@ -23,6 +23,42 @@ Patch10: %{name}-0.23.0-openssl-ctx.patch
Patch11: %{name}-0.23.0-openpgp.patch
# https://github.com/OpenSC/OpenSC/commit/81944d1529202bd28359bede57c0a15deb65ba8a
Patch12: %{name}-0.23.0-cardos-pkcs15init.patch
# https://github.com/OpenSC/OpenSC/commit/bff98ff078a99e6864ba1a598fd7dc9af4a9476b
# https://github.com/OpenSC/OpenSC/commit/0875c69295ef28b45fb682b37cede58fc36b7a1a
Patch13: %{name}-0.23.0-cache-offsets.patch
# https://github.com/OpenSC/OpenSC/commit/868f76fb31255fd3fdacfc3e476452efeb61c3e7
# https://github.com/OpenSC/OpenSC/commit/80cc5d30635f0d2c92b5099c0f9dc680d0ffce2f
Patch14: %{name}-0.23.0-pin-bypass.patch
# https://github.com/OpenSC/OpenSC/commit/245efe608d083fd4e4ec96793fdefd218e26fde7
# https://github.com/OpenSC/OpenSC/commit/440ca666eff10cc7011901252d20f3fc4ea23651
# https://github.com/OpenSC/OpenSC/commit/41d61da8481582e12710b5858f8b635e0a71ab5e
# https://github.com/OpenSC/OpenSC/commit/88880db0307a07e33cf2e1592bb029e9c170dfea
# https://github.com/OpenSC/OpenSC/commit/638a5007a5d240d6fa901aa822cfeef94fe36e85
# https://github.com/OpenSC/OpenSC/commit/c449a181a6988cc1e8dc8764d23574e48cdc3fa6
# https://github.com/OpenSC/OpenSC/commit/5631e9843c832a99769def85b7b9b68b4e3e3959
# https://github.com/OpenSC/OpenSC/commit/e7f81d86dcdc751f4737f4b29a99bfc54d29c5c9
# https://github.com/OpenSC/OpenSC/commit/df5a176bfdf8c52ba89c7fef1f82f6f3b9312bc1
# https://github.com/OpenSC/OpenSC/commit/578aed8391ef117ca64a9e0cba8e5c264368a0ec
# https://github.com/OpenSC/OpenSC/commit/4013a807492568bf9907cfb3df41f130ac83c7b9
# https://github.com/OpenSC/OpenSC/commit/09164045facaeae193feb48d9c2fc5cc4321e8a
# https://github.com/OpenSC/OpenSC/commit/fc2c20c3f895569eeb58328bb882aec07325d3b
# https://github.com/OpenSC/OpenSC/commit/3b9129bd3cfc6ac57d5554e015c3df85f5076dc
# https://github.com/OpenSC/OpenSC/commit/bda61d0d276dc98b9d1d1e6810bbd21d19e3859
# https://github.com/OpenSC/OpenSC/commit/a4921ab23fd0853f327517636c50de947548161
# https://github.com/OpenSC/OpenSC/commit/085994384a7171c5c68f6718d9db10ed77c5af1
# https://github.com/OpenSC/OpenSC/commit/0f0985f6343eeac4044661d56807ee9286db42c
# https://github.com/OpenSC/OpenSC/commit/5f6370a35f151497838628f78111087eb8e7ff1
# https://github.com/OpenSC/OpenSC/commit/fbff25ec6c6d0ad3f8df76f57210698f7947fc3
Patch15: %{name}-0.23.0-pkcs15init.patch
# https://github.com/OpenSC/OpenSC/commit/cde2e050ec4f2f1b7db38429aa4e9c0f4656308c
# https://github.com/OpenSC/OpenSC/commit/f1993dc4e0b33050b8f72a3558ee88b24c4063b2
Patch16: %{name}-0.23.0-myeid-sym.patch
# https://github.com/OpenSC/OpenSC/pull/2948
# https://github.com/OpenSC/OpenSC/pull/3016
Patch17: %{name}-0.23.0-constant-time-pkcs1.5.patch
# https://github.com/OpenSC/OpenSC/pull/3125
# https://github.com/OpenSC/OpenSC/pull/3130
Patch18: %{name}-0.23.0-pkcs11-uri.patch
BuildRequires: make
BuildRequires: pcsc-lite-devel
@ -66,6 +102,12 @@ every software/card that does so, too.
%patch10 -p1 -b .ossl3context
%patch11 -p1 -b .openpgp
%patch12 -p1 -b .cardos-pkcs15init
%patch13 -p1 -b .cache-offsets
%patch14 -p1 -b .pin-bypass
%patch15 -p1 -b .pkcs15init
%patch16 -p1 -b .myeid-sym
%patch17 -p1 -b .constant-time-pkcs1
%patch18 -p1 -b .pkcs11-uri
cp -p src/pkcs15init/README ./README.pkcs15init
cp -p src/scconf/README.scconf .
@ -207,6 +249,19 @@ rm %{buildroot}%{_mandir}/man1/opensc-notify.1*
%changelog
* Thu Oct 24 2024 Veronika Hanulikova <vhanulik@redhat.com> - 0.23.0-5
- Add URI in PKCS#11 objects and pkcs11-tool (RHEL-53115)
* Thu Feb 08 2024 Veronika Hanulikova <vhanulik@redhat.com> - 0.23.0-4
- Fix CVE-2023-5992: Side-channel leaks while stripping encryption PKCS#1.5 padding
* Thu Nov 30 2023 Jakub Jelen <jjelen@redhat.com> - 0.23.0-3
- Fix file caching with different offsets (RHEL-4079)
- Fix CVE-2023-40660: Potential PIN bypass
- Fix CVE-2023-40661: Dynamic analyzers reports in pkcs15init
- Fix CVE-2023-4535: Out-of-bounds read in MyEID driver handling encryption using symmetric keys
- Fix CVE-2023-5992: Side-channel leaks while stripping encryption PKCS#1.5 padding
* Thu May 25 2023 Jakub Jelen <jjelen@redhat.com> - 0.23.0-2
- Fix regression in handling OpenPGP cards
- Fix CVE-2023-2977: buffer overrun in pkcs15init for cardos