PKCS#7: Appropriately restrict authenticated attributes and content type
authorDavid Howells <dhowells@redhat.com>
Wed, 5 Aug 2015 14:22:27 +0000 (15:22 +0100)
committerDavid Howells <dhowells@redhat.com>
Wed, 12 Aug 2015 16:01:01 +0000 (17:01 +0100)
A PKCS#7 or CMS message can have per-signature authenticated attributes
that are digested as a lump and signed by the authorising key for that
signature.  If such attributes exist, the content digest isn't itself
signed, but rather it is included in a special authattr which then
contributes to the signature.

Further, we already require the master message content type to be
pkcs7_signedData - but there's also a separate content type for the data
itself within the SignedData object and this must be repeated inside the
authattrs for each signer [RFC2315 9.2, RFC5652 11.1].

We should really validate the authattrs if they exist or forbid them
entirely as appropriate.  To this end:

 (1) Alter the PKCS#7 parser to reject any message that has more than one
     signature where at least one signature has authattrs and at least one
     that does not.

 (2) Validate authattrs if they are present and strongly restrict them.
     Only the following authattrs are permitted and all others are
     rejected:

     (a) contentType.  This is checked to be an OID that matches the
       content type in the SignedData object.

     (b) messageDigest.  This must match the crypto digest of the data.

     (c) signingTime.  If present, we check that this is a valid, parseable
       UTCTime or GeneralTime and that the date it encodes fits within
       the validity window of the matching X.509 cert.

     (d) S/MIME capabilities.  We don't check the contents.

     (e) Authenticode SP Opus Info.  We don't check the contents.

     (f) Authenticode Statement Type.  We don't check the contents.

     The message is rejected if (a) or (b) are missing.  If the message is
     an Authenticode type, the message is rejected if (e) is missing; if
     not Authenticode, the message is rejected if (d) - (f) are present.

     The S/MIME capabilities authattr (d) unfortunately has to be allowed
     to support kernels already signed by the pesign program.  This only
     affects kexec.  sign-file suppresses them (CMS_NOSMIMECAP).

     The message is also rejected if an authattr is given more than once or
     if it contains more than one element in its set of values.

 (3) Add a parameter to pkcs7_verify() to select one of the following
     restrictions and pass in the appropriate option from the callers:

     (*) VERIFYING_MODULE_SIGNATURE

 This requires that the SignedData content type be pkcs7-data and
 forbids authattrs.  sign-file sets CMS_NOATTR.  We could be more
 flexible and permit authattrs optionally, but only permit minimal
 content.

     (*) VERIFYING_FIRMWARE_SIGNATURE

 This requires that the SignedData content type be pkcs7-data and
 requires authattrs.  In future, this will require an attribute
 holding the target firmware name in addition to the minimal set.

     (*) VERIFYING_UNSPECIFIED_SIGNATURE

 This requires that the SignedData content type be pkcs7-data but
 allows either no authattrs or only permits the minimal set.

     (*) VERIFYING_KEXEC_PE_SIGNATURE

 This only supports the Authenticode SPC_INDIRECT_DATA content type
 and requires at least an SpcSpOpusInfo authattr in addition to the
 minimal set.  It also permits an SPC_STATEMENT_TYPE authattr (and
 an S/MIME capabilities authattr because the pesign program doesn't
 remove these).

     (*) VERIFYING_KEY_SIGNATURE
     (*) VERIFYING_KEY_SELF_SIGNATURE

 These are invalid in this context but are included for later use
 when limiting the use of X.509 certs.

 (4) The pkcs7_test key type is given a module parameter to select between
     the above options for testing purposes.  For example:

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

     will attempt to check the signature on stuff.pkcs7 as if it contains a
     firmware blob (1 being VERIFYING_FIRMWARE_SIGNATURE).

