LCOV - code coverage report
Current view: top level - crypto/asymmetric_keys - pkcs7_trust.c (source / functions) Hit Total Coverage
Test: Real Lines: 23 49 46.9 %
Date: 2020-10-17 15:46:16 Functions: 0 2 0.0 %
Legend: Neither, QEMU, Real, Both Branches: 0 0 -

           Branch data     Line data    Source code
       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                 :            :  */
      22                 :          3 : static int pkcs7_validate_trust_one(struct pkcs7_message *pkcs7,
      23                 :            :                                     struct pkcs7_signed_info *sinfo,
      24                 :            :                                     struct key *trust_keyring)
      25                 :            : {
      26                 :          3 :         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                 :          3 :         if (sinfo->unsupported_crypto) {
      34                 :            :                 kleave(" = -ENOPKG [cached]");
      35                 :            :                 return -ENOPKG;
      36                 :            :         }
      37                 :            : 
      38                 :          3 :         for (x509 = sinfo->signer; x509; x509 = x509->signer) {
      39                 :          3 :                 if (x509->seen) {
      40                 :          0 :                         if (x509->verified)
      41                 :            :                                 goto verified;
      42                 :            :                         kleave(" = -ENOKEY [cached]");
      43                 :            :                         return -ENOKEY;
      44                 :            :                 }
      45                 :          3 :                 x509->seen = true;
      46                 :            : 
      47                 :            :                 /* Look to see if this certificate is present in the trusted
      48                 :            :                  * keys.
      49                 :            :                  */
      50                 :          3 :                 key = find_asymmetric_key(trust_keyring,
      51                 :          3 :                                           x509->id, x509->skid, false);
      52                 :          3 :                 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                 :          0 :                 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                 :          0 :                 if (x509->signer == x509) {
      69                 :            :                         kleave(" = -ENOKEY [unknown self-signed]");
      70                 :            :                         return -ENOKEY;
      71                 :            :                 }
      72                 :            : 
      73                 :          0 :                 might_sleep();
      74                 :            :                 last = x509;
      75                 :          0 :                 sig = last->sig;
      76                 :            :         }
      77                 :            : 
      78                 :            :         /* No match - see if the root certificate has a signer amongst the
      79                 :            :          * trusted keys.
      80                 :            :          */
      81                 :          0 :         if (last && (last->sig->auth_ids[0] || last->sig->auth_ids[1])) {
      82                 :          0 :                 key = find_asymmetric_key(trust_keyring,
      83                 :            :                                           last->sig->auth_ids[0],
      84                 :          0 :                                           last->sig->auth_ids[1],
      85                 :            :                                           false);
      86                 :          0 :                 if (!IS_ERR(key)) {
      87                 :          0 :                         x509 = last;
      88                 :            :                         pr_devel("sinfo %u: Root cert %u signer is key %x\n",
      89                 :            :                                  sinfo->index, x509->index, key_serial(key));
      90                 :          0 :                         goto matched;
      91                 :            :                 }
      92                 :          0 :                 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                 :          0 :         key = find_asymmetric_key(trust_keyring,
     100                 :          0 :                                   sinfo->sig->auth_ids[0], NULL, false);
     101                 :          0 :         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                 :          0 :                 sig = sinfo->sig;
     106                 :          0 :                 goto matched;
     107                 :            :         }
     108                 :          0 :         if (PTR_ERR(key) != -ENOKEY)
     109                 :          0 :                 return PTR_ERR(key);
     110                 :            : 
     111                 :            :         kleave(" = -ENOKEY [no backref]");
     112                 :            :         return -ENOKEY;
     113                 :            : 
     114                 :            : matched:
     115                 :          3 :         ret = verify_signature(key, sig);
     116                 :          3 :         key_put(key);
     117                 :          3 :         if (ret < 0) {
     118                 :          0 :                 if (ret == -ENOMEM)
     119                 :          0 :                         return ret;
     120                 :            :                 kleave(" = -EKEYREJECTED [verify %d]", ret);
     121                 :            :                 return -EKEYREJECTED;
     122                 :            :         }
     123                 :            : 
     124                 :            : verified:
     125                 :          3 :         if (x509) {
     126                 :          3 :                 x509->verified = true;
     127                 :          3 :                 for (p = sinfo->signer; p != x509; p = p->signer)
     128                 :          0 :                         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                 :            :  */
     158                 :          3 : int 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                 :          3 :         for (p = pkcs7->certs; p; p = p->next)
     167                 :          3 :                 p->seen = false;
     168                 :            : 
     169                 :          3 :         for (sinfo = pkcs7->signed_infos; sinfo; sinfo = sinfo->next) {
     170                 :          3 :                 ret = pkcs7_validate_trust_one(pkcs7, sinfo, trust_keyring);
     171                 :          3 :                 switch (ret) {
     172                 :            :                 case -ENOKEY:
     173                 :          0 :                         continue;
     174                 :            :                 case -ENOPKG:
     175                 :          0 :                         if (cached_ret == -ENOKEY)
     176                 :            :                                 cached_ret = -ENOPKG;
     177                 :          0 :                         continue;
     178                 :            :                 case 0:
     179                 :            :                         cached_ret = 0;
     180                 :          3 :                         continue;
     181                 :            :                 default:
     182                 :          0 :                         return ret;
     183                 :            :                 }
     184                 :            :         }
     185                 :            : 
     186                 :          3 :         return cached_ret;
     187                 :            : }
     188                 :            : EXPORT_SYMBOL_GPL(pkcs7_validate_trust);
    

Generated by: LCOV version 1.14