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>
This commit is contained in:
Nicholas Wilson 2015-08-25 12:45:27 +01:00 committed by Frank Morgner
parent be2cc38565
commit e5707b545e
11 changed files with 678 additions and 161 deletions

View File

@ -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 {

View File

@ -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 {

View File

@ -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

View File

@ -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

View File

@ -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");
}

View File

@ -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);
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");
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))

View File

@ -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,51 +3704,42 @@ 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)
// 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;
case CKM_SHA256:
if (hlen != 32)
return CKR_MECHANISM_PARAM_INVALID;
break;
default:
return CKR_MECHANISM_PARAM_INVALID;
}
// 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;
break;
case CKG_MGF1_SHA256:
if (hlen != 32)
return CKR_MECHANISM_PARAM_INVALID;
break;
default:
return CKR_MECHANISM_PARAM_INVALID;
}
// SmartCards typically support only a salt length equal to the hash length
if (pss_param->sLen != hlen)
return CKR_MECHANISM_PARAM_INVALID;
/* other aspects of pss params were already verified during SignInit */
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:
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 -1;
}
}
static CK_RV
@ -3798,36 +3790,75 @@ 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_RSA_PKCS_PSS:
rv = pkcs15_prkey_check_pss_param(pMechanism, (int)ulDataLen);
if (rv != CKR_OK)
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;
flags = SC_ALGORITHM_RSA_PAD_PSS | SC_ALGORITHM_RSA_HASH_SHA1;
break;
case CKM_SHA256_RSA_PKCS_PSS:
rv = pkcs15_prkey_check_pss_param(pMechanism, 32);
if (rv != CKR_OK)
return rv;
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;
break;
case CKM_RSA_PKCS_PSS:
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;
}
/* 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;
}
/* 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_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:
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;
}
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;
}
/* 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;
break;
@ -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;
}

View File

@ -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:

View File

@ -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 */
};
static sc_pkcs11_mechanism_type_t openssl_sha256_mech = {
CKM_SHA256,
{ 0, 0, CKF_DIGEST },
@ -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));
openssl_sha256_mech.mech_data = EVP_sha256();
sc_pkcs11_register_mechanism(p11card, dup_mem(&openssl_sha256_mech, sizeof openssl_sha256_mech));
openssl_sha384_mech.mech_data = EVP_sha384();
@ -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

View File

@ -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 {

View File

@ -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