/*
* COPYRIGHT (c) International Business Machines Corp. 2001-2017
*
* This program is provided under the terms of the Common Public License,
* version 1.0 (CPL-1.0). Any use, reproduction or distribution for this
* software constitutes recipient's acceptance of CPL-1.0 terms which can be
* found in the file LICENSE file or at
* https://opensource.org/licenses/cpl1.0.php
*/
// File: mech_rsa.c
//
// Mechanisms for RSA
//
// Routines contained within:
#include <pthread.h>
#include <stdio.h>
#include <string.h> // for memcmp() et al
#include <stdlib.h>
#include "pkcs11types.h"
#include "defs.h"
#include "host_defs.h"
#include "h_extern.h"
#include "tok_spec_struct.h"
#include "trace.h"
#include <openssl/crypto.h>
CK_RV rsa_get_key_info(OBJECT *key_obj, CK_ULONG *mod_bytes,
CK_OBJECT_CLASS *keyclass)
{
CK_RV rc;
CK_ATTRIBUTE *attr;
rc = template_attribute_find(key_obj->template, CKA_MODULUS, &attr);
if (rc == FALSE) {
TRACE_ERROR("Could not find CKA_MODULUS in the template\n");
return CKR_FUNCTION_FAILED;
}
*mod_bytes = attr->ulValueLen;
rc = template_attribute_find(key_obj->template, CKA_CLASS, &attr);
if (rc == FALSE) {
TRACE_ERROR("Could not find CKA_CLASS in the template\n");
return CKR_FUNCTION_FAILED;
}
*keyclass = *(CK_OBJECT_CLASS *) attr->pValue;
return CKR_OK;
}
/*
* Format an encryption block according to PKCS #1: RSA Encryption, Version
* 1.5.
*/
CK_RV rsa_format_block(STDLL_TokData_t *tokdata,
CK_BYTE *in_data,
CK_ULONG in_data_len,
CK_BYTE *out_data, CK_ULONG out_data_len, CK_ULONG type)
{
CK_ULONG padding_len, i;
CK_RV rc = CKR_OK;
if (!in_data || !out_data || !out_data_len) {
TRACE_ERROR("%s received bad argument(s)\n", __func__);
return CKR_FUNCTION_FAILED;
}
if (out_data_len < (in_data_len + 11)) {
TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL));
return CKR_BUFFER_TOO_SMALL;
}
/*
* The padding string PS shall consist of k-3-||D|| octets.
*/
padding_len = out_data_len - 3 - in_data_len;
/*
* For block types 01 and 02, the padding string is at least eight octets
* long, which is a security condition for public-key operations that
* prevents an attacker from recoving data by trying all possible
* encryption blocks.
*/
if ((type == 1 || type == 2) && ((padding_len) < 8)) {
TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE));
return CKR_DATA_LEN_RANGE;
}
/*
* The leading 00 octet.
*/
out_data[0] = (CK_BYTE) 0;
/*
* The block type.
*/
out_data[1] = (CK_BYTE) type;
switch (type) {
/*
* For block type 00, the octets shall have value 00.
* EB = 00 || 00 || 00 * i || D
* Where D must begin with a nonzero octet.
*/
case 0:
if (in_data[0] == (CK_BYTE) 0) {
TRACE_ERROR("%s\n", ock_err(ERR_DATA_INVALID));
return CKR_DATA_INVALID;
}
for (i = 2; i < (padding_len + 2); i++)
out_data[i] = (CK_BYTE) 0;
break;
/*
* For block type 01, they shall have value FF.
* EB = 00 || 01 || FF * i || 00 || D
*/
case 1:
for (i = 2; i < (padding_len + 2); i++)
out_data[i] = (CK_BYTE) 0xff;
break;
/*
* For block type 02, they shall be pseudorandomly generated and
* nonzero.
* EB = 00 || 02 || ?? * i || 00 || D
* Where ?? is nonzero.
*/
case 2:
rc = rng_generate(tokdata, &out_data[2], padding_len);
if (rc != CKR_OK) {
TRACE_DEVEL("rng_generate failed.\n");
return rc;
}
for (i = 2; i < (padding_len + 2); i++) {
while (out_data[i] == (CK_BYTE) 0) {
rc = rng_generate(tokdata, &out_data[i], 1);
if (rc != CKR_OK) {
TRACE_DEVEL("rng_generate failed.\n");
return rc;
}
}
}
break;
default:
TRACE_ERROR("%s\n", ock_err(ERR_DATA_INVALID));
return CKR_DATA_INVALID;
}
out_data[i] = (CK_BYTE) 0;
i++;
if (in_data_len)
memcpy(&out_data[i], in_data, in_data_len);
return rc;
}
/*
* Parse an encryption block according to PKCS #1: RSA Encryption, Version
* 1.5.
*/
CK_RV rsa_parse_block(CK_BYTE *in_data,
CK_ULONG in_data_len,
CK_BYTE *out_data,
CK_ULONG *out_data_len, CK_ULONG type)
{
CK_ULONG i;
CK_RV rc = CKR_OK;
if (!in_data || !out_data || !out_data_len) {
TRACE_ERROR("%s received bad argument(s)\n", __func__);
return CKR_FUNCTION_FAILED;
}
if (in_data_len <= 11) {
TRACE_DEVEL("%s\n", ock_err(ERR_FUNCTION_FAILED));
return CKR_FUNCTION_FAILED;
}
/*
* Check for the leading 00 octet.
*/
if (in_data[0] != (CK_BYTE) 0) {
TRACE_ERROR("%s\n", ock_err(ERR_ENCRYPTED_DATA_INVALID));
return CKR_ENCRYPTED_DATA_INVALID;
}
/*
* Check the block type.
*/
if (in_data[1] != (CK_BYTE) type) {
TRACE_ERROR("%s\n", ock_err(ERR_ENCRYPTED_DATA_INVALID));
return CKR_ENCRYPTED_DATA_INVALID;
}
/*
* The block type shall be a single octet indicating the structure of the
* encryption block. It shall have value 00, 01, or 02. For a private-key
* operation, the block type shall be 00 or 01. For a public-key
* operation, it shall be 02.
*
* For block type 00, the octets shall have value 00; for block type 01,
* they shall have value FF; and for block type 02, they shall be
* pseudorandomly generated and nonzero.
*
* For block type 00, the data must begin with a nonzero octet or have
* known length so that the encryption block can be parsed unambiguously.
* For block types 01 and 02, the encryption block can be parsed
* unambiguously since the padding string contains no octets with value 00
* and the padding string is separated from the data by an octet with
* value 00.
*/
switch (type) {
/*
* For block type 00, the octets shall have value 00.
* EB = 00 || 00 || 00 * i || D
* Where D must begin with a nonzero octet.
*/
case 0:
for (i = 2; i <= (in_data_len - 2); i++) {
if (in_data[i] != (CK_BYTE) 0)
break;
}
break;
/*
* For block type 01, they shall have value FF.
* EB = 00 || 01 || FF * i || 00 || D
*/
case 1:
for (i = 2; i <= (in_data_len - 2); i++) {
if (in_data[i] != (CK_BYTE) 0xff) {
if (in_data[i] == (CK_BYTE) 0) {
i++;
break;
}
TRACE_ERROR("%s\n", ock_err(ERR_ENCRYPTED_DATA_INVALID));
return CKR_ENCRYPTED_DATA_INVALID;
}
}
break;
/*
* For block type 02, they shall be pseudorandomly generated and
* nonzero.
* EB = 00 || 02 || ?? * i || 00 || D
* Where ?? is nonzero.
*/
case 2:
for (i = 2; i <= (in_data_len - 2); i++) {
if (in_data[i] == (CK_BYTE) 0) {
i++;
break;
}
}
break;
default:
TRACE_ERROR("%s\n", ock_err(ERR_ENCRYPTED_DATA_INVALID));
return CKR_ENCRYPTED_DATA_INVALID;
}
/*
* For block types 01 and 02, the padding string is at least eight octets
* long, which is a security condition for public-key operations that
* prevents an attacker from recoving data by trying all possible
* encryption blocks.
*/
if ((type == 1 || type == 2) && ((i - 3) < 8)) {
TRACE_ERROR("%s\n", ock_err(ERR_ENCRYPTED_DATA_INVALID));
return CKR_ENCRYPTED_DATA_INVALID;
}
if (in_data_len <= i) {
TRACE_ERROR("%s\n", ock_err(ERR_ENCRYPTED_DATA_INVALID));
return CKR_ENCRYPTED_DATA_INVALID;
}
if (*out_data_len < (in_data_len - i)) {
TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL));
return CKR_BUFFER_TOO_SMALL;
}
memcpy(out_data, &in_data[i], in_data_len - i);
*out_data_len = in_data_len - i;
return rc;
}
/* helper function for rsa-oaep */
CK_RV get_mgf_mech(CK_RSA_PKCS_MGF_TYPE mgf, CK_MECHANISM_TYPE *mech)
{
switch (mgf) {
case CKG_MGF1_SHA1:
*mech = CKM_SHA_1;
break;
case CKG_MGF1_SHA224:
*mech = CKM_SHA224;
break;
case CKG_MGF1_SHA256:
*mech = CKM_SHA256;
break;
case CKG_MGF1_SHA384:
*mech = CKM_SHA384;
break;
case CKG_MGF1_SHA512:
*mech = CKM_SHA512;
break;
default:
return CKR_MECHANISM_INVALID;
}
return CKR_OK;
}
//
//
CK_RV rsa_pkcs_encrypt(STDLL_TokData_t *tokdata,
SESSION *sess,
CK_BBOOL length_only,
ENCR_DECR_CONTEXT *ctx,
CK_BYTE *in_data,
CK_ULONG in_data_len,
CK_BYTE *out_data, CK_ULONG *out_data_len)
{
OBJECT *key_obj = NULL;
CK_ULONG modulus_bytes;
CK_OBJECT_CLASS keyclass;
CK_RV rc;
UNUSED(sess);
rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK);
if (rc != CKR_OK) {
TRACE_ERROR("Failed to acquire key from specified handle");
if (rc == CKR_OBJECT_HANDLE_INVALID)
return CKR_KEY_HANDLE_INVALID;
else
return rc;
}
rc = rsa_get_key_info(key_obj, &modulus_bytes, &keyclass);
if (rc != CKR_OK) {
TRACE_DEVEL("rsa_get_key_info failed.\n");
goto done;
}
// check input data length restrictions
//
if (in_data_len > (modulus_bytes - 11)) {
TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE));
rc = CKR_DATA_LEN_RANGE;
goto done;
}
if (length_only == TRUE) {
*out_data_len = modulus_bytes;
rc = CKR_OK;
goto done;
}
if (*out_data_len < modulus_bytes) {
*out_data_len = modulus_bytes;
TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL));
rc = CKR_BUFFER_TOO_SMALL;
goto done;
}
// this had better be a public key
if (keyclass != CKO_PUBLIC_KEY) {
TRACE_ERROR("This operation requires a public key.\n");
rc = CKR_KEY_FUNCTION_NOT_PERMITTED;
goto done;
}
if (token_specific.t_rsa_encrypt == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID));
rc = CKR_MECHANISM_INVALID;
goto done;
}
rc = token_specific.t_rsa_encrypt(tokdata, in_data, in_data_len, out_data,
out_data_len, key_obj);
if (rc != CKR_OK)
TRACE_DEVEL("Token Specific rsa encrypt failed.\n");
done:
object_put(tokdata, key_obj, TRUE);
key_obj = NULL;
return rc;
}
//
//
CK_RV rsa_pkcs_decrypt(STDLL_TokData_t *tokdata,
SESSION *sess,
CK_BBOOL length_only,
ENCR_DECR_CONTEXT *ctx,
CK_BYTE *in_data,
CK_ULONG in_data_len,
CK_BYTE *out_data, CK_ULONG *out_data_len)
{
OBJECT *key_obj = NULL;
CK_ULONG modulus_bytes;
CK_OBJECT_CLASS keyclass;
CK_RV rc;
UNUSED(sess);
rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK);
if (rc != CKR_OK) {
TRACE_ERROR("Failed to acquire key from specified handle");
if (rc == CKR_OBJECT_HANDLE_INVALID)
return CKR_KEY_HANDLE_INVALID;
else
return rc;
}
rc = rsa_get_key_info(key_obj, &modulus_bytes, &keyclass);
if (rc != CKR_OK) {
TRACE_DEVEL("rsa_get_key_info failed.\n");
goto done;
}
// check input data length restrictions
//
if (in_data_len != modulus_bytes) {
TRACE_ERROR("%s\n", ock_err(ERR_ENCRYPTED_DATA_LEN_RANGE));
rc = CKR_ENCRYPTED_DATA_LEN_RANGE;
goto done;
}
if (length_only == TRUE) {
// this is not exact but it's the upper bound; otherwise we'll need
// to do the RSA operation just to get the required length
//
*out_data_len = modulus_bytes - 11;
rc = CKR_OK;
goto done;
}
if (*out_data_len < (modulus_bytes - 11)) {
*out_data_len = modulus_bytes - 11;
TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL));
rc = CKR_BUFFER_TOO_SMALL;
goto done;
}
// this had better be a private key
if (keyclass != CKO_PRIVATE_KEY) {
TRACE_ERROR("This operation requires a private key.\n");
rc = CKR_KEY_FUNCTION_NOT_PERMITTED;
goto done;
}
/* check for token specific call first */
if (token_specific.t_rsa_decrypt == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID));
rc = CKR_MECHANISM_INVALID;
goto done;
}
rc = token_specific.t_rsa_decrypt(tokdata, in_data, in_data_len, out_data,
out_data_len, key_obj);
if (rc != CKR_OK) {
if (rc == CKR_DATA_LEN_RANGE) {
TRACE_ERROR("%s\n", ock_err(ERR_ENCRYPTED_DATA_LEN_RANGE));
rc = CKR_ENCRYPTED_DATA_LEN_RANGE;
goto done;
}
TRACE_DEVEL("Token Specific rsa decrypt failed.\n");
}
done:
object_put(tokdata, key_obj, TRUE);
key_obj = NULL;
return rc;
}
CK_RV rsa_oaep_crypt(STDLL_TokData_t *tokdata, SESSION *sess,
CK_BBOOL length_only,
ENCR_DECR_CONTEXT *ctx, CK_BYTE *in_data,
CK_ULONG in_data_len, CK_BYTE *out_data,
CK_ULONG *out_data_len, CK_BBOOL encrypt)
{
OBJECT *key_obj = NULL;
CK_ULONG hlen, modulus_bytes;
CK_OBJECT_CLASS keyclass;
CK_BYTE hash[MAX_SHA_HASH_SIZE];
CK_RV rc;
CK_RSA_PKCS_OAEP_PARAMS_PTR oaepParms = NULL;
UNUSED(sess);
rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK);
if (rc != CKR_OK) {
TRACE_ERROR("Failed to acquire key from specified handle");
if (rc == CKR_OBJECT_HANDLE_INVALID)
return CKR_KEY_HANDLE_INVALID;
else
return rc;
}
rc = rsa_get_key_info(key_obj, &modulus_bytes, &keyclass);
if (rc != CKR_OK) {
TRACE_DEVEL("rsa_get_key_info failed.\n");
rc = CKR_FUNCTION_FAILED;
goto done;
}
if (length_only == TRUE) {
*out_data_len = modulus_bytes;
rc = CKR_OK;
goto done;
}
if (*out_data_len < modulus_bytes) {
*out_data_len = modulus_bytes;
TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL));
rc = CKR_BUFFER_TOO_SMALL;
goto done;
}
/*
* To help mitigate timing and fault attacks when decrypting,
* check oaep parameters that are passed in right now and compute
* the hash of the Label.
*
* PKCS#11v2.20, section 12.1.7, Step a: if "source" is empty,
* then pSourceData and ulSourceDatalen must be NULL, and zero
* respectively.
*/
oaepParms = (CK_RSA_PKCS_OAEP_PARAMS_PTR) ctx->mech.pParameter;
if (!(oaepParms->source) && (oaepParms->pSourceData ||
oaepParms->ulSourceDataLen)) {
TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID));
rc = CKR_MECHANISM_PARAM_INVALID;
goto done;
}
/* verify hashAlg now as well as get hash size. */
hlen = 0;
rc = get_sha_size(oaepParms->hashAlg, &hlen);
if (rc != CKR_OK) {
TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID));
rc = CKR_MECHANISM_PARAM_INVALID;
goto done;
}
/* modulus size should be >= 2*hashsize+2 */
if (modulus_bytes < (2 * hlen + 2)) {
TRACE_ERROR("%s\n", ock_err(ERR_KEY_SIZE_RANGE));
rc = CKR_KEY_SIZE_RANGE;
goto done;
}
/* hash the label now */
if (!(oaepParms->pSourceData) || !(oaepParms->ulSourceDataLen))
rc = compute_sha(tokdata, (CK_BYTE *)"", 0, hash, oaepParms->hashAlg);
else
rc = compute_sha(tokdata, oaepParms->pSourceData,
oaepParms->ulSourceDataLen, hash, oaepParms->hashAlg);
if (rc != CKR_OK)
goto done;
if (encrypt) {
if (in_data_len > (modulus_bytes - 2 * hlen - 2)) {
TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE));
rc = CKR_DATA_LEN_RANGE;
goto done;
}
// this had better be a public key
if (keyclass != CKO_PUBLIC_KEY) {
TRACE_ERROR("This operation requires a public key.\n");
rc = CKR_KEY_FUNCTION_NOT_PERMITTED;
goto done;
}
if (token_specific.t_rsa_oaep_encrypt == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID));
rc = CKR_MECHANISM_INVALID;
goto done;
}
rc = token_specific.t_rsa_oaep_encrypt(tokdata, ctx, in_data,
in_data_len, out_data,
out_data_len, hash, hlen);
} else {
// decrypt
if (in_data_len != modulus_bytes) {
TRACE_ERROR("%s\n", ock_err(ERR_ENCRYPTED_DATA_LEN_RANGE));
rc = CKR_ENCRYPTED_DATA_LEN_RANGE;
goto done;
}
// this had better be a private key
if (keyclass != CKO_PRIVATE_KEY) {
TRACE_ERROR("This operation requires a private key.\n");
rc = CKR_KEY_FUNCTION_NOT_PERMITTED;
goto done;
}
if (token_specific.t_rsa_oaep_decrypt == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID));
rc = CKR_MECHANISM_INVALID;
goto done;
}
rc = token_specific.t_rsa_oaep_decrypt(tokdata, ctx, in_data,
in_data_len, out_data,
out_data_len, hash, hlen);
}
if (rc != CKR_OK)
TRACE_DEVEL("Token Specific rsa oaep decrypt failed.\n");
done:
object_put(tokdata, key_obj, TRUE);
key_obj = NULL;
return rc;
}
CK_RV rsa_pkcs_sign(STDLL_TokData_t *tokdata,
SESSION *sess,
CK_BBOOL length_only,
SIGN_VERIFY_CONTEXT *ctx,
CK_BYTE *in_data,
CK_ULONG in_data_len,
CK_BYTE *out_data, CK_ULONG *out_data_len)
{
OBJECT *key_obj = NULL;
CK_ULONG modulus_bytes;
CK_OBJECT_CLASS keyclass;
CK_RV rc;
if (!sess || !ctx || !out_data_len) {
TRACE_ERROR("%s received bad argument(s)\n", __func__);
return CKR_FUNCTION_FAILED;
}
rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK);
if (rc != CKR_OK) {
TRACE_ERROR("Failed to acquire key from specified handle");
if (rc == CKR_OBJECT_HANDLE_INVALID)
return CKR_KEY_HANDLE_INVALID;
else
return rc;
}
rc = rsa_get_key_info(key_obj, &modulus_bytes, &keyclass);
if (rc != CKR_OK) {
TRACE_DEVEL("rsa_get_key_info failed.\n");
goto done;
}
// check input data length restrictions
//
if (in_data_len > (modulus_bytes - 11)) {
TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE));
rc = CKR_DATA_LEN_RANGE;
goto done;
}
if (length_only == TRUE) {
*out_data_len = modulus_bytes;
rc = CKR_OK;
goto done;
}
if (*out_data_len < modulus_bytes) {
*out_data_len = modulus_bytes;
TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL));
rc = CKR_BUFFER_TOO_SMALL;
goto done;
}
// this had better be a private key
//
if (keyclass != CKO_PRIVATE_KEY) {
TRACE_ERROR("This operation requires a private key.\n");
rc = CKR_KEY_FUNCTION_NOT_PERMITTED;
goto done;
}
/* check for token specific call first */
if (token_specific.t_rsa_sign == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID));
rc = CKR_MECHANISM_INVALID;
goto done;
}
rc = token_specific.t_rsa_sign(tokdata, sess, in_data, in_data_len,
out_data, out_data_len, key_obj);
if (rc != CKR_OK)
TRACE_DEVEL("Token Specific rsa sign failed.\n");
done:
object_put(tokdata, key_obj, TRUE);
key_obj = NULL;
return rc;
}
//
//
CK_RV rsa_pkcs_verify(STDLL_TokData_t *tokdata,
SESSION *sess,
SIGN_VERIFY_CONTEXT *ctx,
CK_BYTE *in_data,
CK_ULONG in_data_len,
CK_BYTE *signature, CK_ULONG sig_len)
{
OBJECT *key_obj = NULL;
CK_ULONG modulus_bytes;
CK_OBJECT_CLASS keyclass;
CK_RV rc;
rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK);
if (rc != CKR_OK) {
TRACE_ERROR("Failed to acquire key from specified handle");
if (rc == CKR_OBJECT_HANDLE_INVALID)
return CKR_KEY_HANDLE_INVALID;
else
return rc;
}
rc = rsa_get_key_info(key_obj, &modulus_bytes, &keyclass);
if (rc != CKR_OK) {
TRACE_DEVEL("rsa_get_key_info failed.\n");
goto done;
}
// check input data length restrictions
//
if (sig_len != modulus_bytes) {
TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_LEN_RANGE));
rc = CKR_SIGNATURE_LEN_RANGE;
goto done;
}
// verifying is a public key operation
//
if (keyclass != CKO_PUBLIC_KEY) {
TRACE_ERROR("This operation requires a public key.\n");
rc = CKR_KEY_FUNCTION_NOT_PERMITTED;
goto done;
}
/* check for token specific call first */
if (token_specific.t_rsa_verify == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID));
rc = CKR_MECHANISM_INVALID;
goto done;
}
rc = token_specific.t_rsa_verify(tokdata, sess, in_data, in_data_len,
signature, sig_len, key_obj);
if (rc != CKR_OK)
TRACE_DEVEL("Token Specific rsa verify failed.\n");
done:
object_put(tokdata, key_obj, TRUE);
key_obj = NULL;
return rc;
}
//
//
CK_RV rsa_pkcs_verify_recover(STDLL_TokData_t *tokdata,
SESSION *sess,
CK_BBOOL length_only,
SIGN_VERIFY_CONTEXT *ctx,
CK_BYTE *signature,
CK_ULONG sig_len,
CK_BYTE *out_data, CK_ULONG *out_data_len)
{
OBJECT *key_obj = NULL;
CK_OBJECT_CLASS keyclass;
CK_ULONG modulus_bytes;
CK_RV rc;
if (!sess || !ctx || !out_data_len) {
TRACE_ERROR("%s received bad argument(s)\n", __func__);
return CKR_FUNCTION_FAILED;
}
rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK);
if (rc != CKR_OK) {
TRACE_ERROR("Failed to acquire key from specified handle");
if (rc == CKR_OBJECT_HANDLE_INVALID)
return CKR_KEY_HANDLE_INVALID;
else
return rc;
}
rc = rsa_get_key_info(key_obj, &modulus_bytes, &keyclass);
if (rc != CKR_OK) {
TRACE_DEVEL("rsa_get_key_info failed.\n");
goto done;
}
// check input data length restrictions
//
if (sig_len != modulus_bytes) {
TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_LEN_RANGE));
rc = CKR_SIGNATURE_LEN_RANGE;
goto done;
}
if (length_only == TRUE) {
*out_data_len = modulus_bytes - 11;
rc = CKR_OK;
goto done;
}
/* this had better be a public key */
if (keyclass != CKO_PUBLIC_KEY) {
TRACE_ERROR("This operation requires a public key.\n");
rc = CKR_KEY_FUNCTION_NOT_PERMITTED;
goto done;
}
/* check for token specific call first */
if (token_specific.t_rsa_verify_recover == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID));
rc = CKR_MECHANISM_INVALID;
goto done;
}
rc = token_specific.t_rsa_verify_recover(tokdata, signature, sig_len,
out_data, out_data_len, key_obj);
if (rc != CKR_OK)
TRACE_DEVEL("Token Specific rsa verify failed.\n");
done:
object_put(tokdata, key_obj, TRUE);
key_obj = NULL;
return rc;
}
//
//
CK_RV rsa_x509_encrypt(STDLL_TokData_t *tokdata,
SESSION *sess,
CK_BBOOL length_only,
ENCR_DECR_CONTEXT *ctx,
CK_BYTE *in_data,
CK_ULONG in_data_len,
CK_BYTE *out_data, CK_ULONG *out_data_len)
{
OBJECT *key_obj = NULL;
CK_OBJECT_CLASS keyclass;
CK_ULONG modulus_bytes;
CK_RV rc;
UNUSED(sess);
rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK);
if (rc != CKR_OK) {
TRACE_ERROR("Failed to acquire key from specified handle");
if (rc == CKR_OBJECT_HANDLE_INVALID)
return CKR_KEY_HANDLE_INVALID;
else
return rc;
}
rc = rsa_get_key_info(key_obj, &modulus_bytes, &keyclass);
if (rc != CKR_OK) {
TRACE_DEVEL("rsa_get_key_info failed.\n");
goto done;
}
// CKM_RSA_X_509 requires input data length to be no bigger than the modulus
//
if (in_data_len > modulus_bytes) {
TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE));
return CKR_DATA_LEN_RANGE;
}
if (length_only == TRUE) {
*out_data_len = modulus_bytes;
rc = CKR_OK;
goto done;
}
if (*out_data_len < modulus_bytes) {
*out_data_len = modulus_bytes;
TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL));
rc = CKR_BUFFER_TOO_SMALL;
goto done;
}
/* this had better be a public key */
if (keyclass != CKO_PUBLIC_KEY) {
TRACE_ERROR("This operation requires a public key.\n");
rc = CKR_KEY_FUNCTION_NOT_PERMITTED;
goto done;
}
/* check for token specific call first */
if (token_specific.t_rsa_x509_encrypt == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID));
rc = CKR_MECHANISM_INVALID;
goto done;
}
rc = token_specific.t_rsa_x509_encrypt(tokdata, in_data, in_data_len,
out_data, out_data_len, key_obj);
if (rc != CKR_OK)
TRACE_DEVEL("Token Specific rsa x509 encrypt failed.\n");
done:
object_put(tokdata, key_obj, TRUE);
key_obj = NULL;
return rc;
}
//
//
CK_RV rsa_x509_decrypt(STDLL_TokData_t *tokdata,
SESSION *sess,
CK_BBOOL length_only,
ENCR_DECR_CONTEXT *ctx,
CK_BYTE *in_data,
CK_ULONG in_data_len,
CK_BYTE *out_data, CK_ULONG *out_data_len)
{
OBJECT *key_obj = NULL;
CK_ULONG modulus_bytes;
CK_OBJECT_CLASS keyclass;
CK_RV rc;
UNUSED(sess);
rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK);
if (rc != CKR_OK) {
TRACE_ERROR("Failed to acquire key from specified handle");
if (rc == CKR_OBJECT_HANDLE_INVALID)
return CKR_KEY_HANDLE_INVALID;
else
return rc;
}
rc = rsa_get_key_info(key_obj, &modulus_bytes, &keyclass);
if (rc != CKR_OK) {
TRACE_DEVEL("rsa_get_key_info failed.\n");
goto done;
}
// check input data length restrictions
//
if (in_data_len != modulus_bytes) {
TRACE_ERROR("%s\n", ock_err(ERR_ENCRYPTED_DATA_LEN_RANGE));
rc = CKR_ENCRYPTED_DATA_LEN_RANGE;
goto done;
}
if (length_only == TRUE) {
*out_data_len = modulus_bytes;
rc = CKR_OK;
goto done;
}
// Although X.509 prepads with zeros, we don't strip it after
// decryption (PKCS #11 specifies that X.509 decryption is supposed
// to produce K bytes of cleartext where K is the modulus length)
//
if (*out_data_len < modulus_bytes) {
*out_data_len = modulus_bytes;
TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL));
rc = CKR_BUFFER_TOO_SMALL;
goto done;
}
/* this had better be a private key */
if (keyclass != CKO_PRIVATE_KEY) {
TRACE_ERROR("This operation requires a private key.\n");
rc = CKR_KEY_FUNCTION_NOT_PERMITTED;
goto done;
}
/* check for token specific call first */
if (token_specific.t_rsa_x509_encrypt == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID));
rc = CKR_MECHANISM_INVALID;
goto done;
}
rc = token_specific.t_rsa_x509_decrypt(tokdata, in_data, in_data_len,
out_data, out_data_len, key_obj);
if (rc != CKR_OK)
TRACE_ERROR("Token Specific rsa x509 decrypt failed.\n");
// ckm_rsa_operation is used for all RSA operations so we need to adjust
// the return code accordingly
//
if (rc == CKR_DATA_LEN_RANGE) {
TRACE_ERROR("%s\n", ock_err(ERR_ENCRYPTED_DATA_LEN_RANGE));
rc = CKR_ENCRYPTED_DATA_LEN_RANGE;
goto done;
}
done:
object_put(tokdata, key_obj, TRUE);
key_obj = NULL;
return rc;
}
//
//
CK_RV rsa_x509_sign(STDLL_TokData_t *tokdata,
SESSION *sess,
CK_BBOOL length_only,
SIGN_VERIFY_CONTEXT *ctx,
CK_BYTE *in_data,
CK_ULONG in_data_len,
CK_BYTE *out_data, CK_ULONG *out_data_len)
{
OBJECT *key_obj = NULL;
CK_ULONG modulus_bytes;
CK_OBJECT_CLASS keyclass;
CK_RV rc;
if (!sess || !ctx || !out_data_len) {
TRACE_ERROR("%s received bad argument(s)\n", __func__);
return CKR_FUNCTION_FAILED;
}
rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK);
if (rc != CKR_OK) {
TRACE_ERROR("Failed to acquire key from specified handle");
if (rc == CKR_OBJECT_HANDLE_INVALID)
return CKR_KEY_HANDLE_INVALID;
else
return rc;
}
rc = rsa_get_key_info(key_obj, &modulus_bytes, &keyclass);
if (rc != CKR_OK) {
TRACE_DEVEL("rsa_get_key_info failed.\n");
goto done;
}
// check input data length restrictions
//
if (in_data_len > modulus_bytes) {
TRACE_ERROR("%s\n", ock_err(ERR_DATA_LEN_RANGE));
rc = CKR_DATA_LEN_RANGE;
goto done;
}
if (length_only == TRUE) {
*out_data_len = modulus_bytes;
rc = CKR_OK;
goto done;
}
if (*out_data_len < modulus_bytes) {
*out_data_len = modulus_bytes;
TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL));
rc = CKR_BUFFER_TOO_SMALL;
goto done;
}
/* this had better be a private key */
if (keyclass != CKO_PRIVATE_KEY) {
TRACE_ERROR("This operation requires a private key.\n");
rc = CKR_KEY_FUNCTION_NOT_PERMITTED;
goto done;
}
/* check for token specific call first */
if (token_specific.t_rsa_x509_sign == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID));
rc = CKR_MECHANISM_INVALID;
goto done;
}
rc = token_specific.t_rsa_x509_sign(tokdata, in_data, in_data_len, out_data,
out_data_len, key_obj);
if (rc != CKR_OK)
TRACE_DEVEL("Token Specific rsa x509 sign failed.\n");
done:
object_put(tokdata, key_obj, TRUE);
key_obj = NULL;
return rc;
}
//
//
CK_RV rsa_x509_verify(STDLL_TokData_t *tokdata,
SESSION *sess,
SIGN_VERIFY_CONTEXT *ctx,
CK_BYTE *in_data,
CK_ULONG in_data_len,
CK_BYTE *signature, CK_ULONG sig_len)
{
OBJECT *key_obj = NULL;
CK_OBJECT_CLASS keyclass;
CK_ULONG modulus_bytes;
CK_RV rc;
UNUSED(sess);
rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK);
if (rc != CKR_OK) {
TRACE_ERROR("Failed to acquire key from specified handle");
if (rc == CKR_OBJECT_HANDLE_INVALID)
return CKR_KEY_HANDLE_INVALID;
else
return rc;
}
rc = rsa_get_key_info(key_obj, &modulus_bytes, &keyclass);
if (rc != CKR_OK) {
TRACE_DEVEL("rsa_get_key_info failed.\n");
goto done;
}
// check input data length restrictions
//
if (sig_len != modulus_bytes) {
TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_LEN_RANGE));
rc = CKR_SIGNATURE_LEN_RANGE;
goto done;
}
/* this had better be a public key */
if (keyclass != CKO_PUBLIC_KEY) {
TRACE_ERROR("This operation requires a public key.\n");
rc = CKR_KEY_FUNCTION_NOT_PERMITTED;
goto done;
}
/* check for token specific call first */
if (token_specific.t_rsa_x509_verify == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID));
rc = CKR_MECHANISM_INVALID;
goto done;
}
// verify is a public key operation --> encrypt
//
rc = token_specific.t_rsa_x509_verify(tokdata, in_data, in_data_len,
signature, sig_len, key_obj);
if (rc != CKR_OK)
TRACE_ERROR("Token Specific rsa x509 verify failed.\n");
done:
object_put(tokdata, key_obj, TRUE);
key_obj = NULL;
return rc;
}
//
//
CK_RV rsa_x509_verify_recover(STDLL_TokData_t *tokdata,
SESSION *sess,
CK_BBOOL length_only,
SIGN_VERIFY_CONTEXT *ctx,
CK_BYTE *signature,
CK_ULONG sig_len,
CK_BYTE *out_data, CK_ULONG *out_data_len)
{
OBJECT *key_obj = NULL;
CK_ULONG modulus_bytes;
CK_OBJECT_CLASS keyclass;
CK_RV rc;
if (!sess || !ctx || !out_data_len) {
TRACE_ERROR("%s received bad argument(s)\n", __func__);
return CKR_FUNCTION_FAILED;
}
rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK);
if (rc != CKR_OK) {
TRACE_ERROR("Failed to acquire key from specified handle");
if (rc == CKR_OBJECT_HANDLE_INVALID)
return CKR_KEY_HANDLE_INVALID;
else
return rc;
}
rc = rsa_get_key_info(key_obj, &modulus_bytes, &keyclass);
if (rc != CKR_OK) {
TRACE_DEVEL("rsa_get_key_info failed.\n");
goto done;
}
// check input data length restrictions
//
if (sig_len != modulus_bytes) {
TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_LEN_RANGE));
return CKR_SIGNATURE_LEN_RANGE;
}
if (length_only == TRUE) {
*out_data_len = modulus_bytes;
rc = CKR_OK;
goto done;
}
// we perform no stripping of prepended zero bytes here
//
if (*out_data_len < modulus_bytes) {
*out_data_len = modulus_bytes;
TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL));
rc = CKR_BUFFER_TOO_SMALL;
goto done;
}
/* this had better be a public key */
if (keyclass != CKO_PUBLIC_KEY) {
TRACE_ERROR("This operation requires a public key.\n");
rc = CKR_KEY_FUNCTION_NOT_PERMITTED;
goto done;
}
/* check for token specific call first */
if (token_specific.t_rsa_x509_verify_recover == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID));
rc = CKR_MECHANISM_INVALID;
goto done;
}
// verify is a public key operation --> encrypt
//
rc = token_specific.t_rsa_x509_verify_recover(tokdata, signature, sig_len,
out_data, out_data_len,
key_obj);
if (rc != CKR_OK)
TRACE_ERROR("Token Specific rsa x509 verify recover.\n");
done:
object_put(tokdata, key_obj, TRUE);
key_obj = NULL;
return rc;
}
CK_RV rsa_pss_sign(STDLL_TokData_t *tokdata, SESSION *sess,
CK_BBOOL length_only,
SIGN_VERIFY_CONTEXT *ctx, CK_BYTE *in_data,
CK_ULONG in_data_len, CK_BYTE *out_data,
CK_ULONG *out_data_len)
{
CK_RV rc;
OBJECT *key_obj = NULL;
CK_ULONG modulus_bytes, hlen;
CK_OBJECT_CLASS keyclass;
CK_RSA_PKCS_PSS_PARAMS_PTR pssParms = NULL;
if (!sess || !ctx || !out_data_len) {
TRACE_ERROR("%s received bad argument(s)\n", __func__);
return CKR_FUNCTION_FAILED;
}
rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK);
if (rc != CKR_OK) {
TRACE_ERROR("Failed to acquire key from specified handle");
if (rc == CKR_OBJECT_HANDLE_INVALID)
return CKR_KEY_HANDLE_INVALID;
else
return rc;
}
/* get modulus and key class */
rc = rsa_get_key_info(key_obj, &modulus_bytes, &keyclass);
if (rc != CKR_OK) {
TRACE_DEVEL("rsa_get_key_info failed.\n");
goto done;
}
if (length_only == TRUE) {
*out_data_len = modulus_bytes;
rc = CKR_OK;
goto done;
}
/* verify hashAlg now as well as get hash size. */
pssParms = (CK_RSA_PKCS_PSS_PARAMS_PTR) ctx->mech.pParameter;
hlen = 0;
rc = get_sha_size(pssParms->hashAlg, &hlen);
if (rc != CKR_OK) {
TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID));
rc = CKR_MECHANISM_PARAM_INVALID;
goto done;
}
/* pkcs#11v2.2, 12.1.10 states that this mechanism does not
* compute a hash value on the message to be signed.
* It assumes the input data is the hashed message.
*/
if (in_data_len != hlen) {
TRACE_ERROR("%s\n", ock_err(CKR_DATA_LEN_RANGE));
rc = CKR_DATA_LEN_RANGE;
goto done;
}
if (*out_data_len < modulus_bytes) {
*out_data_len = modulus_bytes;
TRACE_ERROR("%s\n", ock_err(ERR_BUFFER_TOO_SMALL));
rc = CKR_BUFFER_TOO_SMALL;
goto done;
}
/* this had better be a private key */
if (keyclass != CKO_PRIVATE_KEY) {
TRACE_ERROR("This operation requires a private key.\n");
rc = CKR_KEY_FUNCTION_NOT_PERMITTED;
goto done;
}
if (token_specific.t_rsa_pss_sign == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID));
rc = CKR_MECHANISM_INVALID;
goto done;
}
rc = token_specific.t_rsa_pss_sign(tokdata, sess, ctx, in_data, in_data_len,
out_data, out_data_len);
if (rc != CKR_OK)
TRACE_DEVEL("Token Specific rsa pss sign failed.\n");
done:
object_put(tokdata, key_obj, TRUE);
key_obj = NULL;
return rc;
}
CK_RV rsa_pss_verify(STDLL_TokData_t *tokdata, SESSION *sess,
SIGN_VERIFY_CONTEXT *ctx, CK_BYTE *in_data,
CK_ULONG in_data_len, CK_BYTE *signature,
CK_ULONG sig_len)
{
CK_RV rc;
OBJECT *key_obj = NULL;
CK_ULONG modulus_bytes;
CK_OBJECT_CLASS keyclass;
rc = object_mgr_find_in_map1(tokdata, ctx->key, &key_obj, READ_LOCK);
if (rc != CKR_OK) {
TRACE_ERROR("Failed to acquire key from specified handle");
if (rc == CKR_OBJECT_HANDLE_INVALID)
return CKR_KEY_HANDLE_INVALID;
else
return rc;
}
/* get modulus and key class */
rc = rsa_get_key_info(key_obj, &modulus_bytes, &keyclass);
if (rc != CKR_OK) {
TRACE_DEVEL("rsa_get_key_info failed.\n");
goto done;
}
/* check input data length restrictions */
if (sig_len != modulus_bytes) {
TRACE_ERROR("%s\n", ock_err(ERR_SIGNATURE_LEN_RANGE));
rc = CKR_SIGNATURE_LEN_RANGE;
goto done;
}
/* this had better be a public key */
if (keyclass != CKO_PUBLIC_KEY) {
TRACE_ERROR("This operation requires a public key.\n");
rc = CKR_KEY_FUNCTION_NOT_PERMITTED;
goto done;
}
if (token_specific.t_rsa_pss_verify == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID));
rc = CKR_MECHANISM_INVALID;
goto done;
}
rc = token_specific.t_rsa_pss_verify(tokdata, sess, ctx, in_data,
in_data_len, signature, sig_len);
if (rc != CKR_OK)
TRACE_ERROR("Token Specific rsa pss verify.\n");
done:
object_put(tokdata, key_obj, TRUE);
key_obj = NULL;
return rc;
}
CK_RV rsa_hash_pss_sign(STDLL_TokData_t *tokdata, SESSION *sess,
CK_BBOOL length_only,
SIGN_VERIFY_CONTEXT *ctx, CK_BYTE *in_data,
CK_ULONG in_data_len, CK_BYTE *sig, CK_ULONG *sig_len)
{
CK_ULONG hlen;
CK_BYTE hash[MAX_SHA_HASH_SIZE];
DIGEST_CONTEXT digest_ctx;
SIGN_VERIFY_CONTEXT sign_ctx;
CK_MECHANISM digest_mech, sign_mech;
CK_RV rc;
if (!sess || !ctx || !in_data) {
TRACE_ERROR("%s received bad argument(s)\n", __func__);
return CKR_FUNCTION_FAILED;
}
memset(&digest_ctx, 0x0, sizeof(digest_ctx));
memset(&sign_ctx, 0x0, sizeof(sign_ctx));
switch (ctx->mech.mechanism) {
case CKM_SHA1_RSA_PKCS_PSS:
digest_mech.mechanism = CKM_SHA_1;
break;
case CKM_SHA224_RSA_PKCS_PSS:
digest_mech.mechanism = CKM_SHA224;
break;
case CKM_SHA256_RSA_PKCS_PSS:
digest_mech.mechanism = CKM_SHA256;
break;
case CKM_SHA384_RSA_PKCS_PSS:
digest_mech.mechanism = CKM_SHA384;
break;
case CKM_SHA512_RSA_PKCS_PSS:
digest_mech.mechanism = CKM_SHA512;
break;
default:
return CKR_MECHANISM_INVALID;
}
digest_mech.ulParameterLen = 0;
digest_mech.pParameter = NULL;
rc = get_sha_size(digest_mech.mechanism, &hlen);
if (rc != CKR_OK) {
TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID));
return CKR_MECHANISM_PARAM_INVALID;
}
rc = digest_mgr_init(tokdata, sess, &digest_ctx, &digest_mech);
if (rc != CKR_OK) {
TRACE_DEVEL("Digest Mgr Init failed.\n");
return rc;
}
rc = digest_mgr_digest(tokdata, sess, length_only, &digest_ctx,
in_data, in_data_len, hash, &hlen);
if (rc != CKR_OK) {
TRACE_DEVEL("Digest Mgr Digest failed.\n");
return rc;
}
/* sign the hash */
sign_mech.mechanism = CKM_RSA_PKCS_PSS;
sign_mech.ulParameterLen = ctx->mech.ulParameterLen;
sign_mech.pParameter = ctx->mech.pParameter;
rc = sign_mgr_init(tokdata, sess, &sign_ctx, &sign_mech, FALSE, ctx->key);
if (rc != CKR_OK) {
TRACE_DEVEL("Sign Mgr Init failed.\n");
goto done;
}
rc = sign_mgr_sign(tokdata, sess, length_only, &sign_ctx, hash, hlen,
sig, sig_len);
if (rc != CKR_OK)
TRACE_DEVEL("Sign Mgr Sign failed.\n");
done:
sign_mgr_cleanup(&sign_ctx);
return rc;
}
CK_RV rsa_hash_pss_update(STDLL_TokData_t *tokdata, SESSION *sess,
SIGN_VERIFY_CONTEXT *ctx,
CK_BYTE *in_data, CK_ULONG in_data_len)
{
DIGEST_CONTEXT *digest_ctx = NULL;
CK_MECHANISM digest_mech;
CK_RV rc;
if (!sess || !ctx) {
TRACE_ERROR("%s received bad argument(s)\n", __func__);
return CKR_FUNCTION_FAILED;
}
/* see if digest has already been through init */
digest_ctx = (DIGEST_CONTEXT *) ctx->context;
if (digest_ctx->active == FALSE) {
switch (ctx->mech.mechanism) {
case CKM_SHA1_RSA_PKCS_PSS:
digest_mech.mechanism = CKM_SHA_1;
break;
case CKM_SHA224_RSA_PKCS_PSS:
digest_mech.mechanism = CKM_SHA224;
break;
case CKM_SHA256_RSA_PKCS_PSS:
digest_mech.mechanism = CKM_SHA256;
break;
case CKM_SHA384_RSA_PKCS_PSS:
digest_mech.mechanism = CKM_SHA384;
break;
case CKM_SHA512_RSA_PKCS_PSS:
digest_mech.mechanism = CKM_SHA512;
break;
default:
return CKR_MECHANISM_INVALID;
}
digest_mech.ulParameterLen = 0;
digest_mech.pParameter = NULL;
rc = digest_mgr_init(tokdata, sess, digest_ctx, &digest_mech);
if (rc != CKR_OK) {
TRACE_DEVEL("Digest Mgr Init failed.\n");
return rc;
}
}
rc = digest_mgr_digest_update(tokdata, sess, digest_ctx, in_data,
in_data_len);
if (rc != CKR_OK)
TRACE_DEVEL("Digest Mgr Update failed.\n");
return rc;
}
CK_RV rsa_hash_pss_sign_final(STDLL_TokData_t *tokdata, SESSION *sess,
CK_BBOOL length_only, SIGN_VERIFY_CONTEXT *ctx,
CK_BYTE *signature, CK_ULONG *sig_len)
{
CK_ULONG hlen;
CK_BYTE hash[MAX_SHA_HASH_SIZE];
DIGEST_CONTEXT *digest_ctx;
SIGN_VERIFY_CONTEXT sign_ctx;
CK_MECHANISM sign_mech;
CK_RV rc;
if (!sess || !ctx || !sig_len) {
TRACE_ERROR("%s received bad argument(s)\n", __func__);
return CKR_FUNCTION_FAILED;
}
memset(&sign_ctx, 0x0, sizeof(sign_ctx));
digest_ctx = (DIGEST_CONTEXT *) ctx->context;
rc = get_sha_size(digest_ctx->mech.mechanism, &hlen);
if (rc != CKR_OK) {
TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID));
return CKR_MECHANISM_PARAM_INVALID;
}
rc = digest_mgr_digest_final(tokdata, sess, length_only, digest_ctx,
hash, &hlen);
if (rc != CKR_OK) {
TRACE_DEVEL("Digest Mgr Final failed.\n");
return rc;
}
/* sign the hash */
sign_mech.mechanism = CKM_RSA_PKCS_PSS;
sign_mech.ulParameterLen = ctx->mech.ulParameterLen;
sign_mech.pParameter = ctx->mech.pParameter;
rc = sign_mgr_init(tokdata, sess, &sign_ctx, &sign_mech, FALSE, ctx->key);
if (rc != CKR_OK) {
TRACE_DEVEL("Sign Mgr Init failed.\n");
goto done;
}
rc = sign_mgr_sign(tokdata, sess, length_only, &sign_ctx, hash, hlen,
signature, sig_len);
if (rc != CKR_OK)
TRACE_DEVEL("Sign Mgr Sign failed.\n");
done:
sign_mgr_cleanup(&sign_ctx);
return rc;
}
CK_RV rsa_hash_pss_verify(STDLL_TokData_t *tokdata, SESSION *sess,
SIGN_VERIFY_CONTEXT *ctx,
CK_BYTE *in_data, CK_ULONG in_data_len,
CK_BYTE *signature, CK_ULONG sig_len)
{
CK_ULONG hlen;
CK_BYTE hash[MAX_SHA_HASH_SIZE];
DIGEST_CONTEXT digest_ctx;
SIGN_VERIFY_CONTEXT verify_ctx;
CK_MECHANISM digest_mech, verify_mech;
CK_RV rc;
if (!sess || !ctx || !in_data) {
TRACE_ERROR("%s received bad argument(s)\n", __func__);
return CKR_FUNCTION_FAILED;
}
memset(&digest_ctx, 0x0, sizeof(digest_ctx));
memset(&verify_ctx, 0x0, sizeof(verify_ctx));
switch (ctx->mech.mechanism) {
case CKM_SHA1_RSA_PKCS_PSS:
digest_mech.mechanism = CKM_SHA_1;
break;
case CKM_SHA224_RSA_PKCS_PSS:
digest_mech.mechanism = CKM_SHA224;
break;
case CKM_SHA256_RSA_PKCS_PSS:
digest_mech.mechanism = CKM_SHA256;
break;
case CKM_SHA384_RSA_PKCS_PSS:
digest_mech.mechanism = CKM_SHA384;
break;
case CKM_SHA512_RSA_PKCS_PSS:
digest_mech.mechanism = CKM_SHA512;
break;
default:
return CKR_MECHANISM_INVALID;
}
digest_mech.ulParameterLen = 0;
digest_mech.pParameter = NULL;
rc = get_sha_size(digest_mech.mechanism, &hlen);
if (rc != CKR_OK) {
TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID));
return CKR_MECHANISM_PARAM_INVALID;
}
rc = digest_mgr_init(tokdata, sess, &digest_ctx, &digest_mech);
if (rc != CKR_OK) {
TRACE_DEVEL("Digest Mgr Init failed.\n");
return rc;
}
rc = digest_mgr_digest(tokdata, sess, FALSE, &digest_ctx, in_data,
in_data_len, hash, &hlen);
if (rc != CKR_OK) {
TRACE_DEVEL("Digest Mgr Digest failed.\n");
return rc;
}
/* sign the hash */
verify_mech.mechanism = CKM_RSA_PKCS_PSS;
verify_mech.ulParameterLen = ctx->mech.ulParameterLen;
verify_mech.pParameter = ctx->mech.pParameter;
rc = verify_mgr_init(tokdata, sess, &verify_ctx, &verify_mech, FALSE,
ctx->key);
if (rc != CKR_OK) {
TRACE_DEVEL("Verify Mgr Init failed.\n");
goto done;
}
rc = verify_mgr_verify(tokdata, sess, &verify_ctx, hash, hlen,
signature, sig_len);
if (rc != CKR_OK)
TRACE_DEVEL("Verify Mgr Verify failed.\n");
done:
verify_mgr_cleanup(&verify_ctx);
return rc;
}
CK_RV rsa_hash_pss_verify_final(STDLL_TokData_t *tokdata, SESSION *sess,
SIGN_VERIFY_CONTEXT *ctx,
CK_BYTE *signature, CK_ULONG sig_len)
{
CK_ULONG hlen;
CK_BYTE hash[MAX_SHA_HASH_SIZE];
DIGEST_CONTEXT *digest_ctx;
SIGN_VERIFY_CONTEXT verify_ctx;
CK_MECHANISM verify_mech;
CK_RV rc;
if (!sess || !ctx || !signature) {
TRACE_ERROR("%s received bad argument(s)\n", __func__);
return CKR_FUNCTION_FAILED;
}
memset(&verify_ctx, 0x0, sizeof(verify_ctx));
digest_ctx = (DIGEST_CONTEXT *) ctx->context;
rc = get_sha_size(digest_ctx->mech.mechanism, &hlen);
if (rc != CKR_OK) {
TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID));
return CKR_MECHANISM_PARAM_INVALID;
}
rc = digest_mgr_digest_final(tokdata, sess, FALSE, digest_ctx, hash, &hlen);
if (rc != CKR_OK) {
TRACE_DEVEL("Digest Mgr Final failed.\n");
return rc;
}
/* sign the hash */
verify_mech.mechanism = CKM_RSA_PKCS_PSS;
verify_mech.ulParameterLen = ctx->mech.ulParameterLen;
verify_mech.pParameter = ctx->mech.pParameter;
rc = verify_mgr_init(tokdata, sess, &verify_ctx, &verify_mech, FALSE,
ctx->key);
if (rc != CKR_OK) {
TRACE_DEVEL("Verify Mgr Init failed.\n");
goto done;
}
rc = verify_mgr_verify(tokdata, sess, &verify_ctx, hash, hlen,
signature, sig_len);
if (rc != CKR_OK)
TRACE_DEVEL("Verify Mgr Verify failed.\n");
done:
verify_mgr_cleanup(&verify_ctx);
return rc;
}
//
//
CK_RV rsa_hash_pkcs_sign(STDLL_TokData_t *tokdata,
SESSION *sess,
CK_BBOOL length_only,
SIGN_VERIFY_CONTEXT *ctx,
CK_BYTE *in_data,
CK_ULONG in_data_len,
CK_BYTE *signature, CK_ULONG *sig_len)
{
CK_BYTE *ber_data = NULL;
CK_BYTE *octet_str = NULL;
const CK_BYTE *oid = NULL;
CK_BYTE *tmp = NULL;
CK_ULONG buf1[16]; // 64 bytes is more than enough
// must be large enough for the largest hash
CK_BYTE hash[MAX_SHA_HASH_SIZE];
DIGEST_CONTEXT digest_ctx;
SIGN_VERIFY_CONTEXT sign_ctx;
CK_MECHANISM digest_mech;
CK_MECHANISM sign_mech;
CK_ULONG ber_data_len, hash_len, octet_str_len, oid_len;
CK_RV rc;
if (!sess || !ctx || !in_data) {
TRACE_ERROR("%s received bad argument(s)\n", __func__);
return CKR_FUNCTION_FAILED;
}
memset(&digest_ctx, 0x0, sizeof(digest_ctx));
memset(&sign_ctx, 0x0, sizeof(sign_ctx));
if (ctx->mech.mechanism == CKM_MD2_RSA_PKCS) {
digest_mech.mechanism = CKM_MD2;
oid = ber_AlgMd2;
oid_len = ber_AlgMd2Len;
} else if (ctx->mech.mechanism == CKM_MD5_RSA_PKCS) {
digest_mech.mechanism = CKM_MD5;
oid = ber_AlgMd5;
oid_len = ber_AlgMd5Len;
} else if (ctx->mech.mechanism == CKM_SHA224_RSA_PKCS) {
digest_mech.mechanism = CKM_SHA224;
oid = ber_AlgSha224;
oid_len = ber_AlgSha224Len;
} else if (ctx->mech.mechanism == CKM_SHA256_RSA_PKCS) {
digest_mech.mechanism = CKM_SHA256;
oid = ber_AlgSha256;
oid_len = ber_AlgSha256Len;
} else if (ctx->mech.mechanism == CKM_SHA384_RSA_PKCS) {
digest_mech.mechanism = CKM_SHA384;
oid = ber_AlgSha384;
oid_len = ber_AlgSha384Len;
} else if (ctx->mech.mechanism == CKM_SHA512_RSA_PKCS) {
digest_mech.mechanism = CKM_SHA512;
oid = ber_AlgSha512;
oid_len = ber_AlgSha512Len;
} else {
digest_mech.mechanism = CKM_SHA_1;
oid = ber_AlgSha1;
oid_len = ber_AlgSha1Len;
}
digest_mech.ulParameterLen = 0;
digest_mech.pParameter = NULL;
rc = digest_mgr_init(tokdata, sess, &digest_ctx, &digest_mech);
if (rc != CKR_OK) {
TRACE_DEVEL("Digest Mgr Init failed.\n");
return rc;
}
hash_len = sizeof(hash);
rc = digest_mgr_digest(tokdata, sess, length_only, &digest_ctx, in_data,
in_data_len, hash, &hash_len);
if (rc != CKR_OK) {
TRACE_DEVEL("Digest Mgr Digest failed.\n");
return rc;
}
// build the BER-encodings
rc = ber_encode_OCTET_STRING(FALSE, &octet_str, &octet_str_len, hash,
hash_len);
if (rc != CKR_OK) {
TRACE_DEVEL("ber_encode_OCTET_STRING failed.\n");
goto error;
}
tmp = (CK_BYTE *) buf1;
memcpy(tmp, oid, oid_len);
memcpy(tmp + oid_len, octet_str, octet_str_len);
rc = ber_encode_SEQUENCE(FALSE, &ber_data, &ber_data_len, tmp,
(oid_len + octet_str_len));
if (rc != CKR_OK) {
TRACE_DEVEL("ber_encode_SEQUENCE failed.\n");
goto error;
}
// sign the BER-encoded data block
sign_mech.mechanism = CKM_RSA_PKCS;
sign_mech.ulParameterLen = 0;
sign_mech.pParameter = NULL;
rc = sign_mgr_init(tokdata, sess, &sign_ctx, &sign_mech, FALSE, ctx->key);
if (rc != CKR_OK) {
TRACE_DEVEL("Sign Mgr Init failed.\n");
goto error;
}
rc = sign_mgr_sign(tokdata, sess, length_only, &sign_ctx, ber_data,
ber_data_len, signature, sig_len);
if (rc != CKR_OK)
TRACE_DEVEL("Sign Mgr Sign failed.\n");
error:
if (octet_str)
free(octet_str);
if (ber_data)
free(ber_data);
sign_mgr_cleanup(&sign_ctx);
return rc;
}
//
//
CK_RV rsa_hash_pkcs_sign_update(STDLL_TokData_t *tokdata,
SESSION *sess,
SIGN_VERIFY_CONTEXT *ctx,
CK_BYTE *in_data, CK_ULONG in_data_len)
{
RSA_DIGEST_CONTEXT *context = NULL;
CK_MECHANISM digest_mech;
CK_RV rc;
if (!sess || !ctx) {
TRACE_ERROR("%s received bad argument(s)\n", __func__);
return CKR_FUNCTION_FAILED;
}
context = (RSA_DIGEST_CONTEXT *) ctx->context;
if (context->flag == FALSE) {
if (ctx->mech.mechanism == CKM_MD2_RSA_PKCS)
digest_mech.mechanism = CKM_MD2;
else if (ctx->mech.mechanism == CKM_MD5_RSA_PKCS)
digest_mech.mechanism = CKM_MD5;
else if (ctx->mech.mechanism == CKM_SHA224_RSA_PKCS)
digest_mech.mechanism = CKM_SHA224;
else if (ctx->mech.mechanism == CKM_SHA256_RSA_PKCS)
digest_mech.mechanism = CKM_SHA256;
else if (ctx->mech.mechanism == CKM_SHA384_RSA_PKCS)
digest_mech.mechanism = CKM_SHA384;
else if (ctx->mech.mechanism == CKM_SHA512_RSA_PKCS)
digest_mech.mechanism = CKM_SHA512;
else
digest_mech.mechanism = CKM_SHA_1;
digest_mech.ulParameterLen = 0;
digest_mech.pParameter = NULL;
rc = digest_mgr_init(tokdata, sess, &context->hash_context,
&digest_mech);
if (rc != CKR_OK) {
TRACE_DEVEL("Digest Mgr Init failed.\n");
return rc;
}
context->flag = TRUE;
}
rc = digest_mgr_digest_update(tokdata, sess, &context->hash_context,
in_data, in_data_len);
if (rc != CKR_OK) {
TRACE_DEVEL("Digest Mgr Digest failed.\n");
return rc;
}
return CKR_OK;
}
//
//
CK_RV rsa_hash_pkcs_verify(STDLL_TokData_t *tokdata,
SESSION *sess,
SIGN_VERIFY_CONTEXT *ctx,
CK_BYTE *in_data,
CK_ULONG in_data_len,
CK_BYTE *signature, CK_ULONG sig_len)
{
CK_BYTE *ber_data = NULL;
CK_BYTE *octet_str = NULL;
const CK_BYTE *oid = NULL;
CK_BYTE *tmp = NULL;
CK_ULONG buf1[16]; // 64 bytes is more than enough
CK_BYTE hash[MAX_SHA_HASH_SIZE];
DIGEST_CONTEXT digest_ctx;
SIGN_VERIFY_CONTEXT verify_ctx;
CK_MECHANISM digest_mech;
CK_MECHANISM verify_mech;
CK_ULONG ber_data_len, hash_len, octet_str_len, oid_len;
CK_RV rc;
if (!sess || !ctx || !in_data) {
TRACE_ERROR("%s received bad argument(s)\n", __func__);
return CKR_FUNCTION_FAILED;
}
memset(&digest_ctx, 0x0, sizeof(digest_ctx));
memset(&verify_ctx, 0x0, sizeof(verify_ctx));
if (ctx->mech.mechanism == CKM_MD2_RSA_PKCS) {
digest_mech.mechanism = CKM_MD2;
oid = ber_AlgMd2;
oid_len = ber_AlgMd2Len;
} else if (ctx->mech.mechanism == CKM_MD5_RSA_PKCS) {
digest_mech.mechanism = CKM_MD5;
oid = ber_AlgMd5;
oid_len = ber_AlgMd5Len;
} else if (ctx->mech.mechanism == CKM_SHA224_RSA_PKCS) {
digest_mech.mechanism = CKM_SHA224;
oid = ber_AlgSha224;
oid_len = ber_AlgSha224Len;
} else if (ctx->mech.mechanism == CKM_SHA256_RSA_PKCS) {
digest_mech.mechanism = CKM_SHA256;
oid = ber_AlgSha256;
oid_len = ber_AlgSha256Len;
} else if (ctx->mech.mechanism == CKM_SHA384_RSA_PKCS) {
digest_mech.mechanism = CKM_SHA384;
oid = ber_AlgSha384;
oid_len = ber_AlgSha384Len;
} else if (ctx->mech.mechanism == CKM_SHA512_RSA_PKCS) {
digest_mech.mechanism = CKM_SHA512;
oid = ber_AlgSha512;
oid_len = ber_AlgSha512Len;
} else {
digest_mech.mechanism = CKM_SHA_1;
oid = ber_AlgSha1;
oid_len = ber_AlgSha1Len;
}
digest_mech.ulParameterLen = 0;
digest_mech.pParameter = NULL;
rc = digest_mgr_init(tokdata, sess, &digest_ctx, &digest_mech);
if (rc != CKR_OK) {
TRACE_DEVEL("Digest Mgr Init failed.\n");
return rc;
}
hash_len = sizeof(hash);
rc = digest_mgr_digest(tokdata, sess, FALSE, &digest_ctx, in_data,
in_data_len, hash, &hash_len);
if (rc != CKR_OK) {
TRACE_DEVEL("Digest Mgr Digest failed.\n");
return rc;
}
// Build the BER encoding
//
rc = ber_encode_OCTET_STRING(FALSE, &octet_str, &octet_str_len, hash,
hash_len);
if (rc != CKR_OK) {
TRACE_DEVEL("ber_encode_OCTET_STRING failed.\n");
goto done;
}
tmp = (CK_BYTE *) buf1;
memcpy(tmp, oid, oid_len);
memcpy(tmp + oid_len, octet_str, octet_str_len);
rc = ber_encode_SEQUENCE(FALSE, &ber_data, &ber_data_len, tmp,
(oid_len + octet_str_len));
if (rc != CKR_OK) {
TRACE_DEVEL("ber_encode_SEQUENCE failed.\n");
goto done;
}
// Verify the Signed BER-encoded Data block
//
verify_mech.mechanism = CKM_RSA_PKCS;
verify_mech.ulParameterLen = 0;
verify_mech.pParameter = NULL;
rc = verify_mgr_init(tokdata, sess, &verify_ctx, &verify_mech, FALSE,
ctx->key);
if (rc != CKR_OK) {
TRACE_DEVEL("Verify Mgr Init failed.\n");
goto done;
}
rc = verify_mgr_verify(tokdata, sess, &verify_ctx, ber_data, ber_data_len,
signature, sig_len);
if (rc != CKR_OK)
TRACE_DEVEL("Verify Mgr Verify failed.\n");
done:
if (octet_str)
free(octet_str);
if (ber_data)
free(ber_data);
sign_mgr_cleanup(&verify_ctx);
return rc;
}
//
//
CK_RV rsa_hash_pkcs_verify_update(STDLL_TokData_t *tokdata,
SESSION *sess,
SIGN_VERIFY_CONTEXT *ctx,
CK_BYTE *in_data, CK_ULONG in_data_len)
{
RSA_DIGEST_CONTEXT *context = NULL;
CK_MECHANISM digest_mech;
CK_RV rc;
if (!sess || !ctx) {
TRACE_ERROR("%s received bad argument(s)\n", __func__);
return CKR_FUNCTION_FAILED;
}
context = (RSA_DIGEST_CONTEXT *) ctx->context;
if (context->flag == FALSE) {
if (ctx->mech.mechanism == CKM_MD2_RSA_PKCS)
digest_mech.mechanism = CKM_MD2;
else if (ctx->mech.mechanism == CKM_MD5_RSA_PKCS)
digest_mech.mechanism = CKM_MD5;
else if (ctx->mech.mechanism == CKM_SHA224_RSA_PKCS)
digest_mech.mechanism = CKM_SHA224;
else if (ctx->mech.mechanism == CKM_SHA256_RSA_PKCS)
digest_mech.mechanism = CKM_SHA256;
else if (ctx->mech.mechanism == CKM_SHA384_RSA_PKCS)
digest_mech.mechanism = CKM_SHA384;
else if (ctx->mech.mechanism == CKM_SHA512_RSA_PKCS)
digest_mech.mechanism = CKM_SHA512;
else
digest_mech.mechanism = CKM_SHA_1;
digest_mech.ulParameterLen = 0;
digest_mech.pParameter = NULL;
rc = digest_mgr_init(tokdata, sess, &context->hash_context,
&digest_mech);
if (rc != CKR_OK) {
TRACE_DEVEL("Digest Mgr Init failed.\n");
return rc;
}
context->flag = TRUE;
}
rc = digest_mgr_digest_update(tokdata, sess, &context->hash_context,
in_data, in_data_len);
if (rc != CKR_OK) {
TRACE_DEVEL("Digest Mgr Update failed.\n");
return rc;
}
return CKR_OK;
}
//
//
CK_RV rsa_hash_pkcs_sign_final(STDLL_TokData_t *tokdata,
SESSION *sess,
CK_BBOOL length_only,
SIGN_VERIFY_CONTEXT *ctx,
CK_BYTE *signature, CK_ULONG *sig_len)
{
CK_BYTE *ber_data = NULL;
CK_BYTE *octet_str = NULL;
const CK_BYTE *oid = NULL;
CK_BYTE *tmp = NULL;
CK_ULONG buf1[16]; // 64 bytes is more than enough
CK_BYTE hash[MAX_SHA_HASH_SIZE];
RSA_DIGEST_CONTEXT *context = NULL;
CK_ULONG ber_data_len, hash_len, octet_str_len, oid_len;
CK_MECHANISM sign_mech;
SIGN_VERIFY_CONTEXT sign_ctx;
CK_RV rc;
if (!sess || !ctx || !sig_len) {
TRACE_ERROR("%s received bad argument(s)\n", __func__);
return CKR_FUNCTION_FAILED;
}
if (ctx->mech.mechanism == CKM_MD2_RSA_PKCS) {
oid = ber_AlgMd2;
oid_len = ber_AlgMd2Len;
} else if (ctx->mech.mechanism == CKM_MD5_RSA_PKCS) {
oid = ber_AlgMd5;
oid_len = ber_AlgMd5Len;
} else if (ctx->mech.mechanism == CKM_SHA224_RSA_PKCS) {
oid = ber_AlgSha224;
oid_len = ber_AlgSha224Len;
} else if (ctx->mech.mechanism == CKM_SHA256_RSA_PKCS) {
oid = ber_AlgSha256;
oid_len = ber_AlgSha256Len;
} else if (ctx->mech.mechanism == CKM_SHA384_RSA_PKCS) {
oid = ber_AlgSha384;
oid_len = ber_AlgSha384Len;
} else if (ctx->mech.mechanism == CKM_SHA512_RSA_PKCS) {
oid = ber_AlgSha512;
oid_len = ber_AlgSha512Len;
} else {
oid = ber_AlgSha1;
oid_len = ber_AlgSha1Len;
}
memset(&sign_ctx, 0x0, sizeof(sign_ctx));
context = (RSA_DIGEST_CONTEXT *) ctx->context;
hash_len = sizeof(hash);
rc = digest_mgr_digest_final(tokdata, sess, length_only,
&context->hash_context, hash, &hash_len);
if (rc != CKR_OK) {
TRACE_DEVEL("Digest Mgr Final failed.\n");
return rc;
}
// Build the BER Encoded Data block
//
rc = ber_encode_OCTET_STRING(FALSE, &octet_str, &octet_str_len, hash,
hash_len);
if (rc != CKR_OK) {
TRACE_DEVEL("ber_encode_OCTET_STRING failed.\n");
return rc;
}
tmp = (CK_BYTE *) buf1;
memcpy(tmp, oid, oid_len);
memcpy(tmp + oid_len, octet_str, octet_str_len);
rc = ber_encode_SEQUENCE(FALSE, &ber_data, &ber_data_len, tmp,
(oid_len + octet_str_len));
if (rc != CKR_OK) {
TRACE_DEVEL("ber_encode_SEQUENCE failed.\n");
goto done;
}
// sign the BER-encoded data block
//
sign_mech.mechanism = CKM_RSA_PKCS;
sign_mech.ulParameterLen = 0;
sign_mech.pParameter = NULL;
rc = sign_mgr_init(tokdata, sess, &sign_ctx, &sign_mech, FALSE, ctx->key);
if (rc != CKR_OK) {
TRACE_DEVEL("Sign Mgr Init failed.\n");
goto done;
}
rc = sign_mgr_sign(tokdata, sess, length_only, &sign_ctx, ber_data,
ber_data_len, signature, sig_len);
if (rc != CKR_OK)
TRACE_DEVEL("Sign Mgr Sign failed.\n");
/** Not sure why this check is here */
if (length_only == TRUE || rc == CKR_BUFFER_TOO_SMALL)
goto done;
done:
if (octet_str)
free(octet_str);
if (ber_data)
free(ber_data);
sign_mgr_cleanup(&sign_ctx);
return rc;
}
//
//
CK_RV rsa_hash_pkcs_verify_final(STDLL_TokData_t *tokdata,
SESSION *sess,
SIGN_VERIFY_CONTEXT *ctx,
CK_BYTE *signature, CK_ULONG sig_len)
{
CK_BYTE *ber_data = NULL;
CK_BYTE *octet_str = NULL;
const CK_BYTE *oid = NULL;
CK_BYTE *tmp = NULL;
CK_ULONG buf1[16]; // 64 bytes is more than enough
CK_BYTE hash[MAX_SHA_HASH_SIZE];
RSA_DIGEST_CONTEXT *context = NULL;
CK_ULONG ber_data_len, hash_len, octet_str_len, oid_len;
CK_MECHANISM verify_mech;
SIGN_VERIFY_CONTEXT verify_ctx;
CK_RV rc;
if (!sess || !ctx || !signature) {
TRACE_ERROR("%s received bad argument(s)\n", __func__);
return CKR_FUNCTION_FAILED;
}
if (ctx->mech.mechanism == CKM_MD2_RSA_PKCS) {
oid = ber_AlgMd2;
oid_len = ber_AlgMd2Len;
} else if (ctx->mech.mechanism == CKM_MD5_RSA_PKCS) {
oid = ber_AlgMd5;
oid_len = ber_AlgMd5Len;
} else if (ctx->mech.mechanism == CKM_SHA224_RSA_PKCS) {
oid = ber_AlgSha224;
oid_len = ber_AlgSha224Len;
} else if (ctx->mech.mechanism == CKM_SHA256_RSA_PKCS) {
oid = ber_AlgSha256;
oid_len = ber_AlgSha256Len;
} else if (ctx->mech.mechanism == CKM_SHA384_RSA_PKCS) {
oid = ber_AlgSha384;
oid_len = ber_AlgSha384Len;
} else if (ctx->mech.mechanism == CKM_SHA512_RSA_PKCS) {
oid = ber_AlgSha512;
oid_len = ber_AlgSha512Len;
} else {
oid = ber_AlgSha1;
oid_len = ber_AlgSha1Len;
}
memset(&verify_ctx, 0x0, sizeof(verify_ctx));
context = (RSA_DIGEST_CONTEXT *) ctx->context;
hash_len = sizeof(hash);
rc = digest_mgr_digest_final(tokdata, sess, FALSE, &context->hash_context,
hash, &hash_len);
if (rc != CKR_OK) {
TRACE_DEVEL("Digest Mgr Final failed.\n");
return rc;
}
// Build the BER encoding
//
rc = ber_encode_OCTET_STRING(FALSE, &octet_str, &octet_str_len, hash,
hash_len);
if (rc != CKR_OK) {
TRACE_DEVEL("ber_encode_OCTET_STRING failed.\n");
goto done;
}
tmp = (CK_BYTE *) buf1;
memcpy(tmp, oid, oid_len);
memcpy(tmp + oid_len, octet_str, octet_str_len);
rc = ber_encode_SEQUENCE(FALSE, &ber_data, &ber_data_len, tmp,
(oid_len + octet_str_len));
if (rc != CKR_OK) {
TRACE_DEVEL("ber_encode_SEQUENCE failed.\n");
goto done;
}
// verify the signed BER-encoded data block
//
verify_mech.mechanism = CKM_RSA_PKCS;
verify_mech.ulParameterLen = 0;
verify_mech.pParameter = NULL;
rc = verify_mgr_init(tokdata, sess, &verify_ctx, &verify_mech, FALSE,
ctx->key);
if (rc != CKR_OK) {
TRACE_DEVEL("Verify Mgr Init failed.\n");
goto done;
}
rc = verify_mgr_verify(tokdata, sess, &verify_ctx, ber_data, ber_data_len,
signature, sig_len);
if (rc != CKR_OK)
TRACE_DEVEL("Verify Mgr Verify failed.\n");
done:
if (octet_str)
free(octet_str);
if (ber_data)
free(ber_data);
verify_mgr_cleanup(&verify_ctx);
return rc;
}
//
// mechanisms
//
//
//
CK_RV ckm_rsa_key_pair_gen(STDLL_TokData_t *tokdata,
TEMPLATE *publ_tmpl, TEMPLATE *priv_tmpl)
{
CK_RV rc;
/* check for token specific call first */
if (token_specific.t_rsa_generate_keypair == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID));
return CKR_MECHANISM_INVALID;
}
rc = token_specific.t_rsa_generate_keypair(tokdata, publ_tmpl, priv_tmpl);
if (rc != CKR_OK)
TRACE_DEVEL("Token specific rsa generate keypair failed.\n");
return rc;
}
CK_RV mgf1(STDLL_TokData_t *tokdata, CK_BYTE *seed, CK_ULONG seedlen,
CK_BYTE *mask, CK_ULONG maskLen, CK_RSA_PKCS_MGF_TYPE mgf)
{
int i;
char *seed_buffer;
unsigned char counter[4];
CK_BYTE hash[MAX_SHA_HASH_SIZE];
CK_RV rc = CKR_OK;
CK_MECHANISM_TYPE mech;
CK_ULONG hlen, T_len = 0;
if (!mask || !seed)
return CKR_FUNCTION_FAILED;
rc = get_mgf_mech(mgf, &mech);
if (rc != CKR_OK)
return CKR_FUNCTION_FAILED;
rc = get_sha_size(mech, &hlen);
if (rc != CKR_OK)
return CKR_FUNCTION_FAILED;
/* do some preparations */
seed_buffer = malloc(seedlen + 4);
if (seed_buffer == NULL)
return CKR_HOST_MEMORY;
T_len = maskLen;
for (i = 0; T_len > 0; i++) {
/* convert i to an octet string of length 4 octets. */
counter[0] = (unsigned char) ((i >> 24) & 0xff);
counter[1] = (unsigned char) ((i >> 16) & 0xff);
counter[2] = (unsigned char) ((i >> 8) & 0xff);
counter[3] = (unsigned char) (i & 0xff);
/* concatenate seed and octet string */
memset(seed_buffer, 0, seedlen + 4);
memcpy(seed_buffer, seed, seedlen);
memcpy(seed_buffer + seedlen, counter, 4);
/* compute hash of concatenated seed and octet string */
rc = compute_sha(tokdata, (CK_BYTE *)seed_buffer, seedlen + 4, hash,
mech);
if (rc != CKR_OK)
goto done;
if (T_len >= hlen) {
memcpy(mask + (i * hlen), hash, hlen);
T_len -= hlen;
} else {
/* in the case masklen is not a multiple of the
* of the hash length, only copy over remainder
*/
memcpy(mask + (i * hlen), hash, T_len);
T_len = 0;
}
}
done:
if (seed_buffer)
free(seed_buffer);
return rc;
}
// RSA mechanism - EME-OAEP encoding
//
CK_RV encode_eme_oaep(STDLL_TokData_t *tokdata, CK_BYTE *mData, CK_ULONG mLen,
CK_BYTE *emData, CK_ULONG modLength,
CK_RSA_PKCS_MGF_TYPE mgf, CK_BYTE *hash, CK_ULONG hlen)
{
int ps_len;
CK_ULONG dbMask_len, i;
CK_BYTE *maskedSeed, *maskedDB, *dbMask;
CK_BYTE seed[MAX_SHA_HASH_SIZE];
CK_RV rc = CKR_OK;
if (!mData || !emData) {
TRACE_ERROR("%s received bad argument(s)\n", __func__);
return CKR_FUNCTION_FAILED;
}
/* pkcs1v2.2 Step i:
* The encoded messages is a concatenated single octet, 0x00 with
* maskedSeed and maskedDB to create encoded message EM.
* So lets mark of the places in our output buffer.
*/
memset(emData, 0, modLength);
maskedSeed = emData + 1;
maskedDB = emData + hlen + 1;
/* pkcs1v2.2, Step b:
* Generate an octet string PS and concatenate to DB.
*/
ps_len = modLength - mLen - (2 * hlen) - 2;
memcpy(maskedDB, hash, hlen);
memset(maskedDB + hlen, 0, ps_len);
/* pkcs1v2.2, Step c:
* We have already concatenated hash and PS to maskedDB.
* Now just concatenate 0x01 and message.
*/
maskedDB[hlen + ps_len] = 0x01;
memcpy(maskedDB + (hlen + ps_len + 1), mData, mLen);
/* pkcs1v2.2, Step d:
* Generate a random seed.
*/
rc = rng_generate(tokdata, seed, hlen);
if (rc != CKR_OK)
return rc;
/* pkcs1v2.2, Step e:
* Compute dbmask using MGF1.
*/
dbMask_len = modLength - hlen - 1;
dbMask = malloc(sizeof(CK_BYTE) * dbMask_len);
if (dbMask == NULL) {
TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
return CKR_HOST_MEMORY;
}
rc = mgf1(tokdata, seed, hlen, dbMask, dbMask_len, mgf);
if (rc != CKR_OK)
goto done;
/* pkcs1v2.2, Step f:
* Compute maskedDB.
*/
for (i = 0; i < dbMask_len; i++)
maskedDB[i] ^= dbMask[i];
/* pkcs1v2.2, Step g:
* Compute seedMask using MGF1.
*/
memset(maskedSeed, 0, hlen);
rc = mgf1(tokdata, maskedDB, dbMask_len, maskedSeed, hlen, mgf);
if (rc != CKR_OK)
goto done;
/* pkcs1v2.2, Step h:
* Compute maskedSeed.
*/
for (i = 0; i < hlen; i++)
maskedSeed[i] ^= seed[i];
done:
if (dbMask)
free(dbMask);
return rc;
}
CK_RV decode_eme_oaep(STDLL_TokData_t *tokdata, CK_BYTE *emData,
CK_ULONG emLen, CK_BYTE *out_data,
CK_ULONG *out_data_len, CK_RSA_PKCS_MGF_TYPE mgf,
CK_BYTE *hash, CK_ULONG hlen)
{
int error = 0;;
CK_RV rc = CKR_OK;
CK_ULONG dbMask_len, ps_len, i;
CK_BYTE *maskedSeed, *maskedDB, *dbMask, *seedMask;
UNUSED(emLen);
if (!emData || !out_data) {
TRACE_ERROR("%s received bad argument(s)\n", __func__);
return CKR_FUNCTION_FAILED;
}
/* allocate memory now for later use */
dbMask_len = *out_data_len - hlen - 1;
dbMask = malloc(sizeof(CK_BYTE) * dbMask_len);
seedMask = malloc(sizeof(CK_BYTE) * hlen);
if ((seedMask == NULL) || (dbMask == NULL)) {
TRACE_ERROR("%s\n", ock_err(ERR_HOST_MEMORY));
rc = CKR_HOST_MEMORY;
goto done;
}
/* pkcs1v2.2, section 7.1.2, Step 3b:
* Separate the encoded message EM and process the decrypted message.
*
* To mitigate fault and timing attacks, just flag errors and
* keep going.
*/
maskedSeed = emData + 1;
maskedDB = emData + hlen + 1;
/* pkcs1v2.2, section 7.1.2, Step 3c:
* Compute seedMask using MGF1.
*/
if (mgf1(tokdata, maskedDB, dbMask_len, seedMask, hlen, mgf))
error++;
/* pkcs1v2.2, section 7.1.2, Step 3d:
* Compute seed using MGF1.
*/
for (i = 0; i < hlen; i++)
seedMask[i] ^= maskedSeed[i];
/* pkcs1v2.2, section 7.1.2, Step 3e:
* Compute dbMask using MGF1.
*/
if (mgf1(tokdata, seedMask, hlen, dbMask, dbMask_len, mgf))
error++;
/* pkcs1v2.2, section 7.1.2, Step 3f:
* Compute db using MGF1.
*/
for (i = 0; i < dbMask_len; i++)
dbMask[i] ^= maskedDB[i];
/* pkcs1v2.2, section 7.1.2, Step 3g:
* DB = lHash’ || PS || 0x01 || M .
*
* If there is no octet with hexadecimal value 0x01 to separate
* PS from M, if lHash does not equal lHash’, output “decryption
* error” and stop.
*/
if (memcmp(dbMask, hash, hlen))
error++;
ps_len = hlen;
while ((dbMask[ps_len] == 0x00) && (ps_len < dbMask_len))
ps_len++;
if ((ps_len >= dbMask_len) ||
(ps_len < dbMask_len && dbMask[ps_len] != 0x01) ||
emData[0])
error++;
if (error) {
rc = CKR_FUNCTION_FAILED;
goto done;
} else {
ps_len++;
*out_data_len = dbMask_len - ps_len;
memcpy(out_data, dbMask + ps_len, dbMask_len - ps_len);
}
done:
if (seedMask)
free(seedMask);
if (dbMask)
free(dbMask);
return rc;
}
CK_RV emsa_pss_encode(STDLL_TokData_t *tokdata,
CK_RSA_PKCS_PSS_PARAMS *pssParms, CK_BYTE *in_data,
CK_ULONG in_data_len, CK_BYTE *em, CK_ULONG *modbytes)
{
CK_BYTE *salt, *DB, *H, *buf = NULL;
CK_ULONG emBits, emLen, buflen, hlen, PSlen, i;
CK_RV rc = CKR_OK;
/*
* Note: pkcs#11v2.20, Section 12.1.10:
* in_data is the hashed message, mHash.
*
* Note: em is provided by the caller. It should be big enough to
* hold k bytes of data, where k is the length in octets of the
* modulus n.
*/
/* pkcs1v2.2 8.1.1 describes emBits as length in bits of the
* modulus - 1. It also says, the octet length of EM will be
* one less than k if modBits - 1 is divisible by 8 and equal
* to k otherwise. k is the length in octets of the modulus n.
*/
emBits = (*modbytes * 8) - 1;
if ((emBits % 8) == 0)
emLen = *modbytes - 1;
else
emLen = *modbytes;
/* get hash size based on hashAlg */
if (get_sha_size(pssParms->hashAlg, &hlen))
return CKR_MECHANISM_INVALID;
/* allocate a helper buffer to be used for M' and dbmask */
buflen = emLen - hlen - 1;
if (buflen < (8 + hlen + pssParms->sLen))
buflen = 8 + hlen + pssParms->sLen;
buf = (CK_BYTE *) malloc(buflen);
if (buf == NULL)
return CKR_HOST_MEMORY;
memset(em, 0, emLen);
memset(buf, 0, buflen);
/* set some pointers for EM */
DB = em;
H = em + (emLen - hlen - 1);
/* pkcs1v2.2, Step 3: Check length */
if (emLen < hlen + pssParms->sLen + 2) {
rc = CKR_FUNCTION_FAILED;
goto done;
}
/* pkcs1v2.2, Step 4: Generate salt */
salt = buf + (8 + in_data_len);
if (pssParms->sLen > 0) {
rc = rng_generate(tokdata, salt, pssParms->sLen);
if (rc != CKR_OK)
goto done;
}
/* pkcs1v2.2, Step 5: set M' */
if (in_data_len > 0)
memcpy(buf + 8, in_data, in_data_len);
/* pkcs1v2.2, Step 6: Compute Hash(M') */
rc = compute_sha(tokdata, buf, 8 + hlen + pssParms->sLen, H,
pssParms->hashAlg);
if (rc != CKR_OK)
goto done;
/* pkcs1v2.2, Step 7 & 8: Generate DB */
PSlen = emLen - pssParms->sLen - hlen - 2;
DB[PSlen] = 0x01;
memcpy(DB + (PSlen + 1), salt, pssParms->sLen);
/* pkcs1v2.2, Step 9: Generate dbMask
* Note: reuse "buf" for dbMask.
*/
memset(buf, 0, buflen);
rc = mgf1(tokdata, H, hlen, buf, emLen - hlen - 1, pssParms->mgf);
if (rc != CKR_OK)
goto done;
/* pkcs1v2.2, Step 10: Compute maskedDB */
for (i = 0; i < (emLen - hlen - 1); i++)
em[i] ^= buf[i];
/* pkcs1v2.2, Step 11: Set leftmost bits to zero. */
em[0] &= 0xFF >> (8 * emLen - emBits);
/* pkcs1v2.2, Step 12: EM = maskedDB || H || 0xbc */
em[emLen - 1] = 0xbc;
*modbytes = emLen;
done:
if (buf)
free(buf);
return rc;
}
CK_RV emsa_pss_verify(STDLL_TokData_t *tokdata,
CK_RSA_PKCS_PSS_PARAMS *pssParms, CK_BYTE *in_data,
CK_ULONG in_data_len, CK_BYTE *sig, CK_ULONG modbytes)
{
CK_ULONG buflen, hlen, emBits, emLen, plen, i;
CK_BYTE *salt, *H, *M, *buf = NULL;
CK_BYTE hash[MAX_SHA_HASH_SIZE];
CK_RV rc = CKR_OK;
/* pkcs1v2.2 8.1.1 describes emBits as length in bits of the
* modulus - 1. It also says, the octet length of EM will be
* one less than k if modBits - 1 is divisible by 8 and equal
* to k otherwise. k is the length in octets of the modulus n.
*/
emBits = (modbytes * 8) - 1;
if ((emBits % 8) == 0)
emLen = modbytes - 1;
else
emLen = modbytes;
/* get hash size based on hashAlg */
if (get_sha_size(pssParms->hashAlg, &hlen))
return CKR_MECHANISM_INVALID;
/* set up a big enough helper buffer to be used for M' and DB. */
buflen = (emLen - hlen - 1) + (8 + hlen + pssParms->sLen);
buf = (CK_BYTE *) malloc(buflen);
if (buf == NULL)
return CKR_HOST_MEMORY;
memset(buf, 0, buflen);
/* pkcs1v2.2, Step 4: Check rightmost octet. */
if (sig[emLen - 1] != 0xbc) {
rc = CKR_SIGNATURE_INVALID;
goto done;
}
/* pkcs1v2.2, Step 5: Extract maskedDB and H */
H = sig + (emLen - hlen - 1);
/* pkcs1v2.2, Step 6: Check leftmost bits */
if (sig[0] & ~(0xFF >> (8 * emLen - emBits))) {
rc = CKR_SIGNATURE_INVALID;
goto done;
}
/* pkcs1v2.2, Step 7: Compute mgf. */
rc = mgf1(tokdata, H, hlen, buf, emLen - hlen - 1, pssParms->mgf);
if (rc != CKR_OK)
goto done;
/* pkcs1v2.2, Step 8: DB = maskedDB ^ dbMask. */
for (i = 0; i < emLen - hlen - 1; i++)
buf[i] ^= sig[i];
/* pkcs1v2.2, Step 9: Set leftmost bits in DB to zero. */
buf[0] &= 0xFF >> (8 * emLen - emBits);
/* pkcs1v2.2, Step 10: check DB. */
i = 0;
plen = emLen - hlen - pssParms->sLen - 2;
while ((buf[i] == 0) && (i < plen))
i++;
if ((i != plen) || (buf[i++] != 0x01)) {
rc = CKR_SIGNATURE_INVALID;
goto done;
}
/* pkcs1v2.2, Step 11: Get the salt from DB. */
salt = buf + i;
/* pkcs1v2.2, Step 12: Set M'. Note: Use end of buf. */
M = buf + (i + pssParms->sLen);
memset(M, 0, 8);
if (in_data_len > 0)
memcpy(M + 8, in_data, in_data_len); // in_data is mHash.
memcpy(M + (8 + in_data_len), salt, pssParms->sLen);
/* pkcs1v2.2, Step 13: Compute Hash(M'). */
rc = compute_sha(tokdata, M, 8 + hlen + pssParms->sLen, hash,
pssParms->hashAlg);
if (rc != CKR_OK)
goto done;
/* pkcs1v2.2, Step 14: H == H'. */
if (CRYPTO_memcmp(hash, H, hlen))
rc = CKR_SIGNATURE_INVALID;
else
rc = CKR_OK;
done:
if (buf)
free(buf);
return rc;
}
CK_RV check_pss_params(CK_MECHANISM *mech, CK_ULONG modlen)
{
CK_RSA_PKCS_PSS_PARAMS *pssParams;
CK_MECHANISM_TYPE mgf_mech;
CK_ULONG hlen;
CK_RV rc;
pssParams = (CK_RSA_PKCS_PSS_PARAMS *) mech->pParameter;
if (mech->ulParameterLen != sizeof(CK_RSA_PKCS_PSS_PARAMS)) {
TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID));
return CKR_MECHANISM_PARAM_INVALID;
}
/*
* If the signature mechanism includes hashing, make sure
* pssParams->hashAlg matches.
*
* Note: pkcs#1v2.2, Section 8.1, It is recommended that the
* hash algorithm used to hash the message be the same as the
* one used in mgf.
*/
rc = get_mgf_mech(pssParams->mgf, &mgf_mech);
if (rc != CKR_OK) {
TRACE_DEVEL("MGF mechanism is invalid.\n");
return rc;
}
switch (mech->mechanism) {
case CKM_SHA1_RSA_PKCS_PSS:
if ((pssParams->hashAlg != CKM_SHA_1) &&
(pssParams->hashAlg != mgf_mech)) {
TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID));
return CKR_MECHANISM_PARAM_INVALID;
}
break;
case CKM_SHA224_RSA_PKCS_PSS:
if ((pssParams->hashAlg != CKM_SHA224) &&
(pssParams->hashAlg != mgf_mech)) {
TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID));
return CKR_MECHANISM_PARAM_INVALID;
}
break;
case CKM_SHA256_RSA_PKCS_PSS:
if ((pssParams->hashAlg != CKM_SHA256) &&
(pssParams->hashAlg != mgf_mech)) {
TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID));
return CKR_MECHANISM_PARAM_INVALID;
}
break;
case CKM_SHA384_RSA_PKCS_PSS:
if ((pssParams->hashAlg != CKM_SHA384) &&
(pssParams->hashAlg != mgf_mech)) {
TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID));
return CKR_MECHANISM_PARAM_INVALID;
}
break;
case CKM_SHA512_RSA_PKCS_PSS:
if ((pssParams->hashAlg != CKM_SHA512) &&
(pssParams->hashAlg != mgf_mech)) {
TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID));
return CKR_MECHANISM_PARAM_INVALID;
}
break;
case CKM_RSA_PKCS_PSS:
if (pssParams->hashAlg != mgf_mech) {
TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID));
return CKR_MECHANISM_PARAM_INVALID;
}
break;
default:
TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_INVALID));
return CKR_MECHANISM_INVALID;
}
/* check the salt length, pkcs11v2.2 Section 12.1.14 */
rc = get_sha_size(pssParams->hashAlg, &hlen);
if (rc != CKR_OK) {
TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID));
return CKR_MECHANISM_PARAM_INVALID;
}
if (!(pssParams->sLen <= modlen - 2 - hlen)) {
TRACE_ERROR("%s\n", ock_err(ERR_MECHANISM_PARAM_INVALID));
return CKR_MECHANISM_PARAM_INVALID;
}
return CKR_OK;
}