aboutsummaryrefslogtreecommitdiffstats
path: root/security
diff options
context:
space:
mode:
authorDmitry Kasatkin <dmitry.kasatkin@intel.com>2013-02-06 17:12:08 -0500
committerMimi Zohar <zohar@linux.vnet.ibm.com>2013-02-06 21:22:18 -0500
commite0751257a64ea10cca96ccb06522bfb10e36cb5b (patch)
tree7ff1ec8b4d359f383fc3408876dd6ff6532f9ab6 /security
parent50af554466804bf51a52fa3d1d0a76f96bd33929 (diff)
ima: digital signature verification using asymmetric keys
Asymmetric keys were introduced in linux-3.7 to verify the signature on signed kernel modules. The asymmetric keys infrastructure abstracts the signature verification from the crypto details. This patch adds IMA/EVM signature verification using asymmetric keys. Support for additional signature verification methods can now be delegated to the asymmetric key infrastructure. Although the module signature header and the IMA/EVM signature header could use the same format, to minimize the signature length and save space in the extended attribute, this patch defines a new IMA/EVM header format. The main difference is that the key identifier is a sha1[12 - 19] hash of the key modulus and exponent, similar to the current implementation. The only purpose of the key identifier is to identify the corresponding key in the kernel keyring. ima-evm-utils was updated to support the new signature format. While asymmetric signature verification functionality supports many different hash algorithms, the hash used in this patch is calculated during the IMA collection phase, based on the configured algorithm. The default algorithm is sha1, but for backwards compatibility md5 is supported. Due to this current limitation, signatures should be generated using a sha1 hash algorithm. Changes in this patch: - Functionality has been moved to separate source file in order to get rid of in source #ifdefs. - keyid is derived according to the RFC 3280. It does not require to assign IMA/EVM specific "description" when loading X509 certificate. Kernel asymmetric key subsystem automatically generate the description. Also loading a certificate does not require using of ima-evm-utils and can be done using keyctl only. - keyid size is reduced to 32 bits to save xattr space. Key search is done using partial match functionality of asymmetric_key_match(). - Kconfig option title was changed Signed-off-by: Dmitry Kasatkin <dmitry.kasatkin@intel.com> Acked-by: David Howells <dhowells@redhat.com> Signed-off-by: Mimi Zohar <zohar@linux.vnet.ibm.com>
Diffstat (limited to 'security')
-rw-r--r--security/integrity/Kconfig12
-rw-r--r--security/integrity/Makefile1
-rw-r--r--security/integrity/digsig.c11
-rw-r--r--security/integrity/digsig_asymmetric.c115
-rw-r--r--security/integrity/integrity.h12
5 files changed, 150 insertions, 1 deletions
diff --git a/security/integrity/Kconfig b/security/integrity/Kconfig
index 5bd1cc1b4a54..4bb3a775a996 100644
--- a/security/integrity/Kconfig
+++ b/security/integrity/Kconfig
@@ -17,5 +17,17 @@ config INTEGRITY_SIGNATURE
17 This is useful for evm and module keyrings, when keys are 17 This is useful for evm and module keyrings, when keys are
18 usually only added from initramfs. 18 usually only added from initramfs.
19 19
20config INTEGRITY_ASYMMETRIC_KEYS
21 boolean "Enable asymmetric keys support"
22 depends on INTEGRITY_SIGNATURE
23 default n
24 select ASYMMETRIC_KEY_TYPE
25 select ASYMMETRIC_PUBLIC_KEY_SUBTYPE
26 select PUBLIC_KEY_ALGO_RSA
27 select X509_CERTIFICATE_PARSER
28 help
29 This option enables digital signature verification using
30 asymmetric keys.
31
20source security/integrity/ima/Kconfig 32source security/integrity/ima/Kconfig
21source security/integrity/evm/Kconfig 33source security/integrity/evm/Kconfig
diff --git a/security/integrity/Makefile b/security/integrity/Makefile
index d43799cc14f6..ebb6409b3fcb 100644
--- a/security/integrity/Makefile
+++ b/security/integrity/Makefile
@@ -4,6 +4,7 @@
4 4
5obj-$(CONFIG_INTEGRITY) += integrity.o 5obj-$(CONFIG_INTEGRITY) += integrity.o
6obj-$(CONFIG_INTEGRITY_SIGNATURE) += digsig.o 6obj-$(CONFIG_INTEGRITY_SIGNATURE) += digsig.o
7obj-$(CONFIG_INTEGRITY_ASYMMETRIC_KEYS) += digsig_asymmetric.o
7 8
8integrity-y := iint.o 9integrity-y := iint.o
9 10
diff --git a/security/integrity/digsig.c b/security/integrity/digsig.c
index 2dc167d7cde9..0b759e17a131 100644
--- a/security/integrity/digsig.c
+++ b/security/integrity/digsig.c
@@ -44,5 +44,14 @@ int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen,
44 } 44 }
45 } 45 }
46 46
47 return digsig_verify(keyring[id], sig, siglen, digest, digestlen); 47 switch (sig[0]) {
48 case 1:
49 return digsig_verify(keyring[id], sig, siglen,
50 digest, digestlen);
51 case 2:
52 return asymmetric_verify(keyring[id], sig, siglen,
53 digest, digestlen);
54 }
55
56 return -EOPNOTSUPP;
48} 57}
diff --git a/security/integrity/digsig_asymmetric.c b/security/integrity/digsig_asymmetric.c
new file mode 100644
index 000000000000..b4754667659d
--- /dev/null
+++ b/security/integrity/digsig_asymmetric.c
@@ -0,0 +1,115 @@
1/*
2 * Copyright (C) 2013 Intel Corporation
3 *
4 * Author:
5 * Dmitry Kasatkin <dmitry.kasatkin@intel.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, version 2 of the License.
10 *
11 */
12
13#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
14
15#include <linux/err.h>
16#include <linux/key-type.h>
17#include <crypto/public_key.h>
18#include <keys/asymmetric-type.h>
19
20#include "integrity.h"
21
22/*
23 * signature format v2 - for using with asymmetric keys
24 */
25struct signature_v2_hdr {
26 uint8_t version; /* signature format version */
27 uint8_t hash_algo; /* Digest algorithm [enum pkey_hash_algo] */
28 uint32_t keyid; /* IMA key identifier - not X509/PGP specific*/
29 uint16_t sig_size; /* signature size */
30 uint8_t sig[0]; /* signature payload */
31} __packed;
32
33/*
34 * Request an asymmetric key.
35 */
36static struct key *request_asymmetric_key(struct key *keyring, uint32_t keyid)
37{
38 struct key *key;
39 char name[12];
40
41 sprintf(name, "id:%x", keyid);
42
43 pr_debug("key search: \"%s\"\n", name);
44
45 if (keyring) {
46 /* search in specific keyring */
47 key_ref_t kref;
48 kref = keyring_search(make_key_ref(keyring, 1),
49 &key_type_asymmetric, name);
50 if (IS_ERR(kref))
51 key = ERR_CAST(kref);
52 else
53 key = key_ref_to_ptr(kref);
54 } else {
55 key = request_key(&key_type_asymmetric, name, NULL);
56 }
57
58 if (IS_ERR(key)) {
59 pr_warn("Request for unknown key '%s' err %ld\n",
60 name, PTR_ERR(key));
61 switch (PTR_ERR(key)) {
62 /* Hide some search errors */
63 case -EACCES:
64 case -ENOTDIR:
65 case -EAGAIN:
66 return ERR_PTR(-ENOKEY);
67 default:
68 return key;
69 }
70 }
71
72 pr_debug("%s() = 0 [%x]\n", __func__, key_serial(key));
73
74 return key;
75}
76
77int asymmetric_verify(struct key *keyring, const char *sig,
78 int siglen, const char *data, int datalen)
79{
80 struct public_key_signature pks;
81 struct signature_v2_hdr *hdr = (struct signature_v2_hdr *)sig;
82 struct key *key;
83 int ret = -ENOMEM;
84
85 if (siglen <= sizeof(*hdr))
86 return -EBADMSG;
87
88 siglen -= sizeof(*hdr);
89
90 if (siglen != __be16_to_cpu(hdr->sig_size))
91 return -EBADMSG;
92
93 if (hdr->hash_algo >= PKEY_HASH__LAST)
94 return -ENOPKG;
95
96 key = request_asymmetric_key(keyring, __be32_to_cpu(hdr->keyid));
97 if (IS_ERR(key))
98 return PTR_ERR(key);
99
100 memset(&pks, 0, sizeof(pks));
101
102 pks.pkey_hash_algo = hdr->hash_algo;
103 pks.digest = (u8 *)data;
104 pks.digest_size = datalen;
105 pks.nr_mpi = 1;
106 pks.rsa.s = mpi_read_raw_data(hdr->sig, siglen);
107
108 if (pks.rsa.s)
109 ret = verify_signature(key, &pks);
110
111 mpi_free(pks.rsa.s);
112 key_put(key);
113 pr_debug("%s() = %d\n", __func__, ret);
114 return ret;
115}
diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h
index 0ae08fc88585..84c37c4db914 100644
--- a/security/integrity/integrity.h
+++ b/security/integrity/integrity.h
@@ -14,6 +14,7 @@
14#include <linux/types.h> 14#include <linux/types.h>
15#include <linux/integrity.h> 15#include <linux/integrity.h>
16#include <crypto/sha.h> 16#include <crypto/sha.h>
17#include <linux/key.h>
17 18
18/* iint action cache flags */ 19/* iint action cache flags */
19#define IMA_MEASURE 0x00000001 20#define IMA_MEASURE 0x00000001
@@ -101,5 +102,16 @@ static inline int integrity_digsig_verify(const unsigned int id,
101 102
102#endif /* CONFIG_INTEGRITY_SIGNATURE */ 103#endif /* CONFIG_INTEGRITY_SIGNATURE */
103 104
105#ifdef CONFIG_INTEGRITY_ASYMMETRIC_KEYS
106int asymmetric_verify(struct key *keyring, const char *sig,
107 int siglen, const char *data, int datalen);
108#else
109static inline int asymmetric_verify(struct key *keyring, const char *sig,
110 int siglen, const char *data, int datalen)
111{
112 return -EOPNOTSUPP;
113}
114#endif
115
104/* set during initialization */ 116/* set during initialization */
105extern int iint_initialized; 117extern int iint_initialized;