Blame view

kernel/module_signing.c 5.9 KB
106a4ee25   Rusty Russell   module: signature...
1
2
3
4
5
6
7
8
9
10
11
12
13
  /* 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/err.h>
48ba2462a   David Howells   MODSIGN: Implemen...
14
15
16
  #include <crypto/public_key.h>
  #include <crypto/hash.h>
  #include <keys/asymmetric-type.h>
b56e5a17b   David Howells   KEYS: Separate th...
17
  #include <keys/system_keyring.h>
106a4ee25   Rusty Russell   module: signature...
18
19
20
  #include "module-internal.h"
  
  /*
48ba2462a   David Howells   MODSIGN: Implemen...
21
22
23
24
25
26
27
28
29
30
   * 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 {
12e130b04   David Howells   MODSIGN: Don't us...
31
  	u8	algo;		/* Public-key crypto algorithm [enum pkey_algo] */
3fe78ca2f   Dmitry Kasatkin   keys: change asym...
32
  	u8	hash;		/* Digest algorithm [enum hash_algo] */
12e130b04   David Howells   MODSIGN: Don't us...
33
34
35
36
37
  	u8	id_type;	/* Key identifier type [enum pkey_id_type] */
  	u8	signer_len;	/* Length of signer's name */
  	u8	key_id_len;	/* Length of key identifier */
  	u8	__pad[3];
  	__be32	sig_len;	/* Length of signature data */
48ba2462a   David Howells   MODSIGN: Implemen...
38
39
40
41
42
  };
  
  /*
   * Digest the module contents.
   */
