KEYS: Provide software public key query function [ver #2]

Provide a query function for the software public key implementation.  This
permits information about such a key to be obtained using
query_asymmetric_key() or KEYCTL_PKEY_QUERY.

Signed-off-by: David Howells <dhowells@redhat.com>
Tested-by: Marcel Holtmann <marcel@holtmann.org>
Reviewed-by: Marcel Holtmann <marcel@holtmann.org>
Reviewed-by: Denis Kenzior <denkenz@gmail.com>
Tested-by: Denis Kenzior <denkenz@gmail.com>
Signed-off-by: James Morris <james.morris@microsoft.com>
This commit is contained in:
David Howells 2018-10-09 17:47:23 +01:00 committed by James Morris
parent 0398849077
commit 82f94f2447
1 changed files with 82 additions and 17 deletions

View File

@ -59,6 +59,81 @@ static void public_key_destroy(void *payload0, void *payload3)
public_key_signature_free(payload3);
}
/*
* Determine the crypto algorithm name.
*/
static
int software_key_determine_akcipher(const char *encoding,
const char *hash_algo,
const struct public_key *pkey,
char alg_name[CRYPTO_MAX_ALG_NAME])
{
int n;
if (strcmp(encoding, "pkcs1") == 0) {
/* The data wangled by the RSA algorithm is typically padded
* and encoded in some manner, such as EMSA-PKCS1-1_5 [RFC3447
* sec 8.2].
*/
if (!hash_algo)
n = snprintf(alg_name, CRYPTO_MAX_ALG_NAME,
"pkcs1pad(%s)",
pkey->pkey_algo);
else
n = snprintf(alg_name, CRYPTO_MAX_ALG_NAME,
"pkcs1pad(%s,%s)",
pkey->pkey_algo, hash_algo);
return n >= CRYPTO_MAX_ALG_NAME ? -EINVAL : 0;
}
if (strcmp(encoding, "raw") == 0) {
strcpy(alg_name, pkey->pkey_algo);
return 0;
}
return -ENOPKG;
}
/*
* Query information about a key.
*/
static int software_key_query(const struct kernel_pkey_params *params,
struct kernel_pkey_query *info)
{
struct crypto_akcipher *tfm;
struct public_key *pkey = params->key->payload.data[asym_crypto];
char alg_name[CRYPTO_MAX_ALG_NAME];
int ret, len;
ret = software_key_determine_akcipher(params->encoding,
params->hash_algo,
pkey, alg_name);
if (ret < 0)
return ret;
tfm = crypto_alloc_akcipher(alg_name, 0, 0);
if (IS_ERR(tfm))
return PTR_ERR(tfm);
ret = crypto_akcipher_set_pub_key(tfm, pkey->key, pkey->keylen);
if (ret < 0)
goto error_free_tfm;
len = crypto_akcipher_maxsize(tfm);
info->key_size = len * 8;
info->max_data_size = len;
info->max_sig_size = len;
info->max_enc_size = len;
info->max_dec_size = len;
info->supported_ops = KEYCTL_SUPPORTS_VERIFY;
ret = 0;
error_free_tfm:
crypto_free_akcipher(tfm);
pr_devel("<==%s() = %d\n", __func__, ret);
return ret;
}
/*
* Verify a signature using a public key.
*/
@ -69,8 +144,7 @@ int public_key_verify_signature(const struct public_key *pkey,
struct crypto_akcipher *tfm;
struct akcipher_request *req;
struct scatterlist sig_sg, digest_sg;
const char *alg_name;
char alg_name_buf[CRYPTO_MAX_ALG_NAME];
char alg_name[CRYPTO_MAX_ALG_NAME];
void *output;
unsigned int outlen;
int ret;
@ -81,21 +155,11 @@ int public_key_verify_signature(const struct public_key *pkey,
BUG_ON(!sig);
BUG_ON(!sig->s);
if (!sig->digest)
return -ENOPKG;
alg_name = sig->pkey_algo;
if (strcmp(sig->pkey_algo, "rsa") == 0) {
/* The data wangled by the RSA algorithm is typically padded
* and encoded in some manner, such as EMSA-PKCS1-1_5 [RFC3447
* sec 8.2].
*/
if (snprintf(alg_name_buf, CRYPTO_MAX_ALG_NAME,
"pkcs1pad(rsa,%s)", sig->hash_algo
) >= CRYPTO_MAX_ALG_NAME)
return -EINVAL;
alg_name = alg_name_buf;
}
ret = software_key_determine_akcipher(sig->encoding,
sig->hash_algo,
pkey, alg_name);
if (ret < 0)
return ret;
tfm = crypto_alloc_akcipher(alg_name, 0, 0);
if (IS_ERR(tfm))
@ -167,6 +231,7 @@ struct asymmetric_key_subtype public_key_subtype = {
.name_len = sizeof("public_key") - 1,
.describe = public_key_describe,
.destroy = public_key_destroy,
.query = software_key_query,
.verify_signature = public_key_verify_signature_2,
};
EXPORT_SYMBOL_GPL(public_key_subtype);