2014-07-01 23:40:19 +08:00
|
|
|
/* PKCS#7 parser
|
|
|
|
*
|
|
|
|
* 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) "PKCS7: "fmt
|
|
|
|
#include <linux/kernel.h>
|
|
|
|
#include <linux/export.h>
|
|
|
|
#include <linux/slab.h>
|
|
|
|
#include <linux/err.h>
|
|
|
|
#include <linux/oid_registry.h>
|
2016-02-03 02:08:53 +08:00
|
|
|
#include <crypto/public_key.h>
|
2014-07-01 23:40:19 +08:00
|
|
|
#include "pkcs7_parser.h"
|
|
|
|
#include "pkcs7-asn1.h"
|
|
|
|
|
|
|
|
struct pkcs7_parse_context {
|
|
|
|
struct pkcs7_message *msg; /* Message being constructed */
|
|
|
|
struct pkcs7_signed_info *sinfo; /* SignedInfo being constructed */
|
|
|
|
struct pkcs7_signed_info **ppsinfo;
|
|
|
|
struct x509_certificate *certs; /* Certificate cache */
|
|
|
|
struct x509_certificate **ppcerts;
|
|
|
|
unsigned long data; /* Start of data */
|
|
|
|
enum OID last_oid; /* Last OID encountered */
|
|
|
|
unsigned x509_index;
|
|
|
|
unsigned sinfo_index;
|
2014-09-17 00:36:13 +08:00
|
|
|
const void *raw_serial;
|
|
|
|
unsigned raw_serial_size;
|
|
|
|
unsigned raw_issuer_size;
|
|
|
|
const void *raw_issuer;
|
2015-07-21 04:16:33 +08:00
|
|
|
const void *raw_skid;
|
|
|
|
unsigned raw_skid_size;
|
|
|
|
bool expect_skid;
|
2014-07-01 23:40:19 +08:00
|
|
|
};
|
|
|
|
|
2014-09-17 00:29:03 +08:00
|
|
|
/*
|
|
|
|
* Free a signed information block.
|
|
|
|
*/
|
|
|
|
static void pkcs7_free_signed_info(struct pkcs7_signed_info *sinfo)
|
|
|
|
{
|
|
|
|
if (sinfo) {
|
2016-02-03 02:08:53 +08:00
|
|
|
kfree(sinfo->sig.s);
|
2014-09-17 00:29:03 +08:00
|
|
|
kfree(sinfo->sig.digest);
|
2014-09-17 00:36:13 +08:00
|
|
|
kfree(sinfo->signing_cert_id);
|
2014-09-17 00:29:03 +08:00
|
|
|
kfree(sinfo);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-01 23:40:19 +08:00
|
|
|
/**
|
|
|
|
* pkcs7_free_message - Free a PKCS#7 message
|
|
|
|
* @pkcs7: The PKCS#7 message to free
|
|
|
|
*/
|
|
|
|
void pkcs7_free_message(struct pkcs7_message *pkcs7)
|
|
|
|
{
|
|
|
|
struct x509_certificate *cert;
|
|
|
|
struct pkcs7_signed_info *sinfo;
|
|
|
|
|
|
|
|
if (pkcs7) {
|
|
|
|
while (pkcs7->certs) {
|
|
|
|
cert = pkcs7->certs;
|
|
|
|
pkcs7->certs = cert->next;
|
|
|
|
x509_free_certificate(cert);
|
|
|
|
}
|
|
|
|
while (pkcs7->crl) {
|
|
|
|
cert = pkcs7->crl;
|
|
|
|
pkcs7->crl = cert->next;
|
|
|
|
x509_free_certificate(cert);
|
|
|
|
}
|
|
|
|
while (pkcs7->signed_infos) {
|
|
|
|
sinfo = pkcs7->signed_infos;
|
|
|
|
pkcs7->signed_infos = sinfo->next;
|
2014-09-17 00:29:03 +08:00
|
|
|
pkcs7_free_signed_info(sinfo);
|
2014-07-01 23:40:19 +08:00
|
|
|
}
|
|
|
|
kfree(pkcs7);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(pkcs7_free_message);
|
|
|
|
|
PKCS#7: Appropriately restrict authenticated attributes and content type
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>
2015-08-05 22:22:27 +08:00
|
|
|
/*
|
|
|
|
* 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;
|
|
|
|
}
|
|
|
|
|
2014-07-01 23:40:19 +08:00
|
|
|
/**
|
|
|
|
* pkcs7_parse_message - Parse a PKCS#7 message
|
|
|
|
* @data: The raw binary ASN.1 encoded message to be parsed
|
|
|
|
* @datalen: The size of the encoded message
|
|
|
|
*/
|
|
|
|
struct pkcs7_message *pkcs7_parse_message(const void *data, size_t datalen)
|
|
|
|
{
|
|
|
|
struct pkcs7_parse_context *ctx;
|
2014-09-17 00:29:03 +08:00
|
|
|
struct pkcs7_message *msg = ERR_PTR(-ENOMEM);
|
|
|
|
int ret;
|
2014-07-01 23:40:19 +08:00
|
|
|
|
|
|
|
ctx = kzalloc(sizeof(struct pkcs7_parse_context), GFP_KERNEL);
|
|
|
|
if (!ctx)
|
2014-09-17 00:29:03 +08:00
|
|
|
goto out_no_ctx;
|
|
|
|
ctx->msg = kzalloc(sizeof(struct pkcs7_message), GFP_KERNEL);
|
|
|
|
if (!ctx->msg)
|
|
|
|
goto out_no_msg;
|
2014-07-01 23:40:19 +08:00
|
|
|
ctx->sinfo = kzalloc(sizeof(struct pkcs7_signed_info), GFP_KERNEL);
|
|
|
|
if (!ctx->sinfo)
|
2014-09-17 00:29:03 +08:00
|
|
|
goto out_no_sinfo;
|
2014-07-01 23:40:19 +08:00
|
|
|
|
|
|
|
ctx->data = (unsigned long)data;
|
|
|
|
ctx->ppcerts = &ctx->certs;
|
|
|
|
ctx->ppsinfo = &ctx->msg->signed_infos;
|
|
|
|
|
|
|
|
/* Attempt to decode the signature */
|
|
|
|
ret = asn1_ber_decoder(&pkcs7_decoder, ctx, data, datalen);
|
2014-09-17 00:29:03 +08:00
|
|
|
if (ret < 0) {
|
|
|
|
msg = ERR_PTR(ret);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
PKCS#7: Appropriately restrict authenticated attributes and content type
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>
2015-08-05 22:22:27 +08:00
|
|
|
ret = pkcs7_check_authattrs(ctx->msg);
|
|
|
|
if (ret < 0)
|
|
|
|
goto out;
|
|
|
|
|
2014-09-17 00:29:03 +08:00
|
|
|
msg = ctx->msg;
|
|
|
|
ctx->msg = NULL;
|
2014-07-01 23:40:19 +08:00
|
|
|
|
2014-09-17 00:29:03 +08:00
|
|
|
out:
|
2014-07-01 23:40:19 +08:00
|
|
|
while (ctx->certs) {
|
|
|
|
struct x509_certificate *cert = ctx->certs;
|
|
|
|
ctx->certs = cert->next;
|
|
|
|
x509_free_certificate(cert);
|
|
|
|
}
|
2014-09-17 00:29:03 +08:00
|
|
|
pkcs7_free_signed_info(ctx->sinfo);
|
2014-09-17 00:29:03 +08:00
|
|
|
out_no_sinfo:
|
|
|
|
pkcs7_free_message(ctx->msg);
|
|
|
|
out_no_msg:
|
2014-07-01 23:40:19 +08:00
|
|
|
kfree(ctx);
|
2014-09-17 00:29:03 +08:00
|
|
|
out_no_ctx:
|
2014-07-01 23:40:19 +08:00
|
|
|
return msg;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(pkcs7_parse_message);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* pkcs7_get_content_data - Get access to the PKCS#7 content
|
|
|
|
* @pkcs7: The preparsed PKCS#7 message to access
|
|
|
|
* @_data: Place to return a pointer to the data
|
|
|
|
* @_data_len: Place to return the data length
|
|
|
|
* @want_wrapper: True if the ASN.1 object header should be included in the data
|
|
|
|
*
|
|
|
|
* Get access to the data content of the PKCS#7 message, including, optionally,
|
|
|
|
* the header of the ASN.1 object that contains it. Returns -ENODATA if the
|
|
|
|
* data object was missing from the message.
|
|
|
|
*/
|
|
|
|
int pkcs7_get_content_data(const struct pkcs7_message *pkcs7,
|
|
|
|
const void **_data, size_t *_data_len,
|
|
|
|
bool want_wrapper)
|
|
|
|
{
|
|
|
|
size_t wrapper;
|
|
|
|
|
|
|
|
if (!pkcs7->data)
|
|
|
|
return -ENODATA;
|
|
|
|
|
|
|
|
wrapper = want_wrapper ? pkcs7->data_hdrlen : 0;
|
|
|
|
*_data = pkcs7->data - wrapper;
|
|
|
|
*_data_len = pkcs7->data_len + wrapper;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
EXPORT_SYMBOL_GPL(pkcs7_get_content_data);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Note an OID when we find one for later processing when we know how
|
|
|
|
* to interpret it.
|
|
|
|
*/
|
|
|
|
int pkcs7_note_OID(void *context, size_t hdrlen,
|
|
|
|
unsigned char tag,
|
|
|
|
const void *value, size_t vlen)
|
|
|
|
{
|
|
|
|
struct pkcs7_parse_context *ctx = context;
|
|
|
|
|
|
|
|
ctx->last_oid = look_up_OID(value, vlen);
|
|
|
|
if (ctx->last_oid == OID__NR) {
|
|
|
|
char buffer[50];
|
|
|
|
sprint_oid(value, vlen, buffer, sizeof(buffer));
|
|
|
|
printk("PKCS7: Unknown OID: [%lu] %s\n",
|
|
|
|
(unsigned long)value - ctx->data, buffer);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Note the digest algorithm for the signature.
|
|
|
|
*/
|
|
|
|
int pkcs7_sig_note_digest_algo(void *context, size_t hdrlen,
|
|
|
|
unsigned char tag,
|
|
|
|
const void *value, size_t vlen)
|
|
|
|
{
|
|
|
|
struct pkcs7_parse_context *ctx = context;
|
|
|
|
|
|
|
|
switch (ctx->last_oid) {
|
|
|
|
case OID_md4:
|
|
|
|
ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_MD4;
|
|
|
|
break;
|
|
|
|
case OID_md5:
|
|
|
|
ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_MD5;
|
|
|
|
break;
|
|
|
|
case OID_sha1:
|
|
|
|
ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_SHA1;
|
|
|
|
break;
|
|
|
|
case OID_sha256:
|
|
|
|
ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_SHA256;
|
|
|
|
break;
|
2015-08-30 23:59:57 +08:00
|
|
|
case OID_sha384:
|
|
|
|
ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_SHA384;
|
|
|
|
break;
|
|
|
|
case OID_sha512:
|
|
|
|
ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_SHA512;
|
|
|
|
break;
|
|
|
|
case OID_sha224:
|
|
|
|
ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_SHA224;
|
2014-07-01 23:40:19 +08:00
|
|
|
default:
|
|
|
|
printk("Unsupported digest algo: %u\n", ctx->last_oid);
|
|
|
|
return -ENOPKG;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Note the public key algorithm for the signature.
|
|
|
|
*/
|
|
|
|
int pkcs7_sig_note_pkey_algo(void *context, size_t hdrlen,
|
|
|
|
unsigned char tag,
|
|
|
|
const void *value, size_t vlen)
|
|
|
|
{
|
|
|
|
struct pkcs7_parse_context *ctx = context;
|
|
|
|
|
|
|
|
switch (ctx->last_oid) {
|
|
|
|
case OID_rsaEncryption:
|
|
|
|
ctx->sinfo->sig.pkey_algo = PKEY_ALGO_RSA;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
printk("Unsupported pkey algo: %u\n", ctx->last_oid);
|
|
|
|
return -ENOPKG;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-07-21 04:16:31 +08:00
|
|
|
/*
|
|
|
|
* We only support signed data [RFC2315 sec 9].
|
|
|
|
*/
|
|
|
|
int pkcs7_check_content_type(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_signed_data) {
|
|
|
|
pr_warn("Only support pkcs7_signedData type\n");
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Note the SignedData version
|
|
|
|
*/
|
|
|
|
int pkcs7_note_signeddata_version(void *context, size_t hdrlen,
|
|
|
|
unsigned char tag,
|
|
|
|
const void *value, size_t vlen)
|
|
|
|
{
|
2015-07-21 04:16:33 +08:00
|
|
|
struct pkcs7_parse_context *ctx = context;
|
2015-07-21 04:16:31 +08:00
|
|
|
unsigned version;
|
|
|
|
|
|
|
|
if (vlen != 1)
|
|
|
|
goto unsupported;
|
|
|
|
|
2015-07-21 04:16:33 +08:00
|
|
|
ctx->msg->version = version = *(const u8 *)value;
|
2015-07-21 04:16:31 +08:00
|
|
|
switch (version) {
|
|
|
|
case 1:
|
2015-07-21 04:16:33 +08:00
|
|
|
/* PKCS#7 SignedData [RFC2315 sec 9.1]
|
|
|
|
* CMS ver 1 SignedData [RFC5652 sec 5.1]
|
|
|
|
*/
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
/* CMS ver 3 SignedData [RFC2315 sec 5.1] */
|
2015-07-21 04:16:31 +08:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
goto unsupported;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
unsupported:
|
|
|
|
pr_warn("Unsupported SignedData version\n");
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Note the SignerInfo version
|
|
|
|
*/
|
|
|
|
int pkcs7_note_signerinfo_version(void *context, size_t hdrlen,
|
|
|
|
unsigned char tag,
|
|
|
|
const void *value, size_t vlen)
|
|
|
|
{
|
2015-07-21 04:16:33 +08:00
|
|
|
struct pkcs7_parse_context *ctx = context;
|
2015-07-21 04:16:31 +08:00
|
|
|
unsigned version;
|
|
|
|
|
|
|
|
if (vlen != 1)
|
|
|
|
goto unsupported;
|
|
|
|
|
|
|
|
version = *(const u8 *)value;
|
|
|
|
switch (version) {
|
|
|
|
case 1:
|
2015-07-21 04:16:33 +08:00
|
|
|
/* PKCS#7 SignerInfo [RFC2315 sec 9.2]
|
|
|
|
* CMS ver 1 SignerInfo [RFC5652 sec 5.3]
|
|
|
|
*/
|
|
|
|
if (ctx->msg->version != 1)
|
|
|
|
goto version_mismatch;
|
|
|
|
ctx->expect_skid = false;
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
/* CMS ver 3 SignerInfo [RFC2315 sec 5.3] */
|
|
|
|
if (ctx->msg->version == 1)
|
|
|
|
goto version_mismatch;
|
|
|
|
ctx->expect_skid = true;
|
2015-07-21 04:16:31 +08:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
goto unsupported;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
unsupported:
|
|
|
|
pr_warn("Unsupported SignerInfo version\n");
|
|
|
|
return -EINVAL;
|
2015-07-21 04:16:33 +08:00
|
|
|
version_mismatch:
|
|
|
|
pr_warn("SignedData-SignerInfo version mismatch\n");
|
|
|
|
return -EBADMSG;
|
2015-07-21 04:16:31 +08:00
|
|
|
}
|
|
|
|
|
2014-07-01 23:40:19 +08:00
|
|
|
/*
|
|
|
|
* Extract a certificate and store it in the context.
|
|
|
|
*/
|
|
|
|
int pkcs7_extract_cert(void *context, size_t hdrlen,
|
|
|
|
unsigned char tag,
|
|
|
|
const void *value, size_t vlen)
|
|
|
|
{
|
|
|
|
struct pkcs7_parse_context *ctx = context;
|
|
|
|
struct x509_certificate *x509;
|
|
|
|
|
|
|
|
if (tag != ((ASN1_UNIV << 6) | ASN1_CONS_BIT | ASN1_SEQ)) {
|
|
|
|
pr_debug("Cert began with tag %02x at %lu\n",
|
|
|
|
tag, (unsigned long)ctx - ctx->data);
|
|
|
|
return -EBADMSG;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* We have to correct for the header so that the X.509 parser can start
|
|
|
|
* from the beginning. Note that since X.509 stipulates DER, there
|
|
|
|
* probably shouldn't be an EOC trailer - but it is in PKCS#7 (which
|
|
|
|
* stipulates BER).
|
|
|
|
*/
|
|
|
|
value -= hdrlen;
|
|
|
|
vlen += hdrlen;
|
|
|
|
|
|
|
|
if (((u8*)value)[1] == 0x80)
|
|
|
|
vlen += 2; /* Indefinite length - there should be an EOC */
|
|
|
|
|
|
|
|
x509 = x509_cert_parse(value, vlen);
|
|
|
|
if (IS_ERR(x509))
|
|
|
|
return PTR_ERR(x509);
|
|
|
|
|
|
|
|
x509->index = ++ctx->x509_index;
|
2014-09-17 00:36:13 +08:00
|
|
|
pr_debug("Got cert %u for %s\n", x509->index, x509->subject);
|
|
|
|
pr_debug("- fingerprint %*phN\n", x509->id->len, x509->id->data);
|
|
|
|
|
2014-07-01 23:40:19 +08:00
|
|
|
*ctx->ppcerts = x509;
|
|
|
|
ctx->ppcerts = &x509->next;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Save the certificate list
|
|
|
|
*/
|
|
|
|
int pkcs7_note_certificate_list(void *context, size_t hdrlen,
|
|
|
|
unsigned char tag,
|
|
|
|
const void *value, size_t vlen)
|
|
|
|
{
|
|
|
|
struct pkcs7_parse_context *ctx = context;
|
|
|
|
|
|
|
|
pr_devel("Got cert list (%02x)\n", tag);
|
|
|
|
|
|
|
|
*ctx->ppcerts = ctx->msg->certs;
|
|
|
|
ctx->msg->certs = ctx->certs;
|
|
|
|
ctx->certs = NULL;
|
|
|
|
ctx->ppcerts = &ctx->certs;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
PKCS#7: Appropriately restrict authenticated attributes and content type
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>
2015-08-05 22:22:27 +08:00
|
|
|
/*
|
|
|
|
* 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;
|
|
|
|
}
|
|
|
|
|
2014-07-01 23:40:19 +08:00
|
|
|
/*
|
|
|
|
* Extract the data from the message and store that and its content type OID in
|
|
|
|
* the context.
|
|
|
|
*/
|
|
|
|
int pkcs7_note_data(void *context, size_t hdrlen,
|
|
|
|
unsigned char tag,
|
|
|
|
const void *value, size_t vlen)
|
|
|
|
{
|
|
|
|
struct pkcs7_parse_context *ctx = context;
|
|
|
|
|
|
|
|
pr_debug("Got data\n");
|
|
|
|
|
|
|
|
ctx->msg->data = value;
|
|
|
|
ctx->msg->data_len = vlen;
|
|
|
|
ctx->msg->data_hdrlen = hdrlen;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
PKCS#7: Appropriately restrict authenticated attributes and content type
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>
2015-08-05 22:22:27 +08:00
|
|
|
* Parse authenticated attributes.
|
2014-07-01 23:40:19 +08:00
|
|
|
*/
|
|
|
|
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;
|
PKCS#7: Appropriately restrict authenticated attributes and content type
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>
2015-08-05 22:22:27 +08:00
|
|
|
struct pkcs7_signed_info *sinfo = ctx->sinfo;
|
|
|
|
enum OID content_type;
|
2014-07-01 23:40:19 +08:00
|
|
|
|
|
|
|
pr_devel("AuthAttr: %02x %zu [%*ph]\n", tag, vlen, (unsigned)vlen, value);
|
|
|
|
|
|
|
|
switch (ctx->last_oid) {
|
PKCS#7: Appropriately restrict authenticated attributes and content type
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>
2015-08-05 22:22:27 +08:00
|
|
|
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);
|
|
|
|
|
2014-07-01 23:40:19 +08:00
|
|
|
case OID_messageDigest:
|
PKCS#7: Appropriately restrict authenticated attributes and content type
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>
2015-08-05 22:22:27 +08:00
|
|
|
if (__test_and_set_bit(sinfo_has_message_digest, &sinfo->aa_set))
|
|
|
|
goto repeated;
|
2014-07-01 23:40:19 +08:00
|
|
|
if (tag != ASN1_OTS)
|
|
|
|
return -EBADMSG;
|
PKCS#7: Appropriately restrict authenticated attributes and content type
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>
2015-08-05 22:22:27 +08:00
|
|
|
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 */
|
2014-07-01 23:40:19 +08:00
|
|
|
return 0;
|
|
|
|
default:
|
|
|
|
return 0;
|
|
|
|
}
|
PKCS#7: Appropriately restrict authenticated attributes and content type
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>
2015-08-05 22:22:27 +08:00
|
|
|
|
|
|
|
repeated:
|
|
|
|
/* We permit max one item per AuthenticatedAttribute and no repeats */
|
|
|
|
pr_warn("Repeated/multivalue AuthAttrs not permitted\n");
|
|
|
|
return -EKEYREJECTED;
|
2014-07-01 23:40:19 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2015-07-21 04:16:31 +08:00
|
|
|
* Note the set of auth attributes for digestion purposes [RFC2315 sec 9.3]
|
2014-07-01 23:40:19 +08:00
|
|
|
*/
|
|
|
|
int pkcs7_sig_note_set_of_authattrs(void *context, size_t hdrlen,
|
|
|
|
unsigned char tag,
|
|
|
|
const void *value, size_t vlen)
|
|
|
|
{
|
|
|
|
struct pkcs7_parse_context *ctx = context;
|
PKCS#7: Appropriately restrict authenticated attributes and content type
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>
2015-08-05 22:22:27 +08:00
|
|
|
struct pkcs7_signed_info *sinfo = ctx->sinfo;
|
|
|
|
|
|
|
|
if (!test_bit(sinfo_has_content_type, &sinfo->aa_set) ||
|
PKCS#7: Don't require SpcSpOpusInfo in Authenticode pkcs7 signatures
Dave Young reported:
> Hi,
>
> I saw the warning "Missing required AuthAttr" when testing kexec,
> known issue? Idea about how to fix it?
>
> The kernel is latest linus tree plus sevral patches from Toshi to
> cleanup io resource structure.
>
> in function pkcs7_sig_note_set_of_authattrs():
> 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;
> }
>
> The third condition below is true:
> (ctx->msg->data_type == OID_msIndirectData &&
> !test_bit(sinfo_has_ms_opus_info, &sinfo->aa_set))
>
> I signed the kernel with redhat test key like below:
> pesign -c 'Red Hat Test Certificate' -i arch/x86/boot/bzImage -o /boot/vmlinuz-4.4.0-rc8+ -s --force
And right he is! The Authenticode specification is a paragon amongst
technical documents, and has this pearl of wisdom to offer:
---------------------------------
Authenticode-Specific SignerInfo UnauthenticatedAttributes Structures
The following Authenticode-specific data structures are present in
SignerInfo authenticated attributes.
SpcSpOpusInfo
SpcSpOpusInfo is identified by SPC_SP_OPUS_INFO_OBJID
(1.3.6.1.4.1.311.2.1.12) and is defined as follows:
SpcSpOpusInfo ::= SEQUENCE {
programName [0] EXPLICIT SpcString OPTIONAL,
moreInfo [1] EXPLICIT SpcLink OPTIONAL,
} --#public--
SpcSpOpusInfo has two fields:
programName
This field contains the program description:
If publisher chooses not to specify a description, the SpcString
structure contains a zero-length program name.
If the publisher chooses to specify a
description, the SpcString structure contains a Unicode string.
moreInfo
This field is set to an SPCLink structure that contains a URL for
a Web site with more information about the signer. The URL is an
ASCII string.
---------------------------------
Which is to say that this is an optional *unauthenticated* field which
may be present in the Authenticated Attribute list. This is not how
pkcs7 is supposed to work, so when David implemented this, he didn't
appreciate the subtlety the original spec author was working with, and
missed the part of the sublime prose that says this Authenticated
Attribute is an Unauthenticated Attribute. As a result, the code in
question simply takes as given that the Authenticated Attributes should
be authenticated.
But this one should not, individually. Because it says it's not
authenticated.
It still has to hash right so the TBS digest is correct. So it is both
authenticated and unauthenticated, all at once. Truly, a wonder of
technical accomplishment.
Additionally, pesign's implementation has always attempted to be
compatible with the signatures emitted from contemporary versions of
Microsoft's signtool.exe. During the initial implementation, Microsoft
signatures always produced the same values for SpcSpOpusInfo -
{U"Microsoft Windows", "http://www.microsoft.com"} - without regard to
who the signer was.
Sometime between Windows 8 and Windows 8.1 they stopped including the
field in their signatures altogether, and as such pesign stopped
producing them in commits c0c4da6 and d79cb0c, sometime around June of
2012. The theory here is that anything that breaks with
pesign signatures would also be breaking with signtool.exe sigs as well,
and that'll be a more noticed problem for firmwares parsing it, so it'll
get fixed. The fact that we've done exactly this bug in Linux code is
first class, grade A irony.
So anyway, we should not be checking this field for presence or any
particular value: if the field exists, it should be at the right place,
but aside from that, as long as the hash matches the field is good.
Signed-off-by: Peter Jones <pjones@redhat.com>
Tested-by: Dave Young <dyoung@redhat.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
2016-01-18 23:49:58 +08:00
|
|
|
!test_bit(sinfo_has_message_digest, &sinfo->aa_set)) {
|
PKCS#7: Appropriately restrict authenticated attributes and content type
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>
2015-08-05 22:22:27 +08:00
|
|
|
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;
|
|
|
|
}
|
2014-07-01 23:40:19 +08:00
|
|
|
|
|
|
|
/* We need to switch the 'CONT 0' to a 'SET OF' when we digest */
|
PKCS#7: Appropriately restrict authenticated attributes and content type
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>
2015-08-05 22:22:27 +08:00
|
|
|
sinfo->authattrs = value - (hdrlen - 1);
|
|
|
|
sinfo->authattrs_len = vlen + (hdrlen - 1);
|
2014-07-01 23:40:19 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Note the issuing certificate serial number
|
|
|
|
*/
|
|
|
|
int pkcs7_sig_note_serial(void *context, size_t hdrlen,
|
|
|
|
unsigned char tag,
|
|
|
|
const void *value, size_t vlen)
|
|
|
|
{
|
|
|
|
struct pkcs7_parse_context *ctx = context;
|
2014-09-17 00:36:13 +08:00
|
|
|
ctx->raw_serial = value;
|
|
|
|
ctx->raw_serial_size = vlen;
|
2014-07-01 23:40:19 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Note the issuer's name
|
|
|
|
*/
|
|
|
|
int pkcs7_sig_note_issuer(void *context, size_t hdrlen,
|
|
|
|
unsigned char tag,
|
|
|
|
const void *value, size_t vlen)
|
|
|
|
{
|
|
|
|
struct pkcs7_parse_context *ctx = context;
|
2014-09-17 00:36:13 +08:00
|
|
|
ctx->raw_issuer = value;
|
|
|
|
ctx->raw_issuer_size = vlen;
|
2014-07-01 23:40:19 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2015-07-21 04:16:33 +08:00
|
|
|
/*
|
|
|
|
* Note the issuing cert's subjectKeyIdentifier
|
|
|
|
*/
|
|
|
|
int pkcs7_sig_note_skid(void *context, size_t hdrlen,
|
|
|
|
unsigned char tag,
|
|
|
|
const void *value, size_t vlen)
|
|
|
|
{
|
|
|
|
struct pkcs7_parse_context *ctx = context;
|
|
|
|
|
|
|
|
pr_devel("SKID: %02x %zu [%*ph]\n", tag, vlen, (unsigned)vlen, value);
|
|
|
|
|
|
|
|
ctx->raw_skid = value;
|
|
|
|
ctx->raw_skid_size = vlen;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-07-01 23:40:19 +08:00
|
|
|
/*
|
|
|
|
* Note the signature data
|
|
|
|
*/
|
|
|
|
int pkcs7_sig_note_signature(void *context, size_t hdrlen,
|
|
|
|
unsigned char tag,
|
|
|
|
const void *value, size_t vlen)
|
|
|
|
{
|
|
|
|
struct pkcs7_parse_context *ctx = context;
|
|
|
|
|
|
|
|
BUG_ON(ctx->sinfo->sig.pkey_algo != PKEY_ALGO_RSA);
|
|
|
|
|
2016-02-03 02:08:53 +08:00
|
|
|
ctx->sinfo->sig.s = kmemdup(value, vlen, GFP_KERNEL);
|
|
|
|
if (!ctx->sinfo->sig.s)
|
2014-07-01 23:40:19 +08:00
|
|
|
return -ENOMEM;
|
|
|
|
|
2016-02-03 02:08:53 +08:00
|
|
|
ctx->sinfo->sig.s_size = vlen;
|
2014-07-01 23:40:19 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Note a signature information block
|
|
|
|
*/
|
|
|
|
int pkcs7_note_signed_info(void *context, size_t hdrlen,
|
|
|
|
unsigned char tag,
|
|
|
|
const void *value, size_t vlen)
|
|
|
|
{
|
|
|
|
struct pkcs7_parse_context *ctx = context;
|
2014-09-17 00:36:13 +08:00
|
|
|
struct pkcs7_signed_info *sinfo = ctx->sinfo;
|
|
|
|
struct asymmetric_key_id *kid;
|
|
|
|
|
PKCS#7: Appropriately restrict authenticated attributes and content type
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>
2015-08-05 22:22:27 +08:00
|
|
|
if (ctx->msg->data_type == OID_msIndirectData && !sinfo->authattrs) {
|
|
|
|
pr_warn("Authenticode requires AuthAttrs\n");
|
|
|
|
return -EBADMSG;
|
|
|
|
}
|
|
|
|
|
2014-09-17 00:36:13 +08:00
|
|
|
/* Generate cert issuer + serial number key ID */
|
2015-07-21 04:16:33 +08:00
|
|
|
if (!ctx->expect_skid) {
|
|
|
|
kid = asymmetric_key_generate_id(ctx->raw_serial,
|
|
|
|
ctx->raw_serial_size,
|
|
|
|
ctx->raw_issuer,
|
|
|
|
ctx->raw_issuer_size);
|
|
|
|
} else {
|
|
|
|
kid = asymmetric_key_generate_id(ctx->raw_skid,
|
|
|
|
ctx->raw_skid_size,
|
|
|
|
"", 0);
|
|
|
|
}
|
2014-09-17 00:36:13 +08:00
|
|
|
if (IS_ERR(kid))
|
|
|
|
return PTR_ERR(kid);
|
|
|
|
|
2015-07-21 04:16:33 +08:00
|
|
|
pr_devel("SINFO KID: %u [%*phN]\n", kid->len, kid->len, kid->data);
|
|
|
|
|
2014-09-17 00:36:13 +08:00
|
|
|
sinfo->signing_cert_id = kid;
|
|
|
|
sinfo->index = ++ctx->sinfo_index;
|
|
|
|
*ctx->ppsinfo = sinfo;
|
|
|
|
ctx->ppsinfo = &sinfo->next;
|
2014-07-01 23:40:19 +08:00
|
|
|
ctx->sinfo = kzalloc(sizeof(struct pkcs7_signed_info), GFP_KERNEL);
|
|
|
|
if (!ctx->sinfo)
|
|
|
|
return -ENOMEM;
|
|
|
|
return 0;
|
|
|
|
}
|