comparison rsa.c @ 4:fe6bca95afa7

Makefile.in contains updated files required
author Matt Johnston <matt@ucc.asn.au>
date Tue, 01 Jun 2004 02:46:09 +0000
parents
children e2a1eaa19f22
comparison
equal deleted inserted replaced
-1:000000000000 4:fe6bca95afa7
1 /*
2 * Dropbear - a SSH2 server
3 *
4 * Copyright (c) 2002,2003 Matt Johnston
5 * All rights reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 * SOFTWARE. */
24
25 /* Perform RSA operations on data, including reading keys, signing and
26 * verification.
27 *
28 * The format is specified in rfc2437, Applied Cryptography or The Handbook of
29 * Applied Cryptography detail the general algorithm. */
30
31 #include "includes.h"
32 #include "dbutil.h"
33 #include "bignum.h"
34 #include "rsa.h"
35 #include "buffer.h"
36 #include "ssh.h"
37 #include "random.h"
38
39 #ifdef DROPBEAR_RSA
40
41 static mp_int * rsa_pad_em(rsa_key * key,
42 const unsigned char * data, unsigned int len);
43
44 /* Load a public rsa key from a buffer, initialising the values.
45 * The key will have the same format as buf_put_rsa_key.
46 * These should be freed with rsa_key_free.
47 * Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
48 int buf_get_rsa_pub_key(buffer* buf, rsa_key *key) {
49
50 TRACE(("enter buf_get_rsa_pub_key"));
51 assert(key != NULL);
52 key->e = m_malloc(sizeof(mp_int));
53 key->n = m_malloc(sizeof(mp_int));
54 m_mp_init_multi(key->e, key->n, NULL);
55 key->d = NULL;
56 key->p = NULL;
57 key->q = NULL;
58
59 buf_incrpos(buf, 4+SSH_SIGNKEY_RSA_LEN); /* int + "ssh-rsa" */
60
61 if (buf_getmpint(buf, key->e) == DROPBEAR_FAILURE
62 || buf_getmpint(buf, key->n) == DROPBEAR_FAILURE) {
63 TRACE(("leave buf_get_rsa_pub_key: failure"));
64 return DROPBEAR_FAILURE;
65 }
66
67 if (mp_count_bits(key->n) < MIN_RSA_KEYLEN) {
68 dropbear_log(LOG_WARNING, "rsa key too short");
69 return DROPBEAR_FAILURE;
70 }
71
72 TRACE(("leave buf_get_rsa_pub_key: success"));
73 return DROPBEAR_SUCCESS;
74
75 }
76
77 /* Same as buf_get_rsa_pub_key, but reads a private "x" key at the end.
78 * Loads a private rsa key from a buffer
79 * Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
80 int buf_get_rsa_priv_key(buffer* buf, rsa_key *key) {
81
82 assert(key != NULL);
83
84 TRACE(("enter buf_get_rsa_priv_key"));
85
86 if (buf_get_rsa_pub_key(buf, key) == DROPBEAR_FAILURE) {
87 TRACE(("leave buf_get_rsa_priv_key: pub: ret == DROPBEAR_FAILURE"));
88 return DROPBEAR_FAILURE;
89 }
90
91 key->d = m_malloc(sizeof(mp_int));
92 m_mp_init(key->d);
93 if (buf_getmpint(buf, key->d) == DROPBEAR_FAILURE) {
94 TRACE(("leave buf_get_rsa_priv_key: d: ret == DROPBEAR_FAILURE"));
95 return DROPBEAR_FAILURE;
96 }
97
98 /* old Dropbear private keys didn't keep p and q, so we will ignore them*/
99 if (buf->pos == buf->len) {
100 key->p = NULL;
101 key->q = NULL;
102 } else {
103 key->p = m_malloc(sizeof(mp_int));
104 key->q = m_malloc(sizeof(mp_int));
105 m_mp_init_multi(key->p, key->q, NULL);
106
107 if (buf_getmpint(buf, key->p) == DROPBEAR_FAILURE) {
108 TRACE(("leave buf_get_rsa_priv_key: p: ret == DROPBEAR_FAILURE"));
109 return DROPBEAR_FAILURE;
110 }
111
112 if (buf_getmpint(buf, key->q) == DROPBEAR_FAILURE) {
113 TRACE(("leave buf_get_rsa_priv_key: q: ret == DROPBEAR_FAILURE"));
114 return DROPBEAR_FAILURE;
115 }
116 }
117
118 TRACE(("leave buf_get_rsa_priv_key"));
119 return DROPBEAR_SUCCESS;
120 }
121
122
123 /* Clear and free the memory used by a public or private key */
124 void rsa_key_free(rsa_key *key) {
125
126 TRACE(("enter rsa_key_free"));
127
128 if (key == NULL) {
129 TRACE(("leave rsa_key_free: key == NULL"));
130 return;
131 }
132 if (key->d) {
133 mp_clear(key->d);
134 m_free(key->d);
135 }
136 if (key->e) {
137 mp_clear(key->e);
138 m_free(key->e);
139 }
140 if (key->n) {
141 mp_clear(key->n);
142 m_free(key->n);
143 }
144 if (key->p) {
145 mp_clear(key->p);
146 m_free(key->p);
147 }
148 if (key->q) {
149 mp_clear(key->q);
150 m_free(key->q);
151 }
152 m_free(key);
153 TRACE(("leave rsa_key_free"));
154 }
155
156 /* Put the public rsa key into the buffer in the required format:
157 *
158 * string "ssh-rsa"
159 * mp_int e
160 * mp_int n
161 */
162 void buf_put_rsa_pub_key(buffer* buf, rsa_key *key) {
163
164 TRACE(("enter buf_put_rsa_pub_key"));
165 assert(key != NULL);
166
167 buf_putstring(buf, SSH_SIGNKEY_RSA, SSH_SIGNKEY_RSA_LEN);
168 buf_putmpint(buf, key->e);
169 buf_putmpint(buf, key->n);
170
171 TRACE(("leave buf_put_rsa_pub_key"));
172
173 }
174
175 /* Same as buf_put_rsa_pub_key, but with the private "x" key appended */
176 void buf_put_rsa_priv_key(buffer* buf, rsa_key *key) {
177
178 TRACE(("enter buf_put_rsa_priv_key"));
179
180 assert(key != NULL);
181 buf_put_rsa_pub_key(buf, key);
182 buf_putmpint(buf, key->d);
183
184 /* new versions have p and q, old versions don't */
185 if (key->p) {
186 buf_putmpint(buf, key->p);
187 }
188 if (key->q) {
189 buf_putmpint(buf, key->q);
190 }
191
192
193 TRACE(("leave buf_put_rsa_priv_key"));
194
195 }
196
197 #ifdef DROPBEAR_SIGNKEY_VERIFY
198 /* Verify a signature in buf, made on data by the key given.
199 * Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
200 int buf_rsa_verify(buffer * buf, rsa_key *key, const unsigned char* data,
201 unsigned int len) {
202
203 unsigned int slen;
204 mp_int rsa_s, rsa_mdash;
205 mp_int *rsa_em = NULL;
206 int ret = DROPBEAR_FAILURE;
207
208 assert(key != NULL);
209
210 m_mp_init_multi(&rsa_mdash, &rsa_s, NULL);
211
212 slen = buf_getint(buf);
213 if (slen != (unsigned int)mp_unsigned_bin_size(key->n)) {
214 TRACE(("bad size"));
215 goto out;
216 }
217
218 if (mp_read_unsigned_bin(&rsa_s, buf_getptr(buf, buf->len - buf->pos),
219 buf->len - buf->pos) != MP_OKAY) {
220 goto out;
221 }
222
223 /* check that s <= n-1 */
224 if (mp_cmp(&rsa_s, key->n) != MP_LT) {
225 TRACE(("s > n-1"));
226 goto out;
227 }
228
229 /* create the magic PKCS padded value */
230 rsa_em = rsa_pad_em(key, data, len);
231
232 if (mp_exptmod(&rsa_s, key->e, key->n, &rsa_mdash) != MP_OKAY) {
233 goto out;
234 }
235
236 if (mp_cmp(rsa_em, &rsa_mdash) == MP_EQ) {
237 /* signature is valid */
238 ret = DROPBEAR_SUCCESS;
239 }
240
241 out:
242 mp_clear_multi(rsa_em, &rsa_mdash, &rsa_s, NULL);
243 m_free(rsa_em);
244 return ret;
245
246 }
247 #endif /* DROPBEAR_SIGNKEY_VERIFY */
248
249 /* Sign the data presented with key, writing the signature contents
250 * to the buffer */
251 void buf_put_rsa_sign(buffer* buf, rsa_key *key, const unsigned char* data,
252 unsigned int len) {
253
254 unsigned int nsize, ssize;
255 unsigned int i;
256 mp_int rsa_s;
257 mp_int *rsa_em;
258
259 TRACE(("enter buf_put_rsa_sign"));
260 assert(key != NULL);
261
262 rsa_em = rsa_pad_em(key, data, len);
263
264 /* the actual signing of the padded data */
265 m_mp_init(&rsa_s);
266 /* s = em^d mod n */
267 if (mp_exptmod(rsa_em, key->d, key->n, &rsa_s) != MP_OKAY) {
268 dropbear_exit("rsa error");
269 }
270 mp_clear(rsa_em);
271 m_free(rsa_em);
272
273 /* create the signature to return */
274 buf_putstring(buf, SSH_SIGNKEY_RSA, SSH_SIGNKEY_RSA_LEN);
275
276 nsize = mp_unsigned_bin_size(key->n);
277
278 /* string rsa_signature_blob length */
279 buf_putint(buf, nsize);
280 /* pad out s to same length as n */
281 ssize = mp_unsigned_bin_size(&rsa_s);
282 assert(ssize <= nsize);
283 for (i = 0; i < nsize-ssize; i++) {
284 buf_putbyte(buf, 0x00);
285 }
286
287 if (mp_to_unsigned_bin(&rsa_s, buf_getwriteptr(buf, ssize)) != MP_OKAY) {
288 dropbear_exit("rsa error");
289 }
290 buf_incrwritepos(buf, ssize);
291 mp_clear(&rsa_s);
292
293 #if defined(DEBUG_RSA) && defined(DEBUG_TRACE)
294 printhex(buf->data, buf->len);
295 #endif
296
297
298 TRACE(("leave buf_put_rsa_sign"));
299 }
300
301 /* Creates the message value as expected by PKCS, see rfc2437 etc */
302 /* format to be padded to is:
303 * EM = 01 | FF* | 00 | prefix | hash
304 *
305 * where FF is repeated enough times to make EM one byte
306 * shorter than the size of key->n
307 *
308 * prefix is the ASN1 designator prefix,
309 * hex 30 21 30 09 06 05 2B 0E 03 02 1A 05 00 04 14
310 */
311 static mp_int * rsa_pad_em(rsa_key * key,
312 const unsigned char * data, unsigned int len) {
313
314 /* ASN1 designator (including the 0x00 preceding) */
315 const char rsa_asn1_magic[] =
316 {0x00, 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b,
317 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14};
318 #define RSA_ASN1_MAGIC_LEN 16
319 buffer * rsa_EM;
320 hash_state hs;
321 unsigned int nsize;
322 mp_int * rsa_em;
323
324 assert(key != NULL);
325 assert(data != NULL);
326 nsize = mp_unsigned_bin_size(key->n);
327
328 rsa_EM = buf_new(nsize-1);
329 /* type byte */
330 buf_putbyte(rsa_EM, 0x01);
331 /* Padding with 0xFF bytes */
332 while(rsa_EM->pos != rsa_EM->size - RSA_ASN1_MAGIC_LEN - SHA1_HASH_SIZE) {
333 buf_putbyte(rsa_EM, 0xff);
334 }
335 /* Magic ASN1 stuff */
336 memcpy(buf_getwriteptr(rsa_EM, RSA_ASN1_MAGIC_LEN),
337 rsa_asn1_magic, RSA_ASN1_MAGIC_LEN);
338 buf_incrwritepos(rsa_EM, RSA_ASN1_MAGIC_LEN);
339
340 /* The hash of the data */
341 sha1_init(&hs);
342 sha1_process(&hs, data, len);
343 sha1_done(&hs, buf_getwriteptr(rsa_EM, SHA1_HASH_SIZE));
344 buf_incrwritepos(rsa_EM, SHA1_HASH_SIZE);
345
346 assert(rsa_EM->pos == rsa_EM->size);
347
348 /* Create the mp_int from the encoded bytes */
349 buf_setpos(rsa_EM, 0);
350 rsa_em = (mp_int*)m_malloc(sizeof(mp_int));
351 m_mp_init(rsa_em);
352 if (mp_read_unsigned_bin(rsa_em, buf_getptr(rsa_EM, rsa_EM->size),
353 rsa_EM->size) != MP_OKAY) {
354 dropbear_exit("rsa error");
355 }
356 buf_free(rsa_EM);
357
358 return rsa_em;
359
360 }
361
362 #endif /* DROPBEAR_RSA */