diff options
Diffstat (limited to 'crypto/asymmetric_keys')
-rw-r--r-- | crypto/asymmetric_keys/pkcs7_verify.c | 38 | ||||
-rw-r--r-- | crypto/asymmetric_keys/x509_cert_parser.c | 10 | ||||
-rw-r--r-- | crypto/asymmetric_keys/x509_parser.h | 7 | ||||
-rw-r--r-- | crypto/asymmetric_keys/x509_public_key.c | 126 |
4 files changed, 110 insertions, 71 deletions
diff --git a/crypto/asymmetric_keys/pkcs7_verify.c b/crypto/asymmetric_keys/pkcs7_verify.c index 1426f03e630b..44b746e9df1b 100644 --- a/crypto/asymmetric_keys/pkcs7_verify.c +++ b/crypto/asymmetric_keys/pkcs7_verify.c | |||
@@ -190,9 +190,8 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7, | |||
190 | x509->subject, | 190 | x509->subject, |
191 | x509->raw_serial_size, x509->raw_serial); | 191 | x509->raw_serial_size, x509->raw_serial); |
192 | x509->seen = true; | 192 | x509->seen = true; |
193 | ret = x509_get_sig_params(x509); | 193 | if (x509->unsupported_key) |
194 | if (ret < 0) | 194 | goto unsupported_crypto_in_x509; |
195 | goto maybe_missing_crypto_in_x509; | ||
196 | 195 | ||
197 | pr_debug("- issuer %s\n", x509->issuer); | 196 | pr_debug("- issuer %s\n", x509->issuer); |
198 | sig = x509->sig; | 197 | sig = x509->sig; |
@@ -203,22 +202,14 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7, | |||
203 | pr_debug("- authkeyid.skid %*phN\n", | 202 | pr_debug("- authkeyid.skid %*phN\n", |
204 | sig->auth_ids[1]->len, sig->auth_ids[1]->data); | 203 | sig->auth_ids[1]->len, sig->auth_ids[1]->data); |
205 | 204 | ||
206 | if ((!x509->sig->auth_ids[0] && !x509->sig->auth_ids[1]) || | 205 | if (x509->self_signed) { |
207 | strcmp(x509->subject, x509->issuer) == 0) { | ||
208 | /* If there's no authority certificate specified, then | 206 | /* If there's no authority certificate specified, then |
209 | * the certificate must be self-signed and is the root | 207 | * the certificate must be self-signed and is the root |
210 | * of the chain. Likewise if the cert is its own | 208 | * of the chain. Likewise if the cert is its own |
211 | * authority. | 209 | * authority. |
212 | */ | 210 | */ |
213 | pr_debug("- no auth?\n"); | 211 | if (x509->unsupported_sig) |
214 | if (x509->raw_subject_size != x509->raw_issuer_size || | 212 | goto unsupported_crypto_in_x509; |
215 | memcmp(x509->raw_subject, x509->raw_issuer, | ||
216 | x509->raw_issuer_size) != 0) | ||
217 | return 0; | ||
218 | |||
219 | ret = x509_check_signature(x509->pub, x509); | ||
220 | if (ret < 0) | ||
221 | goto maybe_missing_crypto_in_x509; | ||
222 | x509->signer = x509; | 213 | x509->signer = x509; |
223 | pr_debug("- self-signed\n"); | 214 | pr_debug("- self-signed\n"); |
224 | return 0; | 215 | return 0; |
@@ -270,7 +261,7 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7, | |||
270 | sinfo->index); | 261 | sinfo->index); |
271 | return 0; | 262 | return 0; |
272 | } | 263 | } |
273 | ret = x509_check_signature(p->pub, x509); | 264 | ret = public_key_verify_signature(p->pub, p->sig); |
274 | if (ret < 0) | 265 | if (ret < 0) |
275 | return ret; | 266 | return ret; |
276 | x509->signer = p; | 267 | x509->signer = p; |
@@ -282,16 +273,14 @@ static int pkcs7_verify_sig_chain(struct pkcs7_message *pkcs7, | |||
282 | might_sleep(); | 273 | might_sleep(); |
283 | } | 274 | } |
284 | 275 | ||
285 | maybe_missing_crypto_in_x509: | 276 | unsupported_crypto_in_x509: |
286 | /* Just prune the certificate chain at this point if we lack some | 277 | /* Just prune the certificate chain at this point if we lack some |
287 | * crypto module to go further. Note, however, we don't want to set | 278 | * crypto module to go further. Note, however, we don't want to set |
288 | * sinfo->missing_crypto as the signed info block may still be | 279 | * sinfo->unsupported_crypto as the signed info block may still be |
289 | * validatable against an X.509 cert lower in the chain that we have a | 280 | * validatable against an X.509 cert lower in the chain that we have a |
290 | * trusted copy of. | 281 | * trusted copy of. |
291 | */ | 282 | */ |
292 | if (ret == -ENOPKG) | 283 | return 0; |
293 | return 0; | ||
294 | return ret; | ||
295 | } | 284 | } |
296 | 285 | ||
297 | /* | 286 | /* |
@@ -378,9 +367,8 @@ int pkcs7_verify(struct pkcs7_message *pkcs7, | |||
378 | enum key_being_used_for usage) | 367 | enum key_being_used_for usage) |
379 | { | 368 | { |
380 | struct pkcs7_signed_info *sinfo; | 369 | struct pkcs7_signed_info *sinfo; |
381 | struct x509_certificate *x509; | ||
382 | int enopkg = -ENOPKG; | 370 | int enopkg = -ENOPKG; |
383 | int ret, n; | 371 | int ret; |
384 | 372 | ||
385 | kenter(""); | 373 | kenter(""); |
386 | 374 | ||
@@ -422,12 +410,6 @@ int pkcs7_verify(struct pkcs7_message *pkcs7, | |||
422 | return -EINVAL; | 410 | return -EINVAL; |
423 | } | 411 | } |
424 | 412 | ||
425 | for (n = 0, x509 = pkcs7->certs; x509; x509 = x509->next, n++) { | ||
426 | ret = x509_get_sig_params(x509); | ||
427 | if (ret < 0) | ||
428 | return ret; | ||
429 | } | ||
430 | |||
431 | for (sinfo = pkcs7->signed_infos; sinfo; sinfo = sinfo->next) { | 413 | for (sinfo = pkcs7->signed_infos; sinfo; sinfo = sinfo->next) { |
432 | ret = pkcs7_verify_one(pkcs7, sinfo); | 414 | ret = pkcs7_verify_one(pkcs7, sinfo); |
433 | if (ret < 0) { | 415 | if (ret < 0) { |
diff --git a/crypto/asymmetric_keys/x509_cert_parser.c b/crypto/asymmetric_keys/x509_cert_parser.c index a2fefa713614..865f46ea724f 100644 --- a/crypto/asymmetric_keys/x509_cert_parser.c +++ b/crypto/asymmetric_keys/x509_cert_parser.c | |||
@@ -108,6 +108,11 @@ struct x509_certificate *x509_cert_parse(const void *data, size_t datalen) | |||
108 | 108 | ||
109 | cert->pub->keylen = ctx->key_size; | 109 | cert->pub->keylen = ctx->key_size; |
110 | 110 | ||
111 | /* Grab the signature bits */ | ||
112 | ret = x509_get_sig_params(cert); | ||
113 | if (ret < 0) | ||
114 | goto error_decode; | ||
115 | |||
111 | /* Generate cert issuer + serial number key ID */ | 116 | /* Generate cert issuer + serial number key ID */ |
112 | kid = asymmetric_key_generate_id(cert->raw_serial, | 117 | kid = asymmetric_key_generate_id(cert->raw_serial, |
113 | cert->raw_serial_size, | 118 | cert->raw_serial_size, |
@@ -119,6 +124,11 @@ struct x509_certificate *x509_cert_parse(const void *data, size_t datalen) | |||
119 | } | 124 | } |
120 | cert->id = kid; | 125 | cert->id = kid; |
121 | 126 | ||
127 | /* Detect self-signed certificates */ | ||
128 | ret = x509_check_for_self_signed(cert); | ||
129 | if (ret < 0) | ||
130 | goto error_decode; | ||
131 | |||
122 | kfree(ctx); | 132 | kfree(ctx); |
123 | return cert; | 133 | return cert; |
124 | 134 | ||
diff --git a/crypto/asymmetric_keys/x509_parser.h b/crypto/asymmetric_keys/x509_parser.h index 26a4d83e4e6d..f24f4d808e7f 100644 --- a/crypto/asymmetric_keys/x509_parser.h +++ b/crypto/asymmetric_keys/x509_parser.h | |||
@@ -40,7 +40,9 @@ struct x509_certificate { | |||
40 | bool seen; /* Infinite recursion prevention */ | 40 | bool seen; /* Infinite recursion prevention */ |
41 | bool verified; | 41 | bool verified; |
42 | bool trusted; | 42 | bool trusted; |
43 | bool unsupported_crypto; /* T if can't be verified due to missing crypto */ | 43 | bool self_signed; /* T if self-signed (check unsupported_sig too) */ |
44 | bool unsupported_key; /* T if key uses unsupported crypto */ | ||
45 | bool unsupported_sig; /* T if signature uses unsupported crypto */ | ||
44 | }; | 46 | }; |
45 | 47 | ||
46 | /* | 48 | /* |
@@ -56,5 +58,4 @@ extern int x509_decode_time(time64_t *_t, size_t hdrlen, | |||
56 | * x509_public_key.c | 58 | * x509_public_key.c |
57 | */ | 59 | */ |
58 | extern int x509_get_sig_params(struct x509_certificate *cert); | 60 | extern int x509_get_sig_params(struct x509_certificate *cert); |
59 | extern int x509_check_signature(const struct public_key *pub, | 61 | extern int x509_check_for_self_signed(struct x509_certificate *cert); |
60 | struct x509_certificate *cert); | ||
diff --git a/crypto/asymmetric_keys/x509_public_key.c b/crypto/asymmetric_keys/x509_public_key.c index 4cd102de174c..752d8d5b48fa 100644 --- a/crypto/asymmetric_keys/x509_public_key.c +++ b/crypto/asymmetric_keys/x509_public_key.c | |||
@@ -161,10 +161,17 @@ int x509_get_sig_params(struct x509_certificate *cert) | |||
161 | 161 | ||
162 | pr_devel("==>%s()\n", __func__); | 162 | pr_devel("==>%s()\n", __func__); |
163 | 163 | ||
164 | if (cert->unsupported_crypto) | 164 | if (!cert->pub->pkey_algo) |
165 | return -ENOPKG; | 165 | cert->unsupported_key = true; |
166 | if (sig->s) | 166 | |
167 | if (!sig->pkey_algo) | ||
168 | cert->unsupported_sig = true; | ||
169 | |||
170 | /* We check the hash if we can - even if we can't then verify it */ | ||
171 | if (!sig->hash_algo) { | ||
172 | cert->unsupported_sig = true; | ||
167 | return 0; | 173 | return 0; |
174 | } | ||
168 | 175 | ||
169 | sig->s = kmemdup(cert->raw_sig, cert->raw_sig_size, GFP_KERNEL); | 176 | sig->s = kmemdup(cert->raw_sig, cert->raw_sig_size, GFP_KERNEL); |
170 | if (!sig->s) | 177 | if (!sig->s) |
@@ -178,8 +185,8 @@ int x509_get_sig_params(struct x509_certificate *cert) | |||
178 | tfm = crypto_alloc_shash(sig->hash_algo, 0, 0); | 185 | tfm = crypto_alloc_shash(sig->hash_algo, 0, 0); |
179 | if (IS_ERR(tfm)) { | 186 | if (IS_ERR(tfm)) { |
180 | if (PTR_ERR(tfm) == -ENOENT) { | 187 | if (PTR_ERR(tfm) == -ENOENT) { |
181 | cert->unsupported_crypto = true; | 188 | cert->unsupported_sig = true; |
182 | return -ENOPKG; | 189 | return 0; |
183 | } | 190 | } |
184 | return PTR_ERR(tfm); | 191 | return PTR_ERR(tfm); |
185 | } | 192 | } |
@@ -212,29 +219,53 @@ error: | |||
212 | pr_devel("<==%s() = %d\n", __func__, ret); | 219 | pr_devel("<==%s() = %d\n", __func__, ret); |
213 | return ret; | 220 | return ret; |
214 | } | 221 | } |
215 | EXPORT_SYMBOL_GPL(x509_get_sig_params); | ||
216 | 222 | ||
217 | /* | 223 | /* |
218 | * Check the signature on a certificate using the provided public key | 224 | * Check for self-signedness in an X.509 cert and if found, check the signature |
225 | * immediately if we can. | ||
219 | */ | 226 | */ |
220 | int x509_check_signature(const struct public_key *pub, | 227 | int x509_check_for_self_signed(struct x509_certificate *cert) |
221 | struct x509_certificate *cert) | ||
222 | { | 228 | { |
223 | int ret; | 229 | int ret = 0; |
224 | 230 | ||
225 | pr_devel("==>%s()\n", __func__); | 231 | pr_devel("==>%s()\n", __func__); |
226 | 232 | ||
227 | ret = x509_get_sig_params(cert); | 233 | if (cert->sig->auth_ids[0] || cert->sig->auth_ids[1]) { |
228 | if (ret < 0) | 234 | /* If the AKID is present it may have one or two parts. If |
229 | return ret; | 235 | * both are supplied, both must match. |
236 | */ | ||
237 | bool a = asymmetric_key_id_same(cert->skid, cert->sig->auth_ids[1]); | ||
238 | bool b = asymmetric_key_id_same(cert->id, cert->sig->auth_ids[0]); | ||
239 | |||
240 | if (!a && !b) | ||
241 | goto not_self_signed; | ||
242 | |||
243 | ret = -EKEYREJECTED; | ||
244 | if (((a && !b) || (b && !a)) && | ||
245 | cert->sig->auth_ids[0] && cert->sig->auth_ids[1]) | ||
246 | goto out; | ||
247 | } | ||
248 | |||
249 | ret = public_key_verify_signature(cert->pub, cert->sig); | ||
250 | if (ret < 0) { | ||
251 | if (ret == -ENOPKG) { | ||
252 | cert->unsupported_sig = true; | ||
253 | ret = 0; | ||
254 | } | ||
255 | goto out; | ||
256 | } | ||
257 | |||
258 | pr_devel("Cert Self-signature verified"); | ||
259 | cert->self_signed = true; | ||
230 | 260 | ||
231 | ret = public_key_verify_signature(pub, cert->sig); | 261 | out: |
232 | if (ret == -ENOPKG) | 262 | pr_devel("<==%s() = %d\n", __func__, ret); |
233 | cert->unsupported_crypto = true; | ||
234 | pr_debug("Cert Verification: %d\n", ret); | ||
235 | return ret; | 263 | return ret; |
264 | |||
265 | not_self_signed: | ||
266 | pr_devel("<==%s() = 0 [not]\n", __func__); | ||
267 | return 0; | ||
236 | } | 268 | } |
237 | EXPORT_SYMBOL_GPL(x509_check_signature); | ||
238 | 269 | ||
239 | /* | 270 | /* |
240 | * Check the new certificate against the ones in the trust keyring. If one of | 271 | * Check the new certificate against the ones in the trust keyring. If one of |
@@ -252,22 +283,30 @@ static int x509_validate_trust(struct x509_certificate *cert, | |||
252 | struct key *key; | 283 | struct key *key; |
253 | int ret = 1; | 284 | int ret = 1; |
254 | 285 | ||
286 | if (!sig->auth_ids[0] && !sig->auth_ids[1]) | ||
287 | return 1; | ||
288 | |||
255 | if (!trust_keyring) | 289 | if (!trust_keyring) |
256 | return -EOPNOTSUPP; | 290 | return -EOPNOTSUPP; |
257 | |||
258 | if (ca_keyid && !asymmetric_key_id_partial(sig->auth_ids[1], ca_keyid)) | 291 | if (ca_keyid && !asymmetric_key_id_partial(sig->auth_ids[1], ca_keyid)) |
259 | return -EPERM; | 292 | return -EPERM; |
293 | if (cert->unsupported_sig) | ||
294 | return -ENOPKG; | ||
260 | 295 | ||
261 | key = x509_request_asymmetric_key(trust_keyring, | 296 | key = x509_request_asymmetric_key(trust_keyring, |
262 | sig->auth_ids[0], sig->auth_ids[1], | 297 | sig->auth_ids[0], sig->auth_ids[1], |
263 | false); | 298 | false); |
264 | if (!IS_ERR(key)) { | 299 | if (IS_ERR(key)) |
265 | if (!use_builtin_keys | 300 | return PTR_ERR(key); |
266 | || test_bit(KEY_FLAG_BUILTIN, &key->flags)) | 301 | |
267 | ret = x509_check_signature(key->payload.data[asym_crypto], | 302 | if (!use_builtin_keys || |
268 | cert); | 303 | test_bit(KEY_FLAG_BUILTIN, &key->flags)) { |
269 | key_put(key); | 304 | ret = public_key_verify_signature( |
305 | key->payload.data[asym_crypto], cert->sig); | ||
306 | if (ret == -ENOPKG) | ||
307 | cert->unsupported_sig = true; | ||
270 | } | 308 | } |
309 | key_put(key); | ||
271 | return ret; | 310 | return ret; |
272 | } | 311 | } |
273 | 312 | ||
@@ -290,34 +329,41 @@ static int x509_key_preparse(struct key_preparsed_payload *prep) | |||
290 | pr_devel("Cert Issuer: %s\n", cert->issuer); | 329 | pr_devel("Cert Issuer: %s\n", cert->issuer); |
291 | pr_devel("Cert Subject: %s\n", cert->subject); | 330 | pr_devel("Cert Subject: %s\n", cert->subject); |
292 | 331 | ||
293 | if (!cert->pub->pkey_algo || | 332 | if (cert->unsupported_key) { |
294 | !cert->sig->pkey_algo || | ||
295 | !cert->sig->hash_algo) { | ||
296 | ret = -ENOPKG; | 333 | ret = -ENOPKG; |
297 | goto error_free_cert; | 334 | goto error_free_cert; |
298 | } | 335 | } |
299 | 336 | ||
300 | pr_devel("Cert Key Algo: %s\n", cert->pub->pkey_algo); | 337 | pr_devel("Cert Key Algo: %s\n", cert->pub->pkey_algo); |
301 | pr_devel("Cert Valid period: %lld-%lld\n", cert->valid_from, cert->valid_to); | 338 | pr_devel("Cert Valid period: %lld-%lld\n", cert->valid_from, cert->valid_to); |
302 | pr_devel("Cert Signature: %s + %s\n", | ||
303 | cert->sig->pkey_algo, | ||
304 | cert->sig->hash_algo); | ||
305 | 339 | ||
306 | cert->pub->id_type = "X509"; | 340 | cert->pub->id_type = "X509"; |
307 | 341 | ||
308 | /* Check the signature on the key if it appears to be self-signed */ | 342 | /* See if we can derive the trustability of this certificate. |
309 | if ((!cert->sig->auth_ids[0] && !cert->sig->auth_ids[1]) || | 343 | * |
310 | asymmetric_key_id_same(cert->skid, cert->sig->auth_ids[1]) || | 344 | * When it comes to self-signed certificates, we cannot evaluate |
311 | asymmetric_key_id_same(cert->id, cert->sig->auth_ids[0])) { | 345 | * trustedness except by the fact that we obtained it from a trusted |
312 | ret = x509_check_signature(cert->pub, cert); /* self-signed */ | 346 | * location. So we just rely on x509_validate_trust() failing in this |
313 | if (ret < 0) | 347 | * case. |
314 | goto error_free_cert; | 348 | * |
315 | } else if (!prep->trusted) { | 349 | * Note that there's a possibility of a self-signed cert matching a |
350 | * cert that we have (most likely a duplicate that we already trust) - | ||
351 | * in which case it will be marked trusted. | ||
352 | */ | ||
353 | if (cert->unsupported_sig || cert->self_signed) { | ||
354 | public_key_signature_free(cert->sig); | ||
355 | cert->sig = NULL; | ||
356 | } else { | ||
357 | pr_devel("Cert Signature: %s + %s\n", | ||
358 | cert->sig->pkey_algo, cert->sig->hash_algo); | ||
359 | |||
316 | ret = x509_validate_trust(cert, get_system_trusted_keyring()); | 360 | ret = x509_validate_trust(cert, get_system_trusted_keyring()); |
317 | if (ret) | 361 | if (ret) |
318 | ret = x509_validate_trust(cert, get_ima_mok_keyring()); | 362 | ret = x509_validate_trust(cert, get_ima_mok_keyring()); |
363 | if (ret == -EKEYREJECTED) | ||
364 | goto error_free_cert; | ||
319 | if (!ret) | 365 | if (!ret) |
320 | prep->trusted = 1; | 366 | prep->trusted = true; |
321 | } | 367 | } |
322 | 368 | ||
323 | /* Propose a description */ | 369 | /* Propose a description */ |