diff options
Diffstat (limited to 'crypto/asymmetric_keys/pkcs7_trust.c')
-rw-r--r-- | crypto/asymmetric_keys/pkcs7_trust.c | 90 |
1 files changed, 62 insertions, 28 deletions
diff --git a/crypto/asymmetric_keys/pkcs7_trust.c b/crypto/asymmetric_keys/pkcs7_trust.c index e666eb011a85..1d29376072da 100644 --- a/crypto/asymmetric_keys/pkcs7_trust.c +++ b/crypto/asymmetric_keys/pkcs7_trust.c @@ -23,9 +23,9 @@ /** * Check the trust on one PKCS#7 SignedInfo block. */ -int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7, - struct pkcs7_signed_info *sinfo, - struct key *trust_keyring) +static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7, + struct pkcs7_signed_info *sinfo, + struct key *trust_keyring) { struct public_key_signature *sig = &sinfo->sig; struct x509_certificate *x509, *last = NULL, *p; @@ -35,6 +35,11 @@ int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7, kenter(",%u,", sinfo->index); + if (sinfo->unsupported_crypto) { + kleave(" = -ENOPKG [cached]"); + return -ENOPKG; + } + for (x509 = sinfo->signer; x509; x509 = x509->signer) { if (x509->seen) { if (x509->verified) { @@ -49,15 +54,18 @@ int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7, /* Look to see if this certificate is present in the trusted * keys. */ - key = x509_request_asymmetric_key(trust_keyring, x509->subject, - x509->fingerprint); - if (!IS_ERR(key)) + key = x509_request_asymmetric_key(trust_keyring, x509->id, + false); + if (!IS_ERR(key)) { /* One of the X.509 certificates in the PKCS#7 message * is apparently the same as one we already trust. * Verify that the trusted variant can also validate * the signature on the descendant. */ + pr_devel("sinfo %u: Cert %u as key %x\n", + sinfo->index, x509->index, key_serial(key)); goto matched; + } if (key == ERR_PTR(-ENOMEM)) return -ENOMEM; @@ -77,16 +85,36 @@ int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7, /* No match - see if the root certificate has a signer amongst the * trusted keys. */ - if (!last || !last->issuer || !last->authority) { - kleave(" = -ENOKEY [no backref]"); - return -ENOKEY; + if (last && last->authority) { + key = x509_request_asymmetric_key(trust_keyring, last->authority, + false); + if (!IS_ERR(key)) { + x509 = last; + pr_devel("sinfo %u: Root cert %u signer is key %x\n", + sinfo->index, x509->index, key_serial(key)); + goto matched; + } + if (PTR_ERR(key) != -ENOKEY) + return PTR_ERR(key); + } + + /* As a last resort, see if we have a trusted public key that matches + * the signed info directly. + */ + key = x509_request_asymmetric_key(trust_keyring, + sinfo->signing_cert_id, + false); + if (!IS_ERR(key)) { + pr_devel("sinfo %u: Direct signer is key %x\n", + sinfo->index, key_serial(key)); + x509 = NULL; + goto matched; } + if (PTR_ERR(key) != -ENOKEY) + return PTR_ERR(key); - key = x509_request_asymmetric_key(trust_keyring, last->issuer, - last->authority); - if (IS_ERR(key)) - return PTR_ERR(key) == -ENOMEM ? -ENOMEM : -ENOKEY; - x509 = last; + kleave(" = -ENOKEY [no backref]"); + return -ENOKEY; matched: ret = verify_signature(key, sig); @@ -100,10 +128,12 @@ matched: } verified: - x509->verified = true; - for (p = sinfo->signer; p != x509; p = p->signer) { - p->verified = true; - p->trusted = trusted; + if (x509) { + x509->verified = true; + for (p = sinfo->signer; p != x509; p = p->signer) { + p->verified = true; + p->trusted = trusted; + } } sinfo->trusted = trusted; kleave(" = 0"); @@ -141,24 +171,28 @@ int pkcs7_validate_trust(struct pkcs7_message *pkcs7, { struct pkcs7_signed_info *sinfo; struct x509_certificate *p; - int cached_ret = 0, ret; + int cached_ret = -ENOKEY; + int ret; for (p = pkcs7->certs; p; p = p->next) p->seen = false; for (sinfo = pkcs7->signed_infos; sinfo; sinfo = sinfo->next) { ret = pkcs7_validate_trust_one(pkcs7, sinfo, trust_keyring); - if (ret < 0) { - if (ret == -ENOPKG) { + switch (ret) { + case -ENOKEY: + continue; + case -ENOPKG: + if (cached_ret == -ENOKEY) cached_ret = -ENOPKG; - } else if (ret == -ENOKEY) { - if (cached_ret == 0) - cached_ret = -ENOKEY; - } else { - return ret; - } + continue; + case 0: + *_trusted |= sinfo->trusted; + cached_ret = 0; + continue; + default: + return ret; } - *_trusted |= sinfo->trusted; } return cached_ret; |