1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright (C) 2011 Intel Corporation |
4 | * |
5 | * Author: |
6 | * Dmitry Kasatkin <dmitry.kasatkin@intel.com> |
7 | */ |
8 | |
9 | #include <linux/err.h> |
10 | #include <linux/sched.h> |
11 | #include <linux/slab.h> |
12 | #include <linux/cred.h> |
13 | #include <linux/kernel_read_file.h> |
14 | #include <linux/key-type.h> |
15 | #include <linux/digsig.h> |
16 | #include <linux/vmalloc.h> |
17 | #include <crypto/public_key.h> |
18 | #include <keys/system_keyring.h> |
19 | |
20 | #include "integrity.h" |
21 | |
22 | static struct key *keyring[INTEGRITY_KEYRING_MAX]; |
23 | |
24 | static const char * const keyring_name[INTEGRITY_KEYRING_MAX] = { |
25 | #ifndef CONFIG_INTEGRITY_TRUSTED_KEYRING |
26 | "_evm" , |
27 | "_ima" , |
28 | #else |
29 | ".evm" , |
30 | ".ima" , |
31 | #endif |
32 | ".platform" , |
33 | ".machine" , |
34 | }; |
35 | |
36 | #ifdef CONFIG_IMA_KEYRINGS_PERMIT_SIGNED_BY_BUILTIN_OR_SECONDARY |
37 | #define restrict_link_to_ima restrict_link_by_digsig_builtin_and_secondary |
38 | #else |
39 | #define restrict_link_to_ima restrict_link_by_digsig_builtin |
40 | #endif |
41 | |
42 | static struct key *integrity_keyring_from_id(const unsigned int id) |
43 | { |
44 | if (id >= INTEGRITY_KEYRING_MAX) |
45 | return ERR_PTR(error: -EINVAL); |
46 | |
47 | if (!keyring[id]) { |
48 | keyring[id] = |
49 | request_key(type: &key_type_keyring, description: keyring_name[id], NULL); |
50 | if (IS_ERR(ptr: keyring[id])) { |
51 | int err = PTR_ERR(ptr: keyring[id]); |
52 | pr_err("no %s keyring: %d\n" , keyring_name[id], err); |
53 | keyring[id] = NULL; |
54 | return ERR_PTR(error: err); |
55 | } |
56 | } |
57 | |
58 | return keyring[id]; |
59 | } |
60 | |
61 | int integrity_digsig_verify(const unsigned int id, const char *sig, int siglen, |
62 | const char *digest, int digestlen) |
63 | { |
64 | struct key *keyring; |
65 | |
66 | if (siglen < 2) |
67 | return -EINVAL; |
68 | |
69 | keyring = integrity_keyring_from_id(id); |
70 | if (IS_ERR(ptr: keyring)) |
71 | return PTR_ERR(ptr: keyring); |
72 | |
73 | switch (sig[1]) { |
74 | case 1: |
75 | /* v1 API expect signature without xattr type */ |
76 | return digsig_verify(keyring, sig: sig + 1, siglen: siglen - 1, digest, |
77 | digestlen); |
78 | case 2: /* regular file data hash based signature */ |
79 | case 3: /* struct ima_file_id data based signature */ |
80 | return asymmetric_verify(keyring, sig, siglen, data: digest, |
81 | datalen: digestlen); |
82 | } |
83 | |
84 | return -EOPNOTSUPP; |
85 | } |
86 | |
87 | int integrity_modsig_verify(const unsigned int id, const struct modsig *modsig) |
88 | { |
89 | struct key *keyring; |
90 | |
91 | keyring = integrity_keyring_from_id(id); |
92 | if (IS_ERR(ptr: keyring)) |
93 | return PTR_ERR(ptr: keyring); |
94 | |
95 | return ima_modsig_verify(keyring, modsig); |
96 | } |
97 | |
98 | static int __init __integrity_init_keyring(const unsigned int id, |
99 | key_perm_t perm, |
100 | struct key_restriction *restriction) |
101 | { |
102 | const struct cred *cred = current_cred(); |
103 | int err = 0; |
104 | |
105 | keyring[id] = keyring_alloc(description: keyring_name[id], KUIDT_INIT(0), |
106 | KGIDT_INIT(0), cred, perm, |
107 | KEY_ALLOC_NOT_IN_QUOTA, restrict_link: restriction, NULL); |
108 | if (IS_ERR(keyring[id])) { |
109 | err = PTR_ERR(keyring[id]); |
110 | pr_info("Can't allocate %s keyring (%d)\n" , |
111 | keyring_name[id], err); |
112 | keyring[id] = NULL; |
113 | } else { |
114 | if (id == INTEGRITY_KEYRING_PLATFORM) |
115 | set_platform_trusted_keys(keyring[id]); |
116 | if (id == INTEGRITY_KEYRING_MACHINE && imputed_trust_enabled()) |
117 | set_machine_trusted_keys(keyring[id]); |
118 | if (id == INTEGRITY_KEYRING_IMA) |
119 | load_module_cert(keyring[id]); |
120 | } |
121 | |
122 | return err; |
123 | } |
124 | |
125 | int __init integrity_init_keyring(const unsigned int id) |
126 | { |
127 | struct key_restriction *restriction; |
128 | key_perm_t perm; |
129 | int ret; |
130 | |
131 | perm = (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_VIEW |
132 | | KEY_USR_READ | KEY_USR_SEARCH; |
133 | |
134 | if (id == INTEGRITY_KEYRING_PLATFORM || |
135 | (id == INTEGRITY_KEYRING_MACHINE && |
136 | !IS_ENABLED(CONFIG_INTEGRITY_CA_MACHINE_KEYRING))) { |
137 | restriction = NULL; |
138 | goto out; |
139 | } |
140 | |
141 | if (!IS_ENABLED(CONFIG_INTEGRITY_TRUSTED_KEYRING)) |
142 | return 0; |
143 | |
144 | restriction = kzalloc(size: sizeof(struct key_restriction), GFP_KERNEL); |
145 | if (!restriction) |
146 | return -ENOMEM; |
147 | |
148 | if (id == INTEGRITY_KEYRING_MACHINE) |
149 | restriction->check = restrict_link_by_ca; |
150 | else |
151 | restriction->check = restrict_link_to_ima; |
152 | |
153 | /* |
154 | * MOK keys can only be added through a read-only runtime services |
155 | * UEFI variable during boot. No additional keys shall be allowed to |
156 | * load into the machine keyring following init from userspace. |
157 | */ |
158 | if (id != INTEGRITY_KEYRING_MACHINE) |
159 | perm |= KEY_USR_WRITE; |
160 | |
161 | out: |
162 | ret = __integrity_init_keyring(id, perm, restriction); |
163 | if (ret) |
164 | kfree(objp: restriction); |
165 | return ret; |
166 | } |
167 | |
168 | static int __init integrity_add_key(const unsigned int id, const void *data, |
169 | off_t size, key_perm_t perm) |
170 | { |
171 | key_ref_t key; |
172 | int rc = 0; |
173 | |
174 | if (!keyring[id]) |
175 | return -EINVAL; |
176 | |
177 | key = key_create_or_update(keyring: make_key_ref(key: keyring[id], possession: 1), type: "asymmetric" , |
178 | NULL, payload: data, plen: size, perm, |
179 | KEY_ALLOC_NOT_IN_QUOTA); |
180 | if (IS_ERR(ptr: key)) { |
181 | rc = PTR_ERR(ptr: key); |
182 | pr_err("Problem loading X.509 certificate %d\n" , rc); |
183 | } else { |
184 | pr_notice("Loaded X.509 cert '%s'\n" , |
185 | key_ref_to_ptr(key)->description); |
186 | key_ref_put(key_ref: key); |
187 | } |
188 | |
189 | return rc; |
190 | |
191 | } |
192 | |
193 | int __init integrity_load_x509(const unsigned int id, const char *path) |
194 | { |
195 | void *data = NULL; |
196 | size_t size; |
197 | int rc; |
198 | key_perm_t perm; |
199 | |
200 | rc = kernel_read_file_from_path(path, offset: 0, buf: &data, INT_MAX, NULL, |
201 | id: READING_X509_CERTIFICATE); |
202 | if (rc < 0) { |
203 | pr_err("Unable to open file: %s (%d)" , path, rc); |
204 | return rc; |
205 | } |
206 | size = rc; |
207 | |
208 | perm = (KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_VIEW | KEY_USR_READ; |
209 | |
210 | pr_info("Loading X.509 certificate: %s\n" , path); |
211 | rc = integrity_add_key(id, data: (const void *)data, size, perm); |
212 | |
213 | vfree(addr: data); |
214 | return rc; |
215 | } |
216 | |
217 | int __init integrity_load_cert(const unsigned int id, const char *source, |
218 | const void *data, size_t len, key_perm_t perm) |
219 | { |
220 | if (!data) |
221 | return -EINVAL; |
222 | |
223 | pr_info("Loading X.509 certificate: %s\n" , source); |
224 | return integrity_add_key(id, data, size: len, perm); |
225 | } |
226 | |