Suggested-by: Andy Lutomirski <luto@kernel.org>
Signed-off-by: David Howells <dhowells@redhat.com>
Reviewed-by: Marcel Holtmann <marcel@holtmann.org>
Reviewed-by: David Woodhouse <David.Woodhouse@intel.com>
16 files changed:
arch/x86/kernel/kexec-bzimage64.c
crypto/asymmetric_keys/asymmetric_type.c
crypto/asymmetric_keys/pkcs7.asn1
crypto/asymmetric_keys/pkcs7_key_type.c
crypto/asymmetric_keys/pkcs7_parser.c
crypto/asymmetric_keys/pkcs7_parser.h
crypto/asymmetric_keys/pkcs7_verify.c
crypto/asymmetric_keys/verify_pefile.c
include/crypto/pkcs7.h
include/crypto/public_key.h
include/keys/system_keyring.h
include/linux/oid_registry.h
include/linux/verify_pefile.h
kernel/module_signing.c
kernel/system_keyring.c
scripts/sign-file.c

index ca83f7ac388bec2e8c494e51ac5fdbeeda9525c9..fab22e72808c07d445599df6954dd9d74e9349cb 100644 (file)
@@ -536,7 +536,9 @@ static int bzImage64_verify_sig(const char *kernel, unsigned long kernel_len)
        int ret;
 
        ret = verify_pefile_signature(kernel, kernel_len,
-                                     system_trusted_keyring, &trusted);
+                                     system_trusted_keyring,
+                                     VERIFYING_KEXEC_PE_SIGNATURE,
+                                     &trusted);
        if (ret < 0)
                return ret;
        if (!trusted)
index b0e4ed23d6683c54b47d633b1f6e4f01f1de8025..1916680ad81b08fc6db5a0f9f2751dc0526b3e9b 100644 (file)
@@ -12,6 +12,7 @@
  */
 #include <keys/asymmetric-subtype.h>
 #include <keys/asymmetric-parser.h>
+#include <crypto/public_key.h>
 #include <linux/seq_file.h>
 #include <linux/module.h>
 #include <linux/slab.h>
 
 MODULE_LICENSE("GPL");
 
+const char *const key_being_used_for[NR__KEY_BEING_USED_FOR] = {
+       [VERIFYING_MODULE_SIGNATURE]            = "mod sig",
+       [VERIFYING_FIRMWARE_SIGNATURE]          = "firmware sig",
+       [VERIFYING_KEXEC_PE_SIGNATURE]          = "kexec PE sig",
+       [VERIFYING_KEY_SIGNATURE]               = "key sig",
+       [VERIFYING_KEY_SELF_SIGNATURE]          = "key self sig",
+       [VERIFYING_UNSPECIFIED_SIGNATURE]       = "unspec sig",
+};
+EXPORT_SYMBOL_GPL(key_being_used_for);
+
 static LIST_HEAD(asymmetric_key_parsers);
 static DECLARE_RWSEM(asymmetric_key_parsers_sem);
 
