refactoring of the ASN.1 parser

This commit is contained in:
Andreas Steffen
2008-04-26 09:24:14 +00:00
parent 3444390241
commit d3d7e46b8c
19 changed files with 1587 additions and 1166 deletions
+38 -39
View File
@@ -18,8 +18,10 @@
#include "gmp_public_key.h"
#include <asn1/asn1.h>
#include <debug.h>
#include <asn1/oid.h>
#include <asn1/asn1.h>
#include <asn1/asn1_parser.h>
/**
* ASN.1 definition of a subjectPublicKeyInfo structure
@@ -27,67 +29,64 @@
static const asn1Object_t pkinfoObjects[] = {
{ 0, "subjectPublicKeyInfo",ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
{ 1, "algorithm", ASN1_EOC, ASN1_RAW }, /* 1 */
{ 1, "subjectPublicKey", ASN1_BIT_STRING, ASN1_NONE }, /* 2 */
{ 2, "publicKey", ASN1_SEQUENCE, ASN1_RAW }, /* 3 */
{ 1, "subjectPublicKey", ASN1_BIT_STRING, ASN1_OBJ }, /* 2 */
};
#define PKINFO 0
#define PKINFO_SUBJECT_PUBLIC_KEY_ALGORITHM 1
#define PKINFO_SUBJECT_PUBLIC_KEY 2
#define PKINFO_PUBLIC_KEY 3
#define PKINFO_ROOF 4
#define PKINFO_ROOF 3
/**
* Load a public key from an ASN1 encoded blob
*/
static public_key_t *load(chunk_t blob)
{
asn1_ctx_t ctx;
chunk_t object, data = chunk_empty;
u_int level;
int objectID = 0;
asn1_parser_t *parser;
chunk_t object;
int objectID;
public_key_t *key = NULL;
key_type_t type = KEY_ANY;
parser = asn1_parser_create(pkinfoObjects, PKINFO_ROOF, blob);
asn1_init(&ctx, blob, 0, FALSE, FALSE);
while (objectID < PKINFO_ROOF)
while (parser->iterate(parser, &objectID, &object))
{
if (!extract_object(pkinfoObjects, &objectID, &object, &level, &ctx))
{
free(blob.ptr);
return NULL;
}
switch (objectID)
{
case PKINFO_SUBJECT_PUBLIC_KEY_ALGORITHM:
switch (parse_algorithmIdentifier(object, level, NULL))
{
int oid = asn1_parse_algorithmIdentifier(object,
parser->get_level(parser)+1, NULL);
if (oid == OID_RSA_ENCRYPTION)
{
case OID_RSA_ENCRYPTION:
type = KEY_RSA;
break;
default:
break;
type = KEY_RSA;
}
else
{
/* key type not supported */
goto end;
}
break;
}
case PKINFO_SUBJECT_PUBLIC_KEY:
if (ctx.blobs[2].len > 0 && *ctx.blobs[2].ptr == 0x00)
{ /* skip initial bit string octet defining 0 unused bits */
ctx.blobs[2].ptr++; ctx.blobs[2].len--;
if (object.len > 0 && *object.ptr == 0x00)
{
/* skip initial bit string octet defining 0 unused bits */
object.ptr++;
object.len--;
key = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, type,
BUILD_BLOB_ASN1_DER,
chunk_clone(object),
BUILD_END);
}
break;
case PKINFO_PUBLIC_KEY:
data = chunk_clone(object);
break;
}
objectID++;
}
}
end:
parser->destroy(parser);
free(blob.ptr);
if (type == KEY_ANY)
{
free(data.ptr);
return NULL;
}
return lib->creds->create(lib->creds, CRED_PUBLIC_KEY, type,
BUILD_BLOB_ASN1_DER, data, BUILD_END);
return key;
}
typedef struct private_builder_t private_builder_t;
@@ -25,7 +25,9 @@
#include "gmp_rsa_public_key.h"
#include <debug.h>
#include <asn1/oid.h>
#include <asn1/asn1.h>
#include <asn1/asn1_parser.h>
/**
* Public exponent to use for key generation.
@@ -109,8 +111,10 @@ struct private_gmp_rsa_private_key_t {
refcount_t ref;
};
/* ASN.1 definition of a PKCS#1 RSA private key */
static const asn1Object_t privkey_objects[] = {
/**
* ASN.1 definition of a PKCS#1 RSA private key
*/
static const asn1Object_t privkeyObjects[] = {
{ 0, "RSAPrivateKey", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */
{ 1, "version", ASN1_INTEGER, ASN1_BODY }, /* 1 */
{ 1, "modulus", ASN1_INTEGER, ASN1_BODY }, /* 2 */
@@ -673,10 +677,11 @@ static gmp_rsa_private_key_t *generate(size_t key_size)
*/
static gmp_rsa_private_key_t *load(chunk_t blob)
{
asn1_ctx_t ctx;
asn1_parser_t *parser;
chunk_t object;
u_int level;
int objectID = 0;
int objectID ;
bool success = TRUE;
private_gmp_rsa_private_key_t *this = gmp_rsa_private_key_create_empty();
mpz_init(this->n);
@@ -688,24 +693,17 @@ static gmp_rsa_private_key_t *load(chunk_t blob)
mpz_init(this->exp2);
mpz_init(this->coeff);
asn1_init(&ctx, blob, 0, FALSE, TRUE);
parser = asn1_parser_create(privkeyObjects, PRIV_KEY_ROOF, blob);
parser->set_flags(parser, FALSE, TRUE);
while (objectID < PRIV_KEY_ROOF)
while (parser->iterate(parser, &objectID, &object))
{
if (!extract_object(privkey_objects, &objectID, &object, &level, &ctx))
{
chunk_clear(&blob);
destroy(this);
return NULL;
}
switch (objectID)
{
case PRIV_KEY_VERSION:
if (object.len > 0 && *object.ptr != 0)
{
chunk_clear(&blob);
destroy(this);
return NULL;
goto end;
}
break;
case PRIV_KEY_MODULUS:
@@ -733,18 +731,28 @@ static gmp_rsa_private_key_t *load(chunk_t blob)
mpz_import(this->coeff, object.len, 1, 1, 1, 0, object.ptr);
break;
}
objectID++;
}
end:
success &= parser->success(parser);
parser->destroy(parser);
chunk_clear(&blob);
if (!success)
{
destroy(this);
return NULL;
}
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);
@@ -25,35 +25,38 @@
#include "gmp_rsa_public_key.h"
#include <debug.h>
#include <crypto/hashers/hasher.h>
#include <asn1/oid.h>
#include <asn1/asn1.h>
#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);
/* ASN.1 definition of RSApublicKey */
/**
* 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 */
};
#define PUB_KEY_RSA_PUBLIC_KEY 0
#define PUB_KEY_MODULUS 1
#define PUB_KEY_EXPONENT 2
#define PUB_KEY_ROOF 3
/* ASN.1 definition of digestInfo */
/**
* 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
@@ -141,7 +144,7 @@ static bool verify_emsa_pkcs1_signature(private_gmp_rsa_public_key_t *this,
chunk_t data, chunk_t signature)
{
chunk_t em_ori, em;
bool res = FALSE;
bool success = FALSE;
/* remove any preceding 0-bytes from signature */
while (signature.len && *(signature.ptr) == 0x00)
@@ -199,20 +202,15 @@ static bool verify_emsa_pkcs1_signature(private_gmp_rsa_public_key_t *this,
/* parse ASN.1-based digestInfo */
{
asn1_ctx_t ctx;
asn1_parser_t *parser;
chunk_t object;
u_int level;
int objectID = 0;
int objectID;
hash_algorithm_t hash_algorithm = HASH_UNKNOWN;
asn1_init(&ctx, em, 0, FALSE, FALSE);
parser = asn1_parser_create(digestInfoObjects, DIGEST_INFO_ROOF, em);
while (objectID < DIGEST_INFO_ROOF)
while (parser->iterate(parser, &objectID, &object))
{
if (!extract_object(digestInfoObjects, &objectID, &object, &level, &ctx))
{
goto end;
}
switch (objectID)
{
case DIGEST_INFO:
@@ -221,20 +219,21 @@ static bool verify_emsa_pkcs1_signature(private_gmp_rsa_public_key_t *this,
{
DBG1("digestInfo field in signature is followed by %u surplus bytes",
em.len - object.len);
goto end;
goto end_parser;
}
break;
}
case DIGEST_INFO_ALGORITHM:
{
int hash_oid = parse_algorithmIdentifier(object, level+1, NULL);
int hash_oid = asn1_parse_algorithmIdentifier(object,
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))
{
DBG1("wrong hash algorithm used in signature");
goto end;
goto end_parser;
}
break;
}
@@ -248,7 +247,7 @@ static bool verify_emsa_pkcs1_signature(private_gmp_rsa_public_key_t *this,
{
DBG1("hash algorithm %N not supported",
hash_algorithm_names, hash_algorithm);
goto end;
goto end_parser;
}
if (object.len != hasher->get_hash_size(hasher))
@@ -256,26 +255,29 @@ static bool verify_emsa_pkcs1_signature(private_gmp_rsa_public_key_t *this,
DBG1("hash size in signature is %u bytes instead of %u "
"bytes", object.len, hasher->get_hash_size(hasher));
hasher->destroy(hasher);
goto end;
goto end_parser;
}
/* build our own hash and compare */
hasher->allocate_hash(hasher, data, &hash);
hasher->destroy(hasher);
res = memeq(object.ptr, hash.ptr, hash.len);
success = memeq(object.ptr, hash.ptr, hash.len);
free(hash.ptr);
break;
}
default:
break;
}
objectID++;
}
end_parser:
success &= parser->success(parser);
parser->destroy(parser);
}
end:
free(em_ori.ptr);
return res;
return success;
}
/**
@@ -465,25 +467,20 @@ gmp_rsa_public_key_t *gmp_rsa_public_key_create_from_n_e(mpz_t n, mpz_t e)
*/
static gmp_rsa_public_key_t *load(chunk_t blob)
{
asn1_ctx_t ctx;
asn1_parser_t *parser;
chunk_t object;
u_int level;
int objectID = 0;
int objectID;
bool success;
private_gmp_rsa_public_key_t *this = gmp_rsa_public_key_create_empty();
mpz_init(this->n);
mpz_init(this->e);
asn1_init(&ctx, blob, 0, FALSE, FALSE);
parser = asn1_parser_create(pubkeyObjects, PUB_KEY_ROOF, blob);
while (objectID < PUB_KEY_ROOF)
while (parser->iterate(parser, &objectID, &object))
{
if (!extract_object(pubkeyObjects, &objectID, &object, &level, &ctx))
{
free(blob.ptr);
destroy(this);
return NULL;
}
switch (objectID)
{
case PUB_KEY_MODULUS:
@@ -493,10 +490,20 @@ static gmp_rsa_public_key_t *load(chunk_t blob)
mpz_import(this->e, object.len, 1, 1, 1, 0, object.ptr);
break;
}
objectID++;
}
free(blob.ptr);
success = parser->success(parser);
parser->destroy(parser);
if (!success)
{
destroy(this);
return NULL;
}
this->k = (mpz_sizeinbase(this->n, 2) + 7) / 8;
if (!gmp_rsa_public_key_build_id(this->n, this->e,
&this->keyid, &this->keyid_info))
{