2002-12-17 11:49:12 +00:00
|
|
|
/*
|
|
|
|
* Generic handling of PKCS11 mechanisms
|
|
|
|
*
|
|
|
|
* Copyright (C) 2002 Olaf Kirch <okir@lst.de>
|
|
|
|
*/
|
|
|
|
|
2010-03-04 08:14:36 +00:00
|
|
|
#include "config.h"
|
|
|
|
|
2003-01-06 23:46:24 +00:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
2010-03-04 08:14:36 +00:00
|
|
|
|
2002-12-17 11:49:12 +00:00
|
|
|
#include "sc-pkcs11.h"
|
|
|
|
|
2003-06-27 15:26:17 +00:00
|
|
|
/* Also used for verification data */
|
2002-12-17 11:49:12 +00:00
|
|
|
struct hash_signature_info {
|
|
|
|
CK_MECHANISM_TYPE mech;
|
|
|
|
CK_MECHANISM_TYPE hash_mech;
|
|
|
|
CK_MECHANISM_TYPE sign_mech;
|
|
|
|
sc_pkcs11_mechanism_type_t *hash_type;
|
|
|
|
sc_pkcs11_mechanism_type_t *sign_type;
|
|
|
|
};
|
|
|
|
|
2003-10-01 06:51:49 +00:00
|
|
|
/* Also used for verification and decryption data */
|
2002-12-17 11:49:12 +00:00
|
|
|
struct signature_data {
|
|
|
|
struct sc_pkcs11_object *key;
|
|
|
|
struct hash_signature_info *info;
|
|
|
|
sc_pkcs11_operation_t * md;
|
|
|
|
CK_BYTE buffer[4096/8];
|
|
|
|
unsigned int buffer_len;
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Register a mechanism
|
|
|
|
*/
|
|
|
|
CK_RV
|
|
|
|
sc_pkcs11_register_mechanism(struct sc_pkcs11_card *p11card,
|
|
|
|
sc_pkcs11_mechanism_type_t *mt)
|
|
|
|
{
|
|
|
|
sc_pkcs11_mechanism_type_t **p;
|
|
|
|
|
|
|
|
if (mt == NULL)
|
|
|
|
return CKR_HOST_MEMORY;
|
|
|
|
|
|
|
|
p = (sc_pkcs11_mechanism_type_t **) realloc(p11card->mechanisms,
|
|
|
|
(p11card->nmechanisms + 2) * sizeof(*p));
|
|
|
|
if (p == NULL)
|
|
|
|
return CKR_HOST_MEMORY;
|
|
|
|
p11card->mechanisms = p;
|
|
|
|
p[p11card->nmechanisms++] = mt;
|
|
|
|
p[p11card->nmechanisms] = NULL;
|
|
|
|
return CKR_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Look up a mechanism
|
|
|
|
*/
|
|
|
|
sc_pkcs11_mechanism_type_t *
|
2010-01-24 20:45:02 +00:00
|
|
|
sc_pkcs11_find_mechanism(struct sc_pkcs11_card *p11card, CK_MECHANISM_TYPE mech, unsigned int flags)
|
2002-12-17 11:49:12 +00:00
|
|
|
{
|
|
|
|
sc_pkcs11_mechanism_type_t *mt;
|
|
|
|
unsigned int n;
|
|
|
|
|
|
|
|
for (n = 0; n < p11card->nmechanisms; n++) {
|
|
|
|
mt = p11card->mechanisms[n];
|
|
|
|
if (mt && mt->mech == mech && ((mt->mech_info.flags & flags) == flags))
|
|
|
|
return mt;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Query mechanisms.
|
2002-12-19 09:27:08 +00:00
|
|
|
* All of this is greatly simplified by having the framework
|
|
|
|
* register all supported mechanisms at initialization
|
|
|
|
* time.
|
2002-12-17 11:49:12 +00:00
|
|
|
*/
|
|
|
|
CK_RV
|
|
|
|
sc_pkcs11_get_mechanism_list(struct sc_pkcs11_card *p11card,
|
|
|
|
CK_MECHANISM_TYPE_PTR pList,
|
|
|
|
CK_ULONG_PTR pulCount)
|
|
|
|
{
|
|
|
|
sc_pkcs11_mechanism_type_t *mt;
|
|
|
|
unsigned int n, count = 0;
|
|
|
|
int rv;
|
|
|
|
|
|
|
|
for (n = 0; n < p11card->nmechanisms; n++) {
|
|
|
|
if (!(mt = p11card->mechanisms[n]))
|
|
|
|
continue;
|
2009-09-14 10:12:24 +00:00
|
|
|
if (pList && count < *pulCount)
|
2002-12-17 11:49:12 +00:00
|
|
|
pList[count] = mt->mech;
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
|
|
|
|
rv = CKR_OK;
|
2002-12-19 09:27:08 +00:00
|
|
|
if (pList && count > *pulCount)
|
2002-12-17 11:49:12 +00:00
|
|
|
rv = CKR_BUFFER_TOO_SMALL;
|
|
|
|
*pulCount = count;
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
CK_RV
|
|
|
|
sc_pkcs11_get_mechanism_info(struct sc_pkcs11_card *p11card,
|
|
|
|
CK_MECHANISM_TYPE mechanism,
|
|
|
|
CK_MECHANISM_INFO_PTR pInfo)
|
|
|
|
{
|
|
|
|
sc_pkcs11_mechanism_type_t *mt;
|
|
|
|
|
|
|
|
if (!(mt = sc_pkcs11_find_mechanism(p11card, mechanism, 0)))
|
|
|
|
return CKR_MECHANISM_INVALID;
|
|
|
|
memcpy(pInfo, &mt->mech_info, sizeof(*pInfo));
|
|
|
|
return CKR_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Create/destroy operation handle
|
|
|
|
*/
|
|
|
|
sc_pkcs11_operation_t *
|
|
|
|
sc_pkcs11_new_operation(sc_pkcs11_session_t *session,
|
|
|
|
sc_pkcs11_mechanism_type_t *type)
|
|
|
|
{
|
|
|
|
sc_pkcs11_operation_t *res;
|
|
|
|
|
Do not cast the return value of malloc(3) and calloc(3)
From http://en.wikipedia.org/wiki/Malloc#Casting_and_type_safety
" Casting and type safety
malloc returns a void pointer (void *), which indicates that it is a
pointer to a region of unknown data type. One may "cast" (see type
conversion) this pointer to a specific type, as in
int *ptr = (int*)malloc(10 * sizeof (int));
When using C, this is considered bad practice; it is redundant under the
C standard. Moreover, putting in a cast may mask failure to include the
header stdlib.h, in which the prototype for malloc is found. In the
absence of a prototype for malloc, the C compiler will assume that
malloc returns an int, and will issue a warning in a context such as the
above, provided the error is not masked by a cast. On certain
architectures and data models (such as LP64 on 64 bit systems, where
long and pointers are 64 bit and int is 32 bit), this error can actually
result in undefined behavior, as the implicitly declared malloc returns
a 32 bit value whereas the actually defined function returns a 64 bit
value. Depending on calling conventions and memory layout, this may
result in stack smashing.
The returned pointer need not be explicitly cast to a more specific
pointer type, since ANSI C defines an implicit conversion between the
void pointer type and other pointers to objects. An explicit cast of
malloc's return value is sometimes performed because malloc originally
returned a char *, but this cast is unnecessary in standard C
code.[4][5] Omitting the cast, however, creates an incompatibility with
C++, which does require it.
The lack of a specific pointer type returned from malloc is type-unsafe
behaviour: malloc allocates based on byte count but not on type. This
distinguishes it from the C++ new operator that returns a pointer whose
type relies on the operand. (see C Type Safety). "
See also
http://www.opensc-project.org/pipermail/opensc-devel/2010-August/014586.html
git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@4636 c6295689-39f2-0310-b995-f0e70906c6a9
2010-08-18 15:08:51 +00:00
|
|
|
res = calloc(1, type->obj_size);
|
2002-12-17 11:49:12 +00:00
|
|
|
if (res) {
|
|
|
|
res->session = session;
|
|
|
|
res->type = type;
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
sc_pkcs11_release_operation(sc_pkcs11_operation_t **ptr)
|
|
|
|
{
|
|
|
|
sc_pkcs11_operation_t *operation = *ptr;
|
|
|
|
|
|
|
|
if (!operation)
|
|
|
|
return;
|
|
|
|
if (operation->type && operation->type->release)
|
|
|
|
operation->type->release(operation);
|
|
|
|
memset(operation, 0, sizeof(*operation));
|
|
|
|
free(operation);
|
|
|
|
*ptr = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
CK_RV
|
|
|
|
sc_pkcs11_md_init(struct sc_pkcs11_session *session,
|
|
|
|
CK_MECHANISM_PTR pMechanism)
|
|
|
|
{
|
|
|
|
struct sc_pkcs11_card *p11card;
|
|
|
|
sc_pkcs11_operation_t *operation;
|
|
|
|
sc_pkcs11_mechanism_type_t *mt;
|
|
|
|
int rv;
|
|
|
|
|
2012-05-26 19:17:39 +00:00
|
|
|
LOG_FUNC_CALLED(context);
|
|
|
|
if (!session || !session->slot || !(p11card = session->slot->card))
|
|
|
|
LOG_FUNC_RETURN(context, CKR_ARGUMENTS_BAD);
|
2002-12-17 11:49:12 +00:00
|
|
|
|
|
|
|
/* See if we support this mechanism type */
|
|
|
|
mt = sc_pkcs11_find_mechanism(p11card, pMechanism->mechanism, CKF_DIGEST);
|
|
|
|
if (mt == NULL)
|
2012-05-26 19:17:39 +00:00
|
|
|
LOG_FUNC_RETURN(context, CKR_MECHANISM_INVALID);
|
2002-12-17 11:49:12 +00:00
|
|
|
|
|
|
|
rv = session_start_operation(session, SC_PKCS11_OPERATION_DIGEST, mt, &operation);
|
|
|
|
if (rv != CKR_OK)
|
2012-05-26 19:17:39 +00:00
|
|
|
LOG_FUNC_RETURN(context, rv);
|
2002-12-17 11:49:12 +00:00
|
|
|
|
|
|
|
memcpy(&operation->mechanism, pMechanism, sizeof(CK_MECHANISM));
|
|
|
|
|
2003-07-17 22:09:18 +00:00
|
|
|
rv = mt->md_init(operation);
|
|
|
|
|
|
|
|
if (rv != CKR_OK)
|
|
|
|
session_stop_operation(session, SC_PKCS11_OPERATION_DIGEST);
|
|
|
|
|
2012-05-26 19:17:39 +00:00
|
|
|
LOG_FUNC_RETURN(context, rv);
|
2002-12-17 11:49:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
CK_RV
|
|
|
|
sc_pkcs11_md_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_DIGEST, &op);
|
|
|
|
if (rv != CKR_OK)
|
2003-07-17 22:09:18 +00:00
|
|
|
goto done;
|
|
|
|
|
|
|
|
rv = op->type->md_update(op, pData, ulDataLen);
|
2002-12-17 11:49:12 +00:00
|
|
|
|
2003-07-17 22:09:18 +00:00
|
|
|
done:
|
|
|
|
if (rv != CKR_OK)
|
|
|
|
session_stop_operation(session, SC_PKCS11_OPERATION_DIGEST);
|
|
|
|
|
2012-05-26 19:17:39 +00:00
|
|
|
LOG_FUNC_RETURN(context, rv);
|
2002-12-17 11:49:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
CK_RV
|
|
|
|
sc_pkcs11_md_final(struct sc_pkcs11_session *session,
|
|
|
|
CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen)
|
|
|
|
{
|
|
|
|
sc_pkcs11_operation_t *op;
|
2010-01-24 20:45:02 +00:00
|
|
|
CK_RV rv;
|
2002-12-17 11:49:12 +00:00
|
|
|
|
|
|
|
rv = session_get_operation(session, SC_PKCS11_OPERATION_DIGEST, &op);
|
|
|
|
if (rv != CKR_OK)
|
2012-05-26 19:17:39 +00:00
|
|
|
LOG_FUNC_RETURN(context, rv);
|
2002-12-17 11:49:12 +00:00
|
|
|
|
2003-01-03 14:28:50 +00:00
|
|
|
/* This is a request for the digest length */
|
|
|
|
if (pData == NULL)
|
|
|
|
*pulDataLen = 0;
|
|
|
|
|
2002-12-17 11:49:12 +00:00
|
|
|
rv = op->type->md_final(op, pData, pulDataLen);
|
2003-01-03 14:28:50 +00:00
|
|
|
if (rv == CKR_BUFFER_TOO_SMALL)
|
2012-05-26 19:17:39 +00:00
|
|
|
LOG_FUNC_RETURN(context, pData == NULL ? CKR_OK : CKR_BUFFER_TOO_SMALL);
|
2003-01-03 14:28:50 +00:00
|
|
|
|
|
|
|
session_stop_operation(session, SC_PKCS11_OPERATION_DIGEST);
|
2012-05-26 19:17:39 +00:00
|
|
|
LOG_FUNC_RETURN(context, rv);
|
2002-12-17 11:49:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Initialize a signing context. When we get here, we know
|
|
|
|
* the key object is capable of signing _something_
|
|
|
|
*/
|
|
|
|
CK_RV
|
2012-05-26 19:17:39 +00:00
|
|
|
sc_pkcs11_sign_init(struct sc_pkcs11_session *session, CK_MECHANISM_PTR pMechanism,
|
|
|
|
struct sc_pkcs11_object *key, CK_MECHANISM_TYPE key_type)
|
2002-12-17 11:49:12 +00:00
|
|
|
{
|
|
|
|
struct sc_pkcs11_card *p11card;
|
|
|
|
sc_pkcs11_operation_t *operation;
|
|
|
|
sc_pkcs11_mechanism_type_t *mt;
|
|
|
|
int rv;
|
|
|
|
|
2012-05-26 19:17:39 +00:00
|
|
|
LOG_FUNC_CALLED(context);
|
|
|
|
if (!session || !session->slot || !(p11card = session->slot->card))
|
|
|
|
LOG_FUNC_RETURN(context, CKR_ARGUMENTS_BAD);
|
2002-12-17 11:49:12 +00:00
|
|
|
|
|
|
|
/* See if we support this mechanism type */
|
2012-05-26 19:17:39 +00:00
|
|
|
sc_log(context, "mechanism 0x%X, key-type 0x%X", pMechanism->mechanism, key_type);
|
2002-12-17 11:49:12 +00:00
|
|
|
mt = sc_pkcs11_find_mechanism(p11card, pMechanism->mechanism, CKF_SIGN);
|
|
|
|
if (mt == NULL)
|
2012-05-26 19:17:39 +00:00
|
|
|
LOG_FUNC_RETURN(context, CKR_MECHANISM_INVALID);
|
2002-12-17 11:49:12 +00:00
|
|
|
|
|
|
|
/* See if compatible with key type */
|
|
|
|
if (mt->key_type != key_type)
|
2012-05-26 19:17:39 +00:00
|
|
|
LOG_FUNC_RETURN(context, CKR_KEY_TYPE_INCONSISTENT);
|
2002-12-17 11:49:12 +00:00
|
|
|
|
|
|
|
rv = session_start_operation(session, SC_PKCS11_OPERATION_SIGN, mt, &operation);
|
|
|
|
if (rv != CKR_OK)
|
2012-05-26 19:17:39 +00:00
|
|
|
LOG_FUNC_RETURN(context, rv);
|
2002-12-17 11:49:12 +00:00
|
|
|
|
|
|
|
memcpy(&operation->mechanism, pMechanism, sizeof(CK_MECHANISM));
|
2003-07-17 22:09:18 +00:00
|
|
|
rv = mt->sign_init(operation, key);
|
|
|
|
if (rv != CKR_OK)
|
|
|
|
session_stop_operation(session, SC_PKCS11_OPERATION_SIGN);
|
|
|
|
|
2012-05-26 19:17:39 +00:00
|
|
|
LOG_FUNC_RETURN(context, rv);
|
2002-12-17 11:49:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
CK_RV
|
|
|
|
sc_pkcs11_sign_update(struct sc_pkcs11_session *session,
|
|
|
|
CK_BYTE_PTR pData, CK_ULONG ulDataLen)
|
|
|
|
{
|
|
|
|
sc_pkcs11_operation_t *op;
|
|
|
|
int rv;
|
|
|
|
|
2012-05-26 19:17:39 +00:00
|
|
|
LOG_FUNC_CALLED(context);
|
2002-12-17 11:49:12 +00:00
|
|
|
rv = session_get_operation(session, SC_PKCS11_OPERATION_SIGN, &op);
|
|
|
|
if (rv != CKR_OK)
|
2012-05-26 19:17:39 +00:00
|
|
|
LOG_FUNC_RETURN(context, rv);
|
2002-12-17 11:49:12 +00:00
|
|
|
|
2003-07-17 22:09:18 +00:00
|
|
|
if (op->type->sign_update == NULL) {
|
|
|
|
rv = CKR_KEY_TYPE_INCONSISTENT;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
rv = op->type->sign_update(op, pData, ulDataLen);
|
2002-12-17 11:49:12 +00:00
|
|
|
|
2003-07-17 22:09:18 +00:00
|
|
|
done:
|
|
|
|
if (rv != CKR_OK)
|
|
|
|
session_stop_operation(session, SC_PKCS11_OPERATION_SIGN);
|
|
|
|
|
2012-05-26 19:17:39 +00:00
|
|
|
LOG_FUNC_RETURN(context, rv);
|
2002-12-17 11:49:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
CK_RV
|
|
|
|
sc_pkcs11_sign_final(struct sc_pkcs11_session *session,
|
|
|
|
CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen)
|
|
|
|
{
|
|
|
|
sc_pkcs11_operation_t *op;
|
|
|
|
int rv;
|
|
|
|
|
2012-05-26 19:17:39 +00:00
|
|
|
LOG_FUNC_CALLED(context);
|
2002-12-17 11:49:12 +00:00
|
|
|
rv = session_get_operation(session, SC_PKCS11_OPERATION_SIGN, &op);
|
|
|
|
if (rv != CKR_OK)
|
2012-05-26 19:17:39 +00:00
|
|
|
LOG_FUNC_RETURN(context, rv);
|
2002-12-17 11:49:12 +00:00
|
|
|
|
|
|
|
/* Bail out for signature mechanisms that don't do hashing */
|
2003-07-17 22:09:18 +00:00
|
|
|
if (op->type->sign_final == NULL) {
|
|
|
|
rv = CKR_KEY_TYPE_INCONSISTENT;
|
|
|
|
goto done;
|
|
|
|
}
|
2002-12-17 11:49:12 +00:00
|
|
|
|
|
|
|
rv = op->type->sign_final(op, pSignature, pulSignatureLen);
|
|
|
|
|
2003-07-17 22:09:18 +00:00
|
|
|
done:
|
2002-12-17 11:49:12 +00:00
|
|
|
if (rv != CKR_BUFFER_TOO_SMALL && pSignature != NULL)
|
|
|
|
session_stop_operation(session, SC_PKCS11_OPERATION_SIGN);
|
2003-07-17 22:09:18 +00:00
|
|
|
|
2012-05-26 19:17:39 +00:00
|
|
|
LOG_FUNC_RETURN(context, rv);
|
2002-12-17 11:49:12 +00:00
|
|
|
}
|
|
|
|
|
2003-01-03 14:28:50 +00:00
|
|
|
CK_RV
|
|
|
|
sc_pkcs11_sign_size(struct sc_pkcs11_session *session, CK_ULONG_PTR pLength)
|
|
|
|
{
|
|
|
|
sc_pkcs11_operation_t *op;
|
|
|
|
int rv;
|
|
|
|
|
|
|
|
rv = session_get_operation(session, SC_PKCS11_OPERATION_SIGN, &op);
|
|
|
|
if (rv != CKR_OK)
|
2012-05-26 19:17:39 +00:00
|
|
|
LOG_FUNC_RETURN(context, rv);
|
2003-01-03 14:28:50 +00:00
|
|
|
|
|
|
|
/* Bail out for signature mechanisms that don't do hashing */
|
2003-07-17 22:09:18 +00:00
|
|
|
if (op->type->sign_size == NULL) {
|
|
|
|
rv = CKR_KEY_TYPE_INCONSISTENT;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
rv = op->type->sign_size(op, pLength);
|
2003-01-03 14:28:50 +00:00
|
|
|
|
2003-07-17 22:09:18 +00:00
|
|
|
done:
|
|
|
|
if (rv != CKR_OK)
|
|
|
|
session_stop_operation(session, SC_PKCS11_OPERATION_SIGN);
|
|
|
|
|
2012-05-26 19:17:39 +00:00
|
|
|
LOG_FUNC_RETURN(context, rv);
|
2003-01-03 14:28:50 +00:00
|
|
|
}
|
|
|
|
|
2002-12-17 11:49:12 +00:00
|
|
|
/*
|
|
|
|
* Initialize a signature operation
|
|
|
|
*/
|
|
|
|
static CK_RV
|
|
|
|
sc_pkcs11_signature_init(sc_pkcs11_operation_t *operation,
|
2012-05-26 19:17:39 +00:00
|
|
|
struct sc_pkcs11_object *key)
|
2002-12-17 11:49:12 +00:00
|
|
|
{
|
|
|
|
struct hash_signature_info *info;
|
|
|
|
struct signature_data *data;
|
2012-05-26 19:17:39 +00:00
|
|
|
CK_RV rv;
|
|
|
|
int can_do_it = 0;
|
2002-12-17 11:49:12 +00:00
|
|
|
|
2012-05-26 19:17:39 +00:00
|
|
|
LOG_FUNC_CALLED(context);
|
Do not cast the return value of malloc(3) and calloc(3)
From http://en.wikipedia.org/wiki/Malloc#Casting_and_type_safety
" Casting and type safety
malloc returns a void pointer (void *), which indicates that it is a
pointer to a region of unknown data type. One may "cast" (see type
conversion) this pointer to a specific type, as in
int *ptr = (int*)malloc(10 * sizeof (int));
When using C, this is considered bad practice; it is redundant under the
C standard. Moreover, putting in a cast may mask failure to include the
header stdlib.h, in which the prototype for malloc is found. In the
absence of a prototype for malloc, the C compiler will assume that
malloc returns an int, and will issue a warning in a context such as the
above, provided the error is not masked by a cast. On certain
architectures and data models (such as LP64 on 64 bit systems, where
long and pointers are 64 bit and int is 32 bit), this error can actually
result in undefined behavior, as the implicitly declared malloc returns
a 32 bit value whereas the actually defined function returns a 64 bit
value. Depending on calling conventions and memory layout, this may
result in stack smashing.
The returned pointer need not be explicitly cast to a more specific
pointer type, since ANSI C defines an implicit conversion between the
void pointer type and other pointers to objects. An explicit cast of
malloc's return value is sometimes performed because malloc originally
returned a char *, but this cast is unnecessary in standard C
code.[4][5] Omitting the cast, however, creates an incompatibility with
C++, which does require it.
The lack of a specific pointer type returned from malloc is type-unsafe
behaviour: malloc allocates based on byte count but not on type. This
distinguishes it from the C++ new operator that returns a pointer whose
type relies on the operand. (see C Type Safety). "
See also
http://www.opensc-project.org/pipermail/opensc-devel/2010-August/014586.html
git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@4636 c6295689-39f2-0310-b995-f0e70906c6a9
2010-08-18 15:08:51 +00:00
|
|
|
if (!(data = calloc(1, sizeof(*data))))
|
2012-05-26 19:17:39 +00:00
|
|
|
LOG_FUNC_RETURN(context, CKR_HOST_MEMORY);
|
2002-12-17 11:49:12 +00:00
|
|
|
data->info = NULL;
|
|
|
|
data->key = key;
|
|
|
|
|
2012-05-26 19:17:39 +00:00
|
|
|
if (key->ops->can_do) {
|
|
|
|
rv = key->ops->can_do(operation->session, key, operation->type->mech, CKF_SIGN);
|
|
|
|
if (rv == CKR_OK) {
|
|
|
|
/* Mechanism recognised and can be performed by pkcs#15 card */
|
|
|
|
can_do_it = 1;
|
|
|
|
}
|
|
|
|
else if (rv == CKR_FUNCTION_NOT_SUPPORTED) {
|
|
|
|
/* Mechanism not recognised by pkcs#15 card */
|
|
|
|
can_do_it = 0;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* Mechanism recognised but cannot be performed by pkcs#15 card, or some general error. */
|
|
|
|
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 */
|
2002-12-17 11:49:12 +00:00
|
|
|
info = (struct hash_signature_info *) operation->type->mech_data;
|
2012-05-26 19:17:39 +00:00
|
|
|
if (info != NULL && !can_do_it) {
|
2002-12-17 11:49:12 +00:00
|
|
|
/* Initialize hash operation */
|
2012-05-26 19:17:39 +00:00
|
|
|
|
|
|
|
data->md = sc_pkcs11_new_operation(operation->session, info->hash_type);
|
2002-12-17 11:49:12 +00:00
|
|
|
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);
|
2012-05-26 19:17:39 +00:00
|
|
|
LOG_FUNC_RETURN(context, rv);
|
2002-12-17 11:49:12 +00:00
|
|
|
}
|
|
|
|
data->info = info;
|
|
|
|
}
|
|
|
|
|
|
|
|
operation->priv_data = data;
|
2012-05-26 19:17:39 +00:00
|
|
|
LOG_FUNC_RETURN(context, CKR_OK);
|
2002-12-17 11:49:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static CK_RV
|
|
|
|
sc_pkcs11_signature_update(sc_pkcs11_operation_t *operation,
|
2012-05-26 19:17:39 +00:00
|
|
|
CK_BYTE_PTR pPart, CK_ULONG ulPartLen)
|
2002-12-17 11:49:12 +00:00
|
|
|
{
|
|
|
|
struct signature_data *data;
|
|
|
|
|
2012-05-26 19:17:39 +00:00
|
|
|
LOG_FUNC_CALLED(context);
|
|
|
|
sc_log(context, "data part length %li", ulPartLen);
|
2002-12-17 11:49:12 +00:00
|
|
|
data = (struct signature_data *) operation->priv_data;
|
|
|
|
if (data->md) {
|
2012-05-26 19:17:39 +00:00
|
|
|
CK_RV rv = data->md->type->md_update(data->md, pPart, ulPartLen);
|
|
|
|
LOG_FUNC_RETURN(context, rv);
|
2002-12-17 11:49:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* This signature mechanism operates on the raw data */
|
|
|
|
if (data->buffer_len + ulPartLen > sizeof(data->buffer))
|
2012-05-26 19:17:39 +00:00
|
|
|
LOG_FUNC_RETURN(context, CKR_DATA_LEN_RANGE);
|
2002-12-17 11:49:12 +00:00
|
|
|
memcpy(data->buffer + data->buffer_len, pPart, ulPartLen);
|
|
|
|
data->buffer_len += ulPartLen;
|
2012-05-26 19:17:39 +00:00
|
|
|
sc_log(context, "data length %li", data->buffer_len);
|
|
|
|
LOG_FUNC_RETURN(context, CKR_OK);
|
2002-12-17 11:49:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static CK_RV
|
|
|
|
sc_pkcs11_signature_final(sc_pkcs11_operation_t *operation,
|
2012-05-26 19:17:39 +00:00
|
|
|
CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen)
|
2002-12-17 11:49:12 +00:00
|
|
|
{
|
|
|
|
struct signature_data *data;
|
2012-05-26 19:17:39 +00:00
|
|
|
CK_RV rv;
|
2002-12-17 11:49:12 +00:00
|
|
|
|
2012-05-26 19:17:39 +00:00
|
|
|
LOG_FUNC_CALLED(context);
|
2002-12-17 11:49:12 +00:00
|
|
|
data = (struct signature_data *) operation->priv_data;
|
2012-05-26 19:17:39 +00:00
|
|
|
sc_log(context, "data length %li", data->buffer_len);
|
2002-12-17 11:49:12 +00:00
|
|
|
if (data->md) {
|
|
|
|
sc_pkcs11_operation_t *md = data->md;
|
|
|
|
CK_ULONG len = sizeof(data->buffer);
|
|
|
|
|
|
|
|
rv = md->type->md_final(md, data->buffer, &len);
|
|
|
|
if (rv == CKR_BUFFER_TOO_SMALL)
|
|
|
|
rv = CKR_FUNCTION_FAILED;
|
|
|
|
if (rv != CKR_OK)
|
2012-05-26 19:17:39 +00:00
|
|
|
LOG_FUNC_RETURN(context, rv);
|
2002-12-17 11:49:12 +00:00
|
|
|
data->buffer_len = len;
|
|
|
|
}
|
|
|
|
|
2012-05-26 19:17:39 +00:00
|
|
|
sc_log(context, "%li bytes to sign", data->buffer_len);
|
|
|
|
rv = data->key->ops->sign(operation->session, data->key, &operation->mechanism,
|
|
|
|
data->buffer, data->buffer_len, pSignature, pulSignatureLen);
|
|
|
|
LOG_FUNC_RETURN(context, rv);
|
2002-12-17 11:49:12 +00:00
|
|
|
}
|
|
|
|
|
2003-01-03 14:28:50 +00:00
|
|
|
static CK_RV
|
|
|
|
sc_pkcs11_signature_size(sc_pkcs11_operation_t *operation, CK_ULONG_PTR pLength)
|
|
|
|
{
|
|
|
|
struct sc_pkcs11_object *key;
|
|
|
|
CK_ATTRIBUTE attr = { CKA_MODULUS_BITS, pLength, sizeof(*pLength) };
|
2009-10-05 20:10:07 +00:00
|
|
|
CK_KEY_TYPE key_type;
|
|
|
|
CK_ATTRIBUTE attr_key_type = { CKA_KEY_TYPE, &key_type, sizeof(key_type) };
|
2003-01-20 09:56:53 +00:00
|
|
|
CK_RV rv;
|
2003-01-03 14:28:50 +00:00
|
|
|
|
|
|
|
key = ((struct signature_data *) operation->priv_data)->key;
|
2010-12-01 20:08:42 +00:00
|
|
|
/*
|
2010-12-09 07:23:10 +00:00
|
|
|
* EC and GOSTR do not have CKA_MODULUS_BITS attribute.
|
2012-04-02 22:00:56 +00:00
|
|
|
* But other code in framework treats them as if they do.
|
2010-12-01 20:08:42 +00:00
|
|
|
* So should do switch(key_type)
|
2012-04-02 22:00:56 +00:00
|
|
|
* and then get what ever attributes are needed.
|
2010-12-01 20:08:42 +00:00
|
|
|
*/
|
|
|
|
rv = key->ops->get_attribute(operation->session, key, &attr_key_type);
|
2012-04-02 22:00:56 +00:00
|
|
|
if (rv == CKR_OK) {
|
2010-12-01 20:08:42 +00:00
|
|
|
switch(key_type) {
|
|
|
|
case CKK_RSA:
|
2012-04-02 22:00:56 +00:00
|
|
|
rv = key->ops->get_attribute(operation->session, key, &attr);
|
2010-12-01 20:08:42 +00:00
|
|
|
/* convert bits to bytes */
|
|
|
|
if (rv == CKR_OK)
|
|
|
|
*pLength = (*pLength + 7) / 8;
|
|
|
|
break;
|
|
|
|
case CKK_EC:
|
|
|
|
/* TODO: -DEE we should use something other then CKA_MODULUS_BITS... */
|
|
|
|
rv = key->ops->get_attribute(operation->session, key, &attr);
|
2012-08-11 19:21:31 +00:00
|
|
|
*pLength = ((*pLength + 7)/8) * 2 ; /* 2*nLen in bytes */
|
2010-12-01 20:08:42 +00:00
|
|
|
break;
|
|
|
|
case CKK_GOSTR3410:
|
|
|
|
rv = key->ops->get_attribute(operation->session, key, &attr);
|
|
|
|
if (rv == CKR_OK)
|
2010-12-09 07:23:10 +00:00
|
|
|
*pLength = (*pLength + 7) / 8 * 2;
|
2010-12-01 20:08:42 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
rv = CKR_MECHANISM_INVALID;
|
|
|
|
}
|
2009-10-05 20:10:07 +00:00
|
|
|
}
|
|
|
|
|
2012-05-26 19:17:39 +00:00
|
|
|
LOG_FUNC_RETURN(context, rv);
|
2003-01-03 14:28:50 +00:00
|
|
|
}
|
|
|
|
|
2002-12-17 11:49:12 +00:00
|
|
|
static void
|
|
|
|
sc_pkcs11_signature_release(sc_pkcs11_operation_t *operation)
|
|
|
|
{
|
|
|
|
struct signature_data *data;
|
|
|
|
|
|
|
|
data = (struct signature_data *) operation->priv_data;
|
2012-05-26 19:17:39 +00:00
|
|
|
if (!data)
|
|
|
|
return;
|
2002-12-17 11:49:12 +00:00
|
|
|
sc_pkcs11_release_operation(&data->md);
|
|
|
|
memset(data, 0, sizeof(*data));
|
|
|
|
free(data);
|
|
|
|
}
|
|
|
|
|
2008-03-06 16:06:59 +00:00
|
|
|
#ifdef ENABLE_OPENSSL
|
2003-06-27 15:26:17 +00:00
|
|
|
/*
|
|
|
|
* Initialize a verify context. When we get here, we know
|
|
|
|
* the key object is capable of verifying _something_
|
|
|
|
*/
|
|
|
|
CK_RV
|
2012-05-26 19:17:39 +00:00
|
|
|
sc_pkcs11_verif_init(struct sc_pkcs11_session *session, CK_MECHANISM_PTR pMechanism,
|
|
|
|
struct sc_pkcs11_object *key, CK_MECHANISM_TYPE key_type)
|
2003-06-27 15:26:17 +00:00
|
|
|
{
|
|
|
|
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));
|
2003-07-17 22:09:18 +00:00
|
|
|
rv = mt->verif_init(operation, key);
|
|
|
|
|
|
|
|
if (rv != CKR_OK)
|
|
|
|
session_stop_operation(session, SC_PKCS11_OPERATION_VERIFY);
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
|
2003-06-27 15:26:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
2003-07-17 22:09:18 +00:00
|
|
|
if (op->type->verif_update == NULL) {
|
|
|
|
rv = CKR_KEY_TYPE_INCONSISTENT;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
|
|
|
rv = op->type->verif_update(op, pData, ulDataLen);
|
2003-06-27 15:26:17 +00:00
|
|
|
|
2003-07-17 22:09:18 +00:00
|
|
|
done:
|
|
|
|
if (rv != CKR_OK)
|
|
|
|
session_stop_operation(session, SC_PKCS11_OPERATION_VERIFY);
|
|
|
|
|
|
|
|
return rv;
|
2003-06-27 15:26:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
2003-07-17 22:09:18 +00:00
|
|
|
if (op->type->verif_final == NULL) {
|
|
|
|
rv = CKR_KEY_TYPE_INCONSISTENT;
|
|
|
|
goto done;
|
|
|
|
}
|
2003-06-27 15:26:17 +00:00
|
|
|
|
|
|
|
rv = op->type->verif_final(op, pSignature, ulSignatureLen);
|
|
|
|
|
2003-07-17 22:09:18 +00:00
|
|
|
done:
|
2003-06-27 15:26:17 +00:00
|
|
|
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;
|
|
|
|
|
Do not cast the return value of malloc(3) and calloc(3)
From http://en.wikipedia.org/wiki/Malloc#Casting_and_type_safety
" Casting and type safety
malloc returns a void pointer (void *), which indicates that it is a
pointer to a region of unknown data type. One may "cast" (see type
conversion) this pointer to a specific type, as in
int *ptr = (int*)malloc(10 * sizeof (int));
When using C, this is considered bad practice; it is redundant under the
C standard. Moreover, putting in a cast may mask failure to include the
header stdlib.h, in which the prototype for malloc is found. In the
absence of a prototype for malloc, the C compiler will assume that
malloc returns an int, and will issue a warning in a context such as the
above, provided the error is not masked by a cast. On certain
architectures and data models (such as LP64 on 64 bit systems, where
long and pointers are 64 bit and int is 32 bit), this error can actually
result in undefined behavior, as the implicitly declared malloc returns
a 32 bit value whereas the actually defined function returns a 64 bit
value. Depending on calling conventions and memory layout, this may
result in stack smashing.
The returned pointer need not be explicitly cast to a more specific
pointer type, since ANSI C defines an implicit conversion between the
void pointer type and other pointers to objects. An explicit cast of
malloc's return value is sometimes performed because malloc originally
returned a char *, but this cast is unnecessary in standard C
code.[4][5] Omitting the cast, however, creates an incompatibility with
C++, which does require it.
The lack of a specific pointer type returned from malloc is type-unsafe
behaviour: malloc allocates based on byte count but not on type. This
distinguishes it from the C++ new operator that returns a pointer whose
type relies on the operand. (see C Type Safety). "
See also
http://www.opensc-project.org/pipermail/opensc-devel/2010-August/014586.html
git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@4636 c6295689-39f2-0310-b995-f0e70906c6a9
2010-08-18 15:08:51 +00:00
|
|
|
if (!(data = calloc(1, sizeof(*data))))
|
2003-06-27 15:26:17 +00:00
|
|
|
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;
|
2009-10-05 20:10:07 +00:00
|
|
|
CK_KEY_TYPE key_type;
|
|
|
|
CK_BYTE params[9 /* GOST_PARAMS_OID_SIZE */] = { 0 };
|
2003-06-27 15:26:17 +00:00
|
|
|
CK_ATTRIBUTE attr = {CKA_VALUE, NULL, 0};
|
2009-10-05 20:10:07 +00:00
|
|
|
CK_ATTRIBUTE attr_key_type = {CKA_KEY_TYPE, &key_type, sizeof(key_type)};
|
|
|
|
CK_ATTRIBUTE attr_key_params = {CKA_GOSTR3410_PARAMS, ¶ms, sizeof(params)};
|
2003-06-27 15:26:17 +00:00
|
|
|
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;
|
2013-03-15 20:12:25 +00:00
|
|
|
pubkey_value = calloc(1, attr.ulValueLen);
|
2003-06-27 15:26:17 +00:00
|
|
|
attr.pValue = pubkey_value;
|
|
|
|
rv = key->ops->get_attribute(operation->session, key, &attr);
|
|
|
|
if (rv != CKR_OK)
|
|
|
|
goto done;
|
|
|
|
|
2009-10-05 20:10:07 +00:00
|
|
|
rv = key->ops->get_attribute(operation->session, key, &attr_key_type);
|
|
|
|
if (rv == CKR_OK && key_type == CKK_GOSTR3410) {
|
|
|
|
rv = key->ops->get_attribute(operation->session, key, &attr_key_params);
|
|
|
|
if (rv != CKR_OK)
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
2003-06-27 15:26:17 +00:00
|
|
|
rv = sc_pkcs11_verify_data(pubkey_value, attr.ulValueLen,
|
2009-10-05 20:10:07 +00:00
|
|
|
params, sizeof(params),
|
2003-06-27 15:26:17 +00:00
|
|
|
operation->mechanism.mechanism, data->md,
|
|
|
|
data->buffer, data->buffer_len, pSignature, ulSignatureLen);
|
|
|
|
|
|
|
|
done:
|
|
|
|
free(pubkey_value);
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2003-10-01 06:51:49 +00:00
|
|
|
/*
|
|
|
|
* Initialize a decryption context. When we get here, we know
|
|
|
|
* the key object is capable of decrypting _something_
|
2003-10-02 08:29:32 +00:00
|
|
|
*/
|
|
|
|
CK_RV
|
|
|
|
sc_pkcs11_decr_init(struct sc_pkcs11_session *session,
|
|
|
|
CK_MECHANISM_PTR pMechanism,
|
|
|
|
struct sc_pkcs11_object *key,
|
|
|
|
CK_MECHANISM_TYPE key_type)
|
2003-10-01 06:51:49 +00:00
|
|
|
{
|
|
|
|
struct sc_pkcs11_card *p11card;
|
|
|
|
sc_pkcs11_operation_t *operation;
|
|
|
|
sc_pkcs11_mechanism_type_t *mt;
|
2003-10-02 08:29:32 +00:00
|
|
|
CK_RV rv;
|
2003-10-01 06:51:49 +00:00
|
|
|
|
|
|
|
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_DECRYPT);
|
|
|
|
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_DECRYPT, mt, &operation);
|
|
|
|
if (rv != CKR_OK)
|
|
|
|
return rv;
|
|
|
|
|
|
|
|
memcpy(&operation->mechanism, pMechanism, sizeof(CK_MECHANISM));
|
|
|
|
rv = mt->decrypt_init(operation, key);
|
|
|
|
|
|
|
|
if (rv != CKR_OK)
|
|
|
|
session_stop_operation(session, SC_PKCS11_OPERATION_DECRYPT);
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
CK_RV
|
|
|
|
sc_pkcs11_decr(struct sc_pkcs11_session *session,
|
2003-10-02 08:29:32 +00:00
|
|
|
CK_BYTE_PTR pEncryptedData, CK_ULONG ulEncryptedDataLen,
|
|
|
|
CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen)
|
2003-10-01 06:51:49 +00:00
|
|
|
{
|
|
|
|
sc_pkcs11_operation_t *op;
|
|
|
|
int rv;
|
|
|
|
|
|
|
|
rv = session_get_operation(session, SC_PKCS11_OPERATION_DECRYPT, &op);
|
|
|
|
if (rv != CKR_OK)
|
|
|
|
return rv;
|
|
|
|
|
|
|
|
rv = op->type->decrypt(op, pEncryptedData, ulEncryptedDataLen,
|
|
|
|
pData, pulDataLen);
|
|
|
|
|
|
|
|
if (rv != CKR_BUFFER_TOO_SMALL && pData != NULL)
|
|
|
|
session_stop_operation(session, SC_PKCS11_OPERATION_DECRYPT);
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2012-05-26 19:17:39 +00:00
|
|
|
/* Derive one key from another, and return results in created object */
|
|
|
|
CK_RV
|
|
|
|
sc_pkcs11_deri(struct sc_pkcs11_session *session,
|
|
|
|
CK_MECHANISM_PTR pMechanism,
|
|
|
|
struct sc_pkcs11_object * basekey,
|
|
|
|
CK_KEY_TYPE key_type,
|
|
|
|
CK_SESSION_HANDLE hSession,
|
|
|
|
CK_OBJECT_HANDLE hdkey,
|
|
|
|
struct sc_pkcs11_object * dkey)
|
|
|
|
{
|
|
|
|
|
|
|
|
struct sc_pkcs11_card *p11card;
|
|
|
|
sc_pkcs11_operation_t *operation;
|
|
|
|
sc_pkcs11_mechanism_type_t *mt;
|
|
|
|
CK_BYTE_PTR keybuf = NULL;
|
|
|
|
CK_ULONG ulDataLen = 0;
|
|
|
|
CK_ATTRIBUTE template[] = {
|
|
|
|
{CKA_VALUE, keybuf, 0}
|
|
|
|
};
|
|
|
|
|
|
|
|
CK_RV 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_DERIVE);
|
|
|
|
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_DERIVE, mt, &operation);
|
|
|
|
if (rv != CKR_OK)
|
|
|
|
return rv;
|
|
|
|
|
|
|
|
memcpy(&operation->mechanism, pMechanism, sizeof(CK_MECHANISM));
|
|
|
|
|
|
|
|
/* Get the size of the data to be returned
|
|
|
|
* If the card could derive a key an leave it on the card
|
|
|
|
* then no data is returned.
|
|
|
|
* If the card returns the data, we will store it in the sercet key CKA_VALUE
|
|
|
|
*/
|
|
|
|
|
|
|
|
ulDataLen = 0;
|
|
|
|
rv = operation->type->derive(operation, basekey,
|
|
|
|
pMechanism->pParameter, pMechanism->ulParameterLen,
|
|
|
|
NULL, &ulDataLen);
|
|
|
|
if (rv != CKR_OK)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
if (ulDataLen > 0)
|
|
|
|
keybuf = calloc(1,ulDataLen);
|
|
|
|
else
|
|
|
|
keybuf = calloc(1,8); /* pass in dummy buffer */
|
|
|
|
|
|
|
|
if (!keybuf) {
|
|
|
|
rv = CKR_HOST_MEMORY;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Now do the actuall derivation */
|
|
|
|
|
|
|
|
rv = operation->type->derive(operation, basekey,
|
|
|
|
pMechanism->pParameter, pMechanism->ulParameterLen,
|
|
|
|
keybuf, &ulDataLen);
|
|
|
|
if (rv != CKR_OK)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
|
|
|
|
/* add the CKA_VALUE attribute to the template if it was returned
|
|
|
|
* if not assume it is on the card...
|
|
|
|
* But for now PIV with ECDH returns the generic key data
|
|
|
|
* TODO need to support truncation, if CKA_VALUE_LEN < ulDataLem
|
|
|
|
*/
|
|
|
|
if (ulDataLen > 0) {
|
|
|
|
template[0].pValue = keybuf;
|
|
|
|
template[0].ulValueLen = ulDataLen;
|
|
|
|
|
|
|
|
dkey->ops->set_attribute(session, dkey, &template[0]);
|
|
|
|
|
|
|
|
memset(keybuf,0,ulDataLen);
|
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
|
|
|
session_stop_operation(session, SC_PKCS11_OPERATION_DERIVE);
|
|
|
|
|
|
|
|
if (keybuf)
|
|
|
|
free(keybuf);
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-10-01 06:51:49 +00:00
|
|
|
/*
|
|
|
|
* Initialize a signature operation
|
|
|
|
*/
|
|
|
|
static CK_RV
|
|
|
|
sc_pkcs11_decrypt_init(sc_pkcs11_operation_t *operation,
|
2003-10-02 08:29:32 +00:00
|
|
|
struct sc_pkcs11_object *key)
|
2003-10-01 06:51:49 +00:00
|
|
|
{
|
|
|
|
struct signature_data *data;
|
|
|
|
|
Do not cast the return value of malloc(3) and calloc(3)
From http://en.wikipedia.org/wiki/Malloc#Casting_and_type_safety
" Casting and type safety
malloc returns a void pointer (void *), which indicates that it is a
pointer to a region of unknown data type. One may "cast" (see type
conversion) this pointer to a specific type, as in
int *ptr = (int*)malloc(10 * sizeof (int));
When using C, this is considered bad practice; it is redundant under the
C standard. Moreover, putting in a cast may mask failure to include the
header stdlib.h, in which the prototype for malloc is found. In the
absence of a prototype for malloc, the C compiler will assume that
malloc returns an int, and will issue a warning in a context such as the
above, provided the error is not masked by a cast. On certain
architectures and data models (such as LP64 on 64 bit systems, where
long and pointers are 64 bit and int is 32 bit), this error can actually
result in undefined behavior, as the implicitly declared malloc returns
a 32 bit value whereas the actually defined function returns a 64 bit
value. Depending on calling conventions and memory layout, this may
result in stack smashing.
The returned pointer need not be explicitly cast to a more specific
pointer type, since ANSI C defines an implicit conversion between the
void pointer type and other pointers to objects. An explicit cast of
malloc's return value is sometimes performed because malloc originally
returned a char *, but this cast is unnecessary in standard C
code.[4][5] Omitting the cast, however, creates an incompatibility with
C++, which does require it.
The lack of a specific pointer type returned from malloc is type-unsafe
behaviour: malloc allocates based on byte count but not on type. This
distinguishes it from the C++ new operator that returns a pointer whose
type relies on the operand. (see C Type Safety). "
See also
http://www.opensc-project.org/pipermail/opensc-devel/2010-August/014586.html
git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@4636 c6295689-39f2-0310-b995-f0e70906c6a9
2010-08-18 15:08:51 +00:00
|
|
|
if (!(data = calloc(1, sizeof(*data))))
|
2003-10-01 06:51:49 +00:00
|
|
|
return CKR_HOST_MEMORY;
|
|
|
|
|
|
|
|
data->key = key;
|
|
|
|
|
|
|
|
operation->priv_data = data;
|
|
|
|
return CKR_OK;
|
|
|
|
}
|
|
|
|
|
2003-10-02 08:29:32 +00:00
|
|
|
static CK_RV
|
2003-10-01 06:51:49 +00:00
|
|
|
sc_pkcs11_decrypt(sc_pkcs11_operation_t *operation,
|
2003-10-02 08:29:32 +00:00
|
|
|
CK_BYTE_PTR pEncryptedData, CK_ULONG ulEncryptedDataLen,
|
|
|
|
CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen)
|
2003-10-01 06:51:49 +00:00
|
|
|
{
|
|
|
|
struct signature_data *data;
|
|
|
|
struct sc_pkcs11_object *key;
|
|
|
|
|
|
|
|
data = (struct signature_data*) operation->priv_data;
|
|
|
|
|
|
|
|
key = data->key;
|
|
|
|
return key->ops->decrypt(operation->session,
|
|
|
|
key, &operation->mechanism,
|
|
|
|
pEncryptedData, ulEncryptedDataLen,
|
|
|
|
pData, pulDataLen);
|
|
|
|
}
|
|
|
|
|
2012-05-26 19:17:39 +00:00
|
|
|
static CK_RV
|
|
|
|
sc_pkcs11_derive(sc_pkcs11_operation_t *operation,
|
|
|
|
struct sc_pkcs11_object *basekey,
|
|
|
|
CK_BYTE_PTR pmechParam, CK_ULONG ulmechParamLen,
|
|
|
|
CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen)
|
|
|
|
{
|
|
|
|
|
|
|
|
return basekey->ops->derive(operation->session,
|
|
|
|
basekey,
|
|
|
|
&operation->mechanism,
|
|
|
|
pmechParam, ulmechParamLen,
|
|
|
|
pData, pulDataLen);
|
|
|
|
}
|
2002-12-17 11:49:12 +00:00
|
|
|
/*
|
|
|
|
* Create new mechanism type for a mechanism supported by
|
|
|
|
* the card
|
|
|
|
*/
|
|
|
|
sc_pkcs11_mechanism_type_t *
|
|
|
|
sc_pkcs11_new_fw_mechanism(CK_MECHANISM_TYPE mech,
|
|
|
|
CK_MECHANISM_INFO_PTR pInfo,
|
|
|
|
CK_KEY_TYPE key_type,
|
|
|
|
void *priv_data)
|
|
|
|
{
|
|
|
|
sc_pkcs11_mechanism_type_t *mt;
|
|
|
|
|
Do not cast the return value of malloc(3) and calloc(3)
From http://en.wikipedia.org/wiki/Malloc#Casting_and_type_safety
" Casting and type safety
malloc returns a void pointer (void *), which indicates that it is a
pointer to a region of unknown data type. One may "cast" (see type
conversion) this pointer to a specific type, as in
int *ptr = (int*)malloc(10 * sizeof (int));
When using C, this is considered bad practice; it is redundant under the
C standard. Moreover, putting in a cast may mask failure to include the
header stdlib.h, in which the prototype for malloc is found. In the
absence of a prototype for malloc, the C compiler will assume that
malloc returns an int, and will issue a warning in a context such as the
above, provided the error is not masked by a cast. On certain
architectures and data models (such as LP64 on 64 bit systems, where
long and pointers are 64 bit and int is 32 bit), this error can actually
result in undefined behavior, as the implicitly declared malloc returns
a 32 bit value whereas the actually defined function returns a 64 bit
value. Depending on calling conventions and memory layout, this may
result in stack smashing.
The returned pointer need not be explicitly cast to a more specific
pointer type, since ANSI C defines an implicit conversion between the
void pointer type and other pointers to objects. An explicit cast of
malloc's return value is sometimes performed because malloc originally
returned a char *, but this cast is unnecessary in standard C
code.[4][5] Omitting the cast, however, creates an incompatibility with
C++, which does require it.
The lack of a specific pointer type returned from malloc is type-unsafe
behaviour: malloc allocates based on byte count but not on type. This
distinguishes it from the C++ new operator that returns a pointer whose
type relies on the operand. (see C Type Safety). "
See also
http://www.opensc-project.org/pipermail/opensc-devel/2010-August/014586.html
git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@4636 c6295689-39f2-0310-b995-f0e70906c6a9
2010-08-18 15:08:51 +00:00
|
|
|
mt = calloc(1, sizeof(*mt));
|
2002-12-17 11:49:12 +00:00
|
|
|
if (mt == NULL)
|
|
|
|
return mt;
|
|
|
|
mt->mech = mech;
|
|
|
|
mt->mech_info = *pInfo;
|
|
|
|
mt->key_type = key_type;
|
|
|
|
mt->mech_data = priv_data;
|
|
|
|
mt->obj_size = sizeof(sc_pkcs11_operation_t);
|
|
|
|
|
|
|
|
mt->release = sc_pkcs11_signature_release;
|
|
|
|
|
|
|
|
if (pInfo->flags & CKF_SIGN) {
|
|
|
|
mt->sign_init = sc_pkcs11_signature_init;
|
|
|
|
mt->sign_update = sc_pkcs11_signature_update;
|
|
|
|
mt->sign_final = sc_pkcs11_signature_final;
|
2003-01-03 14:28:50 +00:00
|
|
|
mt->sign_size = sc_pkcs11_signature_size;
|
2008-03-06 16:06:59 +00:00
|
|
|
#ifdef ENABLE_OPENSSL
|
2003-06-27 15:26:17 +00:00
|
|
|
mt->verif_init = sc_pkcs11_verify_init;
|
|
|
|
mt->verif_update = sc_pkcs11_verify_update;
|
|
|
|
mt->verif_final = sc_pkcs11_verify_final;
|
|
|
|
#endif
|
2002-12-17 11:49:12 +00:00
|
|
|
}
|
|
|
|
if (pInfo->flags & CKF_UNWRAP) {
|
2010-01-24 20:45:02 +00:00
|
|
|
/* TODO */
|
2002-12-17 11:49:12 +00:00
|
|
|
}
|
2010-12-01 20:08:42 +00:00
|
|
|
if (pInfo->flags & CKF_DERIVE) {
|
2012-05-26 19:17:39 +00:00
|
|
|
mt->derive = sc_pkcs11_derive;
|
2010-12-01 20:08:42 +00:00
|
|
|
}
|
2003-10-01 06:51:49 +00:00
|
|
|
if (pInfo->flags & CKF_DECRYPT) {
|
|
|
|
mt->decrypt_init = sc_pkcs11_decrypt_init;
|
|
|
|
mt->decrypt = sc_pkcs11_decrypt;
|
|
|
|
}
|
2002-12-17 11:49:12 +00:00
|
|
|
|
|
|
|
return mt;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2002-12-17 20:16:31 +00:00
|
|
|
* Register generic mechanisms
|
2002-12-17 11:49:12 +00:00
|
|
|
*/
|
|
|
|
CK_RV
|
|
|
|
sc_pkcs11_register_generic_mechanisms(struct sc_pkcs11_card *p11card)
|
|
|
|
{
|
2008-03-06 16:06:59 +00:00
|
|
|
#ifdef ENABLE_OPENSSL
|
2002-12-17 11:49:12 +00:00
|
|
|
sc_pkcs11_register_openssl_mechanisms(p11card);
|
|
|
|
#endif
|
2002-12-17 20:16:31 +00:00
|
|
|
return CKR_OK;
|
|
|
|
}
|
2002-12-17 11:49:12 +00:00
|
|
|
|
2002-12-17 20:16:31 +00:00
|
|
|
/*
|
|
|
|
* Register a sign+hash algorithm derived from an algorithm supported
|
|
|
|
* by the token + a software hash mechanism
|
|
|
|
*/
|
|
|
|
CK_RV
|
|
|
|
sc_pkcs11_register_sign_and_hash_mechanism(struct sc_pkcs11_card *p11card,
|
|
|
|
CK_MECHANISM_TYPE mech,
|
|
|
|
CK_MECHANISM_TYPE hash_mech,
|
|
|
|
sc_pkcs11_mechanism_type_t *sign_type)
|
|
|
|
{
|
|
|
|
sc_pkcs11_mechanism_type_t *hash_type, *new_type;
|
|
|
|
struct hash_signature_info *info;
|
2003-09-29 13:54:39 +00:00
|
|
|
CK_MECHANISM_INFO mech_info = sign_type->mech_info;
|
2002-12-17 20:16:31 +00:00
|
|
|
|
|
|
|
if (!(hash_type = sc_pkcs11_find_mechanism(p11card, hash_mech, CKF_DIGEST)))
|
|
|
|
return CKR_MECHANISM_INVALID;
|
2002-12-17 11:49:12 +00:00
|
|
|
|
2003-09-29 13:54:39 +00:00
|
|
|
/* These hash-based mechs can only be used for sign/verify */
|
|
|
|
mech_info.flags &= (CKF_SIGN | CKF_SIGN_RECOVER | CKF_VERIFY | CKF_VERIFY_RECOVER);
|
|
|
|
|
Do not cast the return value of malloc(3) and calloc(3)
From http://en.wikipedia.org/wiki/Malloc#Casting_and_type_safety
" Casting and type safety
malloc returns a void pointer (void *), which indicates that it is a
pointer to a region of unknown data type. One may "cast" (see type
conversion) this pointer to a specific type, as in
int *ptr = (int*)malloc(10 * sizeof (int));
When using C, this is considered bad practice; it is redundant under the
C standard. Moreover, putting in a cast may mask failure to include the
header stdlib.h, in which the prototype for malloc is found. In the
absence of a prototype for malloc, the C compiler will assume that
malloc returns an int, and will issue a warning in a context such as the
above, provided the error is not masked by a cast. On certain
architectures and data models (such as LP64 on 64 bit systems, where
long and pointers are 64 bit and int is 32 bit), this error can actually
result in undefined behavior, as the implicitly declared malloc returns
a 32 bit value whereas the actually defined function returns a 64 bit
value. Depending on calling conventions and memory layout, this may
result in stack smashing.
The returned pointer need not be explicitly cast to a more specific
pointer type, since ANSI C defines an implicit conversion between the
void pointer type and other pointers to objects. An explicit cast of
malloc's return value is sometimes performed because malloc originally
returned a char *, but this cast is unnecessary in standard C
code.[4][5] Omitting the cast, however, creates an incompatibility with
C++, which does require it.
The lack of a specific pointer type returned from malloc is type-unsafe
behaviour: malloc allocates based on byte count but not on type. This
distinguishes it from the C++ new operator that returns a pointer whose
type relies on the operand. (see C Type Safety). "
See also
http://www.opensc-project.org/pipermail/opensc-devel/2010-August/014586.html
git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@4636 c6295689-39f2-0310-b995-f0e70906c6a9
2010-08-18 15:08:51 +00:00
|
|
|
info = calloc(1, sizeof(*info));
|
2002-12-17 20:16:31 +00:00
|
|
|
info->mech = mech;
|
|
|
|
info->sign_type = sign_type;
|
|
|
|
info->hash_type = hash_type;
|
|
|
|
info->sign_mech = sign_type->mech;
|
|
|
|
info->hash_mech = hash_mech;
|
|
|
|
|
2010-11-29 14:22:09 +00:00
|
|
|
new_type = sc_pkcs11_new_fw_mechanism(mech, &mech_info, sign_type->key_type, info);
|
2012-04-02 22:00:56 +00:00
|
|
|
|
2010-11-29 14:22:09 +00:00
|
|
|
if (!new_type)
|
2012-04-02 22:00:56 +00:00
|
|
|
return CKR_HOST_MEMORY;
|
2010-11-29 14:22:09 +00:00
|
|
|
return sc_pkcs11_register_mechanism(p11card, new_type);
|
2002-12-17 11:49:12 +00:00
|
|
|
}
|