index 6bf8ff4f7414ee7bb9aa7ae833e212f6aa010178..1eca740b816ace4680870df9e3a7885b8ba47538 100644 (file)
@@ -8,7 +8,7 @@ ContentType ::= OBJECT IDENTIFIER ({ pkcs7_note_OID })
 SignedData ::= SEQUENCE {
        version                 INTEGER ({ pkcs7_note_signeddata_version }),
        digestAlgorithms        DigestAlgorithmIdentifiers,
-       contentInfo             ContentInfo,
+       contentInfo             ContentInfo ({ pkcs7_note_content }),
        certificates            CHOICE {
                certSet         [0] IMPLICIT ExtendedCertificatesAndCertificates,
                certSequence    [2] IMPLICIT Certificates
@@ -21,7 +21,7 @@ SignedData ::= SEQUENCE {
 }
 
 ContentInfo ::= SEQUENCE {
-       contentType     ContentType,
+       contentType     ContentType ({ pkcs7_note_OID }),
        content         [0] EXPLICIT Data OPTIONAL
 }
 
@@ -111,7 +111,7 @@ AuthenticatedAttribute ::= SEQUENCE {
 }
 
 UnauthenticatedAttribute ::= SEQUENCE {
-       type                    OBJECT IDENTIFIER ({ pkcs7_note_OID }),
+       type                    OBJECT IDENTIFIER,
        values                  SET OF ANY
 }
 
index 3d13b042da735823b7c6425f93cce9cff82e0abe..10d34dbd00b9b1dc47a679edc6ace80e6fa7751d 100644 (file)
 #include <linux/err.h>
 #include <linux/module.h>
 #include <linux/key-type.h>
+#include <keys/asymmetric-type.h>
 #include <crypto/pkcs7.h>
 #include <keys/user-type.h>
 #include <keys/system_keyring.h>
 #include "pkcs7_parser.h"
 
+static unsigned pkcs7_usage;
+module_param_named(usage, pkcs7_usage, uint, S_IWUSR | S_IRUGO);
+MODULE_PARM_DESC(pkcs7_usage,
+                "Usage to specify when verifying the PKCS#7 message");
+
 /*
  * Preparse a PKCS#7 wrapped and validated data blob.
  */
 static int pkcs7_preparse(struct key_preparsed_payload *prep)
 {
+       enum key_being_used_for usage = pkcs7_usage;
        struct pkcs7_message *pkcs7;
        const void *data, *saved_prep_data;
        size_t datalen, saved_prep_datalen;
@@ -32,6 +39,11 @@ static int pkcs7_preparse(struct key_preparsed_payload *prep)
 
        kenter("");
 
+       if (usage >= NR__KEY_BEING_USED_FOR) {
+               pr_err("Invalid usage type %d\n", usage);
+               return -EINVAL;
+       }
+
        saved_prep_data = prep->data;
        saved_prep_datalen = prep->datalen;
        pkcs7 = pkcs7_parse_message(saved_prep_data, saved_prep_datalen);
@@ -40,7 +52,7 @@ static int pkcs7_preparse(struct key_preparsed_payload *prep)
                goto error;
        }
 
-       ret = pkcs7_verify(pkcs7);
+       ret = pkcs7_verify(pkcs7, usage);
        if (ret < 0)
                goto error_free;
 
index 826e2f3f507bd8b233ccd428f3b78bb550dfa67b..e6298b7a945a97b21e233104d49d1e801be1c2d4 100644 (file)
@@ -81,6 +81,30 @@ void pkcs7_free_message(struct pkcs7_message *pkcs7)
 }
 EXPORT_SYMBOL_GPL(pkcs7_free_message);
 
+/*
+ * Check authenticatedAttributes are provided or not provided consistently.
+ */
+static int pkcs7_check_authattrs(struct pkcs7_message *msg)
+{
+       struct pkcs7_signed_info *sinfo;
+       bool want;
+
+       sinfo = msg->signed_infos;
+       if (sinfo->authattrs) {
+               want = true;
+               msg->have_authattrs = true;
+       }
+
+       for (sinfo = sinfo->next; sinfo; sinfo = sinfo->next)
+               if (!!sinfo->authattrs != want)
+                       goto inconsistent;
+       return 0;
+
+inconsistent:
+       pr_warn("Inconsistently supplied authAttrs\n");
+       return -EINVAL;
+}
+
 /**
  * pkcs7_parse_message - Parse a PKCS#7 message
  * @data: The raw binary ASN.1 encoded message to be parsed
@@ -113,6 +137,10 @@ struct pkcs7_message *pkcs7_parse_message(const void *data, size_t datalen)
                goto out;
        }
 
+       ret = pkcs7_check_authattrs(ctx->msg);
+       if (ret < 0)
+               goto out;
+
        msg = ctx->msg;
        ctx->msg = NULL;
 
@@ -380,6 +408,25 @@ int pkcs7_note_certificate_list(void *context, size_t hdrlen,
        return 0;
 }
 
+/*
+ * Note the content type.
+ */
+int pkcs7_note_content(void *context, size_t hdrlen,
+                      unsigned char tag,
+                      const void *value, size_t vlen)
+{
+       struct pkcs7_parse_context *ctx = context;
+
+       if (ctx->last_oid != OID_data &&
+           ctx->last_oid != OID_msIndirectData) {
+               pr_warn("Unsupported data type %d\n", ctx->last_oid);
+               return -EINVAL;
+       }
+
+       ctx->msg->data_type = ctx->last_oid;
+       return 0;
+}
+
 /*
  * Extract the data from the message and store that and its content type OID in
  * the context.
@@ -395,31 +442,90 @@ int pkcs7_note_data(void *context, size_t hdrlen,
        ctx->msg->data = value;
        ctx->msg->data_len = vlen;
        ctx->msg->data_hdrlen = hdrlen;
-       ctx->msg->data_type = ctx->last_oid;
        return 0;
 }
 
 /*
- * Parse authenticated attributes
+ * Parse authenticated attributes.
  */
 int pkcs7_sig_note_authenticated_attr(void *context, size_t hdrlen,
                                      unsigned char tag,
                                      const void *value, size_t vlen)
 {
        struct pkcs7_parse_context *ctx = context;
+       struct pkcs7_signed_info *sinfo = ctx->sinfo;
+       enum OID content_type;
 
        pr_devel("AuthAttr: %02x %zu [%*ph]\n", tag, vlen, (unsigned)vlen, value);
 
        switch (ctx->last_oid) {
+       case OID_contentType:
+               if (__test_and_set_bit(sinfo_has_content_type, &sinfo->aa_set))
+                       goto repeated;
+               content_type = look_up_OID(value, vlen);
+               if (content_type != ctx->msg->data_type) {
+                       pr_warn("Mismatch between global data type (%d) and sinfo %u (%d)\n",
+                               ctx->msg->data_type, sinfo->index,
+                               content_type);
+                       return -EBADMSG;
+               }
+               return 0;
+
+       case OID_signingTime:
+               if (__test_and_set_bit(sinfo_has_signing_time, &sinfo->aa_set))
+                       goto repeated;
+               /* Should we check that the signing time is consistent
+                * with the signer's X.509 cert?
+                */
+               return x509_decode_time(&sinfo->signing_time,
+                                       hdrlen, tag, value, vlen);
+
        case OID_messageDigest:
+               if (__test_and_set_bit(sinfo_has_message_digest, &sinfo->aa_set))
+                       goto repeated;
                if (tag != ASN1_OTS)
                        return -EBADMSG;
-               ctx->sinfo->msgdigest = value;
-               ctx->sinfo->msgdigest_len = vlen;
+               sinfo->msgdigest = value;
+               sinfo->msgdigest_len = vlen;
+               return 0;
+
+       case OID_smimeCapabilites:
+               if (__test_and_set_bit(sinfo_has_smime_caps, &sinfo->aa_set))
+                       goto repeated;
+               if (ctx->msg->data_type != OID_msIndirectData) {
+                       pr_warn("S/MIME Caps only allowed with Authenticode\n");
+                       return -EKEYREJECTED;
+               }
+               return 0;
+
+               /* Microsoft SpOpusInfo seems to be contain cont[0] 16-bit BE
+                * char URLs and cont[1] 8-bit char URLs.
+                *
+                * Microsoft StatementType seems to contain a list of OIDs that
+                * are also used as extendedKeyUsage types in X.509 certs.
+                */
+       case OID_msSpOpusInfo:
+               if (__test_and_set_bit(sinfo_has_ms_opus_info, &sinfo->aa_set))
+                       goto repeated;
+               goto authenticode_check;
+       case OID_msStatementType:
+               if (__test_and_set_bit(sinfo_has_ms_statement_type, &sinfo->aa_set))
+                       goto repeated;
+       authenticode_check:
+               if (ctx->msg->data_type != OID_msIndirectData) {
+                       pr_warn("Authenticode AuthAttrs only allowed with Authenticode\n");
+                       return -EKEYREJECTED;
+               }
+               /* I'm not sure how to validate these */
                return 0;
        default:
                return 0;
        }
+
+repeated:
+       /* We permit max one item per AuthenticatedAttribute and no repeats */
+       pr_warn("Repeated/multivalue AuthAttrs not permitted\n");
+       return -EKEYREJECTED;
 }
 
 /*
@@ -430,10 +536,25 @@ int pkcs7_sig_note_set_of_authattrs(void *context, size_t hdrlen,
                                    const void *value, size_t vlen)
 {
        struct pkcs7_parse_context *ctx = context;
+       struct pkcs7_signed_info *sinfo = ctx->sinfo;
+
+       if (!test_bit(sinfo_has_content_type, &sinfo->aa_set) ||
+           !test_bit(sinfo_has_message_digest, &sinfo->aa_set) ||
+           (ctx->msg->data_type == OID_msIndirectData &&
+            !test_bit(sinfo_has_ms_opus_info, &sinfo->aa_set))) {
+               pr_warn("Missing required AuthAttr\n");
+               return -EBADMSG;
+       }
+
+       if (ctx->msg->data_type != OID_msIndirectData &&
+           test_bit(sinfo_has_ms_opus_info, &sinfo->aa_set)) {
+               pr_warn("Unexpected Authenticode AuthAttr\n");
+               return -EBADMSG;
+       }
 
        /* We need to switch the 'CONT 0' to a 'SET OF' when we digest */
-       ctx->sinfo->authattrs = value - (hdrlen - 1);
-       ctx->sinfo->authattrs_len = vlen + (hdrlen - 1);
+       sinfo->authattrs = value - (hdrlen - 1);
+       sinfo->authattrs_len = vlen + (hdrlen - 1);
        return 0;
 }
 
