]> git.ipfire.org Git - thirdparty/strongswan.git/blame - src/libstrongswan/plugins/gmp/gmp_rsa_public_key.c
supporting multiple comma seperated subnets in left/rightsubnet definition
[thirdparty/strongswan.git] / src / libstrongswan / plugins / gmp / gmp_rsa_public_key.c
CommitLineData
552cc11b
MW
1/*
2 * Copyright (C) 2005-2008 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 * $Id$
17 */
18
19#include <gmp.h>
20#include <sys/stat.h>
21#include <unistd.h>
22#include <stdio.h>
23#include <string.h>
24
25#include "gmp_rsa_public_key.h"
26
27#include <debug.h>
28#include <crypto/hashers/hasher.h>
29#include <asn1/asn1.h>
30#include <asn1/pem.h>
31
32/**
33 * defined in gmp_rsa_private_key.c
34 */
35extern chunk_t gmp_mpz_to_asn1(const mpz_t value);
36
552cc11b
MW
37
38/* ASN.1 definition of RSApublicKey */
39static const asn1Object_t pubkeyObjects[] = {
40 { 0, "RSAPublicKey", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */
41 { 1, "modulus", ASN1_INTEGER, ASN1_BODY }, /* 1 */
42 { 1, "publicExponent", ASN1_INTEGER, ASN1_BODY }, /* 2 */
43};
44
0ea70ca6 45#define PUB_KEY_RSA_PUBLIC_KEY 0
552cc11b
MW
46#define PUB_KEY_MODULUS 1
47#define PUB_KEY_EXPONENT 2
48#define PUB_KEY_ROOF 3
49
50/* ASN.1 definition of digestInfo */
51static const asn1Object_t digestInfoObjects[] = {
52 { 0, "digestInfo", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */
53 { 1, "digestAlgorithm", ASN1_EOC, ASN1_RAW }, /* 1 */
54 { 1, "digest", ASN1_OCTET_STRING, ASN1_BODY }, /* 2 */
55};
56
57#define DIGEST_INFO 0
58#define DIGEST_INFO_ALGORITHM 1
59#define DIGEST_INFO_DIGEST 2
60#define DIGEST_INFO_ROOF 3
61
62typedef struct private_gmp_rsa_public_key_t private_gmp_rsa_public_key_t;
63
64/**
65 * Private data structure with signing context.
66 */
67struct private_gmp_rsa_public_key_t {
68 /**
69 * Public interface for this signer.
70 */
71 gmp_rsa_public_key_t public;
72
73 /**
74 * Public modulus.
75 */
76 mpz_t n;
77
78 /**
79 * Public exponent.
80 */
81 mpz_t e;
82
83 /**
84 * Keysize in bytes.
85 */
86 size_t k;
87
88 /**
89 * Keyid formed as a SHA-1 hash of a publicKeyInfo object
90 */
91 identification_t *keyid_info;
92
93 /**
94 * Keyid formed as a SHA-1 hash of a publicKey object
95 */
96 identification_t *keyid;
97
98 /**
99 * reference counter
100 */
101 refcount_t ref;
102};
103
104/**
105 * RSAEP algorithm specified in PKCS#1.
106 */
107static chunk_t rsaep(private_gmp_rsa_public_key_t *this, chunk_t data)
108{
109 mpz_t m, c;
110 chunk_t encrypted;
111
112 mpz_init(c);
113 mpz_init(m);
114
115 mpz_import(m, data.len, 1, 1, 1, 0, data.ptr);
116
117 mpz_powm(c, m, this->e, this->n);
118
119 encrypted.len = this->k;
120 encrypted.ptr = mpz_export(NULL, NULL, 1, encrypted.len, 1, 0, c);
121
122 mpz_clear(c);
123 mpz_clear(m);
124
125 return encrypted;
126}
127
128/**
129 * RSAVP1 algorithm specified in PKCS#1.
130 */
131static chunk_t rsavp1(private_gmp_rsa_public_key_t *this, chunk_t data)
132{
133 return rsaep(this, data);
134}
135
136/**
137 * Verification of an EMPSA PKCS1 signature described in PKCS#1
138 */
139static bool verify_emsa_pkcs1_signature(private_gmp_rsa_public_key_t *this,
140 hash_algorithm_t algorithm,
141 chunk_t data, chunk_t signature)
142{
143 chunk_t em_ori, em;
144 bool res = FALSE;
145
146 /* remove any preceding 0-bytes from signature */
147 while (signature.len && *(signature.ptr) == 0x00)
148 {
149 signature.len -= 1;
150 signature.ptr++;
151 }
152
153 if (signature.len > this->k)
154 {
155 return INVALID_ARG;
156 }
157
158 /* unpack signature */
159 em_ori = em = rsavp1(this, signature);
160
161 /* result should look like this:
162 * EM = 0x00 || 0x01 || PS || 0x00 || T.
163 * PS = 0xFF padding, with length to fill em
164 * T = oid || hash
165 */
166
167 /* check magic bytes */
168 if (*(em.ptr) != 0x00 || *(em.ptr+1) != 0x01)
169 {
170 goto end;
171 }
172 em.ptr += 2;
173 em.len -= 2;
174
175 /* find magic 0x00 */
176 while (em.len > 0)
177 {
178 if (*em.ptr == 0x00)
179 {
180 /* found magic byte, stop */
181 em.ptr++;
182 em.len--;
183 break;
184 }
185 else if (*em.ptr != 0xFF)
186 {
187 /* bad padding, decryption failed ?!*/
188 goto end;
189 }
190 em.ptr++;
191 em.len--;
192 }
193
194 if (em.len == 0)
195 {
196 /* no digestInfo found */
197 goto end;
198 }
199
200 /* parse ASN.1-based digestInfo */
201 {
202 asn1_ctx_t ctx;
203 chunk_t object;
204 u_int level;
205 int objectID = 0;
206 hash_algorithm_t hash_algorithm = HASH_UNKNOWN;
207
208 asn1_init(&ctx, em, 0, FALSE, FALSE);
209
210 while (objectID < DIGEST_INFO_ROOF)
211 {
212 if (!extract_object(digestInfoObjects, &objectID, &object, &level, &ctx))
213 {
214 goto end;
215 }
216 switch (objectID)
217 {
218 case DIGEST_INFO:
219 {
220 if (em.len > object.len)
221 {
222 DBG1("digestInfo field in signature is followed by %u surplus bytes",
223 em.len - object.len);
224 goto end;
225 }
226 break;
227 }
228 case DIGEST_INFO_ALGORITHM:
229 {
230 int hash_oid = parse_algorithmIdentifier(object, level+1, NULL);
231
232 hash_algorithm = hasher_algorithm_from_oid(hash_oid);
233 if (hash_algorithm == HASH_UNKNOWN ||
234 (algorithm != HASH_UNKNOWN && hash_algorithm != algorithm))
235 {
236 DBG1("wrong hash algorithm used in signature");
237 goto end;
238 }
239 break;
240 }
241 case DIGEST_INFO_DIGEST:
242 {
243 chunk_t hash;
244 hasher_t *hasher;
245
246 hasher = lib->crypto->create_hasher(lib->crypto, hash_algorithm);
247 if (hasher == NULL)
248 {
249 DBG1("hash algorithm %N not supported",
250 hash_algorithm_names, hash_algorithm);
251 goto end;
252 }
253
254 if (object.len != hasher->get_hash_size(hasher))
255 {
256 DBG1("hash size in signature is %u bytes instead of %u "
257 "bytes", object.len, hasher->get_hash_size(hasher));
258 hasher->destroy(hasher);
259 goto end;
260 }
261
262 /* build our own hash and compare */
263 hasher->allocate_hash(hasher, data, &hash);
264 hasher->destroy(hasher);
265 res = memeq(object.ptr, hash.ptr, hash.len);
266 free(hash.ptr);
267 break;
268 }
269 default:
270 break;
271 }
272 objectID++;
273 }
274 }
275
276end:
277 free(em_ori.ptr);
278 return res;
279}
280
281/**
282 * Implementation of public_key_t.get_type.
283 */
284static key_type_t get_type(private_gmp_rsa_public_key_t *this)
285{
286 return KEY_RSA;
287}
288
289/**
290 * Implementation of public_key_t.verify.
291 */
292static bool verify(private_gmp_rsa_public_key_t *this, signature_scheme_t scheme,
293 chunk_t data, chunk_t signature)
294{
295 switch (scheme)
296 {
297 case SIGN_DEFAULT: /* default is EMSA-PKCS1 using included OID */
298 return verify_emsa_pkcs1_signature(this, HASH_UNKNOWN, data, signature);
299 case SIGN_RSA_EMSA_PKCS1_MD5:
300 return verify_emsa_pkcs1_signature(this, HASH_MD5, data, signature);
301 case SIGN_RSA_EMSA_PKCS1_SHA1:
302 return verify_emsa_pkcs1_signature(this, HASH_SHA1, data, signature);
303 case SIGN_RSA_EMSA_PKCS1_SHA256:
304 return verify_emsa_pkcs1_signature(this, HASH_SHA256, data, signature);
305 case SIGN_RSA_EMSA_PKCS1_SHA384:
306 return verify_emsa_pkcs1_signature(this, HASH_SHA384, data, signature);
307 case SIGN_RSA_EMSA_PKCS1_SHA512:
308 return verify_emsa_pkcs1_signature(this, HASH_SHA512, data, signature);
309 default:
310 DBG1("signature scheme %N not supported in RSA",
311 signature_scheme_names, scheme);
312 return FALSE;
313 }
314}
315
316/**
317 * Implementation of public_key_t.get_keysize.
318 */
319static bool encrypt(private_gmp_rsa_public_key_t *this, chunk_t crypto, chunk_t *plain)
320{
321 DBG1("RSA public key encryption not implemented");
322 return FALSE;
323}
324
325/**
326 * Implementation of public_key_t.get_keysize.
327 */
328static size_t get_keysize(private_gmp_rsa_public_key_t *this)
329{
330 return this->k;
331}
332
333/**
334 * Implementation of public_key_t.get_id.
335 */
336static identification_t *get_id(private_gmp_rsa_public_key_t *this,
337 id_type_t type)
338{
339 switch (type)
340 {
341 case ID_PUBKEY_INFO_SHA1:
342 return this->keyid_info;
343 case ID_PUBKEY_SHA1:
344 return this->keyid;
345 default:
346 return NULL;
347 }
348}
349
350/*
351 * Implementation of public_key_t.get_encoding.
352 */
353static chunk_t get_encoding(private_gmp_rsa_public_key_t *this)
354{
355 return asn1_wrap(ASN1_SEQUENCE, "mm",
356 gmp_mpz_to_asn1(this->n),
357 gmp_mpz_to_asn1(this->e));
358}
359
360/**
361 * Implementation of public_key_t.get_ref.
362 */
363static private_gmp_rsa_public_key_t* get_ref(private_gmp_rsa_public_key_t *this)
364{
365 ref_get(&this->ref);
366 return this;
367}
368
369/**
370 * Implementation of gmp_rsa_public_key.destroy.
371 */
372static void destroy(private_gmp_rsa_public_key_t *this)
373{
374 if (ref_put(&this->ref))
375 {
376 mpz_clear(this->n);
377 mpz_clear(this->e);
378 DESTROY_IF(this->keyid);
379 DESTROY_IF(this->keyid_info);
380 free(this);
381 }
382}
383
384/**
385 * Generic private constructor
386 */
387static private_gmp_rsa_public_key_t *gmp_rsa_public_key_create_empty()
388{
389 private_gmp_rsa_public_key_t *this = malloc_thing(private_gmp_rsa_public_key_t);
390
391 this->public.interface.get_type = (key_type_t (*)(public_key_t *this))get_type;
392 this->public.interface.verify = (bool (*)(public_key_t *this, signature_scheme_t scheme, chunk_t data, chunk_t signature))verify;
393 this->public.interface.encrypt = (bool (*)(public_key_t *this, chunk_t crypto, chunk_t *plain))encrypt;
394 this->public.interface.get_keysize = (size_t (*) (public_key_t *this))get_keysize;
395 this->public.interface.get_id = (identification_t* (*) (public_key_t *this,id_type_t))get_id;
396 this->public.interface.get_encoding = (chunk_t(*)(public_key_t*))get_encoding;
397 this->public.interface.get_ref = (public_key_t* (*)(public_key_t *this))get_ref;
398 this->public.interface.destroy = (void (*)(public_key_t *this))destroy;
399
400 this->keyid = NULL;
401 this->keyid_info = NULL;
402 this->ref = 1;
403
404 return this;
405}
406
407/**
408 * Build the RSA key identifier from n and e using SHA1 hashed publicKey(Info).
409 * Also used in rsa_private_key.c.
410 */
411bool gmp_rsa_public_key_build_id(mpz_t n, mpz_t e, identification_t **keyid,
412 identification_t **keyid_info)
413{
414 chunk_t publicKeyInfo, publicKey, hash;
415 hasher_t *hasher;
416
417 hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1);
418 if (hasher == NULL)
419 {
420 DBG1("SHA1 hash algorithm not supported, unable to use RSA");
421 return FALSE;
422 }
423 publicKey = asn1_wrap(ASN1_SEQUENCE, "mm",
424 gmp_mpz_to_asn1(n),
425 gmp_mpz_to_asn1(e));
426 hasher->allocate_hash(hasher, publicKey, &hash);
427 *keyid = identification_create_from_encoding(ID_PUBKEY_SHA1, hash);
428 chunk_free(&hash);
429
430 publicKeyInfo = asn1_wrap(ASN1_SEQUENCE, "cm",
431 asn1_algorithmIdentifier(OID_RSA_ENCRYPTION),
432 asn1_bitstring("m", publicKey));
433 hasher->allocate_hash(hasher, publicKeyInfo, &hash);
434 *keyid_info = identification_create_from_encoding(ID_PUBKEY_INFO_SHA1, hash);
435 chunk_free(&hash);
436
437 hasher->destroy(hasher);
438 chunk_free(&publicKeyInfo);
439
440 return TRUE;
441}
442
d7c529f5
MW
443/**
444 * Create a public key from mpz values, used in gmp_rsa_private_key
445 */
446gmp_rsa_public_key_t *gmp_rsa_public_key_create_from_n_e(mpz_t n, mpz_t e)
447{
448 private_gmp_rsa_public_key_t *this = gmp_rsa_public_key_create_empty();
449
450 mpz_init_set(this->n, n);
451 mpz_init_set(this->e, e);
452
453 this->k = (mpz_sizeinbase(this->n, 2) + 7) / 8;
454 if (!gmp_rsa_public_key_build_id(this->n, this->e,
455 &this->keyid, &this->keyid_info))
456 {
457 destroy(this);
458 return NULL;
459 }
460 return &this->public;
461}
462
552cc11b
MW
463/**
464 * Load a public key from an ASN1 encoded blob
465 */
466static gmp_rsa_public_key_t *load(chunk_t blob)
467{
468 asn1_ctx_t ctx;
469 chunk_t object;
470 u_int level;
471 int objectID = 0;
472 private_gmp_rsa_public_key_t *this = gmp_rsa_public_key_create_empty();
473
474 mpz_init(this->n);
475 mpz_init(this->e);
476
477 asn1_init(&ctx, blob, 0, FALSE, FALSE);
478
479 while (objectID < PUB_KEY_ROOF)
480 {
481 if (!extract_object(pubkeyObjects, &objectID, &object, &level, &ctx))
482 {
483 free(blob.ptr);
484 destroy(this);
485 return NULL;
486 }
487 switch (objectID)
488 {
489 case PUB_KEY_MODULUS:
490 mpz_import(this->n, object.len, 1, 1, 1, 0, object.ptr);
491 break;
492 case PUB_KEY_EXPONENT:
493 mpz_import(this->e, object.len, 1, 1, 1, 0, object.ptr);
494 break;
495 }
496 objectID++;
497 }
498 free(blob.ptr);
499 this->k = (mpz_sizeinbase(this->n, 2) + 7) / 8;
500 if (!gmp_rsa_public_key_build_id(this->n, this->e,
501 &this->keyid, &this->keyid_info))
502 {
503 destroy(this);
504 return NULL;
505 }
506 return &this->public;
507}
508
552cc11b
MW
509typedef struct private_builder_t private_builder_t;
510/**
511 * Builder implementation for key loading
512 */
513struct private_builder_t {
514 /** implements the builder interface */
515 builder_t public;
516 /** loaded public key */
517 gmp_rsa_public_key_t *key;
518};
519
520/**
521 * Implementation of builder_t.build
522 */
523static gmp_rsa_public_key_t *build(private_builder_t *this)
524{
525 gmp_rsa_public_key_t *key = this->key;
526
527 free(this);
528 return key;
529}
530
531/**
532 * Implementation of builder_t.add
533 */
534static void add(private_builder_t *this, builder_part_t part, ...)
535{
536 va_list args;
537
538 if (this->key)
539 {
540 DBG1("ignoring surplus build part %N", builder_part_names, part);
541 return;
542 }
543
544 switch (part)
545 {
546 case BUILD_BLOB_ASN1_DER:
547 {
548 va_start(args, part);
549 this->key = load(va_arg(args, chunk_t));
550 va_end(args);
551 break;
552 }
553 default:
554 DBG1("ignoring unsupported build part %N", builder_part_names, part);
555 break;
556 }
557}
558
559/**
560 * Builder construction function
561 */
562builder_t *gmp_rsa_public_key_builder(key_type_t type)
563{
564 private_builder_t *this;
565
566 if (type != KEY_RSA)
567 {
568 return NULL;
569 }
570
571 this = malloc_thing(private_builder_t);
572
573 this->key = NULL;
574 this->public.add = (void(*)(builder_t *this, builder_part_t part, ...))add;
575 this->public.build = (void*(*)(builder_t *this))build;
576
577 return &this->public;
578}
579