/* * Generic handling of PKCS11 mechanisms * * Copyright (C) 2002 Olaf Kirch */ #include "config.h" #include #include #include "sc-pkcs11.h" /* Also used for verification data */ 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; }; /* Also used for verification and decryption data */ 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 * sc_pkcs11_find_mechanism(struct sc_pkcs11_card *p11card, CK_MECHANISM_TYPE mech, unsigned int flags) { 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. * All of this is greatly simplified by having the framework * register all supported mechanisms at initialization * time. */ 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; if (pList && count < *pulCount) pList[count] = mt->mech; count++; } rv = CKR_OK; if (pList && count > *pulCount) 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; res = calloc(1, type->obj_size); 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; LOG_FUNC_CALLED(context); if (!session || !session->slot || !(p11card = session->slot->card)) LOG_FUNC_RETURN(context, CKR_ARGUMENTS_BAD); /* See if we support this mechanism type */ mt = sc_pkcs11_find_mechanism(p11card, pMechanism->mechanism, CKF_DIGEST); if (mt == NULL) LOG_FUNC_RETURN(context, CKR_MECHANISM_INVALID); rv = session_start_operation(session, SC_PKCS11_OPERATION_DIGEST, mt, &operation); if (rv != CKR_OK) LOG_FUNC_RETURN(context, rv); memcpy(&operation->mechanism, pMechanism, sizeof(CK_MECHANISM)); rv = mt->md_init(operation); if (rv != CKR_OK) session_stop_operation(session, SC_PKCS11_OPERATION_DIGEST); LOG_FUNC_RETURN(context, rv); } 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) goto done; rv = op->type->md_update(op, pData, ulDataLen); done: if (rv != CKR_OK) session_stop_operation(session, SC_PKCS11_OPERATION_DIGEST); LOG_FUNC_RETURN(context, rv); } CK_RV sc_pkcs11_md_final(struct sc_pkcs11_session *session, CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen) { sc_pkcs11_operation_t *op; CK_RV rv; rv = session_get_operation(session, SC_PKCS11_OPERATION_DIGEST, &op); if (rv != CKR_OK) LOG_FUNC_RETURN(context, rv); /* This is a request for the digest length */ if (pData == NULL) *pulDataLen = 0; rv = op->type->md_final(op, pData, pulDataLen); if (rv == CKR_BUFFER_TOO_SMALL) LOG_FUNC_RETURN(context, pData == NULL ? CKR_OK : CKR_BUFFER_TOO_SMALL); session_stop_operation(session, SC_PKCS11_OPERATION_DIGEST); LOG_FUNC_RETURN(context, rv); } /* * Initialize a signing context. When we get here, we know * the key object is capable of signing _something_ */ CK_RV sc_pkcs11_sign_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; LOG_FUNC_CALLED(context); if (!session || !session->slot || !(p11card = session->slot->card)) LOG_FUNC_RETURN(context, CKR_ARGUMENTS_BAD); /* See if we support this mechanism type */ sc_log(context, "mechanism 0x%X, key-type 0x%X", pMechanism->mechanism, key_type); mt = sc_pkcs11_find_mechanism(p11card, pMechanism->mechanism, CKF_SIGN); if (mt == NULL) LOG_FUNC_RETURN(context, CKR_MECHANISM_INVALID); /* See if compatible with key type */ if (mt->key_type != key_type) LOG_FUNC_RETURN(context, CKR_KEY_TYPE_INCONSISTENT); rv = session_start_operation(session, SC_PKCS11_OPERATION_SIGN, mt, &operation); if (rv != CKR_OK) LOG_FUNC_RETURN(context, rv); memcpy(&operation->mechanism, pMechanism, sizeof(CK_MECHANISM)); rv = mt->sign_init(operation, key); if (rv != CKR_OK) session_stop_operation(session, SC_PKCS11_OPERATION_SIGN); LOG_FUNC_RETURN(context, rv); } 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; LOG_FUNC_CALLED(context); rv = session_get_operation(session, SC_PKCS11_OPERATION_SIGN, &op); if (rv != CKR_OK) LOG_FUNC_RETURN(context, rv); if (op->type->sign_update == NULL) { rv = CKR_KEY_TYPE_INCONSISTENT; goto done; } rv = op->type->sign_update(op, pData, ulDataLen); done: if (rv != CKR_OK) session_stop_operation(session, SC_PKCS11_OPERATION_SIGN); LOG_FUNC_RETURN(context, rv); } 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; LOG_FUNC_CALLED(context); rv = session_get_operation(session, SC_PKCS11_OPERATION_SIGN, &op); if (rv != CKR_OK) LOG_FUNC_RETURN(context, rv); /* Bail out for signature mechanisms that don't do hashing */ if (op->type->sign_final == NULL) { rv = CKR_KEY_TYPE_INCONSISTENT; goto done; } rv = op->type->sign_final(op, pSignature, pulSignatureLen); done: if (rv != CKR_BUFFER_TOO_SMALL && pSignature != NULL) session_stop_operation(session, SC_PKCS11_OPERATION_SIGN); LOG_FUNC_RETURN(context, rv); } 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) LOG_FUNC_RETURN(context, rv); /* Bail out for signature mechanisms that don't do hashing */ if (op->type->sign_size == NULL) { rv = CKR_KEY_TYPE_INCONSISTENT; goto done; } rv = op->type->sign_size(op, pLength); done: if (rv != CKR_OK) session_stop_operation(session, SC_PKCS11_OPERATION_SIGN); LOG_FUNC_RETURN(context, rv); } /* * Initialize a signature operation */ static CK_RV sc_pkcs11_signature_init(sc_pkcs11_operation_t *operation, struct sc_pkcs11_object *key) { struct hash_signature_info *info; struct signature_data *data; CK_RV rv; int can_do_it = 0; LOG_FUNC_CALLED(context); if (!(data = calloc(1, sizeof(*data)))) LOG_FUNC_RETURN(context, CKR_HOST_MEMORY); data->info = NULL; data->key = key; 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 */ info = (struct hash_signature_info *) operation->type->mech_data; if (info != NULL && !can_do_it) { /* 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); LOG_FUNC_RETURN(context, rv); } data->info = info; } operation->priv_data = data; LOG_FUNC_RETURN(context, CKR_OK); } static CK_RV sc_pkcs11_signature_update(sc_pkcs11_operation_t *operation, CK_BYTE_PTR pPart, CK_ULONG ulPartLen) { struct signature_data *data; LOG_FUNC_CALLED(context); sc_log(context, "data part length %li", ulPartLen); data = (struct signature_data *) operation->priv_data; if (data->md) { CK_RV rv = data->md->type->md_update(data->md, pPart, ulPartLen); LOG_FUNC_RETURN(context, rv); } /* This signature mechanism operates on the raw data */ if (data->buffer_len + ulPartLen > sizeof(data->buffer)) LOG_FUNC_RETURN(context, CKR_DATA_LEN_RANGE); memcpy(data->buffer + data->buffer_len, pPart, ulPartLen); data->buffer_len += ulPartLen; sc_log(context, "data length %li", data->buffer_len); LOG_FUNC_RETURN(context, CKR_OK); } static CK_RV sc_pkcs11_signature_final(sc_pkcs11_operation_t *operation, CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen) { struct signature_data *data; CK_RV rv; LOG_FUNC_CALLED(context); data = (struct signature_data *) operation->priv_data; sc_log(context, "data length %li", data->buffer_len); 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) LOG_FUNC_RETURN(context, rv); data->buffer_len = len; } 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); } 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) }; CK_KEY_TYPE key_type; CK_ATTRIBUTE attr_key_type = { CKA_KEY_TYPE, &key_type, sizeof(key_type) }; CK_RV rv; key = ((struct signature_data *) operation->priv_data)->key; /* * EC and GOSTR do not have CKA_MODULUS_BITS attribute. * But other code in framework treats them as if they do. * So should do switch(key_type) * and then get what ever attributes are needed. */ rv = key->ops->get_attribute(operation->session, key, &attr_key_type); if (rv == CKR_OK) { switch(key_type) { case CKK_RSA: rv = key->ops->get_attribute(operation->session, key, &attr); /* 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); *pLength = ((*pLength + 7)/8) * 2 ; /* 2*nLen in bytes */ break; case CKK_GOSTR3410: rv = key->ops->get_attribute(operation->session, key, &attr); if (rv == CKR_OK) *pLength = (*pLength + 7) / 8 * 2; break; default: rv = CKR_MECHANISM_INVALID; } } LOG_FUNC_RETURN(context, rv); } static void sc_pkcs11_signature_release(sc_pkcs11_operation_t *operation) { struct signature_data *data; data = (struct signature_data *) operation->priv_data; if (!data) return; sc_pkcs11_release_operation(&data->md); memset(data, 0, sizeof(*data)); free(data); } #ifdef ENABLE_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)); rv = mt->verif_init(operation, key); if (rv != CKR_OK) session_stop_operation(session, SC_PKCS11_OPERATION_VERIFY); return rv; } 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) { rv = CKR_KEY_TYPE_INCONSISTENT; goto done; } rv = op->type->verif_update(op, pData, ulDataLen); done: if (rv != CKR_OK) session_stop_operation(session, SC_PKCS11_OPERATION_VERIFY); return rv; } 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) { rv = CKR_KEY_TYPE_INCONSISTENT; goto done; } rv = op->type->verif_final(op, pSignature, ulSignatureLen); done: 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 = 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_KEY_TYPE key_type; CK_BYTE params[9 /* GOST_PARAMS_OID_SIZE */] = { 0 }; CK_ATTRIBUTE attr = {CKA_VALUE, NULL, 0}; CK_ATTRIBUTE attr_key_type = {CKA_KEY_TYPE, &key_type, sizeof(key_type)}; CK_ATTRIBUTE attr_key_params = {CKA_GOSTR3410_PARAMS, ¶ms, sizeof(params)}; 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 = calloc(1, attr.ulValueLen); attr.pValue = pubkey_value; rv = key->ops->get_attribute(operation->session, key, &attr); if (rv != CKR_OK) goto done; 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; } rv = sc_pkcs11_verify_data(pubkey_value, attr.ulValueLen, params, sizeof(params), operation->mechanism.mechanism, data->md, data->buffer, data->buffer_len, pSignature, ulSignatureLen); done: free(pubkey_value); return rv; } #endif /* * Initialize a decryption context. When we get here, we know * the key object is capable of decrypting _something_ */ 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) { struct sc_pkcs11_card *p11card; sc_pkcs11_operation_t *operation; sc_pkcs11_mechanism_type_t *mt; 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_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, CK_BYTE_PTR pEncryptedData, CK_ULONG ulEncryptedDataLen, CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen) { 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; } /* 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; } /* * Initialize a signature operation */ static CK_RV sc_pkcs11_decrypt_init(sc_pkcs11_operation_t *operation, struct sc_pkcs11_object *key) { struct signature_data *data; if (!(data = calloc(1, sizeof(*data)))) return CKR_HOST_MEMORY; data->key = key; operation->priv_data = data; return CKR_OK; } static CK_RV sc_pkcs11_decrypt(sc_pkcs11_operation_t *operation, CK_BYTE_PTR pEncryptedData, CK_ULONG ulEncryptedDataLen, CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen) { 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); } 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); } /* * 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; mt = calloc(1, sizeof(*mt)); 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; mt->sign_size = sc_pkcs11_signature_size; #ifdef ENABLE_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) { /* TODO */ } if (pInfo->flags & CKF_DERIVE) { mt->derive = sc_pkcs11_derive; } if (pInfo->flags & CKF_DECRYPT) { mt->decrypt_init = sc_pkcs11_decrypt_init; mt->decrypt = sc_pkcs11_decrypt; } return mt; } /* * Register generic mechanisms */ CK_RV sc_pkcs11_register_generic_mechanisms(struct sc_pkcs11_card *p11card) { #ifdef ENABLE_OPENSSL sc_pkcs11_register_openssl_mechanisms(p11card); #endif return CKR_OK; } /* * 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; CK_MECHANISM_INFO mech_info = sign_type->mech_info; if (!(hash_type = sc_pkcs11_find_mechanism(p11card, hash_mech, CKF_DIGEST))) return CKR_MECHANISM_INVALID; /* These hash-based mechs can only be used for sign/verify */ mech_info.flags &= (CKF_SIGN | CKF_SIGN_RECOVER | CKF_VERIFY | CKF_VERIFY_RECOVER); info = calloc(1, sizeof(*info)); info->mech = mech; info->sign_type = sign_type; info->hash_type = hash_type; info->sign_mech = sign_type->mech; info->hash_mech = hash_mech; new_type = sc_pkcs11_new_fw_mechanism(mech, &mech_info, sign_type->key_type, info); if (!new_type) return CKR_HOST_MEMORY; return sc_pkcs11_register_mechanism(p11card, new_type); }