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;