cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

pkcs7_trust.c (4692B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/* Validate the trust chain of a PKCS#7 message.
      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) "PKCS7: "fmt
      9#include <linux/kernel.h>
     10#include <linux/export.h>
     11#include <linux/slab.h>
     12#include <linux/err.h>
     13#include <linux/asn1.h>
     14#include <linux/key.h>
     15#include <keys/asymmetric-type.h>
     16#include <crypto/public_key.h>
     17#include "pkcs7_parser.h"
     18
     19/*
     20 * Check the trust on one PKCS#7 SignedInfo block.
     21 */
     22static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
     23				    struct pkcs7_signed_info *sinfo,
     24				    struct key *trust_keyring)
     25{
     26	struct public_key_signature *sig = sinfo->sig;
     27	struct x509_certificate *x509, *last = NULL, *p;
     28	struct key *key;
     29	int ret;
     30
     31	kenter(",%u,", sinfo->index);
     32
     33	if (sinfo->unsupported_crypto) {
     34		kleave(" = -ENOPKG [cached]");
     35		return -ENOPKG;
     36	}
     37
     38	for (x509 = sinfo->signer; x509; x509 = x509->signer) {
     39		if (x509->seen) {
     40			if (x509->verified)
     41				goto verified;
     42			kleave(" = -ENOKEY [cached]");
     43			return -ENOKEY;
     44		}
     45		x509->seen = true;
     46
     47		/* Look to see if this certificate is present in the trusted
     48		 * keys.
     49		 */
     50		key = find_asymmetric_key(trust_keyring,
     51					  x509->id, x509->skid, NULL, false);
     52		if (!IS_ERR(key)) {
     53			/* One of the X.509 certificates in the PKCS#7 message
     54			 * is apparently the same as one we already trust.
     55			 * Verify that the trusted variant can also validate
     56			 * the signature on the descendant.
     57			 */
     58			pr_devel("sinfo %u: Cert %u as key %x\n",
     59				 sinfo->index, x509->index, key_serial(key));
     60			goto matched;
     61		}
     62		if (key == ERR_PTR(-ENOMEM))
     63			return -ENOMEM;
     64
     65		 /* Self-signed certificates form roots of their own, and if we
     66		  * don't know them, then we can't accept them.
     67		  */
     68		if (x509->signer == x509) {
     69			kleave(" = -ENOKEY [unknown self-signed]");
     70			return -ENOKEY;
     71		}
     72
     73		might_sleep();
     74		last = x509;
     75		sig = last->sig;
     76	}
     77
     78	/* No match - see if the root certificate has a signer amongst the
     79	 * trusted keys.
     80	 */
     81	if (last && (last->sig->auth_ids[0] || last->sig->auth_ids[1])) {
     82		key = find_asymmetric_key(trust_keyring,
     83					  last->sig->auth_ids[0],
     84					  last->sig->auth_ids[1],
     85					  NULL, false);
     86		if (!IS_ERR(key)) {
     87			x509 = last;
     88			pr_devel("sinfo %u: Root cert %u signer is key %x\n",
     89				 sinfo->index, x509->index, key_serial(key));
     90			goto matched;
     91		}
     92		if (PTR_ERR(key) != -ENOKEY)
     93			return PTR_ERR(key);
     94	}
     95
     96	/* As a last resort, see if we have a trusted public key that matches
     97	 * the signed info directly.
     98	 */
     99	key = find_asymmetric_key(trust_keyring,
    100				  sinfo->sig->auth_ids[0], NULL, NULL, false);
    101	if (!IS_ERR(key)) {
    102		pr_devel("sinfo %u: Direct signer is key %x\n",
    103			 sinfo->index, key_serial(key));
    104		x509 = NULL;
    105		sig = sinfo->sig;
    106		goto matched;
    107	}
    108	if (PTR_ERR(key) != -ENOKEY)
    109		return PTR_ERR(key);
    110
    111	kleave(" = -ENOKEY [no backref]");
    112	return -ENOKEY;
    113
    114matched:
    115	ret = verify_signature(key, sig);
    116	key_put(key);
    117	if (ret < 0) {
    118		if (ret == -ENOMEM)
    119			return ret;
    120		kleave(" = -EKEYREJECTED [verify %d]", ret);
    121		return -EKEYREJECTED;
    122	}
    123
    124verified:
    125	if (x509) {
    126		x509->verified = true;
    127		for (p = sinfo->signer; p != x509; p = p->signer)
    128			p->verified = true;
    129	}
    130	kleave(" = 0");
    131	return 0;
    132}
    133
    134/**
    135 * pkcs7_validate_trust - Validate PKCS#7 trust chain
    136 * @pkcs7: The PKCS#7 certificate to validate
    137 * @trust_keyring: Signing certificates to use as starting points
    138 *
    139 * Validate that the certificate chain inside the PKCS#7 message intersects
    140 * keys we already know and trust.
    141 *
    142 * Returns, in order of descending priority:
    143 *
    144 *  (*) -EKEYREJECTED if a signature failed to match for which we have a valid
    145 *	key, or:
    146 *
    147 *  (*) 0 if at least one signature chain intersects with the keys in the trust
    148 *	keyring, or:
    149 *
    150 *  (*) -ENOPKG if a suitable crypto module couldn't be found for a check on a
    151 *	chain.
    152 *
    153 *  (*) -ENOKEY if we couldn't find a match for any of the signature chains in
    154 *	the message.
    155 *
    156 * May also return -ENOMEM.
    157 */
    158int pkcs7_validate_trust(struct pkcs7_message *pkcs7,
    159			 struct key *trust_keyring)
    160{
    161	struct pkcs7_signed_info *sinfo;
    162	struct x509_certificate *p;
    163	int cached_ret = -ENOKEY;
    164	int ret;
    165
    166	for (p = pkcs7->certs; p; p = p->next)
    167		p->seen = false;
    168
    169	for (sinfo = pkcs7->signed_infos; sinfo; sinfo = sinfo->next) {
    170		ret = pkcs7_validate_trust_one(pkcs7, sinfo, trust_keyring);
    171		switch (ret) {
    172		case -ENOKEY:
    173			continue;
    174		case -ENOPKG:
    175			if (cached_ret == -ENOKEY)
    176				cached_ret = -ENOPKG;
    177			continue;
    178		case 0:
    179			cached_ret = 0;
    180			continue;
    181		default:
    182			return ret;
    183		}
    184	}
    185
    186	return cached_ret;
    187}
    188EXPORT_SYMBOL_GPL(pkcs7_validate_trust);