pkcs15: add 'sc_pkcs15_derive' missing for ECDH support
also, key path, that has to be selected before crypto operation, can contain an aid.
This commit is contained in:
parent
9c5dbea883
commit
230b782309
|
@ -44,6 +44,7 @@ extern "C" {
|
|||
#define SC_SEC_OPERATION_DECIPHER 0x0001
|
||||
#define SC_SEC_OPERATION_SIGN 0x0002
|
||||
#define SC_SEC_OPERATION_AUTHENTICATE 0x0003
|
||||
#define SC_SEC_OPERATION_DERIVE 0x0004
|
||||
|
||||
/* sc_security_env flags */
|
||||
#define SC_SEC_ENV_ALG_REF_PRESENT 0x0001
|
||||
|
|
|
@ -41,27 +41,37 @@ static int select_key_file(struct sc_pkcs15_card *p15card,
|
|||
|
||||
LOG_FUNC_CALLED(ctx);
|
||||
|
||||
if (prkey->path.len < 2)
|
||||
LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "invalid private key path");
|
||||
|
||||
memset(&path, 0, sizeof(sc_path_t));
|
||||
memset(&file_id, 0, sizeof(sc_path_t));
|
||||
|
||||
/* TODO: Why file_app may be NULL -- at least 3F00 has to be present?
|
||||
* Check validity of the following assumption. */
|
||||
/* For pkcs15-emulated cards, the file_app may be NULL,
|
||||
in that case we allways assume an absolute path */
|
||||
if (prkey->path.len == 2 && p15card->file_app != NULL) {
|
||||
if (!prkey->path.len && prkey->path.aid.len) {
|
||||
/* Private key is a SDO allocated in application DF */
|
||||
path = prkey->path;
|
||||
}
|
||||
else if (prkey->path.len == 2 && p15card->file_app != NULL) {
|
||||
/* Path is relative to app. DF */
|
||||
path = p15card->file_app->path;
|
||||
file_id = prkey->path;
|
||||
sc_append_path(&path, &file_id);
|
||||
} else {
|
||||
senv->file_ref = file_id;
|
||||
senv->flags |= SC_SEC_ENV_FILE_REF_PRESENT;
|
||||
}
|
||||
else if (prkey->path.len > 2) {
|
||||
path = prkey->path;
|
||||
memcpy(file_id.value, prkey->path.value + prkey->path.len - 2, 2);
|
||||
file_id.len = 2;
|
||||
file_id.type = SC_PATH_TYPE_FILE_ID;
|
||||
}
|
||||
senv->file_ref = file_id;
|
||||
senv->flags |= SC_SEC_ENV_FILE_REF_PRESENT;
|
||||
}
|
||||
else {
|
||||
LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "invalid private key path");
|
||||
}
|
||||
|
||||
r = sc_select_file(p15card->card, &path, NULL);
|
||||
LOG_TEST_RET(ctx, r, "sc_select_file() failed");
|
||||
|
||||
|
@ -135,8 +145,7 @@ int sc_pkcs15_decipher(struct sc_pkcs15_card *p15card,
|
|||
r = sc_lock(p15card->card);
|
||||
LOG_TEST_RET(ctx, r, "sc_lock() failed");
|
||||
|
||||
if (prkey->path.len != 0)
|
||||
{
|
||||
if (prkey->path.len != 0 || prkey->path.aid.len != 0) {
|
||||
r = select_key_file(p15card, prkey, &senv);
|
||||
if (r < 0) {
|
||||
sc_unlock(p15card->card);
|
||||
|
@ -167,6 +176,117 @@ int sc_pkcs15_decipher(struct sc_pkcs15_card *p15card,
|
|||
LOG_FUNC_RETURN(ctx, r);
|
||||
}
|
||||
|
||||
/* derive one key from another. RSA can use decipher, so this is for only ECDH
|
||||
* Since the value may be returned, and the call is expected to provide
|
||||
* the buffer, we used the PKCS#11 convention of outlen == 0 and out == NULL
|
||||
* to indicate that this is a request for the size.
|
||||
* In that case r = 0, and *poutlen = expected size
|
||||
*/
|
||||
int sc_pkcs15_derive(struct sc_pkcs15_card *p15card,
|
||||
const struct sc_pkcs15_object *obj,
|
||||
unsigned long flags,
|
||||
const u8 * in, size_t inlen, u8 *out,
|
||||
unsigned long *poutlen)
|
||||
{
|
||||
sc_context_t *ctx = p15card->card->ctx;
|
||||
int r;
|
||||
sc_algorithm_info_t *alg_info;
|
||||
sc_security_env_t senv;
|
||||
const struct sc_pkcs15_prkey_info *prkey = (const struct sc_pkcs15_prkey_info *) obj->data;
|
||||
unsigned long pad_flags = 0, sec_flags = 0;
|
||||
|
||||
LOG_FUNC_CALLED(ctx);
|
||||
|
||||
memset(&senv, 0, sizeof(senv));
|
||||
|
||||
/* Card driver should have the access to supported algorithms from 'tokenInfo'. So that
|
||||
* it can get value of card specific 'AlgorithmInfo::algRef'. */
|
||||
memcpy(&senv.supported_algos, &p15card->tokeninfo->supported_algos, sizeof(senv.supported_algos));
|
||||
|
||||
/* If the key is not native, we can't operate with it. */
|
||||
if (!prkey->native)
|
||||
LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "This key is not native, cannot operate with it");
|
||||
|
||||
if (!(prkey->usage & (SC_PKCS15_PRKEY_USAGE_DERIVE)))
|
||||
LOG_TEST_RET(ctx, SC_ERROR_NOT_ALLOWED, "This key cannot be used for derivation");
|
||||
|
||||
switch (obj->type) {
|
||||
case SC_PKCS15_TYPE_PRKEY_EC:
|
||||
alg_info = sc_card_find_ec_alg(p15card->card, prkey->field_length);
|
||||
if (alg_info == NULL) {
|
||||
sc_log(ctx, "Card does not support EC with field_size %d", prkey->field_length);
|
||||
LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
if (out == NULL || *poutlen < (prkey->field_length +7) / 8) {
|
||||
*poutlen = (prkey->field_length +7) / 8;
|
||||
r = 0; /* say no data to return */
|
||||
goto out;
|
||||
}
|
||||
|
||||
senv.algorithm = SC_ALGORITHM_EC;
|
||||
senv.flags |= SC_SEC_ENV_ALG_PRESENT;
|
||||
|
||||
senv.flags |= SC_SEC_ENV_ALG_REF_PRESENT;
|
||||
senv.algorithm_ref = prkey->field_length;
|
||||
break;
|
||||
default:
|
||||
LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED,"Key type not supported");
|
||||
}
|
||||
|
||||
r = sc_get_encoding_flags(ctx, flags, alg_info->flags, &pad_flags, &sec_flags);
|
||||
LOG_TEST_RET(ctx, r, "cannot encode security operation flags");
|
||||
|
||||
senv.algorithm_flags = sec_flags;
|
||||
senv.operation = SC_SEC_OPERATION_DERIVE;
|
||||
/* optional keyReference attribute (the default value is -1) */
|
||||
if (prkey->key_reference >= 0) {
|
||||
senv.key_ref_len = 1;
|
||||
senv.key_ref[0] = prkey->key_reference & 0xFF;
|
||||
senv.flags |= SC_SEC_ENV_KEY_REF_PRESENT;
|
||||
}
|
||||
|
||||
r = sc_lock(p15card->card);
|
||||
LOG_TEST_RET(ctx, r, "sc_lock() failed");
|
||||
|
||||
if (prkey->path.len != 0 || prkey->path.aid.len != 0) {
|
||||
r = select_key_file(p15card, prkey, &senv);
|
||||
if (r < 0) {
|
||||
sc_unlock(p15card->card);
|
||||
LOG_TEST_RET(ctx, r,"Unable to select private key file");
|
||||
}
|
||||
}
|
||||
|
||||
r = sc_set_security_env(p15card->card, &senv, 0);
|
||||
if (r < 0) {
|
||||
sc_unlock(p15card->card);
|
||||
LOG_TEST_RET(ctx, r, "sc_set_security_env() failed");
|
||||
}
|
||||
/* TODO Do we need a sc_derive? PIV at least can use the decipher,
|
||||
* senv.operation = SC_SEC_OPERATION_DERIVE;
|
||||
*/
|
||||
r = sc_decipher(p15card->card, in, inlen, out, *poutlen);
|
||||
if (r == SC_ERROR_SECURITY_STATUS_NOT_SATISFIED) {
|
||||
if (sc_pkcs15_pincache_revalidate(p15card, obj) == SC_SUCCESS)
|
||||
r = sc_decipher(p15card->card, in, inlen, out, *poutlen);
|
||||
}
|
||||
sc_unlock(p15card->card);
|
||||
LOG_TEST_RET(ctx, r, "sc_decipher/derive() failed");
|
||||
|
||||
/* Strip any padding */
|
||||
if (pad_flags & SC_ALGORITHM_RSA_PAD_PKCS1) {
|
||||
size_t s = r;
|
||||
r = sc_pkcs1_strip_02_padding(out, s, out, &s);
|
||||
LOG_TEST_RET(ctx, r, "Invalid PKCS#1 padding");
|
||||
}
|
||||
|
||||
/* If card stores derived key on card, then no data is returned
|
||||
* and the key must be used on the card. */
|
||||
*poutlen = r;
|
||||
out:
|
||||
LOG_FUNC_RETURN(ctx, r);
|
||||
}
|
||||
|
||||
/* copied from pkcs15-cardos.c */
|
||||
#define USAGE_ANY_SIGN (SC_PKCS15_PRKEY_USAGE_SIGN|\
|
||||
SC_PKCS15_PRKEY_USAGE_NONREPUDIATION)
|
||||
|
@ -323,7 +443,6 @@ int sc_pkcs15_compute_signature(struct sc_pkcs15_card *p15card,
|
|||
sc_log(ctx, "DEE flags:0x%8.8x alg_info->flags:0x%8.8x pad:0x%8.8x sec:0x%8.8x",
|
||||
flags, alg_info->flags, pad_flags, sec_flags);
|
||||
|
||||
|
||||
/* add the padding bytes (if necessary) */
|
||||
if (pad_flags != 0) {
|
||||
size_t tmplen = sizeof(buf);
|
||||
|
@ -332,7 +451,8 @@ int sc_pkcs15_compute_signature(struct sc_pkcs15_card *p15card,
|
|||
SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, r, "Unable to add padding");
|
||||
|
||||
inlen = tmplen;
|
||||
} else if ( senv.algorithm == SC_ALGORITHM_RSA &&
|
||||
}
|
||||
else if ( senv.algorithm == SC_ALGORITHM_RSA &&
|
||||
(flags & SC_ALGORITHM_RSA_PADS) == SC_ALGORITHM_RSA_PAD_NONE) {
|
||||
/* Add zero-padding if input is shorter than the modulus */
|
||||
if (inlen < modlen) {
|
||||
|
@ -356,7 +476,8 @@ int sc_pkcs15_compute_signature(struct sc_pkcs15_card *p15card,
|
|||
r = sc_lock(p15card->card);
|
||||
LOG_TEST_RET(ctx, r, "sc_lock() failed");
|
||||
|
||||
if (prkey->path.len != 0) {
|
||||
sc_log(ctx, "Private key path '%s'", sc_print_path(&prkey->path));
|
||||
if (prkey->path.len != 0 || prkey->path.aid.len != 0) {
|
||||
r = select_key_file(p15card, prkey, &senv);
|
||||
if (r < 0) {
|
||||
sc_unlock(p15card->card);
|
||||
|
|
Loading…
Reference in New Issue