Merge tag 'keys-next-20140722' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs into next

This commit is contained in:
James Morris 2014-07-24 21:36:19 +10:00
commit 4ca332e11d
48 changed files with 3033 additions and 225 deletions

View File

@ -566,6 +566,11 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
possible to determine what the correct size should be.
This option provides an override for these situations.
ca_keys= [KEYS] This parameter identifies a specific key(s) on
the system trusted keyring to be used for certificate
trust validation.
format: { id:<keyid> | builtin }
ccw_timeout_log [S390]
See Documentation/s390/CommonIO for details.

View File

@ -1150,20 +1150,24 @@ The structure has a number of fields, some of which are mandatory:
const void *data;
size_t datalen;
size_t quotalen;
time_t expiry;
};
Before calling the method, the caller will fill in data and datalen with
the payload blob parameters; quotalen will be filled in with the default
quota size from the key type and the rest will be cleared.
quota size from the key type; expiry will be set to TIME_T_MAX and the
rest will be cleared.
If a description can be proposed from the payload contents, that should be
attached as a string to the description field. This will be used for the
key description if the caller of add_key() passes NULL or "".
The method can attach anything it likes to type_data[] and payload. These
are merely passed along to the instantiate() or update() operations.
are merely passed along to the instantiate() or update() operations. If
set, the expiry time will be applied to the key if it is instantiated from
this data.
The method should return 0 if success ful or a negative error code
The method should return 0 if successful or a negative error code
otherwise.
@ -1172,7 +1176,9 @@ The structure has a number of fields, some of which are mandatory:
This method is only required if the preparse() method is provided,
otherwise it is unused. It cleans up anything attached to the
description, type_data and payload fields of the key_preparsed_payload
struct as filled in by the preparse() method.
struct as filled in by the preparse() method. It will always be called
after preparse() returns successfully, even if instantiate() or update()
succeed.
(*) int (*instantiate)(struct key *key, struct key_preparsed_payload *prep);

View File