3fe78ca2f   Dmitry Kasatkin   keys: change asym...
43
  static struct public_key_signature *mod_make_digest(enum hash_algo hash,
48ba2462a   David Howells   MODSIGN: Implemen...
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
  						    const void *mod,
  						    unsigned long modlen)
  {
  	struct public_key_signature *pks;
  	struct crypto_shash *tfm;
  	struct shash_desc *desc;
  	size_t digest_size, desc_size;
  	int ret;
  
  	pr_devel("==>%s()
  ", __func__);
  	
  	/* Allocate the hashing algorithm we're going to need and find out how
  	 * big the hash operational data will be.
  	 */
3fe78ca2f   Dmitry Kasatkin   keys: change asym...
59
  	tfm = crypto_alloc_shash(hash_algo_name[hash], 0, 0);
48ba2462a   David Howells   MODSIGN: Implemen...
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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
  	if (IS_ERR(tfm))
  		return (PTR_ERR(tfm) == -ENOENT) ? ERR_PTR(-ENOPKG) : ERR_CAST(tfm);
  
  	desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
  	digest_size = crypto_shash_digestsize(tfm);
  
  	/* We allocate the hash operational data storage on the end of our
  	 * context data and the digest output buffer on the end of that.
  	 */
  	ret = -ENOMEM;
  	pks = kzalloc(digest_size + sizeof(*pks) + desc_size, GFP_KERNEL);
  	if (!pks)
  		goto error_no_pks;
  
  	pks->pkey_hash_algo	= hash;
  	pks->digest		= (u8 *)pks + sizeof(*pks) + desc_size;
  	pks->digest_size	= digest_size;
  
  	desc = (void *)pks + sizeof(*pks);
  	desc->tfm   = tfm;
  	desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
  
  	ret = crypto_shash_init(desc);
  	if (ret < 0)
  		goto error;
  
  	ret = crypto_shash_finup(desc, mod, modlen, pks->digest);
  	if (ret < 0)
  		goto error;
  
  	crypto_free_shash(tfm);
  	pr_devel("<==%s() = ok
  ", __func__);
  	return pks;
  
  error:
  	kfree(pks);
  error_no_pks:
  	crypto_free_shash(tfm);
  	pr_devel("<==%s() = %d
  ", __func__, ret);
  	return ERR_PTR(ret);
  }
  
  /*
   * Extract an MPI array from the signature data.  This represents the actual
   * signature.  Each raw MPI is prefaced by a BE 2-byte value indicating the
   * size of the MPI in bytes.
   *
   * RSA signatures only have one MPI, so currently we only read one.
   */
  static int mod_extract_mpi_array(struct public_key_signature *pks,
  				 const void *data, size_t len)
  {
  	size_t nbytes;
  	MPI mpi;
  
  	if (len < 3)
  		return -EBADMSG;
  	nbytes = ((const u8 *)data)[0] << 8 | ((const u8 *)data)[1];
  	data += 2;
  	len -= 2;
  	if (len != nbytes)
  		return -EBADMSG;
  
  	mpi = mpi_read_raw_data(data, nbytes);
  	if (!mpi)
  		return -ENOMEM;
  	pks->mpi[0] = mpi;
  	pks->nr_mpi = 1;
  	return 0;
  }
  
  /*
   * Request an asymmetric key.
   */
  static struct key *request_asymmetric_key(const char *signer, size_t signer_len,
  					  const u8 *key_id, size_t key_id_len)
  {
  	key_ref_t key;
  	size_t i;
  	char *id, *q;
  
  	pr_devel("==>%s(,%zu,,%zu)
  ", __func__, signer_len, key_id_len);
  
  	/* Construct an identifier. */
  	id = kmalloc(signer_len + 2 + key_id_len * 2 + 1, GFP_KERNEL);
  	if (!id)
  		return ERR_PTR(-ENOKEY);
  
  	memcpy(id, signer, signer_len);
  
  	q = id + signer_len;
  	*q++ = ':';
  	*q++ = ' ';
  	for (i = 0; i < key_id_len; i++) {
  		*q++ = hex_asc[*key_id >> 4];
  		*q++ = hex_asc[*key_id++ & 0x0f];
  	}
  
  	*q = 0;
  
  	pr_debug("Look up: \"%s\"
  ", id);
b56e5a17b   David Howells   KEYS: Separate th...
165
  	key = keyring_search(make_key_ref(system_trusted_keyring, 1),
48ba2462a   David Howells   MODSIGN: Implemen...
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
  			     &key_type_asymmetric, id);
  	if (IS_ERR(key))
  		pr_warn("Request for unknown module key '%s' err %ld
  ",
  			id, PTR_ERR(key));
  	kfree(id);
  
  	if (IS_ERR(key)) {
  		switch (PTR_ERR(key)) {
  			/* Hide some search errors */
  		case -EACCES:
  		case -ENOTDIR:
  		case -EAGAIN:
  			return ERR_PTR(-ENOKEY);
  		default:
  			return ERR_CAST(key);
  		}
  	}
  
  	pr_devel("<==%s() = 0 [%x]
  ", __func__, key_serial(key_ref_to_ptr(key)));
  	return key_ref_to_ptr(key);
  }
  
  /*
106a4ee25   Rusty Russell   module: signature...
191
192
   * Verify the signature on a module.
   */
caabe2405   David Howells   MODSIGN: Move the...
193
  int mod_verify_sig(const void *mod, unsigned long *_modlen)
106a4ee25   Rusty Russell   module: signature...
194
  {
48ba2462a   David Howells   MODSIGN: Implemen...
195
196
197
  	struct public_key_signature *pks;
  	struct module_signature ms;
  	struct key *key;
caabe2405   David Howells   MODSIGN: Move the...
198
199
  	const void *sig;
  	size_t modlen = *_modlen, sig_len;
48ba2462a   David Howells   MODSIGN: Implemen...
200
  	int ret;
0390c8835   Randy Dunlap   module_signing: f...
201
202
  	pr_devel("==>%s(,%zu)
  ", __func__, modlen);
48ba2462a   David Howells   MODSIGN: Implemen...
203

caabe2405   David Howells   MODSIGN: Move the...
204
  	if (modlen <= sizeof(ms))
48ba2462a   David Howells   MODSIGN: Implemen...
205
  		return -EBADMSG;
caabe2405   David Howells   MODSIGN: Move the...
206
207
  	memcpy(&ms, mod + (modlen - sizeof(ms)), sizeof(ms));
  	modlen -= sizeof(ms);
48ba2462a   David Howells   MODSIGN: Implemen...
208
209
  
  	sig_len = be32_to_cpu(ms.sig_len);
caabe2405   David Howells   MODSIGN: Move the...
210
  	if (sig_len >= modlen)
48ba2462a   David Howells   MODSIGN: Implemen...
211
  		return -EBADMSG;
caabe2405   David Howells   MODSIGN: Move the...
212
213
214
215
216
217
218
  	modlen -= sig_len;
  	if ((size_t)ms.signer_len + ms.key_id_len >= modlen)
  		return -EBADMSG;
  	modlen -= (size_t)ms.signer_len + ms.key_id_len;
  
  	*_modlen = modlen;
  	sig = mod + modlen;
48ba2462a   David Howells   MODSIGN: Implemen...
219
220
221
222
223
224
225
  
  	/* For the moment, only support RSA and X.509 identifiers */
  	if (ms.algo != PKEY_ALGO_RSA ||
  	    ms.id_type != PKEY_ID_X509)
  		return -ENOPKG;
  
  	if (ms.hash >= PKEY_HASH__LAST ||
3fe78ca2f   Dmitry Kasatkin   keys: change asym...
226
  	    !hash_algo_name[ms.hash])
48ba2462a   David Howells   MODSIGN: Implemen...
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
  		return -ENOPKG;
  
  	key = request_asymmetric_key(sig, ms.signer_len,
  				     sig + ms.signer_len, ms.key_id_len);
  	if (IS_ERR(key))
  		return PTR_ERR(key);
  
  	pks = mod_make_digest(ms.hash, mod, modlen);
  	if (IS_ERR(pks)) {
  		ret = PTR_ERR(pks);
  		goto error_put_key;
  	}
  
  	ret = mod_extract_mpi_array(pks, sig + ms.signer_len + ms.key_id_len,
  				    sig_len);
  	if (ret < 0)
  		goto error_free_pks;
  
  	ret = verify_signature(key, pks);
  	pr_devel("verify_signature() = %d
  ", ret);
  
  error_free_pks:
  	mpi_free(pks->rsa.s);
  	kfree(pks);
  error_put_key:
  	key_put(key);
  	pr_devel("<==%s() = %d
  ", __func__, ret);
  	return ret;	
106a4ee25   Rusty Russell   module: signature...
257
  }