Public/Private keys implement a has_fingerprint() method
[strongswan.git] / src / libstrongswan / plugins / gmp / gmp_rsa_public_key.c
1 /*
2 * Copyright (C) 2005-2009 Martin Willi
3 * Copyright (C) 2005 Jan Hutter
4 * Hochschule fuer Technik Rapperswil
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
15 */
16
17 #include <gmp.h>
18 #include <sys/stat.h>
19 #include <unistd.h>
20 #include <stdio.h>
21 #include <string.h>
22
23 #include "gmp_rsa_public_key.h"
24
25 #include <debug.h>
26 #include <asn1/oid.h>
27 #include <asn1/asn1.h>
28 #include <asn1/asn1_parser.h>
29 #include <crypto/hashers/hasher.h>
30
31 typedef struct private_gmp_rsa_public_key_t private_gmp_rsa_public_key_t;
32
33 /**
34 * Private data structure with signing context.
35 */
36 struct private_gmp_rsa_public_key_t {
37 /**
38 * Public interface for this signer.
39 */
40 gmp_rsa_public_key_t public;
41
42 /**
43 * Public modulus.
44 */
45 mpz_t n;
46
47 /**
48 * Public exponent.
49 */
50 mpz_t e;
51
52 /**
53 * Keysize in bytes.
54 */
55 size_t k;
56
57 /**
58 * reference counter
59 */
60 refcount_t ref;
61 };
62
63 /**
64 * Shared functions defined in gmp_rsa_private_key.c
65 */
66 extern chunk_t gmp_mpz_to_chunk(const mpz_t value);
67
68 /**
69 * RSAEP algorithm specified in PKCS#1.
70 */
71 static chunk_t rsaep(private_gmp_rsa_public_key_t *this, chunk_t data)
72 {
73 mpz_t m, c;
74 chunk_t encrypted;
75
76 mpz_init(c);
77 mpz_init(m);
78
79 mpz_import(m, data.len, 1, 1, 1, 0, data.ptr);
80
81 mpz_powm(c, m, this->e, this->n);
82
83 encrypted.len = this->k;
84 encrypted.ptr = mpz_export(NULL, NULL, 1, encrypted.len, 1, 0, c);
85 if (encrypted.ptr == NULL)
86 {
87 encrypted.len = 0;
88 }
89
90 mpz_clear(c);
91 mpz_clear(m);
92
93 return encrypted;
94 }
95
96 /**
97 * RSAVP1 algorithm specified in PKCS#1.
98 */
99 static chunk_t rsavp1(private_gmp_rsa_public_key_t *this, chunk_t data)
100 {
101 return rsaep(this, data);
102 }
103
104 /**
105 * ASN.1 definition of digestInfo
106 */
107 static const asn1Object_t digestInfoObjects[] = {
108 { 0, "digestInfo", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */
109 { 1, "digestAlgorithm", ASN1_EOC, ASN1_RAW }, /* 1 */
110 { 1, "digest", ASN1_OCTET_STRING, ASN1_BODY }, /* 2 */
111 { 0, "exit", ASN1_EOC, ASN1_EXIT }
112 };
113 #define DIGEST_INFO 0
114 #define DIGEST_INFO_ALGORITHM 1
115 #define DIGEST_INFO_DIGEST 2
116
117 /**
118 * Verification of an EMPSA PKCS1 signature described in PKCS#1
119 */
120 static bool verify_emsa_pkcs1_signature(private_gmp_rsa_public_key_t *this,
121 hash_algorithm_t algorithm,
122 chunk_t data, chunk_t signature)
123 {
124 chunk_t em_ori, em;
125 bool success = FALSE;
126
127 /* remove any preceding 0-bytes from signature */
128 while (signature.len && *(signature.ptr) == 0x00)
129 {
130 signature = chunk_skip(signature, 1);
131 }
132
133 if (signature.len == 0 || signature.len > this->k)
134 {
135 return INVALID_ARG;
136 }
137
138 /* unpack signature */
139 em_ori = em = rsavp1(this, signature);
140
141 /* result should look like this:
142 * EM = 0x00 || 0x01 || PS || 0x00 || T.
143 * PS = 0xFF padding, with length to fill em
144 * T = oid || hash
145 */
146
147 /* check magic bytes */
148 if (*(em.ptr) != 0x00 || *(em.ptr+1) != 0x01)
149 {
150 goto end;
151 }
152 em = chunk_skip(em, 2);
153
154 /* find magic 0x00 */
155 while (em.len > 0)
156 {
157 if (*em.ptr == 0x00)
158 {
159 /* found magic byte, stop */
160 em = chunk_skip(em, 1);
161 break;
162 }
163 else if (*em.ptr != 0xFF)
164 {
165 /* bad padding, decryption failed ?!*/
166 goto end;
167 }
168 em = chunk_skip(em, 1);
169 }
170
171 if (em.len == 0)
172 {
173 /* no digestInfo found */
174 goto end;
175 }
176
177 if (algorithm == HASH_UNKNOWN)
178 { /* IKEv1 signatures without digestInfo */
179 if (em.len != data.len)
180 {
181 DBG1("hash size in signature is %u bytes instead of %u bytes",
182 em.len, data.len);
183 goto end;
184 }
185 success = memeq(em.ptr, data.ptr, data.len);
186 }
187 else
188 { /* IKEv2 and X.509 certificate signatures */
189 asn1_parser_t *parser;
190 chunk_t object;
191 int objectID;
192 hash_algorithm_t hash_algorithm = HASH_UNKNOWN;
193
194 DBG2("signature verification:");
195 parser = asn1_parser_create(digestInfoObjects, em);
196
197 while (parser->iterate(parser, &objectID, &object))
198 {
199 switch (objectID)
200 {
201 case DIGEST_INFO:
202 {
203 if (em.len > object.len)
204 {
205 DBG1("digestInfo field in signature is followed by %u surplus bytes",
206 em.len - object.len);
207 goto end_parser;
208 }
209 break;
210 }
211 case DIGEST_INFO_ALGORITHM:
212 {
213 int hash_oid = asn1_parse_algorithmIdentifier(object,
214 parser->get_level(parser)+1, NULL);
215
216 hash_algorithm = hasher_algorithm_from_oid(hash_oid);
217 if (hash_algorithm == HASH_UNKNOWN || hash_algorithm != algorithm)
218 {
219 DBG1("expected hash algorithm %N, but found %N (OID: %#B)",
220 hash_algorithm_names, algorithm,
221 hash_algorithm_names, hash_algorithm, &object);
222 goto end_parser;
223 }
224 break;
225 }
226 case DIGEST_INFO_DIGEST:
227 {
228 chunk_t hash;
229 hasher_t *hasher;
230
231 hasher = lib->crypto->create_hasher(lib->crypto, hash_algorithm);
232 if (hasher == NULL)
233 {
234 DBG1("hash algorithm %N not supported",
235 hash_algorithm_names, hash_algorithm);
236 goto end_parser;
237 }
238
239 if (object.len != hasher->get_hash_size(hasher))
240 {
241 DBG1("hash size in signature is %u bytes instead of %u "
242 "bytes", object.len, hasher->get_hash_size(hasher));
243 hasher->destroy(hasher);
244 goto end_parser;
245 }
246
247 /* build our own hash and compare */
248 hasher->allocate_hash(hasher, data, &hash);
249 hasher->destroy(hasher);
250 success = memeq(object.ptr, hash.ptr, hash.len);
251 free(hash.ptr);
252 break;
253 }
254 default:
255 break;
256 }
257 }
258
259 end_parser:
260 success &= parser->success(parser);
261 parser->destroy(parser);
262 }
263
264 end:
265 free(em_ori.ptr);
266 return success;
267 }
268
269 /**
270 * Implementation of public_key_t.get_type.
271 */
272 static key_type_t get_type(private_gmp_rsa_public_key_t *this)
273 {
274 return KEY_RSA;
275 }
276
277 /**
278 * Implementation of public_key_t.verify.
279 */
280 static bool verify(private_gmp_rsa_public_key_t *this, signature_scheme_t scheme,
281 chunk_t data, chunk_t signature)
282 {
283 switch (scheme)
284 {
285 case SIGN_RSA_EMSA_PKCS1_NULL:
286 return verify_emsa_pkcs1_signature(this, HASH_UNKNOWN, data, signature);
287 case SIGN_RSA_EMSA_PKCS1_MD5:
288 return verify_emsa_pkcs1_signature(this, HASH_MD5, data, signature);
289 case SIGN_RSA_EMSA_PKCS1_SHA1:
290 return verify_emsa_pkcs1_signature(this, HASH_SHA1, data, signature);
291 case SIGN_RSA_EMSA_PKCS1_SHA224:
292 return verify_emsa_pkcs1_signature(this, HASH_SHA224, data, signature);
293 case SIGN_RSA_EMSA_PKCS1_SHA256:
294 return verify_emsa_pkcs1_signature(this, HASH_SHA256, data, signature);
295 case SIGN_RSA_EMSA_PKCS1_SHA384:
296 return verify_emsa_pkcs1_signature(this, HASH_SHA384, data, signature);
297 case SIGN_RSA_EMSA_PKCS1_SHA512:
298 return verify_emsa_pkcs1_signature(this, HASH_SHA512, data, signature);
299 default:
300 DBG1("signature scheme %N not supported in RSA",
301 signature_scheme_names, scheme);
302 return FALSE;
303 }
304 }
305
306 #define MIN_PS_PADDING 8
307
308 /**
309 * Implementation of public_key_t.encrypt.
310 */
311 static bool encrypt_(private_gmp_rsa_public_key_t *this, chunk_t plain,
312 chunk_t *crypto)
313 {
314 chunk_t em;
315 u_char *pos;
316 int padding, i;
317 rng_t *rng;
318
319 rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
320 if (rng == NULL)
321 {
322 DBG1("no random generator available");
323 return FALSE;
324 }
325
326 /* number of pseudo-random padding octets */
327 padding = this->k - plain.len - 3;
328 if (padding < MIN_PS_PADDING)
329 {
330 DBG1("pseudo-random padding must be at least %d octets", MIN_PS_PADDING);
331 return FALSE;
332 }
333
334 /* padding according to PKCS#1 7.2.1 (RSAES-PKCS1-v1.5-ENCRYPT) */
335 DBG2("padding %u bytes of data to the rsa modulus size of %u bytes",
336 plain.len, this->k);
337 em.len = this->k;
338 em.ptr = malloc(em.len);
339 pos = em.ptr;
340 *pos++ = 0x00;
341 *pos++ = 0x02;
342
343 /* fill with pseudo random octets */
344 rng->get_bytes(rng, padding, pos);
345
346 /* replace zero-valued random octets */
347 for (i = 0; i < padding; i++)
348 {
349 while (*pos == 0)
350 {
351 rng->get_bytes(rng, 1, pos);
352 }
353 pos++;
354 }
355 rng->destroy(rng);
356
357 /* append the padding terminator */
358 *pos++ = 0x00;
359
360 /* now add the data */
361 memcpy(pos, plain.ptr, plain.len);
362 DBG3("padded data before rsa encryption: %B", &em);
363
364 /* rsa encryption using PKCS#1 RSAEP */
365 *crypto = rsaep(this, em);
366 DBG3("rsa encrypted data: %B", crypto);
367 chunk_clear(&em);
368 return TRUE;
369 }
370
371 /**
372 * Implementation of gmp_rsa_public_key.equals.
373 */
374 static bool equals(private_gmp_rsa_public_key_t *this, public_key_t *other)
375 {
376 return public_key_equals(&this->public.interface, other);
377 }
378
379 /**
380 * Implementation of public_key_t.get_keysize.
381 */
382 static size_t get_keysize(private_gmp_rsa_public_key_t *this)
383 {
384 return this->k;
385 }
386
387 /**
388 * Implementation of public_key_t.get_encoding
389 */
390 static bool get_encoding(private_gmp_rsa_public_key_t *this,
391 key_encoding_type_t type, chunk_t *encoding)
392 {
393 chunk_t n, e;
394 bool success;
395
396 n = gmp_mpz_to_chunk(this->n);
397 e = gmp_mpz_to_chunk(this->e);
398
399 success = lib->encoding->encode(lib->encoding, type, NULL, encoding,
400 KEY_PART_RSA_MODULUS, n, KEY_PART_RSA_PUB_EXP, e, KEY_PART_END);
401 chunk_free(&n);
402 chunk_free(&e);
403
404 return success;
405 }
406
407 /**
408 * Implementation of public_key_t.get_fingerprint
409 */
410 static bool get_fingerprint(private_gmp_rsa_public_key_t *this,
411 key_encoding_type_t type, chunk_t *fp)
412 {
413 chunk_t n, e;
414 bool success;
415
416 if (lib->encoding->get_cache(lib->encoding, type, this, fp))
417 {
418 return TRUE;
419 }
420 n = gmp_mpz_to_chunk(this->n);
421 e = gmp_mpz_to_chunk(this->e);
422
423 success = lib->encoding->encode(lib->encoding, type, this, fp,
424 KEY_PART_RSA_MODULUS, n, KEY_PART_RSA_PUB_EXP, e, KEY_PART_END);
425 chunk_free(&n);
426 chunk_free(&e);
427
428 return success;
429 }
430
431 /**
432 * Implementation of public_key_t.get_ref.
433 */
434 static private_gmp_rsa_public_key_t* get_ref(private_gmp_rsa_public_key_t *this)
435 {
436 ref_get(&this->ref);
437 return this;
438 }
439
440 /**
441 * Implementation of gmp_rsa_public_key.destroy.
442 */
443 static void destroy(private_gmp_rsa_public_key_t *this)
444 {
445 if (ref_put(&this->ref))
446 {
447 mpz_clear(this->n);
448 mpz_clear(this->e);
449 lib->encoding->clear_cache(lib->encoding, this);
450 free(this);
451 }
452 }
453
454 /**
455 * See header.
456 */
457 gmp_rsa_public_key_t *gmp_rsa_public_key_load(key_type_t type, va_list args)
458 {
459 private_gmp_rsa_public_key_t *this;
460 chunk_t n, e;
461
462 n = e = chunk_empty;
463 while (TRUE)
464 {
465 switch (va_arg(args, builder_part_t))
466 {
467 case BUILD_RSA_MODULUS:
468 n = va_arg(args, chunk_t);
469 continue;
470 case BUILD_RSA_PUB_EXP:
471 e = va_arg(args, chunk_t);
472 continue;
473 case BUILD_END:
474 break;
475 default:
476 return NULL;
477 }
478 break;
479 }
480 if (!e.ptr || !n.ptr)
481 {
482 return NULL;
483 }
484
485 this = malloc_thing(private_gmp_rsa_public_key_t);
486
487 this->public.interface.get_type = (key_type_t (*) (public_key_t*))get_type;
488 this->public.interface.verify = (bool (*) (public_key_t*, signature_scheme_t, chunk_t, chunk_t))verify;
489 this->public.interface.encrypt = (bool (*) (public_key_t*, chunk_t, chunk_t*))encrypt_;
490 this->public.interface.equals = (bool (*) (public_key_t*, public_key_t*))equals;
491 this->public.interface.get_keysize = (size_t (*) (public_key_t*))get_keysize;
492 this->public.interface.get_fingerprint = (bool(*)(public_key_t*, key_encoding_type_t type, chunk_t *fp))get_fingerprint;
493 this->public.interface.has_fingerprint = (bool(*)(public_key_t*, chunk_t fp))public_key_has_fingerprint;
494 this->public.interface.get_encoding = (bool(*)(public_key_t*, key_encoding_type_t type, chunk_t *encoding))get_encoding;
495 this->public.interface.get_ref = (public_key_t* (*) (public_key_t *this))get_ref;
496 this->public.interface.destroy = (void (*) (public_key_t *this))destroy;
497
498 this->ref = 1;
499
500 mpz_init(this->n);
501 mpz_init(this->e);
502
503 mpz_import(this->n, n.len, 1, 1, 1, 0, n.ptr);
504 mpz_import(this->e, e.len, 1, 1, 1, 0, e.ptr);
505
506 this->k = (mpz_sizeinbase(this->n, 2) + 7) / BITS_PER_BYTE;
507
508 return &this->public;
509 }
510