Skip to content

Commit

Permalink
Merge tag 'keys-pkcs7-20140708' into keys-next
Browse files Browse the repository at this point in the history
Here's a set of changes that implement a PKCS#7 message parser in the kernel.

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

The changes provide the following facilities:

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

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

 (3) Follow the certificate chains and verify that:

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

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

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

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

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

Signed-off-by: David Howells <[email protected]>
  • Loading branch information
dhowells committed Jul 22, 2014
2 parents a19e3c2 + 22d01af commit 1ca72c9
Show file tree
Hide file tree
Showing 13 changed files with 1,339 additions and 2 deletions.
22 changes: 22 additions & 0 deletions crypto/asymmetric_keys/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,26 @@ config X509_CERTIFICATE_PARSER
data and provides the ability to instantiate a crypto key from a
public key packet found inside the certificate.

config PKCS7_MESSAGE_PARSER
tristate "PKCS#7 message parser"
depends on X509_CERTIFICATE_PARSER
select ASN1
select OID_REGISTRY
help
This option provides support for parsing PKCS#7 format messages for
signature data and provides the ability to verify the signature.

config PKCS7_TEST_KEY
tristate "PKCS#7 testing key type"
depends on PKCS7_MESSAGE_PARSER
select SYSTEM_TRUSTED_KEYRING
help
This option provides a type of key that can be loaded up from a
PKCS#7 message - provided the message is signed by a trusted key. If
it is, the PKCS#7 wrapper is discarded and reading the key returns
just the payload. If it isn't, adding the key will fail with an
error.

This is intended for testing the PKCS#7 parser.

endif # ASYMMETRIC_KEY_TYPE
22 changes: 22 additions & 0 deletions crypto/asymmetric_keys/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,25 @@ $(obj)/x509_rsakey-asn1.o: $(obj)/x509_rsakey-asn1.c $(obj)/x509_rsakey-asn1.h

clean-files += x509-asn1.c x509-asn1.h
clean-files += x509_rsakey-asn1.c x509_rsakey-asn1.h

#
# PKCS#7 message handling
#
obj-$(CONFIG_PKCS7_MESSAGE_PARSER) += pkcs7_message.o
pkcs7_message-y := \
pkcs7-asn1.o \
pkcs7_parser.o \
pkcs7_trust.o \
pkcs7_verify.o

$(obj)/pkcs7_parser.o: $(obj)/pkcs7-asn1.h
$(obj)/pkcs7-asn1.o: $(obj)/pkcs7-asn1.c $(obj)/pkcs7-asn1.h

clean-files += pkcs7-asn1.c pkcs7-asn1.h

#
# PKCS#7 parser testing key
#
obj-$(CONFIG_PKCS7_TEST_KEY) += pkcs7_test_key.o
pkcs7_test_key-y := \
pkcs7_key_type.o
127 changes: 127 additions & 0 deletions crypto/asymmetric_keys/pkcs7.asn1
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
PKCS7ContentInfo ::= SEQUENCE {
contentType ContentType,
content [0] EXPLICIT SignedData OPTIONAL
}

ContentType ::= OBJECT IDENTIFIER ({ pkcs7_note_OID })

SignedData ::= SEQUENCE {
version INTEGER,
digestAlgorithms DigestAlgorithmIdentifiers,
contentInfo ContentInfo,
certificates CHOICE {
certSet [0] IMPLICIT ExtendedCertificatesAndCertificates,
certSequence [2] IMPLICIT Certificates
} OPTIONAL ({ pkcs7_note_certificate_list }),
crls CHOICE {
crlSet [1] IMPLICIT CertificateRevocationLists,
crlSequence [3] IMPLICIT CRLSequence
} OPTIONAL,
signerInfos SignerInfos
}

ContentInfo ::= SEQUENCE {
contentType ContentType,
content [0] EXPLICIT Data OPTIONAL
}

Data ::= ANY ({ pkcs7_note_data })

DigestAlgorithmIdentifiers ::= CHOICE {
daSet SET OF DigestAlgorithmIdentifier,
daSequence SEQUENCE OF DigestAlgorithmIdentifier
}

DigestAlgorithmIdentifier ::= SEQUENCE {
algorithm OBJECT IDENTIFIER ({ pkcs7_note_OID }),
parameters ANY OPTIONAL
}

--
-- Certificates and certificate lists
--
ExtendedCertificatesAndCertificates ::= SET OF ExtendedCertificateOrCertificate

ExtendedCertificateOrCertificate ::= CHOICE {
certificate Certificate, -- X.509
extendedCertificate [0] IMPLICIT ExtendedCertificate -- PKCS#6
}

ExtendedCertificate ::= Certificate -- cheating

Certificates ::= SEQUENCE OF Certificate

CertificateRevocationLists ::= SET OF CertificateList

CertificateList ::= SEQUENCE OF Certificate -- This may be defined incorrectly

CRLSequence ::= SEQUENCE OF CertificateList

Certificate ::= ANY ({ pkcs7_extract_cert }) -- X.509

--
-- Signer information
--
SignerInfos ::= CHOICE {
siSet SET OF SignerInfo,
siSequence SEQUENCE OF SignerInfo
}

