diff options
Diffstat (limited to 'src/libstrongswan/plugins/gmp')
-rw-r--r-- | src/libstrongswan/plugins/gmp/Makefile.in | 17 | ||||
-rw-r--r-- | src/libstrongswan/plugins/gmp/gmp_diffie_hellman.c | 6 | ||||
-rw-r--r-- | src/libstrongswan/plugins/gmp/gmp_plugin.c | 2 | ||||
-rw-r--r-- | src/libstrongswan/plugins/gmp/gmp_rsa_private_key.c | 341 | ||||
-rw-r--r-- | src/libstrongswan/plugins/gmp/gmp_rsa_public_key.c | 350 | ||||
-rw-r--r-- | src/libstrongswan/plugins/gmp/gmp_rsa_public_key.h | 2 |
6 files changed, 607 insertions, 111 deletions
diff --git a/src/libstrongswan/plugins/gmp/Makefile.in b/src/libstrongswan/plugins/gmp/Makefile.in index c406f3af6..a60cd998c 100644 --- a/src/libstrongswan/plugins/gmp/Makefile.in +++ b/src/libstrongswan/plugins/gmp/Makefile.in @@ -1,4 +1,4 @@ -# Makefile.in generated by automake 1.10.1 from Makefile.am. +# Makefile.in generated by automake 1.10.2 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, @@ -88,6 +88,7 @@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ +DLLIB = @DLLIB@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ @@ -110,6 +111,9 @@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LEXLIB = @LEXLIB@ LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ +LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@ +LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@ +LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ @@ -121,6 +125,7 @@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ @@ -134,6 +139,8 @@ PATH_SEPARATOR = @PATH_SEPARATOR@ PERL = @PERL@ PKG_CONFIG = @PKG_CONFIG@ RANLIB = @RANLIB@ +RUBY = @RUBY@ +RUBYINCLUDE = @RUBYINCLUDE@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ @@ -194,6 +201,7 @@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ piddir = @piddir@ plugindir = @plugindir@ +pluto_plugins = @pluto_plugins@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ @@ -205,6 +213,7 @@ srcdir = @srcdir@ strongswan_conf = @strongswan_conf@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ xml_CFLAGS = @xml_CFLAGS@ @@ -227,8 +236,8 @@ $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \ - && exit 0; \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ @@ -325,7 +334,7 @@ ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ - $(AWK) '{ files[$$0] = 1; nonemtpy = 1; } \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS diff --git a/src/libstrongswan/plugins/gmp/gmp_diffie_hellman.c b/src/libstrongswan/plugins/gmp/gmp_diffie_hellman.c index 294fb722f..a03e83e66 100644 --- a/src/libstrongswan/plugins/gmp/gmp_diffie_hellman.c +++ b/src/libstrongswan/plugins/gmp/gmp_diffie_hellman.c @@ -14,8 +14,6 @@ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. - * - * $Id: gmp_diffie_hellman.c 4566 2008-11-04 13:12:11Z martin $ */ #include <gmp.h> @@ -30,7 +28,7 @@ */ static u_int8_t group1_modulus[] = { 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,0x21,0x68,0xC2,0x34, - 0xC4,0xC6,0x62,0x8B,0x80 ,0xDC,0x1C,0xD1,0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74, + 0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1,0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74, 0x02,0x0B,0xBE,0xA6,0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD, 0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D,0xF2,0x5F,0x14,0x37, 0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45,0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6, @@ -562,7 +560,7 @@ gmp_diffie_hellman_t *gmp_diffie_hellman_create(diffie_hellman_group_t group) } ansi_x9_42 = lib->settings->get_int(lib->settings, - "charon.dh_exponent_ansi_x9_42", TRUE); + "libstrongswan.dh_exponent_ansi_x9_42", TRUE); exponent_len = (ansi_x9_42) ? this->p_len : this->opt_exponent_len; rng->allocate_bytes(rng, exponent_len, &random); rng->destroy(rng); diff --git a/src/libstrongswan/plugins/gmp/gmp_plugin.c b/src/libstrongswan/plugins/gmp/gmp_plugin.c index 7711b6d34..f6ea964c1 100644 --- a/src/libstrongswan/plugins/gmp/gmp_plugin.c +++ b/src/libstrongswan/plugins/gmp/gmp_plugin.c @@ -11,8 +11,6 @@ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. - * - * $Id: gmp_plugin.c 4309 2008-08-28 11:07:57Z martin $ */ #include "gmp_plugin.h" diff --git a/src/libstrongswan/plugins/gmp/gmp_rsa_private_key.c b/src/libstrongswan/plugins/gmp/gmp_rsa_private_key.c index e445dd670..cbc112762 100644 --- a/src/libstrongswan/plugins/gmp/gmp_rsa_private_key.c +++ b/src/libstrongswan/plugins/gmp/gmp_rsa_private_key.c @@ -12,8 +12,6 @@ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. - * - * $Id: gmp_rsa_private_key.c 4345 2008-09-17 08:10:48Z martin $ */ #include <gmp.h> @@ -28,6 +26,7 @@ #include <asn1/oid.h> #include <asn1/asn1.h> #include <asn1/asn1_parser.h> +#include <pgp/pgp.h> /** * Public exponent to use for key generation. @@ -112,11 +111,12 @@ struct private_gmp_rsa_private_key_t { }; /** - * shared functions, implemented in gmp_rsa_public_key.c + * Shared functions defined in gmp_rsa_public_key.c */ -bool gmp_rsa_public_key_build_id(mpz_t n, mpz_t e, identification_t **keyid, - identification_t **keyid_info); -gmp_rsa_public_key_t *gmp_rsa_public_key_create_from_n_e(mpz_t n, mpz_t e); +extern bool gmp_rsa_public_key_build_id(mpz_t n, mpz_t e, + identification_t **keyid, + identification_t **keyid_info); +extern gmp_rsa_public_key_t *gmp_rsa_public_key_create_from_n_e(mpz_t n, mpz_t e); /** * Auxiliary function overwriting private key material with zero bytes @@ -141,10 +141,10 @@ static status_t compute_prime(private_gmp_rsa_private_key_t *this, rng_t *rng; chunk_t random_bytes; - rng = lib->crypto->create_rng(lib->crypto, RNG_REAL); + rng = lib->crypto->create_rng(lib->crypto, RNG_TRUE); if (!rng) { - DBG1("no RNG of quality %N found", rng_quality_names, RNG_REAL); + DBG1("no RNG of quality %N found", rng_quality_names, RNG_TRUE); return FAILED; } @@ -217,33 +217,44 @@ static bool build_emsa_pkcs1_signature(private_gmp_rsa_private_key_t *this, hash_algorithm_t hash_algorithm, chunk_t data, chunk_t *signature) { - hasher_t *hasher; - chunk_t em, digestInfo, hash; - int hash_oid = hasher_algorithm_to_oid(hash_algorithm); - - if (hash_oid == OID_UNKNOWN) + chunk_t digestInfo = chunk_empty; + chunk_t em; + + if (hash_algorithm != HASH_UNKNOWN) { - return FALSE; + hasher_t *hasher; + chunk_t hash; + int hash_oid = hasher_algorithm_to_oid(hash_algorithm); + + if (hash_oid == OID_UNKNOWN) + { + return FALSE; + } + + hasher = lib->crypto->create_hasher(lib->crypto, hash_algorithm); + if (hasher == NULL) + { + return FALSE; + } + hasher->allocate_hash(hasher, data, &hash); + hasher->destroy(hasher); + + /* build DER-encoded digestInfo */ + digestInfo = asn1_wrap(ASN1_SEQUENCE, "cm", + asn1_algorithmIdentifier(hash_oid), + asn1_simple_object(ASN1_OCTET_STRING, hash) + ); + chunk_free(&hash); + data = digestInfo; } - /* get hasher */ - hasher = lib->crypto->create_hasher(lib->crypto, hash_algorithm); - if (hasher == NULL) + if (data.len > this->k - 3) { + free(digestInfo.ptr); + DBG1("unable to sign %d bytes using a %dbit key", data.len, this->k * 8); return FALSE; } - /* build hash */ - hasher->allocate_hash(hasher, data, &hash); - hasher->destroy(hasher); - - /* build DER-encoded digestInfo */ - digestInfo = asn1_wrap(ASN1_SEQUENCE, "cm", - asn1_algorithmIdentifier(hash_oid), - asn1_simple_object(ASN1_OCTET_STRING, hash) - ); - chunk_free(&hash); - /* build chunk to rsa-decrypt: * EM = 0x00 || 0x01 || PS || 0x00 || T. * PS = 0xFF padding, with length to fill em @@ -257,9 +268,9 @@ static bool build_emsa_pkcs1_signature(private_gmp_rsa_private_key_t *this, /* set magic bytes */ *(em.ptr) = 0x00; *(em.ptr+1) = 0x01; - *(em.ptr + em.len - digestInfo.len - 1) = 0x00; + *(em.ptr + em.len - data.len - 1) = 0x00; /* set DER-encoded hash */ - memcpy(em.ptr + em.len - digestInfo.len, digestInfo.ptr, digestInfo.len); + memcpy(em.ptr + em.len - data.len, data.ptr, data.len); /* build signature */ *signature = rsasp1(this, em); @@ -271,7 +282,7 @@ static bool build_emsa_pkcs1_signature(private_gmp_rsa_private_key_t *this, } /** - * Implementation of gmp_rsa_private_key.destroy. + * Implementation of gmp_rsa_private_key.get_type. */ static key_type_t get_type(private_gmp_rsa_private_key_t *this) { @@ -279,15 +290,15 @@ static key_type_t get_type(private_gmp_rsa_private_key_t *this) } /** - * Implementation of gmp_rsa_private_key.destroy. + * Implementation of gmp_rsa_private_key.sign. */ static bool sign(private_gmp_rsa_private_key_t *this, signature_scheme_t scheme, chunk_t data, chunk_t *signature) { switch (scheme) { - case SIGN_DEFAULT: - /* default is EMSA-PKCS1 using SHA1 */ + case SIGN_RSA_EMSA_PKCS1_NULL: + return build_emsa_pkcs1_signature(this, HASH_UNKNOWN, data, signature); case SIGN_RSA_EMSA_PKCS1_SHA1: return build_emsa_pkcs1_signature(this, HASH_SHA1, data, signature); case SIGN_RSA_EMSA_PKCS1_SHA256: @@ -306,17 +317,46 @@ static bool sign(private_gmp_rsa_private_key_t *this, signature_scheme_t scheme, } /** - * Implementation of gmp_rsa_private_key.destroy. + * Implementation of gmp_rsa_private_key.decrypt. */ -static bool decrypt(private_gmp_rsa_private_key_t *this, - chunk_t crypto, chunk_t *plain) +static bool decrypt(private_gmp_rsa_private_key_t *this, chunk_t crypto, + chunk_t *plain) { - DBG1("RSA private key decryption not implemented"); - return FALSE; + chunk_t em, stripped; + bool success = FALSE; + + /* rsa decryption using PKCS#1 RSADP */ + stripped = em = rsadp(this, crypto); + + /* PKCS#1 v1.5 8.1 encryption-block formatting (EB = 00 || 02 || PS || 00 || D) */ + + /* check for hex pattern 00 02 in decrypted message */ + if ((*stripped.ptr++ != 0x00) || (*(stripped.ptr++) != 0x02)) + { + DBG1("incorrect padding - probably wrong rsa key"); + goto end; + } + stripped.len -= 2; + + /* the plaintext data starts after first 0x00 byte */ + while (stripped.len-- > 0 && *stripped.ptr++ != 0x00) + + if (stripped.len == 0) + { + DBG1("no plaintext data"); + goto end; + } + + *plain = chunk_clone(stripped); + success = TRUE; + +end: + chunk_clear(&em); + return success; } /** - * Implementation of gmp_rsa_private_key.destroy. + * Implementation of gmp_rsa_private_key.get_keysize. */ static size_t get_keysize(private_gmp_rsa_private_key_t *this) { @@ -324,7 +364,7 @@ static size_t get_keysize(private_gmp_rsa_private_key_t *this) } /** - * Implementation of gmp_rsa_private_key.destroy. + * Implementation of gmp_rsa_private_key.get_id. */ static identification_t* get_id(private_gmp_rsa_private_key_t *this, id_type_t type) @@ -349,7 +389,35 @@ static gmp_rsa_public_key_t* get_public_key(private_gmp_rsa_private_key_t *this) } /** - * Implementation of gmp_rsa_private_key.destroy. + * Implementation of gmp_rsa_private_key.equals. + */ +static bool equals(private_gmp_rsa_private_key_t *this, private_key_t *other) +{ + identification_t *keyid; + + if (&this->public.interface == other) + { + return TRUE; + } + if (other->get_type(other) != KEY_RSA) + { + return FALSE; + } + keyid = other->get_id(other, ID_PUBKEY_SHA1); + if (keyid && keyid->equals(keyid, this->keyid)) + { + return TRUE; + } + keyid = other->get_id(other, ID_PUBKEY_INFO_SHA1); + if (keyid && keyid->equals(keyid, this->keyid_info)) + { + return TRUE; + } + return FALSE; +} + +/** + * Implementation of gmp_rsa_private_key.belongs_to. */ static bool belongs_to(private_gmp_rsa_private_key_t *this, public_key_t *public) { @@ -373,19 +441,27 @@ static bool belongs_to(private_gmp_rsa_private_key_t *this, public_key_t *public } /** - * convert a MP integer into a DER coded ASN.1 object + * Convert a MP integer into a chunk_t */ -chunk_t gmp_mpz_to_asn1(const mpz_t value) +chunk_t gmp_mpz_to_chunk(const mpz_t value) { chunk_t n; - n.len = 1 + mpz_sizeinbase(value, 2) / 8; /* size in bytes */ + n.len = 1 + mpz_sizeinbase(value, 2) / BITS_PER_BYTE; n.ptr = mpz_export(NULL, NULL, 1, n.len, 1, 0, value); if (n.ptr == NULL) { /* if we have zero in "value", gmp returns NULL */ n.len = 0; } - return asn1_wrap(ASN1_INTEGER, "m", n); + return n; +} + +/** + * Convert a MP integer into a DER coded ASN.1 object + */ +chunk_t gmp_mpz_to_asn1(const mpz_t value) +{ + return asn1_wrap(ASN1_INTEGER, "m", gmp_mpz_to_chunk(value)); } /** @@ -406,7 +482,7 @@ static chunk_t get_encoding(private_gmp_rsa_private_key_t *this) } /** - * Implementation of gmp_rsa_private_key.destroy. + * Implementation of gmp_rsa_private_key.get_ref. */ static private_gmp_rsa_private_key_t* get_ref(private_gmp_rsa_private_key_t *this) { @@ -447,14 +523,14 @@ static status_t check(private_gmp_rsa_private_key_t *this) /* PKCS#1 1.5 section 6 requires modulus to have at least 12 octets. * We actually require more (for security). */ - if (this->k < 512/8) + if (this->k < 512 / BITS_PER_BYTE) { DBG1("key shorter than 512 bits"); return FAILED; } /* we picked a max modulus size to simplify buffer allocation */ - if (this->k > 8192/8) + if (this->k > 8192 / BITS_PER_BYTE) { DBG1("key larger than 8192 bits"); return FAILED; @@ -542,16 +618,17 @@ static private_gmp_rsa_private_key_t *gmp_rsa_private_key_create_empty(void) { private_gmp_rsa_private_key_t *this = malloc_thing(private_gmp_rsa_private_key_t); - this->public.interface.get_type = (key_type_t (*)(private_key_t *this))get_type; - this->public.interface.sign = (bool (*)(private_key_t *this, signature_scheme_t scheme, chunk_t data, chunk_t *signature))sign; - this->public.interface.decrypt = (bool (*)(private_key_t *this, chunk_t crypto, chunk_t *plain))decrypt; - this->public.interface.get_keysize = (size_t (*) (private_key_t *this))get_keysize; - this->public.interface.get_id = (identification_t* (*) (private_key_t *this,id_type_t))get_id; - this->public.interface.get_public_key = (public_key_t* (*)(private_key_t *this))get_public_key; - this->public.interface.belongs_to = (bool (*) (private_key_t *this, public_key_t *public))belongs_to; - this->public.interface.get_encoding = (chunk_t(*)(private_key_t*))get_encoding; - this->public.interface.get_ref = (private_key_t* (*)(private_key_t *this))get_ref; - this->public.interface.destroy = (void (*)(private_key_t *this))destroy; + this->public.interface.get_type = (key_type_t (*) (private_key_t*))get_type; + this->public.interface.sign = (bool (*) (private_key_t*, signature_scheme_t, chunk_t, chunk_t*))sign; + this->public.interface.decrypt = (bool (*) (private_key_t*, chunk_t, chunk_t*))decrypt; + this->public.interface.get_keysize = (size_t (*) (private_key_t*))get_keysize; + this->public.interface.get_id = (identification_t* (*) (private_key_t*, id_type_t))get_id; + this->public.interface.get_public_key = (public_key_t* (*) (private_key_t*))get_public_key; + this->public.interface.equals = (bool (*) (private_key_t*, private_key_t*))equals; + this->public.interface.belongs_to = (bool (*) (private_key_t*, public_key_t*))belongs_to; + this->public.interface.get_encoding = (chunk_t (*) (private_key_t*))get_encoding; + this->public.interface.get_ref = (private_key_t* (*) (private_key_t*))get_ref; + this->public.interface.destroy = (void (*) (private_key_t*))destroy; this->keyid = NULL; this->keyid_info = NULL; @@ -569,7 +646,7 @@ static gmp_rsa_private_key_t *generate(size_t key_size) mpz_t m, q1, t; private_gmp_rsa_private_key_t *this = gmp_rsa_private_key_create_empty(); - key_size = key_size / 8; + key_size = key_size / BITS_PER_BYTE; /* Get values of primes p and q */ if (compute_prime(this, key_size/2, &p) != SUCCESS) @@ -680,7 +757,7 @@ static const asn1Object_t privkeyObjects[] = { /** * load private key from a ASN1 encoded blob */ -static gmp_rsa_private_key_t *load(chunk_t blob) +static gmp_rsa_private_key_t *load_asn1_der(chunk_t blob) { asn1_parser_t *parser; chunk_t object; @@ -708,6 +785,7 @@ static gmp_rsa_private_key_t *load(chunk_t blob) case PRIV_KEY_VERSION: if (object.len > 0 && *object.ptr != 0) { + DBG1("PKCS#1 private key format is not version 1"); goto end; } break; @@ -757,13 +835,144 @@ end: destroy(this); return NULL; } + if (check(this) != SUCCESS) + { + destroy(this); + return NULL; + } + return &this->public; +} + +/** + * load private key from an OpenPGP blob coded according to section + */ +static gmp_rsa_private_key_t *load_pgp(chunk_t blob) +{ + mpz_t u; + int objectID; + chunk_t packet = blob; + private_gmp_rsa_private_key_t *this = gmp_rsa_private_key_create_empty(); + + mpz_init(this->n); + mpz_init(this->e); + mpz_init(this->p); + mpz_init(this->q); + mpz_init(this->d); + mpz_init(this->exp1); + mpz_init(this->exp2); + mpz_init(this->coeff); + + for (objectID = PRIV_KEY_MODULUS; objectID <= PRIV_KEY_COEFF; objectID++) + { + chunk_t object; + + switch (objectID) + { + case PRIV_KEY_PRIV_EXP: + { + pgp_sym_alg_t s2k; + + /* string-to-key usage */ + s2k = pgp_length(&packet, 1); + DBG2("L3 - string-to-key: %d", s2k); + + if (s2k == 255 || s2k == 254) + { + DBG1("string-to-key specifiers not supported"); + goto end; + } + DBG2(" %N", pgp_sym_alg_names, s2k); + + if (s2k != PGP_SYM_ALG_PLAIN) + { + DBG1("%N encryption not supported", pgp_sym_alg_names, s2k); + goto end; + } + break; + } + case PRIV_KEY_EXP1: + case PRIV_KEY_EXP2: + /* not contained in OpenPGP secret key payload */ + continue; + default: + break; + } + + DBG2("L3 - %s:", privkeyObjects[objectID].name); + object.len = pgp_length(&packet, 2); + + if (object.len == PGP_INVALID_LENGTH) + { + DBG1("OpenPGP length is invalid"); + goto end; + } + object.len = (object.len + 7) / BITS_PER_BYTE; + if (object.len > packet.len) + { + DBG1("OpenPGP field is too short"); + goto end; + } + object.ptr = packet.ptr; + packet.ptr += object.len; + packet.len -= object.len; + DBG4("%B", &object); + + switch (objectID) + { + case PRIV_KEY_MODULUS: + mpz_import(this->n, object.len, 1, 1, 1, 0, object.ptr); + break; + case PRIV_KEY_PUB_EXP: + mpz_import(this->e, object.len, 1, 1, 1, 0, object.ptr); + break; + case PRIV_KEY_PRIV_EXP: + mpz_import(this->d, object.len, 1, 1, 1, 0, object.ptr); + break; + case PRIV_KEY_PRIME1: + mpz_import(this->q, object.len, 1, 1, 1, 0, object.ptr); + break; + case PRIV_KEY_PRIME2: + mpz_import(this->p, object.len, 1, 1, 1, 0, object.ptr); + break; + case PRIV_KEY_COEFF: + mpz_import(this->coeff, object.len, 1, 1, 1, 0, object.ptr); + break; + } + } + + /* auxiliary variable */ + mpz_init(u); + + /* exp1 = d mod (p-1) */ + mpz_sub_ui(u, this->p, 1); + mpz_mod(this->exp1, this->d, u); + + /* exp2 = d mod (q-1) */ + mpz_sub_ui(u, this->q, 1); + mpz_mod(this->exp2, this->d, u); + + mpz_clear(u); + chunk_clear(&blob); + + this->k = (mpz_sizeinbase(this->n, 2) + 7) / BITS_PER_BYTE; + if (!gmp_rsa_public_key_build_id(this->n, this->e, + &this->keyid, &this->keyid_info)) + { + destroy(this); + return NULL; + } if (check(this) != SUCCESS) { destroy(this); return NULL; } return &this->public; + +end: + chunk_clear(&blob); + destroy(this); + return NULL; } typedef struct private_builder_t private_builder_t; @@ -804,7 +1013,15 @@ static void add(private_builder_t *this, builder_part_t part, ...) { va_start(args, part); chunk = va_arg(args, chunk_t); - this->key = load(chunk_clone(chunk)); + this->key = load_asn1_der(chunk_clone(chunk)); + va_end(args); + return; + } + case BUILD_BLOB_PGP: + { + va_start(args, part); + chunk = va_arg(args, chunk_t); + this->key = load_pgp(chunk_clone(chunk)); va_end(args); return; } diff --git a/src/libstrongswan/plugins/gmp/gmp_rsa_public_key.c b/src/libstrongswan/plugins/gmp/gmp_rsa_public_key.c index 8a89849cd..1f3e3072f 100644 --- a/src/libstrongswan/plugins/gmp/gmp_rsa_public_key.c +++ b/src/libstrongswan/plugins/gmp/gmp_rsa_public_key.c @@ -12,8 +12,6 @@ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. - * - * $Id: gmp_rsa_public_key.c 4345 2008-09-17 08:10:48Z martin $ */ #include <gmp.h> @@ -30,11 +28,7 @@ #include <asn1/asn1_parser.h> #include <asn1/pem.h> #include <crypto/hashers/hasher.h> - -/** - * defined in gmp_rsa_private_key.c - */ -extern chunk_t gmp_mpz_to_asn1(const mpz_t value); +#include <pgp/pgp.h> typedef struct private_gmp_rsa_public_key_t private_gmp_rsa_public_key_t; @@ -79,6 +73,12 @@ struct private_gmp_rsa_public_key_t { }; /** + * Shared functions defined in gmp_rsa_private_key.c + */ +extern chunk_t gmp_mpz_to_chunk(const mpz_t value); +extern chunk_t gmp_mpz_to_asn1(const mpz_t value); + +/** * RSAEP algorithm specified in PKCS#1. */ static chunk_t rsaep(private_gmp_rsa_public_key_t *this, chunk_t data) @@ -140,11 +140,10 @@ static bool verify_emsa_pkcs1_signature(private_gmp_rsa_public_key_t *this, /* remove any preceding 0-bytes from signature */ while (signature.len && *(signature.ptr) == 0x00) { - signature.len -= 1; - signature.ptr++; + signature = chunk_skip(signature, 1); } - if (signature.len > this->k) + if (signature.len == 0 || signature.len > this->k) { return INVALID_ARG; } @@ -163,8 +162,7 @@ static bool verify_emsa_pkcs1_signature(private_gmp_rsa_public_key_t *this, { goto end; } - em.ptr += 2; - em.len -= 2; + em = chunk_skip(em, 2); /* find magic 0x00 */ while (em.len > 0) @@ -172,8 +170,7 @@ static bool verify_emsa_pkcs1_signature(private_gmp_rsa_public_key_t *this, if (*em.ptr == 0x00) { /* found magic byte, stop */ - em.ptr++; - em.len--; + em = chunk_skip(em, 1); break; } else if (*em.ptr != 0xFF) @@ -181,8 +178,7 @@ static bool verify_emsa_pkcs1_signature(private_gmp_rsa_public_key_t *this, /* bad padding, decryption failed ?!*/ goto end; } - em.ptr++; - em.len--; + em = chunk_skip(em, 1); } if (em.len == 0) @@ -191,13 +187,24 @@ static bool verify_emsa_pkcs1_signature(private_gmp_rsa_public_key_t *this, goto end; } - /* parse ASN.1-based digestInfo */ - { + if (algorithm == HASH_UNKNOWN) + { /* IKEv1 signatures without digestInfo */ + if (em.len != data.len) + { + DBG1("hash size in signature is %u bytes instead of %u bytes", + em.len, data.len); + goto end; + } + success = memeq(em.ptr, data.ptr, data.len); + } + else + { /* IKEv2 and X.509 certificate signatures */ asn1_parser_t *parser; chunk_t object; int objectID; hash_algorithm_t hash_algorithm = HASH_UNKNOWN; + DBG2("signature verification:"); parser = asn1_parser_create(digestInfoObjects, em); while (parser->iterate(parser, &objectID, &object)) @@ -220,8 +227,7 @@ static bool verify_emsa_pkcs1_signature(private_gmp_rsa_public_key_t *this, parser->get_level(parser)+1, NULL); hash_algorithm = hasher_algorithm_from_oid(hash_oid); - if (hash_algorithm == HASH_UNKNOWN || - (algorithm != HASH_UNKNOWN && hash_algorithm != algorithm)) + if (hash_algorithm == HASH_UNKNOWN || hash_algorithm != algorithm) { DBG1("expected hash algorithm %N, but found %N (OID: %#B)", hash_algorithm_names, algorithm, @@ -289,7 +295,7 @@ static bool verify(private_gmp_rsa_public_key_t *this, signature_scheme_t scheme { switch (scheme) { - case SIGN_DEFAULT: /* default is EMSA-PKCS1 using included OID */ + case SIGN_RSA_EMSA_PKCS1_NULL: return verify_emsa_pkcs1_signature(this, HASH_UNKNOWN, data, signature); case SIGN_RSA_EMSA_PKCS1_MD5: return verify_emsa_pkcs1_signature(this, HASH_MD5, data, signature); @@ -308,12 +314,96 @@ static bool verify(private_gmp_rsa_public_key_t *this, signature_scheme_t scheme } } +#define MIN_PS_PADDING 8 + /** - * Implementation of public_key_t.get_keysize. + * Implementation of public_key_t.encrypt. + */ +static bool encrypt_(private_gmp_rsa_public_key_t *this, chunk_t plain, + chunk_t *crypto) +{ + chunk_t em; + u_char *pos; + int padding, i; + rng_t *rng; + + rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); + if (rng == NULL) + { + DBG1("no random generator available"); + return FALSE; + } + + /* number of pseudo-random padding octets */ + padding = this->k - plain.len - 3; + if (padding < MIN_PS_PADDING) + { + DBG1("pseudo-random padding must be at least %d octets", MIN_PS_PADDING); + return FALSE; + } + + /* padding according to PKCS#1 7.2.1 (RSAES-PKCS1-v1.5-ENCRYPT) */ + DBG2("padding %u bytes of data to the rsa modulus size of %u bytes", + plain.len, this->k); + em.len = this->k; + em.ptr = malloc(em.len); + pos = em.ptr; + *pos++ = 0x00; + *pos++ = 0x02; + + /* fill with pseudo random octets */ + rng->get_bytes(rng, padding, pos); + + /* replace zero-valued random octets */ + for (i = 0; i < padding; i++) + { + while (*pos == 0) + { + rng->get_bytes(rng, 1, pos); + } + pos++; + } + rng->destroy(rng); + + /* append the padding terminator */ + *pos++ = 0x00; + + /* now add the data */ + memcpy(pos, plain.ptr, plain.len); + DBG3("padded data before rsa encryption: %B", &em); + + /* rsa encryption using PKCS#1 RSAEP */ + *crypto = rsaep(this, em); + DBG3("rsa encrypted data: %B", crypto); + chunk_clear(&em); + return TRUE; +} + +/** + * Implementation of gmp_rsa_public_key.equals. */ -static bool encrypt(private_gmp_rsa_public_key_t *this, chunk_t crypto, chunk_t *plain) +static bool equals(private_gmp_rsa_public_key_t *this, public_key_t *other) { - DBG1("RSA public key encryption not implemented"); + identification_t *keyid; + + if (&this->public.interface == other) + { + return TRUE; + } + if (other->get_type(other) != KEY_RSA) + { + return FALSE; + } + keyid = other->get_id(other, ID_PUBKEY_SHA1); + if (keyid && keyid->equals(keyid, this->keyid)) + { + return TRUE; + } + keyid = other->get_id(other, ID_PUBKEY_INFO_SHA1); + if (keyid && keyid->equals(keyid, this->keyid_info)) + { + return TRUE; + } return FALSE; } @@ -326,6 +416,46 @@ static size_t get_keysize(private_gmp_rsa_public_key_t *this) } /** + * Build the PGP version 3 RSA key identifier from n and e using + * MD5 hashed modulus and exponent. Also used in rsa_private_key.c. + */ +static identification_t* gmp_rsa_build_pgp_v3_keyid(mpz_t n, mpz_t e) +{ + identification_t *keyid; + chunk_t modulus, mod, exponent, exp, hash; + hasher_t *hasher; + + hasher= lib->crypto->create_hasher(lib->crypto, HASH_MD5); + if (hasher == NULL) + { + DBG1("computation of PGP V3 keyid failed, no MD5 hasher is available"); + return NULL; + } + mod = modulus = gmp_mpz_to_chunk(n); + exp = exponent = gmp_mpz_to_chunk(e); + + /* remove leading zero bytes before hashing modulus and exponent */ + while (mod.len > 0 && *mod.ptr == 0x00) + { + mod.ptr++; + mod.len--; + } + while (exp.len > 0 && *exp.ptr == 0x00) + { + exp.ptr++; + exp.len--; + } + hasher->allocate_hash(hasher, mod, NULL); + hasher->allocate_hash(hasher, exp, &hash); + hasher->destroy(hasher); + keyid = identification_create_from_encoding(ID_KEY_ID, hash); + free(hash.ptr); + free(modulus.ptr); + free(exponent.ptr); + return keyid; +} + +/** * Implementation of public_key_t.get_id. */ static identification_t *get_id(private_gmp_rsa_public_key_t *this, @@ -337,6 +467,8 @@ static identification_t *get_id(private_gmp_rsa_public_key_t *this, return this->keyid_info; case ID_PUBKEY_SHA1: return this->keyid; + case ID_KEY_ID: + return gmp_rsa_build_pgp_v3_keyid(this->n, this->e); default: return NULL; } @@ -383,14 +515,15 @@ static private_gmp_rsa_public_key_t *gmp_rsa_public_key_create_empty() { private_gmp_rsa_public_key_t *this = malloc_thing(private_gmp_rsa_public_key_t); - this->public.interface.get_type = (key_type_t (*)(public_key_t *this))get_type; - this->public.interface.verify = (bool (*)(public_key_t *this, signature_scheme_t scheme, chunk_t data, chunk_t signature))verify; - this->public.interface.encrypt = (bool (*)(public_key_t *this, chunk_t crypto, chunk_t *plain))encrypt; - this->public.interface.get_keysize = (size_t (*) (public_key_t *this))get_keysize; - this->public.interface.get_id = (identification_t* (*) (public_key_t *this,id_type_t))get_id; - this->public.interface.get_encoding = (chunk_t(*)(public_key_t*))get_encoding; - this->public.interface.get_ref = (public_key_t* (*)(public_key_t *this))get_ref; - this->public.interface.destroy = (void (*)(public_key_t *this))destroy; + this->public.interface.get_type = (key_type_t (*) (public_key_t*))get_type; + this->public.interface.verify = (bool (*) (public_key_t*, signature_scheme_t, chunk_t, chunk_t))verify; + this->public.interface.encrypt = (bool (*) (public_key_t*, chunk_t, chunk_t*))encrypt_; + this->public.interface.equals = (bool (*) (public_key_t*, public_key_t*))equals; + this->public.interface.get_keysize = (size_t (*) (public_key_t*))get_keysize; + this->public.interface.get_id = (identification_t* (*) (public_key_t*, id_type_t))get_id; + this->public.interface.get_encoding = (chunk_t(*) (public_key_t*))get_encoding; + this->public.interface.get_ref = (public_key_t* (*) (public_key_t *this))get_ref; + this->public.interface.destroy = (void (*) (public_key_t *this))destroy; this->keyid = NULL; this->keyid_info = NULL; @@ -445,7 +578,7 @@ gmp_rsa_public_key_t *gmp_rsa_public_key_create_from_n_e(mpz_t n, mpz_t e) mpz_init_set(this->n, n); mpz_init_set(this->e, e); - this->k = (mpz_sizeinbase(this->n, 2) + 7) / 8; + this->k = (mpz_sizeinbase(this->n, 2) + 7) / BITS_PER_BYTE; if (!gmp_rsa_public_key_build_id(this->n, this->e, &this->keyid, &this->keyid_info)) { @@ -469,9 +602,9 @@ static const asn1Object_t pubkeyObjects[] = { #define PUB_KEY_EXPONENT 2 /** - * Load a public key from an ASN1 encoded blob + * Load a public key from an ASN.1 encoded blob */ -static gmp_rsa_public_key_t *load(chunk_t blob) +static gmp_rsa_public_key_t *load_asn1_der(chunk_t blob) { asn1_parser_t *parser; chunk_t object; @@ -507,7 +640,7 @@ static gmp_rsa_public_key_t *load(chunk_t blob) return NULL; } - this->k = (mpz_sizeinbase(this->n, 2) + 7) / 8; + this->k = (mpz_sizeinbase(this->n, 2) + 7) / BITS_PER_BYTE; if (!gmp_rsa_public_key_build_id(this->n, this->e, &this->keyid, &this->keyid_info)) @@ -518,6 +651,133 @@ static gmp_rsa_public_key_t *load(chunk_t blob) return &this->public; } +/** + * Load a public key from an OpenPGP blob + */ +static gmp_rsa_public_key_t* load_pgp(chunk_t blob) +{ + int objectID; + chunk_t packet = blob; + private_gmp_rsa_public_key_t *this = gmp_rsa_public_key_create_empty(); + + mpz_init(this->n); + mpz_init(this->e); + + for (objectID = PUB_KEY_MODULUS; objectID <= PUB_KEY_EXPONENT; objectID++) + { + chunk_t object; + + DBG2("L3 - %s:", pubkeyObjects[objectID].name); + object.len = pgp_length(&packet, 2); + + if (object.len == PGP_INVALID_LENGTH) + { + DBG1("OpenPGP length is invalid"); + goto end; + } + object.len = (object.len + 7) / BITS_PER_BYTE; + if (object.len > packet.len) + { + DBG1("OpenPGP field is too short"); + goto end; + } + object.ptr = packet.ptr; + packet.ptr += object.len; + packet.len -= object.len; + DBG4("%B", &object); + + switch (objectID) + { + case PUB_KEY_MODULUS: + mpz_import(this->n, object.len, 1, 1, 1, 0, object.ptr); + break; + case PUB_KEY_EXPONENT: + mpz_import(this->e, object.len, 1, 1, 1, 0, object.ptr); + break; + } + } + + this->k = (mpz_sizeinbase(this->n, 2) + 7) / BITS_PER_BYTE; + free(blob.ptr); + + if (!gmp_rsa_public_key_build_id(this->n, this->e, + &this->keyid, &this->keyid_info)) + { + destroy(this); + return NULL; + } + return &this->public; + +end: + free(blob.ptr); + destroy(this); + return NULL; +} + +/** + * Load a public key from an RFC 3110 encoded blob + */ +static gmp_rsa_public_key_t *load_rfc_3110(chunk_t blob) +{ + chunk_t exponent, modulus; + u_char *pos = blob.ptr; + size_t len = blob.len; + private_gmp_rsa_public_key_t *this = gmp_rsa_public_key_create_empty(); + + mpz_init(this->n); + mpz_init(this->e); + + if (blob.len < 3) + { + DBG1("RFC 3110 public key blob too short for exponent length"); + goto end; + } + if (pos[0] != 0x00) + { + exponent = chunk_create(pos + 1, pos[0]); + pos++; + len--; + } + else + { + exponent = chunk_create(pos + 3, 256*pos[1] + pos[2]); + pos += 3; + len -= 3; + } + if (exponent.len > len) + { + DBG1("RFC 3110 public key blob too short for exponent"); + goto end; + } + pos += exponent.len; + len -= exponent.len; + + if (len == 0) + { + DBG1("RFC 3110 public key blob has zero length modulus"); + goto end; + } + modulus = chunk_create(pos, len); + + mpz_import(this->n, modulus.len, 1, 1, 1, 0, modulus.ptr); + mpz_import(this->e, exponent.len, 1, 1, 1, 0, exponent.ptr); + this->k = (mpz_sizeinbase(this->n, 2) + 7) / BITS_PER_BYTE; + free(blob.ptr); + + if (!gmp_rsa_public_key_build_id(this->n, this->e, + &this->keyid, &this->keyid_info)) + { + destroy(this); + return NULL; + } + return &this->public; + +end: + free(blob.ptr); + destroy(this); + return NULL; +} + typedef struct private_builder_t private_builder_t; /** * Builder implementation for key loading @@ -556,7 +816,23 @@ static void add(private_builder_t *this, builder_part_t part, ...) { va_start(args, part); chunk = va_arg(args, chunk_t); - this->key = load(chunk_clone(chunk)); + this->key = load_asn1_der(chunk_clone(chunk)); + va_end(args); + return; + } + case BUILD_BLOB_PGP: + { + va_start(args, part); + chunk = va_arg(args, chunk_t); + this->key = load_pgp(chunk_clone(chunk)); + va_end(args); + return; + } + case BUILD_BLOB_RFC_3110: + { + va_start(args, part); + chunk = va_arg(args, chunk_t); + this->key = load_rfc_3110(chunk_clone(chunk)); va_end(args); return; } diff --git a/src/libstrongswan/plugins/gmp/gmp_rsa_public_key.h b/src/libstrongswan/plugins/gmp/gmp_rsa_public_key.h index 46c8c3fd8..ed7b9429f 100644 --- a/src/libstrongswan/plugins/gmp/gmp_rsa_public_key.h +++ b/src/libstrongswan/plugins/gmp/gmp_rsa_public_key.h @@ -12,8 +12,6 @@ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. - * - * $Id: gmp_rsa_public_key.h 5003 2009-03-24 17:43:01Z martin $ */ /** |