hc
2023-11-22 f743a7adbd6e230d66a6206fa115b59fec2d88eb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
/* Module signature checker
 *
 * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
 * Written by David Howells (dhowells@redhat.com)
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public Licence
 * as published by the Free Software Foundation; either version
 * 2 of the Licence, or (at your option) any later version.
 */
 
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/verification.h>
#include <crypto/public_key.h>
#include "module-internal.h"
 
enum pkey_id_type {
   PKEY_ID_PGP,        /* OpenPGP generated key ID */
   PKEY_ID_X509,        /* X.509 arbitrary subjectKeyIdentifier */
   PKEY_ID_PKCS7,        /* Signature in PKCS#7 message */
};
 
/*
 * Module signature information block.
 *
 * The constituents of the signature section are, in order:
 *
 *    - Signer's name
 *    - Key identifier
 *    - Signature data
 *    - Information block
 */
struct module_signature {
   u8    algo;        /* Public-key crypto algorithm [0] */
   u8    hash;        /* Digest algorithm [0] */
   u8    id_type;    /* Key identifier type [PKEY_ID_PKCS7] */
   u8    signer_len;    /* Length of signer's name [0] */
   u8    key_id_len;    /* Length of key identifier [0] */
   u8    __pad[3];
   __be32    sig_len;    /* Length of signature data */
};
 
/*
 * Verify the signature on a module.
 */
int mod_verify_sig(const void *mod, struct load_info *info)
{
   struct module_signature ms;
   size_t sig_len, modlen = info->len;
 
   pr_devel("==>%s(,%zu)\n", __func__, modlen);
 
   if (modlen <= sizeof(ms))
       return -EBADMSG;
 
   memcpy(&ms, mod + (modlen - sizeof(ms)), sizeof(ms));
   modlen -= sizeof(ms);
 
   sig_len = be32_to_cpu(ms.sig_len);
   if (sig_len >= modlen)
       return -EBADMSG;
   modlen -= sig_len;
   info->len = modlen;
 
   if (ms.id_type != PKEY_ID_PKCS7) {
       pr_err("%s: Module is not signed with expected PKCS#7 message\n",
              info->name);
       return -ENOPKG;
   }
 
   if (ms.algo != 0 ||
       ms.hash != 0 ||
       ms.signer_len != 0 ||
       ms.key_id_len != 0 ||
       ms.__pad[0] != 0 ||
       ms.__pad[1] != 0 ||
       ms.__pad[2] != 0) {
       pr_err("%s: PKCS#7 signature info has unexpected non-zero params\n",
              info->name);
       return -EBADMSG;
   }
 
   return verify_pkcs7_signature(mod, modlen, mod + modlen, sig_len,
                     NULL, VERIFYING_MODULE_SIGNATURE,
                     NULL, NULL);
}