1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* Instantiate a public key crypto key from an X.509 Certificate |
3 | * |
4 | * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. |
5 | * Written by David Howells (dhowells@redhat.com) |
6 | */ |
7 | |
8 | #define pr_fmt(fmt) "X.509: "fmt |
9 | #include <crypto/hash.h> |
10 | #include <crypto/sm2.h> |
11 | #include <keys/asymmetric-parser.h> |
12 | #include <keys/asymmetric-subtype.h> |
13 | #include <keys/system_keyring.h> |
14 | #include <linux/module.h> |
15 | #include <linux/kernel.h> |
16 | #include <linux/slab.h> |
17 | #include <linux/string.h> |
18 | #include "asymmetric_keys.h" |
19 | #include "x509_parser.h" |
20 | |
21 | /* |
22 | * Set up the signature parameters in an X.509 certificate. This involves |
23 | * digesting the signed data and extracting the signature. |
24 | */ |
25 | int x509_get_sig_params(struct x509_certificate *cert) |
26 | { |
27 | struct public_key_signature *sig = cert->sig; |
28 | struct crypto_shash *tfm; |
29 | struct shash_desc *desc; |
30 | size_t desc_size; |
31 | int ret; |
32 | |
33 | pr_devel("==>%s()\n" , __func__); |
34 | |
35 | sig->s = kmemdup(p: cert->raw_sig, size: cert->raw_sig_size, GFP_KERNEL); |
36 | if (!sig->s) |
37 | return -ENOMEM; |
38 | |
39 | sig->s_size = cert->raw_sig_size; |
40 | |
41 | /* Allocate the hashing algorithm we're going to need and find out how |
42 | * big the hash operational data will be. |
43 | */ |
44 | tfm = crypto_alloc_shash(alg_name: sig->hash_algo, type: 0, mask: 0); |
45 | if (IS_ERR(ptr: tfm)) { |
46 | if (PTR_ERR(ptr: tfm) == -ENOENT) { |
47 | cert->unsupported_sig = true; |
48 | return 0; |
49 | } |
50 | return PTR_ERR(ptr: tfm); |
51 | } |
52 | |
53 | desc_size = crypto_shash_descsize(tfm) + sizeof(*desc); |
54 | sig->digest_size = crypto_shash_digestsize(tfm); |
55 | |
56 | ret = -ENOMEM; |
57 | sig->digest = kmalloc(size: sig->digest_size, GFP_KERNEL); |
58 | if (!sig->digest) |
59 | goto error; |
60 | |
61 | desc = kzalloc(size: desc_size, GFP_KERNEL); |
62 | if (!desc) |
63 | goto error; |
64 | |
65 | desc->tfm = tfm; |
66 | |
67 | if (strcmp(cert->pub->pkey_algo, "sm2" ) == 0) { |
68 | ret = strcmp(sig->hash_algo, "sm3" ) != 0 ? -EINVAL : |
69 | crypto_shash_init(desc) ?: |
70 | sm2_compute_z_digest(desc, key: cert->pub->key, |
71 | keylen: cert->pub->keylen, dgst: sig->digest) ?: |
72 | crypto_shash_init(desc) ?: |
73 | crypto_shash_update(desc, data: sig->digest, |
74 | len: sig->digest_size) ?: |
75 | crypto_shash_finup(desc, data: cert->tbs, len: cert->tbs_size, |
76 | out: sig->digest); |
77 | } else { |
78 | ret = crypto_shash_digest(desc, data: cert->tbs, len: cert->tbs_size, |
79 | out: sig->digest); |
80 | } |
81 | |
82 | if (ret < 0) |
83 | goto error_2; |
84 | |
85 | ret = is_hash_blacklisted(hash: sig->digest, hash_len: sig->digest_size, |
86 | hash_type: BLACKLIST_HASH_X509_TBS); |
87 | if (ret == -EKEYREJECTED) { |
88 | pr_err("Cert %*phN is blacklisted\n" , |
89 | sig->digest_size, sig->digest); |
90 | cert->blacklisted = true; |
91 | ret = 0; |
92 | } |
93 | |
94 | error_2: |
95 | kfree(objp: desc); |
96 | error: |
97 | crypto_free_shash(tfm); |
98 | pr_devel("<==%s() = %d\n" , __func__, ret); |
99 | return ret; |
100 | } |
101 | |
102 | /* |
103 | * Check for self-signedness in an X.509 cert and if found, check the signature |
104 | * immediately if we can. |
105 | */ |
106 | int x509_check_for_self_signed(struct x509_certificate *cert) |
107 | { |
108 | int ret = 0; |
109 | |
110 | pr_devel("==>%s()\n" , __func__); |
111 | |
112 | if (cert->raw_subject_size != cert->raw_issuer_size || |
113 | memcmp(p: cert->raw_subject, q: cert->raw_issuer, |
114 | size: cert->raw_issuer_size) != 0) |
115 | goto not_self_signed; |
116 | |
117 | if (cert->sig->auth_ids[0] || cert->sig->auth_ids[1]) { |
118 | /* If the AKID is present it may have one or two parts. If |
119 | * both are supplied, both must match. |
120 | */ |
121 | bool a = asymmetric_key_id_same(kid1: cert->skid, kid2: cert->sig->auth_ids[1]); |
122 | bool b = asymmetric_key_id_same(kid1: cert->id, kid2: cert->sig->auth_ids[0]); |
123 | |
124 | if (!a && !b) |
125 | goto not_self_signed; |
126 | |
127 | ret = -EKEYREJECTED; |
128 | if (((a && !b) || (b && !a)) && |
129 | cert->sig->auth_ids[0] && cert->sig->auth_ids[1]) |
130 | goto out; |
131 | } |
132 | |
133 | if (cert->unsupported_sig) { |
134 | ret = 0; |
135 | goto out; |
136 | } |
137 | |
138 | ret = public_key_verify_signature(pkey: cert->pub, sig: cert->sig); |
139 | if (ret < 0) { |
140 | if (ret == -ENOPKG) { |
141 | cert->unsupported_sig = true; |
142 | ret = 0; |
143 | } |
144 | goto out; |
145 | } |
146 | |
147 | pr_devel("Cert Self-signature verified" ); |
148 | cert->self_signed = true; |
149 | |
150 | out: |
151 | pr_devel("<==%s() = %d\n" , __func__, ret); |
152 | return ret; |
153 | |
154 | not_self_signed: |
155 | pr_devel("<==%s() = 0 [not]\n" , __func__); |
156 | return 0; |
157 | } |
158 | |
159 | /* |
160 | * Attempt to parse a data blob for a key as an X509 certificate. |
161 | */ |
162 | static int x509_key_preparse(struct key_preparsed_payload *prep) |
163 | { |
164 | struct asymmetric_key_ids *kids; |
165 | struct x509_certificate *cert; |
166 | const char *q; |
167 | size_t srlen, sulen; |
168 | char *desc = NULL, *p; |
169 | int ret; |
170 | |
171 | cert = x509_cert_parse(data: prep->data, datalen: prep->datalen); |
172 | if (IS_ERR(ptr: cert)) |
173 | return PTR_ERR(ptr: cert); |
174 | |
175 | pr_devel("Cert Issuer: %s\n" , cert->issuer); |
176 | pr_devel("Cert Subject: %s\n" , cert->subject); |
177 | pr_devel("Cert Key Algo: %s\n" , cert->pub->pkey_algo); |
178 | pr_devel("Cert Valid period: %lld-%lld\n" , cert->valid_from, cert->valid_to); |
179 | |
180 | cert->pub->id_type = "X509" ; |
181 | |
182 | if (cert->unsupported_sig) { |
183 | public_key_signature_free(sig: cert->sig); |
184 | cert->sig = NULL; |
185 | } else { |
186 | pr_devel("Cert Signature: %s + %s\n" , |
187 | cert->sig->pkey_algo, cert->sig->hash_algo); |
188 | } |
189 | |
190 | /* Don't permit addition of blacklisted keys */ |
191 | ret = -EKEYREJECTED; |
192 | if (cert->blacklisted) |
193 | goto error_free_cert; |
194 | |
195 | /* Propose a description */ |
196 | sulen = strlen(cert->subject); |
197 | if (cert->raw_skid) { |
198 | srlen = cert->raw_skid_size; |
199 | q = cert->raw_skid; |
200 | } else { |
201 | srlen = cert->raw_serial_size; |
202 | q = cert->raw_serial; |
203 | } |
204 | |
205 | ret = -ENOMEM; |
206 | desc = kmalloc(size: sulen + 2 + srlen * 2 + 1, GFP_KERNEL); |
207 | if (!desc) |
208 | goto error_free_cert; |
209 | p = memcpy(desc, cert->subject, sulen); |
210 | p += sulen; |
211 | *p++ = ':'; |
212 | *p++ = ' '; |
213 | p = bin2hex(dst: p, src: q, count: srlen); |
214 | *p = 0; |
215 | |
216 | kids = kmalloc(size: sizeof(struct asymmetric_key_ids), GFP_KERNEL); |
217 | if (!kids) |
218 | goto error_free_desc; |
219 | kids->id[0] = cert->id; |
220 | kids->id[1] = cert->skid; |
221 | kids->id[2] = asymmetric_key_generate_id(val_1: cert->raw_subject, |
222 | len_1: cert->raw_subject_size, |
223 | val_2: "" , len_2: 0); |
224 | if (IS_ERR(ptr: kids->id[2])) { |
225 | ret = PTR_ERR(ptr: kids->id[2]); |
226 | goto error_free_kids; |
227 | } |
228 | |
229 | /* We're pinning the module by being linked against it */ |
230 | __module_get(module: public_key_subtype.owner); |
231 | prep->payload.data[asym_subtype] = &public_key_subtype; |
232 | prep->payload.data[asym_key_ids] = kids; |
233 | prep->payload.data[asym_crypto] = cert->pub; |
234 | prep->payload.data[asym_auth] = cert->sig; |
235 | prep->description = desc; |
236 | prep->quotalen = 100; |
237 | |
238 | /* We've finished with the certificate */ |
239 | cert->pub = NULL; |
240 | cert->id = NULL; |
241 | cert->skid = NULL; |
242 | cert->sig = NULL; |
243 | desc = NULL; |
244 | kids = NULL; |
245 | ret = 0; |
246 | |
247 | error_free_kids: |
248 | kfree(objp: kids); |
249 | error_free_desc: |
250 | kfree(objp: desc); |
251 | error_free_cert: |
252 | x509_free_certificate(cert); |
253 | return ret; |
254 | } |
255 | |
256 | static struct asymmetric_key_parser x509_key_parser = { |
257 | .owner = THIS_MODULE, |
258 | .name = "x509" , |
259 | .parse = x509_key_preparse, |
260 | }; |
261 | |
262 | /* |
263 | * Module stuff |
264 | */ |
265 | static int __init x509_key_init(void) |
266 | { |
267 | return register_asymmetric_key_parser(&x509_key_parser); |
268 | } |
269 | |
270 | static void __exit x509_key_exit(void) |
271 | { |
272 | unregister_asymmetric_key_parser(&x509_key_parser); |
273 | } |
274 | |
275 | module_init(x509_key_init); |
276 | module_exit(x509_key_exit); |
277 | |
278 | MODULE_DESCRIPTION("X.509 certificate parser" ); |
279 | MODULE_AUTHOR("Red Hat, Inc." ); |
280 | MODULE_LICENSE("GPL" ); |
281 | |