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 <jjelen@redhat.com>
+Date: Sun, 22 Jul 2018 16:23:54 +0200
+Subject: [PATCH 1/5] doc: Fix the pkcs11-tool example
+
+Signed-off-by: Jakub Jelen <jjelen@redhat.com>
+---
+ 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 <replaceable>KEY_ID</replaceable>
+ 			in DER format from smart card:
+-				<programlisting>pkcs11-tool --read-object  --id KEY_ID --type cert --outfile cert.der</programlisting>
++				<programlisting>pkcs11-tool --read-object  --id KEY_ID --type cert --output-file cert.der</programlisting>
+ 
+ 			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 <jjelen@redhat.com>
+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 <jjelen@redhat.com>
+---
+ 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 <nicholas.wilson@realvnc.com>
+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 <jjelen@redhat.com> 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 <jjelen@redhat.com>
+---
+ 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 <openssl/evp.h>
++#include <openssl/rand.h>
++#include <openssl/sha.h>
++#endif
++
+ #include <string.h>
+ #include <stdlib.h>
+ 
+@@ -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 <jjelen@redhat.com>
+Date: Sun, 22 Jul 2018 16:29:19 +0200
+Subject: [PATCH 4/5] pkcs11-tool: Support for signature verification
+
+Signed-off-by: Jakub Jelen <jjelen@redhat.com>
+---
+ 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.</para></listitem>
+ 				</varlistentry>
+ 
++				<varlistentry>
++					<term>
++						<option>--verify</option>,
++					</term>
++					<listitem><para>Verify signature of some data.</para></listitem>
++				</varlistentry>
++
+ 				<varlistentry>
+ 					<term>
+ 						<option>--read-object</option>,
+@@ -530,6 +537,13 @@
+ 					<option>--type</option> cert/privkey/pubkey).</para></listitem>
+ 				</varlistentry>
+ 
++				<varlistentry>
++					<term>
++						<option>--signature-file</option> <replaceable>filename</replaceable>
++					</term>
++					<listitem><para>The path to the signature file for signature verification</para></listitem>
++				</varlistentry>
++
+ 				<varlistentry>
+ 					<term>
+ 						<option>--signature-format</option> <replaceable>format</replaceable>
+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, <args>= the (new) CKA_ID",
+ 	"Use <arg> 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 <arg>: '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 <jjelen@redhat.com>
+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 <jjelen@redhat.com>
+---
+ 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 <deengert@gmail.com>
+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 <jjelen@redhat.com>
+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 <jjelen@redhat.com>
+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 <jjelen@redhat.com>
+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 <jjelen@redhat.com>
+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 <jjelen@redhat.com>
+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 <jjelen@redhat.com>
+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 <jjelen@redhat.com>
+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 <jsikes@suse.de>
+
+- 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 <code@bnavigator.de>
 
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