Merge tag 'keys-pkcs7-20140708' into keys-next
authorDavid Howells <dhowells@redhat.com>
Tue, 22 Jul 2014 20:52:33 +0000 (21:52 +0100)
committerDavid Howells <dhowells@redhat.com>
Tue, 22 Jul 2014 20:53:21 +0000 (21:53 +0100)
Here's a set of changes that implement a PKCS#7 message parser in the kernel.

The PKCS#7 message parsing will then be used to limit kexec to authenticated
kernels only if so configured.

The changes provide the following facilities:

 (1) Parse an ASN.1 PKCS#7 message and pick out useful bits such as the data
     content and the X.509 certificates used to sign it and all the data
     signatures.

 (2) Verify all the data signatures against the set of X.509 certificates
     available in the message.

 (3) Follow the certificate chains and verify that:

     (a) for every self-signed X.509 certificate, check that it validly signed
       itself, and:

     (b) for every non-self-signed certificate, if we have a 'parent'
       certificate, the former is validly signed by the latter.

 (4) Look for intersections between the certificate chains and the trusted
     keyring, if any intersections are found, verify that the trusted
     certificates signed the intersection point in the chain.

 (5) For testing purposes, a key type can be made available that will take a
     PKCS#7 message, check that the message is trustworthy, and if so, add its
     data content into the key.

Note that (5) has to be altered to take account of the preparsing patches
already committed to this branch.

Signed-off-by: David Howells <dhowells@redhat.com>
1  2 
crypto/asymmetric_keys/pkcs7_key_type.c

index 0000000,b1797d2..c2091f7
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,97 +1,99 @@@
 - * Instantiate a PKCS#7 wrapped and validated key.
+ /* Testing module to load key from trusted PKCS#7 message
+  *
+  * Copyright (C) 2014 Red Hat, Inc. All Rights Reserved.
+  * Written by David Howells (dhowells@redhat.com)
+  *
+  * This program is free software; you can redistribute it and/or
+  * modify it under the terms of the GNU General Public Licence
+  * as published by the Free Software Foundation; either version
+  * 2 of the Licence, or (at your option) any later version.
+  */
+ #define pr_fmt(fmt) "PKCS7key: "fmt
+ #include <linux/key.h>
+ #include <linux/key-type.h>
+ #include <crypto/pkcs7.h>
+ #include <keys/user-type.h>
+ #include <keys/system_keyring.h>
+ #include "pkcs7_parser.h"
+ /*
 -int pkcs7_instantiate(struct key *key, struct key_preparsed_payload *prep)
++ * Preparse a PKCS#7 wrapped and validated data blob.
+  */
 -      ret = user_instantiate(key, prep);
++static int pkcs7_preparse(struct key_preparsed_payload *prep)
+ {
+       struct pkcs7_message *pkcs7;
+       const void *data, *saved_prep_data;
+       size_t datalen, saved_prep_datalen;
+       bool trusted;
+       int ret;
+       kenter("");
+       saved_prep_data = prep->data;
+       saved_prep_datalen = prep->datalen;
+       pkcs7 = pkcs7_parse_message(saved_prep_data, saved_prep_datalen);
+       if (IS_ERR(pkcs7)) {
+               ret = PTR_ERR(pkcs7);
+               goto error;
+       }
+       ret = pkcs7_verify(pkcs7);
+       if (ret < 0)
+               goto error_free;
+       ret = pkcs7_validate_trust(pkcs7, system_trusted_keyring, &trusted);
+       if (ret < 0)
+               goto error_free;
+       if (!trusted)
+               pr_warn("PKCS#7 message doesn't chain back to a trusted key\n");
+       ret = pkcs7_get_content_data(pkcs7, &data, &datalen, false);
+       if (ret < 0)
+               goto error_free;
+       prep->data = data;
+       prep->datalen = datalen;
 -      .instantiate            = pkcs7_instantiate,
++      ret = user_preparse(prep);
+       prep->data = saved_prep_data;
+       prep->datalen = saved_prep_datalen;
+ error_free:
+       pkcs7_free_message(pkcs7);
+ error:
+       kleave(" = %d", ret);
+       return ret;
+ }
+ /*
+  * user defined keys take an arbitrary string as the description and an
+  * arbitrary blob of data as the payload
+  */
+ struct key_type key_type_pkcs7 = {
+       .name                   = "pkcs7_test",
+       .def_lookup_type        = KEYRING_SEARCH_LOOKUP_DIRECT,
++      .preparse               = pkcs7_preparse,
++      .free_preparse          = user_free_preparse,
++      .instantiate            = generic_key_instantiate,
+       .match                  = user_match,
+       .revoke                 = user_revoke,
+       .destroy                = user_destroy,
+       .describe               = user_describe,
+       .read                   = user_read,
+ };
+ /*
+  * Module stuff
+  */
+ static int __init pkcs7_key_init(void)
+ {
+       return register_key_type(&key_type_pkcs7);
+ }
+ static void __exit pkcs7_key_cleanup(void)
+ {
+       unregister_key_type(&key_type_pkcs7);
+ }
+ module_init(pkcs7_key_init);
+ module_exit(pkcs7_key_cleanup);