@ -22,7 +22,6 @@ config ASYMMETRIC_PUBLIC_KEY_SUBTYPE
config PUBLIC_KEY_ALGO_RSA
tristate "RSA public-key algorithm"
select MPILIB_EXTRA
select MPILIB
help
This option enables support for the RSA algorithm (PKCS#1, RFC3447).
@ -33,8 +32,39 @@ config X509_CERTIFICATE_PARSER
select ASN1
select OID_REGISTRY
help
This option procides support for parsing X.509 format blobs for key
This option provides support for parsing X.509 format blobs for key
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.
config SIGNED_PE_FILE_VERIFICATION
bool "Support for PE file signature verification"
depends on PKCS7_MESSAGE_PARSER=y
select ASN1
select OID_REGISTRY
help
This option provides support for verifying the signature(s) on a
signed PE binary.
endif # ASYMMETRIC_KEY_TYPE

View File

@ -25,3 +25,40 @@ $(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
#
# Signed PE binary-wrapped key handling
#
obj-$(CONFIG_SIGNED_PE_FILE_VERIFICATION) += verify_signed_pefile.o
verify_signed_pefile-y := \
verify_pefile.o \
mscode_parser.o \
mscode-asn1.o
$(obj)/mscode_parser.o: $(obj)/mscode-asn1.h $(obj)/mscode-asn1.h
$(obj)/mscode-asn1.o: $(obj)/mscode-asn1.c $(obj)/mscode-asn1.h
clean-files += mscode-asn1.c mscode-asn1.h

View File

@ -9,6 +9,8 @@
* 2 of the Licence, or (at your option) any later version.
*/
int asymmetric_keyid_match(const char *kid, const char *id);
static inline const char *asymmetric_key_id(const struct key *key)
{
return key->type_data.p[1];

View File

@ -22,6 +22,35 @@ MODULE_LICENSE("GPL");
static LIST_HEAD(asymmetric_key_parsers);
static DECLARE_RWSEM(asymmetric_key_parsers_sem);
/*
* Match asymmetric key id with partial match
* @id: key id to match in a form "id:<id>"
*/
int asymmetric_keyid_match(const char *kid, const char *id)
{
size_t idlen, kidlen;
if (!kid || !id)
return 0;
/* make it possible to use id as in the request: "id:<id>" */
if (strncmp(id, "id:", 3) == 0)
id += 3;
/* Anything after here requires a partial match on the ID string */
idlen = strlen(id);
kidlen = strlen(kid);
if (idlen > kidlen)
return 0;
kid += kidlen - idlen;
if (strcasecmp(id, kid) != 0)
return 0;
return 1;
}
EXPORT_SYMBOL_GPL(asymmetric_keyid_match);
/*
* Match asymmetric keys on (part of) their name
* We have some shorthand methods for matching keys. We allow:
@ -34,9 +63,8 @@ static int asymmetric_key_match(const struct key *key, const void *description)
{
const struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key);
const char *spec = description;
const char *id, *kid;
const char *id;
ptrdiff_t speclen;
size_t idlen, kidlen;
if (!subtype || !spec || !*spec)
return 0;
@ -55,23 +83,8 @@ static int asymmetric_key_match(const struct key *key, const void *description)
speclen = id - spec;
id++;
/* Anything after here requires a partial match on the ID string */
kid = asymmetric_key_id(key);
if (!kid)
return 0;
idlen = strlen(id);
kidlen = strlen(kid);
if (idlen > kidlen)
return 0;
kid += kidlen - idlen;
if (strcasecmp(id, kid) != 0)
return 0;
if (speclen == 2 &&
memcmp(spec, "id", 2) == 0)
return 1;
if (speclen == 2 && memcmp(spec, "id", 2) == 0)
return asymmetric_keyid_match(asymmetric_key_id(key), id);
if (speclen == subtype->name_len &&
memcmp(spec, subtype->name, speclen) == 0)
@ -156,36 +169,13 @@ static void asymmetric_key_free_preparse(struct key_preparsed_payload *prep)
pr_devel("==>%s()\n", __func__);
if (subtype) {
subtype->destroy(prep->payload);
subtype->destroy(prep->payload[0]);
module_put(subtype->owner);
}
kfree(prep->type_data[1]);
kfree(prep->description);
}
/*
* Instantiate a asymmetric_key defined key. The key was preparsed, so we just
* have to transfer the data here.
*/
static int asymmetric_key_instantiate(struct key *key, struct key_preparsed_payload *prep)
{
int ret;
pr_devel("==>%s()\n", __func__);
ret = key_payload_reserve(key, prep->quotalen);
if (ret == 0) {
key->type_data.p[0] = prep->type_data[0];
key->type_data.p[1] = prep->type_data[1];
key->payload.data = prep->payload;
prep->type_data[0] = NULL;
prep->type_data[1] = NULL;
prep->payload = NULL;
}
pr_devel("<==%s() = %d\n", __func__, ret);
return ret;
}
/*
* dispose of the data dangling from the corpse of a asymmetric key
*/
@ -205,7 +195,7 @@ struct key_type key_type_asymmetric = {
.name = "asymmetric",
.preparse = asymmetric_key_preparse,
.free_preparse = asymmetric_key_free_preparse,
.instantiate = asymmetric_key_instantiate,
.instantiate = generic_key_instantiate,
.match = asymmetric_key_match,
.destroy = asymmetric_key_destroy,
.describe = asymmetric_key_describe,

View File

@ -0,0 +1,28 @@
--- Microsoft individual code signing data blob 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.
---
MSCode ::= SEQUENCE {
type SEQUENCE {
contentType ContentType,
parameters ANY
},
content SEQUENCE {
digestAlgorithm DigestAlgorithmIdentifier,
digest OCTET STRING ({ mscode_note_digest })
}
}
ContentType ::= OBJECT IDENTIFIER ({ mscode_note_content_type })
DigestAlgorithmIdentifier ::= SEQUENCE {
algorithm OBJECT IDENTIFIER ({ mscode_note_digest_algo }),
parameters ANY OPTIONAL
}

View File

@ -0,0 +1,126 @@
/* Parse a Microsoft Individual Code Signing blob
*
* Copyright (C) 2014 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public Licence
* as published by the Free Software Foundation; either version
* 2 of the Licence, or (at your option) any later version.
*/
#define pr_fmt(fmt) "MSCODE: "fmt
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/oid_registry.h>
#include <crypto/pkcs7.h>
#include "verify_pefile.h"
#include "mscode-asn1.h"
/*
* Parse a Microsoft Individual Code Signing blob
*/
int mscode_parse(struct pefile_context *ctx)
{
const void *content_data;
size_t data_len;
int ret;
ret = pkcs7_get_content_data(ctx->pkcs7, &content_data, &data_len, 1);
if (ret) {
pr_debug("PKCS#7 message does not contain data\n");
return ret;
}
pr_devel("Data: %zu [%*ph]\n", data_len, (unsigned)(data_len),
content_data);
return asn1_ber_decoder(&mscode_decoder, ctx, content_data, data_len);
}
/*
* Check the content type OID
*/
int mscode_note_content_type(void *context, size_t hdrlen,
unsigned char tag,
const void *value, size_t vlen)
{
enum OID oid;
oid = look_up_OID(value, vlen);
if (oid == OID__NR) {
char buffer[50];
sprint_oid(value, vlen, buffer, sizeof(buffer));
pr_err("Unknown OID: %s\n", buffer);
return -EBADMSG;
}
/*
* pesign utility had a bug where it was putting
* OID_msIndividualSPKeyPurpose instead of OID_msPeImageDataObjId
* So allow both OIDs.
*/
if (oid != OID_msPeImageDataObjId &&
oid != OID_msIndividualSPKeyPurpose) {
pr_err("Unexpected content type OID %u\n", oid);
return -EBADMSG;
}
return 0;
}
/*
* Note the digest algorithm OID
*/
int mscode_note_digest_algo(void *context, size_t hdrlen,
unsigned char tag,
const void *value, size_t vlen)
{
struct pefile_context *ctx = context;
char buffer[50];
enum OID oid;
oid = look_up_OID(value, vlen);
switch (oid) {
case OID_md4:
ctx->digest_algo = HASH_ALGO_MD4;
break;
case OID_md5:
ctx->digest_algo = HASH_ALGO_MD5;
break;
case OID_sha1:
ctx->digest_algo = HASH_ALGO_SHA1;
break;
case OID_sha256:
ctx->digest_algo = HASH_ALGO_SHA256;
break;
case OID__NR:
sprint_oid(value, vlen, buffer, sizeof(buffer));
pr_err("Unknown OID: %s\n", buffer);
return -EBADMSG;
default:
pr_err("Unsupported content type: %u\n", oid);
return -ENOPKG;
}
return 0;
}
/*
* Note the digest we're guaranteeing with this certificate
*/
int mscode_note_digest(void *context, size_t hdrlen,
unsigned char tag,
const void *value, size_t vlen)
{
struct pefile_context *ctx = context;
ctx->digest = value;
ctx->digest_len = vlen;
return 0;
}

View File

@ -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
}

View File

@ -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 (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public Licence
* as published by the Free Software Foundation; either version
* 2 of the Licence, or (at your option) any later version.
*/
#define pr_fmt(fmt) "PKCS7key: "fmt
#include <linux/key.h>
#include <linux/key-type.h>
#include <crypto/pkcs7.h>
#include <keys/user-type.h>
#include <keys/system_keyring.h>
#include "pkcs7_parser.h"
/*
* 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);

View File

@ -0,0 +1,396 @@
/* 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>
#include "public_key.h"
#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;
};
/**
* 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;
mpi_free(sinfo->sig.mpi[0]);
kfree(sinfo->sig.digest);
kfree(sinfo);
}
kfree(pkcs7);
}
}
EXPORT_SYMBOL_GPL(pkcs7_free_message);
/**
* 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;
struct pkcs7_message *msg;
long ret;
ret = -ENOMEM;
msg = kzalloc(sizeof(struct pkcs7_message), GFP_KERNEL);
if (!msg)
goto error_no_sig;
ctx = kzalloc(sizeof(struct pkcs7_parse_context), GFP_KERNEL);
if (!ctx)
goto error_no_ctx;
ctx->sinfo = kzalloc(sizeof(struct pkcs7_signed_info), GFP_KERNEL);
if (!ctx->sinfo)
goto error_no_sinfo;
ctx->msg = msg;
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);
if (ret < 0)
goto error_decode;
while (ctx->certs) {
struct x509_certificate *cert = ctx->certs;
ctx->certs = cert->next;
x509_free_certificate(cert);
}
mpi_free(ctx->sinfo->sig.mpi[0]);
kfree(ctx->sinfo->sig.digest);
kfree(ctx->sinfo);
kfree(ctx);
return msg;
error_decode:
mpi_free(ctx->sinfo->sig.mpi[0]);
kfree(ctx->sinfo->sig.digest);
kfree(ctx->sinfo);
error_no_sinfo:
kfree(ctx);
error_no_ctx:
pkcs7_free_message(msg);
error_no_sig:
return ERR_PTR(ret);
}
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;
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;
}
/*
* 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);
pr_debug("Got cert for %s\n", x509->subject);
pr_debug("- fingerprint %s\n", x509->fingerprint);
x509->index = ++ctx->x509_index;
*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;
}
/*
* 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;
ctx->msg->data_type = ctx->last_oid;
return 0;
}
/*
* 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;
pr_devel("AuthAttr: %02x %zu [%*ph]\n", tag, vlen, (unsigned)vlen, value);
switch (ctx->last_oid) {
case OID_messageDigest:
if (tag != ASN1_OTS)
return -EBADMSG;
ctx->sinfo->msgdigest = value;
ctx->sinfo->msgdigest_len = vlen;
return 0;
default:
return 0;
}
}
/*
* Note the set of auth attributes for digestion purposes [RFC2315 9.3]
*/
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;
/* 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);
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;
ctx->sinfo->raw_serial = value;
ctx->sinfo->raw_serial_size = vlen;
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;
ctx->sinfo->raw_issuer = value;
ctx->sinfo->raw_issuer_size = vlen;
return 0;
}
/*
* 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;
MPI mpi;
BUG_ON(ctx->sinfo->sig.pkey_algo != PKEY_ALGO_RSA);
mpi = mpi_read_raw_data(value, vlen);
if (!mpi)
return -ENOMEM;
ctx->sinfo->sig.mpi[0] = mpi;
ctx->sinfo->sig.nr_mpi = 1;
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;
ctx->sinfo->index = ++ctx->sinfo_index;
*ctx->ppsinfo = ctx->sinfo;
ctx->ppsinfo = &ctx->sinfo->next;
ctx->sinfo = kzalloc(sizeof(struct pkcs7_signed_info), GFP_KERNEL);
if (!ctx->sinfo)
return -ENOMEM;
return 0;
}

View File

@ -0,0 +1,61 @@
/* PKCS#7 crypto data parser internal definitions
*
* 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.
*/
#include <linux/oid_registry.h>
#include <crypto/pkcs7.h>
#include "x509_parser.h"
#define kenter(FMT, ...) \
pr_devel("==> %s("FMT")\n", __func__, ##__VA_ARGS__)
#define kleave(FMT, ...) \
pr_devel("<== %s()"FMT"\n", __func__, ##__VA_ARGS__)
struct pkcs7_signed_info {
struct pkcs7_signed_info *next;
struct x509_certificate *signer; /* Signing certificate (in msg->certs) */
unsigned index;
bool trusted;
/* Message digest - the digest of the Content Data (or NULL) */
const void *msgdigest;
unsigned msgdigest_len;
/* Authenticated Attribute data (or NULL) */
unsigned authattrs_len;
const void *authattrs;
/* Issuing cert serial number and issuer's name */
const void *raw_serial;
unsigned raw_serial_size;
unsigned raw_issuer_size;
const void *raw_issuer;
/* Message signature.
*
* This contains the generated digest of _either_ the Content Data or
* the Authenticated Attributes [RFC2315 9.3]. If the latter, one of
* the attributes contains the digest of the the Content Data within
* it.
*/
struct public_key_signature sig;
};
struct pkcs7_message {
struct x509_certificate *certs; /* Certificate list */
struct x509_certificate *crl; /* Revocation list */
struct pkcs7_signed_info *signed_infos;
/* Content Data (or NULL) */
enum OID data_type; /* Type of Data */
size_t data_len; /* Length of Data */
size_t data_hdrlen; /* Length of Data ASN.1 header */
const void *data; /* Content Data (or 0) */
};

View File

@ -0,0 +1,219 @@
/* Validate the trust chain of a PKCS#7 message.
*
* 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/asn1.h>
#include <linux/key.h>
#include <keys/asymmetric-type.h>
#include "public_key.h"
#include "pkcs7_parser.h"
/*
* Request an asymmetric key.
*/
static struct key *pkcs7_request_asymmetric_key(
struct key *keyring,
const char *signer, size_t signer_len,
const char *authority, size_t auth_len)
{
key_ref_t key;
char *id;
kenter(",%zu,,%zu", signer_len, auth_len);
/* Construct an identifier. */
id = kmalloc(signer_len + 2 + auth_len + 1, GFP_KERNEL);
if (!id)
return ERR_PTR(-ENOMEM);
memcpy(id, signer, signer_len);
id[signer_len + 0] = ':';
id[signer_len + 1] = ' ';
memcpy(id + signer_len + 2, authority, auth_len);
id[signer_len + 2 + auth_len] = 0;
pr_debug("Look up: \"%s\"\n", id);
key = keyring_search(make_key_ref(keyring, 1),
&key_type_asymmetric, id);
if (IS_ERR(key))
pr_debug("Request for module key '%s' err %ld\n",
id, PTR_ERR(key));
kfree(id);
if (IS_ERR(key)) {
switch (PTR_ERR(key)) {
/* Hide some search errors */
case -EACCES:
case -ENOTDIR:
case -EAGAIN:
return ERR_PTR(-ENOKEY);
default:
return ERR_CAST(key);
}
}
pr_devel("<==%s() = 0 [%x]\n", __func__, key_serial(key_ref_to_ptr(key)));
return key_ref_to_ptr(key);
}
/**
* Check the trust on one PKCS#7 SignedInfo block.
*/
int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
struct pkcs7_signed_info *sinfo,
struct key *trust_keyring)
{
struct public_key_signature *sig = &sinfo->sig;
struct x509_certificate *x509, *last = NULL, *p;
struct key *key;
bool trusted;
int ret;
kenter(",%u,", sinfo->index);
for (x509 = sinfo->signer; x509; x509 = x509->signer) {
if (x509->seen) {
if (x509->verified) {
trusted = x509->trusted;
goto verified;
}
kleave(" = -ENOKEY [cached]");
return -ENOKEY;
}
x509->seen = true;
/* Look to see if this certificate is present in the trusted
* keys.
*/
key = pkcs7_request_asymmetric_key(
trust_keyring,
x509->subject, strlen(x509->subject),
x509->fingerprint, strlen(x509->fingerprint));
if (!IS_ERR(key))
/* One of the X.509 certificates in the PKCS#7 message
* is apparently the same as one we already trust.
* Verify that the trusted variant can also validate
* the signature on the descendant.
*/
goto matched;
if (key == ERR_PTR(-ENOMEM))
return -ENOMEM;
/* Self-signed certificates form roots of their own, and if we
* don't know them, then we can't accept them.
*/
if (x509->next == x509) {
kleave(" = -ENOKEY [unknown self-signed]");
return -ENOKEY;
}
might_sleep();
last = x509;
sig = &last->sig;
}
/* No match - see if the root certificate has a signer amongst the
* trusted keys.
*/
if (!last || !last->issuer || !last->authority) {
kleave(" = -ENOKEY [no backref]");
return -ENOKEY;
}
key = pkcs7_request_asymmetric_key(
trust_keyring,
last->issuer, strlen(last->issuer),
last->authority, strlen(last->authority));
if (IS_ERR(key))
return PTR_ERR(key) == -ENOMEM ? -ENOMEM : -ENOKEY;
x509 = last;
matched:
ret = verify_signature(key, sig);
trusted = test_bit(KEY_FLAG_TRUSTED, &key->flags);
key_put(key);
if (ret < 0) {
if (ret == -ENOMEM)
return ret;
kleave(" = -EKEYREJECTED [verify %d]", ret);
return -EKEYREJECTED;
}
verified:
x509->verified = true;
for (p = sinfo->signer; p != x509; p = p->signer) {
p->verified = true;
p->trusted = trusted;
}
sinfo->trusted = trusted;
kleave(" = 0");
return 0;
}
/**
* pkcs7_validate_trust - Validate PKCS#7 trust chain
* @pkcs7: The PKCS#7 certificate to validate
* @trust_keyring: Signing certificates to use as starting points
* @_trusted: Set to true if trustworth, false otherwise
*
* Validate that the certificate chain inside the PKCS#7 message intersects
* keys we already know and trust.
*
* Returns, in order of descending priority:
*
* (*) -EKEYREJECTED if a signature failed to match for which we have a valid
* key, or:
*
* (*) 0 if at least one signature chain intersects with the keys in the trust
* keyring, or:
*
* (*) -ENOPKG if a suitable crypto module couldn't be found for a check on a
* chain.
*
* (*) -ENOKEY if we couldn't find a match for any of the signature chains in
* the message.
*
* May also return -ENOMEM.
*/
int pkcs7_validate_trust(struct pkcs7_message *pkcs7,
struct key *trust_keyring,
bool *_trusted)
{
struct pkcs7_signed_info *sinfo;
struct x509_certificate *p;
int cached_ret = 0, ret;
for (p = pkcs7->certs; p; p = p->next)
p->seen = false;
for (sinfo = pkcs7->signed_infos; sinfo; sinfo = sinfo->next) {
ret = pkcs7_validate_trust_one(pkcs7, sinfo, trust_keyring);
if (ret < 0) {
if (ret == -ENOPKG) {
cached_ret = -ENOPKG;
} else if (ret == -ENOKEY) {
if (cached_ret == 0)
cached_ret = -ENOKEY;
} else {
return ret;
}
}
*_trusted |= sinfo->trusted;
}
return cached_ret;
}
EXPORT_SYMBOL_GPL(pkcs7_validate_trust);

View File

@ -0,0 +1,323 @@
/* Verify the signature on a PKCS#7 message.
*
* 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/asn1.h>
#include <crypto/hash.h>
#include "public_key.h"
#include "pkcs7_parser.h"
/*
* Digest the relevant parts of the PKCS#7 data
*/
static int pkcs7_digest(struct pkcs7_message *pkcs7,
struct pkcs7_signed_info *sinfo)
{
struct crypto_shash *tfm;
struct shash_desc *desc;
size_t digest_size, desc_size;
void *digest;
int ret;
kenter(",%u,%u", sinfo->index, sinfo->sig.pkey_hash_algo);
if (sinfo->sig.pkey_hash_algo >= PKEY_HASH__LAST ||
!hash_algo_name[sinfo->sig.pkey_hash_algo])
return -ENOPKG;
/* Allocate the hashing algorithm we're going to need and find out how
* big the hash operational data will be.
*/
tfm = crypto_alloc_shash(hash_algo_name[sinfo->sig.pkey_hash_algo],
0, 0);
if (IS_ERR(tfm))
return (PTR_ERR(tfm) == -ENOENT) ? -ENOPKG : PTR_ERR(tfm);
desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
sinfo->sig.digest_size = digest_size = crypto_shash_digestsize(tfm);
ret = -ENOMEM;
digest = kzalloc(digest_size + desc_size, GFP_KERNEL);
if (!digest)
goto error_no_desc;
desc = digest + digest_size;
desc->tfm = tfm;
desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
/* Digest the message [RFC2315 9.3] */
ret = crypto_shash_init(desc);
if (ret < 0)
goto error;
ret = crypto_shash_finup(desc, pkcs7->data, pkcs7->data_len, digest);
if (ret < 0)
goto error;
pr_devel("MsgDigest = [%*ph]\n", 8, digest);
/* However, if there are authenticated attributes, there must be a
* message digest attribute amongst them which corresponds to the
* digest we just calculated.
*/
if (sinfo->msgdigest) {
u8 tag;
if (sinfo->msgdigest_len != sinfo->sig.digest_size) {
pr_debug("Sig %u: Invalid digest size (%u)\n",
sinfo->index, sinfo->msgdigest_len);
ret = -EBADMSG;
goto error;
}
if (memcmp(digest, sinfo->msgdigest, sinfo->msgdigest_len) != 0) {
pr_debug("Sig %u: Message digest doesn't match\n",
sinfo->index);
ret = -EKEYREJECTED;
goto error;
}
/* We then calculate anew, using the authenticated attributes
* as the contents of the digest instead. Note that we need to
* convert the attributes from a CONT.0 into a SET before we
* hash it.
*/
memset(digest, 0, sinfo->sig.digest_size);
ret = crypto_shash_init(desc);
if (ret < 0)
goto error;
tag = ASN1_CONS_BIT | ASN1_SET;
ret = crypto_shash_update(desc, &tag, 1);
if (ret < 0)
goto error;
ret = crypto_shash_finup(desc, sinfo->authattrs,
sinfo->authattrs_len, digest);
if (ret < 0)
goto error;
pr_devel("AADigest = [%*ph]\n", 8, digest);
}
sinfo->sig.digest = digest;
digest = NULL;
error:
kfree(digest);
error_no_desc:
crypto_free_shash(tfm);
kleave(" = %d", ret);
return ret;
}
/*
* Find the key (X.509 certificate) to use to verify a PKCS#7 message. PKCS#7
* uses the issuer's name and the issuing certificate serial number for
* matching purposes. These must match the certificate issuer's name (not
* subject's name) and the certificate serial number [RFC 2315 6.7].
*/
static int pkcs7_find_key(struct pkcs7_message *pkcs7,
struct pkcs7_signed_info *sinfo)
{
struct x509_certificate *x509;
unsigned certix = 1;
kenter("%u,%u,%u",
sinfo->index, sinfo->raw_serial_size, sinfo->raw_issuer_size);
for (x509 = pkcs7->certs; x509; x509 = x509->next, certix++) {
/* I'm _assuming_ that the generator of the PKCS#7 message will
* encode the fields from the X.509 cert in the same way in the
* PKCS#7 message - but I can't be 100% sure of that. It's
* possible this will need element-by-element comparison.
*/
if (x509->raw_serial_size != sinfo->raw_serial_size ||
memcmp(x509->raw_serial, sinfo->raw_serial,
sinfo->raw_serial_size) != 0)
continue;
pr_devel("Sig %u: Found cert serial match X.509[%u]\n",
sinfo->index, certix);
if (x509->raw_issuer_size != sinfo->raw_issuer_size ||
memcmp(x509->raw_issuer, sinfo->raw_issuer,
sinfo->raw_issuer_size) != 0) {
pr_warn("Sig %u: X.509 subject and PKCS#7 issuer don't match\n",
sinfo->index);
continue;
}
if (x509->pub->pkey_algo != sinfo->sig.pkey_algo) {
pr_warn("Sig %u: X.509 algo and PKCS#7 sig algo don't match\n",
sinfo->index);
continue;
}
sinfo->signer = x509;
return 0;
}
pr_warn("Sig %u: Issuing X.509 cert not found (#%*ph)\n",
sinfo->index, sinfo->raw_serial_size, sinfo->raw_serial);
return -ENOKEY;
}
/*
* Verify the internal certificate chain as best we can.
*/
static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7,
struct pkcs7_signed_info *sinfo)
{
struct x509_certificate *x509 = sinfo->signer, *p;
int ret;
kenter("");
for (p = pkcs7->certs; p; p = p->next)
p->seen = false;
for (;;) {
pr_debug("verify %s: %s\n", x509->subject, x509->fingerprint);
x509->seen = true;
ret = x509_get_sig_params(x509);
if (ret < 0)
return ret;
if (x509->issuer)
pr_debug("- issuer %s\n", x509->issuer);
if (x509->authority)
pr_debug("- authkeyid %s\n", x509->authority);
if (!x509->authority ||
(x509->subject &&
strcmp(x509->subject, x509->issuer) == 0)) {
/* If there's no authority certificate specified, then
* the certificate must be self-signed and is the root
* of the chain. Likewise if the cert is its own
* authority.
*/
pr_debug("- no auth?\n");
if (x509->raw_subject_size != x509->raw_issuer_size ||
memcmp(x509->raw_subject, x509->raw_issuer,
x509->raw_issuer_size) != 0)
return 0;
ret = x509_check_signature(x509->pub, x509);
if (ret < 0)
return ret;
x509->signer = x509;
pr_debug("- self-signed\n");
return 0;
}
/* Look through the X.509 certificates in the PKCS#7 message's
* list to see if the next one is there.
*/
pr_debug("- want %s\n", x509->authority);
for (p = pkcs7->certs; p; p = p->next) {
pr_debug("- cmp [%u] %s\n", p->index, p->fingerprint);
if (p->raw_subject_size == x509->raw_issuer_size &&
strcmp(p->fingerprint, x509->authority) == 0 &&
memcmp(p->raw_subject, x509->raw_issuer,
x509->raw_issuer_size) == 0)
goto found_issuer;
}
/* We didn't find the root of this chain */
pr_debug("- top\n");
return 0;
found_issuer:
pr_debug("- issuer %s\n", p->subject);
if (p->seen) {
pr_warn("Sig %u: X.509 chain contains loop\n",
sinfo->index);
return 0;
}
ret = x509_check_signature(p->pub, x509);
if (ret < 0)
return ret;
x509->signer = p;
if (x509 == p) {
pr_debug("- self-signed\n");
return 0;
}
x509 = p;
might_sleep();
}
}
/*
* Verify one signed information block from a PKCS#7 message.
*/
static int pkcs7_verify_one(struct pkcs7_message *pkcs7,
struct pkcs7_signed_info *sinfo)
{
int ret;
kenter(",%u", sinfo->index);
/* First of all, digest the data in the PKCS#7 message and the
* signed information block
*/
ret = pkcs7_digest(pkcs7, sinfo);
if (ret < 0)
return ret;
/* Find the key for the signature */
ret = pkcs7_find_key(pkcs7, sinfo);
if (ret < 0)
return ret;
pr_devel("Using X.509[%u] for sig %u\n",
sinfo->signer->index, sinfo->index);
/* Verify the PKCS#7 binary against the key */
ret = public_key_verify_signature(sinfo->signer->pub, &sinfo->sig);
if (ret < 0)
return ret;
pr_devel("Verified signature %u\n", sinfo->index);
/* Verify the internal certificate chain */
return pkcs7_verify_sig_chain(pkcs7, sinfo);
}
/**
* pkcs7_verify - Verify a PKCS#7 message
* @pkcs7: The PKCS#7 message to be verified
*/
int pkcs7_verify(struct pkcs7_message *pkcs7)
{
struct pkcs7_signed_info *sinfo;
struct x509_certificate *x509;
int ret, n;
kenter("");
for (n = 0, x509 = pkcs7->certs; x509; x509 = x509->next, n++) {
ret = x509_get_sig_params(x509);
if (ret < 0)
return ret;
pr_debug("X.509[%u] %s\n", n, x509->authority);
}
for (sinfo = pkcs7->signed_infos; sinfo; sinfo = sinfo->next) {
ret = pkcs7_verify_one(pkcs7, sinfo);
if (ret < 0) {
kleave(" = %d", ret);
return ret;
}
}
kleave(" = 0");
return 0;
}
EXPORT_SYMBOL_GPL(pkcs7_verify);

View File

@ -0,0 +1,457 @@
/* Parse a signed PE binary
*
* Copyright (C) 2014 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public Licence
* as published by the Free Software Foundation; either version
* 2 of the Licence, or (at your option) any later version.
*/
#define pr_fmt(fmt) "PEFILE: "fmt
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/pe.h>
#include <linux/asn1.h>
#include <crypto/pkcs7.h>
#include <crypto/hash.h>
#include "verify_pefile.h"
/*
* Parse a PE binary.
*/
static int pefile_parse_binary(const void *pebuf, unsigned int pelen,
struct pefile_context *ctx)
{
const struct mz_hdr *mz = pebuf;
const struct pe_hdr *pe;
const struct pe32_opt_hdr *pe32;
const struct pe32plus_opt_hdr *pe64;
const struct data_directory *ddir;
const struct data_dirent *dde;
const struct section_header *secs, *sec;
size_t cursor, datalen = pelen;
kenter("");
#define chkaddr(base, x, s) \
do { \
if ((x) < base || (s) >= datalen || (x) > datalen - (s)) \
return -ELIBBAD; \
} while (0)
chkaddr(0, 0, sizeof(*mz));
if (mz->magic != MZ_MAGIC)
return -ELIBBAD;
cursor = sizeof(*mz);
chkaddr(cursor, mz->peaddr, sizeof(*pe));
pe = pebuf + mz->peaddr;
if (pe->magic != PE_MAGIC)
return -ELIBBAD;
cursor = mz->peaddr + sizeof(*pe);
chkaddr(0, cursor, sizeof(pe32->magic));
pe32 = pebuf + cursor;
pe64 = pebuf + cursor;
switch (pe32->magic) {
case PE_OPT_MAGIC_PE32:
chkaddr(0, cursor, sizeof(*pe32));
ctx->image_checksum_offset =
(unsigned long)&pe32->csum - (unsigned long)pebuf;
ctx->header_size = pe32->header_size;
cursor += sizeof(*pe32);
ctx->n_data_dirents = pe32->data_dirs;
break;
case PE_OPT_MAGIC_PE32PLUS:
chkaddr(0, cursor, sizeof(*pe64));
ctx->image_checksum_offset =
(unsigned long)&pe64->csum - (unsigned long)pebuf;
ctx->header_size = pe64->header_size;
cursor += sizeof(*pe64);
ctx->n_data_dirents = pe64->data_dirs;
break;
default:
pr_debug("Unknown PEOPT magic = %04hx\n", pe32->magic);
return -ELIBBAD;
}
pr_debug("checksum @ %x\n", ctx->image_checksum_offset);
pr_debug("header size = %x\n", ctx->header_size);
if (cursor >= ctx->header_size || ctx->header_size >= datalen)
return -ELIBBAD;
if (ctx->n_data_dirents > (ctx->header_size - cursor) / sizeof(*dde))
return -ELIBBAD;
ddir = pebuf + cursor;
cursor += sizeof(*dde) * ctx->n_data_dirents;
ctx->cert_dirent_offset =
(unsigned long)&ddir->certs - (unsigned long)pebuf;
ctx->certs_size = ddir->certs.size;
if (!ddir->certs.virtual_address || !ddir->certs.size) {
pr_debug("Unsigned PE binary\n");
return -EKEYREJECTED;
}
chkaddr(ctx->header_size, ddir->certs.virtual_address,
ddir->certs.size);
ctx->sig_offset = ddir->certs.virtual_address;
ctx->sig_len = ddir->certs.size;
pr_debug("cert = %x @%x [%*ph]\n",
ctx->sig_len, ctx->sig_offset,
ctx->sig_len, pebuf + ctx->sig_offset);
ctx->n_sections = pe->sections;
if (ctx->n_sections > (ctx->header_size - cursor) / sizeof(*sec))
return -ELIBBAD;
ctx->secs = secs = pebuf + cursor;
return 0;
}
/*
* Check and strip the PE wrapper from around the signature and check that the
* remnant looks something like PKCS#7.
*/
static int pefile_strip_sig_wrapper(const void *pebuf,
struct pefile_context *ctx)
{
struct win_certificate wrapper;
const u8 *pkcs7;
if (ctx->sig_len < sizeof(wrapper)) {
pr_debug("Signature wrapper too short\n");
return -ELIBBAD;
}
memcpy(&wrapper, pebuf + ctx->sig_offset, sizeof(wrapper));
pr_debug("sig wrapper = { %x, %x, %x }\n",
wrapper.length, wrapper.revision, wrapper.cert_type);
/* Both pesign and sbsign round up the length of certificate table
* (in optional header data directories) to 8 byte alignment.
*/
if (round_up(wrapper.length, 8) != ctx->sig_len) {
pr_debug("Signature wrapper len wrong\n");
return -ELIBBAD;
}
if (wrapper.revision != WIN_CERT_REVISION_2_0) {
pr_debug("Signature is not revision 2.0\n");
return -ENOTSUPP;
}
if (wrapper.cert_type != WIN_CERT_TYPE_PKCS_SIGNED_DATA) {
pr_debug("Signature certificate type is not PKCS\n");
return -ENOTSUPP;
}
/* Looks like actual pkcs signature length is in wrapper->length.
* size obtained from data dir entries lists the total size of
* certificate table which is also aligned to octawrod boundary.
*
* So set signature length field appropriately.
*/
ctx->sig_len = wrapper.length;
ctx->sig_offset += sizeof(wrapper);
ctx->sig_len -= sizeof(wrapper);
if (ctx->sig_len == 0) {
pr_debug("Signature data missing\n");
return -EKEYREJECTED;
}
/* What's left should a PKCS#7 cert */
pkcs7 = pebuf + ctx->sig_offset;
if (pkcs7[0] == (ASN1_CONS_BIT | ASN1_SEQ)) {
if (pkcs7[1] == 0x82 &&
pkcs7[2] == (((ctx->sig_len - 4) >> 8) & 0xff) &&
pkcs7[3] == ((ctx->sig_len - 4) & 0xff))
return 0;
if (pkcs7[1] == 0x80)
return 0;
if (pkcs7[1] > 0x82)
return -EMSGSIZE;
}
pr_debug("Signature data not PKCS#7\n");
return -ELIBBAD;
}
/*
* Compare two sections for canonicalisation.
*/
static int pefile_compare_shdrs(const void *a, const void *b)
{
const struct section_header *shdra = a;
const struct section_header *shdrb = b;
int rc;
if (shdra->data_addr > shdrb->data_addr)
return 1;
if (shdrb->data_addr > shdra->data_addr)
return -1;
if (shdra->virtual_address > shdrb->virtual_address)
return 1;
if (shdrb->virtual_address > shdra->virtual_address)
return -1;
rc = strcmp(shdra->name, shdrb->name);
if (rc != 0)
return rc;
if (shdra->virtual_size > shdrb->virtual_size)
return 1;
if (shdrb->virtual_size > shdra->virtual_size)
return -1;
if (shdra->raw_data_size > shdrb->raw_data_size)
return 1;
if (shdrb->raw_data_size > shdra->raw_data_size)
return -1;
return 0;
}
/*
* Load the contents of the PE binary into the digest, leaving out the image
* checksum and the certificate data block.
*/
static int pefile_digest_pe_contents(const void *pebuf, unsigned int pelen,
struct pefile_context *ctx,
struct shash_desc *desc)
{
unsigned *canon, tmp, loop, i, hashed_bytes;
int ret;
/* Digest the header and data directory, but leave out the image
* checksum and the data dirent for the signature.
*/
ret = crypto_shash_update(desc, pebuf, ctx->image_checksum_offset);
if (ret < 0)
return ret;
tmp = ctx->image_checksum_offset + sizeof(uint32_t);
ret = crypto_shash_update(desc, pebuf + tmp,
ctx->cert_dirent_offset - tmp);
if (ret < 0)
return ret;
tmp = ctx->cert_dirent_offset + sizeof(struct data_dirent);
ret = crypto_shash_update(desc, pebuf + tmp, ctx->header_size - tmp);
if (ret < 0)
return ret;
canon = kcalloc(ctx->n_sections, sizeof(unsigned), GFP_KERNEL);
if (!canon)
return -ENOMEM;
/* We have to canonicalise the section table, so we perform an
* insertion sort.
*/
canon[0] = 0;
for (loop = 1; loop < ctx->n_sections; loop++) {
for (i = 0; i < loop; i++) {
if (pefile_compare_shdrs(&ctx->secs[canon[i]],
&ctx->secs[loop]) > 0) {
memmove(&canon[i + 1], &canon[i],
(loop - i) * sizeof(canon[0]));
break;
}
}
canon[i] = loop;
}
hashed_bytes = ctx->header_size;
for (loop = 0; loop < ctx->n_sections; loop++) {
i = canon[loop];
if (ctx->secs[i].raw_data_size == 0)
continue;
ret = crypto_shash_update(desc,
pebuf + ctx->secs[i].data_addr,
ctx->secs[i].raw_data_size);
if (ret < 0) {
kfree(canon);
return ret;
}
hashed_bytes += ctx->secs[i].raw_data_size;
}
kfree(canon);
if (pelen > hashed_bytes) {
tmp = hashed_bytes + ctx->certs_size;
ret = crypto_shash_update(desc,
pebuf + hashed_bytes,
pelen - tmp);
if (ret < 0)
return ret;
}
return 0;
}
/*
* Digest the contents of the PE binary, leaving out the image checksum and the
* certificate data block.
*/
static int pefile_digest_pe(const void *pebuf, unsigned int pelen,
struct pefile_context *ctx)
{
struct crypto_shash *tfm;
struct shash_desc *desc;
size_t digest_size, desc_size;
void *digest;
int ret;
kenter(",%u", ctx->digest_algo);
/* Allocate the hashing algorithm we're going to need and find out how
* big the hash operational data will be.
*/
tfm = crypto_alloc_shash(hash_algo_name[ctx->digest_algo], 0, 0);
if (IS_ERR(tfm))
return (PTR_ERR(tfm) == -ENOENT) ? -ENOPKG : PTR_ERR(tfm);
desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
digest_size = crypto_shash_digestsize(tfm);
if (digest_size != ctx->digest_len) {
pr_debug("Digest size mismatch (%zx != %x)\n",
digest_size, ctx->digest_len);
ret = -EBADMSG;
goto error_no_desc;
}
pr_debug("Digest: desc=%zu size=%zu\n", desc_size, digest_size);
ret = -ENOMEM;
desc = kzalloc(desc_size + digest_size, GFP_KERNEL);
if (!desc)
goto error_no_desc;
desc->tfm = tfm;
desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
ret = crypto_shash_init(desc);
if (ret < 0)
goto error;
ret = pefile_digest_pe_contents(pebuf, pelen, ctx, desc);
if (ret < 0)
goto error;
digest = (void *)desc + desc_size;
ret = crypto_shash_final(desc, digest);
if (ret < 0)
goto error;
pr_debug("Digest calc = [%*ph]\n", ctx->digest_len, digest);
/* Check that the PE file digest matches that in the MSCODE part of the
* PKCS#7 certificate.
*/
if (memcmp(digest, ctx->digest, ctx->digest_len) != 0) {
pr_debug("Digest mismatch\n");
ret = -EKEYREJECTED;
} else {
pr_debug("The digests match!\n");
}
error:
kfree(desc);
error_no_desc:
crypto_free_shash(tfm);
kleave(" = %d", ret);
return ret;
}
/**
* verify_pefile_signature - Verify the signature on a PE binary image
* @pebuf: Buffer containing the PE binary image
* @pelen: Length of the binary image
* @trust_keyring: Signing certificates to use as starting points
* @_trusted: Set to true if trustworth, false otherwise
*
* Validate that the certificate chain inside the PKCS#7 message inside the PE
* binary image intersects keys we already know and trust.
*
* Returns, in order of descending priority:
*
* (*) -ELIBBAD if the image cannot be parsed, or:
*
* (*) -EKEYREJECTED if a signature failed to match for which we have a valid
* key, or:
*
* (*) 0 if at least one signature chain intersects with the keys in the trust
* keyring, or:
*
* (*) -ENOPKG if a suitable crypto module couldn't be found for a check on a
* chain.
*
* (*) -ENOKEY if we couldn't find a match for any of the signature chains in
* the message.
*
* May also return -ENOMEM.
*/
int verify_pefile_signature(const void *pebuf, unsigned pelen,
struct key *trusted_keyring, bool *_trusted)
{
struct pkcs7_message *pkcs7;
struct pefile_context ctx;
const void *data;
size_t datalen;
int ret;
kenter("");
memset(&ctx, 0, sizeof(ctx));
ret = pefile_parse_binary(pebuf, pelen, &ctx);
if (ret < 0)
return ret;
ret = pefile_strip_sig_wrapper(pebuf, &ctx);
if (ret < 0)
return ret;
pkcs7 = pkcs7_parse_message(pebuf + ctx.sig_offset, ctx.sig_len);
if (IS_ERR(pkcs7))
return PTR_ERR(pkcs7);
ctx.pkcs7 = pkcs7;
ret = pkcs7_get_content_data(ctx.pkcs7, &data, &datalen, false);
if (ret < 0 || datalen == 0) {
pr_devel("PKCS#7 message does not contain data\n");
ret = -EBADMSG;
goto error;
}
ret = mscode_parse(&ctx);
if (ret < 0)
goto error;
pr_debug("Digest: %u [%*ph]\n",
ctx.digest_len, ctx.digest_len, ctx.digest);
/* Generate the digest and check against the PKCS7 certificate
* contents.
*/
ret = pefile_digest_pe(pebuf, pelen, &ctx);
if (ret < 0)
goto error;
ret = pkcs7_verify(pkcs7);
if (ret < 0)
goto error;
ret = pkcs7_validate_trust(pkcs7, trusted_keyring, _trusted);
error:
pkcs7_free_message(ctx.pkcs7);
return ret;
}

View File

@ -0,0 +1,42 @@
/* PE Binary parser bits
*
* Copyright (C) 2014 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public Licence
* as published by the Free Software Foundation; either version
* 2 of the Licence, or (at your option) any later version.
*/
#include <linux/verify_pefile.h>
#include <crypto/pkcs7.h>
#include <crypto/hash_info.h>
struct pefile_context {
unsigned header_size;
unsigned image_checksum_offset;
unsigned cert_dirent_offset;
unsigned n_data_dirents;
unsigned n_sections;
unsigned certs_size;
unsigned sig_offset;
unsigned sig_len;
const struct section_header *secs;
struct pkcs7_message *pkcs7;
/* PKCS#7 MS Individual Code Signing content */
const void *digest; /* Digest */
unsigned digest_len; /* Digest length */
enum hash_algo digest_algo; /* Digest algorithm */
};
#define kenter(FMT, ...) \
pr_devel("==> %s("FMT")\n", __func__, ##__VA_ARGS__)
#define kleave(FMT, ...) \
pr_devel("<== %s()"FMT"\n", __func__, ##__VA_ARGS__)
/*
* mscode_parser.c
*/
extern int mscode_parse(struct pefile_context *ctx);

View File

@ -6,7 +6,7 @@ Certificate ::= SEQUENCE {
TBSCertificate ::= SEQUENCE {
version [ 0 ] Version DEFAULT,
serialNumber CertificateSerialNumber,
serialNumber CertificateSerialNumber ({ x509_note_serial }),
signature AlgorithmIdentifier ({ x509_note_pkey_algo }),
issuer Name ({ x509_note_issuer }),
validity Validity,

View File

@ -11,6 +11,7 @@
#define pr_fmt(fmt) "X.509: "fmt
#include <linux/kernel.h>
#include <linux/export.h>
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/oid_registry.h>
@ -52,6 +53,7 @@ void x509_free_certificate(struct x509_certificate *cert)
kfree(cert);
}
}
EXPORT_SYMBOL_GPL(x509_free_certificate);
/*
* Parse an X.509 certificate
@ -97,6 +99,7 @@ error_no_ctx:
error_no_cert:
return ERR_PTR(ret);
}
EXPORT_SYMBOL_GPL(x509_cert_parse);
/*
* Note an OID when we find one for later processing when we know how
@ -210,6 +213,19 @@ int x509_note_signature(void *context, size_t hdrlen,
return 0;
}
/*
* Note the certificate serial number
*/
int x509_note_serial(void *context, size_t hdrlen,
unsigned char tag,
const void *value, size_t vlen)
{
struct x509_parse_context *ctx = context;
ctx->cert->raw_serial = value;
ctx->cert->raw_serial_size = vlen;
return 0;
}
/*
* Note some of the name segments from which we'll fabricate a name.
*/
@ -322,6 +338,8 @@ int x509_note_issuer(void *context, size_t hdrlen,
const void *value, size_t vlen)
{
struct x509_parse_context *ctx = context;
ctx->cert->raw_issuer = value;
ctx->cert->raw_issuer_size = vlen;
return x509_fabricate_name(ctx, hdrlen, tag, &ctx->cert->issuer, vlen);
}
@ -330,6 +348,8 @@ int x509_note_subject(void *context, size_t hdrlen,
const void *value, size_t vlen)
{
struct x509_parse_context *ctx = context;
ctx->cert->raw_subject = value;
ctx->cert->raw_subject_size = vlen;
return x509_fabricate_name(ctx, hdrlen, tag, &ctx->cert->subject, vlen);
}

View File

@ -14,7 +14,9 @@
struct x509_certificate {
struct x509_certificate *next;
struct x509_certificate *signer; /* Certificate that signed this one */
struct public_key *pub; /* Public key details */
struct public_key_signature sig; /* Signature parameters */
char *issuer; /* Name of certificate issuer */
char *subject; /* Name of certificate subject */
char *fingerprint; /* Key fingerprint as hex */
@ -25,7 +27,16 @@ struct x509_certificate {
unsigned tbs_size; /* Size of signed data */
unsigned raw_sig_size; /* Size of sigature */
const void *raw_sig; /* Signature data */
struct public_key_signature sig; /* Signature parameters */
const void *raw_serial; /* Raw serial number in ASN.1 */
unsigned raw_serial_size;
unsigned raw_issuer_size;
const void *raw_issuer; /* Raw issuer name in ASN.1 */
const void *raw_subject; /* Raw subject name in ASN.1 */
unsigned raw_subject_size;
unsigned index;
bool seen; /* Infinite recursion prevention */
bool verified;
bool trusted;
};
/*

View File

@ -18,11 +18,80 @@
#include <linux/asn1_decoder.h>
#include <keys/asymmetric-subtype.h>
#include <keys/asymmetric-parser.h>
#include <keys/system_keyring.h>
#include <crypto/hash.h>
#include "asymmetric_keys.h"
#include "public_key.h"
#include "x509_parser.h"
static bool use_builtin_keys;
static char *ca_keyid;
#ifndef MODULE
static int __init ca_keys_setup(char *str)
{
if (!str) /* default system keyring */
return 1;
if (strncmp(str, "id:", 3) == 0)
ca_keyid = str; /* owner key 'id:xxxxxx' */
else if (strcmp(str, "builtin") == 0)
use_builtin_keys = true;
return 1;
}
__setup("ca_keys=", ca_keys_setup);
#endif
/*
* Find a key in the given keyring by issuer and authority.
*/
static struct key *x509_request_asymmetric_key(struct key *keyring,
const char *signer,
size_t signer_len,
const char *authority,
size_t auth_len)
{
key_ref_t key;
char *id;
/* Construct an identifier. */
id = kmalloc(signer_len + 2 + auth_len + 1, GFP_KERNEL);
if (!id)
return ERR_PTR(-ENOMEM);
memcpy(id, signer, signer_len);
id[signer_len + 0] = ':';
id[signer_len + 1] = ' ';
memcpy(id + signer_len + 2, authority, auth_len);
id[signer_len + 2 + auth_len] = 0;
pr_debug("Look up: \"%s\"\n", id);
key = keyring_search(make_key_ref(keyring, 1),
&key_type_asymmetric, id);
if (IS_ERR(key))
pr_debug("Request for module key '%s' err %ld\n",
id, PTR_ERR(key));
kfree(id);
if (IS_ERR(key)) {
switch (PTR_ERR(key)) {
/* Hide some search errors */
case -EACCES:
case -ENOTDIR:
case -EAGAIN:
return ERR_PTR(-ENOKEY);
default:
return ERR_CAST(key);
}
}
pr_devel("<==%s() = 0 [%x]\n", __func__,
key_serial(key_ref_to_ptr(key)));
return key_ref_to_ptr(key);
}
/*
* Set up the signature parameters in an X.509 certificate. This involves
* digesting the signed data and extracting the signature.
@ -102,6 +171,40 @@ int x509_check_signature(const struct public_key *pub,
}
EXPORT_SYMBOL_GPL(x509_check_signature);
/*
* Check the new certificate against the ones in the trust keyring. If one of
* those is the signing key and validates the new certificate, then mark the
* new certificate as being trusted.
*
* Return 0 if the new certificate was successfully validated, 1 if we couldn't
* find a matching parent certificate in the trusted list and an error if there
* is a matching certificate but the signature check fails.
*/
static int x509_validate_trust(struct x509_certificate *cert,
struct key *trust_keyring)
{
struct key *key;
int ret = 1;
if (!trust_keyring)
return -EOPNOTSUPP;
if (ca_keyid && !asymmetric_keyid_match(cert->authority, ca_keyid))
return -EPERM;
key = x509_request_asymmetric_key(trust_keyring,
cert->issuer, strlen(cert->issuer),
cert->authority,
strlen(cert->authority));
if (!IS_ERR(key)) {
if (!use_builtin_keys
|| test_bit(KEY_FLAG_BUILTIN, &key->flags))
ret = x509_check_signature(key->payload.data, cert);
key_put(key);
}
return ret;
}
/*
* Attempt to parse a data blob for a key as an X509 certificate.
*/
@ -155,9 +258,13 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
/* Check the signature on the key if it appears to be self-signed */
if (!cert->authority ||
strcmp(cert->fingerprint, cert->authority) == 0) {
ret = x509_check_signature(cert->pub, cert);
ret = x509_check_signature(cert->pub, cert); /* self-signed */
if (ret < 0)
goto error_free_cert;
} else if (!prep->trusted) {
ret = x509_validate_trust(cert, get_system_trusted_keyring());
if (!ret)
prep->trusted = 1;
}
/* Propose a description */
@ -177,7 +284,7 @@ static int x509_key_preparse(struct key_preparsed_payload *prep)
__module_get(public_key_subtype.owner);
prep->type_data[0] = &public_key_subtype;
prep->type_data[1] = cert->fingerprint;
prep->payload = cert->pub;
prep->payload[0] = cert->pub;
prep->description = desc;
prep->quotalen = 100;

View File

@ -174,7 +174,9 @@ static int nfs_map_numeric_to_string(__u32 id, char *buf, size_t buflen)
static struct key_type key_type_id_resolver = {
.name = "id_resolver",
.instantiate = user_instantiate,
.preparse = user_preparse,
.free_preparse = user_free_preparse,
.instantiate = generic_key_instantiate,
.match = user_match,
.revoke = user_revoke,
.destroy = user_destroy,
@ -282,6 +284,8 @@ static struct key *nfs_idmap_request_key(const char *name, size_t namelen,
desc, "", 0, idmap);
mutex_unlock(&idmap->idmap_mutex);
}
if (!IS_ERR(rkey))
set_bit(KEY_FLAG_ROOT_CAN_INVAL, &rkey->flags);
kfree(desc);
return rkey;
@ -394,7 +398,9 @@ static const struct rpc_pipe_ops idmap_upcall_ops = {
static struct key_type key_type_id_resolver_legacy = {
.name = "id_legacy",
.instantiate = user_instantiate,
.preparse = user_preparse,
.free_preparse = user_free_preparse,
.instantiate = generic_key_instantiate,
.match = user_match,
.revoke = user_revoke,
.destroy = user_destroy,

36
include/crypto/pkcs7.h Normal file
View File

@ -0,0 +1,36 @@
/* PKCS#7 crypto data 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.
*/
struct key;
struct pkcs7_message;
/*
* pkcs7_parser.c
*/
extern struct pkcs7_message *pkcs7_parse_message(const void *data,
size_t datalen);
extern void pkcs7_free_message(struct pkcs7_message *pkcs7);
extern int pkcs7_get_content_data(const struct pkcs7_message *pkcs7,
const void **_data, size_t *_datalen,
bool want_wrapper);
/*
* pkcs7_trust.c
*/
extern int pkcs7_validate_trust(struct pkcs7_message *pkcs7,
struct key *trust_keyring,
bool *_trusted);
/*
* pkcs7_verify.c
*/
extern int pkcs7_verify(struct pkcs7_message *pkcs7);

View File

@ -16,7 +16,8 @@
extern struct key_type key_type_big_key;
extern int big_key_instantiate(struct key *key, struct key_preparsed_payload *prep);
extern int big_key_preparse(struct key_preparsed_payload *prep);
extern void big_key_free_preparse(struct key_preparsed_payload *prep);
extern void big_key_revoke(struct key *key);
extern void big_key_destroy(struct key *key);
extern void big_key_describe(const struct key *big_key, struct seq_file *m);

View File

@ -17,7 +17,15 @@
#include <linux/key.h>
extern struct key *system_trusted_keyring;
static inline struct key *get_system_trusted_keyring(void)
{
return system_trusted_keyring;
}
#else
static inline struct key *get_system_trusted_keyring(void)
{
return NULL;
}
#endif
#endif /* _KEYS_SYSTEM_KEYRING_H */

View File

@ -37,7 +37,8 @@ extern struct key_type key_type_logon;
struct key_preparsed_payload;
extern int user_instantiate(struct key *key, struct key_preparsed_payload *prep);
extern int user_preparse(struct key_preparsed_payload *prep);
extern void user_free_preparse(struct key_preparsed_payload *prep);
extern int user_update(struct key *key, struct key_preparsed_payload *prep);
extern int user_match(const struct key *key, const void *criterion);
extern void user_revoke(struct key *key);

View File

@ -41,10 +41,11 @@ struct key_construction {
struct key_preparsed_payload {
char *description; /* Proposed key description (or NULL) */
void *type_data[2]; /* Private key-type data */
void *payload; /* Proposed payload */
void *payload[2]; /* Proposed payload */
const void *data; /* Raw data */
size_t datalen; /* Raw datalen */
size_t quotalen; /* Quota length for proposed payload */
time_t expiry; /* Expiry time of key */
bool trusted; /* True if key is trusted */
};
@ -159,5 +160,7 @@ static inline int key_negate_and_link(struct key *key,
return key_reject_and_link(key, timeout, ENOKEY, keyring, instkey);
}
extern int generic_key_instantiate(struct key *key, struct key_preparsed_payload *prep);
#endif /* CONFIG_KEYS */
#endif /* _LINUX_KEY_TYPE_H */

View File

@ -170,6 +170,8 @@ struct key {
#define KEY_FLAG_INVALIDATED 7 /* set if key has been invalidated */
#define KEY_FLAG_TRUSTED 8 /* set if key is trusted */
#define KEY_FLAG_TRUSTED_ONLY 9 /* set if keyring only accepts links to trusted keys */
#define KEY_FLAG_BUILTIN 10 /* set if key is builtin */
#define KEY_FLAG_ROOT_CAN_INVAL 11 /* set if key can be invalidated by root without permission */
/* the key type and key description string
* - the desc is used to match a key against search criteria

View File

@ -52,9 +52,15 @@ enum OID {
OID_md4, /* 1.2.840.113549.2.4 */
OID_md5, /* 1.2.840.113549.2.5 */
OID_certAuthInfoAccess, /* 1.3.6.1.5.5.7.1.1 */
/* Microsoft Authenticode & Software Publishing */
OID_msIndirectData, /* 1.3.6.1.4.1.311.2.1.4 */
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 */
OID_certAuthInfoAccess, /* 1.3.6.1.5.5.7.1.1 */
OID_sha1, /* 1.3.14.3.2.26 */
OID_sha256, /* 2.16.840.1.101.3.4.2.1 */
/* Distinguished Name attribute IDs [RFC 2256] */
OID_commonName, /* 2.5.4.3 */

448
include/linux/pe.h Normal file
View File

@ -0,0 +1,448 @@
/*
* Copyright 2011 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Author(s): Peter Jones <pjones@redhat.com>
*/
#ifndef __LINUX_PE_H
#define __LINUX_PE_H
#include <linux/types.h>
#define MZ_MAGIC 0x5a4d /* "MZ" */
struct mz_hdr {
uint16_t magic; /* MZ_MAGIC */
uint16_t lbsize; /* size of last used block */
uint16_t blocks; /* pages in file, 0x3 */
uint16_t relocs; /* relocations */
uint16_t hdrsize; /* header size in "paragraphs" */
uint16_t min_extra_pps; /* .bss */
uint16_t max_extra_pps; /* runtime limit for the arena size */
uint16_t ss; /* relative stack segment */
uint16_t sp; /* initial %sp register */
uint16_t checksum; /* word checksum */
uint16_t ip; /* initial %ip register */
uint16_t cs; /* initial %cs relative to load segment */
uint16_t reloc_table_offset; /* offset of the first relocation */
uint16_t overlay_num; /* overlay number. set to 0. */
uint16_t reserved0[4]; /* reserved */
uint16_t oem_id; /* oem identifier */
uint16_t oem_info; /* oem specific */
uint16_t reserved1[10]; /* reserved */
uint32_t peaddr; /* address of pe header */
char message[64]; /* message to print */
};
struct mz_reloc {
uint16_t offset;
uint16_t segment;
};
#define PE_MAGIC 0x00004550 /* "PE\0\0" */
#define PE_OPT_MAGIC_PE32 0x010b
#define PE_OPT_MAGIC_PE32_ROM 0x0107
#define PE_OPT_MAGIC_PE32PLUS 0x020b
/* machine type */
#define IMAGE_FILE_MACHINE_UNKNOWN 0x0000
#define IMAGE_FILE_MACHINE_AM33 0x01d3
#define IMAGE_FILE_MACHINE_AMD64 0x8664
#define IMAGE_FILE_MACHINE_ARM 0x01c0
#define IMAGE_FILE_MACHINE_ARMV7 0x01c4
#define IMAGE_FILE_MACHINE_EBC 0x0ebc
#define IMAGE_FILE_MACHINE_I386 0x014c
#define IMAGE_FILE_MACHINE_IA64 0x0200
#define IMAGE_FILE_MACHINE_M32R 0x9041
#define IMAGE_FILE_MACHINE_MIPS16 0x0266
#define IMAGE_FILE_MACHINE_MIPSFPU 0x0366
#define IMAGE_FILE_MACHINE_MIPSFPU16 0x0466
#define IMAGE_FILE_MACHINE_POWERPC 0x01f0
#define IMAGE_FILE_MACHINE_POWERPCFP 0x01f1
#define IMAGE_FILE_MACHINE_R4000 0x0166
#define IMAGE_FILE_MACHINE_SH3 0x01a2
#define IMAGE_FILE_MACHINE_SH3DSP 0x01a3
#define IMAGE_FILE_MACHINE_SH3E 0x01a4
#define IMAGE_FILE_MACHINE_SH4 0x01a6
#define IMAGE_FILE_MACHINE_SH5 0x01a8
#define IMAGE_FILE_MACHINE_THUMB 0x01c2
#define IMAGE_FILE_MACHINE_WCEMIPSV2 0x0169
/* flags */
#define IMAGE_FILE_RELOCS_STRIPPED 0x0001
#define IMAGE_FILE_EXECUTABLE_IMAGE 0x0002
#define IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004
#define IMAGE_FILE_LOCAL_SYMS_STRIPPED 0x0008
#define IMAGE_FILE_AGGRESSIVE_WS_TRIM 0x0010
#define IMAGE_FILE_LARGE_ADDRESS_AWARE 0x0020
#define IMAGE_FILE_16BIT_MACHINE 0x0040
#define IMAGE_FILE_BYTES_REVERSED_LO 0x0080
#define IMAGE_FILE_32BIT_MACHINE 0x0100
#define IMAGE_FILE_DEBUG_STRIPPED 0x0200
#define IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP 0x0400
#define IMAGE_FILE_NET_RUN_FROM_SWAP 0x0800
#define IMAGE_FILE_SYSTEM 0x1000
#define IMAGE_FILE_DLL 0x2000
#define IMAGE_FILE_UP_SYSTEM_ONLY 0x4000
#define IMAGE_FILE_BYTES_REVERSED_HI 0x8000
struct pe_hdr {
uint32_t magic; /* PE magic */
uint16_t machine; /* machine type */
uint16_t sections; /* number of sections */
uint32_t timestamp; /* time_t */
uint32_t symbol_table; /* symbol table offset */
uint32_t symbols; /* number of symbols */
uint16_t opt_hdr_size; /* size of optional header */
uint16_t flags; /* flags */
};
#define IMAGE_FILE_OPT_ROM_MAGIC 0x107
#define IMAGE_FILE_OPT_PE32_MAGIC 0x10b
#define IMAGE_FILE_OPT_PE32_PLUS_MAGIC 0x20b
#define IMAGE_SUBSYSTEM_UNKNOWN 0
#define IMAGE_SUBSYSTEM_NATIVE 1
#define IMAGE_SUBSYSTEM_WINDOWS_GUI 2
#define IMAGE_SUBSYSTEM_WINDOWS_CUI 3
#define IMAGE_SUBSYSTEM_POSIX_CUI 7
#define IMAGE_SUBSYSTEM_WINDOWS_CE_GUI 9
#define IMAGE_SUBSYSTEM_EFI_APPLICATION 10
#define IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER 11
#define IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER 12
#define IMAGE_SUBSYSTEM_EFI_ROM_IMAGE 13
#define IMAGE_SUBSYSTEM_XBOX 14
#define IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE 0x0040
#define IMAGE_DLL_CHARACTERISTICS_FORCE_INTEGRITY 0x0080
#define IMAGE_DLL_CHARACTERISTICS_NX_COMPAT 0x0100
#define IMAGE_DLLCHARACTERISTICS_NO_ISOLATION 0x0200
#define IMAGE_DLLCHARACTERISTICS_NO_SEH 0x0400
#define IMAGE_DLLCHARACTERISTICS_NO_BIND 0x0800
#define IMAGE_DLLCHARACTERISTICS_WDM_DRIVER 0x2000
#define IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE 0x8000
/* the fact that pe32 isn't padded where pe32+ is 64-bit means union won't
* work right. vomit. */
struct pe32_opt_hdr {
/* "standard" header */
uint16_t magic; /* file type */
uint8_t ld_major; /* linker major version */
uint8_t ld_minor; /* linker minor version */
uint32_t text_size; /* size of text section(s) */
uint32_t data_size; /* size of data section(s) */
uint32_t bss_size; /* size of bss section(s) */
uint32_t entry_point; /* file offset of entry point */
uint32_t code_base; /* relative code addr in ram */
uint32_t data_base; /* relative data addr in ram */
/* "windows" header */
uint32_t image_base; /* preferred load address */
uint32_t section_align; /* alignment in bytes */
uint32_t file_align; /* file alignment in bytes */
uint16_t os_major; /* major OS version */
uint16_t os_minor; /* minor OS version */
uint16_t image_major; /* major image version */
uint16_t image_minor; /* minor image version */
uint16_t subsys_major; /* major subsystem version */
uint16_t subsys_minor; /* minor subsystem version */
uint32_t win32_version; /* reserved, must be 0 */
uint32_t image_size; /* image size */
uint32_t header_size; /* header size rounded up to
file_align */
uint32_t csum; /* checksum */
uint16_t subsys; /* subsystem */
uint16_t dll_flags; /* more flags! */
uint32_t stack_size_req;/* amt of stack requested */
uint32_t stack_size; /* amt of stack required */
uint32_t heap_size_req; /* amt of heap requested */
uint32_t heap_size; /* amt of heap required */
uint32_t loader_flags; /* reserved, must be 0 */
uint32_t data_dirs; /* number of data dir entries */
};
struct pe32plus_opt_hdr {
uint16_t magic; /* file type */
uint8_t ld_major; /* linker major version */
uint8_t ld_minor; /* linker minor version */
uint32_t text_size; /* size of text section(s) */
uint32_t data_size; /* size of data section(s) */
uint32_t bss_size; /* size of bss section(s) */
uint32_t entry_point; /* file offset of entry point */
uint32_t code_base; /* relative code addr in ram */
/* "windows" header */
uint64_t image_base; /* preferred load address */
uint32_t section_align; /* alignment in bytes */
uint32_t file_align; /* file alignment in bytes */
uint16_t os_major; /* major OS version */
uint16_t os_minor; /* minor OS version */
uint16_t image_major; /* major image version */
uint16_t image_minor; /* minor image version */
uint16_t subsys_major; /* major subsystem version */
uint16_t subsys_minor; /* minor subsystem version */
uint32_t win32_version; /* reserved, must be 0 */
uint32_t image_size; /* image size */
uint32_t header_size; /* header size rounded up to
file_align */
uint32_t csum; /* checksum */
uint16_t subsys; /* subsystem */
uint16_t dll_flags; /* more flags! */
uint64_t stack_size_req;/* amt of stack requested */
uint64_t stack_size; /* amt of stack required */
uint64_t heap_size_req; /* amt of heap requested */
uint64_t heap_size; /* amt of heap required */
uint32_t loader_flags; /* reserved, must be 0 */
uint32_t data_dirs; /* number of data dir entries */
};
struct data_dirent {
uint32_t virtual_address; /* relative to load address */
uint32_t size;
};
struct data_directory {
struct data_dirent exports; /* .edata */
struct data_dirent imports; /* .idata */
struct data_dirent resources; /* .rsrc */
struct data_dirent exceptions; /* .pdata */
struct data_dirent certs; /* certs */
struct data_dirent base_relocations; /* .reloc */
struct data_dirent debug; /* .debug */
struct data_dirent arch; /* reservered */
struct data_dirent global_ptr; /* global pointer reg. Size=0 */
struct data_dirent tls; /* .tls */
struct data_dirent load_config; /* load configuration structure */
struct data_dirent bound_imports; /* no idea */
struct data_dirent import_addrs; /* import address table */
struct data_dirent delay_imports; /* delay-load import table */
struct data_dirent clr_runtime_hdr; /* .cor (object only) */
struct data_dirent reserved;
};
struct section_header {
char name[8]; /* name or "/12\0" string tbl offset */
uint32_t virtual_size; /* size of loaded section in ram */
uint32_t virtual_address; /* relative virtual address */
uint32_t raw_data_size; /* size of the section */
uint32_t data_addr; /* file pointer to first page of sec */
uint32_t relocs; /* file pointer to relocation entries */
uint32_t line_numbers; /* line numbers! */
uint16_t num_relocs; /* number of relocations */
uint16_t num_lin_numbers; /* srsly. */
uint32_t flags;
};
/* they actually defined 0x00000000 as well, but I think we'll skip that one. */
#define IMAGE_SCN_RESERVED_0 0x00000001
#define IMAGE_SCN_RESERVED_1 0x00000002
#define IMAGE_SCN_RESERVED_2 0x00000004
#define IMAGE_SCN_TYPE_NO_PAD 0x00000008 /* don't pad - obsolete */
#define IMAGE_SCN_RESERVED_3 0x00000010
#define IMAGE_SCN_CNT_CODE 0x00000020 /* .text */
#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 /* .data */
#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 /* .bss */
#define IMAGE_SCN_LNK_OTHER 0x00000100 /* reserved */
#define IMAGE_SCN_LNK_INFO 0x00000200 /* .drectve comments */
#define IMAGE_SCN_RESERVED_4 0x00000400
#define IMAGE_SCN_LNK_REMOVE 0x00000800 /* .o only - scn to be rm'd*/
#define IMAGE_SCN_LNK_COMDAT 0x00001000 /* .o only - COMDAT data */
#define IMAGE_SCN_RESERVED_5 0x00002000 /* spec omits this */
#define IMAGE_SCN_RESERVED_6 0x00004000 /* spec omits this */
#define IMAGE_SCN_GPREL 0x00008000 /* global pointer referenced data */
/* spec lists 0x20000 twice, I suspect they meant 0x10000 for one of them */
#define IMAGE_SCN_MEM_PURGEABLE 0x00010000 /* reserved for "future" use */
#define IMAGE_SCN_16BIT 0x00020000 /* reserved for "future" use */
#define IMAGE_SCN_LOCKED 0x00040000 /* reserved for "future" use */
#define IMAGE_SCN_PRELOAD 0x00080000 /* reserved for "future" use */
/* and here they just stuck a 1-byte integer in the middle of a bitfield */
#define IMAGE_SCN_ALIGN_1BYTES 0x00100000 /* it does what it says on the box */
#define IMAGE_SCN_ALIGN_2BYTES 0x00200000
#define IMAGE_SCN_ALIGN_4BYTES 0x00300000
#define IMAGE_SCN_ALIGN_8BYTES 0x00400000
#define IMAGE_SCN_ALIGN_16BYTES 0x00500000
#define IMAGE_SCN_ALIGN_32BYTES 0x00600000
#define IMAGE_SCN_ALIGN_64BYTES 0x00700000
#define IMAGE_SCN_ALIGN_128BYTES 0x00800000
#define IMAGE_SCN_ALIGN_256BYTES 0x00900000
#define IMAGE_SCN_ALIGN_512BYTES 0x00a00000
#define IMAGE_SCN_ALIGN_1024BYTES 0x00b00000
#define IMAGE_SCN_ALIGN_2048BYTES 0x00c00000
#define IMAGE_SCN_ALIGN_4096BYTES 0x00d00000
#define IMAGE_SCN_ALIGN_8192BYTES 0x00e00000
#define IMAGE_SCN_LNK_NRELOC_OVFL 0x01000000 /* extended relocations */
#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000 /* scn can be discarded */
#define IMAGE_SCN_MEM_NOT_CACHED 0x04000000 /* cannot be cached */
#define IMAGE_SCN_MEM_NOT_PAGED 0x08000000 /* not pageable */
#define IMAGE_SCN_MEM_SHARED 0x10000000 /* can be shared */
#define IMAGE_SCN_MEM_EXECUTE 0x20000000 /* can be executed as code */
#define IMAGE_SCN_MEM_READ 0x40000000 /* readable */
#define IMAGE_SCN_MEM_WRITE 0x80000000 /* writeable */
enum x64_coff_reloc_type {
IMAGE_REL_AMD64_ABSOLUTE = 0,
IMAGE_REL_AMD64_ADDR64,
IMAGE_REL_AMD64_ADDR32,
IMAGE_REL_AMD64_ADDR32N,
IMAGE_REL_AMD64_REL32,
IMAGE_REL_AMD64_REL32_1,
IMAGE_REL_AMD64_REL32_2,
IMAGE_REL_AMD64_REL32_3,
IMAGE_REL_AMD64_REL32_4,
IMAGE_REL_AMD64_REL32_5,
IMAGE_REL_AMD64_SECTION,
IMAGE_REL_AMD64_SECREL,
IMAGE_REL_AMD64_SECREL7,
IMAGE_REL_AMD64_TOKEN,
IMAGE_REL_AMD64_SREL32,
IMAGE_REL_AMD64_PAIR,
IMAGE_REL_AMD64_SSPAN32,
};
enum arm_coff_reloc_type {
IMAGE_REL_ARM_ABSOLUTE,
IMAGE_REL_ARM_ADDR32,
IMAGE_REL_ARM_ADDR32N,
IMAGE_REL_ARM_BRANCH2,
IMAGE_REL_ARM_BRANCH1,
IMAGE_REL_ARM_SECTION,
IMAGE_REL_ARM_SECREL,
};
enum sh_coff_reloc_type {
IMAGE_REL_SH3_ABSOLUTE,
IMAGE_REL_SH3_DIRECT16,
IMAGE_REL_SH3_DIRECT32,
IMAGE_REL_SH3_DIRECT8,
IMAGE_REL_SH3_DIRECT8_WORD,
IMAGE_REL_SH3_DIRECT8_LONG,
IMAGE_REL_SH3_DIRECT4,
IMAGE_REL_SH3_DIRECT4_WORD,
IMAGE_REL_SH3_DIRECT4_LONG,
IMAGE_REL_SH3_PCREL8_WORD,
IMAGE_REL_SH3_PCREL8_LONG,
IMAGE_REL_SH3_PCREL12_WORD,
IMAGE_REL_SH3_STARTOF_SECTION,
IMAGE_REL_SH3_SIZEOF_SECTION,
IMAGE_REL_SH3_SECTION,
IMAGE_REL_SH3_SECREL,
IMAGE_REL_SH3_DIRECT32_NB,
IMAGE_REL_SH3_GPREL4_LONG,
IMAGE_REL_SH3_TOKEN,
IMAGE_REL_SHM_PCRELPT,
IMAGE_REL_SHM_REFLO,
IMAGE_REL_SHM_REFHALF,
IMAGE_REL_SHM_RELLO,
IMAGE_REL_SHM_RELHALF,
IMAGE_REL_SHM_PAIR,
IMAGE_REL_SHM_NOMODE,
};
enum ppc_coff_reloc_type {
IMAGE_REL_PPC_ABSOLUTE,
IMAGE_REL_PPC_ADDR64,
IMAGE_REL_PPC_ADDR32,
IMAGE_REL_PPC_ADDR24,
IMAGE_REL_PPC_ADDR16,
IMAGE_REL_PPC_ADDR14,
IMAGE_REL_PPC_REL24,
IMAGE_REL_PPC_REL14,
IMAGE_REL_PPC_ADDR32N,
IMAGE_REL_PPC_SECREL,
IMAGE_REL_PPC_SECTION,
IMAGE_REL_PPC_SECREL16,
IMAGE_REL_PPC_REFHI,
IMAGE_REL_PPC_REFLO,
IMAGE_REL_PPC_PAIR,
IMAGE_REL_PPC_SECRELLO,
IMAGE_REL_PPC_GPREL,
IMAGE_REL_PPC_TOKEN,
};
enum x86_coff_reloc_type {
IMAGE_REL_I386_ABSOLUTE,
IMAGE_REL_I386_DIR16,
IMAGE_REL_I386_REL16,
IMAGE_REL_I386_DIR32,
IMAGE_REL_I386_DIR32NB,
IMAGE_REL_I386_SEG12,
IMAGE_REL_I386_SECTION,
IMAGE_REL_I386_SECREL,
IMAGE_REL_I386_TOKEN,
IMAGE_REL_I386_SECREL7,
IMAGE_REL_I386_REL32,
};
enum ia64_coff_reloc_type {
IMAGE_REL_IA64_ABSOLUTE,
IMAGE_REL_IA64_IMM14,
IMAGE_REL_IA64_IMM22,
IMAGE_REL_IA64_IMM64,
IMAGE_REL_IA64_DIR32,
IMAGE_REL_IA64_DIR64,
IMAGE_REL_IA64_PCREL21B,
IMAGE_REL_IA64_PCREL21M,
IMAGE_REL_IA64_PCREL21F,
IMAGE_REL_IA64_GPREL22,
IMAGE_REL_IA64_LTOFF22,
IMAGE_REL_IA64_SECTION,
IMAGE_REL_IA64_SECREL22,
IMAGE_REL_IA64_SECREL64I,
IMAGE_REL_IA64_SECREL32,
IMAGE_REL_IA64_DIR32NB,
IMAGE_REL_IA64_SREL14,
IMAGE_REL_IA64_SREL22,
IMAGE_REL_IA64_SREL32,
IMAGE_REL_IA64_UREL32,
IMAGE_REL_IA64_PCREL60X,
IMAGE_REL_IA64_PCREL60B,
IMAGE_REL_IA64_PCREL60F,
IMAGE_REL_IA64_PCREL60I,
IMAGE_REL_IA64_PCREL60M,
IMAGE_REL_IA64_IMMGPREL6,
IMAGE_REL_IA64_TOKEN,
IMAGE_REL_IA64_GPREL32,
IMAGE_REL_IA64_ADDEND,
};
struct coff_reloc {
uint32_t virtual_address;
uint32_t symbol_table_index;
union {
enum x64_coff_reloc_type x64_type;
enum arm_coff_reloc_type arm_type;
enum sh_coff_reloc_type sh_type;
enum ppc_coff_reloc_type ppc_type;
enum x86_coff_reloc_type x86_type;
enum ia64_coff_reloc_type ia64_type;
uint16_t data;
};
};
/*
* Definitions for the contents of the certs data block
*/
#define WIN_CERT_TYPE_PKCS_SIGNED_DATA 0x0002
#define WIN_CERT_TYPE_EFI_OKCS115 0x0EF0
#define WIN_CERT_TYPE_EFI_GUID 0x0EF1
#define WIN_CERT_REVISION_1_0 0x0100
#define WIN_CERT_REVISION_2_0 0x0200
struct win_certificate {
uint32_t length;
uint16_t revision;
uint16_t cert_type;
};
#endif /* __LINUX_PE_H */

View File

@ -0,0 +1,18 @@
/* Signed PE file verification
*
* Copyright (C) 2014 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public Licence
* as published by the Free Software Foundation; either version
* 2 of the Licence, or (at your option) any later version.
*/
#ifndef _LINUX_VERIFY_PEFILE_H
#define _LINUX_VERIFY_PEFILE_H
extern int verify_pefile_signature(const void *pebuf, unsigned pelen,
struct key *trusted_keyring, bool *_trusted);
#endif /* _LINUX_VERIFY_PEFILE_H */

View File

@ -89,6 +89,7 @@ static __init int load_system_certificate_list(void)
pr_err("Problem loading in-kernel X.509 certificate (%ld)\n",
PTR_ERR(key));
} else {
set_bit(KEY_FLAG_BUILTIN, &key_ref_to_ptr(key)->flags);
pr_notice("Loaded X.509 cert '%s'\n",
key_ref_to_ptr(key)->description);
key_ref_put(key);

View File

@ -451,7 +451,8 @@ config MPILIB
config SIGNATURE
tristate
depends on KEYS && CRYPTO
depends on KEYS
select CRYPTO
select CRYPTO_SHA1
select MPILIB
help

View File

@ -8,6 +8,7 @@
#include <linux/key-type.h>
#include <keys/ceph-type.h>
#include <keys/user-type.h>
#include <linux/ceph/decode.h>
#include "crypto.h"
@ -423,8 +424,7 @@ int ceph_encrypt2(struct ceph_crypto_key *secret, void *dst, size_t *dst_len,
}
}
static int ceph_key_instantiate(struct key *key,
struct key_preparsed_payload *prep)
static int ceph_key_preparse(struct key_preparsed_payload *prep)
{
struct ceph_crypto_key *ckey;
size_t datalen = prep->datalen;
@ -435,10 +435,6 @@ static int ceph_key_instantiate(struct key *key,
if (datalen <= 0 || datalen > 32767 || !prep->data)
goto err;
ret = key_payload_reserve(key, datalen);
if (ret < 0)
goto err;
ret = -ENOMEM;
ckey = kmalloc(sizeof(*ckey), GFP_KERNEL);
if (!ckey)
@ -450,7 +446,8 @@ static int ceph_key_instantiate(struct key *key,
if (ret < 0)
goto err_ckey;
key->payload.data = ckey;
prep->payload[0] = ckey;
prep->quotalen = datalen;
return 0;
err_ckey:
@ -459,12 +456,15 @@ err:
return ret;
}
static int ceph_key_match(const struct key *key, const void *description)
static void ceph_key_free_preparse(struct key_preparsed_payload *prep)
{
return strcmp(key->description, description) == 0;
struct ceph_crypto_key *ckey = prep->payload[0];
ceph_crypto_key_destroy(ckey);
kfree(ckey);
}
static void ceph_key_destroy(struct key *key) {
static void ceph_key_destroy(struct key *key)
{
struct ceph_crypto_key *ckey = key->payload.data;
ceph_crypto_key_destroy(ckey);
@ -473,8 +473,10 @@ static void ceph_key_destroy(struct key *key) {
struct key_type key_type_ceph = {
.name = "ceph",
.instantiate = ceph_key_instantiate,
.match = ceph_key_match,
.preparse = ceph_key_preparse,
.free_preparse = ceph_key_free_preparse,
.instantiate = generic_key_instantiate,
.match = user_match,
.destroy = ceph_key_destroy,
};

View File

@ -46,7 +46,7 @@ const struct cred *dns_resolver_cache;
#define DNS_ERRORNO_OPTION "dnserror"
/*
* Instantiate a user defined key for dns_resolver.
* Preparse instantiation data for a dns_resolver key.
*
* The data must be a NUL-terminated string, with the NUL char accounted in
* datalen.
@ -58,17 +58,15 @@ const struct cred *dns_resolver_cache;
* "ip1,ip2,...#foo=bar"
*/
static int
dns_resolver_instantiate(struct key *key, struct key_preparsed_payload *prep)
dns_resolver_preparse(struct key_preparsed_payload *prep)
{
struct user_key_payload *upayload;
unsigned long derrno;
int ret;
size_t datalen = prep->datalen, result_len = 0;
int datalen = prep->datalen, result_len = 0;
const char *data = prep->data, *end, *opt;
kenter("%%%d,%s,'%*.*s',%zu",
key->serial, key->description,
(int)datalen, (int)datalen, data, datalen);
kenter("'%*.*s',%u", datalen, datalen, data, datalen);
if (datalen <= 1 || !data || data[datalen - 1] != '\0')
return -EINVAL;
@ -95,8 +93,7 @@ dns_resolver_instantiate(struct key *key, struct key_preparsed_payload *prep)
opt_len = next_opt - opt;
if (!opt_len) {
printk(KERN_WARNING
"Empty option to dns_resolver key %d\n",
key->serial);
"Empty option to dns_resolver key\n");
return -EINVAL;
}
@ -125,30 +122,28 @@ dns_resolver_instantiate(struct key *key, struct key_preparsed_payload *prep)
goto bad_option_value;
kdebug("dns error no. = %lu", derrno);
key->type_data.x[0] = -derrno;
prep->type_data[0] = ERR_PTR(-derrno);
continue;
}
bad_option_value:
printk(KERN_WARNING
"Option '%*.*s' to dns_resolver key %d:"
"Option '%*.*s' to dns_resolver key:"
" bad/missing value\n",
opt_nlen, opt_nlen, opt, key->serial);
opt_nlen, opt_nlen, opt);
return -EINVAL;
} while (opt = next_opt + 1, opt < end);
}
/* don't cache the result if we're caching an error saying there's no
* result */
if (key->type_data.x[0]) {
kleave(" = 0 [h_error %ld]", key->type_data.x[0]);
if (prep->type_data[0]) {
kleave(" = 0 [h_error %ld]", PTR_ERR(prep->type_data[0]));
return 0;
}
kdebug("store result");
ret = key_payload_reserve(key, result_len);
if (ret < 0)
return -EINVAL;
prep->quotalen = result_len;
upayload = kmalloc(sizeof(*upayload) + result_len + 1, GFP_KERNEL);
if (!upayload) {
@ -159,12 +154,22 @@ dns_resolver_instantiate(struct key *key, struct key_preparsed_payload *prep)
upayload->datalen = result_len;
memcpy(upayload->data, data, result_len);
upayload->data[result_len] = '\0';
rcu_assign_pointer(key->payload.data, upayload);
prep->payload[0] = upayload;
kleave(" = 0");
return 0;
}
/*
* Clean up the preparse data
*/
static void dns_resolver_free_preparse(struct key_preparsed_payload *prep)
{
pr_devel("==>%s()\n", __func__);
kfree(prep->payload[0]);
}
/*
* The description is of the form "[<type>:]<domain_name>"
*
@ -234,7 +239,9 @@ static long dns_resolver_read(const struct key *key,
struct key_type key_type_dns_resolver = {
.name = "dns_resolver",
.instantiate = dns_resolver_instantiate,
.preparse = dns_resolver_preparse,
.free_preparse = dns_resolver_free_preparse,
.instantiate = generic_key_instantiate,
.match = dns_resolver_match,
.revoke = user_revoke,
.destroy = user_destroy,

View File

@ -129,6 +129,7 @@ int dns_query(const char *type, const char *name, size_t namelen,
}
down_read(&rkey->sem);
set_bit(KEY_FLAG_ROOT_CAN_INVAL, &rkey->flags);
rkey->perm |= KEY_USR_VIEW;
ret = key_validate(rkey);

View File

@ -26,8 +26,10 @@
#include "ar-internal.h"
static int rxrpc_vet_description_s(const char *);
static int rxrpc_instantiate(struct key *, struct key_preparsed_payload *);
static int rxrpc_instantiate_s(struct key *, struct key_preparsed_payload *);
static int rxrpc_preparse(struct key_preparsed_payload *);
static int rxrpc_preparse_s(struct key_preparsed_payload *);
static void rxrpc_free_preparse(struct key_preparsed_payload *);
static void rxrpc_free_preparse_s(struct key_preparsed_payload *);
static void rxrpc_destroy(struct key *);
static void rxrpc_destroy_s(struct key *);
static void rxrpc_describe(const struct key *, struct seq_file *);
@ -39,7 +41,9 @@ static long rxrpc_read(const struct key *, char __user *, size_t);
*/
struct key_type key_type_rxrpc = {
.name = "rxrpc",
.instantiate = rxrpc_instantiate,
.preparse = rxrpc_preparse,
.free_preparse = rxrpc_free_preparse,
.instantiate = generic_key_instantiate,
.match = user_match,
.destroy = rxrpc_destroy,
.describe = rxrpc_describe,
@ -54,7 +58,9 @@ EXPORT_SYMBOL(key_type_rxrpc);
struct key_type key_type_rxrpc_s = {
.name = "rxrpc_s",
.vet_description = rxrpc_vet_description_s,
.instantiate = rxrpc_instantiate_s,
.preparse = rxrpc_preparse_s,
.free_preparse = rxrpc_free_preparse_s,
.instantiate = generic_key_instantiate,
.match = user_match,
.destroy = rxrpc_destroy_s,
.describe = rxrpc_describe,
@ -81,13 +87,13 @@ static int rxrpc_vet_description_s(const char *desc)
* parse an RxKAD type XDR format token
* - the caller guarantees we have at least 4 words
*/
static int rxrpc_instantiate_xdr_rxkad(struct key *key, const __be32 *xdr,
unsigned int toklen)
static int rxrpc_preparse_xdr_rxkad(struct key_preparsed_payload *prep,
size_t datalen,
const __be32 *xdr, unsigned int toklen)
{
struct rxrpc_key_token *token, **pptoken;
size_t plen;
u32 tktlen;
int ret;
_enter(",{%x,%x,%x,%x},%u",
ntohl(xdr[0]), ntohl(xdr[1]), ntohl(xdr[2]), ntohl(xdr[3]),
@ -103,9 +109,7 @@ static int rxrpc_instantiate_xdr_rxkad(struct key *key, const __be32 *xdr,
return -EKEYREJECTED;
plen = sizeof(*token) + sizeof(*token->kad) + tktlen;
ret = key_payload_reserve(key, key->datalen + plen);
if (ret < 0)
return ret;
prep->quotalen = datalen + plen;
plen -= sizeof(*token);
token = kzalloc(sizeof(*token), GFP_KERNEL);
@ -146,16 +150,16 @@ static int rxrpc_instantiate_xdr_rxkad(struct key *key, const __be32 *xdr,
token->kad->ticket[6], token->kad->ticket[7]);
/* count the number of tokens attached */
key->type_data.x[0]++;
prep->type_data[0] = (void *)((unsigned long)prep->type_data[0] + 1);
/* attach the data */
for (pptoken = (struct rxrpc_key_token **)&key->payload.data;
for (pptoken = (struct rxrpc_key_token **)&prep->payload[0];
*pptoken;
pptoken = &(*pptoken)->next)
continue;
*pptoken = token;
if (token->kad->expiry < key->expiry)
key->expiry = token->kad->expiry;
if (token->kad->expiry < prep->expiry)
prep->expiry = token->kad->expiry;
_leave(" = 0");
return 0;
@ -418,8 +422,9 @@ static int rxrpc_krb5_decode_ticket(u8 **_ticket, u16 *_tktlen,
* parse an RxK5 type XDR format token
* - the caller guarantees we have at least 4 words
*/
static int rxrpc_instantiate_xdr_rxk5(struct key *key, const __be32 *xdr,
unsigned int toklen)
static int rxrpc_preparse_xdr_rxk5(struct key_preparsed_payload *prep,
size_t datalen,
const __be32 *xdr, unsigned int toklen)
{
struct rxrpc_key_token *token, **pptoken;
struct rxk5_key *rxk5;
@ -432,9 +437,7 @@ static int rxrpc_instantiate_xdr_rxk5(struct key *key, const __be32 *xdr,
/* reserve some payload space for this subkey - the length of the token
* is a reasonable approximation */
ret = key_payload_reserve(key, key->datalen + toklen);
if (ret < 0)
return ret;
prep->quotalen = datalen + toklen;
token = kzalloc(sizeof(*token), GFP_KERNEL);
if (!token)
@ -520,14 +523,14 @@ static int rxrpc_instantiate_xdr_rxk5(struct key *key, const __be32 *xdr,
if (toklen != 0)
goto inval;
/* attach the payload to the key */
for (pptoken = (struct rxrpc_key_token **)&key->payload.data;
/* attach the payload */
for (pptoken = (struct rxrpc_key_token **)&prep->payload[0];
*pptoken;
pptoken = &(*pptoken)->next)
continue;
*pptoken = token;
if (token->kad->expiry < key->expiry)
key->expiry = token->kad->expiry;
if (token->kad->expiry < prep->expiry)
prep->expiry = token->kad->expiry;
_leave(" = 0");
return 0;
@ -545,16 +548,17 @@ error:
* attempt to parse the data as the XDR format
* - the caller guarantees we have more than 7 words
*/
static int rxrpc_instantiate_xdr(struct key *key, const void *data, size_t datalen)
static int rxrpc_preparse_xdr(struct key_preparsed_payload *prep)
{
const __be32 *xdr = data, *token;
const __be32 *xdr = prep->data, *token;
const char *cp;
unsigned int len, tmp, loop, ntoken, toklen, sec_ix;
size_t datalen = prep->datalen;
int ret;
_enter(",{%x,%x,%x,%x},%zu",
ntohl(xdr[0]), ntohl(xdr[1]), ntohl(xdr[2]), ntohl(xdr[3]),
datalen);
prep->datalen);
if (datalen > AFSTOKEN_LENGTH_MAX)
goto not_xdr;
@ -635,13 +639,13 @@ static int rxrpc_instantiate_xdr(struct key *key, const void *data, size_t datal
switch (sec_ix) {
case RXRPC_SECURITY_RXKAD:
ret = rxrpc_instantiate_xdr_rxkad(key, xdr, toklen);
ret = rxrpc_preparse_xdr_rxkad(prep, datalen, xdr, toklen);
if (ret != 0)
goto error;
break;
case RXRPC_SECURITY_RXK5:
ret = rxrpc_instantiate_xdr_rxk5(key, xdr, toklen);
ret = rxrpc_preparse_xdr_rxk5(prep, datalen, xdr, toklen);
if (ret != 0)
goto error;
break;
@ -665,8 +669,9 @@ error:
}
/*
* instantiate an rxrpc defined key
* data should be of the form:
* Preparse an rxrpc defined key.
*
* Data should be of the form:
* OFFSET LEN CONTENT
* 0 4 key interface version number
* 4 2 security index (type)
@ -678,7 +683,7 @@ error:
*
* if no data is provided, then a no-security key is made
*/
static int rxrpc_instantiate(struct key *key, struct key_preparsed_payload *prep)
static int rxrpc_preparse(struct key_preparsed_payload *prep)
{
const struct rxrpc_key_data_v1 *v1;
struct rxrpc_key_token *token, **pp;
@ -686,7 +691,7 @@ static int rxrpc_instantiate(struct key *key, struct key_preparsed_payload *prep
u32 kver;
int ret;
_enter("{%x},,%zu", key_serial(key), prep->datalen);
_enter("%zu", prep->datalen);
/* handle a no-security key */
if (!prep->data && prep->datalen == 0)
@ -694,7 +699,7 @@ static int rxrpc_instantiate(struct key *key, struct key_preparsed_payload *prep
/* determine if the XDR payload format is being used */
if (prep->datalen > 7 * 4) {
ret = rxrpc_instantiate_xdr(key, prep->data, prep->datalen);
ret = rxrpc_preparse_xdr(prep);
if (ret != -EPROTO)
return ret;
}
@ -743,9 +748,7 @@ static int rxrpc_instantiate(struct key *key, struct key_preparsed_payload *prep
goto error;
plen = sizeof(*token->kad) + v1->ticket_length;
ret = key_payload_reserve(key, plen + sizeof(*token));
if (ret < 0)
goto error;
prep->quotalen = plen + sizeof(*token);
ret = -ENOMEM;
token = kzalloc(sizeof(*token), GFP_KERNEL);
@ -762,15 +765,16 @@ static int rxrpc_instantiate(struct key *key, struct key_preparsed_payload *prep
memcpy(&token->kad->session_key, &v1->session_key, 8);
memcpy(&token->kad->ticket, v1->ticket, v1->ticket_length);
/* attach the data */
key->type_data.x[0]++;
/* count the number of tokens attached */
prep->type_data[0] = (void *)((unsigned long)prep->type_data[0] + 1);
pp = (struct rxrpc_key_token **)&key->payload.data;
/* attach the data */
pp = (struct rxrpc_key_token **)&prep->payload[0];
while (*pp)
pp = &(*pp)->next;
*pp = token;
if (token->kad->expiry < key->expiry)
key->expiry = token->kad->expiry;
if (token->kad->expiry < prep->expiry)
prep->expiry = token->kad->expiry;
token = NULL;
ret = 0;
@ -781,44 +785,14 @@ error:
}
/*
* instantiate a server secret key
* data should be a pointer to the 8-byte secret key
* Free token list.
*/
static int rxrpc_instantiate_s(struct key *key,
struct key_preparsed_payload *prep)
static void rxrpc_free_token_list(struct rxrpc_key_token *token)
{
struct crypto_blkcipher *ci;
struct rxrpc_key_token *next;
_enter("{%x},,%zu", key_serial(key), prep->datalen);
if (prep->datalen != 8)
return -EINVAL;
memcpy(&key->type_data, prep->data, 8);
ci = crypto_alloc_blkcipher("pcbc(des)", 0, CRYPTO_ALG_ASYNC);
if (IS_ERR(ci)) {
_leave(" = %ld", PTR_ERR(ci));
return PTR_ERR(ci);
}
if (crypto_blkcipher_setkey(ci, prep->data, 8) < 0)
BUG();
key->payload.data = ci;
_leave(" = 0");
return 0;
}
/*
* dispose of the data dangling from the corpse of a rxrpc key
*/
static void rxrpc_destroy(struct key *key)
{
struct rxrpc_key_token *token;
while ((token = key->payload.data)) {
key->payload.data = token->next;
for (; token; token = next) {
next = token->next;
switch (token->security_index) {
case RXRPC_SECURITY_RXKAD:
kfree(token->kad);
@ -837,6 +811,61 @@ static void rxrpc_destroy(struct key *key)
}
}
/*
* Clean up preparse data.
*/
static void rxrpc_free_preparse(struct key_preparsed_payload *prep)
{
rxrpc_free_token_list(prep->payload[0]);
}
/*
* Preparse a server secret key.
*
* The data should be the 8-byte secret key.
*/
static int rxrpc_preparse_s(struct key_preparsed_payload *prep)
{
struct crypto_blkcipher *ci;
_enter("%zu", prep->datalen);
if (prep->datalen != 8)
return -EINVAL;
memcpy(&prep->type_data, prep->data, 8);
ci = crypto_alloc_blkcipher("pcbc(des)", 0, CRYPTO_ALG_ASYNC);
if (IS_ERR(ci)) {
_leave(" = %ld", PTR_ERR(ci));
return PTR_ERR(ci);
}
if (crypto_blkcipher_setkey(ci, prep->data, 8) < 0)
BUG();
prep->payload[0] = ci;
_leave(" = 0");
return 0;
}
/*
* Clean up preparse data.
*/
static void rxrpc_free_preparse_s(struct key_preparsed_payload *prep)
{
if (prep->payload[0])
crypto_free_blkcipher(prep->payload[0]);
}
/*
* dispose of the data dangling from the corpse of a rxrpc key
*/
static void rxrpc_destroy(struct key *key)
{
rxrpc_free_token_list(key->payload.data);
}
/*
* dispose of the data dangling from the corpse of a rxrpc key
*/

View File

@ -13,7 +13,9 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/err.h>
#include <linux/sched.h>
#include <linux/rbtree.h>
#include <linux/cred.h>
#include <linux/key-type.h>
#include <linux/digsig.h>
@ -24,7 +26,11 @@ static struct key *keyring[INTEGRITY_KEYRING_MAX];
static const char *keyring_name[INTEGRITY_KEYRING_MAX] = {
"_evm",
"_module",
#ifndef CONFIG_IMA_TRUSTED_KEYRING
"_ima",
#else
".ima",
#endif
};
int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
@ -56,3 +62,25 @@ int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
return -EOPNOTSUPP;
}
int integrity_init_keyring(const unsigned int id)
{
const struct cred *cred = current_cred();
int err = 0;
keyring[id] = keyring_alloc(keyring_name[id], KUIDT_INIT(0),
KGIDT_INIT(0), cred,
((KEY_POS_ALL & ~KEY_POS_SETATTR) |
KEY_USR_VIEW | KEY_USR_READ |
KEY_USR_WRITE | KEY_USR_SEARCH),
KEY_ALLOC_NOT_IN_QUOTA, NULL);
if (!IS_ERR(keyring[id]))
set_bit(KEY_FLAG_TRUSTED_ONLY, &keyring[id]->flags);
else {
err = PTR_ERR(keyring[id]);
pr_info("Can't allocate %s keyring (%d)\n",
keyring_name[id], err);
keyring[id] = NULL;
}
return err;
}

View File

@ -123,3 +123,13 @@ config IMA_APPRAISE
For more information on integrity appraisal refer to:
<http://linux-ima.sourceforge.net>
If unsure, say N.
config IMA_TRUSTED_KEYRING
bool "Require all keys on the .ima keyring be signed"
depends on IMA_APPRAISE && SYSTEM_TRUSTED_KEYRING
depends on INTEGRITY_ASYMMETRIC_KEYS
select KEYS_DEBUG_PROC_KEYS
default y
help
This option requires that all keys added to the .ima
keyring be signed by a key on the system trusted keyring.

View File

@ -249,4 +249,16 @@ static inline int security_filter_rule_match(u32 secid, u32 field, u32 op,
return -EINVAL;
}
#endif /* CONFIG_IMA_LSM_RULES */
#ifdef CONFIG_IMA_TRUSTED_KEYRING
static inline int ima_init_keyring(const unsigned int id)
{
return integrity_init_keyring(id);
}
#else
static inline int ima_init_keyring(const unsigned int id)
{
return 0;
}
#endif /* CONFIG_IMA_TRUSTED_KEYRING */
#endif

View File

@ -325,8 +325,14 @@ static int __init init_ima(void)
hash_setup(CONFIG_IMA_DEFAULT_HASH);
error = ima_init();
if (!error)
ima_initialized = 1;
if (error)
goto out;
error = ima_init_keyring(INTEGRITY_KEYRING_IMA);
if (error)
goto out;
ima_initialized = 1;
out:
return error;
}

View File

@ -124,6 +124,7 @@ struct integrity_iint_cache *integrity_iint_find(struct inode *inode);
int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
const char *digest, int digestlen);
int integrity_init_keyring(const unsigned int id);
#else
static inline int integrity_digsig_verify(const unsigned int id,
@ -133,6 +134,10 @@ static inline int integrity_digsig_verify(const unsigned int id,
return -EOPNOTSUPP;
}
static inline int integrity_init_keyring(const unsigned int id)
{
return 0;
}
#endif /* CONFIG_INTEGRITY_SIGNATURE */
#ifdef CONFIG_INTEGRITY_ASYMMETRIC_KEYS

View File

@ -34,7 +34,9 @@ MODULE_LICENSE("GPL");
struct key_type key_type_big_key = {
.name = "big_key",
.def_lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT,
.instantiate = big_key_instantiate,
.preparse = big_key_preparse,
.free_preparse = big_key_free_preparse,
.instantiate = generic_key_instantiate,
.match = user_match,
.revoke = big_key_revoke,
.destroy = big_key_destroy,
@ -43,11 +45,11 @@ struct key_type key_type_big_key = {
};
/*
* Instantiate a big key
* Preparse a big key
*/
int big_key_instantiate(struct key *key, struct key_preparsed_payload *prep)
int big_key_preparse(struct key_preparsed_payload *prep)
{
struct path *path = (struct path *)&key->payload.data2;
struct path *path = (struct path *)&prep->payload;
struct file *file;
ssize_t written;
size_t datalen = prep->datalen;
@ -58,11 +60,9 @@ int big_key_instantiate(struct key *key, struct key_preparsed_payload *prep)
goto error;
/* Set an arbitrary quota */
ret = key_payload_reserve(key, 16);
if (ret < 0)
goto error;
prep->quotalen = 16;
key->type_data.x[1] = datalen;
prep->type_data[1] = (void *)(unsigned long)datalen;
if (datalen > BIG_KEY_FILE_THRESHOLD) {
/* Create a shmem file to store the data in. This will permit the data
@ -73,7 +73,7 @@ int big_key_instantiate(struct key *key, struct key_preparsed_payload *prep)
file = shmem_kernel_file_setup("", datalen, 0);
if (IS_ERR(file)) {
ret = PTR_ERR(file);
goto err_quota;
goto error;
}
written = kernel_write(file, prep->data, prep->datalen, 0);
@ -93,23 +93,32 @@ int big_key_instantiate(struct key *key, struct key_preparsed_payload *prep)
} else {
/* Just store the data in a buffer */
void *data = kmalloc(datalen, GFP_KERNEL);
if (!data) {
ret = -ENOMEM;
goto err_quota;
}
if (!data)
return -ENOMEM;
key->payload.data = memcpy(data, prep->data, prep->datalen);
prep->payload[0] = memcpy(data, prep->data, prep->datalen);
}
return 0;
err_fput:
fput(file);
err_quota:
key_payload_reserve(key, 0);
error:
return ret;
}
/*
* Clear preparsement.
*/
void big_key_free_preparse(struct key_preparsed_payload *prep)
{
if (prep->datalen > BIG_KEY_FILE_THRESHOLD) {
struct path *path = (struct path *)&prep->payload;
path_put(path);
} else {
kfree(prep->payload[0]);
}
}
/*
* dispose of the links from a revoked keyring
* - called with the key sem write-locked

View File

@ -811,7 +811,7 @@ static int encrypted_instantiate(struct key *key,
goto out;
}
rcu_assign_keypointer(key, epayload);
prep->payload[0] = epayload;
out:
kfree(datablob);
return ret;

View File

@ -437,6 +437,11 @@ static int __key_instantiate_and_link(struct key *key,
/* disable the authorisation key */
if (authkey)
key_revoke(authkey);
if (prep->expiry != TIME_T_MAX) {
key->expiry = prep->expiry;
key_schedule_gc(prep->expiry + key_gc_delay);
}
}
}
@ -479,6 +484,7 @@ int key_instantiate_and_link(struct key *key,
prep.data = data;
prep.datalen = datalen;
prep.quotalen = key->type->def_datalen;
prep.expiry = TIME_T_MAX;
if (key->type->preparse) {
ret = key->type->preparse(&prep);
if (ret < 0)
@ -488,7 +494,7 @@ int key_instantiate_and_link(struct key *key,
if (keyring) {
ret = __key_link_begin(keyring, &key->index_key, &edit);
if (ret < 0)
goto error_free_preparse;
goto error;
}
ret = __key_instantiate_and_link(key, &prep, keyring, authkey, &edit);
@ -496,10 +502,9 @@ int key_instantiate_and_link(struct key *key,
if (keyring)
__key_link_end(keyring, &key->index_key, edit);
error_free_preparse:
error:
if (key->type->preparse)
key->type->free_preparse(&prep);
error:
return ret;
}
@ -811,11 +816,12 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref,
prep.datalen = plen;
prep.quotalen = index_key.type->def_datalen;
prep.trusted = flags & KEY_ALLOC_TRUSTED;
prep.expiry = TIME_T_MAX;
if (index_key.type->preparse) {
ret = index_key.type->preparse(&prep);
if (ret < 0) {
key_ref = ERR_PTR(ret);
goto error_put_type;
goto error_free_prep;
}
if (!index_key.description)
index_key.description = prep.description;
@ -941,6 +947,7 @@ int key_update(key_ref_t key_ref, const void *payload, size_t plen)
prep.data = payload;
prep.datalen = plen;
prep.quotalen = key->type->def_datalen;
prep.expiry = TIME_T_MAX;
if (key->type->preparse) {
ret = key->type->preparse(&prep);
if (ret < 0)
@ -956,9 +963,9 @@ int key_update(key_ref_t key_ref, const void *payload, size_t plen)
up_write(&key->sem);
error:
if (key->type->preparse)
key->type->free_preparse(&prep);
error:
return ret;
}
EXPORT_SYMBOL(key_update);
@ -1023,6 +1030,38 @@ void key_invalidate(struct key *key)
}
EXPORT_SYMBOL(key_invalidate);
/**
* generic_key_instantiate - Simple instantiation of a key from preparsed data
* @key: The key to be instantiated
* @prep: The preparsed data to load.
*
* Instantiate a key from preparsed data. We assume we can just copy the data
* in directly and clear the old pointers.
*
* This can be pointed to directly by the key type instantiate op pointer.
*/
int generic_key_instantiate(struct key *key, struct key_preparsed_payload *prep)
{
int ret;
pr_devel("==>%s()\n", __func__);
ret = key_payload_reserve(key, prep->quotalen);
if (ret == 0) {
key->type_data.p[0] = prep->type_data[0];
key->type_data.p[1] = prep->type_data[1];
rcu_assign_keypointer(key, prep->payload[0]);
key->payload.data2[1] = prep->payload[1];
prep->type_data[0] = NULL;
prep->type_data[1] = NULL;
prep->payload[0] = NULL;
prep->payload[1] = NULL;
}
pr_devel("<==%s() = %d\n", __func__, ret);
return ret;
}
EXPORT_SYMBOL(generic_key_instantiate);
/**
* register_key_type - Register a type of key.
* @ktype: The new key type.

View File

@ -37,8 +37,6 @@ static int key_get_type_from_user(char *type,
return ret;
if (ret == 0 || ret >= len)
return -EINVAL;
if (type[0] == '.')
return -EPERM;
type[len - 1] = '\0';
return 0;
}
@ -86,6 +84,10 @@ SYSCALL_DEFINE5(add_key, const char __user *, _type,
if (!*description) {
kfree(description);
description = NULL;
} else if ((description[0] == '.') &&
(strncmp(type, "keyring", 7) == 0)) {
ret = -EPERM;
goto error2;
}
}
@ -404,12 +406,25 @@ long keyctl_invalidate_key(key_serial_t id)
key_ref = lookup_user_key(id, 0, KEY_NEED_SEARCH);
if (IS_ERR(key_ref)) {
ret = PTR_ERR(key_ref);
/* Root is permitted to invalidate certain special keys */
if (capable(CAP_SYS_ADMIN)) {
key_ref = lookup_user_key(id, 0, 0);
if (IS_ERR(key_ref))
goto error;
if (test_bit(KEY_FLAG_ROOT_CAN_INVAL,
&key_ref_to_ptr(key_ref)->flags))
goto invalidate;
goto error_put;
}
goto error;
}
invalidate:
key_invalidate(key_ref_to_ptr(key_ref));
ret = 0;
error_put:
key_ref_put(key_ref);
error:
kleave(" = %ld", ret);

View File

@ -73,6 +73,8 @@ static inline unsigned keyring_hash(const char *desc)
* can be treated as ordinary keys in addition to having their own special
* operations.
*/
static int keyring_preparse(struct key_preparsed_payload *prep);
static void keyring_free_preparse(struct key_preparsed_payload *prep);
static int keyring_instantiate(struct key *keyring,
struct key_preparsed_payload *prep);
static void keyring_revoke(struct key *keyring);
@ -84,6 +86,8 @@ static long keyring_read(const struct key *keyring,
struct key_type key_type_keyring = {
.name = "keyring",
.def_datalen = 0,
.preparse = keyring_preparse,
.free_preparse = keyring_free_preparse,
.instantiate = keyring_instantiate,
.match = user_match,
.revoke = keyring_revoke,
@ -122,6 +126,21 @@ static void keyring_publish_name(struct key *keyring)
}
}
/*
* Preparse a keyring payload
*/
static int keyring_preparse(struct key_preparsed_payload *prep)
{
return prep->datalen != 0 ? -EINVAL : 0;
}
/*
* Free a preparse of a user defined key payload
*/
static void keyring_free_preparse(struct key_preparsed_payload *prep)
{
}
/*
* Initialise a keyring.
*
@ -130,17 +149,10 @@ static void keyring_publish_name(struct key *keyring)
static int keyring_instantiate(struct key *keyring,
struct key_preparsed_payload *prep)
{
int ret;
ret = -EINVAL;
if (prep->datalen == 0) {
assoc_array_init(&keyring->keys);
/* make the keyring available by name if it has one */
keyring_publish_name(keyring);
ret = 0;
}
return ret;
assoc_array_init(&keyring->keys);
/* make the keyring available by name if it has one */
keyring_publish_name(keyring);
return 0;
}
/*

View File

@ -20,6 +20,8 @@
#include "internal.h"
#include <keys/user-type.h>
static int request_key_auth_preparse(struct key_preparsed_payload *);
static void request_key_auth_free_preparse(struct key_preparsed_payload *);
static int request_key_auth_instantiate(struct key *,
struct key_preparsed_payload *);
static void request_key_auth_describe(const struct key *, struct seq_file *);
@ -33,6 +35,8 @@ static long request_key_auth_read(const struct key *, char __user *, size_t);
struct key_type key_type_request_key_auth = {
.name = ".request_key_auth",
.def_datalen = sizeof(struct request_key_auth),
.preparse = request_key_auth_preparse,
.free_preparse = request_key_auth_free_preparse,
.instantiate = request_key_auth_instantiate,
.describe = request_key_auth_describe,
.revoke = request_key_auth_revoke,
@ -40,6 +44,15 @@ struct key_type key_type_request_key_auth = {
.read = request_key_auth_read,
};
int request_key_auth_preparse(struct key_preparsed_payload *prep)
{
return 0;
}
void request_key_auth_free_preparse(struct key_preparsed_payload *prep)
{
}
/*
* Instantiate a request-key authorisation key.
*/

View File

@ -27,7 +27,9 @@ static int logon_vet_description(const char *desc);
struct key_type key_type_user = {
.name = "user",
.def_lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT,
.instantiate = user_instantiate,
.preparse = user_preparse,
.free_preparse = user_free_preparse,
.instantiate = generic_key_instantiate,
.update = user_update,
.match = user_match,
.revoke = user_revoke,
@ -47,7 +49,9 @@ EXPORT_SYMBOL_GPL(key_type_user);
struct key_type key_type_logon = {
.name = "logon",
.def_lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT,
.instantiate = user_instantiate,
.preparse = user_preparse,
.free_preparse = user_free_preparse,
.instantiate = generic_key_instantiate,
.update = user_update,
.match = user_match,
.revoke = user_revoke,
@ -58,38 +62,37 @@ struct key_type key_type_logon = {
EXPORT_SYMBOL_GPL(key_type_logon);
/*
* instantiate a user defined key
* Preparse a user defined key payload
*/
int user_instantiate(struct key *key, struct key_preparsed_payload *prep)
int user_preparse(struct key_preparsed_payload *prep)
{
struct user_key_payload *upayload;
size_t datalen = prep->datalen;
int ret;
ret = -EINVAL;
if (datalen <= 0 || datalen > 32767 || !prep->data)
goto error;
return -EINVAL;
ret = key_payload_reserve(key, datalen);
if (ret < 0)
goto error;
ret = -ENOMEM;
upayload = kmalloc(sizeof(*upayload) + datalen, GFP_KERNEL);
if (!upayload)
goto error;
return -ENOMEM;
/* attach the data */
prep->quotalen = datalen;
prep->payload[0] = upayload;
upayload->datalen = datalen;
memcpy(upayload->data, prep->data, datalen);
rcu_assign_keypointer(key, upayload);
ret = 0;
error:
return ret;
return 0;
}
EXPORT_SYMBOL_GPL(user_preparse);
EXPORT_SYMBOL_GPL(user_instantiate);
/*
* Free a preparse of a user defined key payload
*/
void user_free_preparse(struct key_preparsed_payload *prep)
{
kfree(prep->payload[0]);
}
EXPORT_SYMBOL_GPL(user_free_preparse);
/*
* update a user defined key