SignerInfo ::= SEQUENCE {
version INTEGER,
issuerAndSerialNumber IssuerAndSerialNumber,
digestAlgorithm DigestAlgorithmIdentifier ({ pkcs7_sig_note_digest_algo }),
authenticatedAttributes CHOICE {
aaSet [0] IMPLICIT SetOfAuthenticatedAttribute
({ pkcs7_sig_note_set_of_authattrs }),
aaSequence [2] EXPLICIT SEQUENCE OF AuthenticatedAttribute
-- Explicit because easier to compute digest on
-- sequence of attributes and then reuse encoded
-- sequence in aaSequence.
} OPTIONAL,
digestEncryptionAlgorithm
DigestEncryptionAlgorithmIdentifier ({ pkcs7_sig_note_pkey_algo }),
encryptedDigest EncryptedDigest,
unauthenticatedAttributes CHOICE {
uaSet [1] IMPLICIT SET OF UnauthenticatedAttribute,
uaSequence [3] IMPLICIT SEQUENCE OF UnauthenticatedAttribute
} OPTIONAL
} ({ pkcs7_note_signed_info })

IssuerAndSerialNumber ::= SEQUENCE {
issuer Name ({ pkcs7_sig_note_issuer }),
serialNumber CertificateSerialNumber ({ pkcs7_sig_note_serial })
}

CertificateSerialNumber ::= INTEGER

SetOfAuthenticatedAttribute ::= SET OF AuthenticatedAttribute

AuthenticatedAttribute ::= SEQUENCE {
type OBJECT IDENTIFIER ({ pkcs7_note_OID }),
values SET OF ANY ({ pkcs7_sig_note_authenticated_attr })
}

UnauthenticatedAttribute ::= SEQUENCE {
type OBJECT IDENTIFIER ({ pkcs7_note_OID }),
values SET OF ANY
}

DigestEncryptionAlgorithmIdentifier ::= SEQUENCE {
algorithm OBJECT IDENTIFIER ({ pkcs7_note_OID }),
parameters ANY OPTIONAL
}

EncryptedDigest ::= OCTET STRING ({ pkcs7_sig_note_signature })

---
--- X.500 Name
---
Name ::= SEQUENCE OF RelativeDistinguishedName

RelativeDistinguishedName ::= SET OF AttributeValueAssertion

AttributeValueAssertion ::= SEQUENCE {
attributeType OBJECT IDENTIFIER ({ pkcs7_note_OID }),
attributeValue ANY
}
99 changes: 99 additions & 0 deletions crypto/asymmetric_keys/pkcs7_key_type.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/* Testing module to load key from trusted PKCS#7 message
*
* Copyright (C) 2014 Red Hat, Inc. All Rights Reserved.
* Written by David Howells ([email protected])
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public Licence
* as published by the Free Software Foundation; either version
* 2 of the Licence, or (at your option) any later version.
*/

#define pr_fmt(fmt) "PKCS7key: "fmt
#include <linux/key.h>
#include <linux/key-type.h>
#include <crypto/pkcs7.h>
#include <keys/user-type.h>
#include <keys/system_keyring.h>
#include "pkcs7_parser.h"

/*
* Preparse a PKCS#7 wrapped and validated data blob.
*/
static int pkcs7_preparse(struct key_preparsed_payload *prep)
{
struct pkcs7_message *pkcs7;
const void *data, *saved_prep_data;
size_t datalen, saved_prep_datalen;
bool trusted;
int ret;

kenter("");

saved_prep_data = prep->data;
saved_prep_datalen = prep->datalen;
pkcs7 = pkcs7_parse_message(saved_prep_data, saved_prep_datalen);
if (IS_ERR(pkcs7)) {
ret = PTR_ERR(pkcs7);
goto error;
}

ret = pkcs7_verify(pkcs7);
if (ret < 0)
goto error_free;

ret = pkcs7_validate_trust(pkcs7, system_trusted_keyring, &trusted);
if (ret < 0)
goto error_free;
if (!trusted)
pr_warn("PKCS#7 message doesn't chain back to a trusted key\n");

ret = pkcs7_get_content_data(pkcs7, &data, &datalen, false);
if (ret < 0)
goto error_free;

prep->data = data;
prep->datalen = datalen;
ret = user_preparse(prep);
prep->data = saved_prep_data;
prep->datalen = saved_prep_datalen;

error_free:
pkcs7_free_message(pkcs7);
error:
kleave(" = %d", ret);
return ret;
}

/*
* user defined keys take an arbitrary string as the description and an
* arbitrary blob of data as the payload
*/
struct key_type key_type_pkcs7 = {
.name = "pkcs7_test",
.def_lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT,
.preparse = pkcs7_preparse,
.free_preparse = user_free_preparse,
.instantiate = generic_key_instantiate,
.match = user_match,
.revoke = user_revoke,
.destroy = user_destroy,
.describe = user_describe,
.read = user_read,
};

/*
* Module stuff
*/
static int __init pkcs7_key_init(void)
{
return register_key_type(&key_type_pkcs7);
}

static void __exit pkcs7_key_cleanup(void)
{
unregister_key_type(&key_type_pkcs7);
}

module_init(pkcs7_key_init);
module_exit(pkcs7_key_cleanup);
Loading

0 comments on commit 1ca72c9

Please sign in to comment.