Annotation of embedaddon/strongswan/src/libstrongswan/plugins/gmp/gmp_rsa_public_key.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2017-2018 Tobias Brunner
! 3: * Copyright (C) 2005-2009 Martin Willi
! 4: * Copyright (C) 2005 Jan Hutter
! 5: * HSR Hochschule fuer Technik Rapperswil
! 6: *
! 7: * This program is free software; you can redistribute it and/or modify it
! 8: * under the terms of the GNU General Public License as published by the
! 9: * Free Software Foundation; either version 2 of the License, or (at your
! 10: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
! 11: *
! 12: * This program is distributed in the hope that it will be useful, but
! 13: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
! 14: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
! 15: * for more details.
! 16: */
! 17:
! 18: #include <gmp.h>
! 19: #include <sys/stat.h>
! 20: #include <unistd.h>
! 21: #include <stdio.h>
! 22: #include <string.h>
! 23:
! 24: #include "gmp_rsa_public_key.h"
! 25:
! 26: #include <utils/debug.h>
! 27: #include <asn1/oid.h>
! 28: #include <asn1/asn1.h>
! 29: #include <asn1/asn1_parser.h>
! 30: #include <crypto/hashers/hasher.h>
! 31: #include <credentials/keys/signature_params.h>
! 32:
! 33: #ifdef HAVE_MPZ_POWM_SEC
! 34: # undef mpz_powm
! 35: # define mpz_powm mpz_powm_sec
! 36: #endif
! 37:
! 38: typedef struct private_gmp_rsa_public_key_t private_gmp_rsa_public_key_t;
! 39:
! 40: /**
! 41: * Private data structure with signing context.
! 42: */
! 43: struct private_gmp_rsa_public_key_t {
! 44: /**
! 45: * Public interface for this signer.
! 46: */
! 47: gmp_rsa_public_key_t public;
! 48:
! 49: /**
! 50: * Public modulus.
! 51: */
! 52: mpz_t n;
! 53:
! 54: /**
! 55: * Public exponent.
! 56: */
! 57: mpz_t e;
! 58:
! 59: /**
! 60: * Keysize in bytes.
! 61: */
! 62: size_t k;
! 63:
! 64: /**
! 65: * reference counter
! 66: */
! 67: refcount_t ref;
! 68: };
! 69:
! 70: /**
! 71: * Shared functions defined in gmp_rsa_private_key.c
! 72: */
! 73: chunk_t gmp_mpz_to_chunk(const mpz_t value);
! 74: bool gmp_emsa_pkcs1_signature_data(hash_algorithm_t hash_algorithm,
! 75: chunk_t data, size_t keylen, chunk_t *em);
! 76:
! 77: /**
! 78: * RSAEP algorithm specified in PKCS#1.
! 79: */
! 80: static chunk_t rsaep(private_gmp_rsa_public_key_t *this, chunk_t data)
! 81: {
! 82: mpz_t m, c;
! 83: chunk_t encrypted;
! 84:
! 85: mpz_init(m);
! 86: mpz_import(m, data.len, 1, 1, 1, 0, data.ptr);
! 87:
! 88: if (mpz_cmp_ui(m, 0) <= 0 || mpz_cmp(m, this->n) >= 0)
! 89: { /* m must be <= n-1, and while 0 is technically a valid value, it
! 90: * doesn't really make sense here, so we filter that too */
! 91: mpz_clear(m);
! 92: return chunk_empty;
! 93: }
! 94:
! 95: mpz_init(c);
! 96: mpz_powm(c, m, this->e, this->n);
! 97:
! 98: encrypted.len = this->k;
! 99: encrypted.ptr = mpz_export(NULL, NULL, 1, encrypted.len, 1, 0, c);
! 100: if (encrypted.ptr == NULL)
! 101: {
! 102: encrypted.len = 0;
! 103: }
! 104:
! 105: mpz_clear(c);
! 106: mpz_clear(m);
! 107:
! 108: return encrypted;
! 109: }
! 110:
! 111: /**
! 112: * RSAVP1 algorithm specified in PKCS#1.
! 113: */
! 114: static chunk_t rsavp1(private_gmp_rsa_public_key_t *this, chunk_t data)
! 115: {
! 116: return rsaep(this, data);
! 117: }
! 118:
! 119: /**
! 120: * Verification of an EMSA PKCS1 signature described in PKCS#1
! 121: */
! 122: static bool verify_emsa_pkcs1_signature(private_gmp_rsa_public_key_t *this,
! 123: hash_algorithm_t algorithm,
! 124: chunk_t data, chunk_t signature)
! 125: {
! 126: chunk_t em_expected, em;
! 127: bool success = FALSE;
! 128:
! 129: /* remove any preceding 0-bytes from signature */
! 130: while (signature.len && *(signature.ptr) == 0x00)
! 131: {
! 132: signature = chunk_skip(signature, 1);
! 133: }
! 134:
! 135: if (signature.len == 0 || signature.len > this->k)
! 136: {
! 137: return FALSE;
! 138: }
! 139:
! 140: /* generate expected signature value */
! 141: if (!gmp_emsa_pkcs1_signature_data(algorithm, data, this->k, &em_expected))
! 142: {
! 143: return FALSE;
! 144: }
! 145:
! 146: /* unpack signature */
! 147: em = rsavp1(this, signature);
! 148:
! 149: success = chunk_equals_const(em_expected, em);
! 150:
! 151: chunk_free(&em_expected);
! 152: chunk_free(&em);
! 153: return success;
! 154: }
! 155:
! 156: /**
! 157: * Verification of an EMSA PSS signature described in PKCS#1
! 158: */
! 159: static bool verify_emsa_pss_signature(private_gmp_rsa_public_key_t *this,
! 160: rsa_pss_params_t *params, chunk_t data,
! 161: chunk_t signature)
! 162: {
! 163: ext_out_function_t xof;
! 164: hasher_t *hasher = NULL;
! 165: xof_t *mgf = NULL;
! 166: chunk_t em, hash, salt, db, h, dbmask, m;
! 167: size_t embits, maskbits;
! 168: int i;
! 169: bool success = FALSE;
! 170:
! 171: if (!params)
! 172: {
! 173: return FALSE;
! 174: }
! 175: xof = xof_mgf1_from_hash_algorithm(params->mgf1_hash);
! 176: if (xof == XOF_UNDEFINED)
! 177: {
! 178: DBG1(DBG_LIB, "%N is not supported for MGF1", hash_algorithm_names,
! 179: params->mgf1_hash);
! 180: return FALSE;
! 181: }
! 182: chunk_skip_zero(signature);
! 183: if (signature.len == 0 || signature.len > this->k)
! 184: {
! 185: return FALSE;
! 186: }
! 187: /* EM = RSAVP1((n, e), S) */
! 188: em = rsavp1(this, signature);
! 189: if (!em.len)
! 190: {
! 191: goto error;
! 192: }
! 193: /* emBits = modBits - 1 */
! 194: embits = mpz_sizeinbase(this->n, 2) - 1;
! 195: /* mHash = Hash(M) */
! 196: hasher = lib->crypto->create_hasher(lib->crypto, params->hash);
! 197: if (!hasher)
! 198: {
! 199: DBG1(DBG_LIB, "hash algorithm %N not supported",
! 200: hash_algorithm_names, params->hash);
! 201: goto error;
! 202: }
! 203: hash = chunk_alloca(hasher->get_hash_size(hasher));
! 204: if (!hasher->get_hash(hasher, data, hash.ptr))
! 205: {
! 206: goto error;
! 207: }
! 208: salt.len = params->salt_len;
! 209: /* verify general structure of EM */
! 210: maskbits = (8 * em.len) - embits;
! 211: if (em.len < (hash.len + salt.len + 2) || em.ptr[em.len-1] != 0xbc ||
! 212: (em.ptr[0] & (0xff << (8-maskbits))))
! 213: { /* inconsistent */
! 214: goto error;
! 215: }
! 216: /* split EM in maskedDB and H */
! 217: db = chunk_create(em.ptr, em.len - hash.len - 1);
! 218: h = chunk_create(em.ptr + db.len, hash.len);
! 219: /* dbMask = MGF(H, emLen - hLen - 1) */
! 220: mgf = lib->crypto->create_xof(lib->crypto, xof);
! 221: if (!mgf)
! 222: {
! 223: DBG1(DBG_LIB, "%N not supported", ext_out_function_names, xof);
! 224: goto error;
! 225: }
! 226: dbmask = chunk_alloca(db.len);
! 227: if (!mgf->set_seed(mgf, h) ||
! 228: !mgf->get_bytes(mgf, dbmask.len, dbmask.ptr))
! 229: {
! 230: DBG1(DBG_LIB, "%N not supported or failed", ext_out_function_names, xof);
! 231: goto error;
! 232: }
! 233: /* DB = maskedDB xor dbMask */
! 234: memxor(db.ptr, dbmask.ptr, db.len);
! 235: if (maskbits)
! 236: {
! 237: db.ptr[0] &= (0xff >> maskbits);
! 238: }
! 239: /* check DB = PS | 0x01 | salt */
! 240: for (i = 0; i < (db.len - salt.len - 1); i++)
! 241: {
! 242: if (db.ptr[i])
! 243: { /* padding not 0 */
! 244: goto error;
! 245: }
! 246: }
! 247: if (db.ptr[i++] != 0x01)
! 248: { /* 0x01 not found */
! 249: goto error;
! 250: }
! 251: salt.ptr = &db.ptr[i];
! 252: /* M' = 0x0000000000000000 | mHash | salt */
! 253: m = chunk_cata("ccc",
! 254: chunk_from_chars(0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00),
! 255: hash, salt);
! 256: if (!hasher->get_hash(hasher, m, hash.ptr))
! 257: {
! 258: goto error;
! 259: }
! 260: success = memeq_const(h.ptr, hash.ptr, hash.len);
! 261:
! 262: error:
! 263: DESTROY_IF(hasher);
! 264: DESTROY_IF(mgf);
! 265: free(em.ptr);
! 266: return success;
! 267: }
! 268:
! 269: METHOD(public_key_t, get_type, key_type_t,
! 270: private_gmp_rsa_public_key_t *this)
! 271: {
! 272: return KEY_RSA;
! 273: }
! 274:
! 275: METHOD(public_key_t, verify, bool,
! 276: private_gmp_rsa_public_key_t *this, signature_scheme_t scheme, void *params,
! 277: chunk_t data, chunk_t signature)
! 278: {
! 279: switch (scheme)
! 280: {
! 281: case SIGN_RSA_EMSA_PKCS1_NULL:
! 282: return verify_emsa_pkcs1_signature(this, HASH_UNKNOWN, data, signature);
! 283: case SIGN_RSA_EMSA_PKCS1_SHA2_224:
! 284: return verify_emsa_pkcs1_signature(this, HASH_SHA224, data, signature);
! 285: case SIGN_RSA_EMSA_PKCS1_SHA2_256:
! 286: return verify_emsa_pkcs1_signature(this, HASH_SHA256, data, signature);
! 287: case SIGN_RSA_EMSA_PKCS1_SHA2_384:
! 288: return verify_emsa_pkcs1_signature(this, HASH_SHA384, data, signature);
! 289: case SIGN_RSA_EMSA_PKCS1_SHA2_512:
! 290: return verify_emsa_pkcs1_signature(this, HASH_SHA512, data, signature);
! 291: case SIGN_RSA_EMSA_PKCS1_SHA3_224:
! 292: return verify_emsa_pkcs1_signature(this, HASH_SHA3_224, data, signature);
! 293: case SIGN_RSA_EMSA_PKCS1_SHA3_256:
! 294: return verify_emsa_pkcs1_signature(this, HASH_SHA3_256, data, signature);
! 295: case SIGN_RSA_EMSA_PKCS1_SHA3_384:
! 296: return verify_emsa_pkcs1_signature(this, HASH_SHA3_384, data, signature);
! 297: case SIGN_RSA_EMSA_PKCS1_SHA3_512:
! 298: return verify_emsa_pkcs1_signature(this, HASH_SHA3_512, data, signature);
! 299: case SIGN_RSA_EMSA_PKCS1_SHA1:
! 300: return verify_emsa_pkcs1_signature(this, HASH_SHA1, data, signature);
! 301: case SIGN_RSA_EMSA_PKCS1_MD5:
! 302: return verify_emsa_pkcs1_signature(this, HASH_MD5, data, signature);
! 303: case SIGN_RSA_EMSA_PSS:
! 304: return verify_emsa_pss_signature(this, params, data, signature);
! 305: default:
! 306: DBG1(DBG_LIB, "signature scheme %N not supported in RSA",
! 307: signature_scheme_names, scheme);
! 308: return FALSE;
! 309: }
! 310: }
! 311:
! 312: #define MIN_PS_PADDING 8
! 313:
! 314: METHOD(public_key_t, encrypt_, bool,
! 315: private_gmp_rsa_public_key_t *this, encryption_scheme_t scheme,
! 316: chunk_t plain, chunk_t *crypto)
! 317: {
! 318: chunk_t em;
! 319: u_char *pos;
! 320: int padding;
! 321: rng_t *rng;
! 322:
! 323: if (scheme != ENCRYPT_RSA_PKCS1)
! 324: {
! 325: DBG1(DBG_LIB, "encryption scheme %N not supported",
! 326: encryption_scheme_names, scheme);
! 327: return FALSE;
! 328: }
! 329: /* number of pseudo-random padding octets */
! 330: padding = this->k - plain.len - 3;
! 331: if (padding < MIN_PS_PADDING)
! 332: {
! 333: DBG1(DBG_LIB, "pseudo-random padding must be at least %d octets",
! 334: MIN_PS_PADDING);
! 335: return FALSE;
! 336: }
! 337: rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
! 338: if (rng == NULL)
! 339: {
! 340: DBG1(DBG_LIB, "no random generator available");
! 341: return FALSE;
! 342: }
! 343:
! 344: /* padding according to PKCS#1 7.2.1 (RSAES-PKCS1-v1.5-ENCRYPT) */
! 345: DBG2(DBG_LIB, "padding %u bytes of data to the rsa modulus size of"
! 346: " %u bytes", plain.len, this->k);
! 347: em.len = this->k;
! 348: em.ptr = malloc(em.len);
! 349: pos = em.ptr;
! 350: *pos++ = 0x00;
! 351: *pos++ = 0x02;
! 352:
! 353: /* fill with pseudo random octets */
! 354: if (!rng_get_bytes_not_zero(rng, padding, pos, TRUE))
! 355: {
! 356: DBG1(DBG_LIB, "failed to allocate padding");
! 357: chunk_clear(&em);
! 358: rng->destroy(rng);
! 359: return FALSE;
! 360: }
! 361: rng->destroy(rng);
! 362:
! 363: pos += padding;
! 364:
! 365: /* append the padding terminator */
! 366: *pos++ = 0x00;
! 367:
! 368: /* now add the data */
! 369: memcpy(pos, plain.ptr, plain.len);
! 370: DBG3(DBG_LIB, "padded data before rsa encryption: %B", &em);
! 371:
! 372: /* rsa encryption using PKCS#1 RSAEP */
! 373: *crypto = rsaep(this, em);
! 374: DBG3(DBG_LIB, "rsa encrypted data: %B", crypto);
! 375: chunk_clear(&em);
! 376: return TRUE;
! 377: }
! 378:
! 379: METHOD(public_key_t, get_keysize, int,
! 380: private_gmp_rsa_public_key_t *this)
! 381: {
! 382: return mpz_sizeinbase(this->n, 2);
! 383: }
! 384:
! 385: METHOD(public_key_t, get_encoding, bool,
! 386: private_gmp_rsa_public_key_t *this, cred_encoding_type_t type,
! 387: chunk_t *encoding)
! 388: {
! 389: chunk_t n, e;
! 390: bool success;
! 391:
! 392: n = gmp_mpz_to_chunk(this->n);
! 393: e = gmp_mpz_to_chunk(this->e);
! 394:
! 395: success = lib->encoding->encode(lib->encoding, type, NULL, encoding,
! 396: CRED_PART_RSA_MODULUS, n, CRED_PART_RSA_PUB_EXP, e, CRED_PART_END);
! 397: chunk_free(&n);
! 398: chunk_free(&e);
! 399:
! 400: return success;
! 401: }
! 402:
! 403: METHOD(public_key_t, get_fingerprint, bool,
! 404: private_gmp_rsa_public_key_t *this, cred_encoding_type_t type, chunk_t *fp)
! 405: {
! 406: chunk_t n, e;
! 407: bool success;
! 408:
! 409: if (lib->encoding->get_cache(lib->encoding, type, this, fp))
! 410: {
! 411: return TRUE;
! 412: }
! 413: n = gmp_mpz_to_chunk(this->n);
! 414: e = gmp_mpz_to_chunk(this->e);
! 415:
! 416: success = lib->encoding->encode(lib->encoding, type, this, fp,
! 417: CRED_PART_RSA_MODULUS, n, CRED_PART_RSA_PUB_EXP, e, CRED_PART_END);
! 418: chunk_free(&n);
! 419: chunk_free(&e);
! 420:
! 421: return success;
! 422: }
! 423:
! 424: METHOD(public_key_t, get_ref, public_key_t*,
! 425: private_gmp_rsa_public_key_t *this)
! 426: {
! 427: ref_get(&this->ref);
! 428: return &this->public.key;
! 429: }
! 430:
! 431: METHOD(public_key_t, destroy, void,
! 432: private_gmp_rsa_public_key_t *this)
! 433: {
! 434: if (ref_put(&this->ref))
! 435: {
! 436: mpz_clear(this->n);
! 437: mpz_clear(this->e);
! 438: lib->encoding->clear_cache(lib->encoding, this);
! 439: free(this);
! 440: }
! 441: }
! 442:
! 443: /**
! 444: * See header.
! 445: */
! 446: gmp_rsa_public_key_t *gmp_rsa_public_key_load(key_type_t type, va_list args)
! 447: {
! 448: private_gmp_rsa_public_key_t *this;
! 449: chunk_t n, e;
! 450:
! 451: n = e = chunk_empty;
! 452: while (TRUE)
! 453: {
! 454: switch (va_arg(args, builder_part_t))
! 455: {
! 456: case BUILD_RSA_MODULUS:
! 457: n = va_arg(args, chunk_t);
! 458: continue;
! 459: case BUILD_RSA_PUB_EXP:
! 460: e = va_arg(args, chunk_t);
! 461: continue;
! 462: case BUILD_END:
! 463: break;
! 464: default:
! 465: return NULL;
! 466: }
! 467: break;
! 468: }
! 469: if (!e.len || !n.len || (n.ptr[n.len-1] & 0x01) == 0)
! 470: {
! 471: return NULL;
! 472: }
! 473:
! 474: INIT(this,
! 475: .public = {
! 476: .key = {
! 477: .get_type = _get_type,
! 478: .verify = _verify,
! 479: .encrypt = _encrypt_,
! 480: .equals = public_key_equals,
! 481: .get_keysize = _get_keysize,
! 482: .get_fingerprint = _get_fingerprint,
! 483: .has_fingerprint = public_key_has_fingerprint,
! 484: .get_encoding = _get_encoding,
! 485: .get_ref = _get_ref,
! 486: .destroy = _destroy,
! 487: },
! 488: },
! 489: .ref = 1,
! 490: );
! 491:
! 492: mpz_init(this->n);
! 493: mpz_init(this->e);
! 494:
! 495: mpz_import(this->n, n.len, 1, 1, 1, 0, n.ptr);
! 496: mpz_import(this->e, e.len, 1, 1, 1, 0, e.ptr);
! 497:
! 498: this->k = (mpz_sizeinbase(this->n, 2) + 7) / BITS_PER_BYTE;
! 499:
! 500: if (!mpz_sgn(this->e))
! 501: {
! 502: destroy(this);
! 503: return NULL;
! 504: }
! 505: return &this->public;
! 506: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>