@@ -511,6 +632,11 @@ int pkcs7_note_signed_info(void *context, size_t hdrlen,
        struct pkcs7_signed_info *sinfo = ctx->sinfo;
        struct asymmetric_key_id *kid;
 
+       if (ctx->msg->data_type == OID_msIndirectData && !sinfo->authattrs) {
+               pr_warn("Authenticode requires AuthAttrs\n");
+               return -EBADMSG;
+       }
+
        /* Generate cert issuer + serial number key ID */
        if (!ctx->expect_skid) {
                kid = asymmetric_key_generate_id(ctx->raw_serial,
index 790dd7cec82c3640135e728ceaac080eb7434054..a66b19ebcf47e4d74bddbb4c7bf475303399bcc3 100644 (file)
@@ -21,9 +21,9 @@
 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 */
+       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) */
        const void      *msgdigest;
@@ -32,6 +32,14 @@ struct pkcs7_signed_info {
        /* Authenticated Attribute data (or NULL) */
        unsigned        authattrs_len;
        const void      *authattrs;
+       unsigned long   aa_set;
+#define        sinfo_has_content_type          0
+#define        sinfo_has_signing_time          1
+#define        sinfo_has_message_digest        2
+#define sinfo_has_smime_caps           3
+#define        sinfo_has_ms_opus_info          4
+#define        sinfo_has_ms_statement_type     5
+       time64_t        signing_time;
 
        /* Issuing cert serial number and issuer's name [PKCS#7 or CMS ver 1]
         * or issuing cert's SKID [CMS ver 3].
@@ -53,6 +61,7 @@ struct pkcs7_message {
        struct x509_certificate *crl;   /* Revocation list */
        struct pkcs7_signed_info *signed_infos;
        u8              version;        /* Version of cert (1 -> PKCS#7 or CMS; 3 -> CMS) */
+       bool            have_authattrs; /* T if have authattrs */
 
        /* Content Data (or NULL) */
        enum OID        data_type;      /* Type of Data */
index 404f89a0f85252d5d2f3606382f6b16a8c7fc5b1..d20c0b4b880ed1e6dde6552cfce4c6d85a05b053 100644 (file)
@@ -70,9 +70,15 @@ static int pkcs7_digest(struct pkcs7_message *pkcs7,
         * message digest attribute amongst them which corresponds to the
         * digest we just calculated.
         */
-       if (sinfo->msgdigest) {
+       if (sinfo->authattrs) {
                u8 tag;
 
+               if (!sinfo->msgdigest) {
+                       pr_warn("Sig %u: No messageDigest\n", sinfo->index);
+                       ret = -EKEYREJECTED;
+                       goto error;
+               }
+
                if (sinfo->msgdigest_len != sinfo->sig.digest_size) {
                        pr_debug("Sig %u: Invalid digest size (%u)\n",
                                 sinfo->index, sinfo->msgdigest_len);
@@ -314,6 +320,18 @@ static int pkcs7_verify_one(struct pkcs7_message *pkcs7,
        pr_devel("Using X.509[%u] for sig %u\n",
                 sinfo->signer->index, sinfo->index);
 
+       /* Check that the PKCS#7 signing time is valid according to the X.509
+        * certificate.  We can't, however, check against the system clock
+        * since that may not have been set yet and may be wrong.
+        */
+       if (test_bit(sinfo_has_signing_time, &sinfo->aa_set)) {
+               if (sinfo->signing_time < sinfo->signer->valid_from ||
+                   sinfo->signing_time > sinfo->signer->valid_to) {
+                       pr_warn("Message signed outside of X.509 validity window\n");
+                       return -EKEYREJECTED;
+               }
+       }
+
        /* Verify the PKCS#7 binary against the key */
        ret = public_key_verify_signature(sinfo->signer->pub, &sinfo->sig);
        if (ret < 0)
@@ -328,6 +346,7 @@ static int pkcs7_verify_one(struct pkcs7_message *pkcs7,
 /**
  * pkcs7_verify - Verify a PKCS#7 message
  * @pkcs7: The PKCS#7 message to be verified
+ * @usage: The use to which the key is being put
  *
  * Verify a PKCS#7 message is internally consistent - that is, the data digest
  * matches the digest in the AuthAttrs and any signature in the message or one
@@ -339,6 +358,9 @@ static int pkcs7_verify_one(struct pkcs7_message *pkcs7,
  *
  * Returns, in order of descending priority:
  *
+ *  (*) -EKEYREJECTED if a key was selected that had a usage restriction at
+ *      odds with the specified usage, or:
+ *
  *  (*) -EKEYREJECTED if a signature failed to match for which we found an
  *     appropriate X.509 certificate, or:
  *
@@ -350,7 +372,8 @@ static int pkcs7_verify_one(struct pkcs7_message *pkcs7,
  *  (*) 0 if all the signature chains that don't incur -ENOPKG can be verified
  *     (note that a signature chain may be of zero length), or:
  */
-int pkcs7_verify(struct pkcs7_message *pkcs7)
+int pkcs7_verify(struct pkcs7_message *pkcs7,
+                enum key_being_used_for usage)
 {
        struct pkcs7_signed_info *sinfo;
        struct x509_certificate *x509;
@@ -359,6 +382,44 @@ int pkcs7_verify(struct pkcs7_message *pkcs7)
 
        kenter("");
 
+       switch (usage) {
+       case VERIFYING_MODULE_SIGNATURE:
+               if (pkcs7->data_type != OID_data) {
+                       pr_warn("Invalid module sig (not pkcs7-data)\n");
+                       return -EKEYREJECTED;
+               }
+               if (pkcs7->have_authattrs) {
+                       pr_warn("Invalid module sig (has authattrs)\n");
+                       return -EKEYREJECTED;
+               }
+               break;
+       case VERIFYING_FIRMWARE_SIGNATURE:
+               if (pkcs7->data_type != OID_data) {
+                       pr_warn("Invalid firmware sig (not pkcs7-data)\n");
+                       return -EKEYREJECTED;
+               }
+               if (!pkcs7->have_authattrs) {
+                       pr_warn("Invalid firmware sig (missing authattrs)\n");
+                       return -EKEYREJECTED;
+               }
+               break;
+       case VERIFYING_KEXEC_PE_SIGNATURE:
+               if (pkcs7->data_type != OID_msIndirectData) {
+                       pr_warn("Invalid kexec sig (not Authenticode)\n");
+                       return -EKEYREJECTED;
+               }
+               /* Authattr presence checked in parser */
+               break;
+       case VERIFYING_UNSPECIFIED_SIGNATURE:
+               if (pkcs7->data_type != OID_data) {
+                       pr_warn("Invalid unspecified sig (not pkcs7-data)\n");
+                       return -EKEYREJECTED;
+               }
+               break;
+       default:
+               return -EINVAL;
+       }
+
        for (n = 0, x509 = pkcs7->certs; x509; x509 = x509->next, n++) {
                ret = x509_get_sig_params(x509);
                if (ret < 0)
index 2421f46184ce873076fe3cfc0f195a2d7bf4f902..897b734dabf9ba7ebc7d356707927c789b9175c9 100644 (file)
@@ -393,6 +393,7 @@ error_no_desc:
  * @pebuf: Buffer containing the PE binary image
  * @pelen: Length of the binary image
  * @trust_keyring: Signing certificates to use as starting points
+ * @usage: The use to which the key is being put.
  * @_trusted: Set to true if trustworth, false otherwise
  *
  * Validate that the certificate chain inside the PKCS#7 message inside the PE
@@ -417,7 +418,9 @@ error_no_desc:
  * May also return -ENOMEM.
  */
 int verify_pefile_signature(const void *pebuf, unsigned pelen,
-                           struct key *trusted_keyring, bool *_trusted)
+                           struct key *trusted_keyring,
+                           enum key_being_used_for usage,
+                           bool *_trusted)
 {
        struct pkcs7_message *pkcs7;
        struct pefile_context ctx;
@@ -462,7 +465,7 @@ int verify_pefile_signature(const void *pebuf, unsigned pelen,
        if (ret < 0)
                goto error;
 
-       ret = pkcs7_verify(pkcs7);
+       ret = pkcs7_verify(pkcs7, usage);
        if (ret < 0)
                goto error;
 
index e235ab4957ee904280e0bc32e4111c4fcfd1f599..441aff9b5aa75923e66566d93fdcd544d948b00f 100644 (file)
@@ -9,6 +9,11 @@
  * 2 of the Licence, or (at your option) any later version.
  */
 
+#ifndef _CRYPTO_PKCS7_H
+#define _CRYPTO_PKCS7_H
+
+#include <crypto/public_key.h>
+
 struct key;
 struct pkcs7_message;
 
@@ -33,7 +38,10 @@ extern int pkcs7_validate_trust(struct pkcs7_message *pkcs7,
 /*
  * pkcs7_verify.c
  */
-extern int pkcs7_verify(struct pkcs7_message *pkcs7);
+extern int pkcs7_verify(struct pkcs7_message *pkcs7,
+                       enum key_being_used_for usage);
 
 extern int pkcs7_supply_detached_data(struct pkcs7_message *pkcs7,
                                      const void *data, size_t datalen);
+
+#endif /* _CRYPTO_PKCS7_H */
index fda097e079a4cc166e0a0d8e5047069564392f5c..067c242b1e152d013f746424ceebd417112154a7 100644 (file)
@@ -39,6 +39,20 @@ enum pkey_id_type {
 
 extern const char *const pkey_id_type_name[PKEY_ID_TYPE__LAST];
 
+/*
+ * The use to which an asymmetric key is being put.
+ */
+enum key_being_used_for {
+       VERIFYING_MODULE_SIGNATURE,
+       VERIFYING_FIRMWARE_SIGNATURE,
+       VERIFYING_KEXEC_PE_SIGNATURE,
+       VERIFYING_KEY_SIGNATURE,
+       VERIFYING_KEY_SELF_SIGNATURE,
+       VERIFYING_UNSPECIFIED_SIGNATURE,
+       NR__KEY_BEING_USED_FOR
+};
+extern const char *const key_being_used_for[NR__KEY_BEING_USED_FOR];
+
 /*
  * Cryptographic data for the public-key subtype of the asymmetric key type.
  *
index 9791c907cdb70c502e570f26eb20060f5763d71d..b20cd885c1fd84b01d5b5602177777a74ea64810 100644 (file)
@@ -15,6 +15,7 @@
 #ifdef CONFIG_SYSTEM_TRUSTED_KEYRING
 
 #include <linux/key.h>
+#include <crypto/public_key.h>
 
 extern struct key *system_trusted_keyring;
 static inline struct key *get_system_trusted_keyring(void)
@@ -30,7 +31,8 @@ static inline struct key *get_system_trusted_keyring(void)
 
 #ifdef CONFIG_SYSTEM_DATA_VERIFICATION
 extern int system_verify_data(const void *data, unsigned long len,
-                             const void *raw_pkcs7, size_t pkcs7_len);
+                             const void *raw_pkcs7, size_t pkcs7_len,
+                             enum key_being_used_for usage);
 #endif
 
 #endif /* _KEYS_SYSTEM_KEYRING_H */
index c2bbf672b84eb58e767bc82882c49761b07abee6..93e0ff92fb9b6282eaf01cd4fa875e5c87934e33 100644 (file)
@@ -41,7 +41,7 @@ enum OID {
        OID_signed_data,                /* 1.2.840.113549.1.7.2 */
        /* PKCS#9 {iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs-9(9)} */
        OID_email_address,              /* 1.2.840.113549.1.9.1 */
-       OID_content_type,               /* 1.2.840.113549.1.9.3 */
+       OID_contentType,                /* 1.2.840.113549.1.9.3 */
        OID_messageDigest,              /* 1.2.840.113549.1.9.4 */
        OID_signingTime,                /* 1.2.840.113549.1.9.5 */
        OID_smimeCapabilites,           /* 1.2.840.113549.1.9.15 */
@@ -54,6 +54,8 @@ enum OID {
 
        /* Microsoft Authenticode & Software Publishing */
        OID_msIndirectData,             /* 1.3.6.1.4.1.311.2.1.4 */
+       OID_msStatementType,            /* 1.3.6.1.4.1.311.2.1.11 */
+       OID_msSpOpusInfo,               /* 1.3.6.1.4.1.311.2.1.12 */
        OID_msPeImageDataObjId,         /* 1.3.6.1.4.1.311.2.1.15 */
        OID_msIndividualSPKeyPurpose,   /* 1.3.6.1.4.1.311.2.1.21 */
        OID_msOutlookExpress,           /* 1.3.6.1.4.1.311.16.4 */
index ac34819214f9133c2800f79b3dff7d90562a1573..da2049b5161ce77f17eeff22eabb6c0743640433 100644 (file)
 #ifndef _LINUX_VERIFY_PEFILE_H
 #define _LINUX_VERIFY_PEFILE_H
 
+#include <crypto/public_key.h>
+
 extern int verify_pefile_signature(const void *pebuf, unsigned pelen,
-                                  struct key *trusted_keyring, bool *_trusted);
+                                  struct key *trusted_keyring,
+                                  enum key_being_used_for usage,
+                                  bool *_trusted);
 
 #endif /* _LINUX_VERIFY_PEFILE_H */
index 70ad463f6df059c43267490da7fcfa0744cec6d4..bd62f5cda74673377ef080c718163917387ddde0 100644 (file)
@@ -72,5 +72,6 @@ int mod_verify_sig(const void *mod, unsigned long *_modlen)
                return -EBADMSG;
        }
 
-       return system_verify_data(mod, modlen, mod + modlen, sig_len);
+       return system_verify_data(mod, modlen, mod + modlen, sig_len,
+                                 VERIFYING_MODULE_SIGNATURE);
 }
index 95f2dcbc761626dfad3f61d48ce6073396576a21..2570598b784de05e9030d3e08aca1c199b2a8fc6 100644 (file)
@@ -113,9 +113,11 @@ 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.
+ * @usage: The use to which the key is being put.
  */
 int system_verify_data(const void *data, unsigned long len,
-                      const void *raw_pkcs7, size_t pkcs7_len)
+                      const void *raw_pkcs7, size_t pkcs7_len,
+                      enum key_being_used_for usage)
 {
        struct pkcs7_message *pkcs7;
        bool trusted;
@@ -132,7 +134,7 @@ int system_verify_data(const void *data, unsigned long len,
                goto error;
        }
 
-       ret = pkcs7_verify(pkcs7);
+       ret = pkcs7_verify(pkcs7, usage);
        if (ret < 0)
                goto error;
 
index de213e5c0cd3be97028c7f2057a6ea0eb158a594..e9741e879bbdd0f29691446e7c31f97892fc729d 100755 (executable)
@@ -111,7 +111,7 @@ int main(int argc, char **argv)
        bool sign_only = false;
        unsigned char buf[4096];
        unsigned long module_size, cms_size;
-       unsigned int use_keyid = 0;
+       unsigned int use_keyid = 0, use_signed_attrs = CMS_NOATTR;
        const EVP_MD *digest_algo;
        EVP_PKEY *private_key;
        CMS_ContentInfo *cms;
@@ -216,7 +216,8 @@ int main(int argc, char **argv)
        ERR(!cms, "CMS_sign");
 
        ERR(!CMS_add1_signer(cms, x509, private_key, digest_algo,
-                            CMS_NOCERTS | CMS_BINARY | CMS_NOSMIMECAP | use_keyid),
+                            CMS_NOCERTS | CMS_BINARY | CMS_NOSMIMECAP |
+                            use_keyid | use_signed_attrs),
            "CMS_sign_add_signer");
        ERR(CMS_final(cms, bm, NULL, CMS_NOCERTS | CMS_BINARY) < 0,
            "CMS_final");