Implemented the C_VerifyXXX() functions
git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@1236 c6295689-39f2-0310-b995-f0e70906c6a9
This commit is contained in:
parent
b7d92d3127
commit
7b7f2106f2
|
@ -2143,6 +2143,9 @@ register_mechanisms(struct sc_pkcs11_card *p11card)
|
|||
sc_pkcs11_register_generic_mechanisms(p11card);
|
||||
|
||||
mech_info.flags = CKF_HW | CKF_SIGN | CKF_UNWRAP;
|
||||
#ifdef HAVE_OPENSSL
|
||||
mech_info.flags |= CKF_VERIFY;
|
||||
#endif
|
||||
mech_info.ulMinKeySize = ~0;
|
||||
mech_info.ulMaxKeySize = 0;
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include <string.h>
|
||||
#include "sc-pkcs11.h"
|
||||
|
||||
/* Also used for verification data */
|
||||
struct hash_signature_info {
|
||||
CK_MECHANISM_TYPE mech;
|
||||
CK_MECHANISM_TYPE hash_mech;
|
||||
|
@ -16,6 +17,7 @@ struct hash_signature_info {
|
|||
sc_pkcs11_mechanism_type_t *sign_type;
|
||||
};
|
||||
|
||||
/* Also used for verification data */
|
||||
struct signature_data {
|
||||
struct sc_pkcs11_object *key;
|
||||
struct hash_signature_info *info;
|
||||
|
@ -412,6 +414,177 @@ sc_pkcs11_signature_release(sc_pkcs11_operation_t *operation)
|
|||
free(data);
|
||||
}
|
||||
|
||||
#ifdef HAVE_OPENSSL
|
||||
/*
|
||||
* Initialize a verify context. When we get here, we know
|
||||
* the key object is capable of verifying _something_
|
||||
*/
|
||||
CK_RV
|
||||
sc_pkcs11_verif_init(struct sc_pkcs11_session *session,
|
||||
CK_MECHANISM_PTR pMechanism,
|
||||
struct sc_pkcs11_object *key,
|
||||
CK_MECHANISM_TYPE key_type)
|
||||
{
|
||||
struct sc_pkcs11_card *p11card;
|
||||
sc_pkcs11_operation_t *operation;
|
||||
sc_pkcs11_mechanism_type_t *mt;
|
||||
int rv;
|
||||
|
||||
if (!session || !session->slot
|
||||
|| !(p11card = session->slot->card))
|
||||
return CKR_ARGUMENTS_BAD;
|
||||
|
||||
/* See if we support this mechanism type */
|
||||
mt = sc_pkcs11_find_mechanism(p11card, pMechanism->mechanism, CKF_VERIFY);
|
||||
if (mt == NULL)
|
||||
return CKR_MECHANISM_INVALID;
|
||||
|
||||
/* See if compatible with key type */
|
||||
if (mt->key_type != key_type)
|
||||
return CKR_KEY_TYPE_INCONSISTENT;
|
||||
|
||||
rv = session_start_operation(session, SC_PKCS11_OPERATION_VERIFY, mt, &operation);
|
||||
if (rv != CKR_OK)
|
||||
return rv;
|
||||
|
||||
memcpy(&operation->mechanism, pMechanism, sizeof(CK_MECHANISM));
|
||||
return mt->verif_init(operation, key);
|
||||
}
|
||||
|
||||
CK_RV
|
||||
sc_pkcs11_verif_update(struct sc_pkcs11_session *session,
|
||||
CK_BYTE_PTR pData, CK_ULONG ulDataLen)
|
||||
{
|
||||
sc_pkcs11_operation_t *op;
|
||||
int rv;
|
||||
|
||||
rv = session_get_operation(session, SC_PKCS11_OPERATION_VERIFY, &op);
|
||||
if (rv != CKR_OK)
|
||||
return rv;
|
||||
|
||||
if (op->type->verif_update == NULL)
|
||||
return CKR_KEY_TYPE_INCONSISTENT;
|
||||
|
||||
return op->type->verif_update(op, pData, ulDataLen);
|
||||
}
|
||||
|
||||
CK_RV
|
||||
sc_pkcs11_verif_final(struct sc_pkcs11_session *session,
|
||||
CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen)
|
||||
{
|
||||
sc_pkcs11_operation_t *op;
|
||||
int rv;
|
||||
|
||||
rv = session_get_operation(session, SC_PKCS11_OPERATION_VERIFY, &op);
|
||||
if (rv != CKR_OK)
|
||||
return rv;
|
||||
|
||||
if (op->type->verif_final == NULL)
|
||||
return CKR_KEY_TYPE_INCONSISTENT;
|
||||
|
||||
rv = op->type->verif_final(op, pSignature, ulSignatureLen);
|
||||
|
||||
session_stop_operation(session, SC_PKCS11_OPERATION_VERIFY);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize a signature operation
|
||||
*/
|
||||
static CK_RV
|
||||
sc_pkcs11_verify_init(sc_pkcs11_operation_t *operation,
|
||||
struct sc_pkcs11_object *key)
|
||||
{
|
||||
struct hash_signature_info *info;
|
||||
struct signature_data *data;
|
||||
int rv;
|
||||
|
||||
if (!(data = (struct signature_data *) calloc(1, sizeof(*data))))
|
||||
return CKR_HOST_MEMORY;
|
||||
|
||||
data->info = NULL;
|
||||
data->key = key;
|
||||
|
||||
/* If this is a verify with hash operation, set up the
|
||||
* hash operation */
|
||||
info = (struct hash_signature_info *) operation->type->mech_data;
|
||||
if (info != NULL) {
|
||||
/* Initialize hash operation */
|
||||
data->md = sc_pkcs11_new_operation(operation->session,
|
||||
info->hash_type);
|
||||
if (data->md == NULL)
|
||||
rv = CKR_HOST_MEMORY;
|
||||
else
|
||||
rv = info->hash_type->md_init(data->md);
|
||||
if (rv != CKR_OK) {
|
||||
sc_pkcs11_release_operation(&data->md);
|
||||
free(data);
|
||||
return rv;
|
||||
}
|
||||
data->info = info;
|
||||
}
|
||||
|
||||
operation->priv_data = data;
|
||||
return CKR_OK;
|
||||
}
|
||||
|
||||
static CK_RV
|
||||
sc_pkcs11_verify_update(sc_pkcs11_operation_t *operation,
|
||||
CK_BYTE_PTR pPart, CK_ULONG ulPartLen)
|
||||
{
|
||||
struct signature_data *data;
|
||||
|
||||
data = (struct signature_data *) operation->priv_data;
|
||||
if (data->md) {
|
||||
sc_pkcs11_operation_t *md = data->md;
|
||||
|
||||
return md->type->md_update(md, pPart, ulPartLen);
|
||||
}
|
||||
|
||||
/* This verification mechanism operates on the raw data */
|
||||
if (data->buffer_len + ulPartLen > sizeof(data->buffer))
|
||||
return CKR_DATA_LEN_RANGE;
|
||||
memcpy(data->buffer + data->buffer_len, pPart, ulPartLen);
|
||||
data->buffer_len += ulPartLen;
|
||||
return CKR_OK;
|
||||
}
|
||||
|
||||
static CK_RV
|
||||
sc_pkcs11_verify_final(sc_pkcs11_operation_t *operation,
|
||||
CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen)
|
||||
{
|
||||
struct signature_data *data;
|
||||
struct sc_pkcs11_object *key;
|
||||
unsigned char *pubkey_value;
|
||||
CK_ATTRIBUTE attr = {CKA_VALUE, NULL, 0};
|
||||
int rv;
|
||||
|
||||
data = (struct signature_data *) operation->priv_data;
|
||||
|
||||
if (pSignature == NULL)
|
||||
return CKR_ARGUMENTS_BAD;
|
||||
|
||||
key = data->key;
|
||||
rv = key->ops->get_attribute(operation->session, key, &attr);
|
||||
if (rv != CKR_OK)
|
||||
return rv;
|
||||
pubkey_value = (unsigned char *) malloc(attr.ulValueLen);
|
||||
attr.pValue = pubkey_value;
|
||||
rv = key->ops->get_attribute(operation->session, key, &attr);
|
||||
if (rv != CKR_OK)
|
||||
goto done;
|
||||
|
||||
rv = sc_pkcs11_verify_data(pubkey_value, attr.ulValueLen,
|
||||
operation->mechanism.mechanism, data->md,
|
||||
data->buffer, data->buffer_len, pSignature, ulSignatureLen);
|
||||
|
||||
done:
|
||||
free(pubkey_value);
|
||||
|
||||
return rv;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Create new mechanism type for a mechanism supported by
|
||||
* the card
|
||||
|
@ -440,6 +613,11 @@ sc_pkcs11_new_fw_mechanism(CK_MECHANISM_TYPE mech,
|
|||
mt->sign_update = sc_pkcs11_signature_update;
|
||||
mt->sign_final = sc_pkcs11_signature_final;
|
||||
mt->sign_size = sc_pkcs11_signature_size;
|
||||
#ifdef HAVE_OPENSSL
|
||||
mt->verif_init = sc_pkcs11_verify_init;
|
||||
mt->verif_update = sc_pkcs11_verify_update;
|
||||
mt->verif_final = sc_pkcs11_verify_final;
|
||||
#endif
|
||||
}
|
||||
if (pInfo->flags & CKF_UNWRAP) {
|
||||
/* ... */
|
||||
|
|
|
@ -235,4 +235,79 @@ sc_pkcs11_gen_keypair_soft(CK_KEY_TYPE keytype, CK_ULONG keybits,
|
|||
|
||||
return CKR_OK;
|
||||
}
|
||||
|
||||
/* If no hash function was used, finish with RSA_public_decrypt().
|
||||
* If a hash function was used, we can make a big shortcut by
|
||||
* finishing with EVP_VerifyFinal().
|
||||
*/
|
||||
CK_RV sc_pkcs11_verify_data(unsigned char *pubkey, int pubkey_len,
|
||||
CK_MECHANISM_TYPE mech, sc_pkcs11_operation_t *md,
|
||||
unsigned char *data, int data_len,
|
||||
unsigned char *signat, int signat_len)
|
||||
{
|
||||
int res;
|
||||
CK_RV rv = CKR_GENERAL_ERROR;
|
||||
EVP_PKEY *pkey;
|
||||
|
||||
pkey = d2i_PublicKey(EVP_PKEY_RSA, NULL, &pubkey, pubkey_len);
|
||||
if (pkey == NULL)
|
||||
return CKR_GENERAL_ERROR;
|
||||
|
||||
|
||||
if (md != NULL) {
|
||||
EVP_MD_CTX *md_ctx = DIGEST_CTX(md);
|
||||
|
||||
res = EVP_VerifyFinal(md_ctx, signat, signat_len, pkey);
|
||||
EVP_PKEY_free(pkey);
|
||||
if (res == 1)
|
||||
return CKR_OK;
|
||||
else if (res == 0)
|
||||
return CKR_SIGNATURE_INVALID;
|
||||
else if (res != 1)
|
||||
return CKR_GENERAL_ERROR;
|
||||
}
|
||||
else {
|
||||
RSA *rsa;
|
||||
unsigned char *rsa_out = NULL, pad;
|
||||
int rsa_outlen = 0;
|
||||
|
||||
switch(mech) {
|
||||
case CKM_RSA_PKCS:
|
||||
pad = RSA_PKCS1_PADDING;
|
||||
break;
|
||||
case CKM_RSA_X_509:
|
||||
pad = RSA_NO_PADDING;
|
||||
break;
|
||||
default:
|
||||
return CKR_ARGUMENTS_BAD;
|
||||
}
|
||||
|
||||
rsa = EVP_PKEY_get1_RSA(pkey);
|
||||
EVP_PKEY_free(pkey);
|
||||
if (rsa == NULL)
|
||||
return CKR_DEVICE_MEMORY;
|
||||
|
||||
rsa_out = (unsigned char *) malloc(RSA_size(rsa));
|
||||
if (rsa_out == NULL) {
|
||||
free(rsa);
|
||||
return CKR_DEVICE_MEMORY;
|
||||
}
|
||||
|
||||
rsa_outlen = RSA_public_decrypt(signat_len, signat, rsa_out, rsa, pad);
|
||||
RSA_free(rsa);
|
||||
if(rsa_outlen <= 0) {
|
||||
free(rsa_out);
|
||||
return CKR_GENERAL_ERROR;
|
||||
}
|
||||
|
||||
if (rsa_outlen == data_len && memcmp(rsa_out, data, data_len) == 0)
|
||||
rv = CKR_OK;
|
||||
else
|
||||
rv = CKR_SIGNATURE_INVALID;
|
||||
|
||||
free(rsa_out);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -476,7 +476,6 @@ CK_RV C_SignInit(CK_SESSION_HANDLE hSession, /* the session's handle */
|
|||
goto out;
|
||||
}
|
||||
|
||||
debug(context, "Sign operation initialized\n");
|
||||
rv = sc_pkcs11_sign_init(session, pMechanism, object, key_type);
|
||||
|
||||
out: debug(context, "Sign initialization returns %d\n", rv);
|
||||
|
@ -915,7 +914,47 @@ CK_RV C_VerifyInit(CK_SESSION_HANDLE hSession, /* the session's handle */
|
|||
CK_MECHANISM_PTR pMechanism, /* the verification mechanism */
|
||||
CK_OBJECT_HANDLE hKey) /* handle of the verification key */
|
||||
{
|
||||
return CKR_FUNCTION_NOT_SUPPORTED;
|
||||
#ifndef HAVE_OPENSSL
|
||||
return CKR_FUNCTION_NOT_SUPPORTED;
|
||||
#else
|
||||
CK_BBOOL can_verify;
|
||||
CK_KEY_TYPE key_type;
|
||||
CK_ATTRIBUTE verify_attribute = { CKA_VERIFY, &can_verify, sizeof(can_verify) };
|
||||
CK_ATTRIBUTE key_type_attr = { CKA_KEY_TYPE, &key_type, sizeof(key_type) };
|
||||
struct sc_pkcs11_session *session;
|
||||
struct sc_pkcs11_object *object;
|
||||
int rv;
|
||||
|
||||
rv = sc_pkcs11_lock();
|
||||
if (rv != CKR_OK)
|
||||
return rv;
|
||||
|
||||
rv = pool_find(&session_pool, hSession, (void**) &session);
|
||||
if (rv != CKR_OK)
|
||||
goto out;
|
||||
|
||||
rv = pool_find(&session->slot->object_pool, hKey, (void**) &object);
|
||||
if (rv != CKR_OK)
|
||||
goto out;
|
||||
|
||||
//rv = object->ops->get_attribute(session, object, &verify_attribute);
|
||||
//if (rv != CKR_OK || !can_verify) {
|
||||
// rv = CKR_KEY_TYPE_INCONSISTENT;
|
||||
// goto out;
|
||||
//}
|
||||
rv = object->ops->get_attribute(session, object, &key_type_attr);
|
||||
if (rv != CKR_OK) {
|
||||
rv = CKR_KEY_TYPE_INCONSISTENT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rv = sc_pkcs11_verif_init(session, pMechanism, object, key_type);
|
||||
|
||||
out: debug(context, "Verify initialization returns %d\n", rv);
|
||||
sc_pkcs11_unlock();
|
||||
|
||||
return rv;
|
||||
#endif
|
||||
}
|
||||
|
||||
CK_RV C_Verify(CK_SESSION_HANDLE hSession, /* the session's handle */
|
||||
|
@ -924,21 +963,79 @@ CK_RV C_Verify(CK_SESSION_HANDLE hSession, /* the session's handle */
|
|||
CK_BYTE_PTR pSignature, /* the signature to be verified */
|
||||
CK_ULONG ulSignatureLen) /* count of bytes of signature */
|
||||
{
|
||||
return CKR_FUNCTION_NOT_SUPPORTED;
|
||||
#ifndef HAVE_OPENSSL
|
||||
return CKR_FUNCTION_NOT_SUPPORTED;
|
||||
#else
|
||||
int rv;
|
||||
struct sc_pkcs11_session *session;
|
||||
|
||||
rv = sc_pkcs11_lock();
|
||||
if (rv != CKR_OK)
|
||||
return rv;
|
||||
|
||||
rv = pool_find(&session_pool, hSession, (void**) &session);
|
||||
if (rv != CKR_OK)
|
||||
goto out;
|
||||
|
||||
rv = sc_pkcs11_verif_update(session, pData, ulDataLen);
|
||||
if (rv == CKR_OK)
|
||||
rv = sc_pkcs11_verif_final(session, pSignature, ulSignatureLen);
|
||||
|
||||
out: debug(context, "Verify result was %d\n", rv);
|
||||
sc_pkcs11_unlock();
|
||||
return rv;
|
||||
#endif
|
||||
}
|
||||
|
||||
CK_RV C_VerifyUpdate(CK_SESSION_HANDLE hSession, /* the session's handle */
|
||||
CK_BYTE_PTR pPart, /* plaintext data (digest) to compare */
|
||||
CK_ULONG ulPartLen) /* length of data (digest) in bytes */
|
||||
{
|
||||
return CKR_FUNCTION_NOT_SUPPORTED;
|
||||
#ifndef HAVE_OPENSSL
|
||||
return CKR_FUNCTION_NOT_SUPPORTED;
|
||||
#else
|
||||
struct sc_pkcs11_session *session;
|
||||
int rv;
|
||||
|
||||
rv = sc_pkcs11_lock();
|
||||
if (rv != CKR_OK)
|
||||
return rv;
|
||||
|
||||
rv = pool_find(&session_pool, hSession, (void**) &session);
|
||||
if (rv == CKR_OK)
|
||||
rv = sc_pkcs11_verif_update(session, pPart, ulPartLen);
|
||||
|
||||
debug(context, "C_VerifyUpdate returns %d\n", rv);
|
||||
sc_pkcs11_unlock();
|
||||
return rv;
|
||||
#endif
|
||||
}
|
||||
|
||||
CK_RV C_VerifyFinal(CK_SESSION_HANDLE hSession, /* the session's handle */
|
||||
CK_BYTE_PTR pSignature, /* the signature to be verified */
|
||||
CK_ULONG ulSignatureLen) /* count of bytes of signature */
|
||||
{
|
||||
return CKR_FUNCTION_NOT_SUPPORTED;
|
||||
#ifndef HAVE_OPENSSL
|
||||
return CKR_FUNCTION_NOT_SUPPORTED;
|
||||
#else
|
||||
struct sc_pkcs11_session *session;
|
||||
int rv;
|
||||
|
||||
rv = sc_pkcs11_lock();
|
||||
if (rv != CKR_OK)
|
||||
return rv;
|
||||
|
||||
rv = pool_find(&session_pool, hSession, (void**) &session);
|
||||
if (rv != CKR_OK)
|
||||
goto out;
|
||||
|
||||
rv = sc_pkcs11_verif_final(session, pSignature, ulSignatureLen);
|
||||
|
||||
out: debug(context, "C_VerifyFinal returns %d\n", rv);
|
||||
sc_pkcs11_unlock();
|
||||
|
||||
return rv;
|
||||
#endif
|
||||
}
|
||||
|
||||
CK_RV C_VerifyRecoverInit(CK_SESSION_HANDLE hSession, /* the session's handle */
|
||||
|
|
|
@ -222,6 +222,7 @@ typedef struct sc_pkcs11_operation sc_pkcs11_operation_t;
|
|||
enum {
|
||||
SC_PKCS11_OPERATION_FIND = 0,
|
||||
SC_PKCS11_OPERATION_SIGN,
|
||||
SC_PKCS11_OPERATION_VERIFY,
|
||||
SC_PKCS11_OPERATION_DIGEST,
|
||||
SC_PKCS11_OPERATION_MAX
|
||||
};
|
||||
|
@ -251,7 +252,14 @@ struct sc_pkcs11_mechanism_type {
|
|||
CK_BYTE_PTR, CK_ULONG_PTR);
|
||||
CK_RV (*sign_size)(sc_pkcs11_operation_t *,
|
||||
CK_ULONG_PTR);
|
||||
|
||||
#ifdef HAVE_OPENSSL
|
||||
CK_RV (*verif_init)(sc_pkcs11_operation_t *,
|
||||
struct sc_pkcs11_object *);
|
||||
CK_RV (*verif_update)(sc_pkcs11_operation_t *,
|
||||
CK_BYTE_PTR, CK_ULONG);
|
||||
CK_RV (*verif_final)(sc_pkcs11_operation_t *,
|
||||
CK_BYTE_PTR, CK_ULONG);
|
||||
#endif
|
||||
/* mechanism specific data */
|
||||
const void * mech_data;
|
||||
};
|
||||
|
@ -371,6 +379,12 @@ CK_RV sc_pkcs11_sign_init(struct sc_pkcs11_session *, CK_MECHANISM_PTR,
|
|||
CK_RV sc_pkcs11_sign_update(struct sc_pkcs11_session *, CK_BYTE_PTR, CK_ULONG);
|
||||
CK_RV sc_pkcs11_sign_final(struct sc_pkcs11_session *, CK_BYTE_PTR, CK_ULONG_PTR);
|
||||
CK_RV sc_pkcs11_sign_size(struct sc_pkcs11_session *, CK_ULONG_PTR);
|
||||
#ifdef HAVE_OPENSSL
|
||||
CK_RV sc_pkcs11_verif_init(struct sc_pkcs11_session *, CK_MECHANISM_PTR,
|
||||
struct sc_pkcs11_object *, CK_MECHANISM_TYPE);
|
||||
CK_RV sc_pkcs11_verif_update(struct sc_pkcs11_session *, CK_BYTE_PTR, CK_ULONG);
|
||||
CK_RV sc_pkcs11_verif_final(struct sc_pkcs11_session *, CK_BYTE_PTR, CK_ULONG);
|
||||
#endif
|
||||
CK_RV sc_pkcs11_sign_hash(struct sc_pkcs11_session *, CK_BYTE_PTR, CK_ULONG,
|
||||
CK_BYTE_PTR, CK_ULONG_PTR);
|
||||
sc_pkcs11_mechanism_type_t *sc_pkcs11_find_mechanism(struct sc_pkcs11_card *,
|
||||
|
@ -395,6 +409,10 @@ CK_RV sc_pkcs11_openssl_add_seed_rand(struct sc_pkcs11_session *, CK_BYTE_PTR, C
|
|||
CK_RV sc_pkcs11_openssl_add_gen_rand(struct sc_pkcs11_session *, CK_BYTE_PTR, CK_ULONG);
|
||||
CK_RV sc_pkcs11_gen_keypair_soft(CK_KEY_TYPE keytype, CK_ULONG keybits,
|
||||
struct sc_pkcs15_prkey *privkey, struct sc_pkcs15_pubkey *pubkey);
|
||||
CK_RV sc_pkcs11_verify_data(unsigned char *pubkey, int pubkey_len,
|
||||
CK_MECHANISM_TYPE mech, sc_pkcs11_operation_t *md,
|
||||
unsigned char *inp, int inp_len,
|
||||
unsigned char *signat, int signat_len);
|
||||
#endif
|
||||
|
||||
/* Load configuration defaults */
|
||||
|
|
Loading…
Reference in New Issue