diff options
Diffstat (limited to 'src/libstrongswan/plugins/gmp/gmp_rsa_private_key.c')
-rw-r--r-- | src/libstrongswan/plugins/gmp/gmp_rsa_private_key.c | 341 |
1 files changed, 279 insertions, 62 deletions
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; } |