- comments added
[strongswan.git] / Source / charon / transforms / rsa / rsa_public_key.c
1 /**
2 * @file rsa_public_key.c
3 *
4 * @brief Implementation of rsa_public_key_t.
5 *
6 */
7
8 /*
9 * Copyright (C) 2005 Jan Hutter, Martin Willi
10 * Hochschule fuer Technik Rapperswil
11 *
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation; either version 2 of the License, or (at your
15 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 * for more details.
21 */
22
23 #include <gmp.h>
24
25 #include "rsa_public_key.h"
26
27 #include <daemon.h>
28 #include <utils/allocator.h>
29 #include <transforms/hashers/hasher.h>
30
31 /* since we don't have an ASN1 parser/generator,
32 * we use these predefined values for
33 * hash algorithm oids. These also contain
34 * the length of the following hash.
35 * These values are also used in rsa_private_key.c
36 */
37
38 u_int8_t md2_oid[18] = {
39 0x30,0x20,0x30,0x0c,0x06,0x08,0x2a,0x86,
40 0x48,0x86,0xf7,0x0d,0x02,0x02,0x05,0x00,
41 0x04,0x10
42 };
43
44 u_int8_t md5_oid[] = {
45 0x30,0x20,0x30,0x0c,0x06,0x08,0x2a,0x86,
46 0x48,0x86,0xf7,0x0d,0x02,0x05,0x05,0x00,
47 0x04,0x10
48 };
49
50 u_int8_t sha1_oid[] = {
51 0x30,0x21,0x30,0x09,0x06,0x05,0x2b,0x0e,
52 0x03,0x02,0x1a,0x05,0x00,0x04,0x14
53 };
54
55 u_int8_t sha256_oid[] = {
56 0x30,0x31,0x30,0x0d,0x06,0x09,0x60,0x86,
57 0x48,0x01,0x65,0x03,0x04,0x02,0x01,0x05,
58 0x00,0x04,0x20
59 };
60
61 u_int8_t sha384_oid[] = {
62 0x30,0x41,0x30,0x0d,0x06,0x09,0x60,0x86,
63 0x48,0x01,0x65,0x03,0x04,0x02,0x02,0x05,
64 0x00,0x04,0x30
65 };
66
67 u_int8_t sha512_oid[] = {
68 0x30,0x51,0x30,0x0d,0x06,0x09,0x60,0x86,
69 0x48,0x01,0x65,0x03,0x04,0x02,0x03,0x05,
70 0x00,0x04,0x40
71 };
72
73
74 typedef struct private_rsa_public_key_t private_rsa_public_key_t;
75
76 /**
77 * private data structure with signing context.
78 */
79 struct private_rsa_public_key_t {
80 /**
81 * Public interface for this signer.
82 */
83 rsa_public_key_t public;
84
85 /**
86 * is the key already set ?
87 */
88 bool is_key_set;
89
90 /**
91 * public modulus
92 */
93 mpz_t n;
94 /**
95 * public exponent
96 */
97 mpz_t e;
98
99 /**
100 * keysize in bytes
101 */
102 size_t k;
103
104 /**
105 * @brief Implements the RSAEP algorithm specified in PKCS#1.
106 */
107 chunk_t (*rsaep) (private_rsa_public_key_t *this, chunk_t data);
108
109 /**
110 * @brief Implements the RSASVP1 algorithm specified in PKCS#1.
111 */
112 chunk_t (*rsavp1) (private_rsa_public_key_t *this, chunk_t data);
113 };
114
115 /**
116 * Implements private_rsa_public_key_t.rsadp
117 * Implements private_rsa_public_key_t.rsavp1
118 */
119 static chunk_t rsaep(private_rsa_public_key_t *this, chunk_t data)
120 {
121 mpz_t m, c;
122 chunk_t encrypted;
123
124 mpz_init(c);
125 mpz_init(m);
126
127 mpz_import(m, data.len, 1, 1, 1, 0, data.ptr);
128
129 mpz_powm(c, m, this->e, this->n);
130
131 encrypted.len = this->k;
132 encrypted.ptr = mpz_export(NULL, NULL, 1, encrypted.len, 1, 0, c);
133
134 mpz_clear(c);
135 mpz_clear(m);
136
137 return encrypted;
138 }
139
140 /**
141 * implementation of rsa_public_key.verify_emsa_signature.
142 */
143 static status_t verify_emsa_pkcs1_signature(private_rsa_public_key_t *this, chunk_t data, chunk_t signature)
144 {
145 hasher_t *hasher = NULL;
146 chunk_t hash;
147 chunk_t em;
148 u_int8_t *pos;
149
150 if(!this->is_key_set)
151 {
152 return INVALID_STATE;
153 }
154
155 if (signature.len > this->k)
156 {
157 return INVALID_ARG;
158 }
159
160 /* unpack signature */
161 em = this->rsavp1(this, signature);
162
163 /* result should look like this:
164 * EM = 0x00 || 0x01 || PS || 0x00 || T.
165 * PS = 0xFF padding, with length to fill em
166 * T = oid || hash
167 */
168
169 /* check magic bytes */
170 if ((*(em.ptr) != 0x00) ||
171 (*(em.ptr+1) != 0x01))
172 {
173 allocator_free(em.ptr);
174 return FAILED;
175 }
176
177 /* find magic 0x00 */
178 pos = em.ptr + 2;
179 while (pos <= em.ptr + em.len)
180 {
181 if (*pos == 0x00)
182 {
183 /* found magic byte, stop */
184 pos++;
185 break;
186 }
187 else if (*pos != 0xFF)
188 {
189 /* bad padding, decryption failed ?!*/
190 allocator_free(em.ptr);
191 return FAILED;
192 }
193 pos++;
194 }
195
196 if (pos + 20 > em.ptr + em.len)
197 {
198 /* not enought room for oid compare */
199 allocator_free(em.ptr);
200 return FAILED;
201 }
202
203 if (memcmp(md2_oid, pos, sizeof(md2_oid)) == 0)
204 {
205 hasher = hasher_create(HASH_MD2);
206 pos += sizeof(md2_oid);
207 }
208 else if (memcmp(md5_oid, pos, sizeof(md5_oid)) == 0)
209 {
210 hasher = hasher_create(HASH_MD5);
211 pos += sizeof(md5_oid);
212 }
213 else if (memcmp(sha1_oid, pos, sizeof(sha1_oid)) == 0)
214 {
215 hasher = hasher_create(HASH_SHA1);
216 pos += sizeof(sha1_oid);
217 }
218 else if (memcmp(sha256_oid, pos, sizeof(sha256_oid)) == 0)
219 {
220 hasher = hasher_create(HASH_SHA256);
221 pos += sizeof(sha256_oid);
222 }
223 else if (memcmp(sha384_oid, pos, sizeof(sha384_oid)) == 0)
224 {
225 hasher = hasher_create(HASH_SHA384);
226 pos += sizeof(sha384_oid);
227 }
228 else if (memcmp(sha512_oid, pos, sizeof(sha512_oid)) == 0)
229 {
230 hasher = hasher_create(HASH_SHA512);
231 pos += sizeof(sha512_oid);
232 }
233
234 if (hasher == NULL)
235 {
236 /* not supported hash algorithm */
237 allocator_free(em.ptr);
238 return NOT_SUPPORTED;
239 }
240
241 if (pos + hasher->get_block_size(hasher) != em.ptr + em.len)
242 {
243 /* bad length */
244 allocator_free(em.ptr);
245 hasher->destroy(hasher);
246 return FAILED;
247 }
248
249 /* build own hash for a compare */
250 hasher->allocate_hash(hasher, data, &hash);
251 hasher->destroy(hasher);
252
253 if (memcmp(hash.ptr, pos, hash.len) != 0)
254 {
255 /* hash does not equal */
256 allocator_free(hash.ptr);
257 allocator_free(em.ptr);
258 return FAILED;
259
260 }
261
262 /* seems good */
263 allocator_free(hash.ptr);
264 allocator_free(em.ptr);
265 return SUCCESS;
266 }
267
268 /**
269 * implementation of rsa_public_key.set_key.
270 */
271 static status_t set_key(private_rsa_public_key_t *this, chunk_t key)
272 {
273 chunk_t n, e;
274
275 n.len = key.len/2;
276 n.ptr = key.ptr;
277 e.len = n.len;
278 e.ptr = key.ptr + n.len;
279
280 mpz_import(this->n, n.len, 1, 1, 1, 0, n.ptr);
281 mpz_import(this->e, n.len, 1, 1, 1, 0, e.ptr);
282
283 this->k = n.len;
284
285 this->is_key_set = TRUE;
286
287 return SUCCESS;
288 }
289
290
291 /**
292 * implementation of rsa_public_key.get_key.
293 */
294 static status_t get_key(private_rsa_public_key_t *this, chunk_t *key)
295 {
296 if (!this->is_key_set)
297 {
298 return INVALID_STATE;
299 }
300
301 chunk_t n, e;
302
303 n.len = this->k;
304 n.ptr = mpz_export(NULL, NULL, 1, n.len, 1, 0, this->n);
305 e.len = this->k;
306 e.ptr = mpz_export(NULL, NULL, 1, e.len, 1, 0, this->e);
307
308 key->len = this->k * 2;
309 key->ptr = allocator_alloc(key->len);
310 memcpy(key->ptr, n.ptr, n.len);
311 memcpy(key->ptr + n.len, e.ptr, e.len);
312 allocator_free(n.ptr);
313 allocator_free(e.ptr);
314
315 return SUCCESS;
316 }
317
318 /**
319 * implementation of rsa_public_key.load_key.
320 */
321 static status_t load_key(private_rsa_public_key_t *this, char *file)
322 {
323 return NOT_SUPPORTED;
324 }
325
326 /**
327 * implementation of rsa_public_key.save_key.
328 */
329 static status_t save_key(private_rsa_public_key_t *this, char *file)
330 {
331 return NOT_SUPPORTED;
332 }
333
334 /**
335 * implementation of rsa_public_key.destroy.
336 */
337 static void destroy(private_rsa_public_key_t *this)
338 {
339 if (this->is_key_set)
340 {
341 mpz_clear(this->n);
342 mpz_clear(this->e);
343 }
344 allocator_free(this);
345 }
346
347 /*
348 * Described in header
349 */
350 rsa_public_key_t *rsa_public_key_create()
351 {
352 private_rsa_public_key_t *this = allocator_alloc_thing(private_rsa_public_key_t);
353
354 /* public functions */
355 this->public.verify_emsa_pkcs1_signature = (status_t (*) (rsa_public_key_t*,chunk_t,chunk_t))verify_emsa_pkcs1_signature;
356 this->public.set_key = (status_t (*) (rsa_public_key_t*,chunk_t))set_key;
357 this->public.get_key = (status_t (*) (rsa_public_key_t*,chunk_t*))get_key;
358 this->public.load_key = (status_t (*) (rsa_public_key_t*,char*))load_key;
359 this->public.save_key = (status_t (*) (rsa_public_key_t*,char*))save_key;
360 this->public.destroy = (void (*) (rsa_public_key_t*))destroy;
361
362 /* private functions */
363 this->rsaep = rsaep;
364 this->rsavp1 = rsaep; /* same algorithm */
365
366 this->is_key_set = FALSE;
367
368 return &(this->public);
369 }