Commit d80903d5 authored by David Howells's avatar David Howells

KEYS: Restrict signature verification to keys appropriate to the purpose

Restrict the verification of X.509 certificates such that a certificate can
only be verified if either:

 (1) A certificate is signed with the key it holds.

 (2) A certificate is signed with a key that has keyCertSign set in its
     keyUsage extension and has no purpose restriction set.

Restrict the verification of PKCS#7 messages such that a signature can only
be verified by a matching key if the key does not have keyCertSign set and
either of the following is true:

 (1) The key has no purpose restriction and the PKCS#7 is not a firmware
     signature.

 (2) The key has a recognised purpose restriction that matches the use to
     which the PKCS#7 signature is being put.

In the event that a restriction mismatch occurs, EKEYREJECTED will be
returned and an error similar to one of the following will be logged to
dmesg:

	PKEY: Firmware signed with non-firmware key (module sig)
	PKEY: Restricted usage key (module sig) used for wrong purpose (kexec sig)

The PKCS#7 test key type is given the usage to specify in a module
parameter.  For example:

	echo 1 >/sys/module/pkcs7_test_key/parameters/usage
	keyctl padd pkcs7_test foo @s </tmp/stuff.pkcs7

will attempt to check the signature on stuff.pkcs7 as if it contains a
firmware blob (1 being KEY_VERIFYING_FIRMWARE_SIGNATURE).
Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
parent f5e057ee
...@@ -536,7 +536,9 @@ static int bzImage64_verify_sig(const char *kernel, unsigned long kernel_len) ...@@ -536,7 +536,9 @@ static int bzImage64_verify_sig(const char *kernel, unsigned long kernel_len)
int ret; int ret;
ret = verify_pefile_signature(kernel, kernel_len, ret = verify_pefile_signature(kernel, kernel_len,
system_trusted_keyring, &trusted); system_trusted_keyring,
KEY_VERIFYING_KEXEC_SIGNATURE,
&trusted);
if (ret < 0) if (ret < 0)
return ret; return ret;
if (!trusted) if (!trusted)
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
*/ */
#include <keys/asymmetric-subtype.h> #include <keys/asymmetric-subtype.h>
#include <keys/asymmetric-parser.h> #include <keys/asymmetric-parser.h>
#include <crypto/public_key.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/slab.h> #include <linux/slab.h>
...@@ -20,6 +21,16 @@ ...@@ -20,6 +21,16 @@
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
const char *const key_being_used_for[NR__KEY_BEING_USED_FOR] = {
[KEY_VERIFYING_MODULE_SIGNATURE] = "mod sig",
[KEY_VERIFYING_FIRMWARE_SIGNATURE] = "firmware sig",
[KEY_VERIFYING_KEXEC_SIGNATURE] = "kexec sig",
[KEY_VERIFYING_KEY_SIGNATURE] = "key sig",
[KEY_VERIFYING_KEY_SELF_SIGNATURE] = "key self sig",
[KEY_VERIFYING_INTEGRITY_SIGNATURE] = "ima sig",
};
EXPORT_SYMBOL_GPL(key_being_used_for);
static LIST_HEAD(asymmetric_key_parsers); static LIST_HEAD(asymmetric_key_parsers);
static DECLARE_RWSEM(asymmetric_key_parsers_sem); static DECLARE_RWSEM(asymmetric_key_parsers_sem);
......
...@@ -14,16 +14,23 @@ ...@@ -14,16 +14,23 @@
#include <linux/err.h> #include <linux/err.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/key-type.h> #include <linux/key-type.h>
#include <keys/asymmetric-type.h>
#include <crypto/pkcs7.h> #include <crypto/pkcs7.h>
#include <keys/user-type.h> #include <keys/user-type.h>
#include <keys/system_keyring.h> #include <keys/system_keyring.h>
#include "pkcs7_parser.h" #include "pkcs7_parser.h"
static unsigned pkcs7_usage;
module_param_named(usage, pkcs7_usage, uint, S_IWUSR | S_IRUGO);
MODULE_PARM_DESC(pkcs7_usage,
"Usage to specify when verifying the PKCS#7 message");
/* /*
* Preparse a PKCS#7 wrapped and validated data blob. * Preparse a PKCS#7 wrapped and validated data blob.
*/ */
static int pkcs7_preparse(struct key_preparsed_payload *prep) static int pkcs7_preparse(struct key_preparsed_payload *prep)
{ {
enum key_being_used_for usage = pkcs7_usage;
struct pkcs7_message *pkcs7; struct pkcs7_message *pkcs7;
const void *data, *saved_prep_data; const void *data, *saved_prep_data;
size_t datalen, saved_prep_datalen; size_t datalen, saved_prep_datalen;
...@@ -32,6 +39,11 @@ static int pkcs7_preparse(struct key_preparsed_payload *prep) ...@@ -32,6 +39,11 @@ static int pkcs7_preparse(struct key_preparsed_payload *prep)
kenter(""); kenter("");
if (usage >= NR__KEY_BEING_USED_FOR) {
pr_err("Invalid usage type %d\n", usage);
return -EINVAL;
}
saved_prep_data = prep->data; saved_prep_data = prep->data;
saved_prep_datalen = prep->datalen; saved_prep_datalen = prep->datalen;
pkcs7 = pkcs7_parse_message(saved_prep_data, saved_prep_datalen); pkcs7 = pkcs7_parse_message(saved_prep_data, saved_prep_datalen);
...@@ -40,11 +52,12 @@ static int pkcs7_preparse(struct key_preparsed_payload *prep) ...@@ -40,11 +52,12 @@ static int pkcs7_preparse(struct key_preparsed_payload *prep)
goto error; goto error;
} }
ret = pkcs7_verify(pkcs7); ret = pkcs7_verify(pkcs7, usage);
if (ret < 0) if (ret < 0)
goto error_free; goto error_free;
ret = pkcs7_validate_trust(pkcs7, system_trusted_keyring, &trusted); ret = pkcs7_validate_trust(pkcs7, system_trusted_keyring, usage,
&trusted);
if (ret < 0) if (ret < 0)
goto error_free; goto error_free;
if (!trusted) if (!trusted)
......
...@@ -25,7 +25,8 @@ ...@@ -25,7 +25,8 @@
*/ */
static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7, static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
struct pkcs7_signed_info *sinfo, struct pkcs7_signed_info *sinfo,
struct key *trust_keyring) struct key *trust_keyring,
enum key_being_used_for usage)
{ {
struct public_key_signature *sig = &sinfo->sig; struct public_key_signature *sig = &sinfo->sig;
struct x509_certificate *x509, *last = NULL, *p; struct x509_certificate *x509, *last = NULL, *p;
...@@ -65,6 +66,7 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7, ...@@ -65,6 +66,7 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
*/ */
pr_devel("sinfo %u: Cert %u as key %x\n", pr_devel("sinfo %u: Cert %u as key %x\n",
sinfo->index, x509->index, key_serial(key)); sinfo->index, x509->index, key_serial(key));
usage = KEY_VERIFYING_KEY_SIGNATURE;
goto matched; goto matched;
} }
if (key == ERR_PTR(-ENOMEM)) if (key == ERR_PTR(-ENOMEM))
...@@ -95,6 +97,7 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7, ...@@ -95,6 +97,7 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
x509 = last; x509 = last;
pr_devel("sinfo %u: Root cert %u signer is key %x\n", pr_devel("sinfo %u: Root cert %u signer is key %x\n",
sinfo->index, x509->index, key_serial(key)); sinfo->index, x509->index, key_serial(key));
usage = KEY_VERIFYING_KEY_SIGNATURE;
goto matched; goto matched;
} }
if (PTR_ERR(key) != -ENOKEY) if (PTR_ERR(key) != -ENOKEY)
...@@ -121,7 +124,7 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7, ...@@ -121,7 +124,7 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
return -ENOKEY; return -ENOKEY;
matched: matched:
ret = verify_signature(key, sig); ret = verify_signature(key, sig, usage);
trusted = test_bit(KEY_FLAG_TRUSTED, &key->flags); trusted = test_bit(KEY_FLAG_TRUSTED, &key->flags);
key_put(key); key_put(key);
if (ret < 0) { if (ret < 0) {
...@@ -148,7 +151,8 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7, ...@@ -148,7 +151,8 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
* pkcs7_validate_trust - Validate PKCS#7 trust chain * pkcs7_validate_trust - Validate PKCS#7 trust chain
* @pkcs7: The PKCS#7 certificate to validate * @pkcs7: The PKCS#7 certificate to validate
* @trust_keyring: Signing certificates to use as starting points * @trust_keyring: Signing certificates to use as starting points
* @_trusted: Set to true if trustworth, false otherwise * @usage: The use to which the key is being put.
* @_trusted: Set to true if trustworthy, false otherwise
* *
* Validate that the certificate chain inside the PKCS#7 message intersects * Validate that the certificate chain inside the PKCS#7 message intersects
* keys we already know and trust. * keys we already know and trust.
...@@ -171,6 +175,7 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7, ...@@ -171,6 +175,7 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
*/ */
int pkcs7_validate_trust(struct pkcs7_message *pkcs7, int pkcs7_validate_trust(struct pkcs7_message *pkcs7,
struct key *trust_keyring, struct key *trust_keyring,
enum key_being_used_for usage,
bool *_trusted) bool *_trusted)
{ {
struct pkcs7_signed_info *sinfo; struct pkcs7_signed_info *sinfo;
...@@ -182,7 +187,8 @@ int pkcs7_validate_trust(struct pkcs7_message *pkcs7, ...@@ -182,7 +187,8 @@ int pkcs7_validate_trust(struct pkcs7_message *pkcs7,
p->seen = false; p->seen = false;
for (sinfo = pkcs7->signed_infos; sinfo; sinfo = sinfo->next) { for (sinfo = pkcs7->signed_infos; sinfo; sinfo = sinfo->next) {
ret = pkcs7_validate_trust_one(pkcs7, sinfo, trust_keyring); ret = pkcs7_validate_trust_one(pkcs7, sinfo, trust_keyring,
usage);
switch (ret) { switch (ret) {
case -ENOKEY: case -ENOKEY:
continue; continue;
......
...@@ -208,7 +208,8 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7, ...@@ -208,7 +208,8 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
x509->raw_issuer_size) != 0) x509->raw_issuer_size) != 0)
return 0; return 0;
ret = x509_check_signature(x509->pub, x509); ret = x509_check_signature(x509->pub, x509,
KEY_VERIFYING_KEY_SELF_SIGNATURE);
if (ret < 0) if (ret < 0)
goto maybe_missing_crypto_in_x509; goto maybe_missing_crypto_in_x509;
x509->signer = x509; x509->signer = x509;
...@@ -262,7 +263,8 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7, ...@@ -262,7 +263,8 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
sinfo->index); sinfo->index);
return 0; return 0;
} }
ret = x509_check_signature(p->pub, x509); ret = x509_check_signature(p->pub, x509,
KEY_VERIFYING_KEY_SIGNATURE);
if (ret < 0) if (ret < 0)
return ret; return ret;
x509->signer = p; x509->signer = p;
...@@ -290,7 +292,8 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7, ...@@ -290,7 +292,8 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
* Verify one signed information block from a PKCS#7 message. * Verify one signed information block from a PKCS#7 message.
*/ */
static int pkcs7_verify_one(struct pkcs7_message *pkcs7, static int pkcs7_verify_one(struct pkcs7_message *pkcs7,
struct pkcs7_signed_info *sinfo) struct pkcs7_signed_info *sinfo,
enum key_being_used_for usage)
{ {
int ret; int ret;
...@@ -315,7 +318,8 @@ static int pkcs7_verify_one(struct pkcs7_message *pkcs7, ...@@ -315,7 +318,8 @@ static int pkcs7_verify_one(struct pkcs7_message *pkcs7,
sinfo->signer->index, sinfo->index); sinfo->signer->index, sinfo->index);
/* Verify the PKCS#7 binary against the key */ /* Verify the PKCS#7 binary against the key */
ret = public_key_verify_signature(sinfo->signer->pub, &sinfo->sig); ret = public_key_verify_signature(sinfo->signer->pub, &sinfo->sig,
usage);
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -328,6 +332,7 @@ static int pkcs7_verify_one(struct pkcs7_message *pkcs7, ...@@ -328,6 +332,7 @@ static int pkcs7_verify_one(struct pkcs7_message *pkcs7,
/** /**
* pkcs7_verify - Verify a PKCS#7 message * pkcs7_verify - Verify a PKCS#7 message
* @pkcs7: The PKCS#7 message to be verified * @pkcs7: The PKCS#7 message to be verified
* @usage: The use to which the key is being put
* *
* Verify a PKCS#7 message is internally consistent - that is, the data digest * Verify a PKCS#7 message is internally consistent - that is, the data digest
* matches the digest in the AuthAttrs and any signature in the message or one * matches the digest in the AuthAttrs and any signature in the message or one
...@@ -339,6 +344,9 @@ static int pkcs7_verify_one(struct pkcs7_message *pkcs7, ...@@ -339,6 +344,9 @@ static int pkcs7_verify_one(struct pkcs7_message *pkcs7,
* *
* Returns, in order of descending priority: * Returns, in order of descending priority:
* *
* (*) -EKEYREJECTED if a key was selected that had a usage restriction at
* odds with the specified usage, or:
*
* (*) -EKEYREJECTED if a signature failed to match for which we found an * (*) -EKEYREJECTED if a signature failed to match for which we found an
* appropriate X.509 certificate, or: * appropriate X.509 certificate, or:
* *
...@@ -350,7 +358,8 @@ static int pkcs7_verify_one(struct pkcs7_message *pkcs7, ...@@ -350,7 +358,8 @@ static int pkcs7_verify_one(struct pkcs7_message *pkcs7,
* (*) 0 if all the signature chains that don't incur -ENOPKG can be verified * (*) 0 if all the signature chains that don't incur -ENOPKG can be verified
* (note that a signature chain may be of zero length), or: * (note that a signature chain may be of zero length), or:
*/ */
int pkcs7_verify(struct pkcs7_message *pkcs7) int pkcs7_verify(struct pkcs7_message *pkcs7,
enum key_being_used_for usage)
{ {
struct pkcs7_signed_info *sinfo; struct pkcs7_signed_info *sinfo;
struct x509_certificate *x509; struct x509_certificate *x509;
...@@ -366,7 +375,7 @@ int pkcs7_verify(struct pkcs7_message *pkcs7) ...@@ -366,7 +375,7 @@ int pkcs7_verify(struct pkcs7_message *pkcs7)
} }
for (sinfo = pkcs7->signed_infos; sinfo; sinfo = sinfo->next) { for (sinfo = pkcs7->signed_infos; sinfo; sinfo = sinfo->next) {
ret = pkcs7_verify_one(pkcs7, sinfo); ret = pkcs7_verify_one(pkcs7, sinfo, usage);
if (ret < 0) { if (ret < 0) {
if (ret == -ENOPKG) { if (ret == -ENOPKG) {
sinfo->unsupported_crypto = true; sinfo->unsupported_crypto = true;
......
...@@ -39,6 +39,7 @@ EXPORT_SYMBOL_GPL(pkey_algo); ...@@ -39,6 +39,7 @@ EXPORT_SYMBOL_GPL(pkey_algo);
const char *const pkey_id_type_name[PKEY_ID_TYPE__LAST] = { const char *const pkey_id_type_name[PKEY_ID_TYPE__LAST] = {
[PKEY_ID_PGP] = "PGP", [PKEY_ID_PGP] = "PGP",
[PKEY_ID_X509] = "X509", [PKEY_ID_X509] = "X509",
[PKEY_ID_PKCS7] = "PKCS#7",
}; };
EXPORT_SYMBOL_GPL(pkey_id_type_name); EXPORT_SYMBOL_GPL(pkey_id_type_name);
...@@ -93,13 +94,57 @@ void public_key_destroy(void *payload) ...@@ -93,13 +94,57 @@ void public_key_destroy(void *payload)
} }
EXPORT_SYMBOL_GPL(public_key_destroy); EXPORT_SYMBOL_GPL(public_key_destroy);
/*
* Apply key usage policy.
*/
static int public_key_usage_policy(enum key_being_used_for usage,
enum key_usage_restriction restriction)
{
switch (usage) {
case KEY_VERIFYING_MODULE_SIGNATURE:
if (restriction != KEY_RESTRICTED_TO_MODULE_SIGNING &&
restriction != KEY_USAGE_NOT_SPECIFIED)
goto wrong_purpose;
return 0;
case KEY_VERIFYING_FIRMWARE_SIGNATURE:
if (restriction != KEY_RESTRICTED_TO_FIRMWARE_SIGNING) {
pr_warn("Firmware signed with non-firmware key (%s)\n",
key_usage_restrictions[restriction]);
return -EKEYREJECTED;
}
return 0;
case KEY_VERIFYING_KEXEC_SIGNATURE:
if (restriction != KEY_RESTRICTED_TO_KEXEC_SIGNING &&
restriction != KEY_USAGE_NOT_SPECIFIED)
goto wrong_purpose;
return 0;
case KEY_VERIFYING_KEY_SIGNATURE:
if (restriction != KEY_RESTRICTED_TO_KEY_SIGNING &&
restriction != KEY_USAGE_NOT_SPECIFIED)
goto wrong_purpose;
return 0;
case KEY_VERIFYING_KEY_SELF_SIGNATURE:
return 0;
default:
BUG();
}
wrong_purpose:
pr_warn("Restricted usage key (%s) used for wrong purpose (%s)\n",
key_usage_restrictions[restriction],
key_being_used_for[usage]);
return -EKEYREJECTED;
}
/* /*
* Verify a signature using a public key. * Verify a signature using a public key.
*/ */
int public_key_verify_signature(const struct public_key *pk, int public_key_verify_signature(const struct public_key *pk,
const struct public_key_signature *sig) const struct public_key_signature *sig,
enum key_being_used_for usage)
{ {
const struct public_key_algorithm *algo; const struct public_key_algorithm *algo;
int ret;
BUG_ON(!pk); BUG_ON(!pk);
BUG_ON(!pk->mpi[0]); BUG_ON(!pk->mpi[0]);
...@@ -126,15 +171,20 @@ int public_key_verify_signature(const struct public_key *pk, ...@@ -126,15 +171,20 @@ int public_key_verify_signature(const struct public_key *pk,
return -EINVAL; return -EINVAL;
} }
ret = public_key_usage_policy(usage, pk->usage_restriction);
if (ret < 0)
return ret;
return algo->verify_signature(pk, sig); return algo->verify_signature(pk, sig);
} }
EXPORT_SYMBOL_GPL(public_key_verify_signature); EXPORT_SYMBOL_GPL(public_key_verify_signature);
static int public_key_verify_signature_2(const struct key *key, static int public_key_verify_signature_2(const struct key *key,
const struct public_key_signature *sig) const struct public_key_signature *sig,
enum key_being_used_for usage)
{ {
const struct public_key *pk = key->payload.data; const struct public_key *pk = key->payload.data;
return public_key_verify_signature(pk, sig); return public_key_verify_signature(pk, sig, usage);
} }
/* /*
......
...@@ -33,4 +33,5 @@ extern const struct public_key_algorithm RSA_public_key_algorithm; ...@@ -33,4 +33,5 @@ extern const struct public_key_algorithm RSA_public_key_algorithm;
* public_key.c * public_key.c
*/ */
extern int public_key_verify_signature(const struct public_key *pk, extern int public_key_verify_signature(const struct public_key *pk,
const struct public_key_signature *sig); const struct public_key_signature *sig,
enum key_being_used_for usage);
...@@ -22,11 +22,13 @@ ...@@ -22,11 +22,13 @@
* verify_signature - Initiate the use of an asymmetric key to verify a signature * verify_signature - Initiate the use of an asymmetric key to verify a signature
* @key: The asymmetric key to verify against * @key: The asymmetric key to verify against
* @sig: The signature to check * @sig: The signature to check
* @usage: The use to which the key is being put.
* *
* Returns 0 if successful or else an error. * Returns 0 if successful or else an error.
*/ */
int verify_signature(const struct key *key, int verify_signature(const struct key *key,
const struct public_key_signature *sig) const struct public_key_signature *sig,
enum key_being_used_for usage)
{ {
const struct asymmetric_key_subtype *subtype; const struct asymmetric_key_subtype *subtype;
int ret; int ret;
...@@ -42,7 +44,7 @@ int verify_signature(const struct key *key, ...@@ -42,7 +44,7 @@ int verify_signature(const struct key *key,
if (!subtype->verify_signature) if (!subtype->verify_signature)
return -ENOTSUPP; return -ENOTSUPP;
ret = subtype->verify_signature(key, sig); ret = subtype->verify_signature(key, sig, usage);
pr_devel("<==%s() = %d\n", __func__, ret); pr_devel("<==%s() = %d\n", __func__, ret);
return ret; return ret;
......
...@@ -393,6 +393,7 @@ static int pefile_digest_pe(const void *pebuf, unsigned int pelen, ...@@ -393,6 +393,7 @@ static int pefile_digest_pe(const void *pebuf, unsigned int pelen,
* @pebuf: Buffer containing the PE binary image * @pebuf: Buffer containing the PE binary image
* @pelen: Length of the binary image * @pelen: Length of the binary image
* @trust_keyring: Signing certificates to use as starting points * @trust_keyring: Signing certificates to use as starting points
* @usage: The use to which the key is being put.
* @_trusted: Set to true if trustworth, false otherwise * @_trusted: Set to true if trustworth, false otherwise
* *
* Validate that the certificate chain inside the PKCS#7 message inside the PE * Validate that the certificate chain inside the PKCS#7 message inside the PE
...@@ -417,7 +418,9 @@ static int pefile_digest_pe(const void *pebuf, unsigned int pelen, ...@@ -417,7 +418,9 @@ static int pefile_digest_pe(const void *pebuf, unsigned int pelen,
* May also return -ENOMEM. * May also return -ENOMEM.
*/ */
int verify_pefile_signature(const void *pebuf, unsigned pelen, int verify_pefile_signature(const void *pebuf, unsigned pelen,
struct key *trusted_keyring, bool *_trusted) struct key *trusted_keyring,
enum key_being_used_for usage,
bool *_trusted)
{ {
struct pkcs7_message *pkcs7; struct pkcs7_message *pkcs7;
struct pefile_context ctx; struct pefile_context ctx;
...@@ -462,11 +465,11 @@ int verify_pefile_signature(const void *pebuf, unsigned pelen, ...@@ -462,11 +465,11 @@ int verify_pefile_signature(const void *pebuf, unsigned pelen,
if (ret < 0) if (ret < 0)
goto error; goto error;
ret = pkcs7_verify(pkcs7); ret = pkcs7_verify(pkcs7, usage);
if (ret < 0) if (ret < 0)
goto error; goto error;
ret = pkcs7_validate_trust(pkcs7, trusted_keyring, _trusted); ret = pkcs7_validate_trust(pkcs7, trusted_keyring, usage, _trusted);
error: error:
pkcs7_free_message(ctx.pkcs7); pkcs7_free_message(ctx.pkcs7);
......
...@@ -55,4 +55,5 @@ extern struct x509_certificate *x509_cert_parse(const void *data, size_t datalen ...@@ -55,4 +55,5 @@ extern struct x509_certificate *x509_cert_parse(const void *data, size_t datalen
*/ */
extern int x509_get_sig_params(struct x509_certificate *cert); extern int x509_get_sig_params(struct x509_certificate *cert);
extern int x509_check_signature(const struct public_key *pub, extern int x509_check_signature(const struct public_key *pub,
struct x509_certificate *cert); struct x509_certificate *cert,
enum key_being_used_for usage);
...@@ -221,7 +221,8 @@ EXPORT_SYMBOL_GPL(x509_get_sig_params); ...@@ -221,7 +221,8 @@ EXPORT_SYMBOL_GPL(x509_get_sig_params);
* Check the signature on a certificate using the provided public key * Check the signature on a certificate using the provided public key
*/ */
int x509_check_signature(const struct public_key *pub, int x509_check_signature(const struct public_key *pub,
struct x509_certificate *cert) struct x509_certificate *cert,
enum key_being_used_for usage)
{ {
int ret; int ret;
...@@ -231,7 +232,7 @@ int x509_check_signature(const struct public_key *pub, ...@@ -231,7 +232,7 @@ int x509_check_signature(const struct public_key *pub,
if (ret < 0) if (ret < 0)
return ret; return ret;
ret = public_key_verify_signature(pub, &cert->sig); ret = public_key_verify_signature(pub, &cert->sig, usage);
if (ret == -ENOPKG) if (ret == -ENOPKG)
cert->unsupported_crypto = true; cert->unsupported_crypto = true;
pr_debug("Cert Verification: %d\n", ret); pr_debug("Cert Verification: %d\n", ret);
...@@ -264,9 +265,10 @@ static int x509_validate_trust(struct x509_certificate *cert, ...@@ -264,9 +265,10 @@ static int x509_validate_trust(struct x509_certificate *cert,
cert->akid_id, cert->akid_skid, cert->akid_id, cert->akid_skid,
false); false);
if (!IS_ERR(key)) { if (!IS_ERR(key)) {
if (!use_builtin_keys if (!use_builtin_keys ||
|| test_bit(KEY_FLAG_BUILTIN, &key->flags)) test_bit(KEY_FLAG_BUILTIN, &key->flags))
ret = x509_check_signature(key->payload.data, cert); ret = x509_check_signature(key->payload.data, cert,
KEY_VERIFYING_KEY_SIGNATURE);
key_put(key); key_put(key);
} }
return ret; return ret;
...@@ -321,7 +323,8 @@ static int x509_key_preparse(struct key_preparsed_payload *prep) ...@@ -321,7 +323,8 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
if ((!cert->akid_skid && !cert->akid_id) || if ((!cert->akid_skid && !cert->akid_id) ||
asymmetric_key_id_same(cert->skid, cert->akid_skid) || asymmetric_key_id_same(cert->skid, cert->akid_skid) ||
asymmetric_key_id_same(cert->id, cert->akid_id)) { asymmetric_key_id_same(cert->id, cert->akid_id)) {
ret = x509_check_signature(cert->pub, cert); /* self-signed */ ret = x509_check_signature(cert->pub, cert,
KEY_VERIFYING_KEY_SELF_SIGNATURE);
if (ret < 0) if (ret < 0)
goto error_free_cert; goto error_free_cert;
} else if (!prep->trusted) { } else if (!prep->trusted) {
......
...@@ -9,6 +9,8 @@ ...@@ -9,6 +9,8 @@
* 2 of the Licence, or (at your option) any later version. * 2 of the Licence, or (at your option) any later version.
*/ */
#include <crypto/public_key.h>
struct key; struct key;
struct pkcs7_message; struct pkcs7_message;
...@@ -29,12 +31,14 @@ extern const char *pkcs7_get_firmware_name(const struct pkcs7_message *pkcs7); ...@@ -29,12 +31,14 @@ extern const char *pkcs7_get_firmware_name(const struct pkcs7_message *pkcs7);
*/ */
extern int pkcs7_validate_trust(struct pkcs7_message *pkcs7, extern int pkcs7_validate_trust(struct pkcs7_message *pkcs7,
struct key *trust_keyring, struct key *trust_keyring,
enum key_being_used_for usage,
bool *_trusted); bool *_trusted);
/* /*
* pkcs7_verify.c * pkcs7_verify.c
*/ */
extern int pkcs7_verify(struct pkcs7_message *pkcs7); extern int pkcs7_verify(struct pkcs7_message *pkcs7,
enum key_being_used_for usage);
extern int pkcs7_supply_detached_data(struct pkcs7_message *pkcs7, extern int pkcs7_supply_detached_data(struct pkcs7_message *pkcs7,
const void *data, size_t datalen); const void *data, size_t datalen);
...@@ -53,6 +53,19 @@ enum key_usage_restriction { ...@@ -53,6 +53,19 @@ enum key_usage_restriction {
NR__KEY_USAGE_RESTRICTIONS NR__KEY_USAGE_RESTRICTIONS
}; };
/*
* The use to which an asymmetric key is being put when verifying a signature.
*/
enum key_being_used_for {
KEY_VERIFYING_MODULE_SIGNATURE,
KEY_VERIFYING_FIRMWARE_SIGNATURE,
KEY_VERIFYING_KEXEC_SIGNATURE,
KEY_VERIFYING_KEY_SIGNATURE,
KEY_VERIFYING_KEY_SELF_SIGNATURE,
KEY_VERIFYING_INTEGRITY_SIGNATURE,
NR__KEY_BEING_USED_FOR
};
extern const char *const key_being_used_for[NR__KEY_BEING_USED_FOR];
/* /*
* Cryptographic data for the public-key subtype of the asymmetric key type. * Cryptographic data for the public-key subtype of the asymmetric key type.
...@@ -114,7 +127,8 @@ struct public_key_signature { ...@@ -114,7 +127,8 @@ struct public_key_signature {
struct key; struct key;
extern int verify_signature(const struct key *key, extern int verify_signature(const struct key *key,
const struct public_key_signature *sig); const struct public_key_signature *sig,
enum key_being_used_for usage);
struct asymmetric_key_id; struct asymmetric_key_id;
extern struct key *x509_request_asymmetric_key(struct key *keyring, extern struct key *x509_request_asymmetric_key(struct key *keyring,
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <keys/asymmetric-type.h> #include <keys/asymmetric-type.h>
struct public_key_signature; struct public_key_signature;
enum key_being_used_for;
/* /*
* Keys of this type declare a subtype that indicates the handlers and * Keys of this type declare a subtype that indicates the handlers and
...@@ -39,7 +40,8 @@ struct asymmetric_key_subtype { ...@@ -39,7 +40,8 @@ struct asymmetric_key_subtype {
/* Verify the signature on a key of this subtype (optional) */ /* Verify the signature on a key of this subtype (optional) */
int (*verify_signature)(const struct key *key, int (*verify_signature)(const struct key *key,
const struct public_key_signature *sig); const struct public_key_signature *sig,
enum key_being_used_for usage);
}; };
/** /**
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#ifdef CONFIG_SYSTEM_TRUSTED_KEYRING #ifdef CONFIG_SYSTEM_TRUSTED_KEYRING
#include <linux/key.h> #include <linux/key.h>
#include <crypto/public_key.h>
extern struct key *system_trusted_keyring; extern struct key *system_trusted_keyring;
static inline struct key *get_system_trusted_keyring(void) static inline struct key *get_system_trusted_keyring(void)
...@@ -31,6 +32,7 @@ static inline struct key *get_system_trusted_keyring(void) ...@@ -31,6 +32,7 @@ static inline struct key *get_system_trusted_keyring(void)
#ifdef CONFIG_SYSTEM_DATA_VERIFICATION #ifdef CONFIG_SYSTEM_DATA_VERIFICATION
extern int system_verify_data(const void *data, unsigned long len, extern int system_verify_data(const void *data, unsigned long len,
const void *raw_pkcs7, size_t pkcs7_len, const void *raw_pkcs7, size_t pkcs7_len,
enum key_being_used_for usage,
const char *firmware_name); const char *firmware_name);
#endif #endif
......
...@@ -12,7 +12,11 @@ ...@@ -12,7 +12,11 @@
#ifndef _LINUX_VERIFY_PEFILE_H #ifndef _LINUX_VERIFY_PEFILE_H
#define _LINUX_VERIFY_PEFILE_H #define _LINUX_VERIFY_PEFILE_H
#include <crypto/public_key.h>
extern int verify_pefile_signature(const void *pebuf, unsigned pelen, extern int verify_pefile_signature(const void *pebuf, unsigned pelen,
struct key *trusted_keyring, bool *_trusted); struct key *trusted_keyring,
enum key_being_used_for usage,
bool *_trusted);
#endif /* _LINUX_VERIFY_PEFILE_H */ #endif /* _LINUX_VERIFY_PEFILE_H */
...@@ -72,5 +72,6 @@ int mod_verify_sig(const void *mod, unsigned long *_modlen) ...@@ -72,5 +72,6 @@ int mod_verify_sig(const void *mod, unsigned long *_modlen)
return -EBADMSG; return -EBADMSG;
} }
return system_verify_data(mod, modlen, mod + modlen, sig_len, NULL); return system_verify_data(mod, modlen, mod + modlen, sig_len,
KEY_VERIFYING_MODULE_SIGNATURE, NULL);
} }
...@@ -113,10 +113,12 @@ late_initcall(load_system_certificate_list); ...@@ -113,10 +113,12 @@ late_initcall(load_system_certificate_list);
* @len: Size of @data. * @len: Size of @data.
* @raw_pkcs7: The PKCS#7 message that is the signature. * @raw_pkcs7: The PKCS#7 message that is the signature.
* @pkcs7_len: The size of @raw_pkcs7. * @pkcs7_len: The size of @raw_pkcs7.
* @usage: The use to which the key is being put.
* @firmware_name: The required firmware name or NULL. * @firmware_name: The required firmware name or NULL.
*/ */
int system_verify_data(const void *data, unsigned long len, int system_verify_data(const void *data, unsigned long len,
const void *raw_pkcs7, size_t pkcs7_len, const void *raw_pkcs7, size_t pkcs7_len,
enum key_being_used_for usage,
const char *firmware_name) const char *firmware_name)
{ {
struct pkcs7_message *pkcs7; struct pkcs7_message *pkcs7;
...@@ -156,11 +158,12 @@ int system_verify_data(const void *data, unsigned long len, ...@@ -156,11 +158,12 @@ int system_verify_data(const void *data, unsigned long len,
goto error; goto error;
} }
ret = pkcs7_verify(pkcs7); ret = pkcs7_verify(pkcs7, usage);
if (ret < 0) if (ret < 0)
goto error; goto error;
ret = pkcs7_validate_trust(pkcs7, system_trusted_keyring, &trusted); ret = pkcs7_validate_trust(pkcs7, system_trusted_keyring, usage,
&trusted);
if (ret < 0) if (ret < 0)
goto error; goto error;
......
...@@ -96,7 +96,8 @@ int asymmetric_verify(struct key *keyring, const char *sig, ...@@ -96,7 +96,8 @@ int asymmetric_verify(struct key *keyring, const char *sig,
pks.rsa.s = mpi_read_raw_data(hdr->sig, siglen); pks.rsa.s = mpi_read_raw_data(hdr->sig, siglen);
if (pks.rsa.s) if (pks.rsa.s)
ret = verify_signature(key, &pks); ret = verify_signature(key, &pks,
KEY_VERIFYING_INTEGRITY_SIGNATURE);
mpi_free(pks.rsa.s); mpi_free(pks.rsa.s);
key_put(key); key_put(key);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment