From d48f4385815314262e5c2de2fa693291ea8a2bb0 Mon Sep 17 00:00:00 2001 From: Doug Engert Date: Sat, 11 Mar 2017 11:49:49 -0600 Subject: [PATCH] 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- 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 --- src/pkcs11/openssl.c | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/src/pkcs11/openssl.c b/src/pkcs11/openssl.c index d16d3290..77ce28d7 100644 --- a/src/pkcs11/openssl.c +++ b/src/pkcs11/openssl.c @@ -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;