Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1312146 > unrolled thread

[RFC PATCH 00/20] KEYS: Restrict additions to 'trusted' keyrings [ver #2]

Started byDavid Howells <dhowells@redhat.com>
First post2016-01-19 12:40 +0100
Last post2016-01-20 20:00 +0100
Articles 19 — 3 participants

Back to article view | Back to linux.kernel


Contents

  [RFC PATCH 00/20] KEYS: Restrict additions to 'trusted' keyrings  [ver #2] David Howells <dhowells@redhat.com> - 2016-01-19 12:40 +0100
    [RFC PATCH 10/20] X.509: Retain the key verification data [ver #2] David Howells <dhowells@redhat.com> - 2016-01-19 12:40 +0100
    [RFC PATCH 01/20] KEYS: Add an alloc flag to convey the builtinness  of a key [ver #2] David Howells <dhowells@redhat.com> - 2016-01-19 12:40 +0100
      Re: [RFC PATCH 01/20] KEYS: Add an alloc flag to convey the  builtinness of a key [ver #2] Mimi Zohar <zohar@linux.vnet.ibm.com> - 2016-01-20 20:00 +0100
    [RFC PATCH 06/20] PKCS#7: Make trust determination dependent on  contents of trust keyring [ver #2] David Howells <dhowells@redhat.com> - 2016-01-19 12:40 +0100
    [RFC PATCH 03/20] X.509: Allow X.509 certs to be blacklisted [ver  #2] David Howells <dhowells@redhat.com> - 2016-01-19 12:40 +0100
      Re: [RFC PATCH 03/20] X.509: Allow X.509 certs to be blacklisted  [ver #2] Mimi Zohar <zohar@linux.vnet.ibm.com> - 2016-01-20 21:40 +0100
    [RFC PATCH 14/20] KEYS: Generalise x509_request_asymmetric_key()  [ver #2] David Howells <dhowells@redhat.com> - 2016-01-19 12:40 +0100
    [RFC PATCH 08/20] KEYS: Allow authentication data to be stored in  an asymmetric key [ver #2] David Howells <dhowells@redhat.com> - 2016-01-19 12:40 +0100
    [RFC PATCH 15/20] KEYS: Move the point of trust determination to  __key_link() [ver #2] David Howells <dhowells@redhat.com> - 2016-01-19 12:40 +0100
    [RFC PATCH 13/20] X.509: Move the trust validation code out to its  own file [ver #2] David Howells <dhowells@redhat.com> - 2016-01-19 12:40 +0100
    [RFC PATCH 19/20] certs: Add a secondary system keyring that can be  added to dynamically [ver #2] David Howells <dhowells@redhat.com> - 2016-01-19 12:40 +0100
    [RFC PATCH 02/20] KEYS: Add a system blacklist keyring [ver #2] David Howells <dhowells@redhat.com> - 2016-01-19 12:40 +0100
      Re: [RFC PATCH 02/20] KEYS: Add a system blacklist keyring [ver #2] Mimi Zohar <zohar@linux.vnet.ibm.com> - 2016-01-20 20:40 +0100
      Re: [RFC PATCH 02/20] KEYS: Add a system blacklist keyring [ver #2] Mimi Zohar <zohar@linux.vnet.ibm.com> - 2016-01-20 21:30 +0100
    [RFC PATCH 11/20] X.509: Extract signature digest and make  self-signed cert checks earlier [ver #2] David Howells <dhowells@redhat.com> - 2016-01-19 12:40 +0100
    [RFC PATCH 09/20] KEYS: Add identifier pointers to  public_key_signature struct [ver #2] David Howells <dhowells@redhat.com> - 2016-01-19 12:40 +0100
    Re: [RFC PATCH 00/20] KEYS: Restrict additions to 'trusted' keyrings  [ver #2] Petko Manolov <petkan@mip-labs.com> - 2016-01-20 18:30 +0100
    Re: [RFC PATCH 00/20] KEYS: Restrict additions to 'trusted'  keyrings [ver #2] Mimi Zohar <zohar@linux.vnet.ibm.com> - 2016-01-20 20:00 +0100

#1312146 — [RFC PATCH 00/20] KEYS: Restrict additions to 'trusted' keyrings [ver #2]

FromDavid Howells <dhowells@redhat.com>
Date2016-01-19 12:40 +0100
Subject[RFC PATCH 00/20] KEYS: Restrict additions to 'trusted' keyrings [ver #2]
Message-ID<qSCNI-78i-3@gated-at.bofh.it>
Here's a set of patches that changes how certificates/keys are determined
to be trusted.  That's currently a two-step process:

 (1) Up until recently, when an X.509 certificate was parsed - no matter
     the source - it was judged against the keys in .system_keyring,
     assuming those keys to be trusted if they have KEY_FLAG_TRUSTED set
     upon them.

     This has just been changed such that any key in the .ima_mok keyring
     may also be used to judge the trustwortiness of a new certificate,
     whether or not the .ima_mok keyring is meant to be consulted for
     whatever process is being undertaken.

     If a certificate is determined to be trustworthy, KEY_FLAG_TRUSTED
     will be set upon a key it is loaded into (if it is loaded into one),
     no matter what the key is going to be loaded for.

 (2) If an X.509 certificate is loaded into a key, then that key - if
     KEY_FLAG_TRUSTED gets set upon it - can be linked into any keyring
     with KEY_FLAG_TRUSTED_ONLY set upon it.  This was meant to be the
     system keyring only, but has been extended to various IMA keyrings.

     A user can at will link any key marked KEY_FLAG_TRUSTED into any
     keyring marked KEY_FLAG_TRUSTED_ONLY if the relevant permissions masks
     permit it.

These patches change that:

 (1) Trust becomes a matter of consulting the ring of trusted keys supplied
     when the trust is evaluated only.

 (2) Asymmetric keys retain the source certificate signature information
     for future evaluation rather than discarding it.

 (3) Every keyring can be supplied with its own manager function to
     restrict what may be added to that keyring.  This is called whenever a
     key is to be linked into the keyring to guard against a key being
     created in one keyring and then linked across.

     This function is supplied with the keyring and the key type and
     payload[*] of the key being linked in for use in its evaluation.  It
     is permitted to use other data also, such as the contents of other
     keyrings such as the system keyrings.

     [*] The type and payload are supplied instead of a key because as an
     	 optimisation this function may be called whilst creating a key and
     	 so may reject the proposed key between preparse and allocation.

 (4) A default manager function is provided that permits keys to be
     restricted to only asymmetric keys that are vouched for by the
     contents of the system keyring.

 (5) A key allocation flag, KEY_ALLOC_BYPASS_RESTRICTION, is made available
     so that the kernel can initialise keyrings with keys that form the
     root of the trust relationship.

 (6) KEY_FLAG_TRUSTED and KEY_FLAG_TRUSTED_ONLY are removed, along with
     key_preparsed_payload::trusted.

This change also makes it possible for userspace to create a private set of
trusted keys and then to seal it by setting a manager function where the
private set is wholly independent of the kernel's trust relationships.

Further changes in the set involve extracting certain IMA special keyrings
and making them generally global:

 (*) .system_keyring is renamed to .builtin_trusted_keys and remains read
     only.  It carries only keys built in to the kernel.  It may be where
     UEFI keys should be loaded - though that could better be the new
     secondary keyring (see below).

 (*) An optional system blacklist keyring is created to replace the IMA
     keyring.

     (*) A 'blacklist' key type is created that may contain a hex string in
         its description (it carries no payload).  When an X.509
         certificate is parsed, the system blacklist is searched for a
         blacklist key that matches the TBS hash of the X.509 certificate
         and if one is found, the certificate is considered blacklisted.

     (*) A list of blacklisted hashes can be added to the system blacklist
         keyring at compile time.  In the future it should also be possible
         to load this up from such as the UEFI blacklist.

     (*) Keys can be added to the blacklist keyring by root if the keys are
     	 signed by a key in the builtin system keyring.  These can then be
     	 searched for by asymmetric key ID.  This allows the functionality
     	 of the IMA blacklist keyring to be replicated.

 	 It might be worth making an asymmetric key subtype that carries no
 	 data to be used here as the cryptographic material is then just
 	 dead weight since the IDs are what matter.

 (*) An optional secondary system keyring (called .secondary_trusted_keys)
     is added to replace the IMA MOK keyring.

     (*) Keys can be added to the secondary keyring by root if the keys can
     	 be vouched for by either ring of system keys.

 (*) Module signing and kexec only use .builtin_trusted_keys and do not use
     the new secondary keyring, but they do consult the system blacklist.

 (*) If the kernel sees a PKCS#7 message with more than one signature, at
     least one of which is blacklisted, it will permit the message if at
     least one of the non-blacklisted signature chains is vouched for.  If
     none are, then EKEYREJECTED will be given.  This error takes priority
     over giving ENOPKG for unsupported encryption.

The patches can be found here also:

	http://git.kernel.org/cgit/linux/kernel/git/dhowells/linux-fs.git/log/?h=keys-trust

David
---
David Howells (20):
      KEYS: Add an alloc flag to convey the builtinness of a key
      KEYS: Add a system blacklist keyring
      X.509: Allow X.509 certs to be blacklisted
      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 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 and KEY_ALLOC_TRUSTED
      PKCS#7: Handle blacklisted certificates
      IMA: Use the system blacklist keyring
      certs: Add a secondary system keyring that can be added to dynamically
      IMA: Replace the .ima_mok keyring with the secondary system keyring


 Documentation/security/keys.txt           |   14 +
 arch/x86/kernel/kexec-bzimage64.c         |   18 --
 certs/Kconfig                             |   26 ++
 certs/Makefile                            |    6 +
 certs/blacklist.c                         |  184 +++++++++++++++++
 certs/blacklist.h                         |    3 
 certs/blacklist_hashes.c                  |    6 +
 certs/blacklist_nohashes.c                |    5 
 certs/system_keyring.c                    |  141 ++++++++++---
 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   |   66 +++---
 crypto/asymmetric_keys/pkcs7_parser.c     |   59 +++--
 crypto/asymmetric_keys/pkcs7_parser.h     |   12 -
 crypto/asymmetric_keys/pkcs7_trust.c      |   44 ++--
 crypto/asymmetric_keys/pkcs7_verify.c     |  141 ++++++-------
 crypto/asymmetric_keys/public_key.c       |   24 ++
 crypto/asymmetric_keys/public_key.h       |    6 +
 crypto/asymmetric_keys/public_key_trust.c |  209 +++++++++++++++++++
 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      |   13 +
 crypto/asymmetric_keys/x509_public_key.c  |  318 +++++++++--------------------
 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             |   52 ++---
 include/linux/key-type.h                  |    1 
 include/linux/key.h                       |   39 +++-
 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               |   10 +
 security/integrity/digsig_asymmetric.c    |   18 +-
 security/integrity/ima/Kconfig            |   18 --
 security/integrity/ima/Makefile           |    1 
 security/integrity/ima/ima_mok.c          |   55 -----
 security/keys/key.c                       |   44 +++-
 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 
 52 files changed, 1131 insertions(+), 722 deletions(-)
 create mode 100644 certs/blacklist.c
 create mode 100644 certs/blacklist.h
 create mode 100644 certs/blacklist_hashes.c
 create mode 100644 certs/blacklist_nohashes.c
 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
 delete mode 100644 security/integrity/ima/ima_mok.c

[toc] | [next] | [standalone]


#1312147 — [RFC PATCH 10/20] X.509: Retain the key verification data [ver #2]

FromDavid Howells <dhowells@redhat.com>
Date2016-01-19 12:40 +0100
Subject[RFC PATCH 10/20] X.509: Retain the key verification data [ver #2]
Message-ID<qSCNJ-78i-27@gated-at.bofh.it>
In reply to#1312146
Retain the key verification data (ie. the struct public_key_signature)
including the digest and the key identifiers.

Note that this means that we need to take a separate copy of the digest in
x509_get_sig_params() rather than lumping it in with the crypto layer data.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 crypto/asymmetric_keys/pkcs7_trust.c      |    8 ++--
 crypto/asymmetric_keys/pkcs7_verify.c     |   20 +++++----
 crypto/asymmetric_keys/x509_cert_parser.c |   41 +++++++++---------
 crypto/asymmetric_keys/x509_parser.h      |    4 --
 crypto/asymmetric_keys/x509_public_key.c  |   66 +++++++++++++++--------------
 5 files changed, 70 insertions(+), 69 deletions(-)

diff --git a/crypto/asymmetric_keys/pkcs7_trust.c b/crypto/asymmetric_keys/pkcs7_trust.c
index 388007fed3b2..7bb9389fd644 100644
--- a/crypto/asymmetric_keys/pkcs7_trust.c
+++ b/crypto/asymmetric_keys/pkcs7_trust.c
@@ -77,16 +77,16 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
 
 		might_sleep();
 		last = x509;
-		sig = &last->sig;
+		sig = last->sig;
 	}
 
 	/* No match - see if the root certificate has a signer amongst the
 	 * trusted keys.
 	 */
-	if (last && (last->akid_id || last->akid_skid)) {
+	if (last && (last->sig->auth_ids[0] || last->sig->auth_ids[1])) {
 		key = x509_request_asymmetric_key(trust_keyring,
-						  last->akid_id,
-						  last->akid_skid,
+						  last->sig->auth_ids[0],
+						  last->sig->auth_ids[1],
 						  false);
 		if (!IS_ERR(key)) {
 			x509 = last;
diff --git a/crypto/asymmetric_keys/pkcs7_verify.c b/crypto/asymmetric_keys/pkcs7_verify.c
index 325575caf6b4..8af45c5d4b6d 100644
--- a/crypto/asymmetric_keys/pkcs7_verify.c
+++ b/crypto/asymmetric_keys/pkcs7_verify.c
@@ -176,6 +176,7 @@ static int pkcs7_find_key(struct pkcs7_message *pkcs7,
 static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
 				  struct pkcs7_signed_info *sinfo)
 {
+	struct public_key_signature *sig;
 	struct x509_certificate *x509 = sinfo->signer, *p;
 	struct asymmetric_key_id *auth;
 	int ret;
@@ -195,14 +196,15 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
 			goto maybe_missing_crypto_in_x509;
 
 		pr_debug("- issuer %s\n", x509->issuer);
-		if (x509->akid_id)
+		sig = x509->sig;
+		if (sig->auth_ids[0])
 			pr_debug("- authkeyid.id %*phN\n",
-				 x509->akid_id->len, x509->akid_id->data);
-		if (x509->akid_skid)
+				 sig->auth_ids[0]->len, sig->auth_ids[0]->data);
+		if (sig->auth_ids[1])
 			pr_debug("- authkeyid.skid %*phN\n",
-				 x509->akid_skid->len, x509->akid_skid->data);
+				 sig->auth_ids[1]->len, sig->auth_ids[1]->data);
 
-		if ((!x509->akid_id && !x509->akid_skid) ||
+		if ((!x509->sig->auth_ids[0] && !x509->sig->auth_ids[1]) ||
 		    strcmp(x509->subject, x509->issuer) == 0) {
 			/* If there's no authority certificate specified, then
 			 * the certificate must be self-signed and is the root
@@ -226,7 +228,7 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
 		/* Look through the X.509 certificates in the PKCS#7 message's
 		 * list to see if the next one is there.
 		 */
-		auth = x509->akid_id;
+		auth = sig->auth_ids[0];
 		if (auth) {
 			pr_debug("- want %*phN\n", auth->len, auth->data);
 			for (p = pkcs7->certs; p; p = p->next) {
@@ -236,7 +238,7 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
 					goto found_issuer_check_skid;
 			}
 		} else {
-			auth = x509->akid_skid;
+			auth = sig->auth_ids[1];
 			pr_debug("- want %*phN\n", auth->len, auth->data);
 			for (p = pkcs7->certs; p; p = p->next) {
 				if (!p->skid)
@@ -256,8 +258,8 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
 		/* We matched issuer + serialNumber, but if there's an
 		 * authKeyId.keyId, that must match the CA subjKeyId also.
 		 */
-		if (x509->akid_skid &&
-		    !asymmetric_key_id_same(p->skid, x509->akid_skid)) {
+		if (sig->auth_ids[1] &&
+		    !asymmetric_key_id_same(p->skid, sig->auth_ids[1])) {
 			pr_warn("Sig %u: X.509 chain contains auth-skid nonmatch (%u->%u)\n",
 				sinfo->index, x509->index, p->index);
 			return -EKEYREJECTED;
diff --git a/crypto/asymmetric_keys/x509_cert_parser.c b/crypto/asymmetric_keys/x509_cert_parser.c
index 74152f1e99eb..c32912c1d84d 100644
--- a/crypto/asymmetric_keys/x509_cert_parser.c
+++ b/crypto/asymmetric_keys/x509_cert_parser.c
@@ -48,15 +48,11 @@ struct x509_parse_context {
 void x509_free_certificate(struct x509_certificate *cert)
 {
 	if (cert) {
-		public_key_free(cert->pub, NULL);
+		public_key_free(cert->pub, cert->sig);
 		kfree(cert->issuer);
 		kfree(cert->subject);
 		kfree(cert->id);
 		kfree(cert->skid);
-		kfree(cert->akid_id);
-		kfree(cert->akid_skid);
-		kfree(cert->sig.digest);
-		mpi_free(cert->sig.rsa.s);
 		kfree(cert);
 	}
 }
@@ -79,6 +75,9 @@ struct x509_certificate *x509_cert_parse(const void *data, size_t datalen)
 	cert->pub = kzalloc(sizeof(struct public_key), GFP_KERNEL);
 	if (!cert->pub)
 		goto error_no_ctx;
+	cert->sig = kzalloc(sizeof(struct public_key_signature), GFP_KERNEL);
+	if (!cert->sig)
+		goto error_no_ctx;
 	ctx = kzalloc(sizeof(struct x509_parse_context), GFP_KERNEL);
 	if (!ctx)
 		goto error_no_ctx;
@@ -188,33 +187,33 @@ int x509_note_pkey_algo(void *context, size_t hdrlen,
 		return -ENOPKG; /* Unsupported combination */
 
 	case OID_md4WithRSAEncryption:
-		ctx->cert->sig.pkey_hash_algo = HASH_ALGO_MD5;
-		ctx->cert->sig.pkey_algo = PKEY_ALGO_RSA;
+		ctx->cert->sig->pkey_hash_algo = HASH_ALGO_MD5;
+		ctx->cert->sig->pkey_algo = PKEY_ALGO_RSA;
 		break;
 
 	case OID_sha1WithRSAEncryption:
-		ctx->cert->sig.pkey_hash_algo = HASH_ALGO_SHA1;
-		ctx->cert->sig.pkey_algo = PKEY_ALGO_RSA;
+		ctx->cert->sig->pkey_hash_algo = HASH_ALGO_SHA1;
+		ctx->cert->sig->pkey_algo = PKEY_ALGO_RSA;
 		break;
 
 	case OID_sha256WithRSAEncryption:
-		ctx->cert->sig.pkey_hash_algo = HASH_ALGO_SHA256;
-		ctx->cert->sig.pkey_algo = PKEY_ALGO_RSA;
+		ctx->cert->sig->pkey_hash_algo = HASH_ALGO_SHA256;
+		ctx->cert->sig->pkey_algo = PKEY_ALGO_RSA;
 		break;
 
 	case OID_sha384WithRSAEncryption:
-		ctx->cert->sig.pkey_hash_algo = HASH_ALGO_SHA384;
-		ctx->cert->sig.pkey_algo = PKEY_ALGO_RSA;
+		ctx->cert->sig->pkey_hash_algo = HASH_ALGO_SHA384;
+		ctx->cert->sig->pkey_algo = PKEY_ALGO_RSA;
 		break;
 
 	case OID_sha512WithRSAEncryption:
-		ctx->cert->sig.pkey_hash_algo = HASH_ALGO_SHA512;
-		ctx->cert->sig.pkey_algo = PKEY_ALGO_RSA;
+		ctx->cert->sig->pkey_hash_algo = HASH_ALGO_SHA512;
+		ctx->cert->sig->pkey_algo = PKEY_ALGO_RSA;
 		break;
 
 	case OID_sha224WithRSAEncryption:
-		ctx->cert->sig.pkey_hash_algo = HASH_ALGO_SHA224;
-		ctx->cert->sig.pkey_algo = PKEY_ALGO_RSA;
+		ctx->cert->sig->pkey_hash_algo = HASH_ALGO_SHA224;
+		ctx->cert->sig->pkey_algo = PKEY_ALGO_RSA;
 		break;
 	}
 
@@ -595,14 +594,14 @@ int x509_akid_note_kid(void *context, size_t hdrlen,
 
 	pr_debug("AKID: keyid: %*phN\n", (int)vlen, value);
 
-	if (ctx->cert->akid_skid)
+	if (ctx->cert->sig->auth_ids[1])
 		return 0;
 
 	kid = asymmetric_key_generate_id(value, vlen, "", 0);
 	if (IS_ERR(kid))
 		return PTR_ERR(kid);
 	pr_debug("authkeyid %*phN\n", kid->len, kid->data);
-	ctx->cert->akid_skid = kid;
+	ctx->cert->sig->auth_ids[1] = kid;
 	return 0;
 }
 
@@ -634,7 +633,7 @@ int x509_akid_note_serial(void *context, size_t hdrlen,
 
 	pr_debug("AKID: serial: %*phN\n", (int)vlen, value);
 
-	if (!ctx->akid_raw_issuer || ctx->cert->akid_id)
+	if (!ctx->akid_raw_issuer || ctx->cert->sig->auth_ids[0])
 		return 0;
 
 	kid = asymmetric_key_generate_id(value,
@@ -645,6 +644,6 @@ int x509_akid_note_serial(void *context, size_t hdrlen,
 		return PTR_ERR(kid);
 
 	pr_debug("authkeyid %*phN\n", kid->len, kid->data);
-	ctx->cert->akid_id = kid;
+	ctx->cert->sig->auth_ids[0] = kid;
 	return 0;
 }
diff --git a/crypto/asymmetric_keys/x509_parser.h b/crypto/asymmetric_keys/x509_parser.h
index b9108c170ceb..600df3bebed4 100644
--- a/crypto/asymmetric_keys/x509_parser.h
+++ b/crypto/asymmetric_keys/x509_parser.h
@@ -17,13 +17,11 @@ struct x509_certificate {
 	struct x509_certificate *next;
 	struct x509_certificate *signer;	/* Certificate that signed this one */
 	struct public_key *pub;			/* Public key details */
-	struct public_key_signature sig;	/* Signature parameters */
+	struct public_key_signature *sig;	/* Signature parameters */
 	char		*issuer;		/* Name of certificate issuer */
 	char		*subject;		/* Name of certificate subject */
 	struct asymmetric_key_id *id;		/* Issuer + Serial number */
 	struct asymmetric_key_id *skid;		/* Subject + subjectKeyId (optional) */
-	struct asymmetric_key_id *akid_id;	/* CA AuthKeyId matching ->id (optional) */
-	struct asymmetric_key_id *akid_skid;	/* CA AuthKeyId matching ->skid (optional) */
 	time64_t	valid_from;
 	time64_t	valid_to;
 	const void	*tbs;			/* Signed data */
diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c
index 630c1c331fe1..8626e84450e4 100644
--- a/crypto/asymmetric_keys/x509_public_key.c
+++ b/crypto/asymmetric_keys/x509_public_key.c
@@ -157,28 +157,28 @@ EXPORT_SYMBOL_GPL(x509_request_asymmetric_key);
  */
 int x509_get_sig_params(struct x509_certificate *cert)
 {
+	struct public_key_signature *sig = cert->sig;
 	struct crypto_shash *tfm;
 	struct shash_desc *desc;
-	size_t digest_size, desc_size;
-	void *digest;
+	size_t desc_size;
 	int ret;
 
 	pr_devel("==>%s()\n", __func__);
 
 	if (cert->unsupported_crypto)
 		return -ENOPKG;
-	if (cert->sig.rsa.s)
+	if (sig->rsa.s)
 		return 0;
 
-	cert->sig.rsa.s = mpi_read_raw_data(cert->raw_sig, cert->raw_sig_size);
-	if (!cert->sig.rsa.s)
+	sig->rsa.s = mpi_read_raw_data(cert->raw_sig, cert->raw_sig_size);
+	if (!sig->rsa.s)
 		return -ENOMEM;
-	cert->sig.nr_mpi = 1;
+	sig->nr_mpi = 1;
 
 	/* 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[cert->sig.pkey_hash_algo], 0, 0);
+	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;
@@ -188,39 +188,38 @@ int x509_get_sig_params(struct x509_certificate *cert)
 	}
 
 	desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
-	digest_size = crypto_shash_digestsize(tfm);
+	sig->digest_size = crypto_shash_digestsize(tfm);
 
-	/* We allocate the hash operational data storage on the end of the
-	 * digest storage space.
-	 */
 	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;
 
-	cert->sig.digest = digest;
-	cert->sig.digest_size = digest_size;
+	desc = kzalloc(desc_size, GFP_KERNEL);
+	if (!desc)
+		goto error;
 
-	desc = PTR_ALIGN(digest + digest_size, __alignof__(*desc));
 	desc->tfm = tfm;
 	desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
 
 	ret = crypto_shash_init(desc);
 	if (ret < 0)
-		goto error;
+		goto error_2;
 	might_sleep();
-	ret = crypto_shash_finup(desc, cert->tbs, cert->tbs_size, digest);
+	ret = crypto_shash_finup(desc, cert->tbs, cert->tbs_size, sig->digest);
 	if (ret < 0)
-		goto error;
+		goto error_2;
 
-	ret = is_bin_hash_blacklisted(digest, digest_size);
+	ret = is_bin_hash_blacklisted(sig->digest, sig->digest_size);
 	if (ret == -EKEYREJECTED) {
-		pr_err("Cert %*phN is blacklisted\n", (int)digest_size, digest);
+		pr_err("Cert %*phN is blacklisted\n",
+		       sig->digest_size, sig->digest);
 		cert->blacklisted = true;
 		ret = 0;
 	}
 
+error_2:
+	kfree(desc);
 error:
 	crypto_free_shash(tfm);
 	pr_devel("<==%s() = %d\n", __func__, ret);
@@ -242,7 +241,7 @@ int x509_check_signature(const struct public_key *pub,
 	if (ret < 0)
 		return ret;
 
-	ret = public_key_verify_signature(pub, &cert->sig);
+	ret = public_key_verify_signature(pub, cert->sig);
 	if (ret == -ENOPKG)
 		cert->unsupported_crypto = true;
 	pr_debug("Cert Verification: %d\n", ret);
@@ -262,20 +261,21 @@ EXPORT_SYMBOL_GPL(x509_check_signature);
 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 (!cert->akid_id && !cert->akid_skid)
+	if (!sig->auth_ids[0] && !sig->auth_ids[1])
 		return 1;
 
 	if (!trust_keyring)
 		return -EOPNOTSUPP;
 
-	if (ca_keyid && !asymmetric_key_id_partial(cert->akid_skid, ca_keyid))
+	if (ca_keyid && !asymmetric_key_id_partial(sig->auth_ids[1], ca_keyid))
 		return -EPERM;
 
 	key = x509_request_asymmetric_key(trust_keyring,
-					  cert->akid_id, cert->akid_skid,
+					  sig->auth_ids[0], sig->auth_ids[1],
 					  false);
 	if (!IS_ERR(key))  {
 		if (!use_builtin_keys
@@ -307,11 +307,11 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
 	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 ||
+	    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]) {
+	    !pkey_algo[cert->sig->pkey_algo] ||
+	    !hash_algo_name[cert->sig->pkey_hash_algo]) {
 		ret = -ENOPKG;
 		goto error_free_cert;
 	}
@@ -319,8 +319,8 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
 	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]);
+		 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;
@@ -381,6 +381,7 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
 	prep->payload.data[asym_subtype] = &public_key_subtype;
 	prep->payload.data[asym_key_ids] = kids;
 	prep->payload.data[asym_crypto] = cert->pub;
+	prep->payload.data[asym_auth] = cert->sig;
 	prep->description = desc;
 	prep->quotalen = 100;
 
@@ -388,6 +389,7 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
 	cert->pub = NULL;
 	cert->id = NULL;
 	cert->skid = NULL;
+	cert->sig = NULL;
 	desc = NULL;
 	ret = 0;
 

[toc] | [prev] | [next] | [standalone]


#1312148 — [RFC PATCH 01/20] KEYS: Add an alloc flag to convey the builtinness of a key [ver #2]

FromDavid Howells <dhowells@redhat.com>
Date2016-01-19 12:40 +0100
Subject[RFC PATCH 01/20] KEYS: Add an alloc flag to convey the builtinness of a key [ver #2]
Message-ID<qSCNI-78i-23@gated-at.bofh.it>
In reply to#1312146
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 2570598b784d..f4180326c2e1 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 07a87311055c..48dbfa543bcb 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]


#1313446 — Re: [RFC PATCH 01/20] KEYS: Add an alloc flag to convey the builtinness of a key [ver #2]

FromMimi Zohar <zohar@linux.vnet.ibm.com>
Date2016-01-20 20:00 +0100
SubjectRe: [RFC PATCH 01/20] KEYS: Add an alloc flag to convey the builtinness of a key [ver #2]
Message-ID<qT693-27H-13@gated-at.bofh.it>
In reply to#1312148
On Tue, 2016-01-19 at 11:30 +0000, David Howells wrote:
> 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>

Acked-by: Mimi Zohar <zohar@linux.vnet.ibm.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 2570598b784d..f4180326c2e1 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 07a87311055c..48dbfa543bcb 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]


#1312152 — [RFC PATCH 06/20] PKCS#7: Make trust determination dependent on contents of trust keyring [ver #2]

FromDavid Howells <dhowells@redhat.com>
Date2016-01-19 12:40 +0100
Subject[RFC PATCH 06/20] PKCS#7: Make trust determination dependent on contents of trust keyring [ver #2]
Message-ID<qSCNJ-78i-41@gated-at.bofh.it>
In reply to#1312146
Make the determination of the trustworthiness of a key dependent on whether
a key that can verify it is present in the ring of trusted keys rather than
whether or not the verifying key has KEY_FLAG_TRUSTED set.

verify_pkcs7_signature() will return -ENOKEY if the PKCS#7 message trust
chain cannot be verified.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 certs/system_keyring.c                  |   13 ++++---------
 crypto/asymmetric_keys/pkcs7_key_type.c |    2 +-
 crypto/asymmetric_keys/pkcs7_parser.h   |    1 -
 crypto/asymmetric_keys/pkcs7_trust.c    |   16 +++-------------
 crypto/asymmetric_keys/verify_pefile.c  |    2 +-
 crypto/asymmetric_keys/x509_parser.h    |    1 -
 include/crypto/pkcs7.h                  |    3 +--
 include/linux/verification.h            |    1 -
 kernel/module_signing.c                 |    2 +-
 9 files changed, 11 insertions(+), 30 deletions(-)

diff --git a/certs/system_keyring.c b/certs/system_keyring.c
index a83bffedc0aa..dc18869ff680 100644
--- a/certs/system_keyring.c
+++ b/certs/system_keyring.c
@@ -121,7 +121,6 @@ late_initcall(load_system_certificate_list);
 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,
@@ -129,7 +128,6 @@ int verify_pkcs7_signature(const void *data, size_t len,
 			   void *ctx)
 {
 	struct pkcs7_message *pkcs7;
-	bool trusted;
 	int ret;
 
 	pkcs7 = pkcs7_parse_message(raw_pkcs7, pkcs7_len);
@@ -149,13 +147,10 @@ int verify_pkcs7_signature(const void *data, size_t len,
 
 	if (!trusted_keys)
 		trusted_keys = system_trusted_keyring;
-	ret = pkcs7_validate_trust(pkcs7, trusted_keys, &trusted);
-	if (ret < 0)
-		goto error;
-
-	if (!trusted && untrusted_error) {
-		pr_err("PKCS#7 signature not signed with a trusted key\n");
-		ret = untrusted_error;
+	ret = pkcs7_validate_trust(pkcs7, trusted_keys);
+	if (ret < 0) {
+		if (ret == -ENOKEY)
+			pr_err("PKCS#7 signature not signed with a trusted key\n");
 		goto error;
 	}
 
diff --git a/crypto/asymmetric_keys/pkcs7_key_type.c b/crypto/asymmetric_keys/pkcs7_key_type.c
index b74aaaefbc07..a684e7ca4f13 100644
--- a/crypto/asymmetric_keys/pkcs7_key_type.c
+++ b/crypto/asymmetric_keys/pkcs7_key_type.c
@@ -71,7 +71,7 @@ static int pkcs7_preparse(struct key_preparsed_payload *prep)
 
 	ret = verify_pkcs7_signature(NULL, 0,
 				     prep->data, prep->datalen,
-				     NULL, -ENOKEY, usage,
+				     NULL, usage,
 				     pkcs7_view_content, prep);
 
 	kleave(" = %d", ret);
diff --git a/crypto/asymmetric_keys/pkcs7_parser.h b/crypto/asymmetric_keys/pkcs7_parser.h
index a66b19ebcf47..c8159983ed8f 100644
--- a/crypto/asymmetric_keys/pkcs7_parser.h
+++ b/crypto/asymmetric_keys/pkcs7_parser.h
@@ -22,7 +22,6 @@ struct pkcs7_signed_info {
 	struct pkcs7_signed_info *next;
 	struct x509_certificate *signer; /* Signing certificate (in msg->certs) */
 	unsigned	index;
-	bool		trusted;
 	bool		unsupported_crypto;	/* T if not usable due to missing crypto */
 
 	/* Message digest - the digest of the Content Data (or NULL) */
diff --git a/crypto/asymmetric_keys/pkcs7_trust.c b/crypto/asymmetric_keys/pkcs7_trust.c
index 90d6d47965b0..388007fed3b2 100644
--- a/crypto/asymmetric_keys/pkcs7_trust.c
+++ b/crypto/asymmetric_keys/pkcs7_trust.c
@@ -30,7 +30,6 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
 	struct public_key_signature *sig = &sinfo->sig;
 	struct x509_certificate *x509, *last = NULL, *p;
 	struct key *key;
-	bool trusted;
 	int ret;
 
 	kenter(",%u,", sinfo->index);
@@ -42,10 +41,8 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
 
 	for (x509 = sinfo->signer; x509; x509 = x509->signer) {
 		if (x509->seen) {
-			if (x509->verified) {
-				trusted = x509->trusted;
+			if (x509->verified)
 				goto verified;
-			}
 			kleave(" = -ENOKEY [cached]");
 			return -ENOKEY;
 		}
@@ -122,7 +119,6 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
 
 matched:
 	ret = verify_signature(key, sig);
-	trusted = test_bit(KEY_FLAG_TRUSTED, &key->flags);
 	key_put(key);
 	if (ret < 0) {
 		if (ret == -ENOMEM)
@@ -134,12 +130,9 @@ matched:
 verified:
 	if (x509) {
 		x509->verified = true;
-		for (p = sinfo->signer; p != x509; p = p->signer) {
+		for (p = sinfo->signer; p != x509; p = p->signer)
 			p->verified = true;
-			p->trusted = trusted;
-		}
 	}
-	sinfo->trusted = trusted;
 	kleave(" = 0");
 	return 0;
 }
@@ -148,7 +141,6 @@ verified:
  * pkcs7_validate_trust - Validate PKCS#7 trust chain
  * @pkcs7: The PKCS#7 certificate to validate
  * @trust_keyring: Signing certificates to use as starting points
- * @_trusted: Set to true if trustworth, false otherwise
  *
  * Validate that the certificate chain inside the PKCS#7 message intersects
  * keys we already know and trust.
@@ -170,8 +162,7 @@ verified:
  * May also return -ENOMEM.
  */
 int pkcs7_validate_trust(struct pkcs7_message *pkcs7,
-			 struct key *trust_keyring,
-			 bool *_trusted)
+			 struct key *trust_keyring)
 {
 	struct pkcs7_signed_info *sinfo;
 	struct x509_certificate *p;
@@ -191,7 +182,6 @@ int pkcs7_validate_trust(struct pkcs7_message *pkcs7,
 				cached_ret = -ENOPKG;
 			continue;
 		case 0:
-			*_trusted |= sinfo->trusted;
 			cached_ret = 0;
 			continue;
 		default:
diff --git a/crypto/asymmetric_keys/verify_pefile.c b/crypto/asymmetric_keys/verify_pefile.c
index 443a00f9cd7a..4112f922cc66 100644
--- a/crypto/asymmetric_keys/verify_pefile.c
+++ b/crypto/asymmetric_keys/verify_pefile.c
@@ -436,7 +436,7 @@ int verify_pefile_signature(const void *pebuf, unsigned pelen,
 
 	ret = verify_pkcs7_signature(NULL, 0,
 				     pebuf + ctx.sig_offset, ctx.sig_len,
-				     trusted_keys, -EKEYREJECTED, usage,
+				     trusted_keys, usage,
 				     mscode_parse, &ctx);
 	if (ret < 0)
 		goto error;
diff --git a/crypto/asymmetric_keys/x509_parser.h b/crypto/asymmetric_keys/x509_parser.h
index be7cf2eae3bd..b9108c170ceb 100644
--- a/crypto/asymmetric_keys/x509_parser.h
+++ b/crypto/asymmetric_keys/x509_parser.h
@@ -41,7 +41,6 @@ struct x509_certificate {
 	unsigned	index;
 	bool		seen;			/* Infinite recursion prevention */
 	bool		verified;
-	bool		trusted;
 	bool		unsupported_crypto;	/* T if can't be verified due to missing crypto */
 	bool		blacklisted;
 };
diff --git a/include/crypto/pkcs7.h b/include/crypto/pkcs7.h
index 8323e3e57131..583f199400a3 100644
--- a/include/crypto/pkcs7.h
+++ b/include/crypto/pkcs7.h
@@ -33,8 +33,7 @@ extern int pkcs7_get_content_data(const struct pkcs7_message *pkcs7,
  * pkcs7_trust.c
  */
 extern int pkcs7_validate_trust(struct pkcs7_message *pkcs7,
-				struct key *trust_keyring,
-				bool *_trusted);
+				struct key *trust_keyring);
 
 /*
  * pkcs7_verify.c
diff --git a/include/linux/verification.h b/include/linux/verification.h
index bb0fcf941cb7..a10549a6c7cd 100644
--- a/include/linux/verification.h
+++ b/include/linux/verification.h
@@ -33,7 +33,6 @@ 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,
diff --git a/kernel/module_signing.c b/kernel/module_signing.c
index 70cf0220efeb..b3dafe4fd320 100644
--- a/kernel/module_signing.c
+++ b/kernel/module_signing.c
@@ -74,6 +74,6 @@ int mod_verify_sig(const void *mod, unsigned long *_modlen)
 	}
 
 	return verify_pkcs7_signature(mod, modlen, mod + modlen, sig_len,
-				      NULL, -ENOKEY, VERIFYING_MODULE_SIGNATURE,
+				      NULL, VERIFYING_MODULE_SIGNATURE,
 				      NULL, NULL);
 }

[toc] | [prev] | [next] | [standalone]


#1312153 — [RFC PATCH 03/20] X.509: Allow X.509 certs to be blacklisted [ver #2]

FromDavid Howells <dhowells@redhat.com>
Date2016-01-19 12:40 +0100
Subject[RFC PATCH 03/20] X.509: Allow X.509 certs to be blacklisted [ver #2]
Message-ID<qSCNJ-78i-43@gated-at.bofh.it>
In reply to#1312146
Allow X.509 certs to be blacklisted based on their TBS hash.  This is
convenient since we have to determine this anyway to be able to check the
signature on an X.509 certificate.

If a certificate built into the kernel is blacklisted, something like the
following might then be seen during boot:

	X.509: Cert 123412341234c55c1dcc601ab8e172917706aa32fb5eaf826813547fdf02dd46 is blacklisted
	Problem loading in-kernel X.509 certificate (-129)

where the hex string shown is the blacklisted hash.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 crypto/asymmetric_keys/x509_parser.h     |    1 +
 crypto/asymmetric_keys/x509_public_key.c |   19 +++++++++++++++++--
 2 files changed, 18 insertions(+), 2 deletions(-)

diff --git a/crypto/asymmetric_keys/x509_parser.h b/crypto/asymmetric_keys/x509_parser.h
index dbeed6018e63..be7cf2eae3bd 100644
--- a/crypto/asymmetric_keys/x509_parser.h
+++ b/crypto/asymmetric_keys/x509_parser.h
@@ -43,6 +43,7 @@ struct x509_certificate {
 	bool		verified;
 	bool		trusted;
 	bool		unsupported_crypto;	/* T if can't be verified due to missing crypto */
+	bool		blacklisted;
 };
 
 /*
diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c
index 9e9e5a6a9ed6..c4f3c40a4ab9 100644
--- a/crypto/asymmetric_keys/x509_public_key.c
+++ b/crypto/asymmetric_keys/x509_public_key.c
@@ -92,7 +92,7 @@ struct key *x509_request_asymmetric_key(struct key *keyring,
 		lookup = skid->data;
 		len = skid->len;
 	}
-	
+
 	/* Construct an identifier "id:<keyid>". */
 	p = req = kmalloc(2 + 1 + len * 2 + 1, GFP_KERNEL);
 	if (!req)
@@ -141,7 +141,7 @@ struct key *x509_request_asymmetric_key(struct key *keyring,
 			goto reject;
 		}
 	}
-	
+
 	pr_devel("<==%s() = 0 [%x]\n", __func__, key_serial(key));
 	return key;
 
@@ -211,6 +211,16 @@ int x509_get_sig_params(struct x509_certificate *cert)
 		goto error;
 	might_sleep();
 	ret = crypto_shash_finup(desc, cert->tbs, cert->tbs_size, digest);
+	if (ret < 0)
+		goto error;
+
+	ret = is_bin_hash_blacklisted(digest, digest_size);
+	if (ret == -EKEYREJECTED) {
+		pr_err("Cert %*phN is blacklisted\n", (int)digest_size, digest);
+		cert->blacklisted = true;
+		ret = 0;
+	}
+
 error:
 	crypto_free_shash(tfm);
 	pr_devel("<==%s() = %d\n", __func__, ret);
@@ -327,6 +337,11 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
 			prep->trusted = 1;
 	}
 
+	/* Don't permit addition of blacklisted keys */
+	ret = -EKEYREJECTED;
+	if (cert->blacklisted)
+		goto error_free_cert;
+
 	/* Propose a description */
 	sulen = strlen(cert->subject);
 	if (cert->raw_skid) {

[toc] | [prev] | [next] | [standalone]


#1313516 — Re: [RFC PATCH 03/20] X.509: Allow X.509 certs to be blacklisted [ver #2]

FromMimi Zohar <zohar@linux.vnet.ibm.com>
Date2016-01-20 21:40 +0100
SubjectRe: [RFC PATCH 03/20] X.509: Allow X.509 certs to be blacklisted [ver #2]
Message-ID<qT7HQ-3eL-15@gated-at.bofh.it>
In reply to#1312153
On Tue, 2016-01-19 at 11:30 +0000, David Howells wrote:
> Allow X.509 certs to be blacklisted based on their TBS hash. 

What is the TBS hash?  This doesn't seem to be the key identifier.  The
cert associated with this key identifier is loaded onto the .ima
keyring.

eg:  openssl x509 -in <pathname> -inform DER -notext -out

<snip>

        X509v3 extensions:
            X509v3 Subject Key Identifier: 

71:12:39:B3:AB:E6:8D:BF:70:E7:26:DE:C8:4A:3F:5F:17:EF:00:6C

# keyctl show %keyring:.blacklist
Keyring
 466574863 ---lswrv      0     0  keyring: .blacklist
 433453563 ---lswrv      0     0   \_ blacklist:
711239b3abe68dbf70e726dec84a3f5f17ef006c

Mimi

>  This is
> convenient since we have to determine this anyway to be able to check the
> signature on an X.509 certificate.
> 
> If a certificate built into the kernel is blacklisted, something like the
> following might then be seen during boot:
> 
> 	X.509: Cert 123412341234c55c1dcc601ab8e172917706aa32fb5eaf826813547fdf02dd46 is blacklisted
> 	Problem loading in-kernel X.509 certificate (-129)
> 
> where the hex string shown is the blacklisted hash.
> 
> Signed-off-by: David Howells <dhowells@redhat.com>

[toc] | [prev] | [next] | [standalone]


#1312154 — [RFC PATCH 14/20] KEYS: Generalise x509_request_asymmetric_key() [ver #2]

FromDavid Howells <dhowells@redhat.com>
Date2016-01-19 12:40 +0100
Subject[RFC PATCH 14/20] KEYS: Generalise x509_request_asymmetric_key() [ver #2]
Message-ID<qSCNJ-78i-45@gated-at.bofh.it>
In reply to#1312146
Generalise x509_request_asymmetric_key().  It doesn't really have any
dependencies on X.509 features as it uses generalised IDs and the
public_key structs that contain data extracted from X.509.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 crypto/asymmetric_keys/asymmetric_keys.h  |    2 +
 crypto/asymmetric_keys/pkcs7_trust.c      |   22 +++++------
 crypto/asymmetric_keys/public_key_trust.c |   60 +++++++++++++----------------
 include/crypto/public_key.h               |    8 ++--
 security/integrity/digsig_asymmetric.c    |    5 +-
 5 files changed, 46 insertions(+), 51 deletions(-)

diff --git a/crypto/asymmetric_keys/asymmetric_keys.h b/crypto/asymmetric_keys/asymmetric_keys.h
index 1d450b580245..ca8e9ac34ce6 100644
--- a/crypto/asymmetric_keys/asymmetric_keys.h
+++ b/crypto/asymmetric_keys/asymmetric_keys.h
@@ -9,6 +9,8 @@
  * 2 of the Licence, or (at your option) any later version.
  */
 
+#include <keys/asymmetric-type.h>
+
 extern struct asymmetric_key_id *asymmetric_key_hex_to_key_id(const char *id);
 
 extern int __asymmetric_key_hex_to_key_id(const char *id,
diff --git a/crypto/asymmetric_keys/pkcs7_trust.c b/crypto/asymmetric_keys/pkcs7_trust.c
index 400ef359448a..8760bc566902 100644
--- a/crypto/asymmetric_keys/pkcs7_trust.c
+++ b/crypto/asymmetric_keys/pkcs7_trust.c
@@ -51,9 +51,9 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
 		/* Look to see if this certificate is present in the trusted
 		 * keys.
 		 */
-		key = x509_request_asymmetric_key(trust_keyring,
-						  x509->id, x509->skid,
-						  false);
+		key = request_asymmetric_key(trust_keyring,
+					     x509->id, x509->skid,
+					     false);
 		if (!IS_ERR(key)) {
 			/* One of the X.509 certificates in the PKCS#7 message
 			 * is apparently the same as one we already trust.
@@ -84,10 +84,10 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
 	 * trusted keys.
 	 */
 	if (last && (last->sig->auth_ids[0] || last->sig->auth_ids[1])) {
-		key = x509_request_asymmetric_key(trust_keyring,
-						  last->sig->auth_ids[0],
-						  last->sig->auth_ids[1],
-						  false);
+		key = request_asymmetric_key(trust_keyring,
+					     last->sig->auth_ids[0],
+					     last->sig->auth_ids[1],
+					     false);
 		if (!IS_ERR(key)) {
 			x509 = last;
 			pr_devel("sinfo %u: Root cert %u signer is key %x\n",
@@ -101,10 +101,10 @@ static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
 	/* As a last resort, see if we have a trusted public key that matches
 	 * the signed info directly.
 	 */
-	key = x509_request_asymmetric_key(trust_keyring,
-					  sinfo->sig->auth_ids[0],
-					  NULL,
-					  false);
+	key = request_asymmetric_key(trust_keyring,
+				     sinfo->sig->auth_ids[0],
+				     NULL,
+				     false);
 	if (!IS_ERR(key)) {
 		pr_devel("sinfo %u: Direct signer is key %x\n",
 			 sinfo->index, key_serial(key));
diff --git a/crypto/asymmetric_keys/public_key_trust.c b/crypto/asymmetric_keys/public_key_trust.c
index 9febe612e659..afb2a3eb583a 100644
--- a/crypto/asymmetric_keys/public_key_trust.c
+++ b/crypto/asymmetric_keys/public_key_trust.c
@@ -1,6 +1,6 @@
-/* Instantiate a public key crypto key from an X.509 Certificate
+/* Validate one public key against another to determine trust chaining.
  *
- * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
+ * Copyright (C) 2016 Red Hat, Inc. All Rights Reserved.
  * Written by David Howells (dhowells@redhat.com)
  *
  * This program is free software; you can redistribute it and/or
@@ -9,17 +9,10 @@
  * 2 of the Licence, or (at your option) any later version.
  */
 
-#define pr_fmt(fmt) "X.509: "fmt
-#include <linux/module.h>
+#define pr_fmt(fmt) "PKEY: "fmt
 #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"
@@ -63,21 +56,20 @@ __setup("ca_keys=", ca_keys_setup);
 #endif
 
 /**
- * x509_request_asymmetric_key - Request a key by X.509 certificate params.
+ * request_asymmetric_key - Request a key by ID.
  * @keyring: The keys to search.
- * @id: The issuer & serialNumber to look for or NULL.
- * @skid: The subjectKeyIdentifier to look for or NULL.
+ * @id_0: The first ID to look for or NULL.
+ * @id_1: The second ID 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.
+ * the id_0 and the fallback identifier is the id_1.  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 *request_asymmetric_key(struct key *keyring,
+				   const struct asymmetric_key_id *id_0,
+				   const struct asymmetric_key_id *id_1,
+				   bool partial)
 {
 	struct key *key;
 	key_ref_t ref;
@@ -85,12 +77,12 @@ struct key *x509_request_asymmetric_key(struct key *keyring,
 	char *req, *p;
 	int len;
 
-	if (id) {
-		lookup = id->data;
-		len = id->len;
+	if (id_0) {
+		lookup = id_0->data;
+		len = id_0->len;
 	} else {
-		lookup = skid->data;
-		len = skid->len;
+		lookup = id_1->data;
+		len = id_1->len;
 	}
 
 	/* Construct an identifier "id:<keyid>". */
@@ -130,14 +122,15 @@ struct key *x509_request_asymmetric_key(struct key *keyring,
 	}
 
 	key = key_ref_to_ptr(ref);
-	if (id && skid) {
+	if (id_0 && id_1) {
 		const struct asymmetric_key_ids *kids = asymmetric_key_ids(key);
-		if (!kids->id[1]) {
-			pr_debug("issuer+serial match, but expected SKID missing\n");
+
+		if (!kids->id[0]) {
+			pr_debug("First ID matches, but second is missing\n");
 			goto reject;
 		}
-		if (!asymmetric_key_id_same(skid, kids->id[1])) {
-			pr_debug("issuer+serial match, but SKID does not\n");
+		if (!asymmetric_key_id_same(id_1, kids->id[1])) {
+			pr_debug("First ID matches, but second does not\n");
 			goto reject;
 		}
 	}
@@ -149,7 +142,7 @@ reject:
 	key_put(key);
 	return ERR_PTR(-EKEYREJECTED);
 }
-EXPORT_SYMBOL_GPL(x509_request_asymmetric_key);
+EXPORT_SYMBOL_GPL(request_asymmetric_key);
 
 /*
  * Check the new certificate against the ones in the trust keyring.  If one of
@@ -177,9 +170,8 @@ int x509_validate_trust(struct x509_certificate *cert,
 	if (cert->unsupported_sig)
 		return -ENOPKG;
 
-	key = x509_request_asymmetric_key(trust_keyring,
-					  sig->auth_ids[0], sig->auth_ids[1],
-					  false);
+	key = request_asymmetric_key(trust_keyring,
+				     sig->auth_ids[0], sig->auth_ids[1], false);
 	if (IS_ERR(key))
 		return PTR_ERR(key);
 
diff --git a/include/crypto/public_key.h b/include/crypto/public_key.h
index ed86bfb23e89..eaaf261d398a 100644
--- a/include/crypto/public_key.h
+++ b/include/crypto/public_key.h
@@ -102,9 +102,9 @@ extern int verify_signature(const struct key *key,
 			    const struct public_key_signature *sig);
 
 struct asymmetric_key_id;
-extern struct key *x509_request_asymmetric_key(struct key *keyring,
-					       const struct asymmetric_key_id *id,
-					       const struct asymmetric_key_id *skid,
-					       bool partial);
+extern struct key *request_asymmetric_key(struct key *keyring,
+					  const struct asymmetric_key_id *id_0,
+					  const struct asymmetric_key_id *id_1,
+					  bool partial);
 
 #endif /* _LINUX_PUBLIC_KEY_H */
diff --git a/security/integrity/digsig_asymmetric.c b/security/integrity/digsig_asymmetric.c
index 5ade2a7517a6..be1af41b5c2a 100644
--- a/security/integrity/digsig_asymmetric.c
+++ b/security/integrity/digsig_asymmetric.c
@@ -24,7 +24,8 @@
 /*
  * Request an asymmetric key.
  */
-static struct key *request_asymmetric_key(struct key *keyring, uint32_t keyid)
+static struct key *ds_request_asymmetric_key(struct key *keyring,
+					     uint32_t keyid)
 {
 	struct key *key;
 	char name[12];
@@ -97,7 +98,7 @@ int asymmetric_verify(struct key *keyring, const char *sig,
 	if (hdr->hash_algo >= PKEY_HASH__LAST)
 		return -ENOPKG;
 
-	key = request_asymmetric_key(keyring, __be32_to_cpu(hdr->keyid));
+	key = ds_request_asymmetric_key(keyring, __be32_to_cpu(hdr->keyid));
 	if (IS_ERR(key))
 		return PTR_ERR(key);
 

[toc] | [prev] | [next] | [standalone]


#1312155 — [RFC PATCH 08/20] KEYS: Allow authentication data to be stored in an asymmetric key [ver #2]

FromDavid Howells <dhowells@redhat.com>
Date2016-01-19 12:40 +0100
Subject[RFC PATCH 08/20] KEYS: Allow authentication data to be stored in an asymmetric key [ver #2]
Message-ID<qSCNJ-78i-49@gated-at.bofh.it>
In reply to#1312146
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]


#1312156 — [RFC PATCH 15/20] KEYS: Move the point of trust determination to __key_link() [ver #2]

FromDavid Howells <dhowells@redhat.com>
Date2016-01-19 12:40 +0100
Subject[RFC PATCH 15/20] KEYS: Move the point of trust determination to __key_link() [ver #2]
Message-ID<qSCNK-78i-51@gated-at.bofh.it>
In reply to#1312146
Move the point at which a key is determined to be trustworthy to
__key_link() so that we use the contents of the keyring being linked in to
to determine whether the key being linked in is trusted or not.

What is 'trusted' then becomes a matter of what's in the keyring.

Currently, the test is done when the key is parsed, but given that at that
point we can only sensibly refer to the contents of the system trusted
keyring, we can only use that as the basis for working out the
trustworthiness of a new key.

With this change, a trusted keyring is a set of keys that once the
trusted-only flag is set cannot be added to except by verification through
one of the contained keys.

Further, adding a key into a trusted keyring, whilst it might grant
trustworthiness in the context of that keyring, does not automatically
grant trustworthiness in the context of a second keyring to which it could
be secondarily linked.

To accomplish this, the authentication data associated with the key source
must now be retained.  For an X.509 cert, this means the contents of the
AuthorityKeyIdentifier and the signature data.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 certs/system_keyring.c                    |   19 ++++++-
 crypto/asymmetric_keys/public_key.h       |    6 ++
 crypto/asymmetric_keys/public_key_trust.c |   76 +++++++++++++++++++----------
 crypto/asymmetric_keys/x509_parser.h      |    6 --
 crypto/asymmetric_keys/x509_public_key.c  |   22 --------
 include/crypto/public_key.h               |    7 +++
 include/keys/system_keyring.h             |   16 ++----
 kernel/module_signing.c                   |    2 -
 security/integrity/digsig.c               |   31 +++++++++++-
 security/integrity/ima/ima_mok.c          |    6 +-
 10 files changed, 117 insertions(+), 74 deletions(-)

diff --git a/certs/system_keyring.c b/certs/system_keyring.c
index 417d65882870..6e069246c168 100644
--- a/certs/system_keyring.c
+++ b/certs/system_keyring.c
@@ -18,12 +18,25 @@
 #include <keys/system_keyring.h>
 #include <crypto/pkcs7.h>
 
-struct key *system_trusted_keyring;
-EXPORT_SYMBOL_GPL(system_trusted_keyring);
+static struct key *system_trusted_keyring;
 
 extern __initconst const u8 system_certificate_list[];
 extern __initconst const unsigned long system_certificate_list_size;
 
+/**
+ * restrict_link_to_system_trusted - Restrict keyring addition by system CA
+ *
+ * Restrict the addition of keys into a keyring based on the key-to-be-added
+ * being vouched for by a key in the system keyring.
+ */
+int restrict_link_by_system_trusted(struct key *keyring,
+				    const struct key_type *type,
+				    unsigned long flags,
+				    const union key_payload *payload)
+{
+	return public_key_restrict_link(system_trusted_keyring, type, payload);
+}
+
 /*
  * Load the compiled-in keys
  */
@@ -37,7 +50,7 @@ static __init int system_trusted_keyring_init(void)
 			      ((KEY_POS_ALL & ~KEY_POS_SETATTR) |
 			      KEY_USR_VIEW | KEY_USR_READ | KEY_USR_SEARCH),
 			      KEY_ALLOC_NOT_IN_QUOTA,
-			      keyring_restrict_trusted_only, NULL);
+			      restrict_link_by_system_trusted, NULL);
 	if (IS_ERR(system_trusted_keyring))
 		panic("Can't allocate system trusted keyring\n");
 	return 0;
diff --git a/crypto/asymmetric_keys/public_key.h b/crypto/asymmetric_keys/public_key.h
index 5c37a22a0637..2962025e1c09 100644
--- a/crypto/asymmetric_keys/public_key.h
+++ b/crypto/asymmetric_keys/public_key.h
@@ -34,3 +34,9 @@ extern const struct public_key_algorithm RSA_public_key_algorithm;
  */
 extern int public_key_verify_signature(const struct public_key *pk,
 				       const struct public_key_signature *sig);
+
+/*
+ * public_key_trust.c
+ */
+extern int public_key_validate_trust(const struct public_key_signature *sig,
+				     struct key *trust_keyring);
diff --git a/crypto/asymmetric_keys/public_key_trust.c b/crypto/asymmetric_keys/public_key_trust.c
index afb2a3eb583a..26d8e6547104 100644
--- a/crypto/asymmetric_keys/public_key_trust.c
+++ b/crypto/asymmetric_keys/public_key_trust.c
@@ -15,7 +15,6 @@
 #include <linux/err.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;
@@ -145,43 +144,66 @@ reject:
 EXPORT_SYMBOL_GPL(request_asymmetric_key);
 
 /*
+ * Try to find a trust relationship for a new key.
+ */
+static int public_key_verify_trust(struct key *trust_keyring,
+				   const struct public_key_signature *sig)
+{
+	struct key *key;
+	int ret;
+
+
+	/* See if we have a key that signed this one. */
+	key = request_asymmetric_key(trust_keyring,
+				     sig->auth_ids[0],
+				     sig->auth_ids[1],
+				     false);
+	if (IS_ERR(key))
+		return -ENOKEY;
+
+	if (use_builtin_keys && !test_bit(KEY_FLAG_BUILTIN, &key->flags))
+		ret = -ENOKEY;
+	else
+		ret = verify_signature(key, sig);
+	key_put(key);
+	return ret;
+}
+
+/**
+ * public_key_restrict_link - Restrict additions to a ring of public keys
+ * @trust_keyring: A ring of keys that can be used to vouch for the new cert.
+ * @type: The type of key being added.
+ * @payload: The payload of the new 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.
+ * Returns 0 if the new certificate was accepted, -ENOKEY if we couldn't find a
+ * matching parent certificate in the trusted list, -EKEYREJECTED if the
+ * signature check fails or the key is blacklisted and some other error if
+ * there is a matching certificate but the signature check cannot be performed.
  */
-int x509_validate_trust(struct x509_certificate *cert,
-			struct key *trust_keyring)
+int public_key_restrict_link(struct key *trust_keyring,
+			     const struct key_type *type,
+			     const union key_payload *payload)
 {
-	struct public_key_signature *sig = cert->sig;
-	struct key *key;
-	int ret = 1;
+	const struct public_key_signature *sig;
 
-	if (!sig->auth_ids[0] && !sig->auth_ids[1])
-		return 1;
+	pr_devel("==>%s()\n", __func__);
 
 	if (!trust_keyring)
+		return -ENOKEY;
+	
+	if (type != &key_type_asymmetric)
 		return -EOPNOTSUPP;
+
+	sig = payload->data[asym_auth];
+	if (!sig->auth_ids[0] && !sig->auth_ids[1])
+		return 0;
+
 	if (ca_keyid && !asymmetric_key_id_partial(sig->auth_ids[1], ca_keyid))
 		return -EPERM;
-	if (cert->unsupported_sig)
-		return -ENOPKG;
 
-	key = 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;
+	return public_key_verify_trust(trust_keyring, sig);
 }
diff --git a/crypto/asymmetric_keys/x509_parser.h b/crypto/asymmetric_keys/x509_parser.h
index 0cf670b196c8..e373e7483812 100644
--- a/crypto/asymmetric_keys/x509_parser.h
+++ b/crypto/asymmetric_keys/x509_parser.h
@@ -59,9 +59,3 @@ 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 7397edb6cefb..7c6a87e3b151 100644
--- a/crypto/asymmetric_keys/x509_public_key.c
+++ b/crypto/asymmetric_keys/x509_public_key.c
@@ -108,7 +108,6 @@ error:
 	pr_devel("<==%s() = %d\n", __func__, ret);
 	return ret;
 }
-EXPORT_SYMBOL_GPL(x509_get_sig_params);
 
 /*
  * Check for self-signedness in an X.509 cert and if found, check the signature
@@ -196,32 +195,13 @@ 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;
 
-	/* 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 (cert->unsupported_sig || cert->self_signed) {
+	if (cert->unsupported_sig) {
 		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)
-			ret = x509_validate_trust(cert, get_ima_mok_keyring());
-		if (ret == -EKEYREJECTED)
-			goto error_free_cert;
-		if (!ret)
-			prep->trusted = true;
 	}
 
 	/* Don't permit addition of blacklisted keys */
diff --git a/include/crypto/public_key.h b/include/crypto/public_key.h
index eaaf261d398a..c2250f2c1450 100644
--- a/include/crypto/public_key.h
+++ b/include/crypto/public_key.h
@@ -98,6 +98,13 @@ extern void public_key_free(struct public_key *key,
 			    struct public_key_signature *sig);
 
 struct key;
+struct key_type;
+union key_payload;
+
+extern int public_key_restrict_link(struct key *trust_keyring,
+				    const struct key_type *type,
+				    const union key_payload *payload);
+
 extern int verify_signature(const struct key *key,
 			    const struct public_key_signature *sig);
 
diff --git a/include/keys/system_keyring.h b/include/keys/system_keyring.h
index 707229245c8f..28ca2d824554 100644
--- a/include/keys/system_keyring.h
+++ b/include/keys/system_keyring.h
@@ -15,19 +15,11 @@
 #ifdef CONFIG_SYSTEM_TRUSTED_KEYRING
 
 #include <linux/key.h>
-#include <linux/verification.h>
-#include <crypto/public_key.h>
 
-extern struct key *system_trusted_keyring;
-static inline struct key *get_system_trusted_keyring(void)
-{
-	return system_trusted_keyring;
-}
-#else
-static inline struct key *get_system_trusted_keyring(void)
-{
-	return NULL;
-}
+extern int restrict_link_by_system_trusted(struct key *keyring,
+					   const struct key_type *type,
+					   unsigned long flags,
+					   const union key_payload *payload);
 #endif
 
 #ifdef CONFIG_SYSTEM_BLACKLIST_KEYRING
diff --git a/kernel/module_signing.c b/kernel/module_signing.c
index b3dafe4fd320..50eab38e0e34 100644
--- a/kernel/module_signing.c
+++ b/kernel/module_signing.c
@@ -11,7 +11,7 @@
 
 #include <linux/kernel.h>
 #include <linux/errno.h>
-#include <keys/system_keyring.h>
+#include <linux/verification.h>
 #include <crypto/public_key.h>
 #include "module-internal.h"
 
diff --git a/security/integrity/digsig.c b/security/integrity/digsig.c
index 659566c2200b..fee9b5b08b01 100644
--- a/security/integrity/digsig.c
+++ b/security/integrity/digsig.c
@@ -18,6 +18,8 @@
 #include <linux/cred.h>
 #include <linux/key-type.h>
 #include <linux/digsig.h>
+#include <crypto/public_key.h>
+#include <keys/system_keyring.h>
 
 #include "integrity.h"
 
@@ -40,6 +42,26 @@ static bool init_keyring __initdata = true;
 static bool init_keyring __initdata;
 #endif
 
+/*
+ * Restrict the addition of keys into the IMA keyring.
+ *
+ * Any key that needs to go in .ima keyring must be signed by CA in
+ * either .system or .ima_mok keyrings.
+ */
+static int restrict_link_by_ima_mok(struct key *keyring,
+				    const struct key_type *type,
+				    unsigned long flags,
+				    const union key_payload *payload)
+{
+	int ret;
+
+	ret = restrict_link_by_system_trusted(keyring, type, flags, payload);
+	if (ret != -ENOKEY)
+		return ret;
+
+	return public_key_restrict_link(get_ima_mok_keyring(), type, payload);
+}
+
 int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
 			    const char *digest, int digestlen)
 {
@@ -72,19 +94,26 @@ int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
 
 int __init integrity_init_keyring(const unsigned int id)
 {
+	int (*restrict_link)(struct key *,
+			     const struct key_type *,
+			     unsigned long,
+			     const union key_payload *) = NULL;
 	const struct cred *cred = current_cred();
 	int err = 0;
 
 	if (!init_keyring)
 		return 0;
 
+	if (id == 1)
+		restrict_link = restrict_link_by_ima_mok;
+
 	keyring[id] = keyring_alloc(keyring_name[id], KUIDT_INIT(0),
 				    KGIDT_INIT(0), 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, NULL);
+				    restrict_link, NULL);
 	if (IS_ERR(keyring[id])) {
 		err = PTR_ERR(keyring[id]);
 		pr_info("Can't allocate %s keyring (%d)\n",
diff --git a/security/integrity/ima/ima_mok.c b/security/integrity/ima/ima_mok.c
index ef91248cb934..be0da013622c 100644
--- a/security/integrity/ima/ima_mok.c
+++ b/security/integrity/ima/ima_mok.c
@@ -17,7 +17,7 @@
 #include <linux/cred.h>
 #include <linux/err.h>
 #include <linux/init.h>
-#include <keys/asymmetric-type.h>
+#include <keys/system_keyring.h>
 
 
 struct key *ima_mok_keyring;
@@ -36,7 +36,7 @@ __init int ima_mok_init(void)
 			      KEY_USR_VIEW | KEY_USR_READ |
 			      KEY_USR_WRITE | KEY_USR_SEARCH,
 			      KEY_ALLOC_NOT_IN_QUOTA,
-			      keyring_restrict_trusted_only, NULL);
+			      restrict_link_by_system_trusted, NULL);
 
 	ima_blacklist_keyring = keyring_alloc(".ima_blacklist",
 				KUIDT_INIT(0), KGIDT_INIT(0), current_cred(),
@@ -44,7 +44,7 @@ __init int ima_mok_init(void)
 				KEY_USR_VIEW | KEY_USR_READ |
 				KEY_USR_WRITE | KEY_USR_SEARCH,
 				KEY_ALLOC_NOT_IN_QUOTA,
-				keyring_restrict_trusted_only, NULL);
+				restrict_link_by_system_trusted, NULL);
 
 	if (IS_ERR(ima_mok_keyring) || IS_ERR(ima_blacklist_keyring))
 		panic("Can't allocate IMA MOK or blacklist keyrings.");

[toc] | [prev] | [next] | [standalone]


#1312157 — [RFC PATCH 13/20] X.509: Move the trust validation code out to its own file [ver #2]

FromDavid Howells <dhowells@redhat.com>
Date2016-01-19 12:40 +0100
Subject[RFC PATCH 13/20] X.509: Move the trust validation code out to its own file [ver #2]
Message-ID<qSCNK-78i-53@gated-at.bofh.it>
In reply to#1312146
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 e373e7483812..0cf670b196c8 100644
--- a/crypto/asymmetric_keys/x509_parser.h
+++ b/crypto/asymmetric_keys/x509_parser.h
@@ -59,3 +59,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 00aef0d121b2..7397edb6cefb 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.
@@ -294,49 +167,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]


#1312158 — [RFC PATCH 19/20] certs: Add a secondary system keyring that can be added to dynamically [ver #2]

FromDavid Howells <dhowells@redhat.com>
Date2016-01-19 12:40 +0100
Subject[RFC PATCH 19/20] certs: Add a secondary system keyring that can be added to dynamically [ver #2]
Message-ID<qSCNK-78i-55@gated-at.bofh.it>
In reply to#1312146
Add a secondary system keyring that can be added to by root whilst the
system is running - provided the key being added is vouched for by a key
built into the kernel or already added to the secondary keyring.

Rename .system_keyring to .builtin_trusted_keys to distinguish it more
obviously from the new keyring (called .secondary_trusted_keys).

The new keyring needs to be enabled with CONFIG_SECONDARY_TRUSTED_KEYRING.

If the secondary keyring is enabled, a link is created from that to
.builtin_trusted_keys so that the the latter will automatically be searched
too if the secondary keyring is searched.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 certs/Kconfig                 |    8 ++++
 certs/system_keyring.c        |   82 +++++++++++++++++++++++++++++++++++------
 include/keys/system_keyring.h |    4 ++
 3 files changed, 82 insertions(+), 12 deletions(-)

diff --git a/certs/Kconfig b/certs/Kconfig
index 7ce41d4b541d..d78354bb5dfc 100644
--- a/certs/Kconfig
+++ b/certs/Kconfig
@@ -57,4 +57,12 @@ config SYSTEM_BLACKLIST_HASH_LIST
 	  wrapper to incorporate the list into the kernel.  Each <hash> should
 	  be a string of hex digits.
 
+config SECONDARY_TRUSTED_KEYRING
+	bool "Provide a keyring to which extra trustable keys may be added"
+	depends on SYSTEM_TRUSTED_KEYRING
+	help
+	  If set, provide a keyring to which extra keys may be added, provided
+	  those keys are not blacklisted and are vouched for by a key built
+	  into the kernel or already in the secondary trusted keyring.
+
 endmenu
diff --git a/certs/system_keyring.c b/certs/system_keyring.c
index 5e76121d4cc2..4d930895f9ac 100644
--- a/certs/system_keyring.c
+++ b/certs/system_keyring.c
@@ -18,7 +18,10 @@
 #include <keys/system_keyring.h>
 #include <crypto/pkcs7.h>
 
-static struct key *system_trusted_keyring;
+static struct key *builtin_trusted_keys;
+#ifdef CONFIG_SECONDARY_TRUSTED_KEYRING
+static struct key *secondary_trusted_keys;
+#endif
 
 extern __initconst const u8 system_certificate_list[];
 extern __initconst const unsigned long system_certificate_list_size;
@@ -33,25 +36,72 @@ int restrict_link_by_system_trusted(struct key *keyring,
 				    const struct key_type *type,
 				    const union key_payload *payload)
 {
-	return public_key_restrict_link(system_trusted_keyring, type, payload);
+	int ret;
+
+	/* If we have a secondary trusted keyring, then that contains a link
+	 * through to the builtin keyring and the search will follow that link.
+	 */
+#ifdef CONFIG_SECONDARY_TRUSTED_KEYRING
+	if (type == &key_type_keyring &&
+	    keyring == secondary_trusted_keys &&
+	    payload == &builtin_trusted_keys->payload)
+		return 0;
+
+	ret = public_key_restrict_link(secondary_trusted_keys, type, payload);
+#else
+	ret = public_key_restrict_link(builtin_trusted_keys, type, payload);
+#endif
+	if (ret == 0 || ret == -EKEYREJECTED)
+		return ret;
+	return ret;
+}
+
+/**
+ * restrict_link_to_builtin_trusted - Restrict keyring addition by built in CA
+ *
+ * Restrict the addition of keys into a keyring based on the key-to-be-added
+ * being vouched for by a key in the built in system keyring.
+ */
+int restrict_link_by_builtin_trusted(struct key *keyring,
+				     const struct key_type *type,
+				     const union key_payload *payload)
+{
+	return public_key_restrict_link(secondary_trusted_keys, type, payload);
 }
 
 /*
- * Load the compiled-in keys
+ * Create the trusted keyrings
  */
 static __init int system_trusted_keyring_init(void)
 {
-	pr_notice("Initialise system trusted keyring\n");
+	pr_notice("Initialise system trusted keyrings\n");
 
-	system_trusted_keyring =
-		keyring_alloc(".system_keyring",
+	builtin_trusted_keys =
+		keyring_alloc(".builtin_trusted_keys",
 			      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, NULL);
+	if (IS_ERR(builtin_trusted_keys))
+		panic("Can't allocate builtin trusted keyring\n");
+
+#ifdef CONFIG_SECONDARY_TRUSTED_KEYRING
+	secondary_trusted_keys =
+		keyring_alloc(".secondary_trusted_keys",
+			      KUIDT_INIT(0), KGIDT_INIT(0), current_cred(),
+			      ((KEY_POS_ALL & ~KEY_POS_SETATTR) |
+			       KEY_USR_VIEW | KEY_USR_READ | KEY_USR_SEARCH |
+			       KEY_USR_WRITE),
+			      KEY_ALLOC_NOT_IN_QUOTA,
 			      restrict_link_by_system_trusted, NULL);
-	if (IS_ERR(system_trusted_keyring))
-		panic("Can't allocate system trusted keyring\n");
+	if (IS_ERR(secondary_trusted_keys))
+		panic("Can't allocate secondary trusted keyring\n");
+#endif
+
+	if (key_link(secondary_trusted_keys, builtin_trusted_keys) < 0)
+		panic("Can't link trusted keyrings\n");
+
 	return 0;
 }
 
@@ -87,7 +137,7 @@ static __init int load_system_certificate_list(void)
 		if (plen > end - p)
 			goto dodgy_cert;
 
-		key = key_create_or_update(make_key_ref(system_trusted_keyring, 1),
+		key = key_create_or_update(make_key_ref(builtin_trusted_keys, 1),
 					   "asymmetric",
 					   NULL,
 					   p,
@@ -124,7 +174,8 @@ late_initcall(load_system_certificate_list);
  * @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).
+ * @trusted_keys: Trusted keys to use (NULL for builtin trusted keys only,
+ *					(void *)1UL for all trusted keys).
  * @usage: The use to which the key is being put.
  * @view_content: Callback to gain access to content.
  * @ctx: Context for callback.
@@ -156,8 +207,15 @@ int verify_pkcs7_signature(const void *data, size_t len,
 	if (ret < 0)
 		goto error;
 
-	if (!trusted_keys)
-		trusted_keys = system_trusted_keyring;
+	if (!trusted_keys) {
+		trusted_keys = builtin_trusted_keys;
+	} else if (trusted_keys == (void *)1UL) {
+#ifdef CONFIG_SECONDARY_TRUSTED_KEYRING
+		trusted_keys = secondary_trusted_keys;
+#else
+		trusted_keys = builtin_trusted_keys;
+#endif
+	}
 	ret = pkcs7_validate_trust(pkcs7, trusted_keys);
 	if (ret < 0) {
 		if (ret == -ENOKEY)
diff --git a/include/keys/system_keyring.h b/include/keys/system_keyring.h
index 15107dcc2ec4..b261362c8b2d 100644
--- a/include/keys/system_keyring.h
+++ b/include/keys/system_keyring.h
@@ -19,6 +19,10 @@
 extern int restrict_link_by_system_trusted(struct key *keyring,
 					   const struct key_type *type,
 					   const union key_payload *payload);
+
+extern int restrict_link_by_builtin_trusted(struct key *keyring,
+					    const struct key_type *type,
+					    const union key_payload *payload);
 #endif
 
 #ifdef CONFIG_SYSTEM_BLACKLIST_KEYRING

[toc] | [prev] | [next] | [standalone]


#1312159 — [RFC PATCH 02/20] KEYS: Add a system blacklist keyring [ver #2]

FromDavid Howells <dhowells@redhat.com>
Date2016-01-19 12:40 +0100
Subject[RFC PATCH 02/20] KEYS: Add a system blacklist keyring [ver #2]
Message-ID<qSCNK-78i-57@gated-at.bofh.it>
In reply to#1312146
Add the following:

 (1) A new system keyring that is used to store information about
     blacklisted certificates and signatures.

 (2) A new key type (called 'blacklist') that is used to store a
     blacklisted hash in its description as a hex string.  The key accepts
     no payload.

 (3) The ability to configure a list of blacklisted hashes into the kernel
     at build time.  This is done by setting
     CONFIG_SYSTEM_BLACKLIST_HASH_LIST to the filename of a list of hashes
     that are in the form:

	"<hash>", "<hash>", ..., "<hash>"

     where each <hash> is a hex string representation of the hash and must
     include all necessary leading zeros to pad the hash to the right size.

The above are enabled with CONFIG_SYSTEM_BLACKLIST_KEYRING.

Once the kernel is booted, the blacklist keyring can be listed:

	root@andromeda ~]# keyctl show %:.blacklist
	Keyring
	 723359729 ---lswrv      0     0  keyring: .blacklist
	 676257228 ---lswrv      0     0   \_ blacklist: 123412341234c55c1dcc601ab8e172917706aa32fb5eaf826813547fdf02dd46

The blacklist cannot currently be modified by userspace, but it will be
possible to load it, for example, from the UEFI blacklist database.

In the future, it should also be made possible to load blacklisted
asymmetric keys in here too.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 certs/Kconfig                 |   18 +++++
 certs/Makefile                |    6 ++
 certs/blacklist.c             |  164 +++++++++++++++++++++++++++++++++++++++++
 certs/blacklist.h             |    3 +
 certs/blacklist_hashes.c      |    6 ++
 certs/blacklist_nohashes.c    |    5 +
 include/keys/system_keyring.h |   15 ++++
 7 files changed, 217 insertions(+)
 create mode 100644 certs/blacklist.c
 create mode 100644 certs/blacklist.h
 create mode 100644 certs/blacklist_hashes.c
 create mode 100644 certs/blacklist_nohashes.c

diff --git a/certs/Kconfig b/certs/Kconfig
index b030b9c7ed34..7ce41d4b541d 100644
--- a/certs/Kconfig
+++ b/certs/Kconfig
@@ -39,4 +39,22 @@ config SYSTEM_TRUSTED_KEYS
 	  form of DER-encoded *.x509 files in the top-level build directory,
 	  those are no longer used. You will need to set this option instead.
 
+config SYSTEM_BLACKLIST_KEYRING
+	bool "Provide system-wide ring of blacklisted keys"
+	depends on KEYS
+	help
+	  Provide a system keyring to which blacklisted keys can be added.
+	  Keys in the keyring are considered entirely untrusted.  Keys in this
+	  keyring are used by the module signature checking to reject loading
+	  of modules signed with a blacklisted key.
+
+config SYSTEM_BLACKLIST_HASH_LIST
+	string "Hashes to be preloaded into the system blacklist keyring"
+	depends on SYSTEM_BLACKLIST_KEYRING
+	help
+	  If set, this option should be the filename of a list of hashes in the
+	  form "<hash>", "<hash>", ... .  This will be included into a C
+	  wrapper to incorporate the list into the kernel.  Each <hash> should
+	  be a string of hex digits.
+
 endmenu
diff --git a/certs/Makefile b/certs/Makefile
index 28ac694dd11a..556705723c68 100644
--- a/certs/Makefile
+++ b/certs/Makefile
@@ -3,6 +3,12 @@
 #
 
 obj-$(CONFIG_SYSTEM_TRUSTED_KEYRING) += system_keyring.o system_certificates.o
+obj-$(CONFIG_SYSTEM_BLACKLIST_KEYRING) += blacklist.o
+ifneq ($(CONFIG_SYSTEM_BLACKLIST_HASH_LIST),"")
+obj-y += blacklist_hashes.o
+else
+obj-y += blacklist_nohashes.o
+endif
 
 ifeq ($(CONFIG_SYSTEM_TRUSTED_KEYRING),y)
 
diff --git a/certs/blacklist.c b/certs/blacklist.c
new file mode 100644
index 000000000000..5f54baae3a32
--- /dev/null
+++ b/certs/blacklist.c
@@ -0,0 +1,164 @@
+/* System hash blacklist.
+ *
+ * Copyright (C) 2016 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) "blacklist: "fmt
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/key.h>
+#include <linux/key-type.h>
+#include <linux/sched.h>
+#include <linux/ctype.h>
+#include <linux/err.h>
+#include <keys/system_keyring.h>
+#include "blacklist.h"
+
+static struct key *blacklist_keyring;
+
+/*
+ * The description must be an even number of hex digits.  We keep the hash
+ * here.
+ */
+static int blacklist_vet_description(const char *desc)
+{
+	int n = 0;
+
+	for (; *desc; desc++) {
+		if (!isxdigit(*desc))
+			return -EINVAL;
+		n++;
+	}
+
+	if (n == 0 || n & 1)
+		return -EINVAL;
+	return 0;
+}
+
+/*
+ * The hash to be blacklisted is expected to be in the description.  There will
+ * be no payload.
+ */
+static int blacklist_preparse(struct key_preparsed_payload *prep)
+{
+	if (prep->datalen > 0)
+		return -EINVAL;
+	return 0;
+}
+
+static void blacklist_free_preparse(struct key_preparsed_payload *prep)
+{
+}
+
+static struct key_type key_type_blacklist = {
+	.name			= "blacklist",
+	.vet_description	= blacklist_vet_description,
+	.preparse		= blacklist_preparse,
+	.free_preparse		= blacklist_free_preparse,
+	.instantiate		= generic_key_instantiate,
+};
+
+/**
+ * mark_hash_blacklisted - Add a hash to the system blacklist
+ * @hash - The hash as a hex string
+ */
+int mark_hash_blacklisted(const char *hash)
+{
+	key_ref_t key;
+
+	key = key_create_or_update(make_key_ref(blacklist_keyring, true),
+				   "blacklist",
+				   hash,
+				   NULL,
+				   0,
+				   ((KEY_POS_ALL & ~KEY_POS_SETATTR) |
+				    KEY_USR_VIEW),
+				   KEY_ALLOC_NOT_IN_QUOTA |
+				   KEY_ALLOC_BUILT_IN);
+	if (IS_ERR(key)) {
+		pr_err("Problem blacklisting hash (%ld)\n",
+		       PTR_ERR(key));
+		return PTR_ERR(key);
+	}
+	return 0;
+}
+
+/**
+ * is_hash_blacklisted - Determine if a hash is blacklisted
+ * @hash: The hash to be checked as a hex string.
+ */
+int is_hash_blacklisted(const char *hash)
+{
+	key_ref_t kref;
+
+	kref = keyring_search(make_key_ref(blacklist_keyring, true),
+			      &key_type_blacklist, hash);
+	if (!IS_ERR(kref)) {
+		key_ref_put(kref);
+		return -EKEYREJECTED;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(is_hash_blacklisted);
+
+/**
+ * is_bin_hash_blacklisted - Determine if a hash is blacklisted
+ * @hash: The hash to be checked as a binary blob
+ * @hash_len: The length of the binary hash
+ */
+int is_bin_hash_blacklisted(const u8 *hash, size_t hash_len)
+{
+	char *buffer;
+	int ret;
+
+	buffer = kmalloc(hash_len * 2 + 1, GFP_KERNEL);
+	if (!buffer)
+		return -ENOMEM;
+	bin2hex(buffer, hash, hash_len);
+	buffer[hash_len * 2] = 0;
+	ret = is_hash_blacklisted(buffer);
+	kfree(buffer);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(is_bin_hash_blacklisted);
+
+/*
+ * Intialise the blacklist
+ */
+static int __init blacklist_init(void)
+{
+	const char *const *bl;
+
+	if (register_key_type(&key_type_blacklist) < 0)
+		panic("Can't allocate system blacklist key type\n");
+
+	blacklist_keyring =
+		keyring_alloc(".blacklist",
+			      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 |
+			      KEY_FLAG_KEEP,
+			      NULL);
+	if (IS_ERR(blacklist_keyring))
+		panic("Can't allocate system blacklist keyring\n");
+
+	for (bl = blacklist_hashes; *bl; bl++)
+		if (mark_hash_blacklisted(*bl) < 0)
+			pr_err("- blacklisting failed\n");
+	return 0;
+}
+
+/*
+ * Must be initialised before we try and load the keys into the keyring.
+ */
+device_initcall(blacklist_init);
diff --git a/certs/blacklist.h b/certs/blacklist.h
new file mode 100644
index 000000000000..150d82da8e99
--- /dev/null
+++ b/certs/blacklist.h
@@ -0,0 +1,3 @@
+#include <linux/kernel.h>
+
+extern const char __initdata *const blacklist_hashes[];
diff --git a/certs/blacklist_hashes.c b/certs/blacklist_hashes.c
new file mode 100644
index 000000000000..5bd449f7db17
--- /dev/null
+++ b/certs/blacklist_hashes.c
@@ -0,0 +1,6 @@
+#include "blacklist.h"
+
+const char __initdata *const blacklist_hashes[] = {
+#include CONFIG_SYSTEM_BLACKLIST_HASH_LIST
+	, NULL
+};
diff --git a/certs/blacklist_nohashes.c b/certs/blacklist_nohashes.c
new file mode 100644
index 000000000000..851de10706a5
--- /dev/null
+++ b/certs/blacklist_nohashes.c
@@ -0,0 +1,5 @@
+#include "blacklist.h"
+
+const char __initdata *const blacklist_hashes[] = {
+	NULL
+};
diff --git a/include/keys/system_keyring.h b/include/keys/system_keyring.h
index 39fd38cfa8c9..e8334d299314 100644
--- a/include/keys/system_keyring.h
+++ b/include/keys/system_keyring.h
@@ -35,6 +35,21 @@ extern int system_verify_data(const void *data, unsigned long len,
 			      enum key_being_used_for usage);
 #endif
 
+#ifdef CONFIG_SYSTEM_BLACKLIST_KEYRING
+extern int mark_hash_blacklisted(const char *hash);
+extern int is_hash_blacklisted(const char *hash);
+extern int is_bin_hash_blacklisted(const u8 *hash, size_t hash_len);
+#else
+static inline int is_hash_blacklisted(const char *hash)
+{
+	return 0;
+}
+static inline int is_bin_hash_blacklisted(const u8 *hash, size_t hash_len)
+{
+	return 0;
+}
+#endif
+
 #ifdef CONFIG_IMA_MOK_KEYRING
 extern struct key *ima_mok_keyring;
 extern struct key *ima_blacklist_keyring;

[toc] | [prev] | [next] | [standalone]


#1313470 — Re: [RFC PATCH 02/20] KEYS: Add a system blacklist keyring [ver #2]

FromMimi Zohar <zohar@linux.vnet.ibm.com>
Date2016-01-20 20:40 +0100
SubjectRe: [RFC PATCH 02/20] KEYS: Add a system blacklist keyring [ver #2]
Message-ID<qT6LN-2E2-47@gated-at.bofh.it>
In reply to#1312159
On Tue, 2016-01-19 at 11:30 +0000, David Howells wrote:
> Add the following:
> 
>  (1) A new system keyring that is used to store information about
>      blacklisted certificates and signatures.
> 
>  (2) A new key type (called 'blacklist') that is used to store a
>      blacklisted hash in its description as a hex string.  The key accepts
>      no payload.

>  (3) The ability to configure a list of blacklisted hashes into the kernel
>      at build time.  This is done by setting
>      CONFIG_SYSTEM_BLACKLIST_HASH_LIST to the filename of a list of hashes
>      that are in the form:
> 
> 	"<hash>", "<hash>", ..., "<hash>"
> 
>      where each <hash> is a hex string representation of the hash and must
>      include all necessary leading zeros to pad the hash to the right size.

Is the output of "keyctl print" the hex string representation?  Update
keys documentation?

> The above are enabled with CONFIG_SYSTEM_BLACKLIST_KEYRING.
> 
> Once the kernel is booted, the blacklist keyring can be listed:
> 
> 	root@andromeda ~]# keyctl show %:.blacklist
> 	Keyring
> 	 723359729 ---lswrv      0     0  keyring: .blacklist
> 	 676257228 ---lswrv      0     0   \_ blacklist: 123412341234c55c1dcc601ab8e172917706aa32fb5eaf826813547fdf02dd46
> 
> The blacklist cannot currently be modified by userspace, but it will be
> possible to load it, for example, from the UEFI blacklist database.

When loading the UEFI blacklist database is enabled, it should be
configurable.

> In the future, it should also be made possible to load blacklisted
> asymmetric keys in here too.

Please update to reflect patch 3/20 "X.509: Allow X.509 certs to be
blacklisted" adds this support.

Mimi

[toc] | [prev] | [next] | [standalone]


#1313506 — Re: [RFC PATCH 02/20] KEYS: Add a system blacklist keyring [ver #2]

FromMimi Zohar <zohar@linux.vnet.ibm.com>
Date2016-01-20 21:30 +0100
SubjectRe: [RFC PATCH 02/20] KEYS: Add a system blacklist keyring [ver #2]
Message-ID<qT7ya-3ae-25@gated-at.bofh.it>
In reply to#1312159
On Tue, 2016-01-19 at 11:30 +0000, David Howells wrote:

> diff --git a/certs/blacklist_hashes.c b/certs/blacklist_hashes.c
> new file mode 100644
> index 000000000000..5bd449f7db17
> --- /dev/null
> +++ b/certs/blacklist_hashes.c
> @@ -0,0 +1,6 @@
> +#include "blacklist.h"
> +
> +const char __initdata *const blacklist_hashes[] = {
> +#include CONFIG_SYSTEM_BLACKLIST_HASH_LIST
> +	, NULL
> +};

It seems CONFIG_SYSTEM_BLACKLIST_HASH_LIST path is expected to be
relative to
the certs directory, not the build root directory.

Mimi

[toc] | [prev] | [next] | [standalone]


#1312160 — [RFC PATCH 11/20] X.509: Extract signature digest and make self-signed cert checks earlier [ver #2]

FromDavid Howells <dhowells@redhat.com>
Date2016-01-19 12:40 +0100
Subject[RFC PATCH 11/20] X.509: Extract signature digest and make self-signed cert checks earlier [ver #2]
Message-ID<qSCNK-78i-59@gated-at.bofh.it>
In reply to#1312146
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 600df3bebed4..e373e7483812 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 */
 	bool		blacklisted;
 };
 
@@ -56,5 +58,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 8626e84450e4..00aef0d121b2 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);
 	}
@@ -228,26 +238,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 = public_key_verify_signature(pub, cert->sig);
-	if (ret == -ENOPKG)
-		cert->unsupported_crypto = true;
-	pr_debug("Cert Verification: %d\n", ret);
+	ret = -EKEYREJECTED;
+	if (cert->pub->pkey_algo != cert->sig->pkey_algo)
+		goto out;
+
+	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
@@ -270,20 +314,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;
 }
 
@@ -306,21 +355,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;
@@ -336,10 +377,19 @@ 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)
 			ret = x509_validate_trust(cert, get_ima_mok_keyring());
+		if (ret == -EKEYREJECTED)
+			goto error_free_cert;
 		if (!ret)
 			prep->trusted = true;
 	}

[toc] | [prev] | [next] | [standalone]


#1312161 — [RFC PATCH 09/20] KEYS: Add identifier pointers to public_key_signature struct [ver #2]

FromDavid Howells <dhowells@redhat.com>
Date2016-01-19 12:40 +0100
Subject[RFC PATCH 09/20] KEYS: Add identifier pointers to public_key_signature struct [ver #2]
Message-ID<qSCNK-78i-63@gated-at.bofh.it>
In reply to#1312146
Add key identifier pointers to public_key_signature struct so that they can
be used to retain the identifier of the key to be used to verify the
signature in both PKCS#7 and X.509.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 crypto/asymmetric_keys/public_key.c |    2 ++
 include/crypto/public_key.h         |    1 +
 2 files changed, 3 insertions(+)

diff --git a/crypto/asymmetric_keys/public_key.c b/crypto/asymmetric_keys/public_key.c
index e537aaeafdbf..f5b4824b7c77 100644
--- a/crypto/asymmetric_keys/public_key.c
+++ b/crypto/asymmetric_keys/public_key.c
@@ -72,6 +72,8 @@ void public_key_free(struct public_key *key,
 	}
 
 	if (sig) {
+		for (i = 0; i < ARRAY_SIZE(sig->auth_ids); i++)
+			kfree(sig->auth_ids[i]);
 		for (i = 0; i < ARRAY_SIZE(sig->mpi); i++)
 			mpi_free(sig->mpi[i]);
 		kfree(sig->digest);
diff --git a/include/crypto/public_key.h b/include/crypto/public_key.h
index a3f8f8268e23..ed86bfb23e89 100644
--- a/include/crypto/public_key.h
+++ b/include/crypto/public_key.h
@@ -76,6 +76,7 @@ struct public_key {
  * Public key cryptography signature data
  */
 struct public_key_signature {
+	struct asymmetric_key_id *auth_ids[2];
 	u8 *digest;
 	u8 digest_size;			/* Number of bytes in digest */
 	u8 nr_mpi;			/* Occupancy of mpi[] */

[toc] | [prev] | [next] | [standalone]


#1313402

FromPetko Manolov <petkan@mip-labs.com>
Date2016-01-20 18:30 +0100
Message-ID<qT4JZ-1jj-21@gated-at.bofh.it>
In reply to#1312146
I assume this is intended for 4.6 or later, correct?


		Petko


On 16-01-19 11:30:26, David Howells wrote:
> 
> Here's a set of patches that changes how certificates/keys are determined
> to be trusted.  That's currently a two-step process:
> 
>  (1) Up until recently, when an X.509 certificate was parsed - no matter
>      the source - it was judged against the keys in .system_keyring,
>      assuming those keys to be trusted if they have KEY_FLAG_TRUSTED set
>      upon them.
> 
>      This has just been changed such that any key in the .ima_mok keyring
>      may also be used to judge the trustwortiness of a new certificate,
>      whether or not the .ima_mok keyring is meant to be consulted for
>      whatever process is being undertaken.
> 
>      If a certificate is determined to be trustworthy, KEY_FLAG_TRUSTED
>      will be set upon a key it is loaded into (if it is loaded into one),
>      no matter what the key is going to be loaded for.
> 
>  (2) If an X.509 certificate is loaded into a key, then that key - if
>      KEY_FLAG_TRUSTED gets set upon it - can be linked into any keyring
>      with KEY_FLAG_TRUSTED_ONLY set upon it.  This was meant to be the
>      system keyring only, but has been extended to various IMA keyrings.
> 
>      A user can at will link any key marked KEY_FLAG_TRUSTED into any
>      keyring marked KEY_FLAG_TRUSTED_ONLY if the relevant permissions masks
>      permit it.
> 
> These patches change that:
> 
>  (1) Trust becomes a matter of consulting the ring of trusted keys supplied
>      when the trust is evaluated only.
> 
>  (2) Asymmetric keys retain the source certificate signature information
>      for future evaluation rather than discarding it.
> 
>  (3) Every keyring can be supplied with its own manager function to
>      restrict what may be added to that keyring.  This is called whenever a
>      key is to be linked into the keyring to guard against a key being
>      created in one keyring and then linked across.
> 
>      This function is supplied with the keyring and the key type and
>      payload[*] of the key being linked in for use in its evaluation.  It
>      is permitted to use other data also, such as the contents of other
>      keyrings such as the system keyrings.
> 
>      [*] The type and payload are supplied instead of a key because as an
>      	 optimisation this function may be called whilst creating a key and
>      	 so may reject the proposed key between preparse and allocation.
> 
>  (4) A default manager function is provided that permits keys to be
>      restricted to only asymmetric keys that are vouched for by the
>      contents of the system keyring.
> 
>  (5) A key allocation flag, KEY_ALLOC_BYPASS_RESTRICTION, is made available
>      so that the kernel can initialise keyrings with keys that form the
>      root of the trust relationship.
> 
>  (6) KEY_FLAG_TRUSTED and KEY_FLAG_TRUSTED_ONLY are removed, along with
>      key_preparsed_payload::trusted.
> 
> This change also makes it possible for userspace to create a private set of
> trusted keys and then to seal it by setting a manager function where the
> private set is wholly independent of the kernel's trust relationships.
> 
> Further changes in the set involve extracting certain IMA special keyrings
> and making them generally global:
> 
>  (*) .system_keyring is renamed to .builtin_trusted_keys and remains read
>      only.  It carries only keys built in to the kernel.  It may be where
>      UEFI keys should be loaded - though that could better be the new
>      secondary keyring (see below).
> 
>  (*) An optional system blacklist keyring is created to replace the IMA
>      keyring.
> 
>      (*) A 'blacklist' key type is created that may contain a hex string in
>          its description (it carries no payload).  When an X.509
>          certificate is parsed, the system blacklist is searched for a
>          blacklist key that matches the TBS hash of the X.509 certificate
>          and if one is found, the certificate is considered blacklisted.
> 
>      (*) A list of blacklisted hashes can be added to the system blacklist
>          keyring at compile time.  In the future it should also be possible
>          to load this up from such as the UEFI blacklist.
> 
>      (*) Keys can be added to the blacklist keyring by root if the keys are
>      	 signed by a key in the builtin system keyring.  These can then be
>      	 searched for by asymmetric key ID.  This allows the functionality
>      	 of the IMA blacklist keyring to be replicated.
> 
>  	 It might be worth making an asymmetric key subtype that carries no
>  	 data to be used here as the cryptographic material is then just
>  	 dead weight since the IDs are what matter.
> 
>  (*) An optional secondary system keyring (called .secondary_trusted_keys)
>      is added to replace the IMA MOK keyring.
> 
>      (*) Keys can be added to the secondary keyring by root if the keys can
>      	 be vouched for by either ring of system keys.
> 
>  (*) Module signing and kexec only use .builtin_trusted_keys and do not use
>      the new secondary keyring, but they do consult the system blacklist.
> 
>  (*) If the kernel sees a PKCS#7 message with more than one signature, at
>      least one of which is blacklisted, it will permit the message if at
>      least one of the non-blacklisted signature chains is vouched for.  If
>      none are, then EKEYREJECTED will be given.  This error takes priority
>      over giving ENOPKG for unsupported encryption.
> 
> The patches can be found here also:
> 
> 	http://git.kernel.org/cgit/linux/kernel/git/dhowells/linux-fs.git/log/?h=keys-trust
> 
> David
> ---
> David Howells (20):
>       KEYS: Add an alloc flag to convey the builtinness of a key
>       KEYS: Add a system blacklist keyring
>       X.509: Allow X.509 certs to be blacklisted
>       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 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 and KEY_ALLOC_TRUSTED
>       PKCS#7: Handle blacklisted certificates
>       IMA: Use the system blacklist keyring
>       certs: Add a secondary system keyring that can be added to dynamically
>       IMA: Replace the .ima_mok keyring with the secondary system keyring
> 
> 
>  Documentation/security/keys.txt           |   14 +
>  arch/x86/kernel/kexec-bzimage64.c         |   18 --
>  certs/Kconfig                             |   26 ++
>  certs/Makefile                            |    6 +
>  certs/blacklist.c                         |  184 +++++++++++++++++
>  certs/blacklist.h                         |    3 
>  certs/blacklist_hashes.c                  |    6 +
>  certs/blacklist_nohashes.c                |    5 
>  certs/system_keyring.c                    |  141 ++++++++++---
>  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   |   66 +++---
>  crypto/asymmetric_keys/pkcs7_parser.c     |   59 +++--
>  crypto/asymmetric_keys/pkcs7_parser.h     |   12 -
>  crypto/asymmetric_keys/pkcs7_trust.c      |   44 ++--
>  crypto/asymmetric_keys/pkcs7_verify.c     |  141 ++++++-------
>  crypto/asymmetric_keys/public_key.c       |   24 ++
>  crypto/asymmetric_keys/public_key.h       |    6 +
>  crypto/asymmetric_keys/public_key_trust.c |  209 +++++++++++++++++++
>  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      |   13 +
>  crypto/asymmetric_keys/x509_public_key.c  |  318 +++++++++--------------------
>  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             |   52 ++---
>  include/linux/key-type.h                  |    1 
>  include/linux/key.h                       |   39 +++-
>  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               |   10 +
>  security/integrity/digsig_asymmetric.c    |   18 +-
>  security/integrity/ima/Kconfig            |   18 --
>  security/integrity/ima/Makefile           |    1 
>  security/integrity/ima/ima_mok.c          |   55 -----
>  security/keys/key.c                       |   44 +++-
>  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 
>  52 files changed, 1131 insertions(+), 722 deletions(-)
>  create mode 100644 certs/blacklist.c
>  create mode 100644 certs/blacklist.h
>  create mode 100644 certs/blacklist_hashes.c
>  create mode 100644 certs/blacklist_nohashes.c
>  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
>  delete mode 100644 security/integrity/ima/ima_mok.c
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

[toc] | [prev] | [next] | [standalone]


#1313445 — Re: [RFC PATCH 00/20] KEYS: Restrict additions to 'trusted' keyrings [ver #2]

FromMimi Zohar <zohar@linux.vnet.ibm.com>
Date2016-01-20 20:00 +0100
SubjectRe: [RFC PATCH 00/20] KEYS: Restrict additions to 'trusted' keyrings [ver #2]
Message-ID<qT693-27H-3@gated-at.bofh.it>
In reply to#1312146
On Tue, 2016-01-19 at 11:30 +0000, David Howells wrote:
> Here's a set of patches that changes how certificates/keys are determined
> to be trusted.  That's currently a two-step process:
> 
>  (1) Up until recently, when an X.509 certificate was parsed - no matter
>      the source - it was judged against the keys in .system_keyring,
>      assuming those keys to be trusted if they have KEY_FLAG_TRUSTED set
>      upon them.
> 
>      This has just been changed such that any key in the .ima_mok keyring

, if configured,

>      may also be used to judge the trustwortiness of a new certificate,
>      whether or not the .ima_mok keyring is meant to be consulted for
>      whatever process is being undertaken.
> 
>      If a certificate is determined to be trustworthy, KEY_FLAG_TRUSTED
>      will be set upon a key it is loaded into (if it is loaded into one),
>      no matter what the key is going to be loaded for.
> 
>  (2) If an X.509 certificate is loaded into a key, then that key - if
>      KEY_FLAG_TRUSTED gets set upon it - can be linked into any keyring
>      with KEY_FLAG_TRUSTED_ONLY set upon it.  This was meant to be the
>      system keyring only, but has been extended to various IMA keyrings.
> 
>      A user can at will link any key marked KEY_FLAG_TRUSTED into any
>      keyring marked KEY_FLAG_TRUSTED_ONLY if the relevant permissions masks
>      permit it.
> 
> These patches change that:
> 
>  (1) Trust becomes a matter of consulting the ring of trusted keys supplied
>      when the trust is evaluated only.
> 
>  (2) Asymmetric keys retain the source certificate signature information
>      for future evaluation rather than discarding it.
> 
>  (3) Every keyring can be supplied with its own manager function to
>      restrict what may be added to that keyring.  This is called whenever a
>      key is to be linked into the keyring to guard against a key being
>      created in one keyring and then linked across.
> 
>      This function is supplied with the keyring and the key type and
>      payload[*] of the key being linked in for use in its evaluation.  It
>      is permitted to use other data also, such as the contents of other
>      keyrings such as the system keyrings.
> 
>      [*] The type and payload are supplied instead of a key because as an
>      	 optimisation this function may be called whilst creating a key and
>      	 so may reject the proposed key between preparse and allocation.
> 
>  (4) A default manager function is provided that permits keys to be
>      restricted to only asymmetric keys that are vouched for by the
>      contents of the system keyring.
> 
>  (5) A key allocation flag, KEY_ALLOC_BYPASS_RESTRICTION, is made available
>      so that the kernel can initialise keyrings with keys that form the
>      root of the trust relationship.
> 
>  (6) KEY_FLAG_TRUSTED and KEY_FLAG_TRUSTED_ONLY are removed, along with
>      key_preparsed_payload::trusted.
> 
> This change also makes it possible for userspace to create a private set of
> trusted keys and then to seal it by setting a manager function where the
> private set is wholly independent of the kernel's trust relationships.
> 
> Further changes in the set involve extracting certain IMA special keyrings
> and making them generally global:
> 
>  (*) .system_keyring is renamed to .builtin_trusted_keys and remains read
>      only.  It carries only keys built in to the kernel.  It may be where
>      UEFI keys should be loaded - though that could better be the new
>      secondary keyring (see below).

or even better a UEFI specific keyring.

>  (*) An optional system blacklist keyring is created to replace the IMA
>      keyring.

to replace the IMA blacklist keyring.

>      (*) A 'blacklist' key type is created that may contain a hex string in
>          its description (it carries no payload).  When an X.509
>          certificate is parsed, the system blacklist is searched for a
>          blacklist key that matches the TBS hash of the X.509 certificate
>          and if one is found, the certificate is considered blacklisted.
> 
>      (*) A list of blacklisted hashes can be added to the system blacklist
>          keyring at compile time.  In the future it should also be possible
>          to load this up from such as the UEFI blacklist.
> 
>      (*) Keys can be added to the blacklist keyring by root if the keys are
>      	 signed by a key in the builtin system keyring.  These can then be
>      	 searched for by asymmetric key ID.  This allows the functionality
>      	 of the IMA blacklist keyring to be replicated.
> 
>  	 It might be worth making an asymmetric key subtype that carries no
>  	 data to be used here as the cryptographic material is then just
>  	 dead weight since the IDs are what matter.

I would go one step farther and say that only this new asymmetric key
subtype, that carries no data, be permitted.  Otherwise the same
certificate, that was used for loading the key in the first place, could
be inadvertently added to the blacklist.

Mimi

>  (*) An optional secondary system keyring (called .secondary_trusted_keys)
>      is added to replace the IMA MOK keyring.
> 
>      (*) Keys can be added to the secondary keyring by root if the keys can
>      	 be vouched for by either ring of system keys.
> 
>  (*) Module signing and kexec only use .builtin_trusted_keys and do not use
>      the new secondary keyring, but they do consult the system blacklist.
> 
>  (*) If the kernel sees a PKCS#7 message with more than one signature, at
>      least one of which is blacklisted, it will permit the message if at
>      least one of the non-blacklisted signature chains is vouched for.  If
>      none are, then EKEYREJECTED will be given.  This error takes priority
>      over giving ENOPKG for unsupported encryption.
> 
> The patches can be found here also:
> 
> 	http://git.kernel.org/cgit/linux/kernel/git/dhowells/linux-fs.git/log/?h=keys-trust
> 
> David
> ---
> David Howells (20):
>       KEYS: Add an alloc flag to convey the builtinness of a key
>       KEYS: Add a system blacklist keyring
>       X.509: Allow X.509 certs to be blacklisted
>       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 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 and KEY_ALLOC_TRUSTED
>       PKCS#7: Handle blacklisted certificates
>       IMA: Use the system blacklist keyring
>       certs: Add a secondary system keyring that can be added to dynamically
>       IMA: Replace the .ima_mok keyring with the secondary system keyring
> 
> 
>  Documentation/security/keys.txt           |   14 +
>  arch/x86/kernel/kexec-bzimage64.c         |   18 --
>  certs/Kconfig                             |   26 ++
>  certs/Makefile                            |    6 +
>  certs/blacklist.c                         |  184 +++++++++++++++++
>  certs/blacklist.h                         |    3 
>  certs/blacklist_hashes.c                  |    6 +
>  certs/blacklist_nohashes.c                |    5 
>  certs/system_keyring.c                    |  141 ++++++++++---
>  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   |   66 +++---
>  crypto/asymmetric_keys/pkcs7_parser.c     |   59 +++--
>  crypto/asymmetric_keys/pkcs7_parser.h     |   12 -
>  crypto/asymmetric_keys/pkcs7_trust.c      |   44 ++--
>  crypto/asymmetric_keys/pkcs7_verify.c     |  141 ++++++-------
>  crypto/asymmetric_keys/public_key.c       |   24 ++
>  crypto/asymmetric_keys/public_key.h       |    6 +
>  crypto/asymmetric_keys/public_key_trust.c |  209 +++++++++++++++++++
>  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      |   13 +
>  crypto/asymmetric_keys/x509_public_key.c  |  318 +++++++++--------------------
>  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             |   52 ++---
>  include/linux/key-type.h                  |    1 
>  include/linux/key.h                       |   39 +++-
>  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               |   10 +
>  security/integrity/digsig_asymmetric.c    |   18 +-
>  security/integrity/ima/Kconfig            |   18 --
>  security/integrity/ima/Makefile           |    1 
>  security/integrity/ima/ima_mok.c          |   55 -----
>  security/keys/key.c                       |   44 +++-
>  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 
>  52 files changed, 1131 insertions(+), 722 deletions(-)
>  create mode 100644 certs/blacklist.c
>  create mode 100644 certs/blacklist.h
>  create mode 100644 certs/blacklist_hashes.c
>  create mode 100644 certs/blacklist_nohashes.c
>  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
>  delete mode 100644 security/integrity/ima/ima_mok.c
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 

[toc] | [prev] | [standalone]


Back to top | Article view | linux.kernel


csiph-web