PKCS#11 does not define a CKA_VALUE for public keys and is missused

OpenSC opennssl.c in sc_pkcs11_verify_data assumes that it can
retieve the CKA_VALUE for a public key object, and expect it to
be usable as RSA.

But internally sc_pkcs15_pubkey can have a "raw" or "spki"
version of the public key as defined by PKCS#15.  Card drivers
or pkcs15-<card> routines may store either the "raw" or "spki"
versions. A get attribute request for CKA_VALUE for a public key
will return either the raw, spki or will derived rsa verison of the
pubkey.

This commit will test if the CKA_VALUE is a spki and use d2i_PUBKEY
which takes a spki version and returns an EVP_KEY. If it not an spki
the current method, d21_PublicKey(EVP_PKEY_RSA,...) is used which
only works for RSA.

The problem was found while testing pkcs11-tool -t -l  where
the  verify tests would fail with a CKR_GENERAL_ERROR because
the card driver stored the public key as a spki.

On branch verify-pubkey-as-spki-2
 Changes to be committed:
	modified:   src/pkcs11/openssl.c

Date:      Fri Apr 07 07:50:00 2017 -0600
This commit is contained in:
Doug Engert 2017-03-11 11:49:49 -06:00 committed by Frank Morgner
parent f5aa3f5cc6
commit d48f438581
1 changed files with 36 additions and 2 deletions

View File

@ -405,7 +405,9 @@ CK_RV sc_pkcs11_verify_data(const unsigned char *pubkey, int pubkey_len,
{
int res;
CK_RV rv = CKR_GENERAL_ERROR;
EVP_PKEY *pkey;
EVP_PKEY *pkey = NULL;
const unsigned char *pubkey_tmp;
int is_spki = 0;
if (mech == CKM_GOSTR3410)
{
@ -419,7 +421,38 @@ CK_RV sc_pkcs11_verify_data(const unsigned char *pubkey, int pubkey_len,
#endif
}
pkey = d2i_PublicKey(EVP_PKEY_RSA, NULL, &pubkey, pubkey_len);
/*
* PKCS#11 does not define CKA_VALUE for public keys, and different cards
* return either the raw or spki versions as defined in PKCS#15
* And we need to support more then just RSA.
* We can use d2i_PUBKEY which works for SPKI and any key type.
*/
pubkey_tmp = pubkey; /* pass in so pubkey pointer is not modified */
/* SPKI ASN.1 starts with SEQUENCE, SEQUENCE, OBJECT IDENTIFIER */
if (*pubkey_tmp++ == 0x30) {
if (*pubkey_tmp & 0x80)
pubkey_tmp += *pubkey_tmp & 0x7F;
pubkey_tmp++;
if (*pubkey_tmp++ == 0x30) {
if (*pubkey_tmp & 0x80)
pubkey_tmp += *pubkey_tmp & 0x7F;
pubkey_tmp += 1;
if (*pubkey_tmp == 0x06)
is_spki = 1;
}
}
pubkey_tmp = pubkey; /* pass in so pubkey pointer is not modified */
if (is_spki) {
pkey = d2i_PUBKEY(NULL, &pubkey_tmp, pubkey_len);
}else {
/* Assume it is RSA */
/* TODO support others but GOST is done above, and EC always uses SPKI */
pkey = d2i_PublicKey(EVP_PKEY_RSA, NULL, &pubkey_tmp, pubkey_len);
}
if (pkey == NULL)
return CKR_GENERAL_ERROR;
@ -449,6 +482,7 @@ CK_RV sc_pkcs11_verify_data(const unsigned char *pubkey, int pubkey_len,
case CKM_RSA_X_509:
pad = RSA_NO_PADDING;
break;
/* TODO support more then RSA */
default:
EVP_PKEY_free(pkey);
return CKR_ARGUMENTS_BAD;