diff --git a/opensc-0.19.0-redundant_logging.patch b/opensc-0.19.0-redundant_logging.patch new file mode 100644 index 0000000..45b025b --- /dev/null +++ b/opensc-0.19.0-redundant_logging.patch @@ -0,0 +1,12 @@ +Index: opensc-0.19.0/src/pkcs15init/pkcs15-oberthur.c +=================================================================== +--- opensc-0.19.0.orig/src/pkcs15init/pkcs15-oberthur.c ++++ opensc-0.19.0/src/pkcs15init/pkcs15-oberthur.c +@@ -70,7 +70,6 @@ cosm_write_tokeninfo (struct sc_pkcs15_c + ctx = p15card->card->ctx; + + SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE); +- sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "cosm_write_tokeninfo() label '%s'; flags 0x%X", label, flags); + if (sc_profile_get_file(profile, COSM_TITLE"-token-info", &file)) { + rv = SC_ERROR_INCONSISTENT_PROFILE; + SC_TEST_GOTO_ERR(ctx, SC_LOG_DEBUG_NORMAL, rv, "Cannot find "COSM_TITLE"-token-info"); diff --git a/opensc-0.19.0-rsa-pss.patch b/opensc-0.19.0-rsa-pss.patch new file mode 100644 index 0000000..37c7661 --- /dev/null +++ b/opensc-0.19.0-rsa-pss.patch @@ -0,0 +1,2257 @@ +From b85c0706db871828f0bc4672571dd0b9c98dd835 Mon Sep 17 00:00:00 2001 +From: Jakub Jelen +Date: Sun, 22 Jul 2018 16:23:54 +0200 +Subject: [PATCH 1/5] doc: Fix the pkcs11-tool example + +Signed-off-by: Jakub Jelen +--- + doc/tools/pkcs11-tool.1.xml | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/doc/tools/pkcs11-tool.1.xml b/doc/tools/pkcs11-tool.1.xml +index 37093f352..c609ec0e2 100644 +--- a/doc/tools/pkcs11-tool.1.xml ++++ b/doc/tools/pkcs11-tool.1.xml +@@ -568,7 +568,7 @@ + + To read the certificate with ID KEY_ID + in DER format from smart card: +- pkcs11-tool --read-object --id KEY_ID --type cert --outfile cert.der ++ pkcs11-tool --read-object --id KEY_ID --type cert --output-file cert.der + + To convert the certificate in DER format to PEM format, use OpenSSL + tools: + +From 5cc144111acb7b9982ddec7f7597a22c10c4d456 Mon Sep 17 00:00:00 2001 +From: Jakub Jelen +Date: Fri, 14 Sep 2018 14:11:18 +0200 +Subject: [PATCH 2/5] p11test: Add missing CKM_SHA224_RSA_PKCS_PSS + +Signed-off-by: Jakub Jelen +--- + src/tests/p11test/p11test_case_common.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/src/tests/p11test/p11test_case_common.c b/src/tests/p11test/p11test_case_common.c +index deb2a56fe..d44b0d8e3 100644 +--- a/src/tests/p11test/p11test_case_common.c ++++ b/src/tests/p11test/p11test_case_common.c +@@ -587,6 +587,8 @@ const char *get_mechanism_name(int mech_id) + return "RSA_PKCS_PSS"; + case CKM_SHA1_RSA_PKCS_PSS: + return "SHA1_RSA_PKCS_PSS"; ++ case CKM_SHA224_RSA_PKCS_PSS: ++ return "SHA224_RSA_PKCS_PSS"; + case CKM_SHA256_RSA_PKCS_PSS: + return "SHA256_RSA_PKCS_PSS"; + case CKM_SHA384_RSA_PKCS_PSS: + +From 5aa3dbcdd76af0197946252ff53a0636cb979ab3 Mon Sep 17 00:00:00 2001 +From: Nicholas Wilson +Date: Tue, 25 Aug 2015 12:45:27 +0100 +Subject: [PATCH 3/5] Add support for PSS padding to RSA signatures + +A card driver may declare support for computing the padding on the card, +or else the padding will be applied locally in padding.c. All five +PKCS11 PSS mechanisms are supported, for signature and verification. + +There are a few limits on what we choose to support, in particular I +don't see a need for arbitrary combinations of MGF hash, data hash, and +salt length, so I've restricted it (for the user's benefit) to the only +cases that really matter, where salt_len = hash_len and the same hash is +used for the MGF and data hashing. + +------------------------------------------------------------------------ +Reworked and extended in 2018 by Jakub Jelen against +current OpenSC master, to actually work with existing PIV cards: + * extended of missing mechanisms (SHA224, possibility to select MGF1) + * compatibility with OpenSSL 1.1+ + * Removed the ANSI padding + * Formatting cleanup, error checking + +Based on the original work from + +https://github.com/NWilson/OpenSC/commit/42f3199e66 + +Signed-off-by: Jakub Jelen +--- + src/libopensc/card-atrust-acos.c | 2 +- + src/libopensc/card-starcos.c | 4 +- + src/libopensc/internal.h | 2 +- + src/libopensc/opensc.h | 74 +++++++-- + src/libopensc/padding.c | 257 ++++++++++++++++++++++++++---- + src/libopensc/pkcs15-sec.c | 33 ++-- + src/pkcs11/framework-pkcs15.c | 265 +++++++++++++++++++++++-------- + src/pkcs11/mechanism.c | 31 +++- + src/pkcs11/openssl.c | 151 ++++++++++++++++-- + src/pkcs11/pkcs11.h | 3 +- + src/pkcs11/sc-pkcs11.h | 9 +- + 11 files changed, 674 insertions(+), 157 deletions(-) + +diff --git a/src/libopensc/card-atrust-acos.c b/src/libopensc/card-atrust-acos.c +index fb0b296c8..05ef0f441 100644 +--- a/src/libopensc/card-atrust-acos.c ++++ b/src/libopensc/card-atrust-acos.c +@@ -722,7 +722,7 @@ static int atrust_acos_compute_signature(struct sc_card *card, + flags = SC_ALGORITHM_RSA_HASH_NONE; + tmp_len = sizeof(sbuf); + r = sc_pkcs1_encode(card->ctx, flags, data, datalen, +- sbuf, &tmp_len, sizeof(sbuf)); ++ sbuf, &tmp_len, sizeof(sbuf)*8); + if (r < 0) + return r; + } else { +diff --git a/src/libopensc/card-starcos.c b/src/libopensc/card-starcos.c +index 7ad132dc1..799c6a680 100644 +--- a/src/libopensc/card-starcos.c ++++ b/src/libopensc/card-starcos.c +@@ -1545,7 +1545,7 @@ static int starcos_compute_signature(sc_card_t *card, + flags = SC_ALGORITHM_RSA_HASH_NONE; + } + tmp_len = sizeof(sbuf); +- r = sc_pkcs1_encode(card->ctx, flags, data, datalen, sbuf, &tmp_len, sizeof(sbuf)); ++ r = sc_pkcs1_encode(card->ctx, flags, data, datalen, sbuf, &tmp_len, sizeof(sbuf)*8); + SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "sc_pkcs1_encode failed"); + } else { + memcpy(sbuf, data, datalen); +@@ -1607,7 +1607,7 @@ static int starcos_compute_signature(sc_card_t *card, + flags = SC_ALGORITHM_RSA_HASH_NONE; + tmp_len = sizeof(sbuf); + r = sc_pkcs1_encode(card->ctx, flags, data, datalen, +- sbuf, &tmp_len, sizeof(sbuf)); ++ sbuf, &tmp_len, sizeof(sbuf)*8); + if (r < 0) + return r; + } else { +diff --git a/src/libopensc/internal.h b/src/libopensc/internal.h +index 9d6a77ffe..08d590f23 100644 +--- a/src/libopensc/internal.h ++++ b/src/libopensc/internal.h +@@ -159,7 +159,7 @@ int sc_pkcs1_strip_digest_info_prefix(unsigned int *algorithm, + * @return SC_SUCCESS on success and an error code otherwise + */ + int sc_pkcs1_encode(sc_context_t *ctx, unsigned long flags, +- const u8 *in, size_t inlen, u8 *out, size_t *outlen, size_t modlen); ++ const u8 *in, size_t inlen, u8 *out, size_t *outlen, size_t mod_bits); + /** + * Get the necessary padding and sec. env. flags. + * @param ctx IN sc_contex_t object +diff --git a/src/libopensc/opensc.h b/src/libopensc/opensc.h +index b9b960d8f..a4e87d5bf 100644 +--- a/src/libopensc/opensc.h ++++ b/src/libopensc/opensc.h +@@ -93,19 +93,39 @@ extern "C" { + #define SC_ALGORITHM_NEED_USAGE 0x40000000 + #define SC_ALGORITHM_SPECIFIC_FLAGS 0x001FFFFF + +-#define SC_ALGORITHM_RSA_RAW 0x00000001 + /* If the card is willing to produce a cryptogram padded with the following +- * methods, set these flags accordingly. */ +-#define SC_ALGORITHM_RSA_PADS 0x0000001E +-#define SC_ALGORITHM_RSA_PAD_NONE 0x00000000 +-#define SC_ALGORITHM_RSA_PAD_PKCS1 0x00000002 ++ * methods, set these flags accordingly. These flags are exclusive: an RSA card ++ * must support at least one of them, and exactly one of them must be selected ++ * for a given operation. */ ++#define SC_ALGORITHM_RSA_RAW 0x00000001 ++#define SC_ALGORITHM_RSA_PADS 0x0000001F ++#define SC_ALGORITHM_RSA_PAD_NONE 0x00000001 ++#define SC_ALGORITHM_RSA_PAD_PKCS1 0x00000002 /* PKCS#1 v1.5 padding */ + #define SC_ALGORITHM_RSA_PAD_ANSI 0x00000004 + #define SC_ALGORITHM_RSA_PAD_ISO9796 0x00000008 +-#define SC_ALGORITHM_RSA_PAD_PSS 0x00000010 ++#define SC_ALGORITHM_RSA_PAD_PSS 0x00000010 /* PKCS#1 v2.0 PSS */ + + /* If the card is willing to produce a cryptogram with the following +- * hash values, set these flags accordingly. */ +-#define SC_ALGORITHM_RSA_HASH_NONE 0x00000100 ++ * hash values, set these flags accordingly. The interpretation of the hash ++ * flags depends on the algorithm and padding chosen: for RSA, the hash flags ++ * determine how the padding is constructed and do not describe the first ++ * hash applied to the document before padding begins. ++ * ++ * - For PAD_NONE, ANSI X9.31, (and ISO9796?), the hash value is therefore ++ * ignored. For ANSI X9.31, the input data must already have the hash ++ * identifier byte appended (eg 0x33 for SHA-1). ++ * - For PKCS1 (v1.5) the hash is recorded in the padding, and HASH_NONE is a ++ * valid value, meaning that the hash's DigestInfo has already been ++ * prepended to the data, otherwise the hash id is put on the front. ++ * - For PSS (PKCS#1 v2.0) the hash is used to derive the padding from the ++ * already-hashed message. ++ * ++ * In no case is the hash actually applied to the entire document. ++ * ++ * It's possible that the card may support different hashes for PKCS1 and PSS ++ * signatures; in this case the card driver has to pick the lowest-denominator ++ * when it sets these flags to indicate its capabilities. */ ++#define SC_ALGORITHM_RSA_HASH_NONE 0x00000100 /* only applies to PKCS1 padding */ + #define SC_ALGORITHM_RSA_HASH_SHA1 0x00000200 + #define SC_ALGORITHM_RSA_HASH_MD5 0x00000400 + #define SC_ALGORITHM_RSA_HASH_MD5_SHA1 0x00000800 +@@ -114,21 +134,39 @@ extern "C" { + #define SC_ALGORITHM_RSA_HASH_SHA384 0x00004000 + #define SC_ALGORITHM_RSA_HASH_SHA512 0x00008000 + #define SC_ALGORITHM_RSA_HASH_SHA224 0x00010000 +-#define SC_ALGORITHM_RSA_HASHES 0x0001FE00 +- ++#define SC_ALGORITHM_RSA_HASHES 0x0001FF00 ++ ++/* This defines the hashes to be used with MGF1 in PSS padding */ ++#define SC_ALGORITHM_MGF1_SHA1 0x00100000 ++#define SC_ALGORITHM_MGF1_SHA256 0x00200000 ++#define SC_ALGORITHM_MGF1_SHA384 0x00400000 ++#define SC_ALGORITHM_MGF1_SHA512 0x00800000 ++#define SC_ALGORITHM_MGF1_SHA224 0x01000000 ++#define SC_ALGORITHM_MGF1_HASHES 0x01F00000 ++ ++/* These flags are exclusive: a GOST R34.10 card must support at least one or the ++ * other of the methods, and exactly one of them applies to any given operation. ++ * Note that the GOST R34.11 hash is actually applied to the data (ie if this ++ * algorithm is chosen the entire unhashed document is passed in). */ + #define SC_ALGORITHM_GOSTR3410_RAW 0x00020000 +-#define SC_ALGORITHM_GOSTR3410_HASH_NONE 0x00040000 ++#define SC_ALGORITHM_GOSTR3410_HASH_NONE SC_ALGORITHM_GOSTR3410_RAW /*XXX*/ + #define SC_ALGORITHM_GOSTR3410_HASH_GOSTR3411 0x00080000 +-#define SC_ALGORITHM_GOSTR3410_HASHES 0x00080000 +-/*TODO: -DEE Should the above be 0x0000E000 */ +-/* Or should the HASH_NONE be 0x00000010 and HASHES be 0x00008010 */ +- ++#define SC_ALGORITHM_GOSTR3410_HASHES 0x000A0000 ++/*TODO: -DEE Should the above be 0x000E0000 */ ++/* Or should the HASH_NONE be 0x00000100 and HASHES be 0x00080010 */ ++ ++/* The ECDSA flags are exclusive, and exactly one of them applies to any given ++ * operation. If ECDSA with a hash is specified, then the data passed in is ++ * the entire document, unhashed, and the hash is applied once to it before ++ * truncating and signing. These flags are distinct from the RSA hash flags, ++ * which determine the hash ids the card is willing to put in RSA message ++ * padding. */ + /* May need more bits if card can do more hashes */ + /* TODO: -DEE Will overload RSA_HASHES with EC_HASHES */ + /* Not clear if these need their own bits or not */ + /* The PIV card does not support and hashes */ +-#define SC_ALGORITHM_ECDSA_RAW 0x00100000 + #define SC_ALGORITHM_ECDH_CDH_RAW 0x00200000 ++#define SC_ALGORITHM_ECDSA_RAW 0x00100000 + #define SC_ALGORITHM_ECDSA_HASH_NONE SC_ALGORITHM_RSA_HASH_NONE + #define SC_ALGORITHM_ECDSA_HASH_SHA1 SC_ALGORITHM_RSA_HASH_SHA1 + #define SC_ALGORITHM_ECDSA_HASH_SHA224 SC_ALGORITHM_RSA_HASH_SHA224 +@@ -142,7 +180,9 @@ extern "C" { + SC_ALGORITHM_ECDSA_HASH_SHA512) + + /* define mask of all algorithms that can do raw */ +-#define SC_ALGORITHM_RAW_MASK (SC_ALGORITHM_RSA_RAW | SC_ALGORITHM_GOSTR3410_RAW | SC_ALGORITHM_ECDSA_RAW) ++#define SC_ALGORITHM_RAW_MASK (SC_ALGORITHM_RSA_RAW | \ ++ SC_ALGORITHM_GOSTR3410_RAW | \ ++ SC_ALGORITHM_ECDSA_RAW) + + /* extended algorithm bits for selected mechs */ + #define SC_ALGORITHM_EXT_EC_F_P 0x00000001 +diff --git a/src/libopensc/padding.c b/src/libopensc/padding.c +index f544e5778..53a87c352 100644 +--- a/src/libopensc/padding.c ++++ b/src/libopensc/padding.c +@@ -23,6 +23,12 @@ + #include "config.h" + #endif + ++#ifdef ENABLE_OPENSSL ++#include ++#include ++#include ++#endif ++ + #include + #include + +@@ -231,22 +237,183 @@ int sc_pkcs1_strip_digest_info_prefix(unsigned int *algorithm, + return SC_ERROR_INTERNAL; + } + ++#ifdef ENABLE_OPENSSL ++ ++static const EVP_MD* hash_flag2md(unsigned int hash) ++{ ++ switch (hash & SC_ALGORITHM_RSA_HASHES) { ++ case SC_ALGORITHM_RSA_HASH_SHA1: ++ return EVP_sha1(); ++ case SC_ALGORITHM_RSA_HASH_SHA224: ++ return EVP_sha224(); ++ case SC_ALGORITHM_RSA_HASH_SHA256: ++ return EVP_sha256(); ++ case SC_ALGORITHM_RSA_HASH_SHA384: ++ return EVP_sha384(); ++ case SC_ALGORITHM_RSA_HASH_SHA512: ++ return EVP_sha512(); ++ default: ++ return NULL; ++ } ++} ++ ++static const EVP_MD* mgf1_flag2md(unsigned int mgf1) ++{ ++ switch (mgf1 & SC_ALGORITHM_MGF1_HASHES) { ++ case SC_ALGORITHM_MGF1_SHA1: ++ return EVP_sha1(); ++ case SC_ALGORITHM_MGF1_SHA224: ++ return EVP_sha224(); ++ case SC_ALGORITHM_MGF1_SHA256: ++ return EVP_sha256(); ++ case SC_ALGORITHM_MGF1_SHA384: ++ return EVP_sha384(); ++ case SC_ALGORITHM_MGF1_SHA512: ++ return EVP_sha512(); ++ default: ++ return NULL; ++ } ++} ++ ++/* add PKCS#1 v2.0 PSS padding */ ++static int sc_pkcs1_add_pss_padding(unsigned int hash, unsigned int mgf1_hash, ++ const u8 *in, size_t in_len, u8 *out, size_t *out_len, size_t mod_bits) ++{ ++ /* hLen = sLen in our case */ ++ int rv = SC_ERROR_INTERNAL, i, j, hlen, dblen, plen, round, mgf_rounds; ++ int mgf1_hlen; ++ const EVP_MD* md, *mgf1_md; ++ EVP_MD_CTX* ctx = NULL; ++ u8 buf[8]; ++ u8 salt[EVP_MAX_MD_SIZE], mask[EVP_MAX_MD_SIZE]; ++ size_t mod_length = (mod_bits + 7) / 8; ++ ++ if (*out_len < mod_length) ++ return SC_ERROR_BUFFER_TOO_SMALL; ++ ++ md = hash_flag2md(hash); ++ if (md == NULL) ++ return SC_ERROR_NOT_SUPPORTED; ++ hlen = EVP_MD_size(md); ++ dblen = mod_length - hlen - 1; /* emLen - hLen - 1 */ ++ plen = mod_length - 2*hlen - 1; ++ if (in_len != (unsigned)hlen) ++ return SC_ERROR_INVALID_ARGUMENTS; ++ if (2 * (unsigned)hlen + 2 > mod_length) ++ /* RSA key too small for chosen hash (1296 bits or higher needed for ++ * signing SHA-512 hashes) */ ++ return SC_ERROR_NOT_SUPPORTED; ++ ++ if (RAND_bytes(salt, hlen) != 1) ++ return SC_ERROR_INTERNAL; ++ ++ /* Hash M' to create H */ ++ if (!(ctx = EVP_MD_CTX_create())) ++ goto done; ++ memset(buf, 0x00, 8); ++ if (EVP_DigestInit_ex(ctx, md, NULL) != 1 || ++ EVP_DigestUpdate(ctx, buf, 8) != 1 || ++ EVP_DigestUpdate(ctx, in, hlen) != 1 || /* mHash */ ++ EVP_DigestUpdate(ctx, salt, hlen) != 1) { ++ goto done; ++ } ++ ++ /* Construct padding2, salt, H, and BC in the output block */ ++ /* DB = PS || 0x01 || salt */ ++ memset(out, 0x00, plen - 1); /* emLen - sLen - hLen - 2 */ ++ out[plen - 1] = 0x01; ++ memcpy(out + plen, salt, hlen); ++ if (EVP_DigestFinal_ex(ctx, out + dblen, NULL) != 1) { /* H */ ++ goto done; ++ } ++ out[dblen + hlen] = 0xBC; ++ /* EM = DB* || H || 0xbc ++ * *the first part is masked later */ ++ ++ /* Construct the DB mask block by block and XOR it in. */ ++ mgf1_md = mgf1_flag2md(mgf1_hash); ++ if (mgf1_md == NULL) ++ return SC_ERROR_NOT_SUPPORTED; ++ mgf1_hlen = EVP_MD_size(mgf1_md); ++ ++ mgf_rounds = (dblen + mgf1_hlen - 1) / mgf1_hlen; /* round up */ ++ for (round = 0; round < mgf_rounds; ++round) { ++ buf[0] = (round&0xFF000000U) >> 24; ++ buf[1] = (round&0x00FF0000U) >> 16; ++ buf[2] = (round&0x0000FF00U) >> 8; ++ buf[3] = (round&0x000000FFU); ++ if (EVP_DigestInit_ex(ctx, mgf1_md, NULL) != 1 || ++ EVP_DigestUpdate(ctx, out + dblen, hlen) != 1 || /* H (Z parameter of MGF1) */ ++ EVP_DigestUpdate(ctx, buf, 4) != 1 || /* C */ ++ EVP_DigestFinal_ex(ctx, mask, NULL)) { ++ goto done; ++ } ++ /* this is no longer part of the MGF1, but actually ++ * XORing mask with DB to create maskedDB inplace */ ++ for (i = round * mgf1_hlen, j = 0; i < dblen && j < mgf1_hlen; ++i, ++j) { ++ out[i] ^= mask[j]; ++ } ++ } ++ ++ /* Set leftmost N bits in leftmost octet in maskedDB to zero ++ * to make sure the result is smaller than the modulus ( +1) ++ */ ++ out[0] &= (0xff >> (8 * mod_length - mod_bits + 1)); ++ ++ *out_len = mod_length; ++ rv = SC_SUCCESS; ++ ++done: ++ OPENSSL_cleanse(salt, sizeof(salt)); ++ OPENSSL_cleanse(mask, sizeof(mask)); ++ if (ctx) { ++ EVP_MD_CTX_destroy(ctx); ++ } ++ return rv; ++} ++ ++static int hash_len2algo(size_t hash_len) ++{ ++ switch (hash_len) { ++ case SHA_DIGEST_LENGTH: ++ return SC_ALGORITHM_RSA_HASH_SHA1; ++ case SHA224_DIGEST_LENGTH: ++ return SC_ALGORITHM_RSA_HASH_SHA224; ++ case SHA256_DIGEST_LENGTH: ++ return SC_ALGORITHM_RSA_HASH_SHA256; ++ case SHA384_DIGEST_LENGTH: ++ return SC_ALGORITHM_RSA_HASH_SHA384; ++ case SHA512_DIGEST_LENGTH: ++ return SC_ALGORITHM_RSA_HASH_SHA512; ++ } ++ /* Should never happen -- the mechanism and data should be already ++ * verified to match one of the above. If not, we will fail later ++ */ ++ return SC_ALGORITHM_RSA_HASH_NONE; ++} ++#endif ++ + /* general PKCS#1 encoding function */ + int sc_pkcs1_encode(sc_context_t *ctx, unsigned long flags, +- const u8 *in, size_t in_len, u8 *out, size_t *out_len, size_t mod_len) ++ const u8 *in, size_t in_len, u8 *out, size_t *out_len, size_t mod_bits) + { + int rv, i; + size_t tmp_len = *out_len; + const u8 *tmp = in; + unsigned int hash_algo, pad_algo; ++ size_t mod_len = (mod_bits + 7) / 8; ++#ifdef ENABLE_OPENSSL ++ unsigned int mgf1_hash; ++#endif + + LOG_FUNC_CALLED(ctx); + +- hash_algo = flags & (SC_ALGORITHM_RSA_HASHES | SC_ALGORITHM_RSA_HASH_NONE); ++ hash_algo = flags & SC_ALGORITHM_RSA_HASHES; + pad_algo = flags & SC_ALGORITHM_RSA_PADS; + sc_log(ctx, "hash algorithm 0x%X, pad algorithm 0x%X", hash_algo, pad_algo); + +- if (hash_algo != SC_ALGORITHM_RSA_HASH_NONE) { ++ if ((pad_algo == SC_ALGORITHM_RSA_PAD_PKCS1 || !pad_algo) && ++ hash_algo != SC_ALGORITHM_RSA_HASH_NONE) { + i = sc_pkcs1_add_digest_info_prefix(hash_algo, in, in_len, out, &tmp_len); + if (i != SC_SUCCESS) { + sc_log(ctx, "Unable to add digest info 0x%x", hash_algo); +@@ -268,10 +435,29 @@ int sc_pkcs1_encode(sc_context_t *ctx, unsigned long flags, + /* add pkcs1 bt01 padding */ + rv = sc_pkcs1_add_01_padding(tmp, tmp_len, out, out_len, mod_len); + LOG_FUNC_RETURN(ctx, rv); ++ case SC_ALGORITHM_RSA_PAD_PSS: ++ /* add PSS padding */ ++#ifdef ENABLE_OPENSSL ++ mgf1_hash = flags & SC_ALGORITHM_MGF1_HASHES; ++ if (hash_algo == SC_ALGORITHM_RSA_HASH_NONE) { ++ /* this is generic RSA_PKCS1_PSS mechanism with hash ++ * already done outside of the module. The parameters ++ * were already checked so we need to adjust the hash ++ * algorithm to do the padding with the correct hash ++ * function. ++ */ ++ hash_algo = hash_len2algo(tmp_len); ++ } ++ rv = sc_pkcs1_add_pss_padding(hash_algo, mgf1_hash, ++ tmp, tmp_len, out, out_len, mod_bits); ++#else ++ rv = SC_ERROR_NOT_SUPPORTED; ++#endif ++ LOG_FUNC_RETURN(ctx, rv); + default: +- /* currently only pkcs1 padding is supported */ +- sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "Unsupported padding algorithm 0x%x", pad_algo); +- LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED); ++ /* We shouldn't be called with an unexpected padding type, we've already ++ * returned SC_ERROR_NOT_SUPPORTED if the card can't be used. */ ++ LOG_FUNC_RETURN(ctx, SC_ERROR_INTERNAL); + } + } + +@@ -279,42 +465,45 @@ int sc_get_encoding_flags(sc_context_t *ctx, + unsigned long iflags, unsigned long caps, + unsigned long *pflags, unsigned long *sflags) + { +- size_t i; +- + LOG_FUNC_CALLED(ctx); + if (pflags == NULL || sflags == NULL) + LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS); + + sc_log(ctx, "iFlags 0x%lX, card capabilities 0x%lX", iflags, caps); +- for (i = 0; digest_info_prefix[i].algorithm != 0; i++) { +- if (iflags & digest_info_prefix[i].algorithm) { +- if (digest_info_prefix[i].algorithm != SC_ALGORITHM_RSA_HASH_NONE && +- caps & digest_info_prefix[i].algorithm) +- *sflags |= digest_info_prefix[i].algorithm; +- else +- *pflags |= digest_info_prefix[i].algorithm; +- break; +- } +- } + +- if (iflags & SC_ALGORITHM_RSA_PAD_PKCS1) { +- if (caps & SC_ALGORITHM_RSA_PAD_PKCS1) +- *sflags |= SC_ALGORITHM_RSA_PAD_PKCS1; +- else +- *pflags |= SC_ALGORITHM_RSA_PAD_PKCS1; +- } else if ((iflags & SC_ALGORITHM_RSA_PADS) == SC_ALGORITHM_RSA_PAD_NONE) { +- +- /* Work with RSA, EC and maybe GOSTR? */ +- if (!(caps & SC_ALGORITHM_RAW_MASK)) +- LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "raw encryption is not supported"); ++ /* For ECDSA and GOSTR, we don't do any padding or hashing ourselves, the ++ * card has to support the requested operation. Similarly, for RSA with ++ * raw padding (raw RSA) and ISO9796, we require the card to do it for us. ++ * Finally, for PKCS1 (v1.5 and PSS) and ASNI X9.31 we can apply the padding ++ * ourselves if the card supports raw RSA. */ + +- *sflags |= (caps & SC_ALGORITHM_RAW_MASK); /* adds in the one raw type */ ++ /* TODO: Could convert GOSTR3410_HASH_GOSTR3411 -> GOSTR3410_RAW and ++ * ECDSA_HASH_ -> ECDSA_RAW using OpenSSL (not much benefit though). */ ++ ++ if ((caps & iflags) == iflags) { ++ /* Card supports the signature operation we want to do, great, let's ++ * go with it then. */ ++ *sflags = iflags; + *pflags = 0; +- } else if (iflags & SC_ALGORITHM_RSA_PAD_PSS) { +- if (caps & SC_ALGORITHM_RSA_PAD_PSS) +- *sflags |= SC_ALGORITHM_RSA_PAD_PSS; +- else +- *pflags |= SC_ALGORITHM_RSA_PAD_PSS; ++ ++ } else if ((caps & SC_ALGORITHM_RSA_PAD_PSS) && ++ (iflags & SC_ALGORITHM_RSA_PAD_PSS)) { ++ *sflags |= SC_ALGORITHM_RSA_PAD_PSS; ++ ++ } else if (((caps & SC_ALGORITHM_RSA_RAW) && ++ (iflags & SC_ALGORITHM_RSA_PAD_PKCS1)) ++ || iflags & SC_ALGORITHM_RSA_PAD_PSS) { ++ /* Use the card's raw RSA capability on the padded input */ ++ *sflags = SC_ALGORITHM_RSA_PAD_NONE; ++ *pflags = iflags; ++ ++ } else if ((caps & (SC_ALGORITHM_RSA_PAD_PKCS1 | SC_ALGORITHM_RSA_HASH_NONE)) && ++ (iflags & SC_ALGORITHM_RSA_PAD_PKCS1)) { ++ /* A corner case - the card can partially do PKCS1, if we prepend the ++ * DigestInfo bit it will do the rest. */ ++ *sflags = SC_ALGORITHM_RSA_PAD_PKCS1 | SC_ALGORITHM_RSA_HASH_NONE; ++ *pflags = iflags & SC_ALGORITHM_RSA_HASHES; ++ + } else { + LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "unsupported algorithm"); + } +diff --git a/src/libopensc/pkcs15-sec.c b/src/libopensc/pkcs15-sec.c +index 6ee4fa3c7..3e7e03b12 100644 +--- a/src/libopensc/pkcs15-sec.c ++++ b/src/libopensc/pkcs15-sec.c +@@ -329,7 +329,7 @@ int sc_pkcs15_compute_signature(struct sc_pkcs15_card *p15card, + + switch (obj->type) { + case SC_PKCS15_TYPE_PRKEY_RSA: +- modlen = prkey->modulus_length / 8; ++ modlen = (prkey->modulus_length + 7) / 8; + break; + case SC_PKCS15_TYPE_PRKEY_GOSTR3410: + modlen = (prkey->modulus_length + 7) / 8 * 2; +@@ -377,7 +377,8 @@ int sc_pkcs15_compute_signature(struct sc_pkcs15_card *p15card, + if (modlen > tmplen) + LOG_TEST_RET(ctx, SC_ERROR_NOT_ALLOWED, "Buffer too small, needs recompile!"); + +- r = sc_pkcs1_encode(ctx, flags, in, inlen, buf, &tmplen, modlen); ++ /* XXX Assuming RSA key here */ ++ r = sc_pkcs1_encode(ctx, flags, in, inlen, buf, &tmplen, prkey->modulus_length); + + /* no padding needed - already done */ + flags &= ~SC_ALGORITHM_RSA_PADS; +@@ -391,10 +392,15 @@ int sc_pkcs15_compute_signature(struct sc_pkcs15_card *p15card, + } + + +- /* If the card doesn't support the requested algorithm, see if we +- * can strip the input so a more restrictive algo can be used */ ++ /* If the card doesn't support the requested algorithm, we normally add the ++ * padding here in software and ask the card to do a raw signature. There's ++ * one exception to that, where we might be able to get the signature to ++ * succeed by stripping padding if the card only offers higher-level ++ * signature operations. The only thing we can strip is the DigestInfo ++ * block from PKCS1 padding. */ + if ((flags == (SC_ALGORITHM_RSA_PAD_PKCS1 | SC_ALGORITHM_RSA_HASH_NONE)) && +- !(alg_info->flags & (SC_ALGORITHM_RSA_RAW | SC_ALGORITHM_RSA_HASH_NONE))) { ++ !(alg_info->flags & SC_ALGORITHM_RSA_RAW) && ++ !(alg_info->flags & (SC_ALGORITHM_RSA_PAD_PKCS1 | SC_ALGORITHM_RSA_HASH_NONE))) { + unsigned int algo; + size_t tmplen = sizeof(buf); + +@@ -420,19 +426,16 @@ int sc_pkcs15_compute_signature(struct sc_pkcs15_card *p15card, + + /* add the padding bytes (if necessary) */ + if (pad_flags != 0) { +- if (flags & SC_ALGORITHM_RSA_PAD_PSS) { +- // TODO PSS padding +- } else { +- size_t tmplen = sizeof(buf); +- +- r = sc_pkcs1_encode(ctx, pad_flags, tmp, inlen, tmp, &tmplen, modlen); +- SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, r, "Unable to add padding"); ++ size_t tmplen = sizeof(buf); + +- inlen = tmplen; +- } ++ /* XXX Assuming RSA key here */ ++ r = sc_pkcs1_encode(ctx, pad_flags, tmp, inlen, tmp, &tmplen, ++ prkey->modulus_length); ++ SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, r, "Unable to add padding"); ++ inlen = tmplen; + } + else if ( senv.algorithm == SC_ALGORITHM_RSA && +- (flags & SC_ALGORITHM_RSA_PADS) == SC_ALGORITHM_RSA_PAD_NONE) { ++ (flags & SC_ALGORITHM_RSA_PADS) == SC_ALGORITHM_RSA_PAD_NONE) { + /* Add zero-padding if input is shorter than the modulus */ + if (inlen < modlen) { + if (modlen > sizeof(buf)) +diff --git a/src/pkcs11/framework-pkcs15.c b/src/pkcs11/framework-pkcs15.c +index 80f9ce89f..a75d239f4 100644 +--- a/src/pkcs11/framework-pkcs15.c ++++ b/src/pkcs11/framework-pkcs15.c +@@ -3478,7 +3478,8 @@ struct sc_pkcs11_object_ops pkcs15_cert_ops = { + NULL, /* unwrap_key */ + NULL, /* decrypt */ + NULL, /* derive */ +- NULL /* can_do */ ++ NULL, /* can_do */ ++ NULL /* init_params */ + }; + + /* +@@ -3703,53 +3704,44 @@ static CK_RV + pkcs15_prkey_check_pss_param(CK_MECHANISM_PTR pMechanism, CK_ULONG hlen) + { + CK_RSA_PKCS_PSS_PARAMS *pss_param; +- +- if (pMechanism->pParameter == NULL) +- return CKR_OK; // Support applications that don't provide CK_RSA_PKCS_PSS_PARAMS +- +- if (pMechanism->ulParameterLen != sizeof(CK_RSA_PKCS_PSS_PARAMS)) +- return CKR_MECHANISM_PARAM_INVALID; ++ int i; ++ const unsigned int hash_lens[5] = { 160, 256, 385, 512, 224 }; ++ const unsigned int hashes[5] = { CKM_SHA_1, CKM_SHA256, ++ CKM_SHA384, CKM_SHA512, CKM_SHA224 }; + + pss_param = (CK_RSA_PKCS_PSS_PARAMS *)pMechanism->pParameter; + +- // Hash parameter must match mechanisms or length of data supplied for CKM_RSA_PKCS_PSS +- switch(pss_param->hashAlg) { +- case CKM_SHA_1: +- if (hlen != 20) +- return CKR_MECHANISM_PARAM_INVALID; +- break; +- case CKM_SHA256: +- if (hlen != 32) ++ // Hash parameter must match length of data supplied for CKM_RSA_PKCS_PSS ++ for (i = 0; i < 5; i++) { ++ if (pss_param->hashAlg == hashes[i] ++ && hlen != hash_lens[i]/8) + return CKR_MECHANISM_PARAM_INVALID; +- break; +- default: +- return CKR_MECHANISM_PARAM_INVALID; + } ++ /* other aspects of pss params were already verified during SignInit */ + +- // SmartCards typically only support MGFs based on the same hash as the +- // message digest +- switch(pss_param->mgf) { +- case CKG_MGF1_SHA1: +- if (hlen != 20) +- return CKR_MECHANISM_PARAM_INVALID; ++ return CKR_OK; ++} ++ ++static int mgf2flags(CK_RSA_PKCS_MGF_TYPE mgf) ++{ ++ switch (mgf) { ++ case CKG_MGF1_SHA224: ++ return SC_ALGORITHM_MGF1_SHA224; + break; + case CKG_MGF1_SHA256: +- if (hlen != 32) +- return CKR_MECHANISM_PARAM_INVALID; +- break; ++ return SC_ALGORITHM_MGF1_SHA256; ++ case CKG_MGF1_SHA384: ++ return SC_ALGORITHM_MGF1_SHA384; ++ case CKG_MGF1_SHA512: ++ return SC_ALGORITHM_MGF1_SHA512; ++ case CKG_MGF1_SHA1: ++ return SC_ALGORITHM_MGF1_SHA1; + default: +- return CKR_MECHANISM_PARAM_INVALID; ++ return -1; + } +- +- // SmartCards typically support only a salt length equal to the hash length +- if (pss_param->sLen != hlen) +- return CKR_MECHANISM_PARAM_INVALID; +- +- return CKR_OK; + } + + +- + static CK_RV + pkcs15_prkey_sign(struct sc_pkcs11_session *session, void *obj, + CK_MECHANISM_PTR pMechanism, CK_BYTE_PTR pData, +@@ -3798,35 +3790,74 @@ pkcs15_prkey_sign(struct sc_pkcs11_session *session, void *obj, + case CKM_SHA512_RSA_PKCS: + flags = SC_ALGORITHM_RSA_PAD_PKCS1 | SC_ALGORITHM_RSA_HASH_SHA512; + break; ++ case CKM_RIPEMD160_RSA_PKCS: ++ flags = SC_ALGORITHM_RSA_PAD_PKCS1 | SC_ALGORITHM_RSA_HASH_RIPEMD160; ++ break; ++ case CKM_RSA_X_509: ++ flags = SC_ALGORITHM_RSA_RAW; ++ break; + case CKM_RSA_PKCS_PSS: +- rv = pkcs15_prkey_check_pss_param(pMechanism, (int)ulDataLen); ++ flags = SC_ALGORITHM_RSA_PAD_PSS; ++ /* The hash was done ouside of the module */ ++ flags |= SC_ALGORITHM_RSA_HASH_NONE; ++ /* Omited parameter can use MGF1-SHA1 ? */ ++ if (pMechanism->pParameter == NULL) { ++ flags |= SC_ALGORITHM_MGF1_SHA1; ++ if (ulDataLen != SHA_DIGEST_LENGTH) ++ return CKR_MECHANISM_PARAM_INVALID; ++ break; ++ } + +- if (rv != CKR_OK) ++ /* Check the data length matches the selected hash */ ++ rv = pkcs15_prkey_check_pss_param(pMechanism, (int)ulDataLen); ++ if (rv != CKR_OK) { ++ sc_log(context, "Invalid data lenght for the selected " ++ "PSS parameters"); + return rv; ++ } + +- flags = SC_ALGORITHM_RSA_PAD_PSS | SC_ALGORITHM_RSA_HASH_NONE; +- break; +- case CKM_SHA1_RSA_PKCS_PSS: +- rv = pkcs15_prkey_check_pss_param(pMechanism, 20); +- +- if (rv != CKR_OK) +- return rv; ++ /* The MGF parameter was already verified in SignInit() */ ++ flags |= mgf2flags(((CK_RSA_PKCS_PSS_PARAMS*)pMechanism->pParameter)->mgf); + +- flags = SC_ALGORITHM_RSA_PAD_PSS | SC_ALGORITHM_RSA_HASH_SHA1; ++ /* Assuming salt is the size of hash */ + break; ++ case CKM_SHA1_RSA_PKCS_PSS: ++ case CKM_SHA224_RSA_PKCS_PSS: + case CKM_SHA256_RSA_PKCS_PSS: +- rv = pkcs15_prkey_check_pss_param(pMechanism, 32); ++ case CKM_SHA384_RSA_PKCS_PSS: ++ case CKM_SHA512_RSA_PKCS_PSS: ++ flags = SC_ALGORITHM_RSA_PAD_PSS; ++ /* Omited parameter can use MGF1-SHA1 and SHA1 hash ? */ ++ if (pMechanism->pParameter == NULL) { ++ flags |= SC_ALGORITHM_RSA_HASH_SHA1; ++ flags |= SC_ALGORITHM_MGF1_SHA1; ++ break; ++ } + +- if (rv != CKR_OK) +- return rv; ++ switch (((CK_RSA_PKCS_PSS_PARAMS*)pMechanism->pParameter)->hashAlg) { ++ case CKM_SHA_1: ++ flags |= SC_ALGORITHM_RSA_HASH_SHA1; ++ break; ++ case CKM_SHA224: ++ flags |= SC_ALGORITHM_RSA_HASH_SHA224; ++ break; ++ case CKM_SHA256: ++ flags |= SC_ALGORITHM_RSA_HASH_SHA256; ++ break; ++ case CKM_SHA384: ++ flags |= SC_ALGORITHM_RSA_HASH_SHA384; ++ break; ++ case CKM_SHA512: ++ flags |= SC_ALGORITHM_RSA_HASH_SHA512; ++ break; ++ default: ++ return CKR_MECHANISM_PARAM_INVALID; ++ } + +- flags = SC_ALGORITHM_RSA_PAD_PSS | SC_ALGORITHM_RSA_HASH_SHA256; +- break; +- case CKM_RIPEMD160_RSA_PKCS: +- flags = SC_ALGORITHM_RSA_PAD_PKCS1 | SC_ALGORITHM_RSA_HASH_RIPEMD160; +- break; +- case CKM_RSA_X_509: +- flags = SC_ALGORITHM_RSA_RAW; ++ /* The MGF parameter was already verified in SignInit() */ ++ flags |= mgf2flags(((CK_RSA_PKCS_PSS_PARAMS*)pMechanism->pParameter)->mgf); ++ ++ /* Assuming salt is the size of hash */ + break; + case CKM_GOSTR3410: + flags = SC_ALGORITHM_GOSTR3410_HASH_NONE; +@@ -4074,6 +4105,76 @@ pkcs15_prkey_can_do(struct sc_pkcs11_session *session, void *obj, + } + + ++static CK_RV ++pkcs15_prkey_init_params(struct sc_pkcs11_session *session, ++ CK_MECHANISM_PTR pMechanism) ++{ ++ const CK_RSA_PKCS_PSS_PARAMS *pss_params; ++ unsigned int expected_hash = 0, i; ++ unsigned int expected_salt_len = 0; ++ const unsigned int salt_lens[5] = { 160, 256, 384, 512, 224 }; ++ const unsigned int hashes[5] = { CKM_SHA_1, CKM_SHA256, ++ CKM_SHA384, CKM_SHA512, CKM_SHA224 }; ++ ++ switch (pMechanism->mechanism) { ++ case CKM_RSA_PKCS_PSS: ++ case CKM_SHA1_RSA_PKCS_PSS: ++ case CKM_SHA224_RSA_PKCS_PSS: ++ case CKM_SHA256_RSA_PKCS_PSS: ++ case CKM_SHA384_RSA_PKCS_PSS: ++ case CKM_SHA512_RSA_PKCS_PSS: ++ if (!pMechanism->pParameter || ++ pMechanism->ulParameterLen != sizeof(CK_RSA_PKCS_PSS_PARAMS)) ++ return CKR_MECHANISM_PARAM_INVALID; ++ ++ pss_params = (CK_RSA_PKCS_PSS_PARAMS*)pMechanism->pParameter; ++ if (pss_params->mgf < CKG_MGF1_SHA1 || pss_params->mgf > CKG_MGF1_SHA224) ++ return CKR_MECHANISM_PARAM_INVALID; ++ ++ /* The hashAlg field can have any value for CKM_RSA_PKCS_PSS and must be ++ * used again in the PSS padding; for the other mechanisms it strictly ++ * must match the padding declared in the mechanism. ++ */ ++ if (pMechanism->mechanism == CKM_SHA1_RSA_PKCS_PSS) { ++ expected_hash = CKM_SHA_1; ++ expected_salt_len = 160; ++ } else if (pMechanism->mechanism == CKM_SHA224_RSA_PKCS_PSS) { ++ expected_hash = CKM_SHA224; ++ expected_salt_len = 224; ++ } else if (pMechanism->mechanism == CKM_SHA256_RSA_PKCS_PSS) { ++ expected_hash = CKM_SHA256; ++ expected_salt_len = 256; ++ } else if (pMechanism->mechanism == CKM_SHA384_RSA_PKCS_PSS) { ++ expected_hash = CKM_SHA384; ++ expected_salt_len = 384; ++ } else if (pMechanism->mechanism == CKM_SHA512_RSA_PKCS_PSS) { ++ expected_hash = CKM_SHA512; ++ expected_salt_len = 512; ++ } else if (pMechanism->mechanism == CKM_RSA_PKCS_PSS) { ++ for (i = 0; i < 5; ++i) { ++ if (hashes[i] == pss_params->hashAlg) { ++ expected_hash = hashes[i]; ++ expected_salt_len = salt_lens[i]; ++ } ++ } ++ } ++ ++ if (expected_hash != pss_params->hashAlg) ++ return CKR_MECHANISM_PARAM_INVALID; ++ ++ /* We're strict, and only do PSS signatures with a salt length that ++ * matches the digest length (any shorter is rubbish, any longer ++ * is useless). */ ++ if (pss_params->sLen != expected_salt_len / 8) ++ return CKR_MECHANISM_PARAM_INVALID; ++ ++ /* TODO support different salt lengths */ ++ break; ++ } ++ return CKR_OK; ++} ++ ++ + struct sc_pkcs11_object_ops pkcs15_prkey_ops = { + pkcs15_prkey_release, + pkcs15_prkey_set_attribute, +@@ -4084,8 +4185,9 @@ struct sc_pkcs11_object_ops pkcs15_prkey_ops = { + pkcs15_prkey_sign, + NULL, /* unwrap */ + pkcs15_prkey_decrypt, +- pkcs15_prkey_derive, +- pkcs15_prkey_can_do ++ pkcs15_prkey_derive, ++ pkcs15_prkey_can_do, ++ pkcs15_prkey_init_params, + }; + + /* +@@ -4322,7 +4424,8 @@ struct sc_pkcs11_object_ops pkcs15_pubkey_ops = { + NULL, /* unwrap_key */ + NULL, /* decrypt */ + NULL, /* derive */ +- NULL /* can_do */ ++ NULL, /* can_do */ ++ NULL /* init_params */ + }; + + +@@ -4500,7 +4603,8 @@ struct sc_pkcs11_object_ops pkcs15_dobj_ops = { + NULL, /* unwrap_key */ + NULL, /* decrypt */ + NULL, /* derive */ +- NULL /* can_do */ ++ NULL, /* can_do */ ++ NULL /* init_params */ + }; + + +@@ -4629,7 +4733,8 @@ struct sc_pkcs11_object_ops pkcs15_skey_ops = { + NULL, /* unwrap_key */ + NULL, /* decrypt */ + NULL, /* derive */ +- NULL /* can_do */ ++ NULL, /* can_do */ ++ NULL /* init_params */ + }; + + /* +@@ -5040,6 +5145,17 @@ register_mechanisms(struct sc_pkcs11_card *p11card) + /* We support PKCS1 padding in software */ + /* either the card supports it or OpenSC does */ + rsa_flags |= SC_ALGORITHM_RSA_PAD_PKCS1; ++#ifdef ENABLE_OPENSSL ++ rsa_flags |= SC_ALGORITHM_RSA_PAD_PSS; ++#endif ++ } ++ ++ if (rsa_flags & SC_ALGORITHM_RSA_PAD_ISO9796) { ++ /* Supported in hardware only, if the card driver declares it. */ ++ mt = sc_pkcs11_new_fw_mechanism(CKM_RSA_9796, &mech_info, CKK_RSA, NULL, NULL); ++ rc = sc_pkcs11_register_mechanism(p11card, mt); ++ if (rc != CKR_OK) ++ return rc; + } + + #ifdef ENABLE_OPENSSL +@@ -5098,23 +5214,40 @@ register_mechanisms(struct sc_pkcs11_card *p11card) + #endif /* ENABLE_OPENSSL */ + } + +- /* TODO support other padding mechanisms */ +- + if (rsa_flags & SC_ALGORITHM_RSA_PAD_PSS) { +- mech_info.flags &= ~(CKF_DECRYPT|CKF_VERIFY); +- ++ mech_info.flags &= ~(CKF_DECRYPT|CKF_ENCRYPT); + mt = sc_pkcs11_new_fw_mechanism(CKM_RSA_PKCS_PSS, &mech_info, CKK_RSA, NULL, NULL); + rc = sc_pkcs11_register_mechanism(p11card, mt); + if (rc != CKR_OK) + return rc; + + if (rsa_flags & SC_ALGORITHM_RSA_HASH_SHA1) { +- rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card, CKM_SHA1_RSA_PKCS_PSS, CKM_SHA_1, mt); ++ rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card, ++ CKM_SHA1_RSA_PKCS_PSS, CKM_SHA_1, mt); ++ if (rc != CKR_OK) ++ return rc; ++ } ++ if (rsa_flags & SC_ALGORITHM_RSA_HASH_SHA224) { ++ rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card, ++ CKM_SHA224_RSA_PKCS_PSS, CKM_SHA224, mt); + if (rc != CKR_OK) + return rc; + } + if (rsa_flags & SC_ALGORITHM_RSA_HASH_SHA256) { +- rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card, CKM_SHA256_RSA_PKCS_PSS, CKM_SHA256, mt); ++ rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card, ++ CKM_SHA256_RSA_PKCS_PSS, CKM_SHA256, mt); ++ if (rc != CKR_OK) ++ return rc; ++ } ++ if (rsa_flags & SC_ALGORITHM_RSA_HASH_SHA384) { ++ rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card, ++ CKM_SHA384_RSA_PKCS_PSS, CKM_SHA384, mt); ++ if (rc != CKR_OK) ++ return rc; ++ } ++ if (rsa_flags & SC_ALGORITHM_RSA_HASH_SHA512) { ++ rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card, ++ CKM_SHA512_RSA_PKCS_PSS, CKM_SHA512, mt); + if (rc != CKR_OK) + return rc; + } +diff --git a/src/pkcs11/mechanism.c b/src/pkcs11/mechanism.c +index 5f006c839..d4ce7fef5 100644 +--- a/src/pkcs11/mechanism.c ++++ b/src/pkcs11/mechanism.c +@@ -262,11 +262,20 @@ sc_pkcs11_sign_init(struct sc_pkcs11_session *session, CK_MECHANISM_PTR pMechani + if (mt->key_type != key_type) + LOG_FUNC_RETURN(context, CKR_KEY_TYPE_INCONSISTENT); + ++ if (pMechanism->pParameter && ++ pMechanism->ulParameterLen > sizeof(operation->mechanism_params)) ++ LOG_FUNC_RETURN(context, CKR_ARGUMENTS_BAD); ++ + rv = session_start_operation(session, SC_PKCS11_OPERATION_SIGN, mt, &operation); + if (rv != CKR_OK) + LOG_FUNC_RETURN(context, rv); + + memcpy(&operation->mechanism, pMechanism, sizeof(CK_MECHANISM)); ++ if (pMechanism->pParameter) { ++ memcpy(&operation->mechanism_params, pMechanism->pParameter, ++ pMechanism->ulParameterLen); ++ operation->mechanism.pParameter = &operation->mechanism_params; ++ } + rv = mt->sign_init(operation, key); + if (rv != CKR_OK) + session_stop_operation(session, SC_PKCS11_OPERATION_SIGN); +@@ -387,6 +396,16 @@ sc_pkcs11_signature_init(sc_pkcs11_operation_t *operation, + } + } + ++ /* Validate the mechanism parameters */ ++ if (key->ops->init_params) { ++ rv = key->ops->init_params(operation->session, &operation->mechanism); ++ if (rv != CKR_OK) { ++ /* Probably bad arguments */ ++ free(data); ++ LOG_FUNC_RETURN(context, rv); ++ } ++ } ++ + /* If this is a signature with hash operation, + * and card cannot perform itself signature with hash operation, + * set up the hash operation */ +@@ -636,6 +655,16 @@ sc_pkcs11_verify_init(sc_pkcs11_operation_t *operation, + } + } + ++ /* Validate the mechanism parameters */ ++ if (key->ops->init_params) { ++ rv = key->ops->init_params(operation->session, &operation->mechanism); ++ if (rv != CKR_OK) { ++ /* Probably bad arguments */ ++ free(data); ++ LOG_FUNC_RETURN(context, rv); ++ } ++ } ++ + /* If this is a verify with hash operation, set up the + * hash operation */ + info = (struct hash_signature_info *) operation->type->mech_data; +@@ -729,7 +758,7 @@ sc_pkcs11_verify_final(sc_pkcs11_operation_t *operation, + + rv = sc_pkcs11_verify_data(pubkey_value, attr.ulValueLen, + params, sizeof(params), +- operation->mechanism.mechanism, data->md, ++ &operation->mechanism, data->md, + data->buffer, data->buffer_len, pSignature, ulSignatureLen); + + done: +diff --git a/src/pkcs11/openssl.c b/src/pkcs11/openssl.c +index 59de1210d..e8b246145 100644 +--- a/src/pkcs11/openssl.c ++++ b/src/pkcs11/openssl.c +@@ -68,6 +68,23 @@ static sc_pkcs11_mechanism_type_t openssl_sha1_mech = { + NULL, /* free_mech_data */ + }; + ++static sc_pkcs11_mechanism_type_t openssl_sha224_mech = { ++ CKM_SHA224, ++ { 0, 0, CKF_DIGEST }, ++ 0, ++ sizeof(struct sc_pkcs11_operation), ++ sc_pkcs11_openssl_md_release, ++ sc_pkcs11_openssl_md_init, ++ sc_pkcs11_openssl_md_update, ++ sc_pkcs11_openssl_md_final, ++ NULL, NULL, NULL, NULL, /* sign_* */ ++ NULL, NULL, NULL, /* verif_* */ ++ NULL, NULL, /* decrypt_* */ ++ NULL, /* derive */ ++ NULL, /* mech_data */ ++ NULL, /* free_mech_data */ ++}; ++ + #if OPENSSL_VERSION_NUMBER >= 0x00908000L + static sc_pkcs11_mechanism_type_t openssl_sha256_mech = { + CKM_SHA256, +@@ -231,6 +248,8 @@ sc_pkcs11_register_openssl_mechanisms(struct sc_pkcs11_card *p11card) + + openssl_sha1_mech.mech_data = EVP_sha1(); + sc_pkcs11_register_mechanism(p11card, dup_mem(&openssl_sha1_mech, sizeof openssl_sha1_mech)); ++ openssl_sha224_mech.mech_data = EVP_sha224(); ++ sc_pkcs11_register_mechanism(p11card, dup_mem(&openssl_sha224_mech, sizeof openssl_sha224_mech)); + #if OPENSSL_VERSION_NUMBER >= 0x00908000L + openssl_sha256_mech.mech_data = EVP_sha256(); + sc_pkcs11_register_mechanism(p11card, dup_mem(&openssl_sha256_mech, sizeof openssl_sha256_mech)); +@@ -396,7 +415,7 @@ static CK_RV gostr3410_verify_data(const unsigned char *pubkey, int pubkey_len, + */ + CK_RV sc_pkcs11_verify_data(const unsigned char *pubkey, int pubkey_len, + const unsigned char *pubkey_params, int pubkey_params_len, +- CK_MECHANISM_TYPE mech, sc_pkcs11_operation_t *md, ++ CK_MECHANISM_PTR mech, sc_pkcs11_operation_t *md, + unsigned char *data, int data_len, + unsigned char *signat, int signat_len) + { +@@ -405,7 +424,7 @@ CK_RV sc_pkcs11_verify_data(const unsigned char *pubkey, int pubkey_len, + EVP_PKEY *pkey = NULL; + const unsigned char *pubkey_tmp = NULL; + +- if (mech == CKM_GOSTR3410) ++ if (mech->mechanism == CKM_GOSTR3410) + { + #if OPENSSL_VERSION_NUMBER >= 0x10000000L && !defined(OPENSSL_NO_EC) + return gostr3410_verify_data(pubkey, pubkey_len, +@@ -429,37 +448,53 @@ CK_RV sc_pkcs11_verify_data(const unsigned char *pubkey, int pubkey_len, + if (pkey == NULL) + return CKR_GENERAL_ERROR; + +- if (md != NULL) { ++ if (md != NULL && (mech->mechanism == CKM_SHA1_RSA_PKCS ++ || mech->mechanism == CKM_SHA224_RSA_PKCS ++ || mech->mechanism == CKM_SHA256_RSA_PKCS ++ || mech->mechanism == CKM_SHA384_RSA_PKCS ++ || mech->mechanism == CKM_SHA512_RSA_PKCS)) { + EVP_MD_CTX *md_ctx = DIGEST_CTX(md); + ++ /* This does not really use the data argument, but the data ++ * are already collected in the md_ctx ++ */ ++ sc_log(context, "Trying to verify using EVP"); + res = EVP_VerifyFinal(md_ctx, signat, signat_len, pkey); + EVP_PKEY_free(pkey); + if (res == 1) + return CKR_OK; +- else if (res == 0) ++ else if (res == 0) { ++ sc_log(context, "EVP_VerifyFinal(): Signature invalid"); + return CKR_SIGNATURE_INVALID; +- else { ++ } else { + sc_log(context, "EVP_VerifyFinal() returned %d\n", res); + return CKR_GENERAL_ERROR; + } +- } +- else { ++ } else { + RSA *rsa; + unsigned char *rsa_out = NULL, pad; + int rsa_outlen = 0; + +- switch(mech) { ++ sc_log(context, "Trying to verify using low-level API"); ++ switch (mech->mechanism) { + case CKM_RSA_PKCS: + pad = RSA_PKCS1_PADDING; + break; +- case CKM_RSA_X_509: +- pad = RSA_NO_PADDING; +- break; +- /* TODO support more then RSA */ +- default: ++ case CKM_RSA_X_509: ++ pad = RSA_NO_PADDING; ++ break; ++ case CKM_RSA_PKCS_PSS: ++ case CKM_SHA1_RSA_PKCS_PSS: ++ case CKM_SHA224_RSA_PKCS_PSS: ++ case CKM_SHA256_RSA_PKCS_PSS: ++ case CKM_SHA384_RSA_PKCS_PSS: ++ case CKM_SHA512_RSA_PKCS_PSS: ++ pad = RSA_NO_PADDING; ++ break; ++ default: + EVP_PKEY_free(pkey); +- return CKR_ARGUMENTS_BAD; +- } ++ return CKR_ARGUMENTS_BAD; ++ } + + rsa = EVP_PKEY_get1_RSA(pkey); + EVP_PKEY_free(pkey); +@@ -473,13 +508,95 @@ CK_RV sc_pkcs11_verify_data(const unsigned char *pubkey, int pubkey_len, + } + + rsa_outlen = RSA_public_decrypt(signat_len, signat, rsa_out, rsa, pad); +- RSA_free(rsa); +- if(rsa_outlen <= 0) { ++ if (rsa_outlen <= 0) { + free(rsa_out); + sc_log(context, "RSA_public_decrypt() returned %d\n", rsa_outlen); + return CKR_GENERAL_ERROR; + } + ++ /* For PSS mechanisms we can not simply compare the "decrypted" ++ * data -- we need to verify the PSS padding is valid ++ */ ++ if (mech->mechanism == CKM_RSA_PKCS_PSS || ++ mech->mechanism == CKM_SHA1_RSA_PKCS_PSS || ++ mech->mechanism == CKM_SHA224_RSA_PKCS_PSS || ++ mech->mechanism == CKM_SHA256_RSA_PKCS_PSS || ++ mech->mechanism == CKM_SHA384_RSA_PKCS_PSS || ++ mech->mechanism == CKM_SHA512_RSA_PKCS_PSS) { ++ CK_RSA_PKCS_PSS_PARAMS* param = NULL; ++ const EVP_MD *mgf_md, *pss_md; ++ unsigned char digest[EVP_MAX_MD_SIZE]; ++ ++ if (mech->pParameter == NULL) { ++ sc_log(context, "PSS mechanism requires parameter"); ++ return CKR_MECHANISM_PARAM_INVALID; ++ } ++ ++ param = (CK_RSA_PKCS_PSS_PARAMS*)mech->pParameter; ++ switch (param->mgf) { ++ case CKG_MGF1_SHA1: ++ mgf_md = EVP_sha1(); ++ break; ++ case CKG_MGF1_SHA224: ++ mgf_md = EVP_sha224(); ++ break; ++ case CKG_MGF1_SHA256: ++ mgf_md = EVP_sha256(); ++ break; ++ case CKG_MGF1_SHA384: ++ mgf_md = EVP_sha384(); ++ break; ++ case CKG_MGF1_SHA512: ++ mgf_md = EVP_sha512(); ++ break; ++ default: ++ return CKR_MECHANISM_PARAM_INVALID; ++ } ++ ++ switch (param->hashAlg) { ++ case CKM_SHA_1: ++ pss_md = EVP_sha1(); ++ break; ++ case CKM_SHA224: ++ pss_md = EVP_sha224(); ++ break; ++ case CKM_SHA256: ++ pss_md = EVP_sha256(); ++ break; ++ case CKM_SHA384: ++ pss_md = EVP_sha384(); ++ break; ++ case CKM_SHA512: ++ pss_md = EVP_sha512(); ++ break; ++ default: ++ return CKR_MECHANISM_PARAM_INVALID; ++ } ++ ++ /* for the mechanisms with hash algorithm, the data ++ * is already added to the hash buffer, so we need ++ * to finish the hash operation here ++ */ ++ if (mech->mechanism != CKM_RSA_PKCS_PSS) { ++ EVP_MD_CTX *md_ctx = DIGEST_CTX(md); ++ unsigned char *tmp = digest; ++ unsigned int tmp_len; ++ ++ EVP_DigestFinal(md_ctx, tmp, &tmp_len); ++ data = tmp; ++ data_len = tmp_len; ++ } ++ rv = CKR_SIGNATURE_INVALID; ++ if (data_len == EVP_MD_size(pss_md) && ++ RSA_verify_PKCS1_PSS_mgf1(rsa, data, pss_md, mgf_md, ++ rsa_out, EVP_MD_size(pss_md)/*sLen*/) == 1) ++ rv = CKR_OK; ++ RSA_free(rsa); ++ sc_log(context, "Returning %lu", rv); ++ return rv; ++ } ++ RSA_free(rsa); ++ + if (rsa_outlen == data_len && memcmp(rsa_out, data, data_len) == 0) + rv = CKR_OK; + else +diff --git a/src/pkcs11/pkcs11.h b/src/pkcs11/pkcs11.h +index 61a5050df..8219b961b 100644 +--- a/src/pkcs11/pkcs11.h ++++ b/src/pkcs11/pkcs11.h +@@ -480,8 +480,6 @@ struct ck_date + + typedef unsigned long ck_mechanism_type_t; + +-typedef unsigned long int ck_rsa_pkcs_mgf_type_t; +- + #define CKM_RSA_PKCS_KEY_PAIR_GEN (0UL) + #define CKM_RSA_PKCS (1UL) + #define CKM_RSA_9796 (2UL) +@@ -764,6 +762,7 @@ typedef struct CK_ECDH1_DERIVE_PARAMS { + unsigned char * pPublicData; + } CK_ECDH1_DERIVE_PARAMS; + ++typedef unsigned long ck_rsa_pkcs_mgf_type_t; + typedef unsigned long CK_RSA_PKCS_OAEP_SOURCE_TYPE; + + typedef struct CK_RSA_PKCS_OAEP_PARAMS { +diff --git a/src/pkcs11/sc-pkcs11.h b/src/pkcs11/sc-pkcs11.h +index 843245882..f0115ed04 100644 +--- a/src/pkcs11/sc-pkcs11.h ++++ b/src/pkcs11/sc-pkcs11.h +@@ -119,6 +119,9 @@ struct sc_pkcs11_object_ops { + /* Check compatibility of PKCS#15 object usage and an asked PKCS#11 mechanism. */ + CK_RV (*can_do)(struct sc_pkcs11_session *, void *, CK_MECHANISM_TYPE, unsigned int); + ++ /* General validation of mechanism parameters (sign, encrypt, etc) */ ++ CK_RV (*init_params)(struct sc_pkcs11_session *, CK_MECHANISM_PTR); ++ + /* Others to be added when implemented */ + }; + +@@ -290,6 +293,10 @@ typedef struct sc_pkcs11_mechanism_type sc_pkcs11_mechanism_type_t; + struct sc_pkcs11_operation { + sc_pkcs11_mechanism_type_t *type; + CK_MECHANISM mechanism; ++ union { ++ CK_RSA_PKCS_PSS_PARAMS pss; ++ CK_RSA_PKCS_OAEP_PARAMS oaep; ++ } mechanism_params; + struct sc_pkcs11_session *session; + void * priv_data; + }; +@@ -434,7 +441,7 @@ CK_RV sc_pkcs11_register_sign_and_hash_mechanism(struct sc_pkcs11_card *, + #ifdef ENABLE_OPENSSL + CK_RV sc_pkcs11_verify_data(const unsigned char *pubkey, int pubkey_len, + const unsigned char *pubkey_params, int pubkey_params_len, +- CK_MECHANISM_TYPE mech, sc_pkcs11_operation_t *md, ++ CK_MECHANISM_PTR mech, sc_pkcs11_operation_t *md, + unsigned char *inp, int inp_len, + unsigned char *signat, int signat_len); + #endif + +From 2f36612d116ed1fb3ed305a5657871fa12f75011 Mon Sep 17 00:00:00 2001 +From: Jakub Jelen +Date: Sun, 22 Jul 2018 16:29:19 +0200 +Subject: [PATCH 4/5] pkcs11-tool: Support for signature verification + +Signed-off-by: Jakub Jelen +--- + doc/tools/pkcs11-tool.1.xml | 14 ++ + src/tools/pkcs11-tool.c | 273 +++++++++++++++++++++++++++--------- + 2 files changed, 222 insertions(+), 65 deletions(-) + +diff --git a/doc/tools/pkcs11-tool.1.xml b/doc/tools/pkcs11-tool.1.xml +index c609ec0e2..fd823c06e 100644 +--- a/doc/tools/pkcs11-tool.1.xml ++++ b/doc/tools/pkcs11-tool.1.xml +@@ -481,6 +481,13 @@ + non-zero number. + + ++ ++ ++ , ++ ++ Verify signature of some data. ++ ++ + + + , +@@ -530,6 +537,13 @@ + cert/privkey/pubkey). + + ++ ++ ++ filename ++ ++ The path to the signature file for signature verification ++ ++ + + + format +diff --git a/src/tools/pkcs11-tool.c b/src/tools/pkcs11-tool.c +index 64525f6ad..e3c52e2f8 100644 +--- a/src/tools/pkcs11-tool.c ++++ b/src/tools/pkcs11-tool.c +@@ -150,6 +150,8 @@ enum { + OPT_HASH_ALGORITHM, + OPT_MGF, + OPT_SALT, ++ OPT_VERIFY, ++ OPT_SIGNATURE_FILE, + }; + + static const struct option options[] = { +@@ -161,6 +163,7 @@ static const struct option options[] = { + { "list-objects", 0, NULL, 'O' }, + + { "sign", 0, NULL, 's' }, ++ { "verify", 0, NULL, OPT_VERIFY }, + { "decrypt", 0, NULL, OPT_DECRYPT }, + { "hash", 0, NULL, 'h' }, + { "derive", 0, NULL, OPT_DERIVE }, +@@ -203,6 +206,7 @@ static const struct option options[] = { + { "set-id", 1, NULL, 'e' }, + { "attr-from", 1, NULL, OPT_ATTR_FROM }, + { "input-file", 1, NULL, 'i' }, ++ { "signature-file", 1, NULL, OPT_SIGNATURE_FILE }, + { "output-file", 1, NULL, 'o' }, + { "signature-format", 1, NULL, 'f' }, + +@@ -230,6 +234,7 @@ static const char *option_help[] = { + "Show objects on token", + + "Sign some data", ++ "Verify a signature of some data", + "Decrypt some data", + "Hash some data", + "Derive a secret key using another key and some data", +@@ -272,6 +277,7 @@ static const char *option_help[] = { + "Set the CKA_ID of an object, = the (new) CKA_ID", + "Use to create some attributes when writing an object", + "Specify the input file", ++ "Specify the file with signature for verification", + "Specify the output file", + "Format for ECDSA signature : 'rs' (default), 'sequence', 'openssl'", + +@@ -293,6 +299,7 @@ static const char * app_name = "pkcs11-tool"; /* for utils.c */ + static int verbose = 0; + static const char * opt_input = NULL; + static const char * opt_output = NULL; ++static const char * opt_signature_file = NULL; + static const char * opt_module = DEFAULT_PKCS11_PROVIDER; + static int opt_slot_set = 0; + static CK_SLOT_ID opt_slot = 0; +@@ -331,8 +338,8 @@ static int opt_derive_pass_der = 0; + static unsigned long opt_random_bytes = 0; + static CK_MECHANISM_TYPE opt_hash_alg = 0; + static unsigned long opt_mgf = 0; +-static long salt_len = 0; +-static int salt_len_given = 0; /* 0 - not given, 1 - given with input parameters */ ++static long opt_salt_len = 0; ++static int opt_salt_len_given = 0; /* 0 - not given, 1 - given with input parameters */ + + static void *module = NULL; + static CK_FUNCTION_LIST_PTR p11 = NULL; +@@ -396,6 +403,7 @@ static void show_key(CK_SESSION_HANDLE, CK_OBJECT_HANDLE); + static void show_cert(CK_SESSION_HANDLE, CK_OBJECT_HANDLE); + static void show_dobj(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj); + static void sign_data(CK_SLOT_ID, CK_SESSION_HANDLE, CK_OBJECT_HANDLE); ++static void verify_signature(CK_SLOT_ID, CK_SESSION_HANDLE, CK_OBJECT_HANDLE); + static void decrypt_data(CK_SLOT_ID, CK_SESSION_HANDLE, CK_OBJECT_HANDLE); + static void hash_data(CK_SLOT_ID, CK_SESSION_HANDLE); + static void derive_key(CK_SLOT_ID, CK_SESSION_HANDLE, CK_OBJECT_HANDLE); +@@ -532,6 +540,7 @@ int main(int argc, char * argv[]) + int do_list_mechs = 0; + int do_list_objects = 0; + int do_sign = 0; ++ int do_verify = 0; + int do_decrypt = 0; + int do_hash = 0; + int do_derive = 0; +@@ -685,6 +694,9 @@ int main(int argc, char * argv[]) + case 'i': + opt_input = optarg; + break; ++ case OPT_SIGNATURE_FILE: ++ opt_signature_file = optarg; ++ break; + case 'l': + need_session |= NEED_SESSION_RW; + opt_login = 1; +@@ -700,8 +712,8 @@ int main(int argc, char * argv[]) + opt_mgf = p11_name_to_mgf(optarg); + break; + case OPT_SALT: +- salt_len = (CK_ULONG) strtoul(optarg, NULL, 0); +- salt_len_given = 1; ++ opt_salt_len = (CK_ULONG) strtoul(optarg, NULL, 0); ++ opt_salt_len_given = 1; + break; + case 'o': + opt_output = optarg; +@@ -726,6 +738,11 @@ int main(int argc, char * argv[]) + do_sign = 1; + action_count++; + break; ++ case OPT_VERIFY: ++ need_session |= NEED_SESSION_RO; ++ do_verify = 1; ++ action_count++; ++ break; + case OPT_DECRYPT: + need_session |= NEED_SESSION_RW; + do_decrypt = 1; +@@ -1037,6 +1054,16 @@ int main(int argc, char * argv[]) + util_fatal("Private key not found"); + } + ++ if (do_verify) { ++ if (!find_object(session, CKO_PUBLIC_KEY, &object, ++ opt_object_id_len ? opt_object_id : NULL, ++ opt_object_id_len, 0) && ++ !find_object(session, CKO_CERTIFICATE, &object, ++ opt_object_id_len ? opt_object_id : NULL, ++ opt_object_id_len, 0)) ++ util_fatal("Public key nor certificate not found"); ++ } ++ + /* before list objects, so we can see a derived key */ + if (do_derive) + derive_key(opt_slot, session, object); +@@ -1047,6 +1074,9 @@ int main(int argc, char * argv[]) + if (do_sign) + sign_data(opt_slot, session, object); + ++ if (do_verify) ++ verify_signature(opt_slot, session, object); ++ + if (do_decrypt) + decrypt_data(opt_slot, session, object); + +@@ -1636,7 +1666,7 @@ static int unlock_pin(CK_SLOT_ID slot, CK_SESSION_HANDLE sess, int login_type) + } + + /* return digest length in bytes */ +-static unsigned long figure_pss_salt_length(const int hash) { ++static unsigned long hash_length(const int hash) { + unsigned long sLen = 0; + switch (hash) { + case CKM_SHA_1: +@@ -1662,26 +1692,16 @@ static unsigned long figure_pss_salt_length(const int hash) { + return sLen; + } + +-static void sign_data(CK_SLOT_ID slot, CK_SESSION_HANDLE session, +- CK_OBJECT_HANDLE key) ++static unsigned long ++parse_pss_params(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE key, ++ CK_MECHANISM *mech, CK_RSA_PKCS_PSS_PARAMS *pss_params) + { +- unsigned char in_buffer[1025], sig_buffer[512]; +- CK_MECHANISM mech; +- CK_RSA_PKCS_PSS_PARAMS pss_params; +- CK_RV rv; +- CK_ULONG sig_len; +- int fd, r; ++ unsigned long hashlen = 0; + +- unsigned long hashlen = 0, modlen = 0; +- +- if (!opt_mechanism_used) +- if (!find_mechanism(slot, CKF_SIGN|CKF_HW, NULL, 0, &opt_mechanism)) +- util_fatal("Sign mechanism not supported"); ++ if (pss_params == NULL) ++ return 0; + +- fprintf(stderr, "Using signature algorithm %s\n", p11_mechanism_to_name(opt_mechanism)); +- memset(&mech, 0, sizeof(mech)); +- mech.mechanism = opt_mechanism; +- pss_params.hashAlg = 0; ++ pss_params->hashAlg = 0; + + if (opt_hash_alg != 0 && opt_mechanism != CKM_RSA_PKCS_PSS) + util_fatal("The hash-algorithm is applicable only to " +@@ -1690,93 +1710,118 @@ static void sign_data(CK_SLOT_ID slot, CK_SESSION_HANDLE session, + /* set "default" MGF and hash algorithms. We can overwrite MGF later */ + switch (opt_mechanism) { + case CKM_RSA_PKCS_PSS: +- pss_params.hashAlg = opt_hash_alg; ++ pss_params->hashAlg = opt_hash_alg; + + switch (opt_hash_alg) { + case CKM_SHA224: +- pss_params.mgf = CKG_MGF1_SHA224; ++ pss_params->mgf = CKG_MGF1_SHA224; + break; + case CKM_SHA256: +- pss_params.mgf = CKG_MGF1_SHA256; ++ pss_params->mgf = CKG_MGF1_SHA256; + break; + case CKM_SHA384: +- pss_params.mgf = CKG_MGF1_SHA384; ++ pss_params->mgf = CKG_MGF1_SHA384; + break; + case CKM_SHA512: +- pss_params.mgf = CKG_MGF1_SHA512; ++ pss_params->mgf = CKG_MGF1_SHA512; + break; + default: + /* the PSS should use SHA-1 if not specified */ +- pss_params.hashAlg = CKM_SHA_1; ++ pss_params->hashAlg = CKM_SHA_1; + /* fallthrough */ + case CKM_SHA_1: +- pss_params.mgf = CKG_MGF1_SHA1; ++ pss_params->mgf = CKG_MGF1_SHA1; + } + break; + + case CKM_SHA1_RSA_PKCS_PSS: +- pss_params.hashAlg = CKM_SHA_1; +- pss_params.mgf = CKG_MGF1_SHA1; ++ pss_params->hashAlg = CKM_SHA_1; ++ pss_params->mgf = CKG_MGF1_SHA1; + break; + + case CKM_SHA224_RSA_PKCS_PSS: +- pss_params.hashAlg = CKM_SHA224; +- pss_params.mgf = CKG_MGF1_SHA224; ++ pss_params->hashAlg = CKM_SHA224; ++ pss_params->mgf = CKG_MGF1_SHA224; + break; + + case CKM_SHA256_RSA_PKCS_PSS: +- pss_params.hashAlg = CKM_SHA256; +- pss_params.mgf = CKG_MGF1_SHA256; ++ pss_params->hashAlg = CKM_SHA256; ++ pss_params->mgf = CKG_MGF1_SHA256; + break; + + case CKM_SHA384_RSA_PKCS_PSS: +- pss_params.hashAlg = CKM_SHA384; +- pss_params.mgf = CKG_MGF1_SHA384; ++ pss_params->hashAlg = CKM_SHA384; ++ pss_params->mgf = CKG_MGF1_SHA384; + break; + + case CKM_SHA512_RSA_PKCS_PSS: +- pss_params.hashAlg = CKM_SHA512; +- pss_params.mgf = CKG_MGF1_SHA512; ++ pss_params->hashAlg = CKM_SHA512; ++ pss_params->mgf = CKG_MGF1_SHA512; + break; + } + + /* One of RSA-PSS mechanisms above: They need parameters */ +- if (pss_params.hashAlg) { ++ if (pss_params->hashAlg) { + if (opt_mgf != 0) +- pss_params.mgf = opt_mgf; ++ pss_params->mgf = opt_mgf; + +- hashlen = figure_pss_salt_length(pss_params.hashAlg); ++ hashlen = hash_length(pss_params->hashAlg); + +- if (salt_len_given == 1) { /* salt size explicitly given */ +- if (salt_len < 0 && salt_len != -1 && salt_len != -2) +- util_fatal("Salt length must be greater or equal \ +-to zero, or equal to -1 (meaning: use digest size) or to -2 \ +-(meaning: use maximum permissible size"); ++ if (opt_salt_len_given == 1) { /* salt size explicitly given */ ++ unsigned long modlen = 0; ++ if (opt_salt_len < 0 && opt_salt_len != -1 && opt_salt_len != -2) ++ util_fatal("Salt length must be greater or equal " ++ "to zero, or equal to -1 (meaning: use digest size) " ++ "or to -2 (meaning: use maximum permissible size"); + + modlen = (get_private_key_length(session, key) + 7) / 8; +- switch(salt_len) { ++ switch (opt_salt_len) { + case -1: /* salt size equals to digest size */ +- pss_params.sLen = hashlen; ++ pss_params->sLen = hashlen; + break; + case -2: /* maximum permissible salt len */ +- pss_params.sLen = modlen - hashlen -2; ++ pss_params->sLen = modlen - hashlen -2; + break; + default: /* use given size but its value must be >= 0 */ +- pss_params.sLen = salt_len; ++ pss_params->sLen = opt_salt_len; + break; +- } /* end switch (salt_len_given) */ ++ } /* end switch (opt_salt_len_given) */ + } else { /* use default: salt len of digest size */ +- pss_params.sLen = hashlen; ++ pss_params->sLen = hashlen; + } + +- mech.pParameter = &pss_params; +- mech.ulParameterLen = sizeof(pss_params); ++ mech->pParameter = pss_params; ++ mech->ulParameterLen = sizeof(*pss_params); + + fprintf(stderr, "PSS parameters: hashAlg=%s, mgf=%s, salt_len=%lu B\n", +- p11_mechanism_to_name(pss_params.hashAlg), +- p11_mgf_to_name(pss_params.mgf), +- pss_params.sLen); ++ p11_mechanism_to_name(pss_params->hashAlg), ++ p11_mgf_to_name(pss_params->mgf), ++ pss_params->sLen); + } ++ return hashlen; ++} ++ ++static void sign_data(CK_SLOT_ID slot, CK_SESSION_HANDLE session, ++ CK_OBJECT_HANDLE key) ++{ ++ unsigned char in_buffer[1025], sig_buffer[512]; ++ CK_MECHANISM mech; ++ CK_RSA_PKCS_PSS_PARAMS pss_params; ++ CK_RV rv; ++ CK_ULONG sig_len; ++ int fd, r; ++ unsigned long hashlen; ++ ++ if (!opt_mechanism_used) ++ if (!find_mechanism(slot, CKF_SIGN|CKF_HW, NULL, 0, &opt_mechanism)) ++ util_fatal("Sign mechanism not supported"); ++ ++ fprintf(stderr, "Using signature algorithm %s\n", p11_mechanism_to_name(opt_mechanism)); ++ memset(&mech, 0, sizeof(mech)); ++ mech.mechanism = opt_mechanism; ++ hashlen = parse_pss_params(session, key, &mech, &pss_params); ++ if (hashlen == 0) ++ util_fatal("Invalid RSA-PSS parameters"); + + if (opt_input == NULL) + fd = 0; +@@ -1787,12 +1832,15 @@ to zero, or equal to -1 (meaning: use digest size) or to -2 \ + if (r < 0) + util_fatal("Cannot read from %s: %m", opt_input); + +- if (opt_mechanism == CKM_RSA_PKCS_PSS && (unsigned long)r != hashlen) +- util_fatal("For %s mechanism, message size (got %d bytes) must be equal to specified digest length (%lu)\n", +- p11_mechanism_to_name(opt_mechanism), r, hashlen); ++ if (opt_mechanism == CKM_RSA_PKCS_PSS) { ++ if ((unsigned long)r != hashlen) ++ util_fatal("For %s mechanism, message size (got %d bytes) " ++ "must be equal to specified digest length (%lu)\n", ++ p11_mechanism_to_name(opt_mechanism), r, hashlen); ++ } + + rv = CKR_CANCEL; +- if (r < (int) sizeof(in_buffer)) { ++ if (r < (int) sizeof(in_buffer)) { + rv = p11->C_SignInit(session, &mech, key); + if (rv != CKR_OK) + p11_fatal("C_SignInit", rv); +@@ -1833,12 +1881,16 @@ to zero, or equal to -1 (meaning: use digest size) or to -2 \ + util_fatal("failed to open %s: %m", opt_output); + } + +- if (opt_mechanism == CKM_ECDSA || opt_mechanism == CKM_ECDSA_SHA1 || opt_mechanism == CKM_ECDSA_SHA256 || opt_mechanism == CKM_ECDSA_SHA384 || opt_mechanism == CKM_ECDSA_SHA512 || opt_mechanism == CKM_ECDSA_SHA224) { +- if (opt_sig_format && (!strcmp(opt_sig_format, "openssl") || !strcmp(opt_sig_format, "sequence"))) { ++ if (opt_mechanism == CKM_ECDSA || opt_mechanism == CKM_ECDSA_SHA1 || ++ opt_mechanism == CKM_ECDSA_SHA256 || opt_mechanism == CKM_ECDSA_SHA384 || ++ opt_mechanism == CKM_ECDSA_SHA512 || opt_mechanism == CKM_ECDSA_SHA224) { ++ if (opt_sig_format && (!strcmp(opt_sig_format, "openssl") || ++ !strcmp(opt_sig_format, "sequence"))) { + unsigned char *seq; + size_t seqlen; + +- if (sc_asn1_sig_value_rs_to_sequence(NULL, sig_buffer, sig_len, &seq, &seqlen)) { ++ if (sc_asn1_sig_value_rs_to_sequence(NULL, sig_buffer, ++ sig_len, &seq, &seqlen)) { + util_fatal("Failed to convert signature to ASN.1 sequence format"); + } + +@@ -1856,6 +1908,97 @@ to zero, or equal to -1 (meaning: use digest size) or to -2 \ + close(fd); + } + ++static void verify_signature(CK_SLOT_ID slot, CK_SESSION_HANDLE session, ++ CK_OBJECT_HANDLE key) ++{ ++ unsigned char in_buffer[1025], sig_buffer[512]; ++ CK_MECHANISM mech; ++ CK_RSA_PKCS_PSS_PARAMS pss_params; ++ CK_RV rv; ++ CK_ULONG sig_len; ++ int fd, fd2, r, r2; ++ unsigned long hashlen; ++ ++ if (!opt_mechanism_used) ++ if (!find_mechanism(slot, CKF_VERIFY|CKF_HW, NULL, 0, &opt_mechanism)) ++ util_fatal("Mechanism not supported for signature verification"); ++ ++ fprintf(stderr, "Using signature algorithm %s\n", p11_mechanism_to_name(opt_mechanism)); ++ memset(&mech, 0, sizeof(mech)); ++ mech.mechanism = opt_mechanism; ++ hashlen = parse_pss_params(session, key, &mech, &pss_params); ++ if (hashlen == 0) ++ util_fatal("Invalid RSA-PSS parameters"); ++ ++ /* Open a signature file */ ++ if (opt_signature_file == NULL) ++ util_fatal("No file with signature provided. Use --signature-file"); ++ else if ((fd2 = open(opt_signature_file, O_RDONLY|O_BINARY)) < 0) ++ util_fatal("Cannot open %s: %m", opt_signature_file); ++ ++ r2 = read(fd2, sig_buffer, sizeof(sig_buffer)); ++ if (r2 < 0) ++ util_fatal("Cannot read from %s: %m", opt_signature_file); ++ ++ close(fd2); ++ ++ /* Open the data file */ ++ if (opt_input == NULL) ++ fd = 0; ++ else if ((fd = open(opt_input, O_RDONLY|O_BINARY)) < 0) ++ util_fatal("Cannot open %s: %m", opt_input); ++ ++ r = read(fd, in_buffer, sizeof(in_buffer)); ++ if (r < 0) ++ util_fatal("Cannot read from %s: %m", opt_input); ++ ++ if (opt_mechanism == CKM_RSA_PKCS_PSS) { ++ if ((unsigned long)r != hashlen) ++ util_fatal("For %s mechanism, message size (got %d bytes)" ++ " must be equal to specified digest length (%lu)\n", ++ p11_mechanism_to_name(opt_mechanism), r, hashlen); ++ } ++ ++ rv = CKR_CANCEL; ++ if (r < (int) sizeof(in_buffer)) { ++ rv = p11->C_VerifyInit(session, &mech, key); ++ if (rv != CKR_OK) ++ p11_fatal("C_VerifyInit", rv); ++ ++ sig_len = r2; ++ rv = p11->C_Verify(session, in_buffer, r, sig_buffer, sig_len); ++ } ++ ++ if (rv != CKR_OK) { ++ rv = p11->C_VerifyInit(session, &mech, key); ++ if (rv != CKR_OK) ++ p11_fatal("C_VerifyInit", rv); ++ ++ do { ++ rv = p11->C_VerifyUpdate(session, in_buffer, r); ++ if (rv != CKR_OK) ++ p11_fatal("C_VerifyUpdate", rv); ++ ++ r = read(fd, in_buffer, sizeof(in_buffer)); ++ } while (r > 0); ++ ++ sig_len = sizeof(sig_buffer); ++ rv = p11->C_VerifyFinal(session, sig_buffer, sig_len); ++ if (rv != CKR_OK) ++ p11_fatal("C_VerifyFinal", rv); ++ } ++ ++ if (fd != 0) ++ close(fd); ++ ++ if (rv == CKR_OK) ++ printf("Signature is valid\n"); ++ else if (rv == CKR_SIGNATURE_INVALID) ++ printf("Invalid signature\n"); ++ else ++ printf("Cryptoki returned erorr: %s\n", CKR2Str(rv)); ++} ++ + + static void decrypt_data(CK_SLOT_ID slot, CK_SESSION_HANDLE session, + CK_OBJECT_HANDLE key) + +From 256502bed97d56a6813c0b4a7d4c64ee1ff0606e Mon Sep 17 00:00:00 2001 +From: Jakub Jelen +Date: Fri, 14 Sep 2018 17:27:11 +0200 +Subject: [PATCH 5/5] slot: Switch cleanup steps to avoid segfaults on errors + +and some more sanity checking + +Signed-off-by: Jakub Jelen +--- + src/pkcs11/framework-pkcs15.c | 2 +- + src/pkcs11/slot.c | 4 ++-- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/src/pkcs11/framework-pkcs15.c b/src/pkcs11/framework-pkcs15.c +index a75d239f4..85e12df66 100644 +--- a/src/pkcs11/framework-pkcs15.c ++++ b/src/pkcs11/framework-pkcs15.c +@@ -365,7 +365,7 @@ pkcs15_unbind(struct sc_pkcs11_card *p11card) + + unlock_card(fw_data); + +- if (fw_data->p15_card) { ++ if (fw_data->p15_card && fw_data->p15_card->card) { + if (idx == 0) { + int rc = sc_detect_card_presence(fw_data->p15_card->card->reader); + if (rc <= 0 || rc & SC_READER_CARD_CHANGED) { +diff --git a/src/pkcs11/slot.c b/src/pkcs11/slot.c +index fe322e68e..3102bf986 100644 +--- a/src/pkcs11/slot.c ++++ b/src/pkcs11/slot.c +@@ -374,10 +374,10 @@ CK_RV card_detect(sc_reader_t *reader) + + fail: + if (free_p11card) { +- if (p11card->card != NULL) +- sc_disconnect_card(p11card->card); + if (p11card->framework) + p11card->framework->unbind(p11card); ++ if (p11card->card != NULL) ++ sc_disconnect_card(p11card->card); + free(p11card); + } + +From 2fd8e278f5d3664555cad706d7270229c87cae56 Mon Sep 17 00:00:00 2001 +From: Doug Engert +Date: Wed, 17 Oct 2018 16:07:20 -0500 +Subject: [PATCH] pkcs11/openssl.c - add missing mechanisms fixes #1497 + + On branch pkcs11-openssl-c + Changes to be committed: + modified: ../pkcs11/openssl.c +--- + src/pkcs11/openssl.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/src/pkcs11/openssl.c b/src/pkcs11/openssl.c +index 00b9814e4..fb9f8fea8 100644 +--- a/src/pkcs11/openssl.c ++++ b/src/pkcs11/openssl.c +@@ -449,6 +449,8 @@ CK_RV sc_pkcs11_verify_data(const unsigned char *pubkey, int pubkey_len, + return CKR_GENERAL_ERROR; + + if (md != NULL && (mech->mechanism == CKM_SHA1_RSA_PKCS ++ || mech->mechanism == CKM_MD5_RSA_PKCS ++ || mech->mechanism == CKM_RIPEMD160_RSA_PKCS + || mech->mechanism == CKM_SHA224_RSA_PKCS + || mech->mechanism == CKM_SHA256_RSA_PKCS + || mech->mechanism == CKM_SHA384_RSA_PKCS +@@ -478,6 +480,8 @@ CK_RV sc_pkcs11_verify_data(const unsigned char *pubkey, int pubkey_len, + sc_log(context, "Trying to verify using low-level API"); + switch (mech->mechanism) { + case CKM_RSA_PKCS: ++ case CKM_MD5_RSA_PKCS: ++ case CKM_RIPEMD160_RSA_PKCS: + pad = RSA_PKCS1_PADDING; + break; + case CKM_RSA_X_509: + + +From 9b289e074bff22f7e2339b7d3f9428c3233efb71 Mon Sep 17 00:00:00 2001 +From: Jakub Jelen +Date: Wed, 31 Oct 2018 11:46:37 +0100 +Subject: [PATCH 2/7] coolkey: Check return values from list initialization + (coverity) + +>>> CID 324484: Error handling issues (CHECKED_RETURN) +>>> Calling "list_init" without checking return value (as is done elsewhere 8 out of 9 times). +--- + src/libopensc/card-coolkey.c | 13 ++++++++++--- + 1 file changed, 10 insertions(+), 3 deletions(-) + +diff --git a/src/libopensc/card-coolkey.c b/src/libopensc/card-coolkey.c +index c1c09b662..e320290df 100644 +--- a/src/libopensc/card-coolkey.c ++++ b/src/libopensc/card-coolkey.c +@@ -784,18 +784,25 @@ size_t coolkey_list_meter(const void *el) { + return sizeof(sc_cardctl_coolkey_object_t); + } + ++static void coolkey_free_private_data(coolkey_private_data_t *priv); ++ + static coolkey_private_data_t *coolkey_new_private_data(void) + { + coolkey_private_data_t *priv; ++ + /* allocate priv and zero all the fields */ + priv = calloc(1, sizeof(coolkey_private_data_t)); + if (!priv) + return NULL; ++ + /* set other fields as appropriate */ + priv->key_id = COOLKEY_INVALID_KEY; +- list_init(&priv->objects_list); +- list_attributes_comparator(&priv->objects_list, coolkey_compare_id); +- list_attributes_copy(&priv->objects_list, coolkey_list_meter, 1); ++ if (list_init(&priv->objects_list) != 0 || ++ list_attributes_comparator(&priv->objects_list, coolkey_compare_id) != 0 || ++ list_attributes_copy(&priv->objects_list, coolkey_list_meter, 1) != 0) { ++ coolkey_free_private_data(priv); ++ return NULL; ++ } + + return priv; + } + +From a32fbd0525ea6e21e73b03086e29862481761848 Mon Sep 17 00:00:00 2001 +From: Jakub Jelen +Date: Wed, 31 Oct 2018 15:02:00 +0100 +Subject: [PATCH 3/7] framework-pkcs15.c: Reformat + + * Reasonable line lengths + * Correct indentation + * Add missing SHA224 mechanism +--- + src/pkcs11/framework-pkcs15.c | 40 +++++++++++++++++++++++------------ + 1 file changed, 26 insertions(+), 14 deletions(-) + +diff --git a/src/pkcs11/framework-pkcs15.c b/src/pkcs11/framework-pkcs15.c +index 85e12df66..3657bcbdd 100644 +--- a/src/pkcs11/framework-pkcs15.c ++++ b/src/pkcs11/framework-pkcs15.c +@@ -5159,18 +5159,14 @@ register_mechanisms(struct sc_pkcs11_card *p11card) + } + + #ifdef ENABLE_OPENSSL +- /* all our software hashes are in OpenSSL */ +- /* Only if card did not list the hashes, will we +- * help it a little, by adding all the OpenSSL hashes +- * that have PKCS#11 mechanisms. +- */ +- if (!(rsa_flags & SC_ALGORITHM_RSA_HASHES)) { +- rsa_flags |= SC_ALGORITHM_RSA_HASHES; +-#if OPENSSL_VERSION_NUMBER < 0x00908000L +- /* turn off hashes not in openssl 0.9.8 */ +- rsa_flags &= ~(SC_ALGORITHM_RSA_HASH_SHA256 | SC_ALGORITHM_RSA_HASH_SHA384 | SC_ALGORITHM_RSA_HASH_SHA512 | SC_ALGORITHM_RSA_HASH_SHA224); +-#endif +- } ++ /* all our software hashes are in OpenSSL */ ++ /* Only if card did not list the hashes, will we ++ * help it a little, by adding all the OpenSSL hashes ++ * that have PKCS#11 mechanisms. ++ */ ++ if (!(rsa_flags & SC_ALGORITHM_RSA_HASHES)) { ++ rsa_flags |= SC_ALGORITHM_RSA_HASHES; ++ } + #endif + + /* No need to Check for PKCS1 We support it in software and turned it on above so always added it */ +@@ -5182,32 +5182,44 @@ register_mechanisms(struct sc_pkcs11_card *p11card) + * Either the card set the hashes or we helped it above */ + + if (rsa_flags & SC_ALGORITHM_RSA_HASH_SHA1) { +- rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card, CKM_SHA1_RSA_PKCS, CKM_SHA_1, mt); ++ rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card, ++ CKM_SHA1_RSA_PKCS, CKM_SHA_1, mt); ++ if (rc != CKR_OK) ++ return rc; ++ } ++ if (rsa_flags & SC_ALGORITHM_RSA_HASH_SHA224) { ++ rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card, ++ CKM_SHA224_RSA_PKCS, CKM_SHA224, mt); + if (rc != CKR_OK) + return rc; + } + if (rsa_flags & SC_ALGORITHM_RSA_HASH_SHA256) { +- rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card, CKM_SHA256_RSA_PKCS, CKM_SHA256, mt); ++ rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card, ++ CKM_SHA256_RSA_PKCS, CKM_SHA256, mt); + if (rc != CKR_OK) + return rc; + } + if (rsa_flags & SC_ALGORITHM_RSA_HASH_SHA384) { +- rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card, CKM_SHA384_RSA_PKCS, CKM_SHA384, mt); ++ rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card, ++ CKM_SHA384_RSA_PKCS, CKM_SHA384, mt); + if (rc != CKR_OK) + return rc; + } + if (rsa_flags & SC_ALGORITHM_RSA_HASH_SHA512) { +- rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card, CKM_SHA512_RSA_PKCS, CKM_SHA512, mt); ++ rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card, ++ CKM_SHA512_RSA_PKCS, CKM_SHA512, mt); + if (rc != CKR_OK) + return rc; + } + if (rsa_flags & SC_ALGORITHM_RSA_HASH_MD5) { +- rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card, CKM_MD5_RSA_PKCS, CKM_MD5, mt); ++ rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card, ++ CKM_MD5_RSA_PKCS, CKM_MD5, mt); + if (rc != CKR_OK) + return rc; + } + if (rsa_flags & SC_ALGORITHM_RSA_HASH_RIPEMD160) { +- rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card, CKM_RIPEMD160_RSA_PKCS, CKM_RIPEMD160, mt); ++ rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card, ++ CKM_RIPEMD160_RSA_PKCS, CKM_RIPEMD160, mt); + if (rc != CKR_OK) + return rc; + } + +From 7461c259c96f086621a35baeb699cf3cdc2968dd Mon Sep 17 00:00:00 2001 +From: Jakub Jelen +Date: Wed, 31 Oct 2018 15:03:40 +0100 +Subject: [PATCH 4/7] framework-pkcs15.c: Add PKCS#1 mechanisms also if + SC_ALGORITHM_RSA_HASH_NONE is defined + +--- + src/pkcs11/framework-pkcs15.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/pkcs11/framework-pkcs15.c b/src/pkcs11/framework-pkcs15.c +index 3657bcbdd..cac39b821 100644 +--- a/src/pkcs11/framework-pkcs15.c ++++ b/src/pkcs11/framework-pkcs15.c +@@ -5164,7 +5164,7 @@ register_mechanisms(struct sc_pkcs11_card *p11card) + * help it a little, by adding all the OpenSSL hashes + * that have PKCS#11 mechanisms. + */ +- if (!(rsa_flags & SC_ALGORITHM_RSA_HASHES)) { ++ if (!(rsa_flags & (SC_ALGORITHM_RSA_HASHES & ~SC_ALGORITHM_RSA_HASH_NONE))) { + rsa_flags |= SC_ALGORITHM_RSA_HASHES; + } + #endif + +From 56a9dab5c0a3bc91175266296a70aea94cb5747b Mon Sep 17 00:00:00 2001 +From: Jakub Jelen +Date: Wed, 31 Oct 2018 15:35:25 +0100 +Subject: [PATCH 5/7] p11test: Do not report incomplete key pairs + +--- + src/tests/p11test/p11test_case_pss_oaep.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/src/tests/p11test/p11test_case_pss_oaep.c b/src/tests/p11test/p11test_case_pss_oaep.c +index d0b8392fd..019471192 100644 +--- a/src/tests/p11test/p11test_case_pss_oaep.c ++++ b/src/tests/p11test/p11test_case_pss_oaep.c +@@ -815,6 +815,10 @@ void pss_oaep_test(void **state) { + for (i = 0; i < objects.count; i++) { + test_cert_t *o = &objects.data[i]; + ++ /* Do not go through incomplete pairs */ ++ if (o->private_handle == CK_INVALID_HANDLE) ++ continue; ++ + /* Do not list non-RSA keys here */ + if (o->type != EVP_PK_RSA) + continue; + +From 21d6d8092c98e572c89853593f3f680d219a06d9 Mon Sep 17 00:00:00 2001 +From: Jakub Jelen +Date: Wed, 31 Oct 2018 15:39:56 +0100 +Subject: [PATCH 6/7] framework-pkcs15.c: Add SHA224 mechanism for PKCS#1.5 + +--- + src/pkcs11/framework-pkcs15.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/src/pkcs11/framework-pkcs15.c b/src/pkcs11/framework-pkcs15.c +index cac39b821..6948e31d4 100644 +--- a/src/pkcs11/framework-pkcs15.c ++++ b/src/pkcs11/framework-pkcs15.c +@@ -3781,6 +3781,9 @@ pkcs15_prkey_sign(struct sc_pkcs11_session *session, void *obj, + case CKM_SHA1_RSA_PKCS: + flags = SC_ALGORITHM_RSA_PAD_PKCS1 | SC_ALGORITHM_RSA_HASH_SHA1; + break; ++ case CKM_SHA224_RSA_PKCS: ++ flags = SC_ALGORITHM_RSA_PAD_PKCS1 | SC_ALGORITHM_RSA_HASH_SHA224; ++ break; + case CKM_SHA256_RSA_PKCS: + flags = SC_ALGORITHM_RSA_PAD_PKCS1 | SC_ALGORITHM_RSA_HASH_SHA256; + break; + +From 7d4fa67efc22bf085863ead342b9fc55513425f1 Mon Sep 17 00:00:00 2001 +From: Jakub Jelen +Date: Wed, 31 Oct 2018 17:50:08 +0100 +Subject: [PATCH 7/7] padding: Fix error checking in RSA-PSS + +--- + src/libopensc/padding.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/libopensc/padding.c b/src/libopensc/padding.c +index 75c92b651..f0e2263b8 100644 +--- a/src/libopensc/padding.c ++++ b/src/libopensc/padding.c +@@ -345,7 +345,7 @@ static int sc_pkcs1_add_pss_padding(unsigned int hash, unsigned int mgf1_hash, + if (EVP_DigestInit_ex(ctx, mgf1_md, NULL) != 1 || + EVP_DigestUpdate(ctx, out + dblen, hlen) != 1 || /* H (Z parameter of MGF1) */ + EVP_DigestUpdate(ctx, buf, 4) != 1 || /* C */ +- EVP_DigestFinal_ex(ctx, mask, NULL)) { ++ EVP_DigestFinal_ex(ctx, mask, NULL) != 1) { + goto done; + } + /* this is no longer part of the MGF1, but actually + +From e5d8395a7b8e5d6d1493d893c31fac321f45433a Mon Sep 17 00:00:00 2001 +From: Jakub Jelen +Date: Tue, 20 Nov 2018 09:29:53 +0100 +Subject: [PATCH] pkcs11-tool: Unbreak signature and verification in + pkcs11-tool + +--- + src/tools/pkcs11-tool.c | 25 +++++++++++-------------- + 1 file changed, 11 insertions(+), 14 deletions(-) + +diff --git a/src/tools/pkcs11-tool.c b/src/tools/pkcs11-tool.c +index df4a0ef3..ff1c00ac 100644 +--- a/src/tools/pkcs11-tool.c ++++ b/src/tools/pkcs11-tool.c +@@ -1758,6 +1758,9 @@ parse_pss_params(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE key, + pss_params->hashAlg = CKM_SHA512; + pss_params->mgf = CKG_MGF1_SHA512; + break; ++ ++ default: /* The non-RSA-PSS algorithms do not need any parameters */ ++ return 0; + } + + /* One of RSA-PSS mechanisms above: They need parameters */ +@@ -1820,8 +1823,6 @@ static void sign_data(CK_SLOT_ID slot, CK_SESSION_HANDLE session, + memset(&mech, 0, sizeof(mech)); + mech.mechanism = opt_mechanism; + hashlen = parse_pss_params(session, key, &mech, &pss_params); +- if (hashlen == 0) +- util_fatal("Invalid RSA-PSS parameters"); + + if (opt_input == NULL) + fd = 0; +@@ -1832,11 +1833,10 @@ static void sign_data(CK_SLOT_ID slot, CK_SESSION_HANDLE session, + if (r < 0) + util_fatal("Cannot read from %s: %m", opt_input); + +- if (opt_mechanism == CKM_RSA_PKCS_PSS) { +- if ((unsigned long)r != hashlen) +- util_fatal("For %s mechanism, message size (got %d bytes) " +- "must be equal to specified digest length (%lu)\n", +- p11_mechanism_to_name(opt_mechanism), r, hashlen); ++ if (opt_mechanism == CKM_RSA_PKCS_PSS && (unsigned long)r != hashlen) { ++ util_fatal("For %s mechanism, message size (got %d bytes) " ++ "must be equal to specified digest length (%lu)\n", ++ p11_mechanism_to_name(opt_mechanism), r, hashlen); + } + + rv = CKR_CANCEL; +@@ -1927,8 +1927,6 @@ static void verify_signature(CK_SLOT_ID slot, CK_SESSION_HANDLE session, + memset(&mech, 0, sizeof(mech)); + mech.mechanism = opt_mechanism; + hashlen = parse_pss_params(session, key, &mech, &pss_params); +- if (hashlen == 0) +- util_fatal("Invalid RSA-PSS parameters"); + + /* Open a signature file */ + if (opt_signature_file == NULL) +@@ -1952,11 +1950,10 @@ static void verify_signature(CK_SLOT_ID slot, CK_SESSION_HANDLE session, + if (r < 0) + util_fatal("Cannot read from %s: %m", opt_input); + +- if (opt_mechanism == CKM_RSA_PKCS_PSS) { +- if ((unsigned long)r != hashlen) +- util_fatal("For %s mechanism, message size (got %d bytes)" +- " must be equal to specified digest length (%lu)\n", +- p11_mechanism_to_name(opt_mechanism), r, hashlen); ++ if (opt_mechanism == CKM_RSA_PKCS_PSS && (unsigned long)r != hashlen) { ++ util_fatal("For %s mechanism, message size (got %d bytes)" ++ " must be equal to specified digest length (%lu)\n", ++ p11_mechanism_to_name(opt_mechanism), r, hashlen); + } + + rv = CKR_CANCEL; +-- +2.19.1 diff --git a/opensc.changes b/opensc.changes index 6fa121e..ea29509 100644 --- a/opensc.changes +++ b/opensc.changes @@ -1,3 +1,15 @@ +------------------------------------------------------------------- +Tue Jul 30 03:15:14 UTC 2019 - Jason Sikes + +- added opensc-0.19.0-rsa-pss.patch + * Fixes the pkcs11-tool example + * Added missing CKM_SHA224_RSA_PKCS_PSS + * Add support for PSS padding to RSA signatures + * Support for signature verification in pkcs11-tool + * Switch cleanup steps to avoid segfaults on errors and more sanity checking +- added opensc-0.19.0-redundant_logging.patch + * Remove redundant debug output + ------------------------------------------------------------------- Tue Jul 23 21:51:42 UTC 2019 - Benjamin Greiner diff --git a/opensc.spec b/opensc.spec index 46da967..af124a5 100644 --- a/opensc.spec +++ b/opensc.spec @@ -30,6 +30,8 @@ Source2: %{name}-rpmlintrc # Register with p11-kit # https://web.archive.org/web/20111225073733/http://www.opensc-project.org/opensc/ticket/390 Source3: opensc.module +Patch1: opensc-0.19.0-rsa-pss.patch +Patch2: opensc-0.19.0-redundant_logging.patch BuildRequires: docbook-xsl-stylesheets BuildRequires: libtool BuildRequires: libxslt @@ -60,6 +62,8 @@ may require third party proprietary software. %prep %setup -q +%patch1 -p1 +%patch2 -p1 %build autoreconf -fvi