Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1304889 > unrolled thread
| Started by | David Howells <dhowells@redhat.com> |
|---|---|
| First post | 2016-01-08 19:40 +0100 |
| Last post | 2016-01-12 01:40 +0100 |
| Articles | 15 — 2 participants |
Back to article view | Back to linux.kernel
[RFC PATCH 00/15] KEYS: Restrict additions to 'trusted' keyrings David Howells <dhowells@redhat.com> - 2016-01-08 19:40 +0100
[RFC PATCH 10/15] X.509: Extract signature digest and make self-signed cert checks earlier David Howells <dhowells@redhat.com> - 2016-01-08 19:40 +0100
[RFC PATCH 03/15] KEYS: Generalise system_verify_data() to provide access to internal content David Howells <dhowells@redhat.com> - 2016-01-08 19:40 +0100
[RFC PATCH 05/15] KEYS: Add an alloc flag to convey the builtinness of a key David Howells <dhowells@redhat.com> - 2016-01-08 19:40 +0100
[RFC PATCH 12/15] X.509: Move the trust validation code out to its own file David Howells <dhowells@redhat.com> - 2016-01-08 19:40 +0100
[RFC PATCH 11/15] PKCS#7: Make the signature a pointer rather than embedding it David Howells <dhowells@redhat.com> - 2016-01-08 19:40 +0100
[RFC PATCH 01/15] X.509: Partially revert patch to add validation against IMA MOK keyring David Howells <dhowells@redhat.com> - 2016-01-08 19:40 +0100
[RFC PATCH 06/15] KEYS: Add a facility to restrict new links into a keyring David Howells <dhowells@redhat.com> - 2016-01-08 19:40 +0100
[RFC PATCH 02/15] X.509: Don't treat self-signed keys specially David Howells <dhowells@redhat.com> - 2016-01-08 19:40 +0100
[RFC PATCH 07/15] KEYS: Allow authentication data to be stored in an asymmetric key David Howells <dhowells@redhat.com> - 2016-01-08 19:40 +0100
Re: [RFC PATCH 00/15] KEYS: Restrict additions to 'trusted' keyrings Mimi Zohar <zohar@linux.vnet.ibm.com> - 2016-01-08 20:00 +0100
Re: [RFC PATCH 00/15] KEYS: Restrict additions to 'trusted' keyrings Mimi Zohar <zohar@linux.vnet.ibm.com> - 2016-01-08 20:30 +0100
Re: [RFC PATCH 00/15] KEYS: Restrict additions to 'trusted' keyrings David Howells <dhowells@redhat.com> - 2016-01-12 01:40 +0100
Re: [RFC PATCH 00/15] KEYS: Restrict additions to 'trusted' keyrings Mimi Zohar <zohar@linux.vnet.ibm.com> - 2016-01-12 03:50 +0100
Re: [RFC PATCH 00/15] KEYS: Restrict additions to 'trusted' keyrings David Howells <dhowells@redhat.com> - 2016-01-12 01:40 +0100
| From | David Howells <dhowells@redhat.com> |
|---|---|
| Date | 2016-01-08 19:40 +0100 |
| Subject | [RFC PATCH 00/15] KEYS: Restrict additions to 'trusted' keyrings |
| Message-ID | <qOK78-2eA-21@gated-at.bofh.it> |
Here's a set of patches that changes how keys are determined to be trusted
- currently, that's a case of whether a key has KEY_FLAG_TRUSTED set upon
it. A keyring can then have a flag set (KEY_FLAG_TRUSTED ONLY) that
indicates that only keys with this flag set may be added to that keyring.
Further, any time an X.509 certificate is instantiated without this flag
set, the certificate is judged against the contents of the system trusted
keyring to determine whether KEY_FLAG_TRUSTED should be set upon it.
With these patches, KEY_FLAG_TRUSTED and KEY_FLAG_TRUSTED_ONLY are removed.
The kernel may add implicitly trusted keys to a trusted-only keyring by
asserting KEY_ALLOC_BYPASS_RESTRICTION when the key is created, but
otherwise the key will only be allowed to be added to the keyring if it can
be verified. The system trusted keyring is not then special in this sense
and other trusted keyrings can be set up that are wholly independent of it.
Each keyring can be given a vetting function that allows it to reject
attempts to add keys to that keyring based on the type and payload of the
new key. This can be set separately for each keyring.
To make this work, we have to retain sufficient data from the X.509
certificate that we can then verify the signature at need.
The patches can be found here also:
http://git.kernel.org/cgit/linux/kernel/git/dhowells/linux-fs.git/log/?h=keys-trust
and are tagged with:
keys-trust-20160108
David
---
David Howells (15):
X.509: Partially revert patch to add validation against IMA MOK keyring
X.509: Don't treat self-signed keys specially
KEYS: Generalise system_verify_data() to provide access to internal content
PKCS#7: Make trust determination dependent on contents of trust keyring
KEYS: Add an alloc flag to convey the builtinness of a key
KEYS: Add a facility to restrict new links into a keyring
KEYS: Allow authentication data to be stored in an asymmetric key
KEYS: Add identifier pointers to public_key_signature struct
X.509: Retain the key verification data
X.509: Extract signature digest and make self-signed cert checks earlier
PKCS#7: Make the signature a pointer rather than embedding it
X.509: Move the trust validation code out to its own file
KEYS: Generalise x509_request_asymmetric_key()
KEYS: Move the point of trust determination to __key_link()
KEYS: Remove KEY_FLAG_TRUSTED
Documentation/security/keys.txt | 14 +
arch/x86/kernel/kexec-bzimage64.c | 18 --
certs/system_keyring.c | 72 +++++--
crypto/asymmetric_keys/Kconfig | 1
crypto/asymmetric_keys/Makefile | 2
crypto/asymmetric_keys/asymmetric_keys.h | 2
crypto/asymmetric_keys/asymmetric_type.c | 7 -
crypto/asymmetric_keys/mscode_parser.c | 21 +-
crypto/asymmetric_keys/pkcs7_key_type.c | 64 +++---
crypto/asymmetric_keys/pkcs7_parser.c | 59 +++---
crypto/asymmetric_keys/pkcs7_parser.h | 11 -
crypto/asymmetric_keys/pkcs7_trust.c | 44 ++--
crypto/asymmetric_keys/pkcs7_verify.c | 109 ++++------
crypto/asymmetric_keys/public_key.c | 24 ++
crypto/asymmetric_keys/public_key.h | 6 +
crypto/asymmetric_keys/public_key_trust.c | 206 ++++++++++++++++++++
crypto/asymmetric_keys/verify_pefile.c | 40 +---
crypto/asymmetric_keys/verify_pefile.h | 5
crypto/asymmetric_keys/x509_cert_parser.c | 51 +++--
crypto/asymmetric_keys/x509_parser.h | 12 -
crypto/asymmetric_keys/x509_public_key.c | 304 ++++++++---------------------
fs/cifs/cifsacl.c | 2
fs/nfs/nfs4idmap.c | 2
include/crypto/pkcs7.h | 6 -
include/crypto/public_key.h | 35 +--
include/keys/asymmetric-subtype.h | 2
include/keys/asymmetric-type.h | 8 -
include/keys/system_keyring.h | 20 --
include/linux/key.h | 40 +++-
include/linux/verification.h | 49 +++++
include/linux/verify_pefile.h | 22 --
kernel/module_signing.c | 7 -
net/dns_resolver/dns_key.c | 2
net/rxrpc/ar-key.c | 4
security/integrity/digsig.c | 34 +++
security/integrity/digsig_asymmetric.c | 5
security/integrity/ima/ima_mok.c | 9 -
security/keys/key.c | 43 +++-
security/keys/keyring.c | 26 ++
security/keys/persistent.c | 4
security/keys/process_keys.c | 16 +-
security/keys/request_key.c | 4
security/keys/request_key_auth.c | 2
43 files changed, 804 insertions(+), 610 deletions(-)
create mode 100644 crypto/asymmetric_keys/public_key_trust.c
create mode 100644 include/linux/verification.h
delete mode 100644 include/linux/verify_pefile.h
[toc] | [next] | [standalone]
| From | David Howells <dhowells@redhat.com> |
|---|---|
| Date | 2016-01-08 19:40 +0100 |
| Subject | [RFC PATCH 10/15] X.509: Extract signature digest and make self-signed cert checks earlier |
| Message-ID | <qOK7a-2eA-65@gated-at.bofh.it> |
| In reply to | #1304889 |
Extract the signature digest for an X.509 certificate earlier, at the end
of x509_cert_parse() rather than leaving it to the callers thereof.
Further, immediately after that, check the signature on self-signed
certificates, also rather in the callers of x509_cert_parse().
This we need to determine whether or not the X.509 cert requires crypto
that we don't support before we do the above two steps.
We note in the x509_certificate struct the following bits of information:
(1) Whether the signature is self-signed (even if we can't check the
signature due to missing crypto).
(2) Whether the key held in the certificate needs unsupported crypto to be
used. We may get a PKCS#7 message with X.509 certs that we can't make
use of - we just ignore them and give ENOPKG at the end it we couldn't
verify anything if at least one of these unusable certs are in the
chain of trust.
(3) Whether the signature held in the certificate needs unsupported crypto
to be checked. We can still use the key held in this certificate,
even if we can't check the signature on it - if it is held in the
system trusted keyring, for instance. We just can't add it to a ring
of trusted keys or follow it further up the chain of trust.
Making these checks earlier allows x509_check_signature() to be removed and
replaced with direct calls to public_key_verify_signature().
Signed-off-by: David Howells <dhowells@redhat.com>
---
crypto/asymmetric_keys/pkcs7_verify.c | 38 ++-------
crypto/asymmetric_keys/x509_cert_parser.c | 10 ++
crypto/asymmetric_keys/x509_parser.h | 7 +-
crypto/asymmetric_keys/x509_public_key.c | 118 +++++++++++++++++++++--------
4 files changed, 108 insertions(+), 65 deletions(-)
diff --git a/crypto/asymmetric_keys/pkcs7_verify.c b/crypto/asymmetric_keys/pkcs7_verify.c
index 8af45c5d4b6d..0d1173081b5c 100644
--- a/crypto/asymmetric_keys/pkcs7_verify.c
+++ b/crypto/asymmetric_keys/pkcs7_verify.c
@@ -191,9 +191,8 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
x509->subject,
x509->raw_serial_size, x509->raw_serial);
x509->seen = true;
- ret = x509_get_sig_params(x509);
- if (ret < 0)
- goto maybe_missing_crypto_in_x509;
+ if (x509->unsupported_key)
+ goto unsupported_crypto_in_x509;
pr_debug("- issuer %s\n", x509->issuer);
sig = x509->sig;
@@ -204,22 +203,14 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
pr_debug("- authkeyid.skid %*phN\n",
sig->auth_ids[1]->len, sig->auth_ids[1]->data);
- if ((!x509->sig->auth_ids[0] && !x509->sig->auth_ids[1]) ||
- strcmp(x509->subject, x509->issuer) == 0) {
+ if (x509->self_signed) {
/* If there's no authority certificate specified, then
* the certificate must be self-signed and is the root
* of the chain. Likewise if the cert is its own
* authority.
*/
- pr_debug("- no auth?\n");
- if (x509->raw_subject_size != x509->raw_issuer_size ||
- memcmp(x509->raw_subject, x509->raw_issuer,
- x509->raw_issuer_size) != 0)
- return 0;
-
- ret = x509_check_signature(x509->pub, x509);
- if (ret < 0)
- goto maybe_missing_crypto_in_x509;
+ if (x509->unsupported_sig)
+ goto unsupported_crypto_in_x509;
x509->signer = x509;
pr_debug("- self-signed\n");
return 0;
@@ -271,7 +262,7 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
sinfo->index);
return 0;
}
- ret = x509_check_signature(p->pub, x509);
+ ret = public_key_verify_signature(p->pub, p->sig);
if (ret < 0)
return ret;
x509->signer = p;
@@ -283,16 +274,14 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
might_sleep();
}
-maybe_missing_crypto_in_x509:
+unsupported_crypto_in_x509:
/* Just prune the certificate chain at this point if we lack some
* crypto module to go further. Note, however, we don't want to set
- * sinfo->missing_crypto as the signed info block may still be
+ * sinfo->unsupported_crypto as the signed info block may still be
* validatable against an X.509 cert lower in the chain that we have a
* trusted copy of.
*/
- if (ret == -ENOPKG)
- return 0;
- return ret;
+ return 0;
}
/*
@@ -379,9 +368,8 @@ int pkcs7_verify(struct pkcs7_message *pkcs7,
enum key_being_used_for usage)
{
struct pkcs7_signed_info *sinfo;
- struct x509_certificate *x509;
int enopkg = -ENOPKG;
- int ret, n;
+ int ret;
kenter("");
@@ -423,12 +411,6 @@ int pkcs7_verify(struct pkcs7_message *pkcs7,
return -EINVAL;
}
- for (n = 0, x509 = pkcs7->certs; x509; x509 = x509->next, n++) {
- ret = x509_get_sig_params(x509);
- if (ret < 0)
- return ret;
- }
-
for (sinfo = pkcs7->signed_infos; sinfo; sinfo = sinfo->next) {
ret = pkcs7_verify_one(pkcs7, sinfo);
if (ret < 0) {
diff --git a/crypto/asymmetric_keys/x509_cert_parser.c b/crypto/asymmetric_keys/x509_cert_parser.c
index c32912c1d84d..5bfaf1112a15 100644
--- a/crypto/asymmetric_keys/x509_cert_parser.c
+++ b/crypto/asymmetric_keys/x509_cert_parser.c
@@ -108,6 +108,11 @@ struct x509_certificate *x509_cert_parse(const void *data, size_t datalen)
if (ret < 0)
goto error_decode;
+ /* Grab the signature bits */
+ ret = x509_get_sig_params(cert);
+ if (ret < 0)
+ goto error_decode;
+
/* Generate cert issuer + serial number key ID */
kid = asymmetric_key_generate_id(cert->raw_serial,
cert->raw_serial_size,
@@ -119,6 +124,11 @@ struct x509_certificate *x509_cert_parse(const void *data, size_t datalen)
}
cert->id = kid;
+ /* Detect self-signed certificates */
+ ret = x509_check_for_self_signed(cert);
+ if (ret < 0)
+ goto error_decode;
+
kfree(ctx);
return cert;
diff --git a/crypto/asymmetric_keys/x509_parser.h b/crypto/asymmetric_keys/x509_parser.h
index 63ff787c74b3..05eef1c68881 100644
--- a/crypto/asymmetric_keys/x509_parser.h
+++ b/crypto/asymmetric_keys/x509_parser.h
@@ -39,7 +39,9 @@ struct x509_certificate {
unsigned index;
bool seen; /* Infinite recursion prevention */
bool verified;
- bool unsupported_crypto; /* T if can't be verified due to missing crypto */
+ bool self_signed; /* T if self-signed (check unsupported_sig too) */
+ bool unsupported_key; /* T if key uses unsupported crypto */
+ bool unsupported_sig; /* T if signature uses unsupported crypto */
};
/*
@@ -55,5 +57,4 @@ extern int x509_decode_time(time64_t *_t, size_t hdrlen,
* x509_public_key.c
*/
extern int x509_get_sig_params(struct x509_certificate *cert);
-extern int x509_check_signature(const struct public_key *pub,
- struct x509_certificate *cert);
+extern int x509_check_for_self_signed(struct x509_certificate *cert);
diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c
index e68995c1c856..8ef99fac821f 100644
--- a/crypto/asymmetric_keys/x509_public_key.c
+++ b/crypto/asymmetric_keys/x509_public_key.c
@@ -165,10 +165,20 @@ int x509_get_sig_params(struct x509_certificate *cert)
pr_devel("==>%s()\n", __func__);
- if (cert->unsupported_crypto)
- return -ENOPKG;
- if (sig->rsa.s)
+ if (cert->pub->pkey_algo >= PKEY_ALGO__LAST ||
+ !pkey_algo[cert->pub->pkey_algo])
+ cert->unsupported_key = true;
+
+ if (sig->pkey_algo >= PKEY_ALGO__LAST ||
+ !pkey_algo[sig->pkey_algo])
+ cert->unsupported_sig = true;
+
+ /* We check the hash if we can - even if we can't then verify it */
+ if (sig->pkey_hash_algo >= PKEY_HASH__LAST ||
+ !hash_algo_name[sig->pkey_hash_algo]) {
+ cert->unsupported_sig = true;
return 0;
+ }
sig->rsa.s = mpi_read_raw_data(cert->raw_sig, cert->raw_sig_size);
if (!sig->rsa.s)
@@ -181,8 +191,8 @@ int x509_get_sig_params(struct x509_certificate *cert)
tfm = crypto_alloc_shash(hash_algo_name[sig->pkey_hash_algo], 0, 0);
if (IS_ERR(tfm)) {
if (PTR_ERR(tfm) == -ENOENT) {
- cert->unsupported_crypto = true;
- return -ENOPKG;
+ cert->unsupported_sig = true;
+ return 0;
}
return PTR_ERR(tfm);
}
@@ -217,26 +227,60 @@ error:
EXPORT_SYMBOL_GPL(x509_get_sig_params);
/*
- * Check the signature on a certificate using the provided public key
+ * Check for self-signedness in an X.509 cert and if found, check the signature
+ * immediately if we can.
*/
-int x509_check_signature(const struct public_key *pub,
- struct x509_certificate *cert)
+int x509_check_for_self_signed(struct x509_certificate *cert)
{
- int ret;
+ int ret = 0;
pr_devel("==>%s()\n", __func__);
- ret = x509_get_sig_params(cert);
- if (ret < 0)
- return ret;
+ if (cert->raw_subject_size != cert->raw_issuer_size ||
+ memcmp(cert->raw_subject, cert->raw_issuer,
+ cert->raw_issuer_size) != 0)
+ goto not_self_signed;
+
+ if (cert->sig->auth_ids[0] || cert->sig->auth_ids[1]) {
+ /* If the AKID is present it may have one or two parts. If
+ * both are supplied, both must match.
+ */
+ bool a = asymmetric_key_id_same(cert->skid, cert->sig->auth_ids[1]);
+ bool b = asymmetric_key_id_same(cert->id, cert->sig->auth_ids[0]);
+
+ if (!a && !b)
+ goto not_self_signed;
+
+ ret = -EKEYREJECTED;
+ if (((a && !b) || (b && !a)) &&
+ cert->sig->auth_ids[0] && cert->sig->auth_ids[1])
+ goto out;
+ }
+
+ ret = -EKEYREJECTED;
+ if (cert->pub->pkey_algo != cert->sig->pkey_algo)
+ goto out;
- ret = public_key_verify_signature(pub, cert->sig);
- if (ret == -ENOPKG)
- cert->unsupported_crypto = true;
- pr_debug("Cert Verification: %d\n", ret);
+ ret = public_key_verify_signature(cert->pub, cert->sig);
+ if (ret < 0) {
+ if (ret == -ENOPKG) {
+ cert->unsupported_sig = true;
+ ret = 0;
+ }
+ goto out;
+ }
+
+ pr_devel("Cert Self-signature verified");
+ cert->self_signed = true;
+
+out:
+ pr_devel("<==%s() = %d\n", __func__, ret);
return ret;
+
+not_self_signed:
+ pr_devel("<==%s() = 0 [not]\n", __func__);
+ return 0;
}
-EXPORT_SYMBOL_GPL(x509_check_signature);
/*
* Check the new certificate against the ones in the trust keyring. If one of
@@ -259,20 +303,25 @@ static int x509_validate_trust(struct x509_certificate *cert,
if (!trust_keyring)
return -EOPNOTSUPP;
-
if (ca_keyid && !asymmetric_key_id_partial(sig->auth_ids[1], ca_keyid))
return -EPERM;
+ if (cert->unsupported_sig)
+ return -ENOPKG;
key = x509_request_asymmetric_key(trust_keyring,
sig->auth_ids[0], sig->auth_ids[1],
false);
- if (!IS_ERR(key)) {
- if (!use_builtin_keys
- || test_bit(KEY_FLAG_BUILTIN, &key->flags))
- ret = x509_check_signature(key->payload.data[asym_crypto],
- cert);
- key_put(key);
+ if (IS_ERR(key))
+ return PTR_ERR(key);
+
+ if (!use_builtin_keys ||
+ test_bit(KEY_FLAG_BUILTIN, &key->flags)) {
+ ret = public_key_verify_signature(
+ key->payload.data[asym_crypto], cert->sig);
+ if (ret == -ENOPKG)
+ cert->unsupported_sig = true;
}
+ key_put(key);
return ret;
}
@@ -295,21 +344,13 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
pr_devel("Cert Issuer: %s\n", cert->issuer);
pr_devel("Cert Subject: %s\n", cert->subject);
- if (cert->pub->pkey_algo >= PKEY_ALGO__LAST ||
- cert->sig->pkey_algo >= PKEY_ALGO__LAST ||
- cert->sig->pkey_hash_algo >= PKEY_HASH__LAST ||
- !pkey_algo[cert->pub->pkey_algo] ||
- !pkey_algo[cert->sig->pkey_algo] ||
- !hash_algo_name[cert->sig->pkey_hash_algo]) {
+ if (cert->unsupported_key) {
ret = -ENOPKG;
goto error_free_cert;
}
pr_devel("Cert Key Algo: %s\n", pkey_algo_name[cert->pub->pkey_algo]);
pr_devel("Cert Valid period: %lld-%lld\n", cert->valid_from, cert->valid_to);
- pr_devel("Cert Signature: %s + %s\n",
- pkey_algo_name[cert->sig->pkey_algo],
- hash_algo_name[cert->sig->pkey_hash_algo]);
cert->pub->algo = pkey_algo[cert->pub->pkey_algo];
cert->pub->id_type = PKEY_ID_X509;
@@ -325,8 +366,17 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
* cert that we have (most likely a duplicate that we already trust) -
* in which case it will be marked trusted.
*/
- if (!prep->trusted) {
+ if (cert->unsupported_sig || cert->self_signed) {
+ public_key_free(NULL, cert->sig);
+ cert->sig = NULL;
+ } else {
+ pr_devel("Cert Signature: %s + %s\n",
+ pkey_algo_name[cert->sig->pkey_algo],
+ hash_algo_name[cert->sig->pkey_hash_algo]);
+
ret = x509_validate_trust(cert, get_system_trusted_keyring());
+ if (ret == -EKEYREJECTED)
+ goto error_free_cert;
if (!ret)
prep->trusted = true;
}
[toc] | [prev] | [next] | [standalone]
| From | David Howells <dhowells@redhat.com> |
|---|---|
| Date | 2016-01-08 19:40 +0100 |
| Subject | [RFC PATCH 03/15] KEYS: Generalise system_verify_data() to provide access to internal content |
| Message-ID | <qOK7a-2eA-63@gated-at.bofh.it> |
| In reply to | #1304889 |
Generalise system_verify_data() to provide access to internal content
through a callback. This allows all the PKCS#7 stuff to be hidden inside
this function and removed from the PE file parser and the PKCS#7 test key.
If external content is not required, NULL should be passed as data to the
function. If the callback is not required, that can be set to NULL.
The function is now called verify_pkcs7_signature() to contrast with
verify_pefile_signature() and the definitions of both have been moved into
linux/verification.h along with the key_being_used_for enum.
Signed-off-by: David Howells <dhowells@redhat.com>
---
arch/x86/kernel/kexec-bzimage64.c | 18 ++-------
certs/system_keyring.c | 45 +++++++++++++++++-----
crypto/asymmetric_keys/Kconfig | 1
crypto/asymmetric_keys/mscode_parser.c | 21 +++-------
crypto/asymmetric_keys/pkcs7_key_type.c | 64 +++++++++++++++----------------
crypto/asymmetric_keys/pkcs7_parser.c | 21 +++++-----
crypto/asymmetric_keys/verify_pefile.c | 40 ++++---------------
crypto/asymmetric_keys/verify_pefile.h | 5 +-
include/crypto/pkcs7.h | 3 +
include/crypto/public_key.h | 14 -------
include/keys/asymmetric-type.h | 1
include/keys/system_keyring.h | 7 ---
include/linux/verification.h | 50 ++++++++++++++++++++++++
include/linux/verify_pefile.h | 22 -----------
kernel/module_signing.c | 5 +-
15 files changed, 156 insertions(+), 161 deletions(-)
create mode 100644 include/linux/verification.h
delete mode 100644 include/linux/verify_pefile.h
diff --git a/arch/x86/kernel/kexec-bzimage64.c b/arch/x86/kernel/kexec-bzimage64.c
index 0f8a6bbaaa44..0b5da62eb203 100644
--- a/arch/x86/kernel/kexec-bzimage64.c
+++ b/arch/x86/kernel/kexec-bzimage64.c
@@ -19,8 +19,7 @@
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/efi.h>
-#include <linux/verify_pefile.h>
-#include <keys/system_keyring.h>
+#include <linux/verification.h>
#include <asm/bootparam.h>
#include <asm/setup.h>
@@ -529,18 +528,9 @@ static int bzImage64_cleanup(void *loader_data)
#ifdef CONFIG_KEXEC_BZIMAGE_VERIFY_SIG
static int bzImage64_verify_sig(const char *kernel, unsigned long kernel_len)
{
- bool trusted;
- int ret;
-
- ret = verify_pefile_signature(kernel, kernel_len,
- system_trusted_keyring,
- VERIFYING_KEXEC_PE_SIGNATURE,
- &trusted);
- if (ret < 0)
- return ret;
- if (!trusted)
- return -EKEYREJECTED;
- return 0;
+ return verify_pefile_signature(kernel, kernel_len,
+ NULL,
+ VERIFYING_KEXEC_PE_SIGNATURE);
}
#endif
diff --git a/certs/system_keyring.c b/certs/system_keyring.c
index 2570598b784d..cf55bd3a072a 100644
--- a/certs/system_keyring.c
+++ b/certs/system_keyring.c
@@ -108,16 +108,25 @@ late_initcall(load_system_certificate_list);
#ifdef CONFIG_SYSTEM_DATA_VERIFICATION
/**
- * Verify a PKCS#7-based signature on system data.
- * @data: The data to be verified.
+ * verify_pkcs7_signature - Verify a PKCS#7-based signature on system data.
+ * @data: The data to be verified (NULL if expecting internal data).
* @len: Size of @data.
* @raw_pkcs7: The PKCS#7 message that is the signature.
* @pkcs7_len: The size of @raw_pkcs7.
+ * @trusted_keys: Trusted keys to use (NULL for system_trusted_keyring).
* @usage: The use to which the key is being put.
+ * @view_content: Callback to gain access to content.
+ * @ctx: Context for callback.
*/
-int system_verify_data(const void *data, unsigned long len,
- const void *raw_pkcs7, size_t pkcs7_len,
- enum key_being_used_for usage)
+int verify_pkcs7_signature(const void *data, size_t len,
+ const void *raw_pkcs7, size_t pkcs7_len,
+ struct key *trusted_keys,
+ int untrusted_error,
+ enum key_being_used_for usage,
+ int (*view_content)(void *ctx,
+ const void *data, size_t len,
+ size_t asn1hdrlen),
+ void *ctx)
{
struct pkcs7_message *pkcs7;
bool trusted;
@@ -128,7 +137,7 @@ int system_verify_data(const void *data, unsigned long len,
return PTR_ERR(pkcs7);
/* The data should be detached - so we need to supply it. */
- if (pkcs7_supply_detached_data(pkcs7, data, len) < 0) {
+ if (data && pkcs7_supply_detached_data(pkcs7, data, len) < 0) {
pr_err("PKCS#7 signature with non-detached data\n");
ret = -EBADMSG;
goto error;
@@ -138,13 +147,29 @@ int system_verify_data(const void *data, unsigned long len,
if (ret < 0)
goto error;
- ret = pkcs7_validate_trust(pkcs7, system_trusted_keyring, &trusted);
+ if (!trusted_keys)
+ trusted_keys = system_trusted_keyring;
+ ret = pkcs7_validate_trust(pkcs7, trusted_keys, &trusted);
if (ret < 0)
goto error;
- if (!trusted) {
+ if (!trusted && untrusted_error) {
pr_err("PKCS#7 signature not signed with a trusted key\n");
- ret = -ENOKEY;
+ ret = untrusted_error;
+ goto error;
+ }
+
+ if (view_content) {
+ size_t asn1hdrlen;
+
+ ret = pkcs7_get_content_data(pkcs7, &data, &len, &asn1hdrlen);
+ if (ret < 0) {
+ if (ret == -ENODATA)
+ pr_devel("PKCS#7 message does not contain data\n");
+ goto error;
+ }
+
+ ret = view_content(ctx, data, len, asn1hdrlen);
}
error:
@@ -152,6 +177,6 @@ error:
pr_devel("<==%s() = %d\n", __func__, ret);
return ret;
}
-EXPORT_SYMBOL_GPL(system_verify_data);
+EXPORT_SYMBOL_GPL(verify_pkcs7_signature);
#endif /* CONFIG_SYSTEM_DATA_VERIFICATION */
diff --git a/crypto/asymmetric_keys/Kconfig b/crypto/asymmetric_keys/Kconfig
index 4870f28403f5..d071989142b5 100644
--- a/crypto/asymmetric_keys/Kconfig
+++ b/crypto/asymmetric_keys/Kconfig
@@ -61,6 +61,7 @@ config PKCS7_TEST_KEY
config SIGNED_PE_FILE_VERIFICATION
bool "Support for PE file signature verification"
depends on PKCS7_MESSAGE_PARSER=y
+ depends on SYSTEM_DATA_VERIFICATION
select ASN1
select OID_REGISTRY
help
diff --git a/crypto/asymmetric_keys/mscode_parser.c b/crypto/asymmetric_keys/mscode_parser.c
index adcef59eec0b..b2fa9eea3ef6 100644
--- a/crypto/asymmetric_keys/mscode_parser.c
+++ b/crypto/asymmetric_keys/mscode_parser.c
@@ -21,19 +21,13 @@
/*
* Parse a Microsoft Individual Code Signing blob
*/
-int mscode_parse(struct pefile_context *ctx)
+int mscode_parse(void *_ctx, const void *content_data, size_t data_len,
+ size_t asn1hdrlen)
{
- const void *content_data;
- size_t data_len;
- int ret;
-
- ret = pkcs7_get_content_data(ctx->pkcs7, &content_data, &data_len, 1);
-
- if (ret) {
- pr_debug("PKCS#7 message does not contain data\n");
- return ret;
- }
+ struct pefile_context *ctx = _ctx;
+ content_data -= asn1hdrlen;
+ data_len += asn1hdrlen;
pr_devel("Data: %zu [%*ph]\n", data_len, (unsigned)(data_len),
content_data);
@@ -129,7 +123,6 @@ int mscode_note_digest(void *context, size_t hdrlen,
{
struct pefile_context *ctx = context;
- ctx->digest = value;
- ctx->digest_len = vlen;
- return 0;
+ ctx->digest = kmemdup(value, vlen, GFP_KERNEL);
+ return ctx->digest ? 0 : -ENOMEM;
}
diff --git a/crypto/asymmetric_keys/pkcs7_key_type.c b/crypto/asymmetric_keys/pkcs7_key_type.c
index e2d0edbbc71a..240a5303ebb7 100644
--- a/crypto/asymmetric_keys/pkcs7_key_type.c
+++ b/crypto/asymmetric_keys/pkcs7_key_type.c
@@ -29,15 +29,37 @@ MODULE_PARM_DESC(pkcs7_usage,
"Usage to specify when verifying the PKCS#7 message");
/*
+ * Retrieve the PKCS#7 message content.
+ */
+static int pkcs7_view_content(void *ctx, const void *data, size_t len,
+ size_t asn1hdrlen)
+{
+ struct key_preparsed_payload *prep = ctx;
+ const void *saved_prep_data;
+ size_t saved_prep_datalen;
+ int ret;
+
+ kenter(",%zu", len);
+
+ saved_prep_data = prep->data;
+ saved_prep_datalen = prep->datalen;
+ prep->data = data;
+ prep->datalen = len;
+
+ ret = user_preparse(prep);
+
+ prep->data = saved_prep_data;
+ prep->datalen = saved_prep_datalen;
+ kleave(" = %d", ret);
+ return ret;
+}
+
+/*
* Preparse a PKCS#7 wrapped and validated data blob.
*/
static int pkcs7_preparse(struct key_preparsed_payload *prep)
{
enum key_being_used_for usage = pkcs7_usage;
- struct pkcs7_message *pkcs7;
- const void *data, *saved_prep_data;
- size_t datalen, saved_prep_datalen;
- bool trusted;
int ret;
kenter("");
@@ -47,37 +69,11 @@ static int pkcs7_preparse(struct key_preparsed_payload *prep)
return -EINVAL;
}
- saved_prep_data = prep->data;
- saved_prep_datalen = prep->datalen;
- pkcs7 = pkcs7_parse_message(saved_prep_data, saved_prep_datalen);
- if (IS_ERR(pkcs7)) {
- ret = PTR_ERR(pkcs7);
- goto error;
- }
-
- ret = pkcs7_verify(pkcs7, usage);
- if (ret < 0)
- goto error_free;
-
- ret = pkcs7_validate_trust(pkcs7, system_trusted_keyring, &trusted);
- if (ret < 0)
- goto error_free;
- if (!trusted)
- pr_warn("PKCS#7 message doesn't chain back to a trusted key\n");
-
- ret = pkcs7_get_content_data(pkcs7, &data, &datalen, false);
- if (ret < 0)
- goto error_free;
-
- prep->data = data;
- prep->datalen = datalen;
- ret = user_preparse(prep);
- prep->data = saved_prep_data;
- prep->datalen = saved_prep_datalen;
+ ret = verify_pkcs7_signature(NULL, 0,
+ prep->data, prep->datalen,
+ NULL, -ENOKEY, usage,
+ pkcs7_view_content, prep);
-error_free:
- pkcs7_free_message(pkcs7);
-error:
kleave(" = %d", ret);
return ret;
}
diff --git a/crypto/asymmetric_keys/pkcs7_parser.c b/crypto/asymmetric_keys/pkcs7_parser.c
index 758acabf2d81..7b69783cff99 100644
--- a/crypto/asymmetric_keys/pkcs7_parser.c
+++ b/crypto/asymmetric_keys/pkcs7_parser.c
@@ -165,24 +165,25 @@ EXPORT_SYMBOL_GPL(pkcs7_parse_message);
* @pkcs7: The preparsed PKCS#7 message to access
* @_data: Place to return a pointer to the data
* @_data_len: Place to return the data length
- * @want_wrapper: True if the ASN.1 object header should be included in the data
+ * @_headerlen: Size of ASN.1 header not included in _data
*
- * Get access to the data content of the PKCS#7 message, including, optionally,
- * the header of the ASN.1 object that contains it. Returns -ENODATA if the
- * data object was missing from the message.
+ * Get access to the data content of the PKCS#7 message. The size of the
+ * header of the ASN.1 object that contains it is also provided and can be used
+ * to adjust *_data and *_data_len to get the entire object.
+ *
+ * Returns -ENODATA if the data object was missing from the message.
*/
int pkcs7_get_content_data(const struct pkcs7_message *pkcs7,
const void **_data, size_t *_data_len,
- bool want_wrapper)
+ size_t *_headerlen)
{
- size_t wrapper;
-
if (!pkcs7->data)
return -ENODATA;
- wrapper = want_wrapper ? pkcs7->data_hdrlen : 0;
- *_data = pkcs7->data - wrapper;
- *_data_len = pkcs7->data_len + wrapper;
+ *_data = pkcs7->data;
+ *_data_len = pkcs7->data_len;
+ if (_headerlen)
+ *_headerlen = pkcs7->data_hdrlen;
return 0;
}
EXPORT_SYMBOL_GPL(pkcs7_get_content_data);
diff --git a/crypto/asymmetric_keys/verify_pefile.c b/crypto/asymmetric_keys/verify_pefile.c
index 897b734dabf9..443a00f9cd7a 100644
--- a/crypto/asymmetric_keys/verify_pefile.c
+++ b/crypto/asymmetric_keys/verify_pefile.c
@@ -16,7 +16,7 @@
#include <linux/err.h>
#include <linux/pe.h>
#include <linux/asn1.h>
-#include <crypto/pkcs7.h>
+#include <linux/verification.h>
#include <crypto/hash.h>
#include "verify_pefile.h"
@@ -392,9 +392,8 @@ error_no_desc:
* verify_pefile_signature - Verify the signature on a PE binary image
* @pebuf: Buffer containing the PE binary image
* @pelen: Length of the binary image
- * @trust_keyring: Signing certificates to use as starting points
+ * @trust_keys: Signing certificate(s) to use as starting points
* @usage: The use to which the key is being put.
- * @_trusted: Set to true if trustworth, false otherwise
*
* Validate that the certificate chain inside the PKCS#7 message inside the PE
* binary image intersects keys we already know and trust.
@@ -418,14 +417,10 @@ error_no_desc:
* May also return -ENOMEM.
*/
int verify_pefile_signature(const void *pebuf, unsigned pelen,
- struct key *trusted_keyring,
- enum key_being_used_for usage,
- bool *_trusted)
+ struct key *trusted_keys,
+ enum key_being_used_for usage)
{
- struct pkcs7_message *pkcs7;
struct pefile_context ctx;
- const void *data;
- size_t datalen;
int ret;
kenter("");
@@ -439,19 +434,10 @@ int verify_pefile_signature(const void *pebuf, unsigned pelen,
if (ret < 0)
return ret;
- pkcs7 = pkcs7_parse_message(pebuf + ctx.sig_offset, ctx.sig_len);
- if (IS_ERR(pkcs7))
- return PTR_ERR(pkcs7);
- ctx.pkcs7 = pkcs7;
-
- ret = pkcs7_get_content_data(ctx.pkcs7, &data, &datalen, false);
- if (ret < 0 || datalen == 0) {
- pr_devel("PKCS#7 message does not contain data\n");
- ret = -EBADMSG;
- goto error;
- }
-
- ret = mscode_parse(&ctx);
+ ret = verify_pkcs7_signature(NULL, 0,
+ pebuf + ctx.sig_offset, ctx.sig_len,
+ trusted_keys, -EKEYREJECTED, usage,
+ mscode_parse, &ctx);
if (ret < 0)
goto error;
@@ -462,16 +448,8 @@ int verify_pefile_signature(const void *pebuf, unsigned pelen,
* contents.
*/
ret = pefile_digest_pe(pebuf, pelen, &ctx);
- if (ret < 0)
- goto error;
-
- ret = pkcs7_verify(pkcs7, usage);
- if (ret < 0)
- goto error;
-
- ret = pkcs7_validate_trust(pkcs7, trusted_keyring, _trusted);
error:
- pkcs7_free_message(ctx.pkcs7);
+ kfree(ctx.digest);
return ret;
}
diff --git a/crypto/asymmetric_keys/verify_pefile.h b/crypto/asymmetric_keys/verify_pefile.h
index 55d5f7ebc45a..d6341d5406d4 100644
--- a/crypto/asymmetric_keys/verify_pefile.h
+++ b/crypto/asymmetric_keys/verify_pefile.h
@@ -9,7 +9,6 @@
* 2 of the Licence, or (at your option) any later version.
*/
-#include <linux/verify_pefile.h>
#include <crypto/pkcs7.h>
#include <crypto/hash_info.h>
@@ -23,7 +22,6 @@ struct pefile_context {
unsigned sig_offset;
unsigned sig_len;
const struct section_header *secs;
- struct pkcs7_message *pkcs7;
/* PKCS#7 MS Individual Code Signing content */
const void *digest; /* Digest */
@@ -39,4 +37,5 @@ struct pefile_context {
/*
* mscode_parser.c
*/
-extern int mscode_parse(struct pefile_context *ctx);
+extern int mscode_parse(void *_ctx, const void *content_data, size_t data_len,
+ size_t asn1hdrlen);
diff --git a/include/crypto/pkcs7.h b/include/crypto/pkcs7.h
index 441aff9b5aa7..8323e3e57131 100644
--- a/include/crypto/pkcs7.h
+++ b/include/crypto/pkcs7.h
@@ -12,6 +12,7 @@
#ifndef _CRYPTO_PKCS7_H
#define _CRYPTO_PKCS7_H
+#include <linux/verification.h>
#include <crypto/public_key.h>
struct key;
@@ -26,7 +27,7 @@ extern void pkcs7_free_message(struct pkcs7_message *pkcs7);
extern int pkcs7_get_content_data(const struct pkcs7_message *pkcs7,
const void **_data, size_t *_datalen,
- bool want_wrapper);
+ size_t *_headerlen);
/*
* pkcs7_trust.c
diff --git a/include/crypto/public_key.h b/include/crypto/public_key.h
index cc2516df0efa..de50d026576d 100644
--- a/include/crypto/public_key.h
+++ b/include/crypto/public_key.h
@@ -39,20 +39,6 @@ enum pkey_id_type {
extern const char *const pkey_id_type_name[PKEY_ID_TYPE__LAST];
/*
- * The use to which an asymmetric key is being put.
- */
-enum key_being_used_for {
- VERIFYING_MODULE_SIGNATURE,
- VERIFYING_FIRMWARE_SIGNATURE,
- VERIFYING_KEXEC_PE_SIGNATURE,
- VERIFYING_KEY_SIGNATURE,
- VERIFYING_KEY_SELF_SIGNATURE,
- VERIFYING_UNSPECIFIED_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.
*
* Note that this may include private part of the key as well as the public
diff --git a/include/keys/asymmetric-type.h b/include/keys/asymmetric-type.h
index 59c1df9cf922..72c18c1f3308 100644
--- a/include/keys/asymmetric-type.h
+++ b/include/keys/asymmetric-type.h
@@ -15,6 +15,7 @@
#define _KEYS_ASYMMETRIC_TYPE_H
#include <linux/key-type.h>
+#include <linux/verification.h>
extern struct key_type key_type_asymmetric;
diff --git a/include/keys/system_keyring.h b/include/keys/system_keyring.h
index 39fd38cfa8c9..b2d645ac35a0 100644
--- a/include/keys/system_keyring.h
+++ b/include/keys/system_keyring.h
@@ -15,6 +15,7 @@
#ifdef CONFIG_SYSTEM_TRUSTED_KEYRING
#include <linux/key.h>
+#include <linux/verification.h>
#include <crypto/public_key.h>
extern struct key *system_trusted_keyring;
@@ -29,12 +30,6 @@ static inline struct key *get_system_trusted_keyring(void)
}
#endif
-#ifdef CONFIG_SYSTEM_DATA_VERIFICATION
-extern int system_verify_data(const void *data, unsigned long len,
- const void *raw_pkcs7, size_t pkcs7_len,
- enum key_being_used_for usage);
-#endif
-
#ifdef CONFIG_IMA_MOK_KEYRING
extern struct key *ima_mok_keyring;
extern struct key *ima_blacklist_keyring;
diff --git a/include/linux/verification.h b/include/linux/verification.h
new file mode 100644
index 000000000000..bb0fcf941cb7
--- /dev/null
+++ b/include/linux/verification.h
@@ -0,0 +1,50 @@
+/* Signature verification
+ *
+ * Copyright (C) 2014 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#ifndef _LINUX_VERIFICATION_H
+#define _LINUX_VERIFICATION_H
+
+/*
+ * The use to which an asymmetric key is being put.
+ */
+enum key_being_used_for {
+ VERIFYING_MODULE_SIGNATURE,
+ VERIFYING_FIRMWARE_SIGNATURE,
+ VERIFYING_KEXEC_PE_SIGNATURE,
+ VERIFYING_KEY_SIGNATURE,
+ VERIFYING_KEY_SELF_SIGNATURE,
+ VERIFYING_UNSPECIFIED_SIGNATURE,
+ NR__KEY_BEING_USED_FOR
+};
+extern const char *const key_being_used_for[NR__KEY_BEING_USED_FOR];
+
+#ifdef CONFIG_SYSTEM_DATA_VERIFICATION
+
+struct key;
+
+extern int verify_pkcs7_signature(const void *data, size_t len,
+ const void *raw_pkcs7, size_t pkcs7_len,
+ struct key *trusted_keys,
+ int untrusted_error,
+ enum key_being_used_for usage,
+ int (*view_content)(void *ctx,
+ const void *data, size_t len,
+ size_t asn1hdrlen),
+ void *ctx);
+
+#ifdef CONFIG_SIGNED_PE_FILE_VERIFICATION
+extern int verify_pefile_signature(const void *pebuf, unsigned pelen,
+ struct key *trusted_keys,
+ enum key_being_used_for usage);
+#endif
+
+#endif /* CONFIG_SYSTEM_DATA_VERIFICATION */
+#endif /* _LINUX_VERIFY_PEFILE_H */
diff --git a/include/linux/verify_pefile.h b/include/linux/verify_pefile.h
deleted file mode 100644
index da2049b5161c..000000000000
--- a/include/linux/verify_pefile.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/* Signed PE file verification
- *
- * Copyright (C) 2014 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells (dhowells@redhat.com)
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public Licence
- * as published by the Free Software Foundation; either version
- * 2 of the Licence, or (at your option) any later version.
- */
-
-#ifndef _LINUX_VERIFY_PEFILE_H
-#define _LINUX_VERIFY_PEFILE_H
-
-#include <crypto/public_key.h>
-
-extern int verify_pefile_signature(const void *pebuf, unsigned pelen,
- struct key *trusted_keyring,
- enum key_being_used_for usage,
- bool *_trusted);
-
-#endif /* _LINUX_VERIFY_PEFILE_H */
diff --git a/kernel/module_signing.c b/kernel/module_signing.c
index 6528a79d998d..70cf0220efeb 100644
--- a/kernel/module_signing.c
+++ b/kernel/module_signing.c
@@ -73,6 +73,7 @@ int mod_verify_sig(const void *mod, unsigned long *_modlen)
return -EBADMSG;
}
- return system_verify_data(mod, modlen, mod + modlen, sig_len,
- VERIFYING_MODULE_SIGNATURE);
+ return verify_pkcs7_signature(mod, modlen, mod + modlen, sig_len,
+ NULL, -ENOKEY, VERIFYING_MODULE_SIGNATURE,
+ NULL, NULL);
}
[toc] | [prev] | [next] | [standalone]
| From | David Howells <dhowells@redhat.com> |
|---|---|
| Date | 2016-01-08 19:40 +0100 |
| Subject | [RFC PATCH 05/15] KEYS: Add an alloc flag to convey the builtinness of a key |
| Message-ID | <qOK7b-2eA-79@gated-at.bofh.it> |
| In reply to | #1304889 |
Add KEY_ALLOC_BUILT_IN to convey that a key should have KEY_FLAG_BUILTIN
set rather than setting it after the fact.
Signed-off-by: David Howells <dhowells@redhat.com>
---
certs/system_keyring.c | 4 ++--
include/linux/key.h | 1 +
security/keys/key.c | 2 ++
3 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/certs/system_keyring.c b/certs/system_keyring.c
index e7f286413276..dc18869ff680 100644
--- a/certs/system_keyring.c
+++ b/certs/system_keyring.c
@@ -84,12 +84,12 @@ static __init int load_system_certificate_list(void)
((KEY_POS_ALL & ~KEY_POS_SETATTR) |
KEY_USR_VIEW | KEY_USR_READ),
KEY_ALLOC_NOT_IN_QUOTA |
- KEY_ALLOC_TRUSTED);
+ KEY_ALLOC_TRUSTED |
+ KEY_ALLOC_BUILT_IN);
if (IS_ERR(key)) {
pr_err("Problem loading in-kernel X.509 certificate (%ld)\n",
PTR_ERR(key));
} else {
- set_bit(KEY_FLAG_BUILTIN, &key_ref_to_ptr(key)->flags);
pr_notice("Loaded X.509 cert '%s'\n",
key_ref_to_ptr(key)->description);
key_ref_put(key);
diff --git a/include/linux/key.h b/include/linux/key.h
index 7321ab8ef949..5f5b1129dc92 100644
--- a/include/linux/key.h
+++ b/include/linux/key.h
@@ -219,6 +219,7 @@ extern struct key *key_alloc(struct key_type *type,
#define KEY_ALLOC_QUOTA_OVERRUN 0x0001 /* add to quota, permit even if overrun */
#define KEY_ALLOC_NOT_IN_QUOTA 0x0002 /* not in quota */
#define KEY_ALLOC_TRUSTED 0x0004 /* Key should be flagged as trusted */
+#define KEY_ALLOC_BUILT_IN 0x0008 /* Key is built into kernel */
extern void key_revoke(struct key *key);
extern void key_invalidate(struct key *key);
diff --git a/security/keys/key.c b/security/keys/key.c
index 09ef276c4bdc..b28755131687 100644
--- a/security/keys/key.c
+++ b/security/keys/key.c
@@ -296,6 +296,8 @@ struct key *key_alloc(struct key_type *type, const char *desc,
key->flags |= 1 << KEY_FLAG_IN_QUOTA;
if (flags & KEY_ALLOC_TRUSTED)
key->flags |= 1 << KEY_FLAG_TRUSTED;
+ if (flags & KEY_ALLOC_BUILT_IN)
+ key->flags |= 1 << KEY_FLAG_BUILTIN;
#ifdef KEY_DEBUGGING
key->magic = KEY_DEBUG_MAGIC;
[toc] | [prev] | [next] | [standalone]
| From | David Howells <dhowells@redhat.com> |
|---|---|
| Date | 2016-01-08 19:40 +0100 |
| Subject | [RFC PATCH 12/15] X.509: Move the trust validation code out to its own file |
| Message-ID | <qOK7b-2eA-77@gated-at.bofh.it> |
| In reply to | #1304889 |
Move the X.509 trust validation code out to its own file so that it can be
generalised.
Signed-off-by: David Howells <dhowells@redhat.com>
---
crypto/asymmetric_keys/Makefile | 2
crypto/asymmetric_keys/public_key_trust.c | 195 +++++++++++++++++++++++++++++
crypto/asymmetric_keys/x509_parser.h | 6 +
crypto/asymmetric_keys/x509_public_key.c | 170 -------------------------
4 files changed, 202 insertions(+), 171 deletions(-)
create mode 100644 crypto/asymmetric_keys/public_key_trust.c
diff --git a/crypto/asymmetric_keys/Makefile b/crypto/asymmetric_keys/Makefile
index cd1406f9b14a..3f291bbf7b74 100644
--- a/crypto/asymmetric_keys/Makefile
+++ b/crypto/asymmetric_keys/Makefile
@@ -6,7 +6,7 @@ obj-$(CONFIG_ASYMMETRIC_KEY_TYPE) += asymmetric_keys.o
asymmetric_keys-y := asymmetric_type.o signature.o
-obj-$(CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE) += public_key.o
+obj-$(CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE) += public_key.o public_key_trust.o
obj-$(CONFIG_PUBLIC_KEY_ALGO_RSA) += rsa.o
#
diff --git a/crypto/asymmetric_keys/public_key_trust.c b/crypto/asymmetric_keys/public_key_trust.c
new file mode 100644
index 000000000000..9febe612e659
--- /dev/null
+++ b/crypto/asymmetric_keys/public_key_trust.c
@@ -0,0 +1,195 @@
+/* Instantiate a public key crypto key from an X.509 Certificate
+ *
+ * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#define pr_fmt(fmt) "X.509: "fmt
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/mpi.h>
+#include <linux/asn1_decoder.h>
+#include <keys/asymmetric-subtype.h>
+#include <keys/asymmetric-parser.h>
+#include <keys/system_keyring.h>
+#include <crypto/hash.h>
+#include "asymmetric_keys.h"
+#include "public_key.h"
+#include "x509_parser.h"
+
+static bool use_builtin_keys;
+static struct asymmetric_key_id *ca_keyid;
+
+#ifndef MODULE
+static struct {
+ struct asymmetric_key_id id;
+ unsigned char data[10];
+} cakey;
+
+static int __init ca_keys_setup(char *str)
+{
+ if (!str) /* default system keyring */
+ return 1;
+
+ if (strncmp(str, "id:", 3) == 0) {
+ struct asymmetric_key_id *p = &cakey.id;
+ size_t hexlen = (strlen(str) - 3) / 2;
+ int ret;
+
+ if (hexlen == 0 || hexlen > sizeof(cakey.data)) {
+ pr_err("Missing or invalid ca_keys id\n");
+ return 1;
+ }
+
+ ret = __asymmetric_key_hex_to_key_id(str + 3, p, hexlen);
+ if (ret < 0)
+ pr_err("Unparsable ca_keys id hex string\n");
+ else
+ ca_keyid = p; /* owner key 'id:xxxxxx' */
+ } else if (strcmp(str, "builtin") == 0) {
+ use_builtin_keys = true;
+ }
+
+ return 1;
+}
+__setup("ca_keys=", ca_keys_setup);
+#endif
+
+/**
+ * x509_request_asymmetric_key - Request a key by X.509 certificate params.
+ * @keyring: The keys to search.
+ * @id: The issuer & serialNumber to look for or NULL.
+ * @skid: The subjectKeyIdentifier to look for or NULL.
+ * @partial: Use partial match if true, exact if false.
+ *
+ * Find a key in the given keyring by identifier. The preferred identifier is
+ * the issuer + serialNumber and the fallback identifier is the
+ * subjectKeyIdentifier. If both are given, the lookup is by the former, but
+ * the latter must also match.
+ */
+struct key *x509_request_asymmetric_key(struct key *keyring,
+ const struct asymmetric_key_id *id,
+ const struct asymmetric_key_id *skid,
+ bool partial)
+{
+ struct key *key;
+ key_ref_t ref;
+ const char *lookup;
+ char *req, *p;
+ int len;
+
+ if (id) {
+ lookup = id->data;
+ len = id->len;
+ } else {
+ lookup = skid->data;
+ len = skid->len;
+ }
+
+ /* Construct an identifier "id:<keyid>". */
+ p = req = kmalloc(2 + 1 + len * 2 + 1, GFP_KERNEL);
+ if (!req)
+ return ERR_PTR(-ENOMEM);
+
+ if (partial) {
+ *p++ = 'i';
+ *p++ = 'd';
+ } else {
+ *p++ = 'e';
+ *p++ = 'x';
+ }
+ *p++ = ':';
+ p = bin2hex(p, lookup, len);
+ *p = 0;
+
+ pr_debug("Look up: \"%s\"\n", req);
+
+ ref = keyring_search(make_key_ref(keyring, 1),
+ &key_type_asymmetric, req);
+ if (IS_ERR(ref))
+ pr_debug("Request for key '%s' err %ld\n", req, PTR_ERR(ref));
+ kfree(req);
+
+ if (IS_ERR(ref)) {
+ switch (PTR_ERR(ref)) {
+ /* Hide some search errors */
+ case -EACCES:
+ case -ENOTDIR:
+ case -EAGAIN:
+ return ERR_PTR(-ENOKEY);
+ default:
+ return ERR_CAST(ref);
+ }
+ }
+
+ key = key_ref_to_ptr(ref);
+ if (id && skid) {
+ const struct asymmetric_key_ids *kids = asymmetric_key_ids(key);
+ if (!kids->id[1]) {
+ pr_debug("issuer+serial match, but expected SKID missing\n");
+ goto reject;
+ }
+ if (!asymmetric_key_id_same(skid, kids->id[1])) {
+ pr_debug("issuer+serial match, but SKID does not\n");
+ goto reject;
+ }
+ }
+
+ pr_devel("<==%s() = 0 [%x]\n", __func__, key_serial(key));
+ return key;
+
+reject:
+ key_put(key);
+ return ERR_PTR(-EKEYREJECTED);
+}
+EXPORT_SYMBOL_GPL(x509_request_asymmetric_key);
+
+/*
+ * Check the new certificate against the ones in the trust keyring. If one of
+ * those is the signing key and validates the new certificate, then mark the
+ * new certificate as being trusted.
+ *
+ * Return 0 if the new certificate was successfully validated, 1 if we couldn't
+ * find a matching parent certificate in the trusted list and an error if there
+ * is a matching certificate but the signature check fails.
+ */
+int x509_validate_trust(struct x509_certificate *cert,
+ struct key *trust_keyring)
+{
+ struct public_key_signature *sig = cert->sig;
+ struct key *key;
+ int ret = 1;
+
+ if (!sig->auth_ids[0] && !sig->auth_ids[1])
+ return 1;
+
+ if (!trust_keyring)
+ return -EOPNOTSUPP;
+ if (ca_keyid && !asymmetric_key_id_partial(sig->auth_ids[1], ca_keyid))
+ return -EPERM;
+ if (cert->unsupported_sig)
+ return -ENOPKG;
+
+ key = x509_request_asymmetric_key(trust_keyring,
+ sig->auth_ids[0], sig->auth_ids[1],
+ false);
+ if (IS_ERR(key))
+ return PTR_ERR(key);
+
+ if (!use_builtin_keys ||
+ test_bit(KEY_FLAG_BUILTIN, &key->flags)) {
+ ret = public_key_verify_signature(
+ key->payload.data[asym_crypto], cert->sig);
+ if (ret == -ENOPKG)
+ cert->unsupported_sig = true;
+ }
+ key_put(key);
+ return ret;
+}
diff --git a/crypto/asymmetric_keys/x509_parser.h b/crypto/asymmetric_keys/x509_parser.h
index 05eef1c68881..7a802b09a509 100644
--- a/crypto/asymmetric_keys/x509_parser.h
+++ b/crypto/asymmetric_keys/x509_parser.h
@@ -58,3 +58,9 @@ extern int x509_decode_time(time64_t *_t, size_t hdrlen,
*/
extern int x509_get_sig_params(struct x509_certificate *cert);
extern int x509_check_for_self_signed(struct x509_certificate *cert);
+
+/*
+ * public_key_trust.c
+ */
+extern int x509_validate_trust(struct x509_certificate *cert,
+ struct key *trust_keyring);
diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c
index 8ef99fac821f..c5c2fbc8c847 100644
--- a/crypto/asymmetric_keys/x509_public_key.c
+++ b/crypto/asymmetric_keys/x509_public_key.c
@@ -24,133 +24,6 @@
#include "public_key.h"
#include "x509_parser.h"
-static bool use_builtin_keys;
-static struct asymmetric_key_id *ca_keyid;
-
-#ifndef MODULE
-static struct {
- struct asymmetric_key_id id;
- unsigned char data[10];
-} cakey;
-
-static int __init ca_keys_setup(char *str)
-{
- if (!str) /* default system keyring */
- return 1;
-
- if (strncmp(str, "id:", 3) == 0) {
- struct asymmetric_key_id *p = &cakey.id;
- size_t hexlen = (strlen(str) - 3) / 2;
- int ret;
-
- if (hexlen == 0 || hexlen > sizeof(cakey.data)) {
- pr_err("Missing or invalid ca_keys id\n");
- return 1;
- }
-
- ret = __asymmetric_key_hex_to_key_id(str + 3, p, hexlen);
- if (ret < 0)
- pr_err("Unparsable ca_keys id hex string\n");
- else
- ca_keyid = p; /* owner key 'id:xxxxxx' */
- } else if (strcmp(str, "builtin") == 0) {
- use_builtin_keys = true;
- }
-
- return 1;
-}
-__setup("ca_keys=", ca_keys_setup);
-#endif
-
-/**
- * x509_request_asymmetric_key - Request a key by X.509 certificate params.
- * @keyring: The keys to search.
- * @id: The issuer & serialNumber to look for or NULL.
- * @skid: The subjectKeyIdentifier to look for or NULL.
- * @partial: Use partial match if true, exact if false.
- *
- * Find a key in the given keyring by identifier. The preferred identifier is
- * the issuer + serialNumber and the fallback identifier is the
- * subjectKeyIdentifier. If both are given, the lookup is by the former, but
- * the latter must also match.
- */
-struct key *x509_request_asymmetric_key(struct key *keyring,
- const struct asymmetric_key_id *id,
- const struct asymmetric_key_id *skid,
- bool partial)
-{
- struct key *key;
- key_ref_t ref;
- const char *lookup;
- char *req, *p;
- int len;
-
- if (id) {
- lookup = id->data;
- len = id->len;
- } else {
- lookup = skid->data;
- len = skid->len;
- }
-
- /* Construct an identifier "id:<keyid>". */
- p = req = kmalloc(2 + 1 + len * 2 + 1, GFP_KERNEL);
- if (!req)
- return ERR_PTR(-ENOMEM);
-
- if (partial) {
- *p++ = 'i';
- *p++ = 'd';
- } else {
- *p++ = 'e';
- *p++ = 'x';
- }
- *p++ = ':';
- p = bin2hex(p, lookup, len);
- *p = 0;
-
- pr_debug("Look up: \"%s\"\n", req);
-
- ref = keyring_search(make_key_ref(keyring, 1),
- &key_type_asymmetric, req);
- if (IS_ERR(ref))
- pr_debug("Request for key '%s' err %ld\n", req, PTR_ERR(ref));
- kfree(req);
-
- if (IS_ERR(ref)) {
- switch (PTR_ERR(ref)) {
- /* Hide some search errors */
- case -EACCES:
- case -ENOTDIR:
- case -EAGAIN:
- return ERR_PTR(-ENOKEY);
- default:
- return ERR_CAST(ref);
- }
- }
-
- key = key_ref_to_ptr(ref);
- if (id && skid) {
- const struct asymmetric_key_ids *kids = asymmetric_key_ids(key);
- if (!kids->id[1]) {
- pr_debug("issuer+serial match, but expected SKID missing\n");
- goto reject;
- }
- if (!asymmetric_key_id_same(skid, kids->id[1])) {
- pr_debug("issuer+serial match, but SKID does not\n");
- goto reject;
- }
- }
-
- pr_devel("<==%s() = 0 [%x]\n", __func__, key_serial(key));
- return key;
-
-reject:
- key_put(key);
- return ERR_PTR(-EKEYREJECTED);
-}
-EXPORT_SYMBOL_GPL(x509_request_asymmetric_key);
-
/*
* Set up the signature parameters in an X.509 certificate. This involves
* digesting the signed data and extracting the signature.
@@ -283,49 +156,6 @@ not_self_signed:
}
/*
- * Check the new certificate against the ones in the trust keyring. If one of
- * those is the signing key and validates the new certificate, then mark the
- * new certificate as being trusted.
- *
- * Return 0 if the new certificate was successfully validated, 1 if we couldn't
- * find a matching parent certificate in the trusted list and an error if there
- * is a matching certificate but the signature check fails.
- */
-static int x509_validate_trust(struct x509_certificate *cert,
- struct key *trust_keyring)
-{
- struct public_key_signature *sig = cert->sig;
- struct key *key;
- int ret = 1;
-
- if (!sig->auth_ids[0] && !sig->auth_ids[1])
- return 1;
-
- if (!trust_keyring)
- return -EOPNOTSUPP;
- if (ca_keyid && !asymmetric_key_id_partial(sig->auth_ids[1], ca_keyid))
- return -EPERM;
- if (cert->unsupported_sig)
- return -ENOPKG;
-
- key = x509_request_asymmetric_key(trust_keyring,
- sig->auth_ids[0], sig->auth_ids[1],
- false);
- if (IS_ERR(key))
- return PTR_ERR(key);
-
- if (!use_builtin_keys ||
- test_bit(KEY_FLAG_BUILTIN, &key->flags)) {
- ret = public_key_verify_signature(
- key->payload.data[asym_crypto], cert->sig);
- if (ret == -ENOPKG)
- cert->unsupported_sig = true;
- }
- key_put(key);
- return ret;
-}
-
-/*
* Attempt to parse a data blob for a key as an X509 certificate.
*/
static int x509_key_preparse(struct key_preparsed_payload *prep)
[toc] | [prev] | [next] | [standalone]
| From | David Howells <dhowells@redhat.com> |
|---|---|
| Date | 2016-01-08 19:40 +0100 |
| Subject | [RFC PATCH 11/15] PKCS#7: Make the signature a pointer rather than embedding it |
| Message-ID | <qOK7b-2eA-81@gated-at.bofh.it> |
| In reply to | #1304889 |
Point to the public_key_signature struct from the pkcs7_signed_info struct
rather than embedding it. This makes it easier to have it take an
arbitrary number of MPIs in future.
We also save a copy of the digest in the signature without sharing the
memory with the crypto layer metadata. This means we can use
public_key_free() to get rid of the signature record.
Signed-off-by: David Howells <dhowells@redhat.com>
---
crypto/asymmetric_keys/pkcs7_parser.c | 38 ++++++++++++++----------
crypto/asymmetric_keys/pkcs7_parser.h | 10 ++----
crypto/asymmetric_keys/pkcs7_trust.c | 4 +-
crypto/asymmetric_keys/pkcs7_verify.c | 53 +++++++++++++++++----------------
4 files changed, 56 insertions(+), 49 deletions(-)
diff --git a/crypto/asymmetric_keys/pkcs7_parser.c b/crypto/asymmetric_keys/pkcs7_parser.c
index 7b69783cff99..8454ae5b5aa8 100644
--- a/crypto/asymmetric_keys/pkcs7_parser.c
+++ b/crypto/asymmetric_keys/pkcs7_parser.c
@@ -44,9 +44,7 @@ struct pkcs7_parse_context {
static void pkcs7_free_signed_info(struct pkcs7_signed_info *sinfo)
{
if (sinfo) {
- mpi_free(sinfo->sig.mpi[0]);
- kfree(sinfo->sig.digest);
- kfree(sinfo->signing_cert_id);
+ public_key_free(NULL, sinfo->sig);
kfree(sinfo);
}
}
@@ -125,6 +123,10 @@ struct pkcs7_message *pkcs7_parse_message(const void *data, size_t datalen)
ctx->sinfo = kzalloc(sizeof(struct pkcs7_signed_info), GFP_KERNEL);
if (!ctx->sinfo)
goto out_no_sinfo;
+ ctx->sinfo->sig = kzalloc(sizeof(struct public_key_signature),
+ GFP_KERNEL);
+ if (!ctx->sinfo->sig)
+ goto out_no_sig;
ctx->data = (unsigned long)data;
ctx->ppcerts = &ctx->certs;
@@ -150,6 +152,7 @@ out:
ctx->certs = cert->next;
x509_free_certificate(cert);
}
+out_no_sig:
pkcs7_free_signed_info(ctx->sinfo);
out_no_sinfo:
pkcs7_free_message(ctx->msg);
@@ -219,25 +222,25 @@ int pkcs7_sig_note_digest_algo(void *context, size_t hdrlen,
switch (ctx->last_oid) {
case OID_md4:
- ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_MD4;
+ ctx->sinfo->sig->pkey_hash_algo = HASH_ALGO_MD4;
break;
case OID_md5:
- ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_MD5;
+ ctx->sinfo->sig->pkey_hash_algo = HASH_ALGO_MD5;
break;
case OID_sha1:
- ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_SHA1;
+ ctx->sinfo->sig->pkey_hash_algo = HASH_ALGO_SHA1;
break;
case OID_sha256:
- ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_SHA256;
+ ctx->sinfo->sig->pkey_hash_algo = HASH_ALGO_SHA256;
break;
case OID_sha384:
- ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_SHA384;
+ ctx->sinfo->sig->pkey_hash_algo = HASH_ALGO_SHA384;
break;
case OID_sha512:
- ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_SHA512;
+ ctx->sinfo->sig->pkey_hash_algo = HASH_ALGO_SHA512;
break;
case OID_sha224:
- ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_SHA224;
+ ctx->sinfo->sig->pkey_hash_algo = HASH_ALGO_SHA224;
default:
printk("Unsupported digest algo: %u\n", ctx->last_oid);
return -ENOPKG;
@@ -256,7 +259,7 @@ int pkcs7_sig_note_pkey_algo(void *context, size_t hdrlen,
switch (ctx->last_oid) {
case OID_rsaEncryption:
- ctx->sinfo->sig.pkey_algo = PKEY_ALGO_RSA;
+ ctx->sinfo->sig->pkey_algo = PKEY_ALGO_RSA;
break;
default:
printk("Unsupported pkey algo: %u\n", ctx->last_oid);
@@ -617,16 +620,17 @@ int pkcs7_sig_note_signature(void *context, size_t hdrlen,
const void *value, size_t vlen)
{
struct pkcs7_parse_context *ctx = context;
+ struct public_key_signature *sig = ctx->sinfo->sig;
MPI mpi;
- BUG_ON(ctx->sinfo->sig.pkey_algo != PKEY_ALGO_RSA);
+ BUG_ON(sig->pkey_algo != PKEY_ALGO_RSA);
mpi = mpi_read_raw_data(value, vlen);
if (!mpi)
return -ENOMEM;
- ctx->sinfo->sig.mpi[0] = mpi;
- ctx->sinfo->sig.nr_mpi = 1;
+ sig->mpi[0] = mpi;
+ sig->nr_mpi = 1;
return 0;
}
@@ -662,12 +666,16 @@ int pkcs7_note_signed_info(void *context, size_t hdrlen,
pr_devel("SINFO KID: %u [%*phN]\n", kid->len, kid->len, kid->data);
- sinfo->signing_cert_id = kid;
+ sinfo->sig->auth_ids[0] = kid;
sinfo->index = ++ctx->sinfo_index;
*ctx->ppsinfo = sinfo;
ctx->ppsinfo = &sinfo->next;
ctx->sinfo = kzalloc(sizeof(struct pkcs7_signed_info), GFP_KERNEL);
if (!ctx->sinfo)
return -ENOMEM;
+ ctx->sinfo->sig = kzalloc(sizeof(struct public_key_signature),
+ GFP_KERNEL);
+ if (!ctx->sinfo->sig)
+ return -ENOMEM;
return 0;
}
diff --git a/crypto/asymmetric_keys/pkcs7_parser.h b/crypto/asymmetric_keys/pkcs7_parser.h
index c8159983ed8f..f4e81074f5e0 100644
--- a/crypto/asymmetric_keys/pkcs7_parser.h
+++ b/crypto/asymmetric_keys/pkcs7_parser.h
@@ -40,19 +40,17 @@ struct pkcs7_signed_info {
#define sinfo_has_ms_statement_type 5
time64_t signing_time;
- /* Issuing cert serial number and issuer's name [PKCS#7 or CMS ver 1]
- * or issuing cert's SKID [CMS ver 3].
- */
- struct asymmetric_key_id *signing_cert_id;
-
/* Message signature.
*
* This contains the generated digest of _either_ the Content Data or
* the Authenticated Attributes [RFC2315 9.3]. If the latter, one of
* the attributes contains the digest of the the Content Data within
* it.
+ *
+ * THis also contains the issuing cert serial number and issuer's name
+ * [PKCS#7 or CMS ver 1] or issuing cert's SKID [CMS ver 3].
*/
- struct public_key_signature sig;
+ struct public_key_signature *sig;
};
struct pkcs7_message {
diff --git a/crypto/asymmetric_keys/pkcs7_trust.c b/crypto/asymmetric_keys/pkcs7_trust.c
index 7bb9389fd644..400ef359448a 100644
--- a/crypto/asymmetric_keys/pkcs7_trust.c
+++ b/crypto/asymmetric_keys/pkcs7_trust.c
@@ -27,7 +27,7 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
struct pkcs7_signed_info *sinfo,
struct key *trust_keyring)
{
- struct public_key_signature *sig = &sinfo->sig;
+ struct public_key_signature *sig = sinfo->sig;
struct x509_certificate *x509, *last = NULL, *p;
struct key *key;
int ret;
@@ -102,7 +102,7 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
* the signed info directly.
*/
key = x509_request_asymmetric_key(trust_keyring,
- sinfo->signing_cert_id,
+ sinfo->sig->auth_ids[0],
NULL,
false);
if (!IS_ERR(key)) {
diff --git a/crypto/asymmetric_keys/pkcs7_verify.c b/crypto/asymmetric_keys/pkcs7_verify.c
index 0d1173081b5c..3b8124c2cd91 100644
--- a/crypto/asymmetric_keys/pkcs7_verify.c
+++ b/crypto/asymmetric_keys/pkcs7_verify.c
@@ -25,36 +25,38 @@
static int pkcs7_digest(struct pkcs7_message *pkcs7,
struct pkcs7_signed_info *sinfo)
{
+ struct public_key_signature *sig = sinfo->sig;
struct crypto_shash *tfm;
struct shash_desc *desc;
- size_t digest_size, desc_size;
- void *digest;
+ size_t desc_size;
int ret;
- kenter(",%u,%u", sinfo->index, sinfo->sig.pkey_hash_algo);
+ kenter(",%u,%u", sinfo->index, sig->pkey_hash_algo);
- if (sinfo->sig.pkey_hash_algo >= PKEY_HASH__LAST ||
- !hash_algo_name[sinfo->sig.pkey_hash_algo])
+ if (sig->pkey_hash_algo >= PKEY_HASH__LAST ||
+ !hash_algo_name[sig->pkey_hash_algo])
return -ENOPKG;
/* Allocate the hashing algorithm we're going to need and find out how
* big the hash operational data will be.
*/
- tfm = crypto_alloc_shash(hash_algo_name[sinfo->sig.pkey_hash_algo],
+ tfm = crypto_alloc_shash(hash_algo_name[sinfo->sig->pkey_hash_algo],
0, 0);
if (IS_ERR(tfm))
return (PTR_ERR(tfm) == -ENOENT) ? -ENOPKG : PTR_ERR(tfm);
desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
- sinfo->sig.digest_size = digest_size = crypto_shash_digestsize(tfm);
+ sig->digest_size = crypto_shash_digestsize(tfm);
ret = -ENOMEM;
- digest = kzalloc(ALIGN(digest_size, __alignof__(*desc)) + desc_size,
- GFP_KERNEL);
- if (!digest)
+ sig->digest = kmalloc(sig->digest_size, GFP_KERNEL);
+ if (!sig->digest)
+ goto error_no_desc;
+
+ desc = kzalloc(desc_size, GFP_KERNEL);
+ if (!desc)
goto error_no_desc;
- desc = PTR_ALIGN(digest + digest_size, __alignof__(*desc));
desc->tfm = tfm;
desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
@@ -62,10 +64,11 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7,
ret = crypto_shash_init(desc);
if (ret < 0)
goto error;
- ret = crypto_shash_finup(desc, pkcs7->data, pkcs7->data_len, digest);
+ ret = crypto_shash_finup(desc, pkcs7->data, pkcs7->data_len,
+ sig->digest);
if (ret < 0)
goto error;
- pr_devel("MsgDigest = [%*ph]\n", 8, digest);
+ pr_devel("MsgDigest = [%*ph]\n", 8, sig->digest);
/* However, if there are authenticated attributes, there must be a
* message digest attribute amongst them which corresponds to the
@@ -80,14 +83,15 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7,
goto error;
}
- if (sinfo->msgdigest_len != sinfo->sig.digest_size) {
+ if (sinfo->msgdigest_len != sig->digest_size) {
pr_debug("Sig %u: Invalid digest size (%u)\n",
sinfo->index, sinfo->msgdigest_len);
ret = -EBADMSG;
goto error;
}
- if (memcmp(digest, sinfo->msgdigest, sinfo->msgdigest_len) != 0) {
+ if (memcmp(sig->digest, sinfo->msgdigest,
+ sinfo->msgdigest_len) != 0) {
pr_debug("Sig %u: Message digest doesn't match\n",
sinfo->index);
ret = -EKEYREJECTED;
@@ -99,7 +103,7 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7,
* convert the attributes from a CONT.0 into a SET before we
* hash it.
*/
- memset(digest, 0, sinfo->sig.digest_size);
+ memset(sig->digest, 0, sig->digest_size);
ret = crypto_shash_init(desc);
if (ret < 0)
@@ -109,17 +113,14 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7,
if (ret < 0)
goto error;
ret = crypto_shash_finup(desc, sinfo->authattrs,
- sinfo->authattrs_len, digest);
+ sinfo->authattrs_len, sig->digest);
if (ret < 0)
goto error;
- pr_devel("AADigest = [%*ph]\n", 8, digest);
+ pr_devel("AADigest = [%*ph]\n", 8, sig->digest);
}
- sinfo->sig.digest = digest;
- digest = NULL;
-
error:
- kfree(digest);
+ kfree(desc);
error_no_desc:
crypto_free_shash(tfm);
kleave(" = %d", ret);
@@ -146,12 +147,12 @@ static int pkcs7_find_key(struct pkcs7_message *pkcs7,
* PKCS#7 message - but I can't be 100% sure of that. It's
* possible this will need element-by-element comparison.
*/
- if (!asymmetric_key_id_same(x509->id, sinfo->signing_cert_id))
+ if (!asymmetric_key_id_same(x509->id, sinfo->sig->auth_ids[0]))
continue;
pr_devel("Sig %u: Found cert serial match X.509[%u]\n",
sinfo->index, certix);
- if (x509->pub->pkey_algo != sinfo->sig.pkey_algo) {
+ if (x509->pub->pkey_algo != sinfo->sig->pkey_algo) {
pr_warn("Sig %u: X.509 algo and PKCS#7 sig algo don't match\n",
sinfo->index);
continue;
@@ -166,7 +167,7 @@ static int pkcs7_find_key(struct pkcs7_message *pkcs7,
*/
pr_debug("Sig %u: Issuing X.509 cert not found (#%*phN)\n",
sinfo->index,
- sinfo->signing_cert_id->len, sinfo->signing_cert_id->data);
+ sinfo->sig->auth_ids[0]->len, sinfo->sig->auth_ids[0]->data);
return 0;
}
@@ -325,7 +326,7 @@ static int pkcs7_verify_one(struct pkcs7_message *pkcs7,
}
/* 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);
if (ret < 0)
return ret;
[toc] | [prev] | [next] | [standalone]
| From | David Howells <dhowells@redhat.com> |
|---|---|
| Date | 2016-01-08 19:40 +0100 |
| Subject | [RFC PATCH 01/15] X.509: Partially revert patch to add validation against IMA MOK keyring |
| Message-ID | <qOK7b-2eA-91@gated-at.bofh.it> |
| In reply to | #1304889 |
Partially revert commit 41c89b64d7184a780f12f2cccdabe65cb2408893:
Author: Petko Manolov <petkan@mip-labs.com>
Date: Wed Dec 2 17:47:55 2015 +0200
IMA: create machine owner and blacklist keyrings
The problem is that prep->trusted is a simple boolean and the additional
x509_validate_trust() call doesn't therefore distinguish levels of
trustedness, but is just OR'd with the result of validation against the
system trusted keyring.
However, setting the trusted flag means that this key may be added to *any*
trusted-only keyring - including the system trusted keyring.
Whilst I appreciate what the patch is trying to do, I don't think this is
quite the right solution.
Signed-off-by: David Howells <dhowells@redhat.com>
cc: Petko Manolov <petkan@mip-labs.com>
cc: Mimi Zohar <zohar@linux.vnet.ibm.com>
cc: keyrings@vger.kernel.org
---
crypto/asymmetric_keys/x509_public_key.c | 2 --
1 file changed, 2 deletions(-)
diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c
index 9e9e5a6a9ed6..2a44b3752471 100644
--- a/crypto/asymmetric_keys/x509_public_key.c
+++ b/crypto/asymmetric_keys/x509_public_key.c
@@ -321,8 +321,6 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
goto error_free_cert;
} else if (!prep->trusted) {
ret = x509_validate_trust(cert, get_system_trusted_keyring());
- if (ret)
- ret = x509_validate_trust(cert, get_ima_mok_keyring());
if (!ret)
prep->trusted = 1;
}
[toc] | [prev] | [next] | [standalone]
| From | David Howells <dhowells@redhat.com> |
|---|---|
| Date | 2016-01-08 19:40 +0100 |
| Subject | [RFC PATCH 06/15] KEYS: Add a facility to restrict new links into a keyring |
| Message-ID | <qOK7b-2eA-83@gated-at.bofh.it> |
| In reply to | #1304889 |
Add a facility whereby proposed new links to be added to a keyring can be
vetted, permitting them to be rejected if necessary. This can be used to
block public keys from which the signature cannot be verified or for which
the signature verification fails. It could also be used to provide
blacklisting.
This affects operations like add_key(), KEYCTL_LINK and KEYCTL_INSTANTIATE.
To this end:
(1) A function pointer is added to the key struct that, if set, points to
the vetting function. This is called as:
int (*restrict_link)(struct key *keyring,
const struct key_type *key_type,
unsigned long key_flags,
const union key_payload *key_payload),
where 'keyring' will be the keyring being added to, key_type and
key_payload will describe the key being added and key_flags[*] can be
AND'ed with KEY_FLAG_TRUSTED.
[*] This parameter will be removed in a later patch when
KEY_FLAG_TRUSTED is removed.
The function should return 0 to allow the link to take place or an
error (typically -ENOKEY, -ENOPKG or -EKEYREJECTED) to reject the
link.
The pointer should not be set directly, but rather should be set
through keyring_alloc().
Note that if called during add_key(), preparse is called before this
method, but a key isn't actually allocated until after this function
is called.
(2) KEY_ALLOC_BYPASS_RESTRICTION is added. This can be passed to
key_create_or_update() or key_instantiate_and_link() to bypass the
restriction check.
(3) KEY_FLAG_TRUSTED_ONLY is removed. The entire contents of a keyring
with this restriction emplaced can be considered 'trustworthy' by
virtue of being in the keyring when that keyring is consulted.
(4) key_alloc() and keyring_alloc() take an extra argument that will be
used to set restrict_link in the new key. This ensures that the
pointer is set before the key is published, thus preventing a window
of unrestrictedness. Normally this argument will be NULL.
(5) As a temporary affair, keyring_restrict_trusted_only() is added. It
should be passed to keyring_alloc() as the extra argument instead of
setting KEY_FLAG_TRUSTED_ONLY on a keyring. This will be replaced in
a later patch with functions that look in the appropriate places for
authoritative keys.
Signed-off-by: David Howells <dhowells@redhat.com>
---
Documentation/security/keys.txt | 14 ++++++++++
certs/system_keyring.c | 8 +++---
fs/cifs/cifsacl.c | 2 +
fs/nfs/nfs4idmap.c | 2 +
include/linux/key.h | 48 ++++++++++++++++++++++++++++-------
net/dns_resolver/dns_key.c | 2 +
net/rxrpc/ar-key.c | 4 +--
security/integrity/digsig.c | 7 ++---
security/integrity/ima/ima_mok.c | 8 +++---
security/keys/key.c | 43 ++++++++++++++++++++++++++-----
security/keys/keyring.c | 52 +++++++++++++++++++++++++++++++++-----
security/keys/persistent.c | 4 +--
security/keys/process_keys.c | 16 +++++++-----
security/keys/request_key.c | 4 +--
security/keys/request_key_auth.c | 2 +
15 files changed, 164 insertions(+), 52 deletions(-)
diff --git a/Documentation/security/keys.txt b/Documentation/security/keys.txt
index 8c183873b2b7..3e2e958f2091 100644
--- a/Documentation/security/keys.txt
+++ b/Documentation/security/keys.txt
@@ -999,6 +999,10 @@ payload contents" for more information.
struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid,
const struct cred *cred,
key_perm_t perm,
+ int (*restrict_link)(struct key *,
+ const struct key_type *,
+ unsigned long,
+ const union key_payload *),
unsigned long flags,
struct key *dest);
@@ -1010,6 +1014,16 @@ payload contents" for more information.
KEY_ALLOC_NOT_IN_QUOTA in flags if the keyring shouldn't be accounted
towards the user's quota). Error ENOMEM can also be returned.
+ If restrict_link not NULL, it should point to a function will be called to
+ vet all attempts to link keys into the keyring, though this can be
+ overridden by passing KEY_ALLOC_BYPASS_RESTRICTION to
+ key_create_or_update().
+
+ When called, the restriction function will be passed the keyring being
+ added to, the key flags value and the type and payload of the key being
+ added. Note that when a new key is being created, this is called between
+ payload preparsing and actual key creation.
+
(*) To check the validity of a key, this function can be called:
diff --git a/certs/system_keyring.c b/certs/system_keyring.c
index dc18869ff680..417d65882870 100644
--- a/certs/system_keyring.c
+++ b/certs/system_keyring.c
@@ -36,11 +36,10 @@ static __init int system_trusted_keyring_init(void)
KUIDT_INIT(0), KGIDT_INIT(0), current_cred(),
((KEY_POS_ALL & ~KEY_POS_SETATTR) |
KEY_USR_VIEW | KEY_USR_READ | KEY_USR_SEARCH),
- KEY_ALLOC_NOT_IN_QUOTA, NULL);
+ KEY_ALLOC_NOT_IN_QUOTA,
+ keyring_restrict_trusted_only, NULL);
if (IS_ERR(system_trusted_keyring))
panic("Can't allocate system trusted keyring\n");
-
- set_bit(KEY_FLAG_TRUSTED_ONLY, &system_trusted_keyring->flags);
return 0;
}
@@ -85,7 +84,8 @@ static __init int load_system_certificate_list(void)
KEY_USR_VIEW | KEY_USR_READ),
KEY_ALLOC_NOT_IN_QUOTA |
KEY_ALLOC_TRUSTED |
- KEY_ALLOC_BUILT_IN);
+ KEY_ALLOC_BUILT_IN |
+ KEY_ALLOC_BYPASS_RESTRICTION);
if (IS_ERR(key)) {
pr_err("Problem loading in-kernel X.509 certificate (%ld)\n",
PTR_ERR(key));
diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c
index 3f93125916bf..71e8a56e9479 100644
--- a/fs/cifs/cifsacl.c
+++ b/fs/cifs/cifsacl.c
@@ -360,7 +360,7 @@ init_cifs_idmap(void)
GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred,
(KEY_POS_ALL & ~KEY_POS_SETATTR) |
KEY_USR_VIEW | KEY_USR_READ,
- KEY_ALLOC_NOT_IN_QUOTA, NULL);
+ KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL);
if (IS_ERR(keyring)) {
ret = PTR_ERR(keyring);
goto failed_put_cred;
diff --git a/fs/nfs/nfs4idmap.c b/fs/nfs/nfs4idmap.c
index 5ba22c6b0ffa..c444285bb1b1 100644
--- a/fs/nfs/nfs4idmap.c
+++ b/fs/nfs/nfs4idmap.c
@@ -201,7 +201,7 @@ int nfs_idmap_init(void)
GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred,
(KEY_POS_ALL & ~KEY_POS_SETATTR) |
KEY_USR_VIEW | KEY_USR_READ,
- KEY_ALLOC_NOT_IN_QUOTA, NULL);
+ KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL);
if (IS_ERR(keyring)) {
ret = PTR_ERR(keyring);
goto failed_put_cred;
diff --git a/include/linux/key.h b/include/linux/key.h
index 5f5b1129dc92..c331b8bed035 100644
--- a/include/linux/key.h
+++ b/include/linux/key.h
@@ -174,10 +174,9 @@ struct key {
#define KEY_FLAG_ROOT_CAN_CLEAR 6 /* set if key can be cleared by root without permission */
#define KEY_FLAG_INVALIDATED 7 /* set if key has been invalidated */
#define KEY_FLAG_TRUSTED 8 /* set if key is trusted */
-#define KEY_FLAG_TRUSTED_ONLY 9 /* set if keyring only accepts links to trusted keys */
-#define KEY_FLAG_BUILTIN 10 /* set if key is builtin */
-#define KEY_FLAG_ROOT_CAN_INVAL 11 /* set if key can be invalidated by root without permission */
-#define KEY_FLAG_KEEP 12 /* set if key should not be removed */
+#define KEY_FLAG_BUILTIN 9 /* set if key is built in to the kernel */
+#define KEY_FLAG_ROOT_CAN_INVAL 10 /* set if key can be invalidated by root without permission */
+#define KEY_FLAG_KEEP 11 /* set if key should not be removed */
/* the key type and key description string
* - the desc is used to match a key against search criteria
@@ -205,6 +204,21 @@ struct key {
};
int reject_error;
};
+
+ /* This is set on a keyring to restrict the addition of a link to a key
+ * to it. If this method isn't provided then it is assumed that the
+ * keyring is open to any addition. It is ignored for non-keyring
+ * keys.
+ *
+ * This is intended for use with rings of trusted keys whereby addition
+ * to the keyring needs to be controlled. KEY_ALLOC_BYPASS_RESTRICTION
+ * overrides this, allowing the kernel to add extra keys without
+ * restriction.
+ */
+ int (*restrict_link)(struct key *keyring,
+ const struct key_type *type,
+ unsigned long flags,
+ const union key_payload *payload);
};
extern struct key *key_alloc(struct key_type *type,
@@ -212,14 +226,19 @@ extern struct key *key_alloc(struct key_type *type,
kuid_t uid, kgid_t gid,
const struct cred *cred,
key_perm_t perm,
- unsigned long flags);
+ unsigned long flags,
+ int (*restrict_link)(struct key *,
+ const struct key_type *,
+ unsigned long,
+ const union key_payload *));
-#define KEY_ALLOC_IN_QUOTA 0x0000 /* add to quota, reject if would overrun */
-#define KEY_ALLOC_QUOTA_OVERRUN 0x0001 /* add to quota, permit even if overrun */
-#define KEY_ALLOC_NOT_IN_QUOTA 0x0002 /* not in quota */
-#define KEY_ALLOC_TRUSTED 0x0004 /* Key should be flagged as trusted */
-#define KEY_ALLOC_BUILT_IN 0x0008 /* Key is built into kernel */
+#define KEY_ALLOC_IN_QUOTA 0x0000 /* add to quota, reject if would overrun */
+#define KEY_ALLOC_QUOTA_OVERRUN 0x0001 /* add to quota, permit even if overrun */
+#define KEY_ALLOC_NOT_IN_QUOTA 0x0002 /* not in quota */
+#define KEY_ALLOC_TRUSTED 0x0004 /* Key should be flagged as trusted */
+#define KEY_ALLOC_BUILT_IN 0x0008 /* Key is built into kernel */
+#define KEY_ALLOC_BYPASS_RESTRICTION 0x0010 /* Override the check on restricted keyrings */
extern void key_revoke(struct key *key);
extern void key_invalidate(struct key *key);
@@ -288,8 +307,17 @@ extern struct key *keyring_alloc(const char *description, kuid_t uid, kgid_t gid
const struct cred *cred,
key_perm_t perm,
unsigned long flags,
+ int (*restrict_link)(struct key *,
+ const struct key_type *,
+ unsigned long,
+ const union key_payload *),
struct key *dest);
+extern int keyring_restrict_trusted_only(struct key *keyring,
+ const struct key_type *type,
+ unsigned long,
+ const union key_payload *payload);
+
extern int keyring_clear(struct key *keyring);
extern key_ref_t keyring_search(key_ref_t keyring,
diff --git a/net/dns_resolver/dns_key.c b/net/dns_resolver/dns_key.c
index c79b85eb4d4c..8737412c7b27 100644
--- a/net/dns_resolver/dns_key.c
+++ b/net/dns_resolver/dns_key.c
@@ -281,7 +281,7 @@ static int __init init_dns_resolver(void)
GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred,
(KEY_POS_ALL & ~KEY_POS_SETATTR) |
KEY_USR_VIEW | KEY_USR_READ,
- KEY_ALLOC_NOT_IN_QUOTA, NULL);
+ KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL);
if (IS_ERR(keyring)) {
ret = PTR_ERR(keyring);
goto failed_put_cred;
diff --git a/net/rxrpc/ar-key.c b/net/rxrpc/ar-key.c
index da3cc09f683e..767d03925659 100644
--- a/net/rxrpc/ar-key.c
+++ b/net/rxrpc/ar-key.c
@@ -977,7 +977,7 @@ int rxrpc_get_server_data_key(struct rxrpc_connection *conn,
key = key_alloc(&key_type_rxrpc, "x",
GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred, 0,
- KEY_ALLOC_NOT_IN_QUOTA);
+ KEY_ALLOC_NOT_IN_QUOTA, NULL);
if (IS_ERR(key)) {
_leave(" = -ENOMEM [alloc %ld]", PTR_ERR(key));
return -ENOMEM;
@@ -1024,7 +1024,7 @@ struct key *rxrpc_get_null_key(const char *keyname)
key = key_alloc(&key_type_rxrpc, keyname,
GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred,
- KEY_POS_SEARCH, KEY_ALLOC_NOT_IN_QUOTA);
+ KEY_POS_SEARCH, KEY_ALLOC_NOT_IN_QUOTA, NULL);
if (IS_ERR(key))
return key;
diff --git a/security/integrity/digsig.c b/security/integrity/digsig.c
index 8ef15118cc78..659566c2200b 100644
--- a/security/integrity/digsig.c
+++ b/security/integrity/digsig.c
@@ -83,10 +83,9 @@ int __init integrity_init_keyring(const unsigned int id)
((KEY_POS_ALL & ~KEY_POS_SETATTR) |
KEY_USR_VIEW | KEY_USR_READ |
KEY_USR_WRITE | KEY_USR_SEARCH),
- KEY_ALLOC_NOT_IN_QUOTA, NULL);
- if (!IS_ERR(keyring[id]))
- set_bit(KEY_FLAG_TRUSTED_ONLY, &keyring[id]->flags);
- else {
+ KEY_ALLOC_NOT_IN_QUOTA,
+ NULL, NULL);
+ if (IS_ERR(keyring[id])) {
err = PTR_ERR(keyring[id]);
pr_info("Can't allocate %s keyring (%d)\n",
keyring_name[id], err);
diff --git a/security/integrity/ima/ima_mok.c b/security/integrity/ima/ima_mok.c
index 676885e4320e..ef91248cb934 100644
--- a/security/integrity/ima/ima_mok.c
+++ b/security/integrity/ima/ima_mok.c
@@ -35,20 +35,20 @@ __init int ima_mok_init(void)
(KEY_POS_ALL & ~KEY_POS_SETATTR) |
KEY_USR_VIEW | KEY_USR_READ |
KEY_USR_WRITE | KEY_USR_SEARCH,
- KEY_ALLOC_NOT_IN_QUOTA, NULL);
+ KEY_ALLOC_NOT_IN_QUOTA,
+ keyring_restrict_trusted_only, NULL);
ima_blacklist_keyring = keyring_alloc(".ima_blacklist",
KUIDT_INIT(0), KGIDT_INIT(0), current_cred(),
(KEY_POS_ALL & ~KEY_POS_SETATTR) |
KEY_USR_VIEW | KEY_USR_READ |
KEY_USR_WRITE | KEY_USR_SEARCH,
- KEY_ALLOC_NOT_IN_QUOTA, NULL);
+ KEY_ALLOC_NOT_IN_QUOTA,
+ keyring_restrict_trusted_only, NULL);
if (IS_ERR(ima_mok_keyring) || IS_ERR(ima_blacklist_keyring))
panic("Can't allocate IMA MOK or blacklist keyrings.");
- set_bit(KEY_FLAG_TRUSTED_ONLY, &ima_mok_keyring->flags);
- set_bit(KEY_FLAG_TRUSTED_ONLY, &ima_blacklist_keyring->flags);
set_bit(KEY_FLAG_KEEP, &ima_blacklist_keyring->flags);
return 0;
}
diff --git a/security/keys/key.c b/security/keys/key.c
index b28755131687..deb881754e03 100644
--- a/security/keys/key.c
+++ b/security/keys/key.c
@@ -201,6 +201,7 @@ serial_exists:
* @cred: The credentials specifying UID namespace.
* @perm: The permissions mask of the new key.
* @flags: Flags specifying quota properties.
+ * @restrict_link: Optional link restriction method for new keyrings.
*
* Allocate a key of the specified type with the attributes given. The key is
* returned in an uninstantiated state and the caller needs to instantiate the
@@ -223,7 +224,11 @@ serial_exists:
*/
struct key *key_alloc(struct key_type *type, const char *desc,
kuid_t uid, kgid_t gid, const struct cred *cred,
- key_perm_t perm, unsigned long flags)
+ key_perm_t perm, unsigned long flags,
+ int (*restrict_link)(struct key *,
+ const struct key_type *,
+ unsigned long,
+ const union key_payload *))
{
struct key_user *user = NULL;
struct key *key;
@@ -291,6 +296,7 @@ struct key *key_alloc(struct key_type *type, const char *desc,
key->uid = uid;
key->gid = gid;
key->perm = perm;
+ key->restrict_link = restrict_link;
if (!(flags & KEY_ALLOC_NOT_IN_QUOTA))
key->flags |= 1 << KEY_FLAG_IN_QUOTA;
@@ -496,6 +502,12 @@ int key_instantiate_and_link(struct key *key,
}
if (keyring) {
+ if (keyring->restrict_link) {
+ ret = keyring->restrict_link(keyring, key->type,
+ key->flags, &prep.payload);
+ if (ret < 0)
+ goto error;
+ }
ret = __key_link_begin(keyring, &key->index_key, &edit);
if (ret < 0)
goto error;
@@ -551,8 +563,12 @@ int key_reject_and_link(struct key *key,
awaken = 0;
ret = -EBUSY;
- if (keyring)
+ if (keyring) {
+ if (keyring->restrict_link)
+ return -EPERM;
+
link_ret = __key_link_begin(keyring, &key->index_key, &edit);
+ }
mutex_lock(&key_construction_mutex);
@@ -793,6 +809,10 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
struct key *keyring, *key = NULL;
key_ref_t key_ref;
int ret;
+ int (*restrict_link)(struct key *,
+ const struct key_type *,
+ unsigned long,
+ const union key_payload *) = NULL;
/* look up the key type to see if it's one of the registered kernel
* types */
@@ -811,6 +831,10 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
key_check(keyring);
+ key_ref = ERR_PTR(-EPERM);
+ if (!(flags & KEY_ALLOC_BYPASS_RESTRICTION))
+ restrict_link = keyring->restrict_link;
+
key_ref = ERR_PTR(-ENOTDIR);
if (keyring->type != &key_type_keyring)
goto error_put_type;
@@ -835,10 +859,15 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
}
index_key.desc_len = strlen(index_key.description);
- key_ref = ERR_PTR(-EPERM);
- if (!prep.trusted && test_bit(KEY_FLAG_TRUSTED_ONLY, &keyring->flags))
- goto error_free_prep;
- flags |= prep.trusted ? KEY_ALLOC_TRUSTED : 0;
+ if (restrict_link) {
+ unsigned long kflags = prep.trusted ? KEY_FLAG_TRUSTED : 0;
+ ret = restrict_link(keyring,
+ index_key.type, kflags, &prep.payload);
+ if (ret < 0) {
+ key_ref = ERR_PTR(ret);
+ goto error_free_prep;
+ }
+ }
ret = __key_link_begin(keyring, &index_key, &edit);
if (ret < 0) {
@@ -879,7 +908,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
/* allocate a new key */
key = key_alloc(index_key.type, index_key.description,
- cred->fsuid, cred->fsgid, cred, perm, flags);
+ cred->fsuid, cred->fsgid, cred, perm, flags, NULL);
if (IS_ERR(key)) {
key_ref = ERR_CAST(key);
goto error_link_end;
diff --git a/security/keys/keyring.c b/security/keys/keyring.c
index f931ccfeefb0..ea023ca6d217 100644
--- a/security/keys/keyring.c
+++ b/security/keys/keyring.c
@@ -491,13 +491,18 @@ static long keyring_read(const struct key *keyring,
*/
struct key *keyring_alloc(const char *description, kuid_t uid, kgid_t gid,
const struct cred *cred, key_perm_t perm,
- unsigned long flags, struct key *dest)
+ unsigned long flags,
+ int (*restrict_link)(struct key *,
+ const struct key_type *,
+ unsigned long,
+ const union key_payload *),
+ struct key *dest)
{
struct key *keyring;
int ret;
keyring = key_alloc(&key_type_keyring, description,
- uid, gid, cred, perm, flags);
+ uid, gid, cred, perm, flags, restrict_link);
if (!IS_ERR(keyring)) {
ret = key_instantiate_and_link(keyring, NULL, 0, dest, NULL);
if (ret < 0) {
@@ -510,6 +515,30 @@ struct key *keyring_alloc(const char *description, kuid_t uid, kgid_t gid,
}
EXPORT_SYMBOL(keyring_alloc);
+/**
+ * keyring_restrict_trusted_only - Restrict additions to a keyring to trusted keys only
+ * @keyring: The keyring being added to.
+ * @type: The type of key being added.
+ * @flags: The key flags.
+ * @payload: The payload of the key intended to be added.
+ *
+ * Reject the addition of any links to a keyring that point to keys that aren't
+ * marked as being trusted. It can be overridden by passing
+ * KEY_ALLOC_BYPASS_RESTRICTION to key_instantiate_and_link() when adding a key
+ * to a keyring.
+ *
+ * This is meant to be passed as the restrict_link parameter to
+ * keyring_alloc().
+ */
+int keyring_restrict_trusted_only(struct key *keyring,
+ const struct key_type *type,
+ unsigned long flags,
+ const union key_payload *payload)
+{
+
+ return flags & KEY_FLAG_TRUSTED ? 0 : -EPERM;
+}
+
/*
* By default, we keys found by getting an exact match on their descriptions.
*/
@@ -1191,6 +1220,17 @@ void __key_link_end(struct key *keyring,
up_write(&keyring->sem);
}
+/*
+ * Check addition of keys to restricted keyrings.
+ */
+static int __key_link_check_restriction(struct key *keyring, struct key *key)
+{
+ if (!keyring->restrict_link)
+ return 0;
+ return keyring->restrict_link(keyring,
+ key->type, key->flags, &key->payload);
+}
+
/**
* key_link - Link a key to a keyring
* @keyring: The keyring to make the link in.
@@ -1221,14 +1261,12 @@ int key_link(struct key *keyring, struct key *key)
key_check(keyring);
key_check(key);
- if (test_bit(KEY_FLAG_TRUSTED_ONLY, &keyring->flags) &&
- !test_bit(KEY_FLAG_TRUSTED, &key->flags))
- return -EPERM;
-
ret = __key_link_begin(keyring, &key->index_key, &edit);
if (ret == 0) {
kdebug("begun {%d,%d}", keyring->serial, atomic_read(&keyring->usage));
- ret = __key_link_check_live_key(keyring, key);
+ ret = __key_link_check_restriction(keyring, key);
+ if (ret == 0)
+ ret = __key_link_check_live_key(keyring, key);
if (ret == 0)
__key_link(key, &edit);
__key_link_end(keyring, &key->index_key, edit);
diff --git a/security/keys/persistent.c b/security/keys/persistent.c
index c9fae5ea89fe..2ef45b319dd9 100644
--- a/security/keys/persistent.c
+++ b/security/keys/persistent.c
@@ -26,7 +26,7 @@ static int key_create_persistent_register(struct user_namespace *ns)
current_cred(),
((KEY_POS_ALL & ~KEY_POS_SETATTR) |
KEY_USR_VIEW | KEY_USR_READ),
- KEY_ALLOC_NOT_IN_QUOTA, NULL);
+ KEY_ALLOC_NOT_IN_QUOTA, NULL, NULL);
if (IS_ERR(reg))
return PTR_ERR(reg);
@@ -60,7 +60,7 @@ static key_ref_t key_create_persistent(struct user_namespace *ns, kuid_t uid,
uid, INVALID_GID, current_cred(),
((KEY_POS_ALL & ~KEY_POS_SETATTR) |
KEY_USR_VIEW | KEY_USR_READ),
- KEY_ALLOC_NOT_IN_QUOTA,
+ KEY_ALLOC_NOT_IN_QUOTA, NULL,
ns->persistent_keyring_register);
if (IS_ERR(persistent))
return ERR_CAST(persistent);
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c
index a3f85d2a00bb..9bb6bb5fd845 100644
--- a/security/keys/process_keys.c
+++ b/security/keys/process_keys.c
@@ -76,7 +76,8 @@ int install_user_keyrings(void)
if (IS_ERR(uid_keyring)) {
uid_keyring = keyring_alloc(buf, user->uid, INVALID_GID,
cred, user_keyring_perm,
- KEY_ALLOC_IN_QUOTA, NULL);
+ KEY_ALLOC_IN_QUOTA,
+ NULL, NULL);
if (IS_ERR(uid_keyring)) {
ret = PTR_ERR(uid_keyring);
goto error;
@@ -92,7 +93,8 @@ int install_user_keyrings(void)
session_keyring =
keyring_alloc(buf, user->uid, INVALID_GID,
cred, user_keyring_perm,
- KEY_ALLOC_IN_QUOTA, NULL);
+ KEY_ALLOC_IN_QUOTA,
+ NULL, NULL);
if (IS_ERR(session_keyring)) {
ret = PTR_ERR(session_keyring);
goto error_release;
@@ -134,7 +136,8 @@ int install_thread_keyring_to_cred(struct cred *new)
keyring = keyring_alloc("_tid", new->uid, new->gid, new,
KEY_POS_ALL | KEY_USR_VIEW,
- KEY_ALLOC_QUOTA_OVERRUN, NULL);
+ KEY_ALLOC_QUOTA_OVERRUN,
+ NULL, NULL);
if (IS_ERR(keyring))
return PTR_ERR(keyring);
@@ -180,7 +183,8 @@ int install_process_keyring_to_cred(struct cred *new)
keyring = keyring_alloc("_pid", new->uid, new->gid, new,
KEY_POS_ALL | KEY_USR_VIEW,
- KEY_ALLOC_QUOTA_OVERRUN, NULL);
+ KEY_ALLOC_QUOTA_OVERRUN,
+ NULL, NULL);
if (IS_ERR(keyring))
return PTR_ERR(keyring);
@@ -231,7 +235,7 @@ int install_session_keyring_to_cred(struct cred *cred, struct key *keyring)
keyring = keyring_alloc("_ses", cred->uid, cred->gid, cred,
KEY_POS_ALL | KEY_USR_VIEW | KEY_USR_READ,
- flags, NULL);
+ flags, NULL, NULL);
if (IS_ERR(keyring))
return PTR_ERR(keyring);
} else {
@@ -785,7 +789,7 @@ long join_session_keyring(const char *name)
keyring = keyring_alloc(
name, old->uid, old->gid, old,
KEY_POS_ALL | KEY_USR_VIEW | KEY_USR_READ | KEY_USR_LINK,
- KEY_ALLOC_IN_QUOTA, NULL);
+ KEY_ALLOC_IN_QUOTA, NULL, NULL);
if (IS_ERR(keyring)) {
ret = PTR_ERR(keyring);
goto error2;
diff --git a/security/keys/request_key.c b/security/keys/request_key.c
index c7a117c9a8f3..a29e3554751e 100644
--- a/security/keys/request_key.c
+++ b/security/keys/request_key.c
@@ -116,7 +116,7 @@ static int call_sbin_request_key(struct key_construction *cons,
cred = get_current_cred();
keyring = keyring_alloc(desc, cred->fsuid, cred->fsgid, cred,
KEY_POS_ALL | KEY_USR_VIEW | KEY_USR_READ,
- KEY_ALLOC_QUOTA_OVERRUN, NULL);
+ KEY_ALLOC_QUOTA_OVERRUN, NULL, NULL);
put_cred(cred);
if (IS_ERR(keyring)) {
ret = PTR_ERR(keyring);
@@ -355,7 +355,7 @@ static int construct_alloc_key(struct keyring_search_context *ctx,
key = key_alloc(ctx->index_key.type, ctx->index_key.description,
ctx->cred->fsuid, ctx->cred->fsgid, ctx->cred,
- perm, flags);
+ perm, flags, NULL);
if (IS_ERR(key))
goto alloc_failed;
diff --git a/security/keys/request_key_auth.c b/security/keys/request_key_auth.c
index 4f0f112fe276..9db8b4a82787 100644
--- a/security/keys/request_key_auth.c
+++ b/security/keys/request_key_auth.c
@@ -202,7 +202,7 @@ struct key *request_key_auth_new(struct key *target, const void *callout_info,
authkey = key_alloc(&key_type_request_key_auth, desc,
cred->fsuid, cred->fsgid, cred,
KEY_POS_VIEW | KEY_POS_READ | KEY_POS_SEARCH |
- KEY_USR_VIEW, KEY_ALLOC_NOT_IN_QUOTA);
+ KEY_USR_VIEW, KEY_ALLOC_NOT_IN_QUOTA, NULL);
if (IS_ERR(authkey)) {
ret = PTR_ERR(authkey);
goto error_alloc;
[toc] | [prev] | [next] | [standalone]
| From | David Howells <dhowells@redhat.com> |
|---|---|
| Date | 2016-01-08 19:40 +0100 |
| Subject | [RFC PATCH 02/15] X.509: Don't treat self-signed keys specially |
| Message-ID | <qOK7b-2eA-85@gated-at.bofh.it> |
| In reply to | #1304889 |
Trust for a self-signed certificate can normally only be determined by
whether we obtained it from a trusted location (ie. it was built into the
kernel at compile time), so there's not really any point in checking it -
we could verify that the signature is valid, but it doesn't really tell us
anything if the signature checks out.
However, there's a bug in the code determining whether a certificate is
self-signed or not - if they have neither AKID nor SKID then we just assume
that the cert is self-signed, which may not be true.
Given this, remove the code that treats self-signed certs specially when it
comes to evaluating trustability and attempt to evaluate them as ordinary
signed certificates. We then expect self-signed certificates to fail the
trustability check and be marked as untrustworthy in x509_key_preparse().
Note that there is the possibility of the trustability check on a
self-signed cert then succeeding. This is most likely to happen when a
duplicate of the certificate is already on the trust keyring - in which
case it shouldn't be a problem.
Signed-off-by: David Howells <dhowells@redhat.com>
cc: David Woodhouse <David.Woodhouse@intel.com>
cc: Mimi Zohar <zohar@linux.vnet.ibm.com>
---
crypto/asymmetric_keys/x509_public_key.c | 25 ++++++++++++++++---------
1 file changed, 16 insertions(+), 9 deletions(-)
diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c
index 2a44b3752471..25455567ac06 100644
--- a/crypto/asymmetric_keys/x509_public_key.c
+++ b/crypto/asymmetric_keys/x509_public_key.c
@@ -255,6 +255,9 @@ static int x509_validate_trust(struct x509_certificate *cert,
struct key *key;
int ret = 1;
+ if (!cert->akid_id && !cert->akid_skid)
+ return 1;
+
if (!trust_keyring)
return -EOPNOTSUPP;
@@ -312,17 +315,21 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
cert->pub->algo = pkey_algo[cert->pub->pkey_algo];
cert->pub->id_type = PKEY_ID_X509;
- /* Check the signature on the key if it appears to be self-signed */
- if ((!cert->akid_skid && !cert->akid_id) ||
- asymmetric_key_id_same(cert->skid, cert->akid_skid) ||
- asymmetric_key_id_same(cert->id, cert->akid_id)) {
- ret = x509_check_signature(cert->pub, cert); /* self-signed */
- if (ret < 0)
- goto error_free_cert;
- } else if (!prep->trusted) {
+ /* See if we can derive the trustability of this certificate.
+ *
+ * When it comes to self-signed certificates, we cannot evaluate
+ * trustedness except by the fact that we obtained it from a trusted
+ * location. So we just rely on x509_validate_trust() failing in this
+ * case.
+ *
+ * Note that there's a possibility of a self-signed cert matching a
+ * cert that we have (most likely a duplicate that we already trust) -
+ * in which case it will be marked trusted.
+ */
+ if (!prep->trusted) {
ret = x509_validate_trust(cert, get_system_trusted_keyring());
if (!ret)
- prep->trusted = 1;
+ prep->trusted = true;
}
/* Propose a description */
[toc] | [prev] | [next] | [standalone]
| From | David Howells <dhowells@redhat.com> |
|---|---|
| Date | 2016-01-08 19:40 +0100 |
| Subject | [RFC PATCH 07/15] KEYS: Allow authentication data to be stored in an asymmetric key |
| Message-ID | <qOK7b-2eA-95@gated-at.bofh.it> |
| In reply to | #1304889 |
Allow authentication data to be stored in an asymmetric key in the 4th
element of the key payload and provide a way for it to be destroyed.
For the public key subtype, this will be a public_key_signature struct.
Signed-off-by: David Howells <dhowells@redhat.com>
---
crypto/asymmetric_keys/asymmetric_type.c | 7 +++++--
crypto/asymmetric_keys/public_key.c | 22 +++++++++++++++++++---
crypto/asymmetric_keys/x509_cert_parser.c | 2 +-
include/crypto/public_key.h | 5 +++--
include/keys/asymmetric-subtype.h | 2 +-
include/keys/asymmetric-type.h | 7 ++++---
6 files changed, 33 insertions(+), 12 deletions(-)
diff --git a/crypto/asymmetric_keys/asymmetric_type.c b/crypto/asymmetric_keys/asymmetric_type.c
index 9f2165b27d52..a79d30128821 100644
--- a/crypto/asymmetric_keys/asymmetric_type.c
+++ b/crypto/asymmetric_keys/asymmetric_type.c
@@ -331,7 +331,8 @@ static void asymmetric_key_free_preparse(struct key_preparsed_payload *prep)
pr_devel("==>%s()\n", __func__);
if (subtype) {
- subtype->destroy(prep->payload.data[asym_crypto]);
+ subtype->destroy(prep->payload.data[asym_crypto],
+ prep->payload.data[asym_auth]);
module_put(subtype->owner);
}
asymmetric_key_free_kids(kids);
@@ -346,13 +347,15 @@ static void asymmetric_key_destroy(struct key *key)
struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key);
struct asymmetric_key_ids *kids = key->payload.data[asym_key_ids];
void *data = key->payload.data[asym_crypto];
+ void *auth = key->payload.data[asym_auth];
key->payload.data[asym_crypto] = NULL;
key->payload.data[asym_subtype] = NULL;
key->payload.data[asym_key_ids] = NULL;
+ key->payload.data[asym_auth] = NULL;
if (subtype) {
- subtype->destroy(data);
+ subtype->destroy(data, auth);
module_put(subtype->owner);
}
diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c
index 6db4c01c6503..e537aaeafdbf 100644
--- a/crypto/asymmetric_keys/public_key.c
+++ b/crypto/asymmetric_keys/public_key.c
@@ -59,18 +59,34 @@ static void public_key_describe(const struct key *asymmetric_key,
/*
* Destroy a public key algorithm key.
*/
-void public_key_destroy(void *payload)
+void public_key_free(struct public_key *key,
+ struct public_key_signature *sig)
{
- struct public_key *key = payload;
int i;
if (key) {
for (i = 0; i < ARRAY_SIZE(key->mpi); i++)
mpi_free(key->mpi[i]);
kfree(key);
+ key = NULL;
}
+
+ if (sig) {
+ for (i = 0; i < ARRAY_SIZE(sig->mpi); i++)
+ mpi_free(sig->mpi[i]);
+ kfree(sig->digest);
+ kfree(sig);
+ }
+}
+EXPORT_SYMBOL_GPL(public_key_free);
+
+/*
+ * Destroy a public key algorithm key.
+ */
+static void public_key_destroy(void *payload0, void *payload3)
+{
+ public_key_free(payload0, payload3);
}
-EXPORT_SYMBOL_GPL(public_key_destroy);
/*
* Verify a signature using a public key.
diff --git a/crypto/asymmetric_keys/x509_cert_parser.c b/crypto/asymmetric_keys/x509_cert_parser.c
index 021d39c0ba75..74152f1e99eb 100644
--- a/crypto/asymmetric_keys/x509_cert_parser.c
+++ b/crypto/asymmetric_keys/x509_cert_parser.c
@@ -48,7 +48,7 @@ struct x509_parse_context {
void x509_free_certificate(struct x509_certificate *cert)
{
if (cert) {
- public_key_destroy(cert->pub);
+ public_key_free(cert->pub, NULL);
kfree(cert->issuer);
kfree(cert->subject);
kfree(cert->id);
diff --git a/include/crypto/public_key.h b/include/crypto/public_key.h
index de50d026576d..a3f8f8268e23 100644
--- a/include/crypto/public_key.h
+++ b/include/crypto/public_key.h
@@ -72,8 +72,6 @@ struct public_key {
};
};
-extern void public_key_destroy(void *payload);
-
/*
* Public key cryptography signature data
*/
@@ -95,6 +93,9 @@ struct public_key_signature {
};
};
+extern void public_key_free(struct public_key *key,
+ struct public_key_signature *sig);
+
struct key;
extern int verify_signature(const struct key *key,
const struct public_key_signature *sig);
diff --git a/include/keys/asymmetric-subtype.h b/include/keys/asymmetric-subtype.h
index 4915d40d3c3c..2480469ce8fb 100644
--- a/include/keys/asymmetric-subtype.h
+++ b/include/keys/asymmetric-subtype.h
@@ -32,7 +32,7 @@ struct asymmetric_key_subtype {
void (*describe)(const struct key *key, struct seq_file *m);
/* Destroy a key of this subtype */
- void (*destroy)(void *payload);
+ void (*destroy)(void *payload_crypto, void *payload_auth);
/* Verify the signature on a key of this subtype (optional) */
int (*verify_signature)(const struct key *key,
diff --git a/include/keys/asymmetric-type.h b/include/keys/asymmetric-type.h
index 72c18c1f3308..d1e23dda4363 100644
--- a/include/keys/asymmetric-type.h
+++ b/include/keys/asymmetric-type.h
@@ -24,9 +24,10 @@ extern struct key_type key_type_asymmetric;
* follows:
*/
enum asymmetric_payload_bits {
- asym_crypto,
- asym_subtype,
- asym_key_ids,
+ asym_crypto, /* The data representing the key */
+ asym_subtype, /* Pointer to an asymmetric_key_subtype struct */
+ asym_key_ids, /* Pointer to an asymmetric_key_ids struct */
+ asym_auth /* The key's authorisation (signature, parent key ID) */
};
/*
[toc] | [prev] | [next] | [standalone]
| From | Mimi Zohar <zohar@linux.vnet.ibm.com> |
|---|---|
| Date | 2016-01-08 20:00 +0100 |
| Message-ID | <qOKqu-2lS-25@gated-at.bofh.it> |
| In reply to | #1304889 |
On Fri, 2016-01-08 at 18:33 +0000, David Howells wrote: > Here's a set of patches that changes how keys are determined to be trusted > - currently, that's a case of whether a key has KEY_FLAG_TRUSTED set upon > it. A keyring can then have a flag set (KEY_FLAG_TRUSTED ONLY) that > indicates that only keys with this flag set may be added to that keyring. > > Further, any time an X.509 certificate is instantiated without this flag > set, the certificate is judged against the contents of the system trusted > keyring to determine whether KEY_FLAG_TRUSTED should be set upon it. > > With these patches, KEY_FLAG_TRUSTED and KEY_FLAG_TRUSTED_ONLY are removed. > > The kernel may add implicitly trusted keys to a trusted-only keyring by > asserting KEY_ALLOC_BYPASS_RESTRICTION when the key is created, but > otherwise the key will only be allowed to be added to the keyring if it can > be verified. The system trusted keyring is not then special in this sense > and other trusted keyrings can be set up that are wholly independent of it. In order to have a certificate chain of trust on any of these trusted keyrings, the system keyring needs to be special. Even if we permit transitive trust, meaning keys on a keyring can be used to validate other keys being added to the same keyring, the first key added to a trusted keyring needs to be vetted against something. That something needs to be the builtin keys on the system keyring. Mimi > Each keyring can be given a vetting function that allows it to reject > attempts to add keys to that keyring based on the type and payload of the > new key. This can be set separately for each keyring. > > To make this work, we have to retain sufficient data from the X.509 > certificate that we can then verify the signature at need. > > The patches can be found here also: > > http://git.kernel.org/cgit/linux/kernel/git/dhowells/linux-fs.git/log/?h=keys-trust > > and are tagged with: > > keys-trust-20160108 > > David > --- > David Howells (15): > X.509: Partially revert patch to add validation against IMA MOK keyring > X.509: Don't treat self-signed keys specially > KEYS: Generalise system_verify_data() to provide access to internal content > PKCS#7: Make trust determination dependent on contents of trust keyring > KEYS: Add an alloc flag to convey the builtinness of a key > KEYS: Add a facility to restrict new links into a keyring > KEYS: Allow authentication data to be stored in an asymmetric key > KEYS: Add identifier pointers to public_key_signature struct > X.509: Retain the key verification data > X.509: Extract signature digest and make self-signed cert checks earlier > PKCS#7: Make the signature a pointer rather than embedding it > X.509: Move the trust validation code out to its own file > KEYS: Generalise x509_request_asymmetric_key() > KEYS: Move the point of trust determination to __key_link() > KEYS: Remove KEY_FLAG_TRUSTED > > > Documentation/security/keys.txt | 14 + > arch/x86/kernel/kexec-bzimage64.c | 18 -- > certs/system_keyring.c | 72 +++++-- > crypto/asymmetric_keys/Kconfig | 1 > crypto/asymmetric_keys/Makefile | 2 > crypto/asymmetric_keys/asymmetric_keys.h | 2 > crypto/asymmetric_keys/asymmetric_type.c | 7 - > crypto/asymmetric_keys/mscode_parser.c | 21 +- > crypto/asymmetric_keys/pkcs7_key_type.c | 64 +++--- > crypto/asymmetric_keys/pkcs7_parser.c | 59 +++--- > crypto/asymmetric_keys/pkcs7_parser.h | 11 - > crypto/asymmetric_keys/pkcs7_trust.c | 44 ++-- > crypto/asymmetric_keys/pkcs7_verify.c | 109 ++++------ > crypto/asymmetric_keys/public_key.c | 24 ++ > crypto/asymmetric_keys/public_key.h | 6 + > crypto/asymmetric_keys/public_key_trust.c | 206 ++++++++++++++++++++ > crypto/asymmetric_keys/verify_pefile.c | 40 +--- > crypto/asymmetric_keys/verify_pefile.h | 5 > crypto/asymmetric_keys/x509_cert_parser.c | 51 +++-- > crypto/asymmetric_keys/x509_parser.h | 12 - > crypto/asymmetric_keys/x509_public_key.c | 304 ++++++++--------------------- > fs/cifs/cifsacl.c | 2 > fs/nfs/nfs4idmap.c | 2 > include/crypto/pkcs7.h | 6 - > include/crypto/public_key.h | 35 +-- > include/keys/asymmetric-subtype.h | 2 > include/keys/asymmetric-type.h | 8 - > include/keys/system_keyring.h | 20 -- > include/linux/key.h | 40 +++- > include/linux/verification.h | 49 +++++ > include/linux/verify_pefile.h | 22 -- > kernel/module_signing.c | 7 - > net/dns_resolver/dns_key.c | 2 > net/rxrpc/ar-key.c | 4 > security/integrity/digsig.c | 34 +++ > security/integrity/digsig_asymmetric.c | 5 > security/integrity/ima/ima_mok.c | 9 - > security/keys/key.c | 43 +++- > security/keys/keyring.c | 26 ++ > security/keys/persistent.c | 4 > security/keys/process_keys.c | 16 +- > security/keys/request_key.c | 4 > security/keys/request_key_auth.c | 2 > 43 files changed, 804 insertions(+), 610 deletions(-) > create mode 100644 crypto/asymmetric_keys/public_key_trust.c > create mode 100644 include/linux/verification.h > delete mode 100644 include/linux/verify_pefile.h >
[toc] | [prev] | [next] | [standalone]
| From | Mimi Zohar <zohar@linux.vnet.ibm.com> |
|---|---|
| Date | 2016-01-08 20:30 +0100 |
| Message-ID | <qOKTw-2Pp-21@gated-at.bofh.it> |
| In reply to | #1304931 |
On Fri, 2016-01-08 at 13:54 -0500, Mimi Zohar wrote: > On Fri, 2016-01-08 at 18:33 +0000, David Howells wrote: > > Here's a set of patches that changes how keys are determined to be trusted > > - currently, that's a case of whether a key has KEY_FLAG_TRUSTED set upon > > it. A keyring can then have a flag set (KEY_FLAG_TRUSTED ONLY) that > > indicates that only keys with this flag set may be added to that keyring. > > > > Further, any time an X.509 certificate is instantiated without this flag > > set, the certificate is judged against the contents of the system trusted > > keyring to determine whether KEY_FLAG_TRUSTED should be set upon it. > > > > With these patches, KEY_FLAG_TRUSTED and KEY_FLAG_TRUSTED_ONLY are removed. > > > > The kernel may add implicitly trusted keys to a trusted-only keyring by > > asserting KEY_ALLOC_BYPASS_RESTRICTION when the key is created, but > > otherwise the key will only be allowed to be added to the keyring if it can > > be verified. The system trusted keyring is not then special in this sense > > and other trusted keyrings can be set up that are wholly independent of it. > > In order to have a certificate chain of trust on any of these trusted > keyrings, the system keyring needs to be special. Even if we permit > transitive trust, meaning keys on a keyring can be used to validate > other keys being added to the same keyring, the first key added to a > trusted keyring needs to be vetted against something. That something > needs to be the builtin keys on the system keyring. Back in November, Mehmet Kayaalp posted a patch for safely adding additional keys to the system keyring post build and a tool for re-signing the kernel. https://www.mail-archive.com/linux-security-module@vger.kernel.org/msg03679.html Mimi
[toc] | [prev] | [next] | [standalone]
| From | David Howells <dhowells@redhat.com> |
|---|---|
| Date | 2016-01-12 01:40 +0100 |
| Message-ID | <qPVa9-1En-7@gated-at.bofh.it> |
| In reply to | #1304947 |
Mimi Zohar <zohar@linux.vnet.ibm.com> wrote: > Back in November, Mehmet Kayaalp posted a patch for safely adding > additional keys to the system keyring post build and a tool for > re-signing the kernel. > > https://www.mail-archive.com/linux-security-module@vger.kernel.org/msg03679.html That's irrelevant to this particular discussion. And, yes, I should deal with his patch. David
[toc] | [prev] | [next] | [standalone]
| From | Mimi Zohar <zohar@linux.vnet.ibm.com> |
|---|---|
| Date | 2016-01-12 03:50 +0100 |
| Message-ID | <qPXbX-30c-3@gated-at.bofh.it> |
| In reply to | #1306860 |
On Tue, 2016-01-12 at 00:38 +0000, David Howells wrote: > Mimi Zohar <zohar@linux.vnet.ibm.com> wrote: > > > Back in November, Mehmet Kayaalp posted a patch for safely adding > > additional keys to the system keyring post build and a tool for > > re-signing the kernel. > > > > https://www.mail-archive.com/linux-security-module@vger.kernel.org/msg03679.html > > That's irrelevant to this particular discussion. Not really. The discussion centers around the system keyring and the origin of the keys on it. These patches safely allow additional keys to be added post-build to the system keyring. > And, yes, I should deal with > his patch. Thank you. Mimi
[toc] | [prev] | [next] | [standalone]
| From | David Howells <dhowells@redhat.com> |
|---|---|
| Date | 2016-01-12 01:40 +0100 |
| Message-ID | <qPVa9-1En-5@gated-at.bofh.it> |
| In reply to | #1304931 |
Mimi Zohar <zohar@linux.vnet.ibm.com> wrote: Mimi Zohar <zohar@linux.vnet.ibm.com> wrote: > > The kernel may add implicitly trusted keys to a trusted-only keyring by > > asserting KEY_ALLOC_BYPASS_RESTRICTION when the key is created, but > > otherwise the key will only be allowed to be added to the keyring if it can > > be verified. The system trusted keyring is not then special in this sense > > and other trusted keyrings can be set up that are wholly independent of > > it. > > In order to have a certificate chain of trust on any of these trusted > keyrings, the system keyring needs to be special. Even if we permit > transitive trust, meaning keys on a keyring can be used to validate > other keys being added to the same keyring, the first key added to a > trusted keyring needs to be vetted against something. That something > needs to be the builtin keys on the system keyring. Note that the KEY_ALLOC_BYPASS_RESTRICTION flag is there to permit built in keys to be added by the kernel in the first place. It would not be available to userspace to use. David
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web