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