summaryrefslogtreecommitdiff
path: root/src/libstrongswan/crypto/rsa/rsa_public_key.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libstrongswan/crypto/rsa/rsa_public_key.c')
-rw-r--r--src/libstrongswan/crypto/rsa/rsa_public_key.c326
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;