mirror of https://gitee.com/openkylin/linux.git
Merge branch 'modules-next' of git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux
Pull module signing support from Rusty Russell: "module signing is the highlight, but it's an all-over David Howells frenzy..." Hmm "Magrathea: Glacier signing key". Somebody has been reading too much HHGTTG. * 'modules-next' of git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux: (37 commits) X.509: Fix indefinite length element skip error handling X.509: Convert some printk calls to pr_devel asymmetric keys: fix printk format warning MODSIGN: Fix 32-bit overflow in X.509 certificate validity date checking MODSIGN: Make mrproper should remove generated files. MODSIGN: Use utf8 strings in signer's name in autogenerated X.509 certs MODSIGN: Use the same digest for the autogen key sig as for the module sig MODSIGN: Sign modules during the build process MODSIGN: Provide a script for generating a key ID from an X.509 cert MODSIGN: Implement module signature checking MODSIGN: Provide module signing public keys to the kernel MODSIGN: Automatically generate module signing keys if missing MODSIGN: Provide Kconfig options MODSIGN: Provide gitignore and make clean rules for extra files MODSIGN: Add FIPS policy module: signature checking hook X.509: Add a crypto key parser for binary (DER) X.509 certificates MPILIB: Provide a function to read raw data into an MPI X.509: Add an ASN.1 decoder X.509: Add simple ASN.1 grammar compiler ...
This commit is contained in:
commit
d25282d1c9
|
@ -14,6 +14,10 @@
|
|||
*.o.*
|
||||
*.a
|
||||
*.s
|
||||
*.ko.unsigned
|
||||
*.ko.stripped
|
||||
*.ko.stripped.dig
|
||||
*.ko.stripped.sig
|
||||
*.ko
|
||||
*.so
|
||||
*.so.dbg
|
||||
|
@ -84,3 +88,13 @@ GTAGS
|
|||
*.orig
|
||||
*~
|
||||
\#*#
|
||||
|
||||
#
|
||||
# Leavings from module signing
|
||||
#
|
||||
extra_certificates
|
||||
signing_key.priv
|
||||
signing_key.x509
|
||||
signing_key.x509.keyid
|
||||
signing_key.x509.signer
|
||||
x509.genkey
|
||||
|
|
|
@ -0,0 +1,312 @@
|
|||
=============================================
|
||||
ASYMMETRIC / PUBLIC-KEY CRYPTOGRAPHY KEY TYPE
|
||||
=============================================
|
||||
|
||||
Contents:
|
||||
|
||||
- Overview.
|
||||
- Key identification.
|
||||
- Accessing asymmetric keys.
|
||||
- Signature verification.
|
||||
- Asymmetric key subtypes.
|
||||
- Instantiation data parsers.
|
||||
|
||||
|
||||
========
|
||||
OVERVIEW
|
||||
========
|
||||
|
||||
The "asymmetric" key type is designed to be a container for the keys used in
|
||||
public-key cryptography, without imposing any particular restrictions on the
|
||||
form or mechanism of the cryptography or form of the key.
|
||||
|
||||
The asymmetric key is given a subtype that defines what sort of data is
|
||||
associated with the key and provides operations to describe and destroy it.
|
||||
However, no requirement is made that the key data actually be stored in the
|
||||
key.
|
||||
|
||||
A completely in-kernel key retention and operation subtype can be defined, but
|
||||
it would also be possible to provide access to cryptographic hardware (such as
|
||||
a TPM) that might be used to both retain the relevant key and perform
|
||||
operations using that key. In such a case, the asymmetric key would then
|
||||
merely be an interface to the TPM driver.
|
||||
|
||||
Also provided is the concept of a data parser. Data parsers are responsible
|
||||
for extracting information from the blobs of data passed to the instantiation
|
||||
function. The first data parser that recognises the blob gets to set the
|
||||
subtype of the key and define the operations that can be done on that key.
|
||||
|
||||
A data parser may interpret the data blob as containing the bits representing a
|
||||
key, or it may interpret it as a reference to a key held somewhere else in the
|
||||
system (for example, a TPM).
|
||||
|
||||
|
||||
==================
|
||||
KEY IDENTIFICATION
|
||||
==================
|
||||
|
||||
If a key is added with an empty name, the instantiation data parsers are given
|
||||
the opportunity to pre-parse a key and to determine the description the key
|
||||
should be given from the content of the key.
|
||||
|
||||
This can then be used to refer to the key, either by complete match or by
|
||||
partial match. The key type may also use other criteria to refer to a key.
|
||||
|
||||
The asymmetric key type's match function can then perform a wider range of
|
||||
comparisons than just the straightforward comparison of the description with
|
||||
the criterion string:
|
||||
|
||||
(1) If the criterion string is of the form "id:<hexdigits>" then the match
|
||||
function will examine a key's fingerprint to see if the hex digits given
|
||||
after the "id:" match the tail. For instance:
|
||||
|
||||
keyctl search @s asymmetric id:5acc2142
|
||||
|
||||
will match a key with fingerprint:
|
||||
|
||||
1A00 2040 7601 7889 DE11 882C 3823 04AD 5ACC 2142
|
||||
|
||||
(2) If the criterion string is of the form "<subtype>:<hexdigits>" then the
|
||||
match will match the ID as in (1), but with the added restriction that
|
||||
only keys of the specified subtype (e.g. tpm) will be matched. For
|
||||
instance:
|
||||
|
||||
keyctl search @s asymmetric tpm:5acc2142
|
||||
|
||||
Looking in /proc/keys, the last 8 hex digits of the key fingerprint are
|
||||
displayed, along with the subtype:
|
||||
|
||||
1a39e171 I----- 1 perm 3f010000 0 0 asymmetri modsign.0: DSA 5acc2142 []
|
||||
|
||||
|
||||
=========================
|
||||
ACCESSING ASYMMETRIC KEYS
|
||||
=========================
|
||||
|
||||
For general access to asymmetric keys from within the kernel, the following
|
||||
inclusion is required:
|
||||
|
||||
#include <crypto/public_key.h>
|
||||
|
||||
This gives access to functions for dealing with asymmetric / public keys.
|
||||
Three enums are defined there for representing public-key cryptography
|
||||
algorithms:
|
||||
|
||||
enum pkey_algo
|
||||
|
||||
digest algorithms used by those:
|
||||
|
||||
enum pkey_hash_algo
|
||||
|
||||
and key identifier representations:
|
||||
|
||||
enum pkey_id_type
|
||||
|
||||
Note that the key type representation types are required because key
|
||||
identifiers from different standards aren't necessarily compatible. For
|
||||
instance, PGP generates key identifiers by hashing the key data plus some
|
||||
PGP-specific metadata, whereas X.509 has arbitrary certificate identifiers.
|
||||
|
||||
The operations defined upon a key are:
|
||||
|
||||
(1) Signature verification.
|
||||
|
||||
Other operations are possible (such as encryption) with the same key data
|
||||
required for verification, but not currently supported, and others
|
||||
(eg. decryption and signature generation) require extra key data.
|
||||
|
||||
|
||||
SIGNATURE VERIFICATION
|
||||
----------------------
|
||||
|
||||
An operation is provided to perform cryptographic signature verification, using
|
||||
an asymmetric key to provide or to provide access to the public key.
|
||||
|
||||
int verify_signature(const struct key *key,
|
||||
const struct public_key_signature *sig);
|
||||
|
||||
The caller must have already obtained the key from some source and can then use
|
||||
it to check the signature. The caller must have parsed the signature and
|
||||
transferred the relevant bits to the structure pointed to by sig.
|
||||
|
||||
struct public_key_signature {
|
||||
u8 *digest;
|
||||
u8 digest_size;
|
||||
enum pkey_hash_algo pkey_hash_algo : 8;
|
||||
u8 nr_mpi;
|
||||
union {
|
||||
MPI mpi[2];
|
||||
...
|
||||
};
|
||||
};
|
||||
|
||||
The algorithm used must be noted in sig->pkey_hash_algo, and all the MPIs that
|
||||
make up the actual signature must be stored in sig->mpi[] and the count of MPIs
|
||||
placed in sig->nr_mpi.
|
||||
|
||||
In addition, the data must have been digested by the caller and the resulting
|
||||
hash must be pointed to by sig->digest and the size of the hash be placed in
|
||||
sig->digest_size.
|
||||
|
||||
The function will return 0 upon success or -EKEYREJECTED if the signature
|
||||
doesn't match.
|
||||
|
||||
The function may also return -ENOTSUPP if an unsupported public-key algorithm
|
||||
or public-key/hash algorithm combination is specified or the key doesn't
|
||||
support the operation; -EBADMSG or -ERANGE if some of the parameters have weird
|
||||
data; or -ENOMEM if an allocation can't be performed. -EINVAL can be returned
|
||||
if the key argument is the wrong type or is incompletely set up.
|
||||
|
||||
|
||||
=======================
|
||||
ASYMMETRIC KEY SUBTYPES
|
||||
=======================
|
||||
|
||||
Asymmetric keys have a subtype that defines the set of operations that can be
|
||||
performed on that key and that determines what data is attached as the key
|
||||
payload. The payload format is entirely at the whim of the subtype.
|
||||
|
||||
The subtype is selected by the key data parser and the parser must initialise
|
||||
the data required for it. The asymmetric key retains a reference on the
|
||||
subtype module.
|
||||
|
||||
The subtype definition structure can be found in:
|
||||
|
||||
#include <keys/asymmetric-subtype.h>
|
||||
|
||||
and looks like the following:
|
||||
|
||||
struct asymmetric_key_subtype {
|
||||
struct module *owner;
|
||||
const char *name;
|
||||
|
||||
void (*describe)(const struct key *key, struct seq_file *m);
|
||||
void (*destroy)(void *payload);
|
||||
int (*verify_signature)(const struct key *key,
|
||||
const struct public_key_signature *sig);
|
||||
};
|
||||
|
||||
Asymmetric keys point to this with their type_data[0] member.
|
||||
|
||||
The owner and name fields should be set to the owning module and the name of
|
||||
the subtype. Currently, the name is only used for print statements.
|
||||
|
||||
There are a number of operations defined by the subtype:
|
||||
|
||||
(1) describe().
|
||||
|
||||
Mandatory. This allows the subtype to display something in /proc/keys
|
||||
against the key. For instance the name of the public key algorithm type
|
||||
could be displayed. The key type will display the tail of the key
|
||||
identity string after this.
|
||||
|
||||
(2) destroy().
|
||||
|
||||
Mandatory. This should free the memory associated with the key. The
|
||||
asymmetric key will look after freeing the fingerprint and releasing the
|
||||
reference on the subtype module.
|
||||
|
||||
(3) verify_signature().
|
||||
|
||||
Optional. These are the entry points for the key usage operations.
|
||||
Currently there is only the one defined. If not set, the caller will be
|
||||
given -ENOTSUPP. The subtype may do anything it likes to implement an
|
||||
operation, including offloading to hardware.
|
||||
|
||||
|
||||
==========================
|
||||
INSTANTIATION DATA PARSERS
|
||||
==========================
|
||||
|
||||
The asymmetric key type doesn't generally want to store or to deal with a raw
|
||||
blob of data that holds the key data. It would have to parse it and error
|
||||
check it each time it wanted to use it. Further, the contents of the blob may
|
||||
have various checks that can be performed on it (eg. self-signatures, validity
|
||||
dates) and may contain useful data about the key (identifiers, capabilities).
|
||||
|
||||
Also, the blob may represent a pointer to some hardware containing the key
|
||||
rather than the key itself.
|
||||
|
||||
Examples of blob formats for which parsers could be implemented include:
|
||||
|
||||
- OpenPGP packet stream [RFC 4880].
|
||||
- X.509 ASN.1 stream.
|
||||
- Pointer to TPM key.
|
||||
- Pointer to UEFI key.
|
||||
|
||||
During key instantiation each parser in the list is tried until one doesn't
|
||||
return -EBADMSG.
|
||||
|
||||
The parser definition structure can be found in:
|
||||
|
||||
#include <keys/asymmetric-parser.h>
|
||||
|
||||
and looks like the following:
|
||||
|
||||
struct asymmetric_key_parser {
|
||||
struct module *owner;
|
||||
const char *name;
|
||||
|
||||
int (*parse)(struct key_preparsed_payload *prep);
|
||||
};
|
||||
|
||||
The owner and name fields should be set to the owning module and the name of
|
||||
the parser.
|
||||
|
||||
There is currently only a single operation defined by the parser, and it is
|
||||
mandatory:
|
||||
|
||||
(1) parse().
|
||||
|
||||
This is called to preparse the key from the key creation and update paths.
|
||||
In particular, it is called during the key creation _before_ a key is
|
||||
allocated, and as such, is permitted to provide the key's description in
|
||||
the case that the caller declines to do so.
|
||||
|
||||
The caller passes a pointer to the following struct with all of the fields
|
||||
cleared, except for data, datalen and quotalen [see
|
||||
Documentation/security/keys.txt].
|
||||
|
||||
struct key_preparsed_payload {
|
||||
char *description;
|
||||
void *type_data[2];
|
||||
void *payload;
|
||||
const void *data;
|
||||
size_t datalen;
|
||||
size_t quotalen;
|
||||
};
|
||||
|
||||
The instantiation data is in a blob pointed to by data and is datalen in
|
||||
size. The parse() function is not permitted to change these two values at
|
||||
all, and shouldn't change any of the other values _unless_ they are
|
||||
recognise the blob format and will not return -EBADMSG to indicate it is
|
||||
not theirs.
|
||||
|
||||
If the parser is happy with the blob, it should propose a description for
|
||||
the key and attach it to ->description, ->type_data[0] should be set to
|
||||
point to the subtype to be used, ->payload should be set to point to the
|
||||
initialised data for that subtype, ->type_data[1] should point to a hex
|
||||
fingerprint and quotalen should be updated to indicate how much quota this
|
||||
key should account for.
|
||||
|
||||
When clearing up, the data attached to ->type_data[1] and ->description
|
||||
will be kfree()'d and the data attached to ->payload will be passed to the
|
||||
subtype's ->destroy() method to be disposed of. A module reference for
|
||||
the subtype pointed to by ->type_data[0] will be put.
|
||||
|
||||
|
||||
If the data format is not recognised, -EBADMSG should be returned. If it
|
||||
is recognised, but the key cannot for some reason be set up, some other
|
||||
negative error code should be returned. On success, 0 should be returned.
|
||||
|
||||
The key's fingerprint string may be partially matched upon. For a
|
||||
public-key algorithm such as RSA and DSA this will likely be a printable
|
||||
hex version of the key's fingerprint.
|
||||
|
||||
Functions are provided to register and unregister parsers:
|
||||
|
||||
int register_asymmetric_key_parser(struct asymmetric_key_parser *parser);
|
||||
void unregister_asymmetric_key_parser(struct asymmetric_key_parser *subtype);
|
||||
|
||||
Parsers may not have the same name. The names are otherwise only used for
|
||||
displaying in debugging messages.
|
|
@ -1593,6 +1593,12 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
|
|||
log everything. Information is printed at KERN_DEBUG
|
||||
so loglevel=8 may also need to be specified.
|
||||
|
||||
module.sig_enforce
|
||||
[KNL] When CONFIG_MODULE_SIG is set, this means that
|
||||
modules without (valid) signatures will fail to load.
|
||||
Note that if CONFIG_MODULE_SIG_ENFORCE is set, that
|
||||
is always true, so this option does nothing.
|
||||
|
||||
mousedev.tap_time=
|
||||
[MOUSE] Maximum time between finger touching and
|
||||
leaving touchpad surface for touch to be considered
|
||||
|
|
|
@ -412,6 +412,10 @@ The main syscalls are:
|
|||
to the keyring. In this case, an error will be generated if the process
|
||||
does not have permission to write to the keyring.
|
||||
|
||||
If the key type supports it, if the description is NULL or an empty
|
||||
string, the key type will try and generate a description from the content
|
||||
of the payload.
|
||||
|
||||
The payload is optional, and the pointer can be NULL if not required by
|
||||
the type. The payload is plen in size, and plen can be zero for an empty
|
||||
payload.
|
||||
|
@ -1114,12 +1118,53 @@ The structure has a number of fields, some of which are mandatory:
|
|||
it should return 0.
|
||||
|
||||
|
||||
(*) int (*instantiate)(struct key *key, const void *data, size_t datalen);
|
||||
(*) int (*preparse)(struct key_preparsed_payload *prep);
|
||||
|
||||
This optional method permits the key type to attempt to parse payload
|
||||
before a key is created (add key) or the key semaphore is taken (update or
|
||||
instantiate key). The structure pointed to by prep looks like:
|
||||
|
||||
struct key_preparsed_payload {
|
||||
char *description;
|
||||
void *type_data[2];
|
||||
void *payload;
|
||||
const void *data;
|
||||
size_t datalen;
|
||||
size_t quotalen;
|
||||
};
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
The method should return 0 if success ful or a negative error code
|
||||
otherwise.
|
||||
|
||||
|
||||
(*) void (*free_preparse)(struct key_preparsed_payload *prep);
|
||||
|
||||
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.
|
||||
|
||||
|
||||
(*) int (*instantiate)(struct key *key, struct key_preparsed_payload *prep);
|
||||
|
||||
This method is called to attach a payload to a key during construction.
|
||||
The payload attached need not bear any relation to the data passed to this
|
||||
function.
|
||||
|
||||
The prep->data and prep->datalen fields will define the original payload
|
||||
blob. If preparse() was supplied then other fields may be filled in also.
|
||||
|
||||
If the amount of data attached to the key differs from the size in
|
||||
keytype->def_datalen, then key_payload_reserve() should be called.
|
||||
|
||||
|
@ -1135,6 +1180,9 @@ The structure has a number of fields, some of which are mandatory:
|
|||
If this type of key can be updated, then this method should be provided.
|
||||
It is called to update a key's payload from the blob of data provided.
|
||||
|
||||
The prep->data and prep->datalen fields will define the original payload
|
||||
blob. If preparse() was supplied then other fields may be filled in also.
|
||||
|
||||
key_payload_reserve() should be called if the data length might change
|
||||
before any changes are actually made. Note that if this succeeds, the type
|
||||
is committed to changing the key because it's already been altered, so all
|
||||
|
|
6
Makefile
6
Makefile
|
@ -997,7 +997,10 @@ CLEAN_DIRS += $(MODVERDIR)
|
|||
MRPROPER_DIRS += include/config usr/include include/generated \
|
||||
arch/*/include/generated
|
||||
MRPROPER_FILES += .config .config.old .version .old_version $(version_h) \
|
||||
Module.symvers tags TAGS cscope* GPATH GTAGS GRTAGS GSYMS
|
||||
Module.symvers tags TAGS cscope* GPATH GTAGS GRTAGS GSYMS \
|
||||
signing_key.priv signing_key.x509 x509.genkey \
|
||||
extra_certificates signing_key.x509.keyid \
|
||||
signing_key.x509.signer
|
||||
|
||||
# clean - Delete most, but leave enough to build external modules
|
||||
#
|
||||
|
@ -1241,6 +1244,7 @@ clean: $(clean-dirs)
|
|||
$(call cmd,rmfiles)
|
||||
@find $(if $(KBUILD_EXTMOD), $(KBUILD_EXTMOD), .) $(RCS_FIND_IGNORE) \
|
||||
\( -name '*.[oas]' -o -name '*.ko' -o -name '.*.cmd' \
|
||||
-o -name '*.ko.*' \
|
||||
-o -name '.*.d' -o -name '.*.tmp' -o -name '*.mod.c' \
|
||||
-o -name '*.symtypes' -o -name 'modules.order' \
|
||||
-o -name modules.builtin -o -name '.tmp_*.o.*' \
|
||||
|
|
19
arch/Kconfig
19
arch/Kconfig
|
@ -322,4 +322,23 @@ config HAVE_IRQ_TIME_ACCOUNTING
|
|||
config HAVE_ARCH_TRANSPARENT_HUGEPAGE
|
||||
bool
|
||||
|
||||
config HAVE_MOD_ARCH_SPECIFIC
|
||||
bool
|
||||
help
|
||||
The arch uses struct mod_arch_specific to store data. Many arches
|
||||
just need a simple module loader without arch specific data - those
|
||||
should not enable this.
|
||||
|
||||
config MODULES_USE_ELF_RELA
|
||||
bool
|
||||
help
|
||||
Modules only use ELF RELA relocations. Modules with ELF REL
|
||||
relocations will give an error.
|
||||
|
||||
config MODULES_USE_ELF_REL
|
||||
bool
|
||||
help
|
||||
Modules only use ELF REL relocations. Modules with ELF RELA
|
||||
relocations will give an error.
|
||||
|
||||
source "kernel/gcov/Kconfig"
|
||||
|
|
|
@ -22,6 +22,8 @@ config ALPHA
|
|||
select GENERIC_STRNLEN_USER
|
||||
select GENERIC_KERNEL_THREAD
|
||||
select GENERIC_KERNEL_EXECVE
|
||||
select HAVE_MOD_ARCH_SPECIFIC
|
||||
select MODULES_USE_ELF_RELA
|
||||
help
|
||||
The Alpha is a 64-bit general-purpose processor designed and
|
||||
marketed by the Digital Equipment Corporation of blessed memory,
|
||||
|
|
|
@ -1,19 +1,13 @@
|
|||
#ifndef _ALPHA_MODULE_H
|
||||
#define _ALPHA_MODULE_H
|
||||
|
||||
#include <asm-generic/module.h>
|
||||
|
||||
struct mod_arch_specific
|
||||
{
|
||||
unsigned int gotsecindex;
|
||||
};
|
||||
|
||||
#define Elf_Sym Elf64_Sym
|
||||
#define Elf_Shdr Elf64_Shdr
|
||||
#define Elf_Ehdr Elf64_Ehdr
|
||||
#define Elf_Phdr Elf64_Phdr
|
||||
#define Elf_Dyn Elf64_Dyn
|
||||
#define Elf_Rel Elf64_Rel
|
||||
#define Elf_Rela Elf64_Rela
|
||||
|
||||
#define ARCH_SHF_SMALL SHF_ALPHA_GPREL
|
||||
|
||||
#ifdef MODULE
|
||||
|
|
|
@ -53,6 +53,8 @@ config ARM
|
|||
select PERF_USE_VMALLOC
|
||||
select RTC_LIB
|
||||
select SYS_SUPPORTS_APM_EMULATION
|
||||
select HAVE_MOD_ARCH_SPECIFIC if ARM_UNWIND
|
||||
select MODULES_USE_ELF_REL
|
||||
help
|
||||
The ARM series is a line of low-power-consumption RISC chip designs
|
||||
licensed by ARM Ltd and targeted at embedded applications and
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
#ifndef _ASM_ARM_MODULE_H
|
||||
#define _ASM_ARM_MODULE_H
|
||||
|
||||
#define Elf_Shdr Elf32_Shdr
|
||||
#define Elf_Sym Elf32_Sym
|
||||
#define Elf_Ehdr Elf32_Ehdr
|
||||
#include <asm-generic/module.h>
|
||||
|
||||
struct unwind_table;
|
||||
|
||||
|
@ -16,13 +14,11 @@ enum {
|
|||
ARM_SEC_DEVEXIT,
|
||||
ARM_SEC_MAX,
|
||||
};
|
||||
#endif
|
||||
|
||||
struct mod_arch_specific {
|
||||
#ifdef CONFIG_ARM_UNWIND
|
||||
struct unwind_table *unwind[ARM_SEC_MAX];
|
||||
#endif
|
||||
};
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Add the ARM architecture version to the version magic string
|
||||
|
|
|
@ -15,6 +15,8 @@ config AVR32
|
|||
select ARCH_WANT_IPC_PARSE_VERSION
|
||||
select ARCH_HAVE_NMI_SAFE_CMPXCHG
|
||||
select GENERIC_CLOCKEVENTS
|
||||
select HAVE_MOD_ARCH_SPECIFIC
|
||||
select MODULES_USE_ELF_RELA
|
||||
help
|
||||
AVR32 is a high-performance 32-bit RISC microprocessor core,
|
||||
designed for cost-sensitive embedded applications, with particular
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#ifndef __ASM_AVR32_MODULE_H
|
||||
#define __ASM_AVR32_MODULE_H
|
||||
|
||||
#include <asm-generic/module.h>
|
||||
|
||||
struct mod_arch_syminfo {
|
||||
unsigned long got_offset;
|
||||
int got_initialized;
|
||||
|
@ -17,10 +19,6 @@ struct mod_arch_specific {
|
|||
struct mod_arch_syminfo *syminfo;
|
||||
};
|
||||
|
||||
#define Elf_Shdr Elf32_Shdr
|
||||
#define Elf_Sym Elf32_Sym
|
||||
#define Elf_Ehdr Elf32_Ehdr
|
||||
|
||||
#define MODULE_PROC_FAMILY "AVR32v1"
|
||||
|
||||
#define MODULE_ARCH_VERMAGIC MODULE_PROC_FAMILY
|
||||
|
|
|
@ -43,6 +43,8 @@ config BLACKFIN
|
|||
select HAVE_NMI_WATCHDOG if NMI_WATCHDOG
|
||||
select GENERIC_SMP_IDLE_THREAD
|
||||
select ARCH_USES_GETTIMEOFFSET if !GENERIC_CLOCKEVENTS
|
||||
select HAVE_MOD_ARCH_SPECIFIC
|
||||
select MODULES_USE_ELF_RELA
|
||||
|
||||
config GENERIC_CSUM
|
||||
def_bool y
|
||||
|
|
|
@ -7,9 +7,7 @@
|
|||
#ifndef _ASM_BFIN_MODULE_H
|
||||
#define _ASM_BFIN_MODULE_H
|
||||
|
||||
#define Elf_Shdr Elf32_Shdr
|
||||
#define Elf_Sym Elf32_Sym
|
||||
#define Elf_Ehdr Elf32_Ehdr
|
||||
#include <asm-generic/module.h>
|
||||
|
||||
struct mod_arch_specific {
|
||||
Elf_Shdr *text_l1;
|
||||
|
|
|
@ -18,6 +18,7 @@ config C6X
|
|||
select OF_EARLY_FLATTREE
|
||||
select GENERIC_CLOCKEVENTS
|
||||
select GENERIC_KERNEL_THREAD
|
||||
select MODULES_USE_ELF_RELA
|
||||
|
||||
config MMU
|
||||
def_bool n
|
||||
|
|
|
@ -13,17 +13,7 @@
|
|||
#ifndef _ASM_C6X_MODULE_H
|
||||
#define _ASM_C6X_MODULE_H
|
||||
|
||||
#define Elf_Shdr Elf32_Shdr
|
||||
#define Elf_Sym Elf32_Sym
|
||||
#define Elf_Ehdr Elf32_Ehdr
|
||||
#define Elf_Addr Elf32_Addr
|
||||
#define Elf_Word Elf32_Word
|
||||
|
||||
/*
|
||||
* This file contains the C6x architecture specific module code.
|
||||
*/
|
||||
struct mod_arch_specific {
|
||||
};
|
||||
#include <asm-generic/module.h>
|
||||
|
||||
struct loaded_sections {
|
||||
unsigned int new_vaddr;
|
||||
|
|
|
@ -48,6 +48,7 @@ config CRIS
|
|||
select GENERIC_IOMAP
|
||||
select GENERIC_SMP_IDLE_THREAD if ETRAX_ARCH_V32
|
||||
select GENERIC_CMOS_UPDATE
|
||||
select MODULES_USE_ELF_RELA
|
||||
|
||||
config HZ
|
||||
int
|
||||
|
|
|
@ -10,3 +10,4 @@ header-y += sync_serial.h
|
|||
|
||||
generic-y += clkdev.h
|
||||
generic-y += exec.h
|
||||
generic-y += module.h
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
#ifndef _ASM_CRIS_MODULE_H
|
||||
#define _ASM_CRIS_MODULE_H
|
||||
/* cris is simple */
|
||||
struct mod_arch_specific { };
|
||||
|
||||
#define Elf_Shdr Elf32_Shdr
|
||||
#define Elf_Sym Elf32_Sym
|
||||
#define Elf_Ehdr Elf32_Ehdr
|
||||
#endif /* _ASM_CRIS_MODULE_H */
|
|
@ -11,13 +11,7 @@
|
|||
#ifndef _ASM_MODULE_H
|
||||
#define _ASM_MODULE_H
|
||||
|
||||
struct mod_arch_specific
|
||||
{
|
||||
};
|
||||
|
||||
#define Elf_Shdr Elf32_Shdr
|
||||
#define Elf_Sym Elf32_Sym
|
||||
#define Elf_Ehdr Elf32_Ehdr
|
||||
#include <asm-generic/module.h>
|
||||
|
||||
/*
|
||||
* Include the architecture version.
|
||||
|
|
|
@ -7,6 +7,7 @@ config H8300
|
|||
select ARCH_WANT_IPC_PARSE_VERSION
|
||||
select GENERIC_IRQ_SHOW
|
||||
select GENERIC_CPU_DEVICES
|
||||
select MODULES_USE_ELF_RELA
|
||||
|
||||
config SYMBOL_PREFIX
|
||||
string
|
||||
|
|
|
@ -2,3 +2,4 @@ include include/asm-generic/Kbuild.asm
|
|||
|
||||
generic-y += clkdev.h
|
||||
generic-y += exec.h
|
||||
generic-y += module.h
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
#ifndef _ASM_H8300_MODULE_H
|
||||
#define _ASM_H8300_MODULE_H
|
||||
/*
|
||||
* This file contains the H8/300 architecture specific module code.
|
||||
*/
|
||||
struct mod_arch_specific { };
|
||||
#define Elf_Shdr Elf32_Shdr
|
||||
#define Elf_Sym Elf32_Sym
|
||||
#define Elf_Ehdr Elf32_Ehdr
|
||||
|
||||
#endif /* _ASM_H8/300_MODULE_H */
|
|
@ -30,6 +30,7 @@ config HEXAGON
|
|||
select KTIME_SCALAR
|
||||
select GENERIC_CLOCKEVENTS
|
||||
select GENERIC_CLOCKEVENTS_BROADCAST
|
||||
select MODULES_USE_ELF_RELA
|
||||
---help---
|
||||
Qualcomm Hexagon is a processor architecture designed for high
|
||||
performance and low power across a wide variety of applications.
|
||||
|
|
|
@ -40,6 +40,8 @@ config IA64
|
|||
select ARCH_THREAD_INFO_ALLOCATOR
|
||||
select ARCH_CLOCKSOURCE_DATA
|
||||
select GENERIC_TIME_VSYSCALL_OLD
|
||||
select HAVE_MOD_ARCH_SPECIFIC
|
||||
select MODULES_USE_ELF_RELA
|
||||
default y
|
||||
help
|
||||
The Itanium Processor Family is Intel's 64-bit successor to
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#ifndef _ASM_IA64_MODULE_H
|
||||
#define _ASM_IA64_MODULE_H
|
||||
|
||||
#include <asm-generic/module.h>
|
||||
|
||||
/*
|
||||
* IA-64-specific support for kernel module loader.
|
||||
*
|
||||
|
@ -29,10 +31,6 @@ struct mod_arch_specific {
|
|||
unsigned int next_got_entry; /* index of next available got entry */
|
||||
};
|
||||
|
||||
#define Elf_Shdr Elf64_Shdr
|
||||
#define Elf_Sym Elf64_Sym
|
||||
#define Elf_Ehdr Elf64_Ehdr
|
||||
|
||||
#define MODULE_PROC_FAMILY "ia64"
|
||||
#define MODULE_ARCH_VERMAGIC MODULE_PROC_FAMILY \
|
||||
"gcc-" __stringify(__GNUC__) "." __stringify(__GNUC_MINOR__)
|
||||
|
|
|
@ -14,6 +14,7 @@ config M32R
|
|||
select GENERIC_IRQ_SHOW
|
||||
select GENERIC_ATOMIC64
|
||||
select ARCH_USES_GETTIMEOFFSET
|
||||
select MODULES_USE_ELF_RELA
|
||||
|
||||
config SBUS
|
||||
bool
|
||||
|
|
|
@ -2,3 +2,4 @@ include include/asm-generic/Kbuild.asm
|
|||
|
||||
generic-y += clkdev.h
|
||||
generic-y += exec.h
|
||||
generic-y += module.h
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
#ifndef _ASM_M32R_MODULE_H
|
||||
#define _ASM_M32R_MODULE_H
|
||||
|
||||
struct mod_arch_specific { };
|
||||
|
||||
#define Elf_Shdr Elf32_Shdr
|
||||
#define Elf_Sym Elf32_Sym
|
||||
#define Elf_Ehdr Elf32_Ehdr
|
||||
|
||||
#endif /* _ASM_M32R_MODULE_H */
|
|
@ -201,18 +201,3 @@ int apply_relocate_add(Elf32_Shdr *sechdrs,
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int apply_relocate(Elf32_Shdr *sechdrs,
|
||||
const char *strtab,
|
||||
unsigned int symindex,
|
||||
unsigned int relsec,
|
||||
struct module *me)
|
||||
{
|
||||
#if 0
|
||||
printk(KERN_ERR "module %s: REL RELOCATION unsupported\n",
|
||||
me->name);
|
||||
return -ENOEXEC;
|
||||
#endif
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
|
|
@ -16,6 +16,9 @@ config M68K
|
|||
select ARCH_WANT_IPC_PARSE_VERSION
|
||||
select ARCH_USES_GETTIMEOFFSET if MMU && !COLDFIRE
|
||||
select GENERIC_KERNEL_THREAD
|
||||
select HAVE_MOD_ARCH_SPECIFIC
|
||||
select MODULES_USE_ELF_REL
|
||||
select MODULES_USE_ELF_RELA
|
||||
|
||||
config RWSEM_GENERIC_SPINLOCK
|
||||
bool
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#ifndef _ASM_M68K_MODULE_H
|
||||
#define _ASM_M68K_MODULE_H
|
||||
|
||||
#include <asm-generic/module.h>
|
||||
|
||||
enum m68k_fixup_type {
|
||||
m68k_fixup_memoffset,
|
||||
m68k_fixup_vnode_shift,
|
||||
|
@ -36,8 +38,4 @@ struct module;
|
|||
extern void module_fixup(struct module *mod, struct m68k_fixup_info *start,
|
||||
struct m68k_fixup_info *end);
|
||||
|
||||
#define Elf_Shdr Elf32_Shdr
|
||||
#define Elf_Sym Elf32_Sym
|
||||
#define Elf_Ehdr Elf32_Ehdr
|
||||
|
||||
#endif /* _ASM_M68K_MODULE_H */
|
||||
|
|
|
@ -25,6 +25,7 @@ config MICROBLAZE
|
|||
select GENERIC_CPU_DEVICES
|
||||
select GENERIC_ATOMIC64
|
||||
select GENERIC_CLOCKEVENTS
|
||||
select MODULES_USE_ELF_RELA
|
||||
|
||||
config SWAP
|
||||
def_bool n
|
||||
|
|
|
@ -37,6 +37,9 @@ config MIPS
|
|||
select BUILDTIME_EXTABLE_SORT
|
||||
select GENERIC_CLOCKEVENTS
|
||||
select GENERIC_CMOS_UPDATE
|
||||
select HAVE_MOD_ARCH_SPECIFIC
|
||||
select MODULES_USE_ELF_REL
|
||||
select MODULES_USE_ELF_RELA if 64BIT
|
||||
|
||||
menu "Machine selection"
|
||||
|
||||
|
|
|
@ -35,11 +35,14 @@ typedef struct {
|
|||
} Elf64_Mips_Rela;
|
||||
|
||||
#ifdef CONFIG_32BIT
|
||||
|
||||
#define Elf_Shdr Elf32_Shdr
|
||||
#define Elf_Sym Elf32_Sym
|
||||
#define Elf_Ehdr Elf32_Ehdr
|
||||
#define Elf_Addr Elf32_Addr
|
||||
#define Elf_Rel Elf32_Rel
|
||||
#define Elf_Rela Elf32_Rela
|
||||
#define ELF_R_TYPE(X) ELF32_R_TYPE(X)
|
||||
#define ELF_R_SYM(X) ELF32_R_SYM(X)
|
||||
|
||||
#define Elf_Mips_Rel Elf32_Rel
|
||||
#define Elf_Mips_Rela Elf32_Rela
|
||||
|
@ -50,11 +53,14 @@ typedef struct {
|
|||
#endif
|
||||
|
||||
#ifdef CONFIG_64BIT
|
||||
|
||||
#define Elf_Shdr Elf64_Shdr
|
||||
#define Elf_Sym Elf64_Sym
|
||||
#define Elf_Ehdr Elf64_Ehdr
|
||||
#define Elf_Addr Elf64_Addr
|
||||
#define Elf_Rel Elf64_Rel
|
||||
#define Elf_Rela Elf64_Rela
|
||||
#define ELF_R_TYPE(X) ELF64_R_TYPE(X)
|
||||
#define ELF_R_SYM(X) ELF64_R_SYM(X)
|
||||
|
||||
#define Elf_Mips_Rel Elf64_Mips_Rel
|
||||
#define Elf_Mips_Rela Elf64_Mips_Rela
|
||||
|
|
|
@ -31,6 +31,7 @@ obj-$(CONFIG_SYNC_R4K) += sync-r4k.o
|
|||
|
||||
obj-$(CONFIG_STACKTRACE) += stacktrace.o
|
||||
obj-$(CONFIG_MODULES) += mips_ksyms.o module.o
|
||||
obj-$(CONFIG_MODULES_USE_ELF_RELA) += module-rela.o
|
||||
|
||||
obj-$(CONFIG_FUNCTION_TRACER) += mcount.o ftrace.o
|
||||
|
||||
|
|
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
* 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; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Copyright (C) 2001 Rusty Russell.
|
||||
* Copyright (C) 2003, 2004 Ralf Baechle (ralf@linux-mips.org)
|
||||
* Copyright (C) 2005 Thiemo Seufer
|
||||
*/
|
||||
|
||||
#include <linux/elf.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/moduleloader.h>
|
||||
|
||||
extern int apply_r_mips_none(struct module *me, u32 *location, Elf_Addr v);
|
||||
|
||||
static int apply_r_mips_32_rela(struct module *me, u32 *location, Elf_Addr v)
|
||||
{
|
||||
*location = v;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int apply_r_mips_26_rela(struct module *me, u32 *location, Elf_Addr v)
|
||||
{
|
||||
if (v % 4) {
|
||||
pr_err("module %s: dangerous R_MIPS_26 RELArelocation\n",
|
||||
me->name);
|
||||
return -ENOEXEC;
|
||||
}
|
||||
|
||||
if ((v & 0xf0000000) != (((unsigned long)location + 4) & 0xf0000000)) {
|
||||
printk(KERN_ERR
|
||||
"module %s: relocation overflow\n",
|
||||
me->name);
|
||||
return -ENOEXEC;
|
||||
}
|
||||
|
||||
*location = (*location & ~0x03ffffff) | ((v >> 2) & 0x03ffffff);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int apply_r_mips_hi16_rela(struct module *me, u32 *location, Elf_Addr v)
|
||||
{
|
||||
*location = (*location & 0xffff0000) |
|
||||
((((long long) v + 0x8000LL) >> 16) & 0xffff);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int apply_r_mips_lo16_rela(struct module *me, u32 *location, Elf_Addr v)
|
||||
{
|
||||
*location = (*location & 0xffff0000) | (v & 0xffff);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int apply_r_mips_64_rela(struct module *me, u32 *location, Elf_Addr v)
|
||||
{
|
||||
*(Elf_Addr *)location = v;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int apply_r_mips_higher_rela(struct module *me, u32 *location,
|
||||
Elf_Addr v)
|
||||
{
|
||||
*location = (*location & 0xffff0000) |
|
||||
((((long long) v + 0x80008000LL) >> 32) & 0xffff);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int apply_r_mips_highest_rela(struct module *me, u32 *location,
|
||||
Elf_Addr v)
|
||||
{
|
||||
*location = (*location & 0xffff0000) |
|
||||
((((long long) v + 0x800080008000LL) >> 48) & 0xffff);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int (*reloc_handlers_rela[]) (struct module *me, u32 *location,
|
||||
Elf_Addr v) = {
|
||||
[R_MIPS_NONE] = apply_r_mips_none,
|
||||
[R_MIPS_32] = apply_r_mips_32_rela,
|
||||
[R_MIPS_26] = apply_r_mips_26_rela,
|
||||
[R_MIPS_HI16] = apply_r_mips_hi16_rela,
|
||||
[R_MIPS_LO16] = apply_r_mips_lo16_rela,
|
||||
[R_MIPS_64] = apply_r_mips_64_rela,
|
||||
[R_MIPS_HIGHER] = apply_r_mips_higher_rela,
|
||||
[R_MIPS_HIGHEST] = apply_r_mips_highest_rela
|
||||
};
|
||||
|
||||
int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab,
|
||||
unsigned int symindex, unsigned int relsec,
|
||||
struct module *me)
|
||||
{
|
||||
Elf_Mips_Rela *rel = (void *) sechdrs[relsec].sh_addr;
|
||||
Elf_Sym *sym;
|
||||
u32 *location;
|
||||
unsigned int i;
|
||||
Elf_Addr v;
|
||||
int res;
|
||||
|
||||
pr_debug("Applying relocate section %u to %u\n", relsec,
|
||||
sechdrs[relsec].sh_info);
|
||||
|
||||
for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
|
||||
/* This is where to make the change */
|
||||
location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
|
||||
+ rel[i].r_offset;
|
||||
/* This is the symbol it is referring to */
|
||||
sym = (Elf_Sym *)sechdrs[symindex].sh_addr
|
||||
+ ELF_MIPS_R_SYM(rel[i]);
|
||||
if (IS_ERR_VALUE(sym->st_value)) {
|
||||
/* Ignore unresolved weak symbol */
|
||||
if (ELF_ST_BIND(sym->st_info) == STB_WEAK)
|
||||
continue;
|
||||
printk(KERN_WARNING "%s: Unknown symbol %s\n",
|
||||
me->name, strtab + sym->st_name);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
v = sym->st_value + rel[i].r_addend;
|
||||
|
||||
res = reloc_handlers_rela[ELF_MIPS_R_TYPE(rel[i])](me, location, v);
|
||||
if (res)
|
||||
return res;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -51,7 +51,7 @@ void *module_alloc(unsigned long size)
|
|||
}
|
||||
#endif
|
||||
|
||||
static int apply_r_mips_none(struct module *me, u32 *location, Elf_Addr v)
|
||||
int apply_r_mips_none(struct module *me, u32 *location, Elf_Addr v)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
@ -63,13 +63,6 @@ static int apply_r_mips_32_rel(struct module *me, u32 *location, Elf_Addr v)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int apply_r_mips_32_rela(struct module *me, u32 *location, Elf_Addr v)
|
||||
{
|
||||
*location = v;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int apply_r_mips_26_rel(struct module *me, u32 *location, Elf_Addr v)
|
||||
{
|
||||
if (v % 4) {
|
||||
|
@ -91,26 +84,6 @@ static int apply_r_mips_26_rel(struct module *me, u32 *location, Elf_Addr v)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int apply_r_mips_26_rela(struct module *me, u32 *location, Elf_Addr v)
|
||||
{
|
||||
if (v % 4) {
|
||||
pr_err("module %s: dangerous R_MIPS_26 RELArelocation\n",
|
||||
me->name);
|
||||
return -ENOEXEC;
|
||||
}
|
||||
|
||||
if ((v & 0xf0000000) != (((unsigned long)location + 4) & 0xf0000000)) {
|
||||
printk(KERN_ERR
|
||||
"module %s: relocation overflow\n",
|
||||
me->name);
|
||||
return -ENOEXEC;
|
||||
}
|
||||
|
||||
*location = (*location & ~0x03ffffff) | ((v >> 2) & 0x03ffffff);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int apply_r_mips_hi16_rel(struct module *me, u32 *location, Elf_Addr v)
|
||||
{
|
||||
struct mips_hi16 *n;
|
||||
|
@ -132,14 +105,6 @@ static int apply_r_mips_hi16_rel(struct module *me, u32 *location, Elf_Addr v)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int apply_r_mips_hi16_rela(struct module *me, u32 *location, Elf_Addr v)
|
||||
{
|
||||
*location = (*location & 0xffff0000) |
|
||||
((((long long) v + 0x8000LL) >> 16) & 0xffff);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void free_relocation_chain(struct mips_hi16 *l)
|
||||
{
|
||||
struct mips_hi16 *next;
|
||||
|
@ -217,38 +182,6 @@ static int apply_r_mips_lo16_rel(struct module *me, u32 *location, Elf_Addr v)
|
|||
return -ENOEXEC;
|
||||
}
|
||||
|
||||
static int apply_r_mips_lo16_rela(struct module *me, u32 *location, Elf_Addr v)
|
||||
{
|
||||
*location = (*location & 0xffff0000) | (v & 0xffff);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int apply_r_mips_64_rela(struct module *me, u32 *location, Elf_Addr v)
|
||||
{
|
||||
*(Elf_Addr *)location = v;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int apply_r_mips_higher_rela(struct module *me, u32 *location,
|
||||
Elf_Addr v)
|
||||
{
|
||||
*location = (*location & 0xffff0000) |
|
||||
((((long long) v + 0x80008000LL) >> 32) & 0xffff);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int apply_r_mips_highest_rela(struct module *me, u32 *location,
|
||||
Elf_Addr v)
|
||||
{
|
||||
*location = (*location & 0xffff0000) |
|
||||
((((long long) v + 0x800080008000LL) >> 48) & 0xffff);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int (*reloc_handlers_rel[]) (struct module *me, u32 *location,
|
||||
Elf_Addr v) = {
|
||||
[R_MIPS_NONE] = apply_r_mips_none,
|
||||
|
@ -258,18 +191,6 @@ static int (*reloc_handlers_rel[]) (struct module *me, u32 *location,
|
|||
[R_MIPS_LO16] = apply_r_mips_lo16_rel
|
||||
};
|
||||
|
||||
static int (*reloc_handlers_rela[]) (struct module *me, u32 *location,
|
||||
Elf_Addr v) = {
|
||||
[R_MIPS_NONE] = apply_r_mips_none,
|
||||
[R_MIPS_32] = apply_r_mips_32_rela,
|
||||
[R_MIPS_26] = apply_r_mips_26_rela,
|
||||
[R_MIPS_HI16] = apply_r_mips_hi16_rela,
|
||||
[R_MIPS_LO16] = apply_r_mips_lo16_rela,
|
||||
[R_MIPS_64] = apply_r_mips_64_rela,
|
||||
[R_MIPS_HIGHER] = apply_r_mips_higher_rela,
|
||||
[R_MIPS_HIGHEST] = apply_r_mips_highest_rela
|
||||
};
|
||||
|
||||
int apply_relocate(Elf_Shdr *sechdrs, const char *strtab,
|
||||
unsigned int symindex, unsigned int relsec,
|
||||
struct module *me)
|
||||
|
@ -324,46 +245,6 @@ int apply_relocate(Elf_Shdr *sechdrs, const char *strtab,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab,
|
||||
unsigned int symindex, unsigned int relsec,
|
||||
struct module *me)
|
||||
{
|
||||
Elf_Mips_Rela *rel = (void *) sechdrs[relsec].sh_addr;
|
||||
Elf_Sym *sym;
|
||||
u32 *location;
|
||||
unsigned int i;
|
||||
Elf_Addr v;
|
||||
int res;
|
||||
|
||||
pr_debug("Applying relocate section %u to %u\n", relsec,
|
||||
sechdrs[relsec].sh_info);
|
||||
|
||||
for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) {
|
||||
/* This is where to make the change */
|
||||
location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
|
||||
+ rel[i].r_offset;
|
||||
/* This is the symbol it is referring to */
|
||||
sym = (Elf_Sym *)sechdrs[symindex].sh_addr
|
||||
+ ELF_MIPS_R_SYM(rel[i]);
|
||||
if (IS_ERR_VALUE(sym->st_value)) {
|
||||
/* Ignore unresolved weak symbol */
|
||||
if (ELF_ST_BIND(sym->st_info) == STB_WEAK)
|
||||
continue;
|
||||
printk(KERN_WARNING "%s: Unknown symbol %s\n",
|
||||
me->name, strtab + sym->st_name);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
v = sym->st_value + rel[i].r_addend;
|
||||
|
||||
res = reloc_handlers_rela[ELF_MIPS_R_TYPE(rel[i])](me, location, v);
|
||||
if (res)
|
||||
return res;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Given an address, look for it in the module exception tables. */
|
||||
const struct exception_table_entry *search_module_dbetables(unsigned long addr)
|
||||
{
|
||||
|
|
|
@ -9,6 +9,7 @@ config MN10300
|
|||
select HAVE_NMI_WATCHDOG if MN10300_WD_TIMER
|
||||
select GENERIC_CLOCKEVENTS
|
||||
select GENERIC_KERNEL_THREAD
|
||||
select MODULES_USE_ELF_RELA
|
||||
|
||||
config AM33_2
|
||||
def_bool n
|
||||
|
|
|
@ -12,12 +12,7 @@
|
|||
#ifndef _ASM_MODULE_H
|
||||
#define _ASM_MODULE_H
|
||||
|
||||
struct mod_arch_specific {
|
||||
};
|
||||
|
||||
#define Elf_Shdr Elf32_Shdr
|
||||
#define Elf_Sym Elf32_Sym
|
||||
#define Elf_Ehdr Elf32_Ehdr
|
||||
#include <asm-generic/module.h>
|
||||
|
||||
/*
|
||||
* Include the MN10300 architecture version.
|
||||
|
|
|
@ -21,6 +21,7 @@ config OPENRISC
|
|||
select GENERIC_CLOCKEVENTS
|
||||
select GENERIC_STRNCPY_FROM_USER
|
||||
select GENERIC_STRNLEN_USER
|
||||
select MODULES_USE_ELF_RELA
|
||||
|
||||
config MMU
|
||||
def_bool y
|
||||
|
|
|
@ -20,6 +20,8 @@ config PARISC
|
|||
select ARCH_HAVE_NMI_SAFE_CMPXCHG
|
||||
select GENERIC_SMP_IDLE_THREAD
|
||||
select GENERIC_STRNCPY_FROM_USER
|
||||
select HAVE_MOD_ARCH_SPECIFIC
|
||||
select MODULES_USE_ELF_RELA
|
||||
|
||||
help
|
||||
The PA-RISC microprocessor is designed by Hewlett-Packard and used
|
||||
|
|
|
@ -1,21 +1,11 @@
|
|||
#ifndef _ASM_PARISC_MODULE_H
|
||||
#define _ASM_PARISC_MODULE_H
|
||||
|
||||
#include <asm-generic/module.h>
|
||||
|
||||
/*
|
||||
* This file contains the parisc architecture specific module code.
|
||||
*/
|
||||
#ifdef CONFIG_64BIT
|
||||
#define Elf_Shdr Elf64_Shdr
|
||||
#define Elf_Sym Elf64_Sym
|
||||
#define Elf_Ehdr Elf64_Ehdr
|
||||
#define Elf_Addr Elf64_Addr
|
||||
#define Elf_Rela Elf64_Rela
|
||||
#else
|
||||
#define Elf_Shdr Elf32_Shdr
|
||||
#define Elf_Sym Elf32_Sym
|
||||
#define Elf_Ehdr Elf32_Ehdr
|
||||
#define Elf_Addr Elf32_Addr
|
||||
#define Elf_Rela Elf32_Rela
|
||||
#endif
|
||||
|
||||
struct unwind_table;
|
||||
|
||||
|
|
|
@ -142,6 +142,8 @@ config PPC
|
|||
select GENERIC_STRNCPY_FROM_USER
|
||||
select GENERIC_STRNLEN_USER
|
||||
select GENERIC_KERNEL_THREAD
|
||||
select HAVE_MOD_ARCH_SPECIFIC
|
||||
select MODULES_USE_ELF_RELA
|
||||
|
||||
config EARLY_PRINTK
|
||||
bool
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
#include <linux/list.h>
|
||||
#include <asm/bug.h>
|
||||
#include <asm-generic/module.h>
|
||||
|
||||
|
||||
#ifndef __powerpc64__
|
||||
|
@ -60,16 +61,10 @@ struct mod_arch_specific {
|
|||
*/
|
||||
|
||||
#ifdef __powerpc64__
|
||||
# define Elf_Shdr Elf64_Shdr
|
||||
# define Elf_Sym Elf64_Sym
|
||||
# define Elf_Ehdr Elf64_Ehdr
|
||||
# ifdef MODULE
|
||||
asm(".section .stubs,\"ax\",@nobits; .align 3; .previous");
|
||||
# endif
|
||||
#else
|
||||
# define Elf_Shdr Elf32_Shdr
|
||||
# define Elf_Sym Elf32_Sym
|
||||
# define Elf_Ehdr Elf32_Ehdr
|
||||
# ifdef MODULE
|
||||
asm(".section .plt,\"ax\",@nobits; .align 3; .previous");
|
||||
asm(".section .init.plt,\"ax\",@nobits; .align 3; .previous");
|
||||
|
|
|
@ -136,6 +136,8 @@ config S390
|
|||
select KTIME_SCALAR if 32BIT
|
||||
select HAVE_ARCH_SECCOMP_FILTER
|
||||
select GENERIC_KERNEL_THREAD
|
||||
select HAVE_MOD_ARCH_SPECIFIC
|
||||
select MODULES_USE_ELF_RELA
|
||||
|
||||
config SCHED_OMIT_FRAME_POINTER
|
||||
def_bool y
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
#ifndef _ASM_S390_MODULE_H
|
||||
#define _ASM_S390_MODULE_H
|
||||
|
||||
#include <asm-generic/module.h>
|
||||
|
||||
/*
|
||||
* This file contains the s390 architecture specific module code.
|
||||
*/
|
||||
|
@ -28,19 +31,4 @@ struct mod_arch_specific
|
|||
struct mod_arch_syminfo *syminfo;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_64BIT
|
||||
#define ElfW(x) Elf64_ ## x
|
||||
#define ELFW(x) ELF64_ ## x
|
||||
#else
|
||||
#define ElfW(x) Elf32_ ## x
|
||||
#define ELFW(x) ELF32_ ## x
|
||||
#endif
|
||||
|
||||
#define Elf_Addr ElfW(Addr)
|
||||
#define Elf_Rela ElfW(Rela)
|
||||
#define Elf_Shdr ElfW(Shdr)
|
||||
#define Elf_Sym ElfW(Sym)
|
||||
#define Elf_Ehdr ElfW(Ehdr)
|
||||
#define ELF_R_SYM ELFW(R_SYM)
|
||||
#define ELF_R_TYPE ELFW(R_TYPE)
|
||||
#endif /* _ASM_S390_MODULE_H */
|
||||
|
|
|
@ -11,6 +11,8 @@ config SCORE
|
|||
select ARCH_DISCARD_MEMBLOCK
|
||||
select GENERIC_CPU_DEVICES
|
||||
select GENERIC_CLOCKEVENTS
|
||||
select HAVE_MOD_ARCH_SPECIFIC
|
||||
select MODULES_USE_ELF_REL
|
||||
|
||||
choice
|
||||
prompt "System type"
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include <linux/list.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm-generic/module.h>
|
||||
|
||||
struct mod_arch_specific {
|
||||
/* Data Bus Error exception tables */
|
||||
|
@ -13,11 +14,6 @@ struct mod_arch_specific {
|
|||
|
||||
typedef uint8_t Elf64_Byte; /* Type for a 8-bit quantity. */
|
||||
|
||||
#define Elf_Shdr Elf32_Shdr
|
||||
#define Elf_Sym Elf32_Sym
|
||||
#define Elf_Ehdr Elf32_Ehdr
|
||||
#define Elf_Addr Elf32_Addr
|
||||
|
||||
/* Given an address, look for it in the exception tables. */
|
||||
#ifdef CONFIG_MODULES
|
||||
const struct exception_table_entry *search_module_dbetables(unsigned long addr);
|
||||
|
|
|
@ -125,16 +125,6 @@ int apply_relocate(Elf_Shdr *sechdrs, const char *strtab,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab,
|
||||
unsigned int symindex, unsigned int relsec,
|
||||
struct module *me)
|
||||
{
|
||||
/* Non-standard return value... most other arch's return -ENOEXEC
|
||||
* for an unsupported relocation variant
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Given an address, look for it in the module exception tables. */
|
||||
const struct exception_table_entry *search_module_dbetables(unsigned long addr)
|
||||
{
|
||||
|
|
|
@ -38,6 +38,8 @@ config SUPERH
|
|||
select GENERIC_CMOS_UPDATE if SH_SH03 || SH_DREAMCAST
|
||||
select GENERIC_STRNCPY_FROM_USER
|
||||
select GENERIC_STRNLEN_USER
|
||||
select HAVE_MOD_ARCH_SPECIFIC if DWARF_UNWINDER
|
||||
select MODULES_USE_ELF_RELA
|
||||
help
|
||||
The SuperH is a RISC processor targeted for use in embedded systems
|
||||
and consumer electronics; it was also used in the Sega Dreamcast
|
||||
|
|
|
@ -1,21 +1,13 @@
|
|||
#ifndef _ASM_SH_MODULE_H
|
||||
#define _ASM_SH_MODULE_H
|
||||
|
||||
struct mod_arch_specific {
|
||||
#include <asm-generic/module.h>
|
||||
|
||||
#ifdef CONFIG_DWARF_UNWINDER
|
||||
struct mod_arch_specific {
|
||||
struct list_head fde_list;
|
||||
struct list_head cie_list;
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef CONFIG_64BIT
|
||||
#define Elf_Shdr Elf64_Shdr
|
||||
#define Elf_Sym Elf64_Sym
|
||||
#define Elf_Ehdr Elf64_Ehdr
|
||||
#else
|
||||
#define Elf_Shdr Elf32_Shdr
|
||||
#define Elf_Sym Elf32_Sym
|
||||
#define Elf_Ehdr Elf32_Ehdr
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_CPU_LITTLE_ENDIAN
|
||||
|
|
|
@ -39,6 +39,7 @@ config SPARC
|
|||
select GENERIC_CLOCKEVENTS
|
||||
select GENERIC_STRNCPY_FROM_USER
|
||||
select GENERIC_STRNLEN_USER
|
||||
select MODULES_USE_ELF_RELA
|
||||
|
||||
config SPARC32
|
||||
def_bool !64BIT
|
||||
|
|
|
@ -7,4 +7,5 @@ generic-y += exec.h
|
|||
generic-y += local64.h
|
||||
generic-y += irq_regs.h
|
||||
generic-y += local.h
|
||||
generic-y += module.h
|
||||
generic-y += word-at-a-time.h
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
#ifndef __SPARC_MODULE_H
|
||||
#define __SPARC_MODULE_H
|
||||
struct mod_arch_specific { };
|
||||
|
||||
/*
|
||||
* Use some preprocessor magic to define the correct symbol
|
||||
* for sparc32 and sparc64.
|
||||
* Elf_Addr becomes Elf32_Addr for sparc32 and Elf64_Addr for sparc64
|
||||
*/
|
||||
#define ___ELF(a, b, c) a##b##c
|
||||
#define __ELF(a, b, c) ___ELF(a, b, c)
|
||||
#define _Elf(t) __ELF(Elf, CONFIG_BITS, t)
|
||||
#define _ELF(t) __ELF(ELF, CONFIG_BITS, t)
|
||||
|
||||
#define Elf_Shdr _Elf(_Shdr)
|
||||
#define Elf_Sym _Elf(_Sym)
|
||||
#define Elf_Ehdr _Elf(_Ehdr)
|
||||
#define Elf_Rela _Elf(_Rela)
|
||||
#define Elf_Addr _Elf(_Addr)
|
||||
|
||||
#define ELF_R_SYM _ELF(_R_SYM)
|
||||
#define ELF_R_TYPE _ELF(_R_TYPE)
|
||||
|
||||
#endif /* __SPARC_MODULE_H */
|
|
@ -20,6 +20,7 @@ config TILE
|
|||
select SYS_HYPERVISOR
|
||||
select ARCH_HAVE_NMI_SAFE_CMPXCHG
|
||||
select GENERIC_CLOCKEVENTS
|
||||
select MODULES_USE_ELF_RELA
|
||||
|
||||
# FIXME: investigate whether we need/want these options.
|
||||
# select HAVE_IOREMAP_PROT
|
||||
|
|
|
@ -15,6 +15,7 @@ config UNICORE32
|
|||
select GENERIC_IRQ_SHOW
|
||||
select ARCH_WANT_FRAME_POINTERS
|
||||
select GENERIC_IOMAP
|
||||
select MODULES_USE_ELF_REL
|
||||
help
|
||||
UniCore-32 is 32-bit Instruction Set Architecture,
|
||||
including a series of low-power-consumption RISC chip
|
||||
|
|
|
@ -110,6 +110,8 @@ config X86
|
|||
select HAVE_IRQ_TIME_ACCOUNTING
|
||||
select GENERIC_KERNEL_THREAD
|
||||
select GENERIC_KERNEL_EXECVE
|
||||
select MODULES_USE_ELF_REL if X86_32
|
||||
select MODULES_USE_ELF_RELA if X86_64
|
||||
|
||||
config INSTRUCTION_DECODER
|
||||
def_bool y
|
||||
|
|
|
@ -24,9 +24,11 @@ config X86_32
|
|||
def_bool !64BIT
|
||||
select HAVE_AOUT
|
||||
select ARCH_WANT_IPC_PARSE_VERSION
|
||||
select MODULES_USE_ELF_REL
|
||||
|
||||
config X86_64
|
||||
def_bool 64BIT
|
||||
select MODULES_USE_ELF_RELA
|
||||
|
||||
config RWSEM_XCHGADD_ALGORITHM
|
||||
def_bool X86_XADD && 64BIT
|
||||
|
|
|
@ -13,15 +13,8 @@
|
|||
#ifndef _XTENSA_MODULE_H
|
||||
#define _XTENSA_MODULE_H
|
||||
|
||||
struct mod_arch_specific
|
||||
{
|
||||
/* No special elements, yet. */
|
||||
};
|
||||
|
||||
#define MODULE_ARCH_VERMAGIC "xtensa-" __stringify(XCHAL_CORE_ID) " "
|
||||
|
||||
#define Elf_Shdr Elf32_Shdr
|
||||
#define Elf_Sym Elf32_Sym
|
||||
#define Elf_Ehdr Elf32_Ehdr
|
||||
#include <asm-generic/module.h>
|
||||
|
||||
#endif /* _XTENSA_MODULE_H */
|
||||
|
|
|
@ -1216,5 +1216,6 @@ config CRYPTO_USER_API_SKCIPHER
|
|||
key cipher algorithms.
|
||||
|
||||
source "drivers/crypto/Kconfig"
|
||||
source crypto/asymmetric_keys/Kconfig
|
||||
|
||||
endif # if CRYPTO
|
||||
|
|
|
@ -97,3 +97,4 @@ obj-$(CONFIG_CRYPTO_USER_API_SKCIPHER) += algif_skcipher.o
|
|||
#
|
||||
obj-$(CONFIG_XOR_BLOCKS) += xor.o
|
||||
obj-$(CONFIG_ASYNC_CORE) += async_tx/
|
||||
obj-$(CONFIG_ASYMMETRIC_KEY_TYPE) += asymmetric_keys/
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
*-asn1.[ch]
|
|
@ -0,0 +1,38 @@
|
|||
menuconfig ASYMMETRIC_KEY_TYPE
|
||||
tristate "Asymmetric (public-key cryptographic) key type"
|
||||
depends on KEYS
|
||||
help
|
||||
This option provides support for a key type that holds the data for
|
||||
the asymmetric keys used for public key cryptographic operations such
|
||||
as encryption, decryption, signature generation and signature
|
||||
verification.
|
||||
|
||||
if ASYMMETRIC_KEY_TYPE
|
||||
|
||||
config ASYMMETRIC_PUBLIC_KEY_SUBTYPE
|
||||
tristate "Asymmetric public-key crypto algorithm subtype"
|
||||
select MPILIB
|
||||
help
|
||||
This option provides support for asymmetric public key type handling.
|
||||
If signature generation and/or verification are to be used,
|
||||
appropriate hash algorithms (such as SHA-1) must be available.
|
||||
ENOPKG will be reported if the requisite algorithm is unavailable.
|
||||
|
||||
config PUBLIC_KEY_ALGO_RSA
|
||||
tristate "RSA public-key algorithm"
|
||||
depends on ASYMMETRIC_PUBLIC_KEY_SUBTYPE
|
||||
select MPILIB_EXTRA
|
||||
help
|
||||
This option enables support for the RSA algorithm (PKCS#1, RFC3447).
|
||||
|
||||
config X509_CERTIFICATE_PARSER
|
||||
tristate "X.509 certificate parser"
|
||||
depends on ASYMMETRIC_PUBLIC_KEY_SUBTYPE
|
||||
select ASN1
|
||||
select OID_REGISTRY
|
||||
help
|
||||
This option procides 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.
|
||||
|
||||
endif # ASYMMETRIC_KEY_TYPE
|
|
@ -0,0 +1,27 @@
|
|||
#
|
||||
# Makefile for asymmetric cryptographic keys
|
||||
#
|
||||
|
||||
obj-$(CONFIG_ASYMMETRIC_KEY_TYPE) += asymmetric_keys.o
|
||||
|
||||
asymmetric_keys-y := asymmetric_type.o signature.o
|
||||
|
||||
obj-$(CONFIG_ASYMMETRIC_PUBLIC_KEY_SUBTYPE) += public_key.o
|
||||
obj-$(CONFIG_PUBLIC_KEY_ALGO_RSA) += rsa.o
|
||||
|
||||
#
|
||||
# X.509 Certificate handling
|
||||
#
|
||||
obj-$(CONFIG_X509_CERTIFICATE_PARSER) += x509_key_parser.o
|
||||
x509_key_parser-y := \
|
||||
x509-asn1.o \
|
||||
x509_rsakey-asn1.o \
|
||||
x509_cert_parser.o \
|
||||
x509_public_key.o
|
||||
|
||||
$(obj)/x509_cert_parser.o: $(obj)/x509-asn1.h $(obj)/x509_rsakey-asn1.h
|
||||
$(obj)/x509-asn1.o: $(obj)/x509-asn1.c $(obj)/x509-asn1.h
|
||||
$(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
|
|
@ -0,0 +1,15 @@
|
|||
/* Internal definitions for asymmetric key type
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
static inline const char *asymmetric_key_id(const struct key *key)
|
||||
{
|
||||
return key->type_data.p[1];
|
||||
}
|
|
@ -0,0 +1,274 @@
|
|||
/* Asymmetric public-key cryptography key type
|
||||
*
|
||||
* See Documentation/security/asymmetric-keys.txt
|
||||
*
|
||||
* 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 <keys/asymmetric-subtype.h>
|
||||
#include <keys/asymmetric-parser.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include "asymmetric_keys.h"
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
static LIST_HEAD(asymmetric_key_parsers);
|
||||
static DECLARE_RWSEM(asymmetric_key_parsers_sem);
|
||||
|
||||
/*
|
||||
* Match asymmetric keys on (part of) their name
|
||||
* We have some shorthand methods for matching keys. We allow:
|
||||
*
|
||||
* "<desc>" - request a key by description
|
||||
* "id:<id>" - request a key matching the ID
|
||||
* "<subtype>:<id>" - request a key of a subtype
|
||||
*/
|
||||
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;
|
||||
ptrdiff_t speclen;
|
||||
size_t idlen, kidlen;
|
||||
|
||||
if (!subtype || !spec || !*spec)
|
||||
return 0;
|
||||
|
||||
/* See if the full key description matches as is */
|
||||
if (key->description && strcmp(key->description, description) == 0)
|
||||
return 1;
|
||||
|
||||
/* All tests from here on break the criterion description into a
|
||||
* specifier, a colon and then an identifier.
|
||||
*/
|
||||
id = strchr(spec, ':');
|
||||
if (!id)
|
||||
return 0;
|
||||
|
||||
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 == subtype->name_len &&
|
||||
memcmp(spec, subtype->name, speclen) == 0)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Describe the asymmetric key
|
||||
*/
|
||||
static void asymmetric_key_describe(const struct key *key, struct seq_file *m)
|
||||
{
|
||||
const struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key);
|
||||
const char *kid = asymmetric_key_id(key);
|
||||
size_t n;
|
||||
|
||||
seq_puts(m, key->description);
|
||||
|
||||
if (subtype) {
|
||||
seq_puts(m, ": ");
|
||||
subtype->describe(key, m);
|
||||
|
||||
if (kid) {
|
||||
seq_putc(m, ' ');
|
||||
n = strlen(kid);
|
||||
if (n <= 8)
|
||||
seq_puts(m, kid);
|
||||
else
|
||||
seq_puts(m, kid + n - 8);
|
||||
}
|
||||
|
||||
seq_puts(m, " [");
|
||||
/* put something here to indicate the key's capabilities */
|
||||
seq_putc(m, ']');
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Preparse a asymmetric payload to get format the contents appropriately for the
|
||||
* internal payload to cut down on the number of scans of the data performed.
|
||||
*
|
||||
* We also generate a proposed description from the contents of the key that
|
||||
* can be used to name the key if the user doesn't want to provide one.
|
||||
*/
|
||||
static int asymmetric_key_preparse(struct key_preparsed_payload *prep)
|
||||
{
|
||||
struct asymmetric_key_parser *parser;
|
||||
int ret;
|
||||
|
||||
pr_devel("==>%s()\n", __func__);
|
||||
|
||||
if (prep->datalen == 0)
|
||||
return -EINVAL;
|
||||
|
||||
down_read(&asymmetric_key_parsers_sem);
|
||||
|
||||
ret = -EBADMSG;
|
||||
list_for_each_entry(parser, &asymmetric_key_parsers, link) {
|
||||
pr_debug("Trying parser '%s'\n", parser->name);
|
||||
|
||||
ret = parser->parse(prep);
|
||||
if (ret != -EBADMSG) {
|
||||
pr_debug("Parser recognised the format (ret %d)\n",
|
||||
ret);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
up_read(&asymmetric_key_parsers_sem);
|
||||
pr_devel("<==%s() = %d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Clean up the preparse data
|
||||
*/
|
||||
static void asymmetric_key_free_preparse(struct key_preparsed_payload *prep)
|
||||
{
|
||||
struct asymmetric_key_subtype *subtype = prep->type_data[0];
|
||||
|
||||
pr_devel("==>%s()\n", __func__);
|
||||
|
||||
if (subtype) {
|
||||
subtype->destroy(prep->payload);
|
||||
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
|
||||
*/
|
||||
static void asymmetric_key_destroy(struct key *key)
|
||||
{
|
||||
struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key);
|
||||
if (subtype) {
|
||||
subtype->destroy(key->payload.data);
|
||||
module_put(subtype->owner);
|
||||
key->type_data.p[0] = NULL;
|
||||
}
|
||||
kfree(key->type_data.p[1]);
|
||||
key->type_data.p[1] = NULL;
|
||||
}
|
||||
|
||||
struct key_type key_type_asymmetric = {
|
||||
.name = "asymmetric",
|
||||
.preparse = asymmetric_key_preparse,
|
||||
.free_preparse = asymmetric_key_free_preparse,
|
||||
.instantiate = asymmetric_key_instantiate,
|
||||
.match = asymmetric_key_match,
|
||||
.destroy = asymmetric_key_destroy,
|
||||
.describe = asymmetric_key_describe,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(key_type_asymmetric);
|
||||
|
||||
/**
|
||||
* register_asymmetric_key_parser - Register a asymmetric key blob parser
|
||||
* @parser: The parser to register
|
||||
*/
|
||||
int register_asymmetric_key_parser(struct asymmetric_key_parser *parser)
|
||||
{
|
||||
struct asymmetric_key_parser *cursor;
|
||||
int ret;
|
||||
|
||||
down_write(&asymmetric_key_parsers_sem);
|
||||
|
||||
list_for_each_entry(cursor, &asymmetric_key_parsers, link) {
|
||||
if (strcmp(cursor->name, parser->name) == 0) {
|
||||
pr_err("Asymmetric key parser '%s' already registered\n",
|
||||
parser->name);
|
||||
ret = -EEXIST;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
list_add_tail(&parser->link, &asymmetric_key_parsers);
|
||||
|
||||
pr_notice("Asymmetric key parser '%s' registered\n", parser->name);
|
||||
ret = 0;
|
||||
|
||||
out:
|
||||
up_write(&asymmetric_key_parsers_sem);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(register_asymmetric_key_parser);
|
||||
|
||||
/**
|
||||
* unregister_asymmetric_key_parser - Unregister a asymmetric key blob parser
|
||||
* @parser: The parser to unregister
|
||||
*/
|
||||
void unregister_asymmetric_key_parser(struct asymmetric_key_parser *parser)
|
||||
{
|
||||
down_write(&asymmetric_key_parsers_sem);
|
||||
list_del(&parser->link);
|
||||
up_write(&asymmetric_key_parsers_sem);
|
||||
|
||||
pr_notice("Asymmetric key parser '%s' unregistered\n", parser->name);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(unregister_asymmetric_key_parser);
|
||||
|
||||
/*
|
||||
* Module stuff
|
||||
*/
|
||||
static int __init asymmetric_key_init(void)
|
||||
{
|
||||
return register_key_type(&key_type_asymmetric);
|
||||
}
|
||||
|
||||
static void __exit asymmetric_key_cleanup(void)
|
||||
{
|
||||
unregister_key_type(&key_type_asymmetric);
|
||||
}
|
||||
|
||||
module_init(asymmetric_key_init);
|
||||
module_exit(asymmetric_key_cleanup);
|
|
@ -0,0 +1,108 @@
|
|||
/* In-software asymmetric public-key crypto subtype
|
||||
*
|
||||
* See Documentation/crypto/asymmetric-keys.txt
|
||||
*
|
||||
* 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) "PKEY: "fmt
|
||||
#include <linux/module.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <keys/asymmetric-subtype.h>
|
||||
#include "public_key.h"
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
const char *const pkey_algo[PKEY_ALGO__LAST] = {
|
||||
[PKEY_ALGO_DSA] = "DSA",
|
||||
[PKEY_ALGO_RSA] = "RSA",
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(pkey_algo);
|
||||
|
||||
const char *const pkey_hash_algo[PKEY_HASH__LAST] = {
|
||||
[PKEY_HASH_MD4] = "md4",
|
||||
[PKEY_HASH_MD5] = "md5",
|
||||
[PKEY_HASH_SHA1] = "sha1",
|
||||
[PKEY_HASH_RIPE_MD_160] = "rmd160",
|
||||
[PKEY_HASH_SHA256] = "sha256",
|
||||
[PKEY_HASH_SHA384] = "sha384",
|
||||
[PKEY_HASH_SHA512] = "sha512",
|
||||
[PKEY_HASH_SHA224] = "sha224",
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(pkey_hash_algo);
|
||||
|
||||
const char *const pkey_id_type[PKEY_ID_TYPE__LAST] = {
|
||||
[PKEY_ID_PGP] = "PGP",
|
||||
[PKEY_ID_X509] = "X509",
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(pkey_id_type);
|
||||
|
||||
/*
|
||||
* Provide a part of a description of the key for /proc/keys.
|
||||
*/
|
||||
static void public_key_describe(const struct key *asymmetric_key,
|
||||
struct seq_file *m)
|
||||
{
|
||||
struct public_key *key = asymmetric_key->payload.data;
|
||||
|
||||
if (key)
|
||||
seq_printf(m, "%s.%s",
|
||||
pkey_id_type[key->id_type], key->algo->name);
|
||||
}
|
||||
|
||||
/*
|
||||
* Destroy a public key algorithm key.
|
||||
*/
|
||||
void public_key_destroy(void *payload)
|
||||
{
|
||||
struct public_key *key = payload;
|
||||
int i;
|
||||
|
||||
if (key) {
|
||||
for (i = 0; i < ARRAY_SIZE(key->mpi); i++)
|
||||
mpi_free(key->mpi[i]);
|
||||
kfree(key);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(public_key_destroy);
|
||||
|
||||
/*
|
||||
* Verify a signature using a public key.
|
||||
*/
|
||||
static int public_key_verify_signature(const struct key *key,
|
||||
const struct public_key_signature *sig)
|
||||
{
|
||||
const struct public_key *pk = key->payload.data;
|
||||
|
||||
if (!pk->algo->verify_signature)
|
||||
return -ENOTSUPP;
|
||||
|
||||
if (sig->nr_mpi != pk->algo->n_sig_mpi) {
|
||||
pr_debug("Signature has %u MPI not %u\n",
|
||||
sig->nr_mpi, pk->algo->n_sig_mpi);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return pk->algo->verify_signature(pk, sig);
|
||||
}
|
||||
|
||||
/*
|
||||
* Public key algorithm asymmetric key subtype
|
||||
*/
|
||||
struct asymmetric_key_subtype public_key_subtype = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "public_key",
|
||||
.describe = public_key_describe,
|
||||
.destroy = public_key_destroy,
|
||||
.verify_signature = public_key_verify_signature,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(public_key_subtype);
|
|
@ -0,0 +1,30 @@
|
|||
/* Public key algorithm internals
|
||||
*
|
||||
* See Documentation/crypto/asymmetric-keys.txt
|
||||
*
|
||||
* 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 <crypto/public_key.h>
|
||||
|
||||
extern struct asymmetric_key_subtype public_key_subtype;
|
||||
|
||||
/*
|
||||
* Public key algorithm definition.
|
||||
*/
|
||||
struct public_key_algorithm {
|
||||
const char *name;
|
||||
u8 n_pub_mpi; /* Number of MPIs in public key */
|
||||
u8 n_sec_mpi; /* Number of MPIs in secret key */
|
||||
u8 n_sig_mpi; /* Number of MPIs in a signature */
|
||||
int (*verify_signature)(const struct public_key *key,
|
||||
const struct public_key_signature *sig);
|
||||
};
|
||||
|
||||
extern const struct public_key_algorithm RSA_public_key_algorithm;
|
|
@ -0,0 +1,277 @@
|
|||
/* RSA asymmetric public-key algorithm [RFC3447]
|
||||
*
|
||||
* 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) "RSA: "fmt
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include "public_key.h"
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("RSA Public Key Algorithm");
|
||||
|
||||
#define kenter(FMT, ...) \
|
||||
pr_devel("==> %s("FMT")\n", __func__, ##__VA_ARGS__)
|
||||
#define kleave(FMT, ...) \
|
||||
pr_devel("<== %s()"FMT"\n", __func__, ##__VA_ARGS__)
|
||||
|
||||
/*
|
||||
* Hash algorithm OIDs plus ASN.1 DER wrappings [RFC4880 sec 5.2.2].
|
||||
*/
|
||||
static const u8 RSA_digest_info_MD5[] = {
|
||||
0x30, 0x20, 0x30, 0x0C, 0x06, 0x08,
|
||||
0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05, /* OID */
|
||||
0x05, 0x00, 0x04, 0x10
|
||||
};
|
||||
|
||||
static const u8 RSA_digest_info_SHA1[] = {
|
||||
0x30, 0x21, 0x30, 0x09, 0x06, 0x05,
|
||||
0x2B, 0x0E, 0x03, 0x02, 0x1A,
|
||||
0x05, 0x00, 0x04, 0x14
|
||||
};
|
||||
|
||||
static const u8 RSA_digest_info_RIPE_MD_160[] = {
|
||||
0x30, 0x21, 0x30, 0x09, 0x06, 0x05,
|
||||
0x2B, 0x24, 0x03, 0x02, 0x01,
|
||||
0x05, 0x00, 0x04, 0x14
|
||||
};
|
||||
|
||||
static const u8 RSA_digest_info_SHA224[] = {
|
||||
0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09,
|
||||
0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04,
|
||||
0x05, 0x00, 0x04, 0x1C
|
||||
};
|
||||
|
||||
static const u8 RSA_digest_info_SHA256[] = {
|
||||
0x30, 0x31, 0x30, 0x0d, 0x06, 0x09,
|
||||
0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01,
|
||||
0x05, 0x00, 0x04, 0x20
|
||||
};
|
||||
|
||||
static const u8 RSA_digest_info_SHA384[] = {
|
||||
0x30, 0x41, 0x30, 0x0d, 0x06, 0x09,
|
||||
0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02,
|
||||
0x05, 0x00, 0x04, 0x30
|
||||
};
|
||||
|
||||
static const u8 RSA_digest_info_SHA512[] = {
|
||||
0x30, 0x51, 0x30, 0x0d, 0x06, 0x09,
|
||||
0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03,
|
||||
0x05, 0x00, 0x04, 0x40
|
||||
};
|
||||
|
||||
static const struct {
|
||||
const u8 *data;
|
||||
size_t size;
|
||||
} RSA_ASN1_templates[PKEY_HASH__LAST] = {
|
||||
#define _(X) { RSA_digest_info_##X, sizeof(RSA_digest_info_##X) }
|
||||
[PKEY_HASH_MD5] = _(MD5),
|
||||
[PKEY_HASH_SHA1] = _(SHA1),
|
||||
[PKEY_HASH_RIPE_MD_160] = _(RIPE_MD_160),
|
||||
[PKEY_HASH_SHA256] = _(SHA256),
|
||||
[PKEY_HASH_SHA384] = _(SHA384),
|
||||
[PKEY_HASH_SHA512] = _(SHA512),
|
||||
[PKEY_HASH_SHA224] = _(SHA224),
|
||||
#undef _
|
||||
};
|
||||
|
||||
/*
|
||||
* RSAVP1() function [RFC3447 sec 5.2.2]
|
||||
*/
|
||||
static int RSAVP1(const struct public_key *key, MPI s, MPI *_m)
|
||||
{
|
||||
MPI m;
|
||||
int ret;
|
||||
|
||||
/* (1) Validate 0 <= s < n */
|
||||
if (mpi_cmp_ui(s, 0) < 0) {
|
||||
kleave(" = -EBADMSG [s < 0]");
|
||||
return -EBADMSG;
|
||||
}
|
||||
if (mpi_cmp(s, key->rsa.n) >= 0) {
|
||||
kleave(" = -EBADMSG [s >= n]");
|
||||
return -EBADMSG;
|
||||
}
|
||||
|
||||
m = mpi_alloc(0);
|
||||
if (!m)
|
||||
return -ENOMEM;
|
||||
|
||||
/* (2) m = s^e mod n */
|
||||
ret = mpi_powm(m, s, key->rsa.e, key->rsa.n);
|
||||
if (ret < 0) {
|
||||
mpi_free(m);
|
||||
return ret;
|
||||
}
|
||||
|
||||
*_m = m;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Integer to Octet String conversion [RFC3447 sec 4.1]
|
||||
*/
|
||||
static int RSA_I2OSP(MPI x, size_t xLen, u8 **_X)
|
||||
{
|
||||
unsigned X_size, x_size;
|
||||
int X_sign;
|
||||
u8 *X;
|
||||
|
||||
/* Make sure the string is the right length. The number should begin
|
||||
* with { 0x00, 0x01, ... } so we have to account for 15 leading zero
|
||||
* bits not being reported by MPI.
|
||||
*/
|
||||
x_size = mpi_get_nbits(x);
|
||||
pr_devel("size(x)=%u xLen*8=%zu\n", x_size, xLen * 8);
|
||||
if (x_size != xLen * 8 - 15)
|
||||
return -ERANGE;
|
||||
|
||||
X = mpi_get_buffer(x, &X_size, &X_sign);
|
||||
if (!X)
|
||||
return -ENOMEM;
|
||||
if (X_sign < 0) {
|
||||
kfree(X);
|
||||
return -EBADMSG;
|
||||
}
|
||||
if (X_size != xLen - 1) {
|
||||
kfree(X);
|
||||
return -EBADMSG;
|
||||
}
|
||||
|
||||
*_X = X;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform the RSA signature verification.
|
||||
* @H: Value of hash of data and metadata
|
||||
* @EM: The computed signature value
|
||||
* @k: The size of EM (EM[0] is an invalid location but should hold 0x00)
|
||||
* @hash_size: The size of H
|
||||
* @asn1_template: The DigestInfo ASN.1 template
|
||||
* @asn1_size: Size of asm1_template[]
|
||||
*/
|
||||
static int RSA_verify(const u8 *H, const u8 *EM, size_t k, size_t hash_size,
|
||||
const u8 *asn1_template, size_t asn1_size)
|
||||
{
|
||||
unsigned PS_end, T_offset, i;
|
||||
|
||||
kenter(",,%zu,%zu,%zu", k, hash_size, asn1_size);
|
||||
|
||||
if (k < 2 + 1 + asn1_size + hash_size)
|
||||
return -EBADMSG;
|
||||
|
||||
/* Decode the EMSA-PKCS1-v1_5 */
|
||||
if (EM[1] != 0x01) {
|
||||
kleave(" = -EBADMSG [EM[1] == %02u]", EM[1]);
|
||||
return -EBADMSG;
|
||||
}
|
||||
|
||||
T_offset = k - (asn1_size + hash_size);
|
||||
PS_end = T_offset - 1;
|
||||
if (EM[PS_end] != 0x00) {
|
||||
kleave(" = -EBADMSG [EM[T-1] == %02u]", EM[PS_end]);
|
||||
return -EBADMSG;
|
||||
}
|
||||
|
||||
for (i = 2; i < PS_end; i++) {
|
||||
if (EM[i] != 0xff) {
|
||||
kleave(" = -EBADMSG [EM[PS%x] == %02u]", i - 2, EM[i]);
|
||||
return -EBADMSG;
|
||||
}
|
||||
}
|
||||
|
||||
if (memcmp(asn1_template, EM + T_offset, asn1_size) != 0) {
|
||||
kleave(" = -EBADMSG [EM[T] ASN.1 mismatch]");
|
||||
return -EBADMSG;
|
||||
}
|
||||
|
||||
if (memcmp(H, EM + T_offset + asn1_size, hash_size) != 0) {
|
||||
kleave(" = -EKEYREJECTED [EM[T] hash mismatch]");
|
||||
return -EKEYREJECTED;
|
||||
}
|
||||
|
||||
kleave(" = 0");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform the verification step [RFC3447 sec 8.2.2].
|
||||
*/
|
||||
static int RSA_verify_signature(const struct public_key *key,
|
||||
const struct public_key_signature *sig)
|
||||
{
|
||||
size_t tsize;
|
||||
int ret;
|
||||
|
||||
/* Variables as per RFC3447 sec 8.2.2 */
|
||||
const u8 *H = sig->digest;
|
||||
u8 *EM = NULL;
|
||||
MPI m = NULL;
|
||||
size_t k;
|
||||
|
||||
kenter("");
|
||||
|
||||
if (!RSA_ASN1_templates[sig->pkey_hash_algo].data)
|
||||
return -ENOTSUPP;
|
||||
|
||||
/* (1) Check the signature size against the public key modulus size */
|
||||
k = mpi_get_nbits(key->rsa.n);
|
||||
tsize = mpi_get_nbits(sig->rsa.s);
|
||||
|
||||
/* According to RFC 4880 sec 3.2, length of MPI is computed starting
|
||||
* from most significant bit. So the RFC 3447 sec 8.2.2 size check
|
||||
* must be relaxed to conform with shorter signatures - so we fail here
|
||||
* only if signature length is longer than modulus size.
|
||||
*/
|
||||
pr_devel("step 1: k=%zu size(S)=%zu\n", k, tsize);
|
||||
if (k < tsize) {
|
||||
ret = -EBADMSG;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Round up and convert to octets */
|
||||
k = (k + 7) / 8;
|
||||
|
||||
/* (2b) Apply the RSAVP1 verification primitive to the public key */
|
||||
ret = RSAVP1(key, sig->rsa.s, &m);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
/* (2c) Convert the message representative (m) to an encoded message
|
||||
* (EM) of length k octets.
|
||||
*
|
||||
* NOTE! The leading zero byte is suppressed by MPI, so we pass a
|
||||
* pointer to the _preceding_ byte to RSA_verify()!
|
||||
*/
|
||||
ret = RSA_I2OSP(m, k, &EM);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
ret = RSA_verify(H, EM - 1, k, sig->digest_size,
|
||||
RSA_ASN1_templates[sig->pkey_hash_algo].data,
|
||||
RSA_ASN1_templates[sig->pkey_hash_algo].size);
|
||||
|
||||
error:
|
||||
kfree(EM);
|
||||
mpi_free(m);
|
||||
kleave(" = %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
const struct public_key_algorithm RSA_public_key_algorithm = {
|
||||
.name = "RSA",
|
||||
.n_pub_mpi = 2,
|
||||
.n_sec_mpi = 3,
|
||||
.n_sig_mpi = 1,
|
||||
.verify_signature = RSA_verify_signature,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(RSA_public_key_algorithm);
|
|
@ -0,0 +1,49 @@
|
|||
/* Signature verification with an asymmetric key
|
||||
*
|
||||
* See Documentation/security/asymmetric-keys.txt
|
||||
*
|
||||
* 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 <keys/asymmetric-subtype.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/err.h>
|
||||
#include <crypto/public_key.h>
|
||||
#include "asymmetric_keys.h"
|
||||
|
||||
/**
|
||||
* verify_signature - Initiate the use of an asymmetric key to verify a signature
|
||||
* @key: The asymmetric key to verify against
|
||||
* @sig: The signature to check
|
||||
*
|
||||
* Returns 0 if successful or else an error.
|
||||
*/
|
||||
int verify_signature(const struct key *key,
|
||||
const struct public_key_signature *sig)
|
||||
{
|
||||
const struct asymmetric_key_subtype *subtype;
|
||||
int ret;
|
||||
|
||||
pr_devel("==>%s()\n", __func__);
|
||||
|
||||
if (key->type != &key_type_asymmetric)
|
||||
return -EINVAL;
|
||||
subtype = asymmetric_key_subtype(key);
|
||||
if (!subtype ||
|
||||
!key->payload.data)
|
||||
return -EINVAL;
|
||||
if (!subtype->verify_signature)
|
||||
return -ENOTSUPP;
|
||||
|
||||
ret = subtype->verify_signature(key, sig);
|
||||
|
||||
pr_devel("<==%s() = %d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(verify_signature);
|
|
@ -0,0 +1,60 @@
|
|||
Certificate ::= SEQUENCE {
|
||||
tbsCertificate TBSCertificate ({ x509_note_tbs_certificate }),
|
||||
signatureAlgorithm AlgorithmIdentifier,
|
||||
signature BIT STRING ({ x509_note_signature })
|
||||
}
|
||||
|
||||
TBSCertificate ::= SEQUENCE {
|
||||
version [ 0 ] Version DEFAULT,
|
||||
serialNumber CertificateSerialNumber,
|
||||
signature AlgorithmIdentifier ({ x509_note_pkey_algo }),
|
||||
issuer Name ({ x509_note_issuer }),
|
||||
validity Validity,
|
||||
subject Name ({ x509_note_subject }),
|
||||
subjectPublicKeyInfo SubjectPublicKeyInfo,
|
||||
issuerUniqueID [ 1 ] IMPLICIT UniqueIdentifier OPTIONAL,
|
||||
subjectUniqueID [ 2 ] IMPLICIT UniqueIdentifier OPTIONAL,
|
||||
extensions [ 3 ] Extensions OPTIONAL
|
||||
}
|
||||
|
||||
Version ::= INTEGER
|
||||
CertificateSerialNumber ::= INTEGER
|
||||
|
||||
AlgorithmIdentifier ::= SEQUENCE {
|
||||
algorithm OBJECT IDENTIFIER ({ x509_note_OID }),
|
||||
parameters ANY OPTIONAL
|
||||
}
|
||||
|
||||
Name ::= SEQUENCE OF RelativeDistinguishedName
|
||||
|
||||
RelativeDistinguishedName ::= SET OF AttributeValueAssertion
|
||||
|
||||
AttributeValueAssertion ::= SEQUENCE {
|
||||
attributeType OBJECT IDENTIFIER ({ x509_note_OID }),
|
||||
attributeValue ANY ({ x509_extract_name_segment })
|
||||
}
|
||||
|
||||
Validity ::= SEQUENCE {
|
||||
notBefore Time ({ x509_note_not_before }),
|
||||
notAfter Time ({ x509_note_not_after })
|
||||
}
|
||||
|
||||
Time ::= CHOICE {
|
||||
utcTime UTCTime,
|
||||
generalTime GeneralizedTime
|
||||
}
|
||||
|
||||
SubjectPublicKeyInfo ::= SEQUENCE {
|
||||
algorithm AlgorithmIdentifier,
|
||||
subjectPublicKey BIT STRING ({ x509_extract_key_data })
|
||||
}
|
||||
|
||||
UniqueIdentifier ::= BIT STRING
|
||||
|
||||
Extensions ::= SEQUENCE OF Extension
|
||||
|
||||
Extension ::= SEQUENCE {
|
||||
extnid OBJECT IDENTIFIER ({ x509_note_OID }),
|
||||
critical BOOLEAN DEFAULT,
|
||||
extnValue OCTET STRING ({ x509_process_extension })
|
||||
}
|
|
@ -0,0 +1,496 @@
|
|||
/* X.509 certificate 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) "X.509: "fmt
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/oid_registry.h>
|
||||
#include "public_key.h"
|
||||
#include "x509_parser.h"
|
||||
#include "x509-asn1.h"
|
||||
#include "x509_rsakey-asn1.h"
|
||||
|
||||
struct x509_parse_context {
|
||||
struct x509_certificate *cert; /* Certificate being constructed */
|
||||
unsigned long data; /* Start of data */
|
||||
const void *cert_start; /* Start of cert content */
|
||||
const void *key; /* Key data */
|
||||
size_t key_size; /* Size of key data */
|
||||
enum OID last_oid; /* Last OID encountered */
|
||||
enum OID algo_oid; /* Algorithm OID */
|
||||
unsigned char nr_mpi; /* Number of MPIs stored */
|
||||
u8 o_size; /* Size of organizationName (O) */
|
||||
u8 cn_size; /* Size of commonName (CN) */
|
||||
u8 email_size; /* Size of emailAddress */
|
||||
u16 o_offset; /* Offset of organizationName (O) */
|
||||
u16 cn_offset; /* Offset of commonName (CN) */
|
||||
u16 email_offset; /* Offset of emailAddress */
|
||||
};
|
||||
|
||||
/*
|
||||
* Free an X.509 certificate
|
||||
*/
|
||||
void x509_free_certificate(struct x509_certificate *cert)
|
||||
{
|
||||
if (cert) {
|
||||
public_key_destroy(cert->pub);
|
||||
kfree(cert->issuer);
|
||||
kfree(cert->subject);
|
||||
kfree(cert->fingerprint);
|
||||
kfree(cert->authority);
|
||||
kfree(cert);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse an X.509 certificate
|
||||
*/
|
||||
struct x509_certificate *x509_cert_parse(const void *data, size_t datalen)
|
||||
{
|
||||
struct x509_certificate *cert;
|
||||
struct x509_parse_context *ctx;
|
||||
long ret;
|
||||
|
||||
ret = -ENOMEM;
|
||||
cert = kzalloc(sizeof(struct x509_certificate), GFP_KERNEL);
|
||||
if (!cert)
|
||||
goto error_no_cert;
|
||||
cert->pub = kzalloc(sizeof(struct public_key), GFP_KERNEL);
|
||||
if (!cert->pub)
|
||||
goto error_no_ctx;
|
||||
ctx = kzalloc(sizeof(struct x509_parse_context), GFP_KERNEL);
|
||||
if (!ctx)
|
||||
goto error_no_ctx;
|
||||
|
||||
ctx->cert = cert;
|
||||
ctx->data = (unsigned long)data;
|
||||
|
||||
/* Attempt to decode the certificate */
|
||||
ret = asn1_ber_decoder(&x509_decoder, ctx, data, datalen);
|
||||
if (ret < 0)
|
||||
goto error_decode;
|
||||
|
||||
/* Decode the public key */
|
||||
ret = asn1_ber_decoder(&x509_rsakey_decoder, ctx,
|
||||
ctx->key, ctx->key_size);
|
||||
if (ret < 0)
|
||||
goto error_decode;
|
||||
|
||||
kfree(ctx);
|
||||
return cert;
|
||||
|
||||
error_decode:
|
||||
kfree(ctx);
|
||||
error_no_ctx:
|
||||
x509_free_certificate(cert);
|
||||
error_no_cert:
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* Note an OID when we find one for later processing when we know how
|
||||
* to interpret it.
|
||||
*/
|
||||
int x509_note_OID(void *context, size_t hdrlen,
|
||||
unsigned char tag,
|
||||
const void *value, size_t vlen)
|
||||
{
|
||||
struct x509_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));
|
||||
pr_debug("Unknown OID: [%lu] %s\n",
|
||||
(unsigned long)value - ctx->data, buffer);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Save the position of the TBS data so that we can check the signature over it
|
||||
* later.
|
||||
*/
|
||||
int x509_note_tbs_certificate(void *context, size_t hdrlen,
|
||||
unsigned char tag,
|
||||
const void *value, size_t vlen)
|
||||
{
|
||||
struct x509_parse_context *ctx = context;
|
||||
|
||||
pr_debug("x509_note_tbs_certificate(,%zu,%02x,%ld,%zu)!\n",
|
||||
hdrlen, tag, (unsigned long)value - ctx->data, vlen);
|
||||
|
||||
ctx->cert->tbs = value - hdrlen;
|
||||
ctx->cert->tbs_size = vlen + hdrlen;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Record the public key algorithm
|
||||
*/
|
||||
int x509_note_pkey_algo(void *context, size_t hdrlen,
|
||||
unsigned char tag,
|
||||
const void *value, size_t vlen)
|
||||
{
|
||||
struct x509_parse_context *ctx = context;
|
||||
|
||||
pr_debug("PubKey Algo: %u\n", ctx->last_oid);
|
||||
|
||||
switch (ctx->last_oid) {
|
||||
case OID_md2WithRSAEncryption:
|
||||
case OID_md3WithRSAEncryption:
|
||||
default:
|
||||
return -ENOPKG; /* Unsupported combination */
|
||||
|
||||
case OID_md4WithRSAEncryption:
|
||||
ctx->cert->sig_hash_algo = PKEY_HASH_MD5;
|
||||
ctx->cert->sig_pkey_algo = PKEY_ALGO_RSA;
|
||||
break;
|
||||
|
||||
case OID_sha1WithRSAEncryption:
|
||||
ctx->cert->sig_hash_algo = PKEY_HASH_SHA1;
|
||||
ctx->cert->sig_pkey_algo = PKEY_ALGO_RSA;
|
||||
break;
|
||||
|
||||
case OID_sha256WithRSAEncryption:
|
||||
ctx->cert->sig_hash_algo = PKEY_HASH_SHA256;
|
||||
ctx->cert->sig_pkey_algo = PKEY_ALGO_RSA;
|
||||
break;
|
||||
|
||||
case OID_sha384WithRSAEncryption:
|
||||
ctx->cert->sig_hash_algo = PKEY_HASH_SHA384;
|
||||
ctx->cert->sig_pkey_algo = PKEY_ALGO_RSA;
|
||||
break;
|
||||
|
||||
case OID_sha512WithRSAEncryption:
|
||||
ctx->cert->sig_hash_algo = PKEY_HASH_SHA512;
|
||||
ctx->cert->sig_pkey_algo = PKEY_ALGO_RSA;
|
||||
break;
|
||||
|
||||
case OID_sha224WithRSAEncryption:
|
||||
ctx->cert->sig_hash_algo = PKEY_HASH_SHA224;
|
||||
ctx->cert->sig_pkey_algo = PKEY_ALGO_RSA;
|
||||
break;
|
||||
}
|
||||
|
||||
ctx->algo_oid = ctx->last_oid;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Note the whereabouts and type of the signature.
|
||||
*/
|
||||
int x509_note_signature(void *context, size_t hdrlen,
|
||||
unsigned char tag,
|
||||
const void *value, size_t vlen)
|
||||
{
|
||||
struct x509_parse_context *ctx = context;
|
||||
|
||||
pr_debug("Signature type: %u size %zu\n", ctx->last_oid, vlen);
|
||||
|
||||
if (ctx->last_oid != ctx->algo_oid) {
|
||||
pr_warn("Got cert with pkey (%u) and sig (%u) algorithm OIDs\n",
|
||||
ctx->algo_oid, ctx->last_oid);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ctx->cert->sig = value;
|
||||
ctx->cert->sig_size = vlen;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Note some of the name segments from which we'll fabricate a name.
|
||||
*/
|
||||
int x509_extract_name_segment(void *context, size_t hdrlen,
|
||||
unsigned char tag,
|
||||
const void *value, size_t vlen)
|
||||
{
|
||||
struct x509_parse_context *ctx = context;
|
||||
|
||||
switch (ctx->last_oid) {
|
||||
case OID_commonName:
|
||||
ctx->cn_size = vlen;
|
||||
ctx->cn_offset = (unsigned long)value - ctx->data;
|
||||
break;
|
||||
case OID_organizationName:
|
||||
ctx->o_size = vlen;
|
||||
ctx->o_offset = (unsigned long)value - ctx->data;
|
||||
break;
|
||||
case OID_email_address:
|
||||
ctx->email_size = vlen;
|
||||
ctx->email_offset = (unsigned long)value - ctx->data;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fabricate and save the issuer and subject names
|
||||
*/
|
||||
static int x509_fabricate_name(struct x509_parse_context *ctx, size_t hdrlen,
|
||||
unsigned char tag,
|
||||
char **_name, size_t vlen)
|
||||
{
|
||||
const void *name, *data = (const void *)ctx->data;
|
||||
size_t namesize;
|
||||
char *buffer;
|
||||
|
||||
if (*_name)
|
||||
return -EINVAL;
|
||||
|
||||
/* Empty name string if no material */
|
||||
if (!ctx->cn_size && !ctx->o_size && !ctx->email_size) {
|
||||
buffer = kmalloc(1, GFP_KERNEL);
|
||||
if (!buffer)
|
||||
return -ENOMEM;
|
||||
buffer[0] = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (ctx->cn_size && ctx->o_size) {
|
||||
/* Consider combining O and CN, but use only the CN if it is
|
||||
* prefixed by the O, or a significant portion thereof.
|
||||
*/
|
||||
namesize = ctx->cn_size;
|
||||
name = data + ctx->cn_offset;
|
||||
if (ctx->cn_size >= ctx->o_size &&
|
||||
memcmp(data + ctx->cn_offset, data + ctx->o_offset,
|
||||
ctx->o_size) == 0)
|
||||
goto single_component;
|
||||
if (ctx->cn_size >= 7 &&
|
||||
ctx->o_size >= 7 &&
|
||||
memcmp(data + ctx->cn_offset, data + ctx->o_offset, 7) == 0)
|
||||
goto single_component;
|
||||
|
||||
buffer = kmalloc(ctx->o_size + 2 + ctx->cn_size + 1,
|
||||
GFP_KERNEL);
|
||||
if (!buffer)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(buffer,
|
||||
data + ctx->o_offset, ctx->o_size);
|
||||
buffer[ctx->o_size + 0] = ':';
|
||||
buffer[ctx->o_size + 1] = ' ';
|
||||
memcpy(buffer + ctx->o_size + 2,
|
||||
data + ctx->cn_offset, ctx->cn_size);
|
||||
buffer[ctx->o_size + 2 + ctx->cn_size] = 0;
|
||||
goto done;
|
||||
|
||||
} else if (ctx->cn_size) {
|
||||
namesize = ctx->cn_size;
|
||||
name = data + ctx->cn_offset;
|
||||
} else if (ctx->o_size) {
|
||||
namesize = ctx->o_size;
|
||||
name = data + ctx->o_offset;
|
||||
} else {
|
||||
namesize = ctx->email_size;
|
||||
name = data + ctx->email_offset;
|
||||
}
|
||||
|
||||
single_component:
|
||||
buffer = kmalloc(namesize + 1, GFP_KERNEL);
|
||||
if (!buffer)
|
||||
return -ENOMEM;
|
||||
memcpy(buffer, name, namesize);
|
||||
buffer[namesize] = 0;
|
||||
|
||||
done:
|
||||
*_name = buffer;
|
||||
ctx->cn_size = 0;
|
||||
ctx->o_size = 0;
|
||||
ctx->email_size = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int x509_note_issuer(void *context, size_t hdrlen,
|
||||
unsigned char tag,
|
||||
const void *value, size_t vlen)
|
||||
{
|
||||
struct x509_parse_context *ctx = context;
|
||||
return x509_fabricate_name(ctx, hdrlen, tag, &ctx->cert->issuer, vlen);
|
||||
}
|
||||
|
||||
int x509_note_subject(void *context, size_t hdrlen,
|
||||
unsigned char tag,
|
||||
const void *value, size_t vlen)
|
||||
{
|
||||
struct x509_parse_context *ctx = context;
|
||||
return x509_fabricate_name(ctx, hdrlen, tag, &ctx->cert->subject, vlen);
|
||||
}
|
||||
|
||||
/*
|
||||
* Extract the data for the public key algorithm
|
||||
*/
|
||||
int x509_extract_key_data(void *context, size_t hdrlen,
|
||||
unsigned char tag,
|
||||
const void *value, size_t vlen)
|
||||
{
|
||||
struct x509_parse_context *ctx = context;
|
||||
|
||||
if (ctx->last_oid != OID_rsaEncryption)
|
||||
return -ENOPKG;
|
||||
|
||||
/* There seems to be an extraneous 0 byte on the front of the data */
|
||||
ctx->cert->pkey_algo = PKEY_ALGO_RSA;
|
||||
ctx->key = value + 1;
|
||||
ctx->key_size = vlen - 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Extract a RSA public key value
|
||||
*/
|
||||
int rsa_extract_mpi(void *context, size_t hdrlen,
|
||||
unsigned char tag,
|
||||
const void *value, size_t vlen)
|
||||
{
|
||||
struct x509_parse_context *ctx = context;
|
||||
MPI mpi;
|
||||
|
||||
if (ctx->nr_mpi >= ARRAY_SIZE(ctx->cert->pub->mpi)) {
|
||||
pr_err("Too many public key MPIs in certificate\n");
|
||||
return -EBADMSG;
|
||||
}
|
||||
|
||||
mpi = mpi_read_raw_data(value, vlen);
|
||||
if (!mpi)
|
||||
return -ENOMEM;
|
||||
|
||||
ctx->cert->pub->mpi[ctx->nr_mpi++] = mpi;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Process certificate extensions that are used to qualify the certificate.
|
||||
*/
|
||||
int x509_process_extension(void *context, size_t hdrlen,
|
||||
unsigned char tag,
|
||||
const void *value, size_t vlen)
|
||||
{
|
||||
struct x509_parse_context *ctx = context;
|
||||
const unsigned char *v = value;
|
||||
char *f;
|
||||
int i;
|
||||
|
||||
pr_debug("Extension: %u\n", ctx->last_oid);
|
||||
|
||||
if (ctx->last_oid == OID_subjectKeyIdentifier) {
|
||||
/* Get hold of the key fingerprint */
|
||||
if (vlen < 3)
|
||||
return -EBADMSG;
|
||||
if (v[0] != ASN1_OTS || v[1] != vlen - 2)
|
||||
return -EBADMSG;
|
||||
v += 2;
|
||||
vlen -= 2;
|
||||
|
||||
f = kmalloc(vlen * 2 + 1, GFP_KERNEL);
|
||||
if (!f)
|
||||
return -ENOMEM;
|
||||
for (i = 0; i < vlen; i++)
|
||||
sprintf(f + i * 2, "%02x", v[i]);
|
||||
pr_debug("fingerprint %s\n", f);
|
||||
ctx->cert->fingerprint = f;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ctx->last_oid == OID_authorityKeyIdentifier) {
|
||||
/* Get hold of the CA key fingerprint */
|
||||
if (vlen < 5)
|
||||
return -EBADMSG;
|
||||
if (v[0] != (ASN1_SEQ | (ASN1_CONS << 5)) ||
|
||||
v[1] != vlen - 2 ||
|
||||
v[2] != (ASN1_CONT << 6) ||
|
||||
v[3] != vlen - 4)
|
||||
return -EBADMSG;
|
||||
v += 4;
|
||||
vlen -= 4;
|
||||
|
||||
f = kmalloc(vlen * 2 + 1, GFP_KERNEL);
|
||||
if (!f)
|
||||
return -ENOMEM;
|
||||
for (i = 0; i < vlen; i++)
|
||||
sprintf(f + i * 2, "%02x", v[i]);
|
||||
pr_debug("authority %s\n", f);
|
||||
ctx->cert->authority = f;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Record a certificate time.
|
||||
*/
|
||||
static int x509_note_time(struct tm *tm, size_t hdrlen,
|
||||
unsigned char tag,
|
||||
const unsigned char *value, size_t vlen)
|
||||
{
|
||||
const unsigned char *p = value;
|
||||
|
||||
#define dec2bin(X) ((X) - '0')
|
||||
#define DD2bin(P) ({ unsigned x = dec2bin(P[0]) * 10 + dec2bin(P[1]); P += 2; x; })
|
||||
|
||||
if (tag == ASN1_UNITIM) {
|
||||
/* UTCTime: YYMMDDHHMMSSZ */
|
||||
if (vlen != 13)
|
||||
goto unsupported_time;
|
||||
tm->tm_year = DD2bin(p);
|
||||
if (tm->tm_year >= 50)
|
||||
tm->tm_year += 1900;
|
||||
else
|
||||
tm->tm_year += 2000;
|
||||
} else if (tag == ASN1_GENTIM) {
|
||||
/* GenTime: YYYYMMDDHHMMSSZ */
|
||||
if (vlen != 15)
|
||||
goto unsupported_time;
|
||||
tm->tm_year = DD2bin(p) * 100 + DD2bin(p);
|
||||
} else {
|
||||
goto unsupported_time;
|
||||
}
|
||||
|
||||
tm->tm_year -= 1900;
|
||||
tm->tm_mon = DD2bin(p) - 1;
|
||||
tm->tm_mday = DD2bin(p);
|
||||
tm->tm_hour = DD2bin(p);
|
||||
tm->tm_min = DD2bin(p);
|
||||
tm->tm_sec = DD2bin(p);
|
||||
|
||||
if (*p != 'Z')
|
||||
goto unsupported_time;
|
||||
|
||||
return 0;
|
||||
|
||||
unsupported_time:
|
||||
pr_debug("Got unsupported time [tag %02x]: '%*.*s'\n",
|
||||
tag, (int)vlen, (int)vlen, value);
|
||||
return -EBADMSG;
|
||||
}
|
||||
|
||||
int x509_note_not_before(void *context, size_t hdrlen,
|
||||
unsigned char tag,
|
||||
const void *value, size_t vlen)
|
||||
{
|
||||
struct x509_parse_context *ctx = context;
|
||||
return x509_note_time(&ctx->cert->valid_from, hdrlen, tag, value, vlen);
|
||||
}
|
||||
|
||||
int x509_note_not_after(void *context, size_t hdrlen,
|
||||
unsigned char tag,
|
||||
const void *value, size_t vlen)
|
||||
{
|
||||
struct x509_parse_context *ctx = context;
|
||||
return x509_note_time(&ctx->cert->valid_to, hdrlen, tag, value, vlen);
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
/* X.509 certificate 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 <crypto/public_key.h>
|
||||
|
||||
struct x509_certificate {
|
||||
struct x509_certificate *next;
|
||||
struct public_key *pub; /* Public key details */
|
||||
char *issuer; /* Name of certificate issuer */
|
||||
char *subject; /* Name of certificate subject */
|
||||
char *fingerprint; /* Key fingerprint as hex */
|
||||
char *authority; /* Authority key fingerprint as hex */
|
||||
struct tm valid_from;
|
||||
struct tm valid_to;
|
||||
enum pkey_algo pkey_algo : 8; /* Public key algorithm */
|
||||
enum pkey_algo sig_pkey_algo : 8; /* Signature public key algorithm */
|
||||
enum pkey_hash_algo sig_hash_algo : 8; /* Signature hash algorithm */
|
||||
const void *tbs; /* Signed data */
|
||||
size_t tbs_size; /* Size of signed data */
|
||||
const void *sig; /* Signature data */
|
||||
size_t sig_size; /* Size of sigature */
|
||||
};
|
||||
|
||||
/*
|
||||
* x509_cert_parser.c
|
||||
*/
|
||||
extern void x509_free_certificate(struct x509_certificate *cert);
|
||||
extern struct x509_certificate *x509_cert_parse(const void *data, size_t datalen);
|
|
@ -0,0 +1,239 @@
|
|||
/* Instantiate a public key crypto key from an X.509 Certificate
|
||||
*
|
||||
* 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) "X.509: "fmt
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/mpi.h>
|
||||
#include <linux/asn1_decoder.h>
|
||||
#include <keys/asymmetric-subtype.h>
|
||||
#include <keys/asymmetric-parser.h>
|
||||
#include <crypto/hash.h>
|
||||
#include "asymmetric_keys.h"
|
||||
#include "public_key.h"
|
||||
#include "x509_parser.h"
|
||||
|
||||
static const
|
||||
struct public_key_algorithm *x509_public_key_algorithms[PKEY_ALGO__LAST] = {
|
||||
[PKEY_ALGO_DSA] = NULL,
|
||||
#if defined(CONFIG_PUBLIC_KEY_ALGO_RSA) || \
|
||||
defined(CONFIG_PUBLIC_KEY_ALGO_RSA_MODULE)
|
||||
[PKEY_ALGO_RSA] = &RSA_public_key_algorithm,
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
* Check the signature on a certificate using the provided public key
|
||||
*/
|
||||
static int x509_check_signature(const struct public_key *pub,
|
||||
const struct x509_certificate *cert)
|
||||
{
|
||||
struct public_key_signature *sig;
|
||||
struct crypto_shash *tfm;
|
||||
struct shash_desc *desc;
|
||||
size_t digest_size, desc_size;
|
||||
int ret;
|
||||
|
||||
pr_devel("==>%s()\n", __func__);
|
||||
|
||||
/* Allocate the hashing algorithm we're going to need and find out how
|
||||
* big the hash operational data will be.
|
||||
*/
|
||||
tfm = crypto_alloc_shash(pkey_hash_algo[cert->sig_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);
|
||||
digest_size = crypto_shash_digestsize(tfm);
|
||||
|
||||
/* We allocate the hash operational data storage on the end of our
|
||||
* context data.
|
||||
*/
|
||||
ret = -ENOMEM;
|
||||
sig = kzalloc(sizeof(*sig) + desc_size + digest_size, GFP_KERNEL);
|
||||
if (!sig)
|
||||
goto error_no_sig;
|
||||
|
||||
sig->pkey_hash_algo = cert->sig_hash_algo;
|
||||
sig->digest = (u8 *)sig + sizeof(*sig) + desc_size;
|
||||
sig->digest_size = digest_size;
|
||||
|
||||
desc = (void *)sig + sizeof(*sig);
|
||||
desc->tfm = tfm;
|
||||
desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
|
||||
|
||||
ret = crypto_shash_init(desc);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
ret = -ENOMEM;
|
||||
sig->rsa.s = mpi_read_raw_data(cert->sig, cert->sig_size);
|
||||
if (!sig->rsa.s)
|
||||
goto error;
|
||||
|
||||
ret = crypto_shash_finup(desc, cert->tbs, cert->tbs_size, sig->digest);
|
||||
if (ret < 0)
|
||||
goto error_mpi;
|
||||
|
||||
ret = pub->algo->verify_signature(pub, sig);
|
||||
|
||||
pr_debug("Cert Verification: %d\n", ret);
|
||||
|
||||
error_mpi:
|
||||
mpi_free(sig->rsa.s);
|
||||
error:
|
||||
kfree(sig);
|
||||
error_no_sig:
|
||||
crypto_free_shash(tfm);
|
||||
|
||||
pr_devel("<==%s() = %d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Attempt to parse a data blob for a key as an X509 certificate.
|
||||
*/
|
||||
static int x509_key_preparse(struct key_preparsed_payload *prep)
|
||||
{
|
||||
struct x509_certificate *cert;
|
||||
struct tm now;
|
||||
size_t srlen, sulen;
|
||||
char *desc = NULL;
|
||||
int ret;
|
||||
|
||||
cert = x509_cert_parse(prep->data, prep->datalen);
|
||||
if (IS_ERR(cert))
|
||||
return PTR_ERR(cert);
|
||||
|
||||
pr_devel("Cert Issuer: %s\n", cert->issuer);
|
||||
pr_devel("Cert Subject: %s\n", cert->subject);
|
||||
pr_devel("Cert Key Algo: %s\n", pkey_algo[cert->pkey_algo]);
|
||||
pr_devel("Cert Valid From: %04ld-%02d-%02d %02d:%02d:%02d\n",
|
||||
cert->valid_from.tm_year + 1900, cert->valid_from.tm_mon + 1,
|
||||
cert->valid_from.tm_mday, cert->valid_from.tm_hour,
|
||||
cert->valid_from.tm_min, cert->valid_from.tm_sec);
|
||||
pr_devel("Cert Valid To: %04ld-%02d-%02d %02d:%02d:%02d\n",
|
||||
cert->valid_to.tm_year + 1900, cert->valid_to.tm_mon + 1,
|
||||
cert->valid_to.tm_mday, cert->valid_to.tm_hour,
|
||||
cert->valid_to.tm_min, cert->valid_to.tm_sec);
|
||||
pr_devel("Cert Signature: %s + %s\n",
|
||||
pkey_algo[cert->sig_pkey_algo],
|
||||
pkey_hash_algo[cert->sig_hash_algo]);
|
||||
|
||||
if (!cert->fingerprint || !cert->authority) {
|
||||
pr_warn("Cert for '%s' must have SubjKeyId and AuthKeyId extensions\n",
|
||||
cert->subject);
|
||||
ret = -EKEYREJECTED;
|
||||
goto error_free_cert;
|
||||
}
|
||||
|
||||
time_to_tm(CURRENT_TIME.tv_sec, 0, &now);
|
||||
pr_devel("Now: %04ld-%02d-%02d %02d:%02d:%02d\n",
|
||||
now.tm_year + 1900, now.tm_mon + 1, now.tm_mday,
|
||||
now.tm_hour, now.tm_min, now.tm_sec);
|
||||
if (now.tm_year < cert->valid_from.tm_year ||
|
||||
(now.tm_year == cert->valid_from.tm_year &&
|
||||
(now.tm_mon < cert->valid_from.tm_mon ||
|
||||
(now.tm_mon == cert->valid_from.tm_mon &&
|
||||
(now.tm_mday < cert->valid_from.tm_mday ||
|
||||
(now.tm_mday == cert->valid_from.tm_mday &&
|
||||
(now.tm_hour < cert->valid_from.tm_hour ||
|
||||
(now.tm_hour == cert->valid_from.tm_hour &&
|
||||
(now.tm_min < cert->valid_from.tm_min ||
|
||||
(now.tm_min == cert->valid_from.tm_min &&
|
||||
(now.tm_sec < cert->valid_from.tm_sec
|
||||
))))))))))) {
|
||||
pr_warn("Cert %s is not yet valid\n", cert->fingerprint);
|
||||
ret = -EKEYREJECTED;
|
||||
goto error_free_cert;
|
||||
}
|
||||
if (now.tm_year > cert->valid_to.tm_year ||
|
||||
(now.tm_year == cert->valid_to.tm_year &&
|
||||
(now.tm_mon > cert->valid_to.tm_mon ||
|
||||
(now.tm_mon == cert->valid_to.tm_mon &&
|
||||
(now.tm_mday > cert->valid_to.tm_mday ||
|
||||
(now.tm_mday == cert->valid_to.tm_mday &&
|
||||
(now.tm_hour > cert->valid_to.tm_hour ||
|
||||
(now.tm_hour == cert->valid_to.tm_hour &&
|
||||
(now.tm_min > cert->valid_to.tm_min ||
|
||||
(now.tm_min == cert->valid_to.tm_min &&
|
||||
(now.tm_sec > cert->valid_to.tm_sec
|
||||
))))))))))) {
|
||||
pr_warn("Cert %s has expired\n", cert->fingerprint);
|
||||
ret = -EKEYEXPIRED;
|
||||
goto error_free_cert;
|
||||
}
|
||||
|
||||
cert->pub->algo = x509_public_key_algorithms[cert->pkey_algo];
|
||||
cert->pub->id_type = PKEY_ID_X509;
|
||||
|
||||
/* Check the signature on the key */
|
||||
if (strcmp(cert->fingerprint, cert->authority) == 0) {
|
||||
ret = x509_check_signature(cert->pub, cert);
|
||||
if (ret < 0)
|
||||
goto error_free_cert;
|
||||
}
|
||||
|
||||
/* Propose a description */
|
||||
sulen = strlen(cert->subject);
|
||||
srlen = strlen(cert->fingerprint);
|
||||
ret = -ENOMEM;
|
||||
desc = kmalloc(sulen + 2 + srlen + 1, GFP_KERNEL);
|
||||
if (!desc)
|
||||
goto error_free_cert;
|
||||
memcpy(desc, cert->subject, sulen);
|
||||
desc[sulen] = ':';
|
||||
desc[sulen + 1] = ' ';
|
||||
memcpy(desc + sulen + 2, cert->fingerprint, srlen);
|
||||
desc[sulen + 2 + srlen] = 0;
|
||||
|
||||
/* We're pinning the module by being linked against it */
|
||||
__module_get(public_key_subtype.owner);
|
||||
prep->type_data[0] = &public_key_subtype;
|
||||
prep->type_data[1] = cert->fingerprint;
|
||||
prep->payload = cert->pub;
|
||||
prep->description = desc;
|
||||
prep->quotalen = 100;
|
||||
|
||||
/* We've finished with the certificate */
|
||||
cert->pub = NULL;
|
||||
cert->fingerprint = NULL;
|
||||
desc = NULL;
|
||||
ret = 0;
|
||||
|
||||
error_free_cert:
|
||||
x509_free_certificate(cert);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct asymmetric_key_parser x509_key_parser = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "x509",
|
||||
.parse = x509_key_preparse,
|
||||
};
|
||||
|
||||
/*
|
||||
* Module stuff
|
||||
*/
|
||||
static int __init x509_key_init(void)
|
||||
{
|
||||
return register_asymmetric_key_parser(&x509_key_parser);
|
||||
}
|
||||
|
||||
static void __exit x509_key_exit(void)
|
||||
{
|
||||
unregister_asymmetric_key_parser(&x509_key_parser);
|
||||
}
|
||||
|
||||
module_init(x509_key_init);
|
||||
module_exit(x509_key_exit);
|
|
@ -0,0 +1,4 @@
|
|||
RSAPublicKey ::= SEQUENCE {
|
||||
modulus INTEGER ({ rsa_extract_mpi }), -- n
|
||||
publicExponent INTEGER ({ rsa_extract_mpi }) -- e
|
||||
}
|
|
@ -31,18 +31,18 @@
|
|||
|
||||
/* create a new cifs key */
|
||||
static int
|
||||
cifs_spnego_key_instantiate(struct key *key, const void *data, size_t datalen)
|
||||
cifs_spnego_key_instantiate(struct key *key, struct key_preparsed_payload *prep)
|
||||
{
|
||||
char *payload;
|
||||
int ret;
|
||||
|
||||
ret = -ENOMEM;
|
||||
payload = kmalloc(datalen, GFP_KERNEL);
|
||||
payload = kmalloc(prep->datalen, GFP_KERNEL);
|
||||
if (!payload)
|
||||
goto error;
|
||||
|
||||
/* attach the data */
|
||||
memcpy(payload, data, datalen);
|
||||
memcpy(payload, prep->data, prep->datalen);
|
||||
key->payload.data = payload;
|
||||
ret = 0;
|
||||
|
||||
|
|
|
@ -167,17 +167,17 @@ static struct shrinker cifs_shrinker = {
|
|||
};
|
||||
|
||||
static int
|
||||
cifs_idmap_key_instantiate(struct key *key, const void *data, size_t datalen)
|
||||
cifs_idmap_key_instantiate(struct key *key, struct key_preparsed_payload *prep)
|
||||
{
|
||||
char *payload;
|
||||
|
||||
payload = kmalloc(datalen, GFP_KERNEL);
|
||||
payload = kmalloc(prep->datalen, GFP_KERNEL);
|
||||
if (!payload)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(payload, data, datalen);
|
||||
memcpy(payload, prep->data, prep->datalen);
|
||||
key->payload.data = payload;
|
||||
key->datalen = datalen;
|
||||
key->datalen = prep->datalen;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
/* Count leading and trailing zeros functions
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _ASM_GENERIC_BITOPS_COUNT_ZEROS_H_
|
||||
#define _ASM_GENERIC_BITOPS_COUNT_ZEROS_H_
|
||||
|
||||
#include <asm/bitops.h>
|
||||
|
||||
/**
|
||||
* count_leading_zeros - Count the number of zeros from the MSB back
|
||||
* @x: The value
|
||||
*
|
||||
* Count the number of leading zeros from the MSB going towards the LSB in @x.
|
||||
*
|
||||
* If the MSB of @x is set, the result is 0.
|
||||
* If only the LSB of @x is set, then the result is BITS_PER_LONG-1.
|
||||
* If @x is 0 then the result is COUNT_LEADING_ZEROS_0.
|
||||
*/
|
||||
static inline int count_leading_zeros(unsigned long x)
|
||||
{
|
||||
if (sizeof(x) == 4)
|
||||
return BITS_PER_LONG - fls(x);
|
||||
else
|
||||
return BITS_PER_LONG - fls64(x);
|
||||
}
|
||||
|
||||
#define COUNT_LEADING_ZEROS_0 BITS_PER_LONG
|
||||
|
||||
/**
|
||||
* count_trailing_zeros - Count the number of zeros from the LSB forwards
|
||||
* @x: The value
|
||||
*
|
||||
* Count the number of trailing zeros from the LSB going towards the MSB in @x.
|
||||
*
|
||||
* If the LSB of @x is set, the result is 0.
|
||||
* If only the MSB of @x is set, then the result is BITS_PER_LONG-1.
|
||||
* If @x is 0 then the result is COUNT_TRAILING_ZEROS_0.
|
||||
*/
|
||||
static inline int count_trailing_zeros(unsigned long x)
|
||||
{
|
||||
#define COUNT_TRAILING_ZEROS_0 (-1)
|
||||
|
||||
if (sizeof(x) == 4)
|
||||
return ffs(x);
|
||||
else
|
||||
return (x != 0) ? __ffs(x) : COUNT_TRAILING_ZEROS_0;
|
||||
}
|
||||
|
||||
#endif /* _ASM_GENERIC_BITOPS_COUNT_ZEROS_H_ */
|
|
@ -5,18 +5,44 @@
|
|||
* Many architectures just need a simple module
|
||||
* loader without arch specific data.
|
||||
*/
|
||||
#ifndef CONFIG_HAVE_MOD_ARCH_SPECIFIC
|
||||
struct mod_arch_specific
|
||||
{
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_64BIT
|
||||
#define Elf_Shdr Elf64_Shdr
|
||||
#define Elf_Sym Elf64_Sym
|
||||
#define Elf_Ehdr Elf64_Ehdr
|
||||
#else
|
||||
#define Elf_Shdr Elf32_Shdr
|
||||
#define Elf_Sym Elf32_Sym
|
||||
#define Elf_Ehdr Elf32_Ehdr
|
||||
#define Elf_Shdr Elf64_Shdr
|
||||
#define Elf_Phdr Elf64_Phdr
|
||||
#define Elf_Sym Elf64_Sym
|
||||
#define Elf_Dyn Elf64_Dyn
|
||||
#define Elf_Ehdr Elf64_Ehdr
|
||||
#define Elf_Addr Elf64_Addr
|
||||
#ifdef CONFIG_MODULES_USE_ELF_REL
|
||||
#define Elf_Rel Elf64_Rel
|
||||
#endif
|
||||
#ifdef CONFIG_MODULES_USE_ELF_RELA
|
||||
#define Elf_Rela Elf64_Rela
|
||||
#endif
|
||||
#define ELF_R_TYPE(X) ELF64_R_TYPE(X)
|
||||
#define ELF_R_SYM(X) ELF64_R_SYM(X)
|
||||
|
||||
#else /* CONFIG_64BIT */
|
||||
|
||||
#define Elf_Shdr Elf32_Shdr
|
||||
#define Elf_Phdr Elf32_Phdr
|
||||
#define Elf_Sym Elf32_Sym
|
||||
#define Elf_Dyn Elf32_Dyn
|
||||
#define Elf_Ehdr Elf32_Ehdr
|
||||
#define Elf_Addr Elf32_Addr
|
||||
#ifdef CONFIG_MODULES_USE_ELF_REL
|
||||
#define Elf_Rel Elf32_Rel
|
||||
#endif
|
||||
#ifdef CONFIG_MODULES_USE_ELF_RELA
|
||||
#define Elf_Rela Elf32_Rela
|
||||
#endif
|
||||
#define ELF_R_TYPE(X) ELF32_R_TYPE(X)
|
||||
#define ELF_R_SYM(X) ELF32_R_SYM(X)
|
||||
#endif
|
||||
|
||||
#endif /* __ASM_GENERIC_MODULE_H */
|
||||
|
|
|
@ -0,0 +1,108 @@
|
|||
/* Asymmetric public-key algorithm definitions
|
||||
*
|
||||
* See Documentation/crypto/asymmetric-keys.txt
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_PUBLIC_KEY_H
|
||||
#define _LINUX_PUBLIC_KEY_H
|
||||
|
||||
#include <linux/mpi.h>
|
||||
|
||||
enum pkey_algo {
|
||||
PKEY_ALGO_DSA,
|
||||
PKEY_ALGO_RSA,
|
||||
PKEY_ALGO__LAST
|
||||
};
|
||||
|
||||
extern const char *const pkey_algo[PKEY_ALGO__LAST];
|
||||
|
||||
enum pkey_hash_algo {
|
||||
PKEY_HASH_MD4,
|
||||
PKEY_HASH_MD5,
|
||||
PKEY_HASH_SHA1,
|
||||
PKEY_HASH_RIPE_MD_160,
|
||||
PKEY_HASH_SHA256,
|
||||
PKEY_HASH_SHA384,
|
||||
PKEY_HASH_SHA512,
|
||||
PKEY_HASH_SHA224,
|
||||
PKEY_HASH__LAST
|
||||
};
|
||||
|
||||
extern const char *const pkey_hash_algo[PKEY_HASH__LAST];
|
||||
|
||||
enum pkey_id_type {
|
||||
PKEY_ID_PGP, /* OpenPGP generated key ID */
|
||||
PKEY_ID_X509, /* X.509 arbitrary subjectKeyIdentifier */
|
||||
PKEY_ID_TYPE__LAST
|
||||
};
|
||||
|
||||
extern const char *const pkey_id_type[PKEY_ID_TYPE__LAST];
|
||||
|
||||
/*
|
||||
* Cryptographic data for the public-key subtype of the asymmetric key type.
|
||||
*
|
||||
* Note that this may include private part of the key as well as the public
|
||||
* part.
|
||||
*/
|
||||
struct public_key {
|
||||
const struct public_key_algorithm *algo;
|
||||
u8 capabilities;
|
||||
#define PKEY_CAN_ENCRYPT 0x01
|
||||
#define PKEY_CAN_DECRYPT 0x02
|
||||
#define PKEY_CAN_SIGN 0x04
|
||||
#define PKEY_CAN_VERIFY 0x08
|
||||
enum pkey_id_type id_type : 8;
|
||||
union {
|
||||
MPI mpi[5];
|
||||
struct {
|
||||
MPI p; /* DSA prime */
|
||||
MPI q; /* DSA group order */
|
||||
MPI g; /* DSA group generator */
|
||||
MPI y; /* DSA public-key value = g^x mod p */
|
||||
MPI x; /* DSA secret exponent (if present) */
|
||||
} dsa;
|
||||
struct {
|
||||
MPI n; /* RSA public modulus */
|
||||
MPI e; /* RSA public encryption exponent */
|
||||
MPI d; /* RSA secret encryption exponent (if present) */
|
||||
MPI p; /* RSA secret prime (if present) */
|
||||
MPI q; /* RSA secret prime (if present) */
|
||||
} rsa;
|
||||
};
|
||||
};
|
||||
|
||||
extern void public_key_destroy(void *payload);
|
||||
|
||||
/*
|
||||
* Public key cryptography signature data
|
||||
*/
|
||||
struct public_key_signature {
|
||||
u8 *digest;
|
||||
u8 digest_size; /* Number of bytes in digest */
|
||||
u8 nr_mpi; /* Occupancy of mpi[] */
|
||||
enum pkey_hash_algo pkey_hash_algo : 8;
|
||||
union {
|
||||
MPI mpi[2];
|
||||
struct {
|
||||
MPI s; /* m^d mod n */
|
||||
} rsa;
|
||||
struct {
|
||||
MPI r;
|
||||
MPI s;
|
||||
} dsa;
|
||||
};
|
||||
};
|
||||
|
||||
struct key;
|
||||
extern int verify_signature(const struct key *key,
|
||||
const struct public_key_signature *sig);
|
||||
|
||||
#endif /* _LINUX_PUBLIC_KEY_H */
|
|
@ -0,0 +1,37 @@
|
|||
/* Asymmetric public-key cryptography data parser
|
||||
*
|
||||
* See Documentation/crypto/asymmetric-keys.txt
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _KEYS_ASYMMETRIC_PARSER_H
|
||||
#define _KEYS_ASYMMETRIC_PARSER_H
|
||||
|
||||
/*
|
||||
* Key data parser. Called during key instantiation.
|
||||
*/
|
||||
struct asymmetric_key_parser {
|
||||
struct list_head link;
|
||||
struct module *owner;
|
||||
const char *name;
|
||||
|
||||
/* Attempt to parse a key from the data blob passed to add_key() or
|
||||
* keyctl_instantiate(). Should also generate a proposed description
|
||||
* that the caller can optionally use for the key.
|
||||
*
|
||||
* Return EBADMSG if not recognised.
|
||||
*/
|
||||
int (*parse)(struct key_preparsed_payload *prep);
|
||||
};
|
||||
|
||||
extern int register_asymmetric_key_parser(struct asymmetric_key_parser *);
|
||||
extern void unregister_asymmetric_key_parser(struct asymmetric_key_parser *);
|
||||
|
||||
#endif /* _KEYS_ASYMMETRIC_PARSER_H */
|
|
@ -0,0 +1,55 @@
|
|||
/* Asymmetric public-key cryptography key subtype
|
||||
*
|
||||
* See Documentation/security/asymmetric-keys.txt
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _KEYS_ASYMMETRIC_SUBTYPE_H
|
||||
#define _KEYS_ASYMMETRIC_SUBTYPE_H
|
||||
|
||||
#include <linux/seq_file.h>
|
||||
#include <keys/asymmetric-type.h>
|
||||
|
||||
struct public_key_signature;
|
||||
|
||||
/*
|
||||
* Keys of this type declare a subtype that indicates the handlers and
|
||||
* capabilities.
|
||||
*/
|
||||
struct asymmetric_key_subtype {
|
||||
struct module *owner;
|
||||
const char *name;
|
||||
unsigned short name_len; /* length of name */
|
||||
|
||||
/* Describe a key of this subtype for /proc/keys */
|
||||
void (*describe)(const struct key *key, struct seq_file *m);
|
||||
|
||||
/* Destroy a key of this subtype */
|
||||
void (*destroy)(void *payload);
|
||||
|
||||
/* Verify the signature on a key of this subtype (optional) */
|
||||
int (*verify_signature)(const struct key *key,
|
||||
const struct public_key_signature *sig);
|
||||
};
|
||||
|
||||
/**
|
||||
* asymmetric_key_subtype - Get the subtype from an asymmetric key
|
||||
* @key: The key of interest.
|
||||
*
|
||||
* Retrieves and returns the subtype pointer of the asymmetric key from the
|
||||
* type-specific data attached to the key.
|
||||
*/
|
||||
static inline
|
||||
struct asymmetric_key_subtype *asymmetric_key_subtype(const struct key *key)
|
||||
{
|
||||
return key->type_data.p[0];
|
||||
}
|
||||
|
||||
#endif /* _KEYS_ASYMMETRIC_SUBTYPE_H */
|
|
@ -0,0 +1,25 @@
|
|||
/* Asymmetric Public-key cryptography key type interface
|
||||
*
|
||||
* See Documentation/security/asymmetric-keys.txt
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _KEYS_ASYMMETRIC_TYPE_H
|
||||
#define _KEYS_ASYMMETRIC_TYPE_H
|
||||
|
||||
#include <linux/key-type.h>
|
||||
|
||||
extern struct key_type key_type_asymmetric;
|
||||
|
||||
/*
|
||||
* The payload is at the discretion of the subtype.
|
||||
*/
|
||||
|
||||
#endif /* _KEYS_ASYMMETRIC_TYPE_H */
|
|
@ -35,8 +35,10 @@ struct user_key_payload {
|
|||
extern struct key_type key_type_user;
|
||||
extern struct key_type key_type_logon;
|
||||
|
||||
extern int user_instantiate(struct key *key, const void *data, size_t datalen);
|
||||
extern int user_update(struct key *key, const void *data, size_t datalen);
|
||||
struct key_preparsed_payload;
|
||||
|
||||
extern int user_instantiate(struct key *key, 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);
|
||||
extern void user_destroy(struct key *key);
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
/* ASN.1 BER/DER/CER encoding 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.
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_ASN1_H
|
||||
#define _LINUX_ASN1_H
|
||||
|
||||
/* Class */
|
||||
enum asn1_class {
|
||||
ASN1_UNIV = 0, /* Universal */
|
||||
ASN1_APPL = 1, /* Application */
|
||||
ASN1_CONT = 2, /* Context */
|
||||
ASN1_PRIV = 3 /* Private */
|
||||
};
|
||||
#define ASN1_CLASS_BITS 0xc0
|
||||
|
||||
|
||||
enum asn1_method {
|
||||
ASN1_PRIM = 0, /* Primitive */
|
||||
ASN1_CONS = 1 /* Constructed */
|
||||
};
|
||||
#define ASN1_CONS_BIT 0x20
|
||||
|
||||
/* Tag */
|
||||
enum asn1_tag {
|
||||
ASN1_EOC = 0, /* End Of Contents or N/A */
|
||||
ASN1_BOOL = 1, /* Boolean */
|
||||
ASN1_INT = 2, /* Integer */
|
||||
ASN1_BTS = 3, /* Bit String */
|
||||
ASN1_OTS = 4, /* Octet String */
|
||||
ASN1_NULL = 5, /* Null */
|
||||
ASN1_OID = 6, /* Object Identifier */
|
||||
ASN1_ODE = 7, /* Object Description */
|
||||
ASN1_EXT = 8, /* External */
|
||||
ASN1_REAL = 9, /* Real float */
|
||||
ASN1_ENUM = 10, /* Enumerated */
|
||||
ASN1_EPDV = 11, /* Embedded PDV */
|
||||
ASN1_UTF8STR = 12, /* UTF8 String */
|
||||
ASN1_RELOID = 13, /* Relative OID */
|
||||
/* 14 - Reserved */
|
||||
/* 15 - Reserved */
|
||||
ASN1_SEQ = 16, /* Sequence and Sequence of */
|
||||
ASN1_SET = 17, /* Set and Set of */
|
||||
ASN1_NUMSTR = 18, /* Numerical String */
|
||||
ASN1_PRNSTR = 19, /* Printable String */
|
||||
ASN1_TEXSTR = 20, /* T61 String / Teletext String */
|
||||
ASN1_VIDSTR = 21, /* Videotex String */
|
||||
ASN1_IA5STR = 22, /* IA5 String */
|
||||
ASN1_UNITIM = 23, /* Universal Time */
|
||||
ASN1_GENTIM = 24, /* General Time */
|
||||
ASN1_GRASTR = 25, /* Graphic String */
|
||||
ASN1_VISSTR = 26, /* Visible String */
|
||||
ASN1_GENSTR = 27, /* General String */
|
||||
ASN1_UNISTR = 28, /* Universal String */
|
||||
ASN1_CHRSTR = 29, /* Character String */
|
||||
ASN1_BMPSTR = 30, /* BMP String */
|
||||
ASN1_LONG_TAG = 31 /* Long form tag */
|
||||
};
|
||||
|
||||
#endif /* _LINUX_ASN1_H */
|
|
@ -0,0 +1,87 @@
|
|||
/* ASN.1 BER/DER/CER parsing state machine 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.
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_ASN1_BER_BYTECODE_H
|
||||
#define _LINUX_ASN1_BER_BYTECODE_H
|
||||
|
||||
#ifdef __KERNEL__
|
||||
#include <linux/types.h>
|
||||
#endif
|
||||
#include <linux/asn1.h>
|
||||
|
||||
typedef int (*asn1_action_t)(void *context,
|
||||
size_t hdrlen, /* In case of ANY type */
|
||||
unsigned char tag, /* In case of ANY type */
|
||||
const void *value, size_t vlen);
|
||||
|
||||
struct asn1_decoder {
|
||||
const unsigned char *machine;
|
||||
size_t machlen;
|
||||
const asn1_action_t *actions;
|
||||
};
|
||||
|
||||
enum asn1_opcode {
|
||||
/* The tag-matching ops come first and the odd-numbered slots
|
||||
* are for OR_SKIP ops.
|
||||
*/
|
||||
#define ASN1_OP_MATCH__SKIP 0x01
|
||||
#define ASN1_OP_MATCH__ACT 0x02
|
||||
#define ASN1_OP_MATCH__JUMP 0x04
|
||||
#define ASN1_OP_MATCH__ANY 0x08
|
||||
#define ASN1_OP_MATCH__COND 0x10
|
||||
|
||||
ASN1_OP_MATCH = 0x00,
|
||||
ASN1_OP_MATCH_OR_SKIP = 0x01,
|
||||
ASN1_OP_MATCH_ACT = 0x02,
|
||||
ASN1_OP_MATCH_ACT_OR_SKIP = 0x03,
|
||||
ASN1_OP_MATCH_JUMP = 0x04,
|
||||
ASN1_OP_MATCH_JUMP_OR_SKIP = 0x05,
|
||||
ASN1_OP_MATCH_ANY = 0x08,
|
||||
ASN1_OP_MATCH_ANY_ACT = 0x0a,
|
||||
/* Everything before here matches unconditionally */
|
||||
|
||||
ASN1_OP_COND_MATCH_OR_SKIP = 0x11,
|
||||
ASN1_OP_COND_MATCH_ACT_OR_SKIP = 0x13,
|
||||
ASN1_OP_COND_MATCH_JUMP_OR_SKIP = 0x15,
|
||||
ASN1_OP_COND_MATCH_ANY = 0x18,
|
||||
ASN1_OP_COND_MATCH_ANY_ACT = 0x1a,
|
||||
|
||||
/* Everything before here will want a tag from the data */
|
||||
#define ASN1_OP__MATCHES_TAG ASN1_OP_COND_MATCH_ANY_ACT
|
||||
|
||||
/* These are here to help fill up space */
|
||||
ASN1_OP_COND_FAIL = 0x1b,
|
||||
ASN1_OP_COMPLETE = 0x1c,
|
||||
ASN1_OP_ACT = 0x1d,
|
||||
ASN1_OP_RETURN = 0x1e,
|
||||
|
||||
/* The following eight have bit 0 -> SET, 1 -> OF, 2 -> ACT */
|
||||
ASN1_OP_END_SEQ = 0x20,
|
||||
ASN1_OP_END_SET = 0x21,
|
||||
ASN1_OP_END_SEQ_OF = 0x22,
|
||||
ASN1_OP_END_SET_OF = 0x23,
|
||||
ASN1_OP_END_SEQ_ACT = 0x24,
|
||||
ASN1_OP_END_SET_ACT = 0x25,
|
||||
ASN1_OP_END_SEQ_OF_ACT = 0x26,
|
||||
ASN1_OP_END_SET_OF_ACT = 0x27,
|
||||
#define ASN1_OP_END__SET 0x01
|
||||
#define ASN1_OP_END__OF 0x02
|
||||
#define ASN1_OP_END__ACT 0x04
|
||||
|
||||
ASN1_OP__NR
|
||||
};
|
||||
|
||||
#define _tag(CLASS, CP, TAG) ((ASN1_##CLASS << 6) | (ASN1_##CP << 5) | ASN1_##TAG)
|
||||
#define _tagn(CLASS, CP, TAG) ((ASN1_##CLASS << 6) | (ASN1_##CP << 5) | TAG)
|
||||
#define _jump_target(N) (N)
|
||||
#define _action(N) (N)
|
||||
|
||||
#endif /* _LINUX_ASN1_BER_BYTECODE_H */
|
|
@ -0,0 +1,24 @@
|
|||
/* ASN.1 decoder
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_ASN1_DECODER_H
|
||||
#define _LINUX_ASN1_DECODER_H
|
||||
|
||||
#include <linux/asn1.h>
|
||||
|
||||
struct asn1_decoder;
|
||||
|
||||
extern int asn1_ber_decoder(const struct asn1_decoder *decoder,
|
||||
void *context,
|
||||
const unsigned char *data,
|
||||
size_t datalen);
|
||||
|
||||
#endif /* _LINUX_ASN1_DECODER_H */
|
|
@ -26,6 +26,27 @@ struct key_construction {
|
|||
struct key *authkey;/* authorisation for key being constructed */
|
||||
};
|
||||
|
||||
/*
|
||||
* Pre-parsed payload, used by key add, update and instantiate.
|
||||
*
|
||||
* This struct will be cleared and data and datalen will be set with the data
|
||||
* and length parameters from the caller and quotalen will be set from
|
||||
* def_datalen from the key type. Then if the preparse() op is provided by the
|
||||
* key type, that will be called. Then the struct will be passed to the
|
||||
* instantiate() or the update() op.
|
||||
*
|
||||
* If the preparse() op is given, the free_preparse() op will be called to
|
||||
* clear the contents.
|
||||
*/
|
||||
struct key_preparsed_payload {
|
||||
char *description; /* Proposed key description (or NULL) */
|
||||
void *type_data[2]; /* Private key-type data */
|
||||
void *payload; /* Proposed payload */
|
||||
const void *data; /* Raw data */
|
||||
size_t datalen; /* Raw datalen */
|
||||
size_t quotalen; /* Quota length for proposed payload */
|
||||
};
|
||||
|
||||
typedef int (*request_key_actor_t)(struct key_construction *key,
|
||||
const char *op, void *aux);
|
||||
|
||||
|
@ -45,18 +66,28 @@ struct key_type {
|
|||
/* vet a description */
|
||||
int (*vet_description)(const char *description);
|
||||
|
||||
/* Preparse the data blob from userspace that is to be the payload,
|
||||
* generating a proposed description and payload that will be handed to
|
||||
* the instantiate() and update() ops.
|
||||
*/
|
||||
int (*preparse)(struct key_preparsed_payload *prep);
|
||||
|
||||
/* Free a preparse data structure.
|
||||
*/
|
||||
void (*free_preparse)(struct key_preparsed_payload *prep);
|
||||
|
||||
/* instantiate a key of this type
|
||||
* - this method should call key_payload_reserve() to determine if the
|
||||
* user's quota will hold the payload
|
||||
*/
|
||||
int (*instantiate)(struct key *key, const void *data, size_t datalen);
|
||||
int (*instantiate)(struct key *key, struct key_preparsed_payload *prep);
|
||||
|
||||
/* update a key of this type (optional)
|
||||
* - this method should call key_payload_reserve() to recalculate the
|
||||
* quota consumption
|
||||
* - the key must be locked against read when modifying
|
||||
*/
|
||||
int (*update)(struct key *key, const void *data, size_t datalen);
|
||||
int (*update)(struct key *key, struct key_preparsed_payload *prep);
|
||||
|
||||
/* match a key against a description */
|
||||
int (*match)(const struct key *key, const void *desc);
|
||||
|
|
|
@ -21,6 +21,9 @@
|
|||
#include <linux/percpu.h>
|
||||
#include <asm/module.h>
|
||||
|
||||
/* In stripped ARM and x86-64 modules, ~ is surprisingly rare. */
|
||||
#define MODULE_SIG_STRING "~Module signature appended~\n"
|
||||
|
||||
/* Not Yet Implemented */
|
||||
#define MODULE_SUPPORTED_DEVICE(name)
|
||||
|
||||
|
@ -260,6 +263,11 @@ struct module
|
|||
const unsigned long *unused_gpl_crcs;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MODULE_SIG
|
||||
/* Signature was verified. */
|
||||
bool sig_ok;
|
||||
#endif
|
||||
|
||||
/* symbols that will be GPL-only in the near future. */
|
||||
const struct kernel_symbol *gpl_future_syms;
|
||||
const unsigned long *gpl_future_crcs;
|
||||
|
|
|
@ -28,21 +28,49 @@ void *module_alloc(unsigned long size);
|
|||
/* Free memory returned from module_alloc. */
|
||||
void module_free(struct module *mod, void *module_region);
|
||||
|
||||
/* Apply the given relocation to the (simplified) ELF. Return -error
|
||||
or 0. */
|
||||
/*
|
||||
* Apply the given relocation to the (simplified) ELF. Return -error
|
||||
* or 0.
|
||||
*/
|
||||
#ifdef CONFIG_MODULES_USE_ELF_REL
|
||||
int apply_relocate(Elf_Shdr *sechdrs,
|
||||
const char *strtab,
|
||||
unsigned int symindex,
|
||||
unsigned int relsec,
|
||||
struct module *mod);
|
||||
#else
|
||||
static inline int apply_relocate(Elf_Shdr *sechdrs,
|
||||
const char *strtab,
|
||||
unsigned int symindex,
|
||||
unsigned int relsec,
|
||||
struct module *me)
|
||||
{
|
||||
printk(KERN_ERR "module %s: REL relocation unsupported\n", me->name);
|
||||
return -ENOEXEC;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Apply the given add relocation to the (simplified) ELF. Return
|
||||
-error or 0 */
|
||||
/*
|
||||
* Apply the given add relocation to the (simplified) ELF. Return
|
||||
* -error or 0
|
||||
*/
|
||||
#ifdef CONFIG_MODULES_USE_ELF_RELA
|
||||
int apply_relocate_add(Elf_Shdr *sechdrs,
|
||||
const char *strtab,
|
||||
unsigned int symindex,
|
||||
unsigned int relsec,
|
||||
struct module *mod);
|
||||
#else
|
||||
static inline int apply_relocate_add(Elf_Shdr *sechdrs,
|
||||
const char *strtab,
|
||||
unsigned int symindex,
|
||||
unsigned int relsec,
|
||||
struct module *me)
|
||||
{
|
||||
printk(KERN_ERR "module %s: REL relocation unsupported\n", me->name);
|
||||
return -ENOEXEC;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Any final processing of module before access. Return -error or 0. */
|
||||
int module_finalize(const Elf_Ehdr *hdr,
|
||||
|
|
|
@ -76,6 +76,7 @@ void mpi_swap(MPI a, MPI b);
|
|||
|
||||
/*-- mpicoder.c --*/
|
||||
MPI do_encode_md(const void *sha_buffer, unsigned nbits);
|
||||
MPI mpi_read_raw_data(const void *xbuffer, size_t nbytes);
|
||||
MPI mpi_read_from_buffer(const void *buffer, unsigned *ret_nread);
|
||||
int mpi_fromstr(MPI val, const char *str);
|
||||
u32 mpi_get_keyid(MPI a, u32 *keyid);
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
/* ASN.1 Object identifier (OID) registry
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_OID_REGISTRY_H
|
||||
#define _LINUX_OID_REGISTRY_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
/*
|
||||
* OIDs are turned into these values if possible, or OID__NR if not held here.
|
||||
*
|
||||
* NOTE! Do not mess with the format of each line as this is read by
|
||||
* build_OID_registry.pl to generate the data for look_up_OID().
|
||||
*/
|
||||
enum OID {
|
||||
OID_id_dsa_with_sha1, /* 1.2.840.10030.4.3 */
|
||||
OID_id_dsa, /* 1.2.840.10040.4.1 */
|
||||
OID_id_ecdsa_with_sha1, /* 1.2.840.10045.4.1 */
|
||||
OID_id_ecPublicKey, /* 1.2.840.10045.2.1 */
|
||||
|
||||
/* PKCS#1 {iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs-1(1)} */
|
||||
OID_rsaEncryption, /* 1.2.840.113549.1.1.1 */
|
||||
OID_md2WithRSAEncryption, /* 1.2.840.113549.1.1.2 */
|
||||
OID_md3WithRSAEncryption, /* 1.2.840.113549.1.1.3 */
|
||||
OID_md4WithRSAEncryption, /* 1.2.840.113549.1.1.4 */
|
||||
OID_sha1WithRSAEncryption, /* 1.2.840.113549.1.1.5 */
|
||||
OID_sha256WithRSAEncryption, /* 1.2.840.113549.1.1.11 */
|
||||
OID_sha384WithRSAEncryption, /* 1.2.840.113549.1.1.12 */
|
||||
OID_sha512WithRSAEncryption, /* 1.2.840.113549.1.1.13 */
|
||||
OID_sha224WithRSAEncryption, /* 1.2.840.113549.1.1.14 */
|
||||
/* PKCS#7 {iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs-7(7)} */
|
||||
OID_data, /* 1.2.840.113549.1.7.1 */
|
||||
OID_signed_data, /* 1.2.840.113549.1.7.2 */
|
||||
/* PKCS#9 {iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs-9(9)} */
|
||||
OID_email_address, /* 1.2.840.113549.1.9.1 */
|
||||
OID_content_type, /* 1.2.840.113549.1.9.3 */
|
||||
OID_messageDigest, /* 1.2.840.113549.1.9.4 */
|
||||
OID_signingTime, /* 1.2.840.113549.1.9.5 */
|
||||
OID_smimeCapabilites, /* 1.2.840.113549.1.9.15 */
|
||||
OID_smimeAuthenticatedAttrs, /* 1.2.840.113549.1.9.16.2.11 */
|
||||
|
||||
/* {iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2)} */
|
||||
OID_md2, /* 1.2.840.113549.2.2 */
|
||||
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 */
|
||||
OID_msOutlookExpress, /* 1.3.6.1.4.1.311.16.4 */
|
||||
OID_sha1, /* 1.3.14.3.2.26 */
|
||||
|
||||
/* Distinguished Name attribute IDs [RFC 2256] */
|
||||
OID_commonName, /* 2.5.4.3 */
|
||||
OID_surname, /* 2.5.4.4 */
|
||||
OID_countryName, /* 2.5.4.6 */
|
||||
OID_locality, /* 2.5.4.7 */
|
||||
OID_stateOrProvinceName, /* 2.5.4.8 */
|
||||
OID_organizationName, /* 2.5.4.10 */
|
||||
OID_organizationUnitName, /* 2.5.4.11 */
|
||||
OID_title, /* 2.5.4.12 */
|
||||
OID_description, /* 2.5.4.13 */
|
||||
OID_name, /* 2.5.4.41 */
|
||||
OID_givenName, /* 2.5.4.42 */
|
||||
OID_initials, /* 2.5.4.43 */
|
||||
OID_generationalQualifier, /* 2.5.4.44 */
|
||||
|
||||
/* Certificate extension IDs */
|
||||
OID_subjectKeyIdentifier, /* 2.5.29.14 */
|
||||
OID_keyUsage, /* 2.5.29.15 */
|
||||
OID_subjectAltName, /* 2.5.29.17 */
|
||||
OID_issuerAltName, /* 2.5.29.18 */
|
||||
OID_basicConstraints, /* 2.5.29.19 */
|
||||
OID_crlDistributionPoints, /* 2.5.29.31 */
|
||||
OID_certPolicies, /* 2.5.29.32 */
|
||||
OID_authorityKeyIdentifier, /* 2.5.29.35 */
|
||||
OID_extKeyUsage, /* 2.5.29.37 */
|
||||
|
||||
OID__NR
|
||||
};
|
||||
|
||||
extern enum OID look_up_OID(const void *data, size_t datasize);
|
||||
extern int sprint_oid(const void *, size_t, char *, size_t);
|
||||
extern int sprint_OID(enum OID, char *, size_t);
|
||||
|
||||
#endif /* _LINUX_OID_REGISTRY_H */
|
68
init/Kconfig
68
init/Kconfig
|
@ -1574,6 +1574,66 @@ config MODULE_SRCVERSION_ALL
|
|||
the version). With this option, such a "srcversion" field
|
||||
will be created for all modules. If unsure, say N.
|
||||
|
||||
config MODULE_SIG
|
||||
bool "Module signature verification"
|
||||
depends on MODULES
|
||||
select KEYS
|
||||
select CRYPTO
|
||||
select ASYMMETRIC_KEY_TYPE
|
||||
select ASYMMETRIC_PUBLIC_KEY_SUBTYPE
|
||||
select PUBLIC_KEY_ALGO_RSA
|
||||
select ASN1
|
||||
select OID_REGISTRY
|
||||
select X509_CERTIFICATE_PARSER
|
||||
help
|
||||
Check modules for valid signatures upon load: the signature
|
||||
is simply appended to the module. For more information see
|
||||
Documentation/module-signing.txt.
|
||||
|
||||
!!!WARNING!!! If you enable this option, you MUST make sure that the
|
||||
module DOES NOT get stripped after being signed. This includes the
|
||||
debuginfo strip done by some packagers (such as rpmbuild) and
|
||||
inclusion into an initramfs that wants the module size reduced.
|
||||
|
||||
config MODULE_SIG_FORCE
|
||||
bool "Require modules to be validly signed"
|
||||
depends on MODULE_SIG
|
||||
help
|
||||
Reject unsigned modules or signed modules for which we don't have a
|
||||
key. Without this, such modules will simply taint the kernel.
|
||||
|
||||
choice
|
||||
prompt "Which hash algorithm should modules be signed with?"
|
||||
depends on MODULE_SIG
|
||||
help
|
||||
This determines which sort of hashing algorithm will be used during
|
||||
signature generation. This algorithm _must_ be built into the kernel
|
||||
directly so that signature verification can take place. It is not
|
||||
possible to load a signed module containing the algorithm to check
|
||||
the signature on that module.
|
||||
|
||||
config MODULE_SIG_SHA1
|
||||
bool "Sign modules with SHA-1"
|
||||
select CRYPTO_SHA1
|
||||
|
||||
config MODULE_SIG_SHA224
|
||||
bool "Sign modules with SHA-224"
|
||||
select CRYPTO_SHA256
|
||||
|
||||
config MODULE_SIG_SHA256
|
||||
bool "Sign modules with SHA-256"
|
||||
select CRYPTO_SHA256
|
||||
|
||||
config MODULE_SIG_SHA384
|
||||
bool "Sign modules with SHA-384"
|
||||
select CRYPTO_SHA512
|
||||
|
||||
config MODULE_SIG_SHA512
|
||||
bool "Sign modules with SHA-512"
|
||||
select CRYPTO_SHA512
|
||||
|
||||
endchoice
|
||||
|
||||
endif # MODULES
|
||||
|
||||
config INIT_ALL_POSSIBLE
|
||||
|
@ -1607,4 +1667,12 @@ config PADATA
|
|||
config BROKEN_RODATA
|
||||
bool
|
||||
|
||||
config ASN1
|
||||
tristate
|
||||
help
|
||||
Build a simple ASN.1 grammar compiler that produces a bytecode output
|
||||
that can be interpreted by the ASN.1 stream decoder and used to
|
||||
inform it as to what tags are to be expected in a stream and what
|
||||
functions to call on what tags.
|
||||
|
||||
source "kernel/Kconfig.locks"
|
||||
|
|
|
@ -54,6 +54,7 @@ obj-$(CONFIG_DEBUG_SPINLOCK) += spinlock.o
|
|||
obj-$(CONFIG_PROVE_LOCKING) += spinlock.o
|
||||
obj-$(CONFIG_UID16) += uid16.o
|
||||
obj-$(CONFIG_MODULES) += module.o
|
||||
obj-$(CONFIG_MODULE_SIG) += module_signing.o modsign_pubkey.o
|
||||
obj-$(CONFIG_KALLSYMS) += kallsyms.o
|
||||
obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o
|
||||
obj-$(CONFIG_KEXEC) += kexec.o
|
||||
|
@ -130,3 +131,79 @@ quiet_cmd_timeconst = TIMEC $@
|
|||
targets += timeconst.h
|
||||
$(obj)/timeconst.h: $(src)/timeconst.pl FORCE
|
||||
$(call if_changed,timeconst)
|
||||
|
||||
ifeq ($(CONFIG_MODULE_SIG),y)
|
||||
#
|
||||
# Pull the signing certificate and any extra certificates into the kernel
|
||||
#
|
||||
extra_certificates:
|
||||
touch $@
|
||||
|
||||
kernel/modsign_pubkey.o: signing_key.x509 extra_certificates
|
||||
|
||||
###############################################################################
|
||||
#
|
||||
# If module signing is requested, say by allyesconfig, but a key has not been
|
||||
# supplied, then one will need to be generated to make sure the build does not
|
||||
# fail and that the kernel may be used afterwards.
|
||||
#
|
||||
###############################################################################
|
||||
sign_key_with_hash :=
|
||||
ifeq ($(CONFIG_MODULE_SIG_SHA1),y)
|
||||
sign_key_with_hash := -sha1
|
||||
endif
|
||||
ifeq ($(CONFIG_MODULE_SIG_SHA224),y)
|
||||
sign_key_with_hash := -sha224
|
||||
endif
|
||||
ifeq ($(CONFIG_MODULE_SIG_SHA256),y)
|
||||
sign_key_with_hash := -sha256
|
||||
endif
|
||||
ifeq ($(CONFIG_MODULE_SIG_SHA384),y)
|
||||
sign_key_with_hash := -sha384
|
||||
endif
|
||||
ifeq ($(CONFIG_MODULE_SIG_SHA512),y)
|
||||
sign_key_with_hash := -sha512
|
||||
endif
|
||||
ifeq ($(sign_key_with_hash),)
|
||||
$(error Could not determine digest type to use from kernel config)
|
||||
endif
|
||||
|
||||
signing_key.priv signing_key.x509: x509.genkey
|
||||
@echo "###"
|
||||
@echo "### Now generating an X.509 key pair to be used for signing modules."
|
||||
@echo "###"
|
||||
@echo "### If this takes a long time, you might wish to run rngd in the"
|
||||
@echo "### background to keep the supply of entropy topped up. It"
|
||||
@echo "### needs to be run as root, and should use a hardware random"
|
||||
@echo "### number generator if one is available, eg:"
|
||||
@echo "###"
|
||||
@echo "### rngd -r /dev/hwrandom"
|
||||
@echo "###"
|
||||
openssl req -new -nodes -utf8 $(sign_key_with_hash) -days 36500 -batch \
|
||||
-x509 -config x509.genkey \
|
||||
-outform DER -out signing_key.x509 \
|
||||
-keyout signing_key.priv
|
||||
@echo "###"
|
||||
@echo "### Key pair generated."
|
||||
@echo "###"
|
||||
|
||||
x509.genkey:
|
||||
@echo Generating X.509 key generation config
|
||||
@echo >x509.genkey "[ req ]"
|
||||
@echo >>x509.genkey "default_bits = 4096"
|
||||
@echo >>x509.genkey "distinguished_name = req_distinguished_name"
|
||||
@echo >>x509.genkey "prompt = no"
|
||||
@echo >>x509.genkey "string_mask = utf8only"
|
||||
@echo >>x509.genkey "x509_extensions = myexts"
|
||||
@echo >>x509.genkey
|
||||
@echo >>x509.genkey "[ req_distinguished_name ]"
|
||||
@echo >>x509.genkey "O = Magrathea"
|
||||
@echo >>x509.genkey "CN = Glacier signing key"
|
||||
@echo >>x509.genkey "emailAddress = slartibartfast@magrathea.h2g2"
|
||||
@echo >>x509.genkey
|
||||
@echo >>x509.genkey "[ myexts ]"
|
||||
@echo >>x509.genkey "basicConstraints=critical,CA:FALSE"
|
||||
@echo >>x509.genkey "keyUsage=digitalSignature"
|
||||
@echo >>x509.genkey "subjectKeyIdentifier=hash"
|
||||
@echo >>x509.genkey "authorityKeyIdentifier=keyid"
|
||||
endif
|
||||
|
|
|
@ -0,0 +1,113 @@
|
|||
/* Public keys for module signature verification
|
||||
*
|
||||
* 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/kernel.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/cred.h>
|
||||
#include <linux/err.h>
|
||||
#include <keys/asymmetric-type.h>
|
||||
#include "module-internal.h"
|
||||
|
||||
struct key *modsign_keyring;
|
||||
|
||||
extern __initdata const u8 modsign_certificate_list[];
|
||||
extern __initdata const u8 modsign_certificate_list_end[];
|
||||
asm(".section .init.data,\"aw\"\n"
|
||||
"modsign_certificate_list:\n"
|
||||
".incbin \"signing_key.x509\"\n"
|
||||
".incbin \"extra_certificates\"\n"
|
||||
"modsign_certificate_list_end:"
|
||||
);
|
||||
|
||||
/*
|
||||
* We need to make sure ccache doesn't cache the .o file as it doesn't notice
|
||||
* if modsign.pub changes.
|
||||
*/
|
||||
static __initdata const char annoy_ccache[] = __TIME__ "foo";
|
||||
|
||||
/*
|
||||
* Load the compiled-in keys
|
||||
*/
|
||||
static __init int module_verify_init(void)
|
||||
{
|
||||
pr_notice("Initialise module verification\n");
|
||||
|
||||
modsign_keyring = key_alloc(&key_type_keyring, ".module_sign",
|
||||
KUIDT_INIT(0), KGIDT_INIT(0),
|
||||
current_cred(),
|
||||
(KEY_POS_ALL & ~KEY_POS_SETATTR) |
|
||||
KEY_USR_VIEW | KEY_USR_READ,
|
||||
KEY_ALLOC_NOT_IN_QUOTA);
|
||||
if (IS_ERR(modsign_keyring))
|
||||
panic("Can't allocate module signing keyring\n");
|
||||
|
||||
if (key_instantiate_and_link(modsign_keyring, NULL, 0, NULL, NULL) < 0)
|
||||
panic("Can't instantiate module signing keyring\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Must be initialised before we try and load the keys into the keyring.
|
||||
*/
|
||||
device_initcall(module_verify_init);
|
||||
|
||||
/*
|
||||
* Load the compiled-in keys
|
||||
*/
|
||||
static __init int load_module_signing_keys(void)
|
||||
{
|
||||
key_ref_t key;
|
||||
const u8 *p, *end;
|
||||
size_t plen;
|
||||
|
||||
pr_notice("Loading module verification certificates\n");
|
||||
|
||||
end = modsign_certificate_list_end;
|
||||
p = modsign_certificate_list;
|
||||
while (p < end) {
|
||||
/* Each cert begins with an ASN.1 SEQUENCE tag and must be more
|
||||
* than 256 bytes in size.
|
||||
*/
|
||||
if (end - p < 4)
|
||||
goto dodgy_cert;
|
||||
if (p[0] != 0x30 &&
|
||||
p[1] != 0x82)
|
||||
goto dodgy_cert;
|
||||
plen = (p[2] << 8) | p[3];
|
||||
plen += 4;
|
||||
if (plen > end - p)
|
||||
goto dodgy_cert;
|
||||
|
||||
key = key_create_or_update(make_key_ref(modsign_keyring, 1),
|
||||
"asymmetric",
|
||||
NULL,
|
||||
p,
|
||||
plen,
|
||||
(KEY_POS_ALL & ~KEY_POS_SETATTR) |
|
||||
KEY_USR_VIEW,
|
||||
KEY_ALLOC_NOT_IN_QUOTA);
|
||||
if (IS_ERR(key))
|
||||
pr_err("MODSIGN: Problem loading in-kernel X.509 certificate (%ld)\n",
|
||||
PTR_ERR(key));
|
||||
else
|
||||
pr_notice("MODSIGN: Loaded cert '%s'\n",
|
||||
key_ref_to_ptr(key)->description);
|
||||
p += plen;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
dodgy_cert:
|
||||
pr_err("MODSIGN: Problem parsing in-kernel X.509 certificate list\n");
|
||||
return 0;
|
||||
}
|
||||
late_initcall(load_module_signing_keys);
|
|
@ -0,0 +1,15 @@
|
|||
/* Module internals
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
extern struct key *modsign_keyring;
|
||||
|
||||
extern int mod_verify_sig(const void *mod, unsigned long modlen,
|
||||
const void *sig, unsigned long siglen);
|
157
kernel/module.c
157
kernel/module.c
|
@ -58,6 +58,8 @@
|
|||
#include <linux/jump_label.h>
|
||||
#include <linux/pfn.h>
|
||||
#include <linux/bsearch.h>
|
||||
#include <linux/fips.h>
|
||||
#include "module-internal.h"
|
||||
|
||||
#define CREATE_TRACE_POINTS
|
||||
#include <trace/events/module.h>
|
||||
|
@ -102,6 +104,43 @@ static LIST_HEAD(modules);
|
|||
struct list_head *kdb_modules = &modules; /* kdb needs the list of modules */
|
||||
#endif /* CONFIG_KGDB_KDB */
|
||||
|
||||
#ifdef CONFIG_MODULE_SIG
|
||||
#ifdef CONFIG_MODULE_SIG_FORCE
|
||||
static bool sig_enforce = true;
|
||||
#else
|
||||
static bool sig_enforce = false;
|
||||
|
||||
static int param_set_bool_enable_only(const char *val,
|
||||
const struct kernel_param *kp)
|
||||
{
|
||||
int err;
|
||||
bool test;
|
||||
struct kernel_param dummy_kp = *kp;
|
||||
|
||||
dummy_kp.arg = &test;
|
||||
|
||||
err = param_set_bool(val, &dummy_kp);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* Don't let them unset it once it's set! */
|
||||
if (!test && sig_enforce)
|
||||
return -EROFS;
|
||||
|
||||
if (test)
|
||||
sig_enforce = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct kernel_param_ops param_ops_bool_enable_only = {
|
||||
.set = param_set_bool_enable_only,
|
||||
.get = param_get_bool,
|
||||
};
|
||||
#define param_check_bool_enable_only param_check_bool
|
||||
|
||||
module_param(sig_enforce, bool_enable_only, 0644);
|
||||
#endif /* !CONFIG_MODULE_SIG_FORCE */
|
||||
#endif /* CONFIG_MODULE_SIG */
|
||||
|
||||
/* Block module loading/unloading? */
|
||||
int modules_disabled = 0;
|
||||
|
@ -136,6 +175,7 @@ struct load_info {
|
|||
unsigned long symoffs, stroffs;
|
||||
struct _ddebug *debug;
|
||||
unsigned int num_debug;
|
||||
bool sig_ok;
|
||||
struct {
|
||||
unsigned int sym, str, mod, vers, info, pcpu;
|
||||
} index;
|
||||
|
@ -1949,26 +1989,6 @@ static int simplify_symbols(struct module *mod, const struct load_info *info)
|
|||
return ret;
|
||||
}
|
||||
|
||||
int __weak apply_relocate(Elf_Shdr *sechdrs,
|
||||
const char *strtab,
|
||||
unsigned int symindex,
|
||||
unsigned int relsec,
|
||||
struct module *me)
|
||||
{
|
||||
pr_err("module %s: REL relocation unsupported\n", me->name);
|
||||
return -ENOEXEC;
|
||||
}
|
||||
|
||||
int __weak apply_relocate_add(Elf_Shdr *sechdrs,
|
||||
const char *strtab,
|
||||
unsigned int symindex,
|
||||
unsigned int relsec,
|
||||
struct module *me)
|
||||
{
|
||||
pr_err("module %s: RELA relocation unsupported\n", me->name);
|
||||
return -ENOEXEC;
|
||||
}
|
||||
|
||||
static int apply_relocations(struct module *mod, const struct load_info *info)
|
||||
{
|
||||
unsigned int i;
|
||||
|
@ -2399,7 +2419,52 @@ static inline void kmemleak_load_module(const struct module *mod,
|
|||
}
|
||||
#endif
|
||||
|
||||
/* Sets info->hdr and info->len. */
|
||||
#ifdef CONFIG_MODULE_SIG
|
||||
static int module_sig_check(struct load_info *info,
|
||||
const void *mod, unsigned long *len)
|
||||
{
|
||||
int err = -ENOKEY;
|
||||
const unsigned long markerlen = sizeof(MODULE_SIG_STRING) - 1;
|
||||
const void *p = mod, *end = mod + *len;
|
||||
|
||||
/* Poor man's memmem. */
|
||||
while ((p = memchr(p, MODULE_SIG_STRING[0], end - p))) {
|
||||
if (p + markerlen > end)
|
||||
break;
|
||||
|
||||
if (memcmp(p, MODULE_SIG_STRING, markerlen) == 0) {
|
||||
const void *sig = p + markerlen;
|
||||
/* Truncate module up to signature. */
|
||||
*len = p - mod;
|
||||
err = mod_verify_sig(mod, *len, sig, end - sig);
|
||||
break;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
|
||||
if (!err) {
|
||||
info->sig_ok = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Not having a signature is only an error if we're strict. */
|
||||
if (err < 0 && fips_enabled)
|
||||
panic("Module verification failed with error %d in FIPS mode\n",
|
||||
err);
|
||||
if (err == -ENOKEY && !sig_enforce)
|
||||
err = 0;
|
||||
|
||||
return err;
|
||||
}
|
||||
#else /* !CONFIG_MODULE_SIG */
|
||||
static int module_sig_check(struct load_info *info,
|
||||
void *mod, unsigned long *len)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif /* !CONFIG_MODULE_SIG */
|
||||
|
||||
/* Sets info->hdr, info->len and info->sig_ok. */
|
||||
static int copy_and_check(struct load_info *info,
|
||||
const void __user *umod, unsigned long len,
|
||||
const char __user *uargs)
|
||||
|
@ -2419,6 +2484,10 @@ static int copy_and_check(struct load_info *info,
|
|||
goto free_hdr;
|
||||
}
|
||||
|
||||
err = module_sig_check(info, hdr, &len);
|
||||
if (err)
|
||||
goto free_hdr;
|
||||
|
||||
/* Sanity checks against insmoding binaries or wrong arch,
|
||||
weird elf version */
|
||||
if (memcmp(hdr->e_ident, ELFMAG, SELFMAG) != 0
|
||||
|
@ -2730,6 +2799,10 @@ static int check_module_license_and_versions(struct module *mod)
|
|||
if (strcmp(mod->name, "driverloader") == 0)
|
||||
add_taint_module(mod, TAINT_PROPRIETARY_MODULE);
|
||||
|
||||
/* lve claims to be GPL but upstream won't provide source */
|
||||
if (strcmp(mod->name, "lve") == 0)
|
||||
add_taint_module(mod, TAINT_PROPRIETARY_MODULE);
|
||||
|
||||
#ifdef CONFIG_MODVERSIONS
|
||||
if ((mod->num_syms && !mod->crcs)
|
||||
|| (mod->num_gpl_syms && !mod->gpl_crcs)
|
||||
|
@ -2861,6 +2934,20 @@ static int post_relocation(struct module *mod, const struct load_info *info)
|
|||
return module_finalize(info->hdr, info->sechdrs, mod);
|
||||
}
|
||||
|
||||
/* Is this module of this name done loading? No locks held. */
|
||||
static bool finished_loading(const char *name)
|
||||
{
|
||||
struct module *mod;
|
||||
bool ret;
|
||||
|
||||
mutex_lock(&module_mutex);
|
||||
mod = find_module(name);
|
||||
ret = !mod || mod->state != MODULE_STATE_COMING;
|
||||
mutex_unlock(&module_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Allocate and load the module: note that size of section 0 is always
|
||||
zero, and we rely on this for optional sections. */
|
||||
static struct module *load_module(void __user *umod,
|
||||
|
@ -2868,7 +2955,7 @@ static struct module *load_module(void __user *umod,
|
|||
const char __user *uargs)
|
||||
{
|
||||
struct load_info info = { NULL, };
|
||||
struct module *mod;
|
||||
struct module *mod, *old;
|
||||
long err;
|
||||
|
||||
pr_debug("load_module: umod=%p, len=%lu, uargs=%p\n",
|
||||
|
@ -2886,6 +2973,12 @@ static struct module *load_module(void __user *umod,
|
|||
goto free_copy;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MODULE_SIG
|
||||
mod->sig_ok = info.sig_ok;
|
||||
if (!mod->sig_ok)
|
||||
add_taint_module(mod, TAINT_FORCED_MODULE);
|
||||
#endif
|
||||
|
||||
/* Now module is in final location, initialize linked lists, etc. */
|
||||
err = module_unload_init(mod);
|
||||
if (err)
|
||||
|
@ -2934,8 +3027,18 @@ static struct module *load_module(void __user *umod,
|
|||
* function to insert in a way safe to concurrent readers.
|
||||
* The mutex protects against concurrent writers.
|
||||
*/
|
||||
again:
|
||||
mutex_lock(&module_mutex);
|
||||
if (find_module(mod->name)) {
|
||||
if ((old = find_module(mod->name)) != NULL) {
|
||||
if (old->state == MODULE_STATE_COMING) {
|
||||
/* Wait in case it fails to load. */
|
||||
mutex_unlock(&module_mutex);
|
||||
err = wait_event_interruptible(module_wq,
|
||||
finished_loading(mod->name));
|
||||
if (err)
|
||||
goto free_arch_cleanup;
|
||||
goto again;
|
||||
}
|
||||
err = -EEXIST;
|
||||
goto unlock;
|
||||
}
|
||||
|
@ -2975,7 +3078,7 @@ static struct module *load_module(void __user *umod,
|
|||
/* Unlink carefully: kallsyms could be walking list. */
|
||||
list_del_rcu(&mod->list);
|
||||
module_bug_cleanup(mod);
|
||||
|
||||
wake_up_all(&module_wq);
|
||||
ddebug:
|
||||
dynamic_debug_remove(info.debug);
|
||||
unlock:
|
||||
|
@ -3050,7 +3153,7 @@ SYSCALL_DEFINE3(init_module, void __user *, umod,
|
|||
blocking_notifier_call_chain(&module_notify_list,
|
||||
MODULE_STATE_GOING, mod);
|
||||
free_module(mod);
|
||||
wake_up(&module_wq);
|
||||
wake_up_all(&module_wq);
|
||||
return ret;
|
||||
}
|
||||
if (ret > 0) {
|
||||
|
@ -3062,9 +3165,8 @@ SYSCALL_DEFINE3(init_module, void __user *, umod,
|
|||
dump_stack();
|
||||
}
|
||||
|
||||
/* Now it's a first class citizen! Wake up anyone waiting for it. */
|
||||
/* Now it's a first class citizen! */
|
||||
mod->state = MODULE_STATE_LIVE;
|
||||
wake_up(&module_wq);
|
||||
blocking_notifier_call_chain(&module_notify_list,
|
||||
MODULE_STATE_LIVE, mod);
|
||||
|
||||
|
@ -3087,6 +3189,7 @@ SYSCALL_DEFINE3(init_module, void __user *, umod,
|
|||
mod->init_ro_size = 0;
|
||||
mod->init_text_size = 0;
|
||||
mutex_unlock(&module_mutex);
|
||||
wake_up_all(&module_wq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,243 @@
|
|||
/* Module signature checker
|
||||
*
|
||||
* 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/kernel.h>
|
||||
#include <linux/err.h>
|
||||
#include <crypto/public_key.h>
|
||||
#include <crypto/hash.h>
|
||||
#include <keys/asymmetric-type.h>
|
||||
#include "module-internal.h"
|
||||
|
||||
/*
|
||||
* Module signature information block.
|
||||
*
|
||||
* The constituents of the signature section are, in order:
|
||||
*
|
||||
* - Signer's name
|
||||
* - Key identifier
|
||||
* - Signature data
|
||||
* - Information block
|
||||
*/
|
||||
struct module_signature {
|
||||
enum pkey_algo algo : 8; /* Public-key crypto algorithm */
|
||||
enum pkey_hash_algo hash : 8; /* Digest algorithm */
|
||||
enum pkey_id_type id_type : 8; /* Key identifier type */
|
||||
u8 signer_len; /* Length of signer's name */
|
||||
u8 key_id_len; /* Length of key identifier */
|
||||
u8 __pad[3];
|
||||
__be32 sig_len; /* Length of signature data */
|
||||
};
|
||||
|
||||
/*
|
||||
* Digest the module contents.
|
||||
*/
|
||||
static struct public_key_signature *mod_make_digest(enum pkey_hash_algo hash,
|
||||
const void *mod,
|
||||
unsigned long modlen)
|
||||
{
|
||||
struct public_key_signature *pks;
|
||||
struct crypto_shash *tfm;
|
||||
struct shash_desc *desc;
|
||||
size_t digest_size, desc_size;
|
||||
int ret;
|
||||
|
||||
pr_devel("==>%s()\n", __func__);
|
||||
|
||||
/* Allocate the hashing algorithm we're going to need and find out how
|
||||
* big the hash operational data will be.
|
||||
*/
|
||||
tfm = crypto_alloc_shash(pkey_hash_algo[hash], 0, 0);
|
||||
if (IS_ERR(tfm))
|
||||
return (PTR_ERR(tfm) == -ENOENT) ? ERR_PTR(-ENOPKG) : ERR_CAST(tfm);
|
||||
|
||||
desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
|
||||
digest_size = crypto_shash_digestsize(tfm);
|
||||
|
||||
/* We allocate the hash operational data storage on the end of our
|
||||
* context data and the digest output buffer on the end of that.
|
||||
*/
|
||||
ret = -ENOMEM;
|
||||
pks = kzalloc(digest_size + sizeof(*pks) + desc_size, GFP_KERNEL);
|
||||
if (!pks)
|
||||
goto error_no_pks;
|
||||
|
||||
pks->pkey_hash_algo = hash;
|
||||
pks->digest = (u8 *)pks + sizeof(*pks) + desc_size;
|
||||
pks->digest_size = digest_size;
|
||||
|
||||
desc = (void *)pks + sizeof(*pks);
|
||||
desc->tfm = tfm;
|
||||
desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
|
||||
|
||||
ret = crypto_shash_init(desc);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
ret = crypto_shash_finup(desc, mod, modlen, pks->digest);
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
crypto_free_shash(tfm);
|
||||
pr_devel("<==%s() = ok\n", __func__);
|
||||
return pks;
|
||||
|
||||
error:
|
||||
kfree(pks);
|
||||
error_no_pks:
|
||||
crypto_free_shash(tfm);
|
||||
pr_devel("<==%s() = %d\n", __func__, ret);
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* Extract an MPI array from the signature data. This represents the actual
|
||||
* signature. Each raw MPI is prefaced by a BE 2-byte value indicating the
|
||||
* size of the MPI in bytes.
|
||||
*
|
||||
* RSA signatures only have one MPI, so currently we only read one.
|
||||
*/
|
||||
static int mod_extract_mpi_array(struct public_key_signature *pks,
|
||||
const void *data, size_t len)
|
||||
{
|
||||
size_t nbytes;
|
||||
MPI mpi;
|
||||
|
||||
if (len < 3)
|
||||
return -EBADMSG;
|
||||
nbytes = ((const u8 *)data)[0] << 8 | ((const u8 *)data)[1];
|
||||
data += 2;
|
||||
len -= 2;
|
||||
if (len != nbytes)
|
||||
return -EBADMSG;
|
||||
|
||||
mpi = mpi_read_raw_data(data, nbytes);
|
||||
if (!mpi)
|
||||
return -ENOMEM;
|
||||
pks->mpi[0] = mpi;
|
||||
pks->nr_mpi = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Request an asymmetric key.
|
||||
*/
|
||||
static struct key *request_asymmetric_key(const char *signer, size_t signer_len,
|
||||
const u8 *key_id, size_t key_id_len)
|
||||
{
|
||||
key_ref_t key;
|
||||
size_t i;
|
||||
char *id, *q;
|
||||
|
||||
pr_devel("==>%s(,%zu,,%zu)\n", __func__, signer_len, key_id_len);
|
||||
|
||||
/* Construct an identifier. */
|
||||
id = kmalloc(signer_len + 2 + key_id_len * 2 + 1, GFP_KERNEL);
|
||||
if (!id)
|
||||
return ERR_PTR(-ENOKEY);
|
||||
|
||||
memcpy(id, signer, signer_len);
|
||||
|
||||
q = id + signer_len;
|
||||
*q++ = ':';
|
||||
*q++ = ' ';
|
||||
for (i = 0; i < key_id_len; i++) {
|
||||
*q++ = hex_asc[*key_id >> 4];
|
||||
*q++ = hex_asc[*key_id++ & 0x0f];
|
||||
}
|
||||
|
||||
*q = 0;
|
||||
|
||||
pr_debug("Look up: \"%s\"\n", id);
|
||||
|
||||
key = keyring_search(make_key_ref(modsign_keyring, 1),
|
||||
&key_type_asymmetric, id);
|
||||
if (IS_ERR(key))
|
||||
pr_warn("Request for unknown 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);
|
||||
}
|
||||
|
||||
/*
|
||||
* Verify the signature on a module.
|
||||
*/
|
||||
int mod_verify_sig(const void *mod, unsigned long modlen,
|
||||
const void *sig, unsigned long siglen)
|
||||
{
|
||||
struct public_key_signature *pks;
|
||||
struct module_signature ms;
|
||||
struct key *key;
|
||||
size_t sig_len;
|
||||
int ret;
|
||||
|
||||
pr_devel("==>%s(,%lu,,%lu,)\n", __func__, modlen, siglen);
|
||||
|
||||
if (siglen <= sizeof(ms))
|
||||
return -EBADMSG;
|
||||
|
||||
memcpy(&ms, sig + (siglen - sizeof(ms)), sizeof(ms));
|
||||
siglen -= sizeof(ms);
|
||||
|
||||
sig_len = be32_to_cpu(ms.sig_len);
|
||||
if (sig_len >= siglen ||
|
||||
siglen - sig_len != (size_t)ms.signer_len + ms.key_id_len)
|
||||
return -EBADMSG;
|
||||
|
||||
/* For the moment, only support RSA and X.509 identifiers */
|
||||
if (ms.algo != PKEY_ALGO_RSA ||
|
||||
ms.id_type != PKEY_ID_X509)
|
||||
return -ENOPKG;
|
||||
|
||||
if (ms.hash >= PKEY_HASH__LAST ||
|
||||
!pkey_hash_algo[ms.hash])
|
||||
return -ENOPKG;
|
||||
|
||||
key = request_asymmetric_key(sig, ms.signer_len,
|
||||
sig + ms.signer_len, ms.key_id_len);
|
||||
if (IS_ERR(key))
|
||||
return PTR_ERR(key);
|
||||
|
||||
pks = mod_make_digest(ms.hash, mod, modlen);
|
||||
if (IS_ERR(pks)) {
|
||||
ret = PTR_ERR(pks);
|
||||
goto error_put_key;
|
||||
}
|
||||
|
||||
ret = mod_extract_mpi_array(pks, sig + ms.signer_len + ms.key_id_len,
|
||||
sig_len);
|
||||
if (ret < 0)
|
||||
goto error_free_pks;
|
||||
|
||||
ret = verify_signature(key, pks);
|
||||
pr_devel("verify_signature() = %d\n", ret);
|
||||
|
||||
error_free_pks:
|
||||
mpi_free(pks->rsa.s);
|
||||
kfree(pks);
|
||||
error_put_key:
|
||||
key_put(key);
|
||||
pr_devel("<==%s() = %d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
|
@ -3,4 +3,4 @@
|
|||
#
|
||||
gen_crc32table
|
||||
crc32table.h
|
||||
|
||||
oid_registry_data.c
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue