]> git.ipfire.org Git - thirdparty/strongswan.git/blame - src/libstrongswan/plugins/gmp/gmp_rsa_public_key.c
cirrus: Explicitly install tpm2-tss-sys package on Alpine
[thirdparty/strongswan.git] / src / libstrongswan / plugins / gmp / gmp_rsa_public_key.c
CommitLineData
552cc11b 1/*
5955db5b 2 * Copyright (C) 2017-2018 Tobias Brunner
7033a70f 3 * Copyright (C) 2005-2009 Martin Willi
552cc11b 4 * Copyright (C) 2005 Jan Hutter
552cc11b
MW
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>
7d6b8164 30#include <credentials/keys/signature_params.h>
552cc11b 31
3e35a6e7
MW
32#ifdef HAVE_MPZ_POWM_SEC
33# undef mpz_powm
34# define mpz_powm mpz_powm_sec
35#endif
36
552cc11b
MW
37typedef struct private_gmp_rsa_public_key_t private_gmp_rsa_public_key_t;
38
39/**
40 * Private data structure with signing context.
41 */
42struct private_gmp_rsa_public_key_t {
43 /**
44 * Public interface for this signer.
45 */
46 gmp_rsa_public_key_t public;
7daf5226 47
552cc11b
MW
48 /**
49 * Public modulus.
50 */
51 mpz_t n;
7daf5226 52
552cc11b
MW
53 /**
54 * Public exponent.
55 */
56 mpz_t e;
7daf5226 57
552cc11b
MW
58 /**
59 * Keysize in bytes.
60 */
61 size_t k;
7daf5226 62
552cc11b
MW
63 /**
64 * reference counter
65 */
66 refcount_t ref;
67};
68
8b799d55
AS
69/**
70 * Shared functions defined in gmp_rsa_private_key.c
71 */
5955db5b
TB
72chunk_t gmp_mpz_to_chunk(const mpz_t value);
73bool gmp_emsa_pkcs1_signature_data(hash_algorithm_t hash_algorithm,
74 chunk_t data, size_t keylen, chunk_t *em);
8b799d55 75
552cc11b
MW
76/**
77 * RSAEP algorithm specified in PKCS#1.
78 */
79static chunk_t rsaep(private_gmp_rsa_public_key_t *this, chunk_t data)
80{
81 mpz_t m, c;
82 chunk_t encrypted;
7daf5226 83
552cc11b 84 mpz_init(m);
552cc11b 85 mpz_import(m, data.len, 1, 1, 1, 0, data.ptr);
7daf5226 86
ef5c37fc
TB
87 if (mpz_cmp_ui(m, 0) <= 0 || mpz_cmp(m, this->n) >= 0)
88 { /* m must be <= n-1, and while 0 is technically a valid value, it
89 * doesn't really make sense here, so we filter that too */
90 mpz_clear(m);
91 return chunk_empty;
92 }
93
94 mpz_init(c);
552cc11b
MW
95 mpz_powm(c, m, this->e, this->n);
96
73f6886a
MW
97 encrypted.len = this->k;
98 encrypted.ptr = mpz_export(NULL, NULL, 1, encrypted.len, 1, 0, c);
99 if (encrypted.ptr == NULL)
100 {
101 encrypted.len = 0;
102 }
7daf5226 103
552cc11b 104 mpz_clear(c);
73f6886a 105 mpz_clear(m);
7daf5226 106
552cc11b
MW
107 return encrypted;
108}
109
110/**
111 * RSAVP1 algorithm specified in PKCS#1.
112 */
113static chunk_t rsavp1(private_gmp_rsa_public_key_t *this, chunk_t data)
114{
115 return rsaep(this, data);
116}
117
118/**
7d6b8164 119 * Verification of an EMSA PKCS1 signature described in PKCS#1
552cc11b
MW
120 */
121static bool verify_emsa_pkcs1_signature(private_gmp_rsa_public_key_t *this,
122 hash_algorithm_t algorithm,
123 chunk_t data, chunk_t signature)
124{
5955db5b 125 chunk_t em_expected, em;
d3d7e46b 126 bool success = FALSE;
7daf5226 127
552cc11b
MW
128 /* remove any preceding 0-bytes from signature */
129 while (signature.len && *(signature.ptr) == 0x00)
130 {
e7227f0b 131 signature = chunk_skip(signature, 1);
552cc11b 132 }
7daf5226 133
e7227f0b 134 if (signature.len == 0 || signature.len > this->k)
552cc11b 135 {
060b508e 136 return FALSE;
552cc11b 137 }
7daf5226 138
5955db5b
TB
139 /* generate expected signature value */
140 if (!gmp_emsa_pkcs1_signature_data(algorithm, data, this->k, &em_expected))
552cc11b 141 {
5955db5b 142 return FALSE;
8b799d55 143 }
552cc11b 144
5955db5b
TB
145 /* unpack signature */
146 em = rsavp1(this, signature);
d3d7e46b 147
5955db5b 148 success = chunk_equals_const(em_expected, em);
552cc11b 149
5955db5b
TB
150 chunk_free(&em_expected);
151 chunk_free(&em);
d3d7e46b 152 return success;
552cc11b
MW
153}
154
7d6b8164
TB
155/**
156 * Verification of an EMSA PSS signature described in PKCS#1
157 */
158static bool verify_emsa_pss_signature(private_gmp_rsa_public_key_t *this,
159 rsa_pss_params_t *params, chunk_t data,
160 chunk_t signature)
161{
162 ext_out_function_t xof;
163 hasher_t *hasher = NULL;
164 xof_t *mgf = NULL;
165 chunk_t em, hash, salt, db, h, dbmask, m;
166 size_t embits, maskbits;
167 int i;
168 bool success = FALSE;
169
234302a1 170 if (!params || params->salt_len < 0)
7d6b8164
TB
171 {
172 return FALSE;
173 }
126fd8af
TB
174 xof = xof_mgf1_from_hash_algorithm(params->mgf1_hash);
175 if (xof == XOF_UNDEFINED)
7d6b8164 176 {
126fd8af
TB
177 DBG1(DBG_LIB, "%N is not supported for MGF1", hash_algorithm_names,
178 params->mgf1_hash);
179 return FALSE;
7d6b8164
TB
180 }
181 chunk_skip_zero(signature);
182 if (signature.len == 0 || signature.len > this->k)
183 {
184 return FALSE;
185 }
186 /* EM = RSAVP1((n, e), S) */
187 em = rsavp1(this, signature);
188 if (!em.len)
189 {
190 goto error;
191 }
192 /* emBits = modBits - 1 */
193 embits = mpz_sizeinbase(this->n, 2) - 1;
194 /* mHash = Hash(M) */
195 hasher = lib->crypto->create_hasher(lib->crypto, params->hash);
196 if (!hasher)
197 {
198 DBG1(DBG_LIB, "hash algorithm %N not supported",
199 hash_algorithm_names, params->hash);
200 goto error;
201 }
202 hash = chunk_alloca(hasher->get_hash_size(hasher));
203 if (!hasher->get_hash(hasher, data, hash.ptr))
204 {
205 goto error;
206 }
ecfe6755 207 salt.len = params->salt_len;
7d6b8164
TB
208 /* verify general structure of EM */
209 maskbits = (8 * em.len) - embits;
210 if (em.len < (hash.len + salt.len + 2) || em.ptr[em.len-1] != 0xbc ||
211 (em.ptr[0] & (0xff << (8-maskbits))))
212 { /* inconsistent */
213 goto error;
214 }
215 /* split EM in maskedDB and H */
216 db = chunk_create(em.ptr, em.len - hash.len - 1);
217 h = chunk_create(em.ptr + db.len, hash.len);
218 /* dbMask = MGF(H, emLen - hLen - 1) */
219 mgf = lib->crypto->create_xof(lib->crypto, xof);
220 if (!mgf)
221 {
222 DBG1(DBG_LIB, "%N not supported", ext_out_function_names, xof);
223 goto error;
224 }
225 dbmask = chunk_alloca(db.len);
226 if (!mgf->set_seed(mgf, h) ||
227 !mgf->get_bytes(mgf, dbmask.len, dbmask.ptr))
228 {
229 DBG1(DBG_LIB, "%N not supported or failed", ext_out_function_names, xof);
230 goto error;
231 }
232 /* DB = maskedDB xor dbMask */
233 memxor(db.ptr, dbmask.ptr, db.len);
234 if (maskbits)
235 {
236 db.ptr[0] &= (0xff >> maskbits);
237 }
238 /* check DB = PS | 0x01 | salt */
239 for (i = 0; i < (db.len - salt.len - 1); i++)
240 {
241 if (db.ptr[i])
242 { /* padding not 0 */
243 goto error;
244 }
245 }
246 if (db.ptr[i++] != 0x01)
247 { /* 0x01 not found */
248 goto error;
249 }
250 salt.ptr = &db.ptr[i];
251 /* M' = 0x0000000000000000 | mHash | salt */
252 m = chunk_cata("ccc",
253 chunk_from_chars(0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00),
254 hash, salt);
255 if (!hasher->get_hash(hasher, m, hash.ptr))
256 {
257 goto error;
258 }
259 success = memeq_const(h.ptr, hash.ptr, hash.len);
260
261error:
262 DESTROY_IF(hasher);
263 DESTROY_IF(mgf);
264 free(em.ptr);
265 return success;
266}
267
876b61e1
MW
268METHOD(public_key_t, get_type, key_type_t,
269 private_gmp_rsa_public_key_t *this)
552cc11b
MW
270{
271 return KEY_RSA;
272}
273
876b61e1 274METHOD(public_key_t, verify, bool,
a413571f 275 private_gmp_rsa_public_key_t *this, signature_scheme_t scheme, void *params,
876b61e1 276 chunk_t data, chunk_t signature)
552cc11b
MW
277{
278 switch (scheme)
279 {
8b799d55 280 case SIGN_RSA_EMSA_PKCS1_NULL:
552cc11b 281 return verify_emsa_pkcs1_signature(this, HASH_UNKNOWN, data, signature);
40f2589a 282 case SIGN_RSA_EMSA_PKCS1_SHA2_224:
b6f739c1 283 return verify_emsa_pkcs1_signature(this, HASH_SHA224, data, signature);
40f2589a 284 case SIGN_RSA_EMSA_PKCS1_SHA2_256:
552cc11b 285 return verify_emsa_pkcs1_signature(this, HASH_SHA256, data, signature);
40f2589a 286 case SIGN_RSA_EMSA_PKCS1_SHA2_384:
552cc11b 287 return verify_emsa_pkcs1_signature(this, HASH_SHA384, data, signature);
40f2589a 288 case SIGN_RSA_EMSA_PKCS1_SHA2_512:
552cc11b 289 return verify_emsa_pkcs1_signature(this, HASH_SHA512, data, signature);
40f2589a
AS
290 case SIGN_RSA_EMSA_PKCS1_SHA3_224:
291 return verify_emsa_pkcs1_signature(this, HASH_SHA3_224, data, signature);
292 case SIGN_RSA_EMSA_PKCS1_SHA3_256:
293 return verify_emsa_pkcs1_signature(this, HASH_SHA3_256, data, signature);
294 case SIGN_RSA_EMSA_PKCS1_SHA3_384:
295 return verify_emsa_pkcs1_signature(this, HASH_SHA3_384, data, signature);
296 case SIGN_RSA_EMSA_PKCS1_SHA3_512:
297 return verify_emsa_pkcs1_signature(this, HASH_SHA3_512, data, signature);
298 case SIGN_RSA_EMSA_PKCS1_SHA1:
299 return verify_emsa_pkcs1_signature(this, HASH_SHA1, data, signature);
300 case SIGN_RSA_EMSA_PKCS1_MD5:
301 return verify_emsa_pkcs1_signature(this, HASH_MD5, data, signature);
7d6b8164
TB
302 case SIGN_RSA_EMSA_PSS:
303 return verify_emsa_pss_signature(this, params, data, signature);
552cc11b 304 default:
8b0e0910 305 DBG1(DBG_LIB, "signature scheme %N not supported in RSA",
552cc11b
MW
306 signature_scheme_names, scheme);
307 return FALSE;
308 }
309}
310
741680d1 311#define MIN_PS_PADDING 8
c50ff68d 312
876b61e1 313METHOD(public_key_t, encrypt_, bool,
33ddaaab 314 private_gmp_rsa_public_key_t *this, encryption_scheme_t scheme,
4abb29f6 315 void *params, chunk_t plain, chunk_t *crypto)
552cc11b 316{
c50ff68d
AS
317 chunk_t em;
318 u_char *pos;
5025135f 319 int padding;
7b3814f7 320 rng_t *rng;
c50ff68d 321
33ddaaab 322 if (scheme != ENCRYPT_RSA_PKCS1)
c50ff68d 323 {
33ddaaab
MW
324 DBG1(DBG_LIB, "encryption scheme %N not supported",
325 encryption_scheme_names, scheme);
c50ff68d
AS
326 return FALSE;
327 }
c50ff68d
AS
328 /* number of pseudo-random padding octets */
329 padding = this->k - plain.len - 3;
7b3814f7 330 if (padding < MIN_PS_PADDING)
c50ff68d 331 {
8b0e0910
TB
332 DBG1(DBG_LIB, "pseudo-random padding must be at least %d octets",
333 MIN_PS_PADDING);
c50ff68d
AS
334 return FALSE;
335 }
33ddaaab
MW
336 rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
337 if (rng == NULL)
338 {
339 DBG1(DBG_LIB, "no random generator available");
340 return FALSE;
341 }
c50ff68d
AS
342
343 /* padding according to PKCS#1 7.2.1 (RSAES-PKCS1-v1.5-ENCRYPT) */
8b0e0910
TB
344 DBG2(DBG_LIB, "padding %u bytes of data to the rsa modulus size of"
345 " %u bytes", plain.len, this->k);
c50ff68d 346 em.len = this->k;
7daf5226 347 em.ptr = malloc(em.len);
c50ff68d
AS
348 pos = em.ptr;
349 *pos++ = 0x00;
350 *pos++ = 0x02;
351
352 /* fill with pseudo random octets */
5025135f 353 if (!rng_get_bytes_not_zero(rng, padding, pos, TRUE))
c50ff68d 354 {
5025135f
TB
355 DBG1(DBG_LIB, "failed to allocate padding");
356 chunk_clear(&em);
357 rng->destroy(rng);
358 return FALSE;
c50ff68d
AS
359 }
360 rng->destroy(rng);
361
828cefc3
MW
362 pos += padding;
363
c50ff68d
AS
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 }
6681d98d 468 if (!e.len || !n.len || (n.ptr[n.len-1] & 0x01) == 0)
1086d00e
MW
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
6681d98d
TB
499 if (!mpz_sgn(this->e))
500 {
501 destroy(this);
502 return NULL;
503 }
552cc11b
MW
504 return &this->public;
505}