summaryrefslogtreecommitdiff
path: root/crypto/asymmetric_keys/pkcs7_trust.c
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2014-09-16 17:38:07 +0100
committerDavid Howells <dhowells@redhat.com>2014-09-16 17:38:07 +0100
commite8ad2d9b5ee05ffc5c49d1dc2731330ad276ae20 (patch)
treeea50915321b345c3d2973fe5259038ccfceda9f8 /crypto/asymmetric_keys/pkcs7_trust.c
parent59d384b06776928f95a18d22efc1b9dfad4cc36e (diff)
parent4fa8d06586307c5403958f1c67120957b0d1ee81 (diff)
downloadlinux-crypto-e8ad2d9b5ee05ffc5c49d1dc2731330ad276ae20.tar.gz
linux-crypto-e8ad2d9b5ee05ffc5c49d1dc2731330ad276ae20.zip
Merge tag 'keys-pkcs7-20140916' into keys-next
Changes for next to improve the matching of asymmetric keys and to improve the handling of PKCS#7 certificates: (1) Provide a method to preparse the data supplied for matching a key. This permits they key type to extract out the bits it needs for matching once only. Further, the type of search (direct lookup or iterative) can be set and the function used to actually check the match can be set by preparse rather than being hard coded for the type. (2) Improves asymmetric keys identification. Keys derived from X.509 certs now get labelled with IDs derived from their issuer and certificate number (required to match PKCS#7) and from their SKID and subject (required to match X.509). IDs are now binary and match criterion preparsing is provided so that criteria can be turned into binary blobs to make matching faster. (3) Improves PKCS#7 message handling to permit PKCS#7 messages without X.509 cert lists to be matched to trusted keys, thereby allowing minimally sized PKCS#7 certs to be used. (4) Improves PKCS#7 message handling to better handle certificate chains that are broken due to unsupported crypto that can otherwise by used to intersect a trust keyring. These must go on top of the PKCS#7 parser cleanup fixes. Signed-off-by: David Howells <dhowells@redhat.com>
Diffstat (limited to 'crypto/asymmetric_keys/pkcs7_trust.c')
-rw-r--r--crypto/asymmetric_keys/pkcs7_trust.c81
1 files changed, 56 insertions, 25 deletions
diff --git a/crypto/asymmetric_keys/pkcs7_trust.c b/crypto/asymmetric_keys/pkcs7_trust.c
index fad888ea..ae47be61 100644
--- a/crypto/asymmetric_keys/pkcs7_trust.c
+++ b/crypto/asymmetric_keys/pkcs7_trust.c
@@ -35,6 +35,11 @@ static 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,17 @@ static 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);
+ 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 +84,34 @@ static 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);
+ 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);
+ 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 +125,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 +168,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;