aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorDmitry Kasatkin <dmitry.kasatkin@intel.com>2011-10-14 08:25:16 -0400
committerDmitry Kasatkin <dmitry.kasatkin@intel.com>2011-11-09 05:10:37 -0500
commit051dbb918c7fb7da8e64a2cd0d804ba73399709f (patch)
tree34d547e74ef6edb7feeda4a8291b221cc016c393 /lib
parent7e8dec918ef8e0f68b4937c3c50fa57002077a4d (diff)
crypto: digital signature verification support
This patch implements RSA digital signature verification using GnuPG library. The format of the signature and the public key is defined by their respective headers. The signature header contains version information, algorithm, and keyid, which was used to generate the signature. The key header contains version and algorythim type. The payload of the signature and the key are multi-precision integers. The signing and key management utilities evm-utils provide functionality to generate signatures and load keys into the kernel keyring. When the key is added to the kernel keyring, the keyid defines the name of the key. Signed-off-by: Dmitry Kasatkin <dmitry.kasatkin@intel.com> Acked-by: Mimi Zohar <zohar@us.ibm.com>
Diffstat (limited to 'lib')
-rw-r--r--lib/Kconfig8
-rw-r--r--lib/Makefile1
-rw-r--r--lib/digsig.c284
3 files changed, 293 insertions, 0 deletions
diff --git a/lib/Kconfig b/lib/Kconfig
index d411de53be4f..c1a89185fe6b 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -293,4 +293,12 @@ config MPILIB_EXTRA
293 This code in unnecessary for RSA digital signature verification, 293 This code in unnecessary for RSA digital signature verification,
294 and can be compiled if needed. 294 and can be compiled if needed.
295 295
296config DIGSIG
297 tristate "In-kernel signature checker"
298 depends on CRYPTO
299 select MPILIB
300 help
301 Digital signature verification. Currently only RSA is supported.
302 Implementation is done using GnuPG MPI library
303
296endmenu 304endmenu
diff --git a/lib/Makefile b/lib/Makefile
index 6ba8cbf4c72f..0f5cff267aff 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -116,6 +116,7 @@ obj-$(CONFIG_CPU_RMAP) += cpu_rmap.o
116obj-$(CONFIG_CORDIC) += cordic.o 116obj-$(CONFIG_CORDIC) += cordic.o
117 117
118obj-$(CONFIG_MPILIB) += mpi/ 118obj-$(CONFIG_MPILIB) += mpi/
119obj-$(CONFIG_DIGSIG) += digsig.o
119 120
120hostprogs-y := gen_crc32table 121hostprogs-y := gen_crc32table
121clean-files := crc32table.h 122clean-files := crc32table.h
diff --git a/lib/digsig.c b/lib/digsig.c
new file mode 100644
index 000000000000..fd2402f67f89
--- /dev/null
+++ b/lib/digsig.c
@@ -0,0 +1,284 @@
1/*
2 * Copyright (C) 2011 Nokia Corporation
3 * Copyright (C) 2011 Intel Corporation
4 *
5 * Author:
6 * Dmitry Kasatkin <dmitry.kasatkin@nokia.com>
7 * <dmitry.kasatkin@intel.com>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation, version 2 of the License.
12 *
13 * File: sign.c
14 * implements signature (RSA) verification
15 * pkcs decoding is based on LibTomCrypt code
16 */
17
18#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
19
20#include <linux/err.h>
21#include <linux/module.h>
22#include <linux/slab.h>
23#include <linux/key.h>
24#include <linux/crypto.h>
25#include <crypto/hash.h>
26#include <crypto/sha.h>
27#include <keys/user-type.h>
28#include <linux/mpi.h>
29#include <linux/digsig.h>
30
31static struct crypto_shash *shash;
32
33static int pkcs_1_v1_5_decode_emsa(const unsigned char *msg,
34 unsigned long msglen,
35 unsigned long modulus_bitlen,
36 unsigned char *out,
37 unsigned long *outlen,
38 int *is_valid)
39{
40 unsigned long modulus_len, ps_len, i;
41 int result;
42
43 /* default to invalid packet */
44 *is_valid = 0;
45
46 modulus_len = (modulus_bitlen >> 3) + (modulus_bitlen & 7 ? 1 : 0);
47
48 /* test message size */
49 if ((msglen > modulus_len) || (modulus_len < 11))
50 return -EINVAL;
51
52 /* separate encoded message */
53 if ((msg[0] != 0x00) || (msg[1] != (unsigned char)1)) {
54 result = -EINVAL;
55 goto bail;
56 }
57
58 for (i = 2; i < modulus_len - 1; i++)
59 if (msg[i] != 0xFF)
60 break;
61
62 /* separator check */
63 if (msg[i] != 0) {
64 /* There was no octet with hexadecimal value 0x00
65 to separate ps from m. */
66 result = -EINVAL;
67 goto bail;
68 }
69
70 ps_len = i - 2;
71
72 if (*outlen < (msglen - (2 + ps_len + 1))) {
73 *outlen = msglen - (2 + ps_len + 1);
74 result = -EOVERFLOW;
75 goto bail;
76 }
77
78 *outlen = (msglen - (2 + ps_len + 1));
79 memcpy(out, &msg[2 + ps_len + 1], *outlen);
80
81 /* valid packet */
82 *is_valid = 1;
83 result = 0;
84bail:
85 return result;
86}
87
88/*
89 * RSA Signature verification with public key
90 */
91static int digsig_verify_rsa(struct key *key,
92 const char *sig, int siglen,
93 const char *h, int hlen)
94{
95 int err = -EINVAL;
96 unsigned long len;
97 unsigned long mlen, mblen;
98 unsigned nret, l;
99 int valid, head, i;
100 unsigned char *out1 = NULL, *out2 = NULL;
101 MPI in = NULL, res = NULL, pkey[2];
102 uint8_t *p, *datap, *endp;
103 struct user_key_payload *ukp;
104 struct pubkey_hdr *pkh;
105
106 down_read(&key->sem);
107 ukp = key->payload.data;
108 pkh = (struct pubkey_hdr *)ukp->data;
109
110 if (pkh->version != 1)
111 goto err1;
112
113 if (pkh->algo != PUBKEY_ALGO_RSA)
114 goto err1;
115
116 if (pkh->nmpi != 2)
117 goto err1;
118
119 datap = pkh->mpi;
120 endp = datap + ukp->datalen;
121
122 for (i = 0; i < pkh->nmpi; i++) {
123 unsigned int remaining = endp - datap;
124 pkey[i] = mpi_read_from_buffer(datap, &remaining);
125 datap += remaining;
126 }
127
128 mblen = mpi_get_nbits(pkey[0]);
129 mlen = (mblen + 7)/8;
130
131 err = -ENOMEM;
132
133 out1 = kzalloc(mlen, GFP_KERNEL);
134 if (!out1)
135 goto err;
136
137 out2 = kzalloc(mlen, GFP_KERNEL);
138 if (!out2)
139 goto err;
140
141 nret = siglen;
142 in = mpi_read_from_buffer(sig, &nret);
143 if (!in)
144 goto err;
145
146 res = mpi_alloc(mpi_get_nlimbs(in) * 2);
147 if (!res)
148 goto err;
149
150 err = mpi_powm(res, in, pkey[1], pkey[0]);
151 if (err)
152 goto err;
153
154 if (mpi_get_nlimbs(res) * BYTES_PER_MPI_LIMB > mlen) {
155 err = -EINVAL;
156 goto err;
157 }
158
159 p = mpi_get_buffer(res, &l, NULL);
160 if (!p) {
161 err = -EINVAL;
162 goto err;
163 }
164
165 len = mlen;
166 head = len - l;
167 memset(out1, 0, head);
168 memcpy(out1 + head, p, l);
169
170 err = -EINVAL;
171 pkcs_1_v1_5_decode_emsa(out1, len, mblen, out2, &len, &valid);
172
173 if (valid && len == hlen)
174 err = memcmp(out2, h, hlen);
175
176err:
177 mpi_free(in);
178 mpi_free(res);
179 kfree(out1);