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