Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

X.509: Extract signature digest and make self-signed cert checks earlier

Extract the signature digest for an X.509 certificate earlier, at the end
of x509_cert_parse() rather than leaving it to the callers thereof since it
has to be called anyway.

Further, immediately after that, check the signature on self-signed
certificates, also rather in the callers of x509_cert_parse().

We note in the x509_certificate struct the following bits of information:

(1) Whether the signature is self-signed (even if we can't check the
signature due to missing crypto).

(2) Whether the key held in the certificate needs unsupported crypto to be
used. We may get a PKCS#7 message with X.509 certs that we can't make
use of - we just ignore them and give ENOPKG at the end it we couldn't
verify anything if at least one of these unusable certs are in the
chain of trust.

(3) Whether the signature held in the certificate needs unsupported crypto
to be checked. We can still use the key held in this certificate,
even if we can't check the signature on it - if it is held in the
system trusted keyring, for instance. We just can't add it to a ring
of trusted keys or follow it further up the chain of trust.

Making these checks earlier allows x509_check_signature() to be removed and
replaced with direct calls to public_key_verify_signature().

Signed-off-by: David Howells <dhowells@redhat.com>

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