diff options
Diffstat (limited to 'src/libstrongswan/crypto/rsa/rsa_public_key.c')
-rw-r--r-- | src/libstrongswan/crypto/rsa/rsa_public_key.c | 326 |
1 files changed, 138 insertions, 188 deletions
diff --git a/src/libstrongswan/crypto/rsa/rsa_public_key.c b/src/libstrongswan/crypto/rsa/rsa_public_key.c index 38899670f..6f2158d2b 100644 --- a/src/libstrongswan/crypto/rsa/rsa_public_key.c +++ b/src/libstrongswan/crypto/rsa/rsa_public_key.c @@ -19,6 +19,8 @@ * 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. + * + * RCSID $Id: rsa_public_key.c 3303 2007-10-12 22:49:39Z andreas $ */ #include <gmp.h> @@ -29,74 +31,13 @@ #include "rsa_public_key.h" +#include <debug.h> #include <crypto/hashers/hasher.h> #include <asn1/asn1.h> #include <asn1/pem.h> -/* - * For simplicity, we use these predefined values for hash algorithm OIDs - * These also contain the length of the appended hash - * These values are also used in rsa_private_key.c. - */ - -const u_int8_t md2_oid[] = { - 0x30,0x20, - 0x30,0x0c, - 0x06,0x08, - 0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x02, - 0x05,0x00, - 0x04,0x10 -}; - -const u_int8_t md5_oid[] = { - 0x30,0x20, - 0x30,0x0c, - 0x06,0x08, - 0x2a,0x86,0x48,0x86,0xf7,0x0d,0x02,0x05, - 0x05,0x00, - 0x04,0x10 -}; - -const u_int8_t sha1_oid[] = { - 0x30,0x21, - 0x30,0x09, - 0x06,0x05, - 0x2b,0x0e,0x03,0x02,0x1a, - 0x05,0x00, - 0x04,0x14 -}; - -const u_int8_t sha256_oid[] = { - 0x30,0x31, - 0x30,0x0d, - 0x06,0x09, - 0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x01, - 0x05,0x00, - 0x04,0x20 -}; - -const u_int8_t sha384_oid[] = { - 0x30,0x41, - 0x30,0x0d, - 0x06,0x09, - 0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x02, - 0x05,0x00, - 0x04,0x30 -}; - -const u_int8_t sha512_oid[] = { - 0x30,0x51, - 0x30,0x0d, - 0x06,0x09, - 0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x03, - 0x05,0x00, - 0x04,0x40 -}; - -#define LARGEST_HASH_OID_SIZE sizeof(sha512_oid) - -/* ASN.1 definition public key */ -static const asn1Object_t pubkey_objects[] = { +/* ASN.1 definition of RSApublicKey */ +static const asn1Object_t pubkeyObjects[] = { { 0, "RSAPublicKey", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */ { 1, "modulus", ASN1_INTEGER, ASN1_BODY }, /* 1 */ { 1, "publicExponent", ASN1_INTEGER, ASN1_BODY }, /* 2 */ @@ -107,6 +48,18 @@ static const asn1Object_t pubkey_objects[] = { #define PUB_KEY_EXPONENT 2 #define PUB_KEY_ROOF 3 +/* ASN.1 definition of digestInfo */ +static const asn1Object_t digestInfoObjects[] = { + { 0, "digestInfo", ASN1_SEQUENCE, ASN1_OBJ }, /* 0 */ + { 1, "digestAlgorithm", ASN1_EOC, ASN1_RAW }, /* 1 */ + { 1, "digest", ASN1_OCTET_STRING, ASN1_BODY }, /* 2 */ +}; + +#define DIGEST_INFO 0 +#define DIGEST_INFO_ALGORITHM 1 +#define DIGEST_INFO_DIGEST 2 +#define DIGEST_INFO_ROOF 3 + typedef struct private_rsa_public_key_t private_rsa_public_key_t; /** @@ -186,12 +139,11 @@ static chunk_t rsaep(const private_rsa_public_key_t *this, chunk_t data) /** * Implementation of rsa_public_key.verify_emsa_pkcs1_signature. */ -static status_t verify_emsa_pkcs1_signature(const private_rsa_public_key_t *this, chunk_t data, chunk_t signature) +static status_t verify_emsa_pkcs1_signature(const private_rsa_public_key_t *this, + hash_algorithm_t algorithm, + chunk_t data, chunk_t signature) { - hasher_t *hasher = NULL; - chunk_t hash; - chunk_t em; - u_int8_t *pos; + chunk_t em_ori, em; status_t res = FAILED; /* remove any preceding 0-bytes from signature */ @@ -207,7 +159,7 @@ static status_t verify_emsa_pkcs1_signature(const private_rsa_public_key_t *this } /* unpack signature */ - em = this->rsavp1(this, signature); + em_ori = em = this->rsavp1(this, signature); /* result should look like this: * EM = 0x00 || 0x01 || PS || 0x00 || T. @@ -216,141 +168,160 @@ static status_t verify_emsa_pkcs1_signature(const private_rsa_public_key_t *this */ /* check magic bytes */ - if ((*(em.ptr) != 0x00) || (*(em.ptr+1) != 0x01)) + if (*(em.ptr) != 0x00 || *(em.ptr+1) != 0x01) { + DBG2("incorrect padding - probably wrong RSA key"); goto end; } + em.ptr += 2; + em.len -= 2; /* find magic 0x00 */ - pos = em.ptr + 2; - while (pos <= em.ptr + em.len) + while (em.len > 0) { - if (*pos == 0x00) + if (*em.ptr == 0x00) { /* found magic byte, stop */ - pos++; + em.ptr++; + em.len--; break; } - else if (*pos != 0xFF) + else if (*em.ptr != 0xFF) { /* bad padding, decryption failed ?!*/ goto end; } - pos++; + em.ptr++; + em.len--; } - if (pos + LARGEST_HASH_OID_SIZE > em.ptr + em.len) - { - /* not enought room for oid compare */ - goto end; - } - - if (memeq(md2_oid, pos, sizeof(md2_oid))) - { - hasher = hasher_create(HASH_MD2); - pos += sizeof(md2_oid); - } - else if (memeq(md5_oid, pos, sizeof(md5_oid))) + if (em.len == 0) { - hasher = hasher_create(HASH_MD5); - pos += sizeof(md5_oid); - } - else if (memeq(sha1_oid, pos, sizeof(sha1_oid))) - { - hasher = hasher_create(HASH_SHA1); - pos += sizeof(sha1_oid); - } - else if (memeq(sha256_oid, pos, sizeof(sha256_oid))) - { - hasher = hasher_create(HASH_SHA256); - pos += sizeof(sha256_oid); - } - else if (memeq(sha384_oid, pos, sizeof(sha384_oid))) - { - hasher = hasher_create(HASH_SHA384); - pos += sizeof(sha384_oid); - } - else if (memeq(sha512_oid, pos, sizeof(sha512_oid))) - { - hasher = hasher_create(HASH_SHA512); - pos += sizeof(sha512_oid); - } - - if (hasher == NULL) - { - /* unsupported hash algorithm */ - res = NOT_SUPPORTED;; + /* no digestInfo found */ goto end; } - - if (pos + hasher->get_hash_size(hasher) != em.ptr + em.len) + + /* parse ASN.1-based digestInfo */ { - /* bad length */ - hasher->destroy(hasher); - goto end; + asn1_ctx_t ctx; + chunk_t object; + u_int level; + int objectID = 0; + hash_algorithm_t hash_algorithm = HASH_UNKNOWN; + + asn1_init(&ctx, em, 0, FALSE, FALSE); + + while (objectID < DIGEST_INFO_ROOF) + { + if (!extract_object(digestInfoObjects, &objectID, &object, &level, &ctx)) + { + goto end; + } + switch (objectID) + { + case DIGEST_INFO: + if (em.len > object.len) + { + DBG1("digestInfo field in signature is followed by %u surplus bytes", + em.len - object.len); + goto end; + } + break; + case DIGEST_INFO_ALGORITHM: + { + int hash_oid = parse_algorithmIdentifier(object, level+1, NULL); + + hash_algorithm = hasher_algorithm_from_oid(hash_oid); + if (hash_algorithm == HASH_UNKNOWN + || (algorithm != HASH_UNKNOWN && hash_algorithm != algorithm)) + { + DBG1("wrong hash algorithm used in signature"); + goto end; + } + } + break; + case DIGEST_INFO_DIGEST: + { + chunk_t hash; + hasher_t *hasher = hasher_create(hash_algorithm); + + if (object.len != hasher->get_hash_size(hasher)) + { + DBG1("hash size in signature is %u bytes instead of %u bytes", + object.len, hasher->get_hash_size(hasher)); + hasher->destroy(hasher); + goto end; + } + + /* build our own hash */ + hasher->allocate_hash(hasher, data, &hash); + hasher->destroy(hasher); + + /* compare the hashes */ + res = memeq(object.ptr, hash.ptr, hash.len) ? SUCCESS : FAILED; + free(hash.ptr); + } + break; + default: + break; + } + objectID++; + } } - - /* build our own hash */ - hasher->allocate_hash(hasher, data, &hash); - hasher->destroy(hasher); - - /* compare the hashes */ - res = memeq(hash.ptr, pos, hash.len) ? SUCCESS : FAILED; - free(hash.ptr); end: - free(em.ptr); + free(em_ori.ptr); return res; } - + + /** - * Implementation of rsa_public_key.get_key. + * Implementation of rsa_public_key_t.get_modulus. */ -static status_t get_key(const private_rsa_public_key_t *this, chunk_t *key) -{ - chunk_t n, e; - - n.len = this->k; - n.ptr = mpz_export(NULL, NULL, 1, n.len, 1, 0, this->n); - e.len = this->k; - e.ptr = mpz_export(NULL, NULL, 1, e.len, 1, 0, this->e); - - key->len = this->k * 2; - key->ptr = malloc(key->len); - memcpy(key->ptr, n.ptr, n.len); - memcpy(key->ptr + n.len, e.ptr, e.len); - free(n.ptr); - free(e.ptr); - - return SUCCESS; +static mpz_t *get_modulus(const private_rsa_public_key_t *this) +{ + return (mpz_t*)&this->n; } /** - * Implementation of rsa_public_key.save_key. + * Implementation of rsa_public_key_t.get_keysize. */ -static status_t save_key(const private_rsa_public_key_t *this, char *file) +static size_t get_keysize(const private_rsa_public_key_t *this) { - return NOT_SUPPORTED; + return this->k; } /** - * Implementation of rsa_public_key.get_modulus. + * Build a DER-encoded publicKeyInfo object from an RSA public key. + * Also used in rsa_private_key.c. */ -static mpz_t *get_modulus(const private_rsa_public_key_t *this) +chunk_t rsa_public_key_info_to_asn1(const mpz_t n, const mpz_t e) { - return (mpz_t*)&this->n; + chunk_t rawKey = asn1_wrap(ASN1_SEQUENCE, "mm", + asn1_integer_from_mpz(n), + asn1_integer_from_mpz(e)); + chunk_t publicKey; + + u_char *pos = build_asn1_object(&publicKey, ASN1_BIT_STRING, 1 + rawKey.len); + + *pos++ = 0x00; + memcpy(pos, rawKey.ptr, rawKey.len); + free(rawKey.ptr); + + return asn1_wrap(ASN1_SEQUENCE, "cm", ASN1_rsaEncryption_id, + publicKey); } /** - * Implementation of rsa_public_key.get_keysize. + * Implementation of rsa_public_key_t.get_publicKeyInfo. */ -static size_t get_keysize(const private_rsa_public_key_t *this) +static chunk_t get_publicKeyInfo(const private_rsa_public_key_t *this) { - return this->k; + return rsa_public_key_info_to_asn1(this->n, this->e); } /** - * Implementation of rsa_public_key.get_keyid. + * Implementation of rsa_public_key_t.get_keyid. */ static chunk_t get_keyid(const private_rsa_public_key_t *this) { @@ -358,7 +329,7 @@ static chunk_t get_keyid(const private_rsa_public_key_t *this) } /** - * Implementation of rsa_public_key.clone. + * Implementation of rsa_public_key_t.clone. */ static rsa_public_key_t* _clone(const private_rsa_public_key_t *this) { @@ -373,7 +344,7 @@ static rsa_public_key_t* _clone(const private_rsa_public_key_t *this) } /** - * Implementation of rsa_public_key.destroy. + * Implementation of rsa_public_key_t.destroy. */ static void destroy(private_rsa_public_key_t *this) { @@ -391,11 +362,10 @@ private_rsa_public_key_t *rsa_public_key_create_empty(void) private_rsa_public_key_t *this = malloc_thing(private_rsa_public_key_t); /* public functions */ - this->public.verify_emsa_pkcs1_signature = (status_t (*) (const rsa_public_key_t*,chunk_t,chunk_t))verify_emsa_pkcs1_signature; - this->public.get_key = (status_t (*) (const rsa_public_key_t*,chunk_t*))get_key; - this->public.save_key = (status_t (*) (const rsa_public_key_t*,char*))save_key; + this->public.verify_emsa_pkcs1_signature = (status_t (*) (const rsa_public_key_t*,hash_algorithm_t,chunk_t,chunk_t))verify_emsa_pkcs1_signature; this->public.get_modulus = (mpz_t *(*) (const rsa_public_key_t*))get_modulus; this->public.get_keysize = (size_t (*) (const rsa_public_key_t*))get_keysize; + this->public.get_publicKeyInfo = (chunk_t (*) (const rsa_public_key_t*))get_publicKeyInfo; this->public.get_keyid = (chunk_t (*) (const rsa_public_key_t*))get_keyid; this->public.clone = (rsa_public_key_t* (*) (const rsa_public_key_t*))_clone; this->public.destroy = (void (*) (rsa_public_key_t*))destroy; @@ -407,27 +377,6 @@ private_rsa_public_key_t *rsa_public_key_create_empty(void) return this; } -/** - * Build a DER-encoded publicKeyInfo object from an RSA public key. - * Also used in rsa_private_key.c. - */ -chunk_t rsa_public_key_info_to_asn1(const mpz_t n, const mpz_t e) -{ - chunk_t rawKey = asn1_wrap(ASN1_SEQUENCE, "mm", - asn1_integer_from_mpz(n), - asn1_integer_from_mpz(e)); - chunk_t publicKey; - - u_char *pos = build_asn1_object(&publicKey, ASN1_BIT_STRING, 1 + rawKey.len); - - *pos++ = 0x00; - memcpy(pos, rawKey.ptr, rawKey.len); - free(rawKey.ptr); - - return asn1_wrap(ASN1_SEQUENCE, "cm", ASN1_rsaEncryption_id, - publicKey); -} - /* * See header */ @@ -447,7 +396,7 @@ rsa_public_key_t *rsa_public_key_create_from_chunk(chunk_t blob) while (objectID < PUB_KEY_ROOF) { - if (!extract_object(pubkey_objects, &objectID, &object, &level, &ctx)) + if (!extract_object(pubkeyObjects, &objectID, &object, &level, &ctx)) { destroy(this); return FALSE; @@ -489,8 +438,9 @@ rsa_public_key_t *rsa_public_key_create_from_file(char *filename) rsa_public_key_t *pubkey = NULL; if (!pem_asn1_load_file(filename, NULL, "public key", &chunk, &pgp)) + { return NULL; - + } pubkey = rsa_public_key_create_from_chunk(chunk); free(chunk.ptr); return pubkey; |