- ported certificate reading to new ASN.1 code
git-svn-id: https://www.opensc-project.org/svnp/opensc/trunk@119 c6295689-39f2-0310-b995-f0e70906c6a9
This commit is contained in:
parent
da88fb7d62
commit
3e96a893ec
2
NEWS
2
NEWS
|
@ -1,6 +1,6 @@
|
||||||
NEWS for OpenSC -- History of user visible changes
|
NEWS for OpenSC -- History of user visible changes
|
||||||
|
|
||||||
New in 0.4.0; 2001-12-xx; Juha Yrjölä:
|
New in 0.4.0; 2001-12-29; Juha Yrjölä:
|
||||||
* Finished migrating to Autotools
|
* Finished migrating to Autotools
|
||||||
* Rewritten ASN.1 decoder (should work better on all PKCS #15 cards)
|
* Rewritten ASN.1 decoder (should work better on all PKCS #15 cards)
|
||||||
* Abstracted card handling, so adding support for new cards is a whiz,
|
* Abstracted card handling, so adding support for new cards is a whiz,
|
||||||
|
|
|
@ -248,9 +248,11 @@ void sc_asn1_print_tags(const u8 * buf, int buflen)
|
||||||
print_tags_recursive(buf, buf, buflen, 0);
|
print_tags_recursive(buf, buf, buflen, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
const u8 *sc_asn1_find_tag(const u8 * buf, int buflen, int tag_in, int *taglen_in)
|
const u8 *sc_asn1_find_tag(struct sc_context *ctx, const u8 * buf,
|
||||||
|
size_t buflen, unsigned int tag_in, size_t *taglen_in)
|
||||||
{
|
{
|
||||||
int left = buflen, cla, tag, taglen;
|
size_t left = buflen, taglen;
|
||||||
|
unsigned int cla, tag;
|
||||||
const u8 *p = buf;
|
const u8 *p = buf;
|
||||||
|
|
||||||
*taglen_in = 0;
|
*taglen_in = 0;
|
||||||
|
@ -265,40 +267,18 @@ const u8 *sc_asn1_find_tag(const u8 * buf, int buflen, int tag_in, int *taglen_i
|
||||||
*taglen_in = taglen;
|
*taglen_in = taglen;
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
if ((cla | tag) == 0xF0) { /* skip 0xF0 foobar tags */
|
|
||||||
fprintf(stderr, "Foobar tag skipped\n");
|
|
||||||
taglen = 0;
|
|
||||||
}
|
|
||||||
left -= taglen;
|
left -= taglen;
|
||||||
p += taglen;
|
p += taglen;
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
const u8 *sc_asn1_skip_tag(const u8 ** buf, int *buflen, int tag_in, int *taglen_out)
|
const u8 *sc_asn1_skip_tag(struct sc_context *ctx, const u8 ** buf, size_t *buflen,
|
||||||
|
unsigned int tag_in, size_t *taglen_out)
|
||||||
{
|
{
|
||||||
const u8 *p = *buf;
|
const u8 *p = *buf;
|
||||||
int len = *buflen, cla, tag, taglen;
|
size_t len = *buflen, taglen;
|
||||||
|
unsigned int cla, tag;
|
||||||
if (read_tag((const u8 **) &p, len, &cla, &tag, &taglen) != 1)
|
|
||||||
return NULL;
|
|
||||||
if ((tag | cla) != tag_in)
|
|
||||||
return NULL;
|
|
||||||
len -= (p - *buf); /* header size */
|
|
||||||
if (taglen > len) {
|
|
||||||
fprintf(stderr, "skip_tag(): too long tag\n");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
*buflen -= (p - *buf) + taglen;
|
|
||||||
*buf = p + taglen; /* point to next tag */
|
|
||||||
*taglen_out = taglen;
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const u8 *sc_asn1_skip_tag2(struct sc_context *ctx, const u8 ** buf, int *buflen, unsigned int tag_in, int *taglen_out)
|
|
||||||
{
|
|
||||||
const u8 *p = *buf;
|
|
||||||
int len = *buflen, cla, tag, taglen;
|
|
||||||
|
|
||||||
if (read_tag((const u8 **) &p, len, &cla, &tag, &taglen) != 1)
|
if (read_tag((const u8 **) &p, len, &cla, &tag, &taglen) != 1)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -340,9 +320,10 @@ static const u8 *sc_asn1_skip_tag2(struct sc_context *ctx, const u8 ** buf, int
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
const u8 *sc_asn1_verify_tag(const u8 * buf, int buflen, int tag_in, int *taglen_out)
|
const u8 *sc_asn1_verify_tag(struct sc_context *ctx, const u8 * buf, size_t buflen,
|
||||||
|
unsigned int tag_in, size_t *taglen_out)
|
||||||
{
|
{
|
||||||
return sc_asn1_skip_tag(&buf, &buflen, tag_in, taglen_out);
|
return sc_asn1_skip_tag(ctx, &buf, &buflen, tag_in, taglen_out);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int decode_bit_string(const u8 * inbuf, int inlen, void *outbuf,
|
static int decode_bit_string(const u8 * inbuf, int inlen, void *outbuf,
|
||||||
|
@ -523,10 +504,13 @@ static int asn1_parse_p15_object(struct sc_context *ctx, const u8 *in, int len,
|
||||||
}
|
}
|
||||||
|
|
||||||
static int asn1_decode_entry(struct sc_context *ctx, struct sc_asn1_struct *entry,
|
static int asn1_decode_entry(struct sc_context *ctx, struct sc_asn1_struct *entry,
|
||||||
const u8 *obj, int objlen, int depth)
|
const u8 *obj, size_t objlen, int depth)
|
||||||
{
|
{
|
||||||
void *parm = entry->parm;
|
void *parm = entry->parm;
|
||||||
int *len = entry->len;
|
int (*callback_func)(struct sc_context *ctx, void *arg, const u8 *obj,
|
||||||
|
size_t objlen, int depth) =
|
||||||
|
(int (*)(struct sc_context *, void *, const u8 *, size_t, int)) parm;
|
||||||
|
int *len = (int *) entry->arg;
|
||||||
int r = 0;
|
int r = 0;
|
||||||
|
|
||||||
if (ctx->debug >= 3) {
|
if (ctx->debug >= 3) {
|
||||||
|
@ -562,9 +546,22 @@ static int asn1_decode_entry(struct sc_context *ctx, struct sc_asn1_struct *entr
|
||||||
if (parm != NULL)
|
if (parm != NULL)
|
||||||
r = sc_asn1_decode_integer(obj, objlen, (int *) entry->parm);
|
r = sc_asn1_decode_integer(obj, objlen, (int *) entry->parm);
|
||||||
break;
|
break;
|
||||||
|
case SC_ASN1_BIT_STRING_NI:
|
||||||
case SC_ASN1_BIT_STRING:
|
case SC_ASN1_BIT_STRING:
|
||||||
if (parm != NULL && len != NULL) {
|
if (parm != NULL) {
|
||||||
r = sc_asn1_decode_bit_string(obj, objlen, (u8 *) parm, *len);
|
int invert = entry->type == SC_ASN1_BIT_STRING ? 1 : 0;
|
||||||
|
assert(len != NULL);
|
||||||
|
if (entry->flags & SC_ASN1_ALLOC) {
|
||||||
|
u8 **buf = (u8 **) parm;
|
||||||
|
*buf = malloc(objlen-1);
|
||||||
|
if (*buf == NULL) {
|
||||||
|
r = SC_ERROR_OUT_OF_MEMORY;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
*len = objlen-1;
|
||||||
|
parm = *buf;
|
||||||
|
}
|
||||||
|
r = decode_bit_string(obj, objlen, (u8 *) parm, *len, invert);
|
||||||
if (r >= 0) {
|
if (r >= 0) {
|
||||||
*len = r;
|
*len = r;
|
||||||
r = 0;
|
r = 0;
|
||||||
|
@ -575,6 +572,16 @@ static int asn1_decode_entry(struct sc_context *ctx, struct sc_asn1_struct *entr
|
||||||
if (parm != NULL) {
|
if (parm != NULL) {
|
||||||
int c;
|
int c;
|
||||||
assert(len != NULL);
|
assert(len != NULL);
|
||||||
|
if (entry->flags & SC_ASN1_ALLOC) {
|
||||||
|
u8 **buf = (u8 **) parm;
|
||||||
|
*buf = malloc(objlen);
|
||||||
|
if (*buf == NULL) {
|
||||||
|
r = SC_ERROR_OUT_OF_MEMORY;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
c = *len = objlen;
|
||||||
|
parm = *buf;
|
||||||
|
} else
|
||||||
c = objlen > *len ? *len : objlen;
|
c = objlen > *len ? *len : objlen;
|
||||||
|
|
||||||
memcpy(parm, obj, c);
|
memcpy(parm, obj, c);
|
||||||
|
@ -588,6 +595,16 @@ static int asn1_decode_entry(struct sc_context *ctx, struct sc_asn1_struct *entr
|
||||||
case SC_ASN1_UTF8STRING:
|
case SC_ASN1_UTF8STRING:
|
||||||
if (parm != NULL) {
|
if (parm != NULL) {
|
||||||
assert(len != NULL);
|
assert(len != NULL);
|
||||||
|
if (entry->flags & SC_ASN1_ALLOC) {
|
||||||
|
u8 **buf = (u8 **) parm;
|
||||||
|
*buf = malloc(objlen-1);
|
||||||
|
if (*buf == NULL) {
|
||||||
|
r = SC_ERROR_OUT_OF_MEMORY;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
*len = objlen-1;
|
||||||
|
parm = *buf;
|
||||||
|
}
|
||||||
r = sc_asn1_decode_utf8string(obj, objlen, parm, len);
|
r = sc_asn1_decode_utf8string(obj, objlen, parm, len);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -608,6 +625,10 @@ static int asn1_decode_entry(struct sc_context *ctx, struct sc_asn1_struct *entr
|
||||||
if (entry->parm != NULL)
|
if (entry->parm != NULL)
|
||||||
r = asn1_parse_p15_object(ctx, obj, objlen, (struct sc_pkcs15_object *) parm, depth);
|
r = asn1_parse_p15_object(ctx, obj, objlen, (struct sc_pkcs15_object *) parm, depth);
|
||||||
break;
|
break;
|
||||||
|
case SC_ASN1_CALLBACK:
|
||||||
|
if (entry->parm != NULL)
|
||||||
|
r = callback_func(ctx, entry->arg, obj, objlen, depth);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
error(ctx, "invalid ASN.1 type: %d\n", entry->type);
|
error(ctx, "invalid ASN.1 type: %d\n", entry->type);
|
||||||
assert(0);
|
assert(0);
|
||||||
|
@ -639,7 +660,7 @@ static int asn1_parse(struct sc_context *ctx, struct sc_asn1_struct *asn1,
|
||||||
for (idx = 0; asn1[idx].name != NULL; idx++) {
|
for (idx = 0; asn1[idx].name != NULL; idx++) {
|
||||||
entry = &asn1[idx];
|
entry = &asn1[idx];
|
||||||
r = 0;
|
r = 0;
|
||||||
obj = sc_asn1_skip_tag2(ctx, &p, &left, entry->tag, &objlen);
|
obj = sc_asn1_skip_tag(ctx, &p, &left, entry->tag, &objlen);
|
||||||
if (obj == NULL) {
|
if (obj == NULL) {
|
||||||
if (choice)
|
if (choice)
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -30,7 +30,7 @@ struct sc_asn1_struct {
|
||||||
unsigned int tag;
|
unsigned int tag;
|
||||||
unsigned int flags;
|
unsigned int flags;
|
||||||
void *parm;
|
void *parm;
|
||||||
int *len;
|
void *arg;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct sc_pkcs15_object {
|
struct sc_pkcs15_object {
|
||||||
|
@ -47,9 +47,12 @@ int sc_asn1_parse(struct sc_context *ctx, struct sc_asn1_struct *asn1,
|
||||||
int sc_asn1_parse_choice(struct sc_context *ctx, struct sc_asn1_struct *asn1,
|
int sc_asn1_parse_choice(struct sc_context *ctx, struct sc_asn1_struct *asn1,
|
||||||
const u8 *in, int len, const u8 **newp, int *left);
|
const u8 *in, int len, const u8 **newp, int *left);
|
||||||
|
|
||||||
const u8 *sc_asn1_find_tag(const u8 * buf, int buflen, int tag, int *taglen);
|
const u8 *sc_asn1_find_tag(struct sc_context *ctx, const u8 * buf,
|
||||||
const u8 *sc_asn1_verify_tag(const u8 * buf, int buflen, int tag, int *taglen);
|
size_t buflen, unsigned int tag, size_t *taglen);
|
||||||
const u8 *sc_asn1_skip_tag(const u8 ** buf, int *buflen, int tag, int *taglen);
|
const u8 *sc_asn1_verify_tag(struct sc_context *ctx, const u8 * buf,
|
||||||
|
size_t buflen, unsigned int tag, size_t *taglen);
|
||||||
|
const u8 *sc_asn1_skip_tag(struct sc_context *ctx, const u8 ** buf,
|
||||||
|
size_t *buflen, unsigned int tag, size_t *taglen);
|
||||||
|
|
||||||
/* DER encoding */
|
/* DER encoding */
|
||||||
|
|
||||||
|
@ -82,10 +85,12 @@ int sc_asn1_decode_object_id(const u8 * inbuf, int inlen,
|
||||||
|
|
||||||
#define SC_ASN1_PRESENT 0x00000001
|
#define SC_ASN1_PRESENT 0x00000001
|
||||||
#define SC_ASN1_OPTIONAL 0x00000002
|
#define SC_ASN1_OPTIONAL 0x00000002
|
||||||
|
#define SC_ASN1_ALLOC 0x00000004
|
||||||
|
|
||||||
#define SC_ASN1_BOOLEAN 1
|
#define SC_ASN1_BOOLEAN 1
|
||||||
#define SC_ASN1_INTEGER 2
|
#define SC_ASN1_INTEGER 2
|
||||||
#define SC_ASN1_BIT_STRING 3
|
#define SC_ASN1_BIT_STRING 3
|
||||||
|
#define SC_ASN1_BIT_STRING_NI 128
|
||||||
#define SC_ASN1_OCTET_STRING 4
|
#define SC_ASN1_OCTET_STRING 4
|
||||||
#define SC_ASN1_NULL 5
|
#define SC_ASN1_NULL 5
|
||||||
#define SC_ASN1_OBJECT 6
|
#define SC_ASN1_OBJECT 6
|
||||||
|
@ -98,14 +103,17 @@ int sc_asn1_decode_object_id(const u8 * inbuf, int inlen,
|
||||||
#define SC_ASN1_GENERALIZEDTIME 24
|
#define SC_ASN1_GENERALIZEDTIME 24
|
||||||
|
|
||||||
/* internal structures */
|
/* internal structures */
|
||||||
#define SC_ASN1_STRUCT 128
|
#define SC_ASN1_STRUCT 129
|
||||||
#define SC_ASN1_CHOICE 129
|
#define SC_ASN1_CHOICE 130
|
||||||
|
|
||||||
/* 'complex' structures */
|
/* 'complex' structures */
|
||||||
#define SC_ASN1_PATH 256
|
#define SC_ASN1_PATH 256
|
||||||
#define SC_ASN1_PKCS15_ID 257
|
#define SC_ASN1_PKCS15_ID 257
|
||||||
#define SC_ASN1_PKCS15_OBJECT 258
|
#define SC_ASN1_PKCS15_OBJECT 258
|
||||||
|
|
||||||
|
/* use callback function */
|
||||||
|
#define SC_ASN1_CALLBACK 384
|
||||||
|
|
||||||
#define ASN1_TAG_CLASS 0xC0
|
#define ASN1_TAG_CLASS 0xC0
|
||||||
#define ASN1_TAG_UNIVERSAL 0x00
|
#define ASN1_TAG_UNIVERSAL 0x00
|
||||||
#define ASN1_TAG_APPLICATION 0x40
|
#define ASN1_TAG_APPLICATION 0x40
|
||||||
|
|
|
@ -103,28 +103,28 @@ static void parse_sec_attr(struct sc_file *file, const u8 *buf, size_t len)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void process_fci(struct sc_context *ctx, struct sc_file *file,
|
static void process_fci(struct sc_context *ctx, struct sc_file *file,
|
||||||
const u8 *buf, int buflen)
|
const u8 *buf, size_t buflen)
|
||||||
{
|
{
|
||||||
int taglen, len = buflen;
|
size_t taglen, len = buflen;
|
||||||
const u8 *tag = NULL, *p = buf;
|
const u8 *tag = NULL, *p = buf;
|
||||||
|
|
||||||
if (ctx->debug >= 3)
|
if (ctx->debug >= 3)
|
||||||
debug(ctx, "processing FCI bytes\n");
|
debug(ctx, "processing FCI bytes\n");
|
||||||
tag = sc_asn1_find_tag(p, len, 0x83, &taglen);
|
tag = sc_asn1_find_tag(ctx, p, len, 0x83, &taglen);
|
||||||
if (tag != NULL && taglen == 2) {
|
if (tag != NULL && taglen == 2) {
|
||||||
file->id = (tag[0] << 8) | tag[1];
|
file->id = (tag[0] << 8) | tag[1];
|
||||||
if (ctx->debug >= 3)
|
if (ctx->debug >= 3)
|
||||||
debug(ctx, " file identifier: 0x%02X%02X\n", tag[0],
|
debug(ctx, " file identifier: 0x%02X%02X\n", tag[0],
|
||||||
tag[1]);
|
tag[1]);
|
||||||
}
|
}
|
||||||
tag = sc_asn1_find_tag(p, len, 0x81, &taglen);
|
tag = sc_asn1_find_tag(ctx, p, len, 0x81, &taglen);
|
||||||
if (tag != NULL && taglen >= 2) {
|
if (tag != NULL && taglen >= 2) {
|
||||||
int bytes = (tag[0] << 8) + tag[1];
|
int bytes = (tag[0] << 8) + tag[1];
|
||||||
if (ctx->debug >= 3)
|
if (ctx->debug >= 3)
|
||||||
debug(ctx, " bytes in file: %d\n", bytes);
|
debug(ctx, " bytes in file: %d\n", bytes);
|
||||||
file->size = bytes;
|
file->size = bytes;
|
||||||
}
|
}
|
||||||
tag = sc_asn1_find_tag(p, len, 0x82, &taglen);
|
tag = sc_asn1_find_tag(ctx, p, len, 0x82, &taglen);
|
||||||
if (tag != NULL) {
|
if (tag != NULL) {
|
||||||
if (taglen > 0) {
|
if (taglen > 0) {
|
||||||
unsigned char byte = tag[0];
|
unsigned char byte = tag[0];
|
||||||
|
@ -159,7 +159,7 @@ static void process_fci(struct sc_context *ctx, struct sc_file *file,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tag = sc_asn1_find_tag(p, len, 0x84, &taglen);
|
tag = sc_asn1_find_tag(ctx, p, len, 0x84, &taglen);
|
||||||
if (tag != NULL && taglen > 0 && taglen <= 16) {
|
if (tag != NULL && taglen > 0 && taglen <= 16) {
|
||||||
char name[17];
|
char name[17];
|
||||||
int i;
|
int i;
|
||||||
|
@ -178,18 +178,18 @@ static void process_fci(struct sc_context *ctx, struct sc_file *file,
|
||||||
if (ctx->debug >= 3)
|
if (ctx->debug >= 3)
|
||||||
debug(ctx, "File name: %s\n", name);
|
debug(ctx, "File name: %s\n", name);
|
||||||
}
|
}
|
||||||
tag = sc_asn1_find_tag(p, len, 0x85, &taglen);
|
tag = sc_asn1_find_tag(ctx, p, len, 0x85, &taglen);
|
||||||
if (tag != NULL && taglen && taglen <= SC_MAX_PROP_ATTR_SIZE) {
|
if (tag != NULL && taglen && taglen <= SC_MAX_PROP_ATTR_SIZE) {
|
||||||
memcpy(file->prop_attr, tag, taglen);
|
memcpy(file->prop_attr, tag, taglen);
|
||||||
file->prop_attr_len = taglen;
|
file->prop_attr_len = taglen;
|
||||||
} else
|
} else
|
||||||
file->prop_attr_len = 0;
|
file->prop_attr_len = 0;
|
||||||
tag = sc_asn1_find_tag(p, len, 0xA5, &taglen);
|
tag = sc_asn1_find_tag(ctx, p, len, 0xA5, &taglen);
|
||||||
if (tag != NULL && taglen && taglen <= SC_MAX_PROP_ATTR_SIZE) {
|
if (tag != NULL && taglen && taglen <= SC_MAX_PROP_ATTR_SIZE) {
|
||||||
memcpy(file->prop_attr, tag, taglen);
|
memcpy(file->prop_attr, tag, taglen);
|
||||||
file->prop_attr_len = taglen;
|
file->prop_attr_len = taglen;
|
||||||
}
|
}
|
||||||
tag = sc_asn1_find_tag(p, len, 0x86, &taglen);
|
tag = sc_asn1_find_tag(ctx, p, len, 0x86, &taglen);
|
||||||
if (tag != NULL && taglen && taglen <= SC_MAX_SEC_ATTR_SIZE)
|
if (tag != NULL && taglen && taglen <= SC_MAX_SEC_ATTR_SIZE)
|
||||||
parse_sec_attr(file, tag, taglen);
|
parse_sec_attr(file, tag, taglen);
|
||||||
else
|
else
|
||||||
|
|
|
@ -31,98 +31,106 @@
|
||||||
|
|
||||||
#undef CACHE_CERTS
|
#undef CACHE_CERTS
|
||||||
|
|
||||||
static int parse_rsa_pubkey(const u8 *buf, int buflen, struct sc_pkcs15_rsa_pubkey *key)
|
static int parse_rsa_pubkey(struct sc_context *ctx, struct sc_pkcs15_rsa_pubkey *key)
|
||||||
{
|
{
|
||||||
const u8 *tag;
|
struct sc_asn1_struct asn1_rsa_pubkey[] = {
|
||||||
int taglen;
|
{ "modulus", SC_ASN1_OCTET_STRING, ASN1_INTEGER, SC_ASN1_ALLOC, &key->modulus, &key->modulus_len },
|
||||||
|
{ "publicExponent", SC_ASN1_INTEGER, ASN1_INTEGER, 0, &key->exponent },
|
||||||
|
{ NULL }
|
||||||
|
};
|
||||||
|
const u8 *obj;
|
||||||
|
size_t objlen;
|
||||||
|
int r;
|
||||||
|
|
||||||
buf = sc_asn1_verify_tag(buf, buflen, 0x30, &buflen);
|
obj = sc_asn1_verify_tag(ctx, key->data, key->data_len, ASN1_SEQUENCE | SC_ASN1_CONS,
|
||||||
if (buf == NULL)
|
&objlen);
|
||||||
return -1;
|
if (obj == NULL) {
|
||||||
|
error(ctx, "RSA public key not found\n");
|
||||||
tag = sc_asn1_verify_tag(buf, buflen, 0x02, &taglen);
|
|
||||||
if (tag == NULL)
|
|
||||||
return -1;
|
|
||||||
key->modulus = malloc(taglen);
|
|
||||||
memcpy(key->modulus, tag, taglen);
|
|
||||||
key->modulus_len = taglen;
|
|
||||||
tag += taglen;
|
|
||||||
buflen -= tag - buf;
|
|
||||||
tag = sc_asn1_verify_tag(tag, buflen, 0x02, &taglen);
|
|
||||||
if (sc_asn1_decode_integer(tag, taglen, (int *) &key->exponent)) {
|
|
||||||
free(key->modulus);
|
|
||||||
return SC_ERROR_INVALID_ASN1_OBJECT;
|
return SC_ERROR_INVALID_ASN1_OBJECT;
|
||||||
}
|
}
|
||||||
|
r = sc_asn1_parse(ctx, asn1_rsa_pubkey, obj, objlen, NULL, NULL);
|
||||||
|
SC_TEST_RET(ctx, r, "ASN.1 parsing failed");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int parse_cert(const u8 *buf, int buflen, struct sc_pkcs15_cert *cert)
|
struct asn1_algorithm_id {
|
||||||
|
struct sc_object_id id;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int parse_algorithm_id(struct sc_context *ctx, void *arg, const u8 *obj,
|
||||||
|
size_t objlen, int depth)
|
||||||
{
|
{
|
||||||
const u8 *tag, *p;
|
struct asn1_algorithm_id *alg_id = (struct asn1_algorithm_id *) arg;
|
||||||
u8 *tmpbuf;
|
struct sc_asn1_struct asn1_alg_id[] = {
|
||||||
int taglen, left, r;
|
{ "algorithm", SC_ASN1_OBJECT, ASN1_OBJECT, 0, &alg_id->id },
|
||||||
|
{ "parameters", SC_ASN1_STRUCT, 0, SC_ASN1_OPTIONAL, NULL },
|
||||||
|
{ NULL }
|
||||||
|
};
|
||||||
|
int r;
|
||||||
|
|
||||||
|
r = sc_asn1_parse(ctx, asn1_alg_id, obj, objlen, NULL, NULL);
|
||||||
|
SC_TEST_RET(ctx, r, "ASN.1 parsing failed");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int parse_x509_cert(struct sc_context *ctx, const u8 *buf, size_t buflen, struct sc_pkcs15_cert *cert)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
struct sc_pkcs15_rsa_pubkey *key = &cert->key;
|
struct sc_pkcs15_rsa_pubkey *key = &cert->key;
|
||||||
const u8 *buf0 = buf;
|
struct asn1_algorithm_id pk_alg, sig_alg;
|
||||||
|
u8 *pk = NULL;
|
||||||
|
size_t pklen = 0;
|
||||||
|
struct sc_asn1_struct asn1_version[] = {
|
||||||
|
{ "version", SC_ASN1_INTEGER, ASN1_INTEGER, 0, &cert->version },
|
||||||
|
{ NULL }
|
||||||
|
};
|
||||||
|
struct sc_asn1_struct asn1_pkinfo[] = {
|
||||||
|
{ "algorithm", SC_ASN1_CALLBACK, ASN1_SEQUENCE | SC_ASN1_CONS, 0, parse_algorithm_id, &pk_alg },
|
||||||
|
{ "subjectPublicKey", SC_ASN1_BIT_STRING_NI, ASN1_BIT_STRING, SC_ASN1_ALLOC, &pk, &pklen },
|
||||||
|
{ NULL }
|
||||||
|
};
|
||||||
|
struct sc_asn1_struct asn1_tbscert[] = {
|
||||||
|
{ "version", SC_ASN1_STRUCT, SC_ASN1_CTX | 0 | SC_ASN1_CONS, 0, asn1_version },
|
||||||
|
{ "serialNumber", SC_ASN1_INTEGER, ASN1_INTEGER, 0, &cert->serial },
|
||||||
|
{ "signature", SC_ASN1_STRUCT, ASN1_SEQUENCE | SC_ASN1_CONS, 0, NULL },
|
||||||
|
{ "issuer", SC_ASN1_STRUCT, ASN1_SEQUENCE | SC_ASN1_CONS, 0, NULL },
|
||||||
|
{ "validity", SC_ASN1_STRUCT, ASN1_SEQUENCE | SC_ASN1_CONS, 0, NULL },
|
||||||
|
{ "subject", SC_ASN1_STRUCT, ASN1_SEQUENCE | SC_ASN1_CONS, 0, NULL },
|
||||||
|
{ "subjectPublicKeyInfo",SC_ASN1_STRUCT, ASN1_SEQUENCE | SC_ASN1_CONS, 0, asn1_pkinfo },
|
||||||
|
{ NULL }
|
||||||
|
};
|
||||||
|
struct sc_asn1_struct asn1_cert[] = {
|
||||||
|
{ "tbsCertificate", SC_ASN1_STRUCT, ASN1_SEQUENCE | SC_ASN1_CONS, 0, asn1_tbscert },
|
||||||
|
{ "signatureAlgorithm", SC_ASN1_CALLBACK, ASN1_SEQUENCE | SC_ASN1_CONS, 0, parse_algorithm_id, &sig_alg },
|
||||||
|
{ "signatureValue", SC_ASN1_BIT_STRING,ASN1_BIT_STRING, 0, NULL, 0 },
|
||||||
|
{ NULL }
|
||||||
|
};
|
||||||
|
const u8 *obj;
|
||||||
|
size_t objlen;
|
||||||
|
|
||||||
buf = sc_asn1_verify_tag(buf, buflen, 0x30, &buflen); /* SEQUENCE */
|
obj = sc_asn1_verify_tag(ctx, buf, buflen, ASN1_SEQUENCE | SC_ASN1_CONS,
|
||||||
if (buf == NULL) /* Certificate */
|
&objlen);
|
||||||
|
if (obj == NULL) {
|
||||||
|
error(ctx, "X.509 certificate not found\n");
|
||||||
return SC_ERROR_INVALID_ASN1_OBJECT;
|
return SC_ERROR_INVALID_ASN1_OBJECT;
|
||||||
cert->data_len = (buf - buf0) + buflen;
|
}
|
||||||
p = sc_asn1_skip_tag(&buf, &buflen, 0x30, &left); /* SEQUENCE */
|
cert->data_len = objlen + (obj - buf);
|
||||||
if (p == NULL) /* tbsCertificate */
|
r = sc_asn1_parse(ctx, asn1_cert, obj, objlen, NULL, NULL);
|
||||||
return SC_ERROR_INVALID_ASN1_OBJECT;
|
SC_TEST_RET(ctx, r, "ASN.1 parsing failed");
|
||||||
cert->version = 0;
|
|
||||||
tag = sc_asn1_skip_tag(&p, &left, 0xA0, &taglen); /* Version */
|
|
||||||
if (tag != NULL) {
|
|
||||||
tag = sc_asn1_verify_tag(tag, taglen, 0x02, &taglen);
|
|
||||||
if (tag != NULL) {
|
|
||||||
sc_asn1_decode_integer(tag, taglen, &cert->version);
|
|
||||||
cert->version++;
|
cert->version++;
|
||||||
}
|
pklen >>= 3; /* convert number of bits to bytes */
|
||||||
}
|
key->data = pk;
|
||||||
tag = sc_asn1_skip_tag(&p, &left, 0x02, &taglen); /* INTEGER */
|
key->data_len = pklen;
|
||||||
if (tag == NULL)
|
/* FIXME: ignore the object id for now, and presume it's RSA */
|
||||||
return SC_ERROR_INVALID_ASN1_OBJECT;
|
r = parse_rsa_pubkey(ctx, key);
|
||||||
sc_asn1_decode_integer(tag, taglen, (int *) &cert->serial);
|
|
||||||
|
|
||||||
tag = sc_asn1_skip_tag(&p, &left, 0x30, &taglen); /* signatureId */
|
|
||||||
if (tag == NULL)
|
|
||||||
return SC_ERROR_INVALID_ASN1_OBJECT;
|
|
||||||
|
|
||||||
tag = sc_asn1_skip_tag(&p, &left, 0x30, &taglen); /* issuer */
|
|
||||||
if (tag == NULL)
|
|
||||||
return SC_ERROR_INVALID_ASN1_OBJECT;
|
|
||||||
|
|
||||||
tag = sc_asn1_skip_tag(&p, &left, 0x30, &taglen); /* validity */
|
|
||||||
if (tag == NULL)
|
|
||||||
return SC_ERROR_INVALID_ASN1_OBJECT;
|
|
||||||
|
|
||||||
tag = sc_asn1_skip_tag(&p, &left, 0x30, &taglen); /* subject */
|
|
||||||
if (tag == NULL)
|
|
||||||
return SC_ERROR_INVALID_ASN1_OBJECT;
|
|
||||||
|
|
||||||
tag = sc_asn1_skip_tag(&p, &left, 0x30, &taglen); /* subjectPKInfo */
|
|
||||||
if (tag == NULL)
|
|
||||||
return SC_ERROR_INVALID_ASN1_OBJECT;
|
|
||||||
/* FIXME: get the algorithm ID */
|
|
||||||
tag = sc_asn1_find_tag(tag, taglen, 0x03, &taglen); /* subjectPubKey */
|
|
||||||
if (tag == NULL)
|
|
||||||
return SC_ERROR_INVALID_ASN1_OBJECT;
|
|
||||||
tmpbuf = malloc(taglen-1);
|
|
||||||
|
|
||||||
r = sc_asn1_decode_bit_string_ni(tag, taglen, tmpbuf, taglen-1);
|
|
||||||
if (r < 0) {
|
|
||||||
free(tmpbuf);
|
|
||||||
return SC_ERROR_INVALID_ASN1_OBJECT;
|
|
||||||
}
|
|
||||||
r >>= 3;
|
|
||||||
key->data = tmpbuf;
|
|
||||||
key->data_len = taglen-1;
|
|
||||||
r = parse_rsa_pubkey(tmpbuf, r, key);
|
|
||||||
if (r) {
|
if (r) {
|
||||||
free(tmpbuf);
|
free(key->data);
|
||||||
return SC_ERROR_INVALID_ASN1_OBJECT;
|
return SC_ERROR_INVALID_ASN1_OBJECT;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -259,7 +267,7 @@ int sc_pkcs15_read_certificate(struct sc_pkcs15_card *p15card,
|
||||||
return SC_ERROR_OUT_OF_MEMORY;
|
return SC_ERROR_OUT_OF_MEMORY;
|
||||||
}
|
}
|
||||||
memset(cert, 0, sizeof(struct sc_pkcs15_cert));
|
memset(cert, 0, sizeof(struct sc_pkcs15_cert));
|
||||||
if (parse_cert(data, len, cert)) {
|
if (parse_x509_cert(p15card->card->ctx, data, len, cert)) {
|
||||||
free(data);
|
free(data);
|
||||||
free(cert);
|
free(cert);
|
||||||
return SC_ERROR_INVALID_ASN1_OBJECT;
|
return SC_ERROR_INVALID_ASN1_OBJECT;
|
||||||
|
|
|
@ -76,7 +76,7 @@ void parse_tokeninfo(struct sc_pkcs15_card *card, const u8 * buf, int buflen)
|
||||||
{ NULL }
|
{ NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
buf = sc_asn1_verify_tag(buf, buflen, 0x30, &buflen); /* SEQUENCE */
|
buf = sc_asn1_verify_tag(card->card->ctx, buf, buflen, SC_ASN1_CONS | ASN1_SEQUENCE, &buflen);
|
||||||
if (buf == NULL) {
|
if (buf == NULL) {
|
||||||
error(card->card->ctx, "invalid EF(TokenInfo)\n");
|
error(card->card->ctx, "invalid EF(TokenInfo)\n");
|
||||||
goto err;
|
goto err;
|
||||||
|
@ -134,7 +134,7 @@ static int parse_dir(const u8 * buf, int buflen, struct sc_pkcs15_card *card)
|
||||||
{ NULL }
|
{ NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
buf = sc_asn1_verify_tag(buf, buflen, 0x61, &buflen);
|
buf = sc_asn1_verify_tag(card->card->ctx, buf, buflen, SC_ASN1_APP | 1 | SC_ASN1_CONS, &buflen);
|
||||||
if (buf == NULL) {
|
if (buf == NULL) {
|
||||||
error(card->card->ctx, "No [APPLICATION 1] tag in EF(DIR)\n");
|
error(card->card->ctx, "No [APPLICATION 1] tag in EF(DIR)\n");
|
||||||
return -1;
|
return -1;
|
||||||
|
|
|
@ -30,7 +30,7 @@ struct sc_asn1_struct {
|
||||||
unsigned int tag;
|
unsigned int tag;
|
||||||
unsigned int flags;
|
unsigned int flags;
|
||||||
void *parm;
|
void *parm;
|
||||||
int *len;
|
void *arg;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct sc_pkcs15_object {
|
struct sc_pkcs15_object {
|
||||||
|
@ -47,9 +47,12 @@ int sc_asn1_parse(struct sc_context *ctx, struct sc_asn1_struct *asn1,
|
||||||
int sc_asn1_parse_choice(struct sc_context *ctx, struct sc_asn1_struct *asn1,
|
int sc_asn1_parse_choice(struct sc_context *ctx, struct sc_asn1_struct *asn1,
|
||||||
const u8 *in, int len, const u8 **newp, int *left);
|
const u8 *in, int len, const u8 **newp, int *left);
|
||||||
|
|
||||||
const u8 *sc_asn1_find_tag(const u8 * buf, int buflen, int tag, int *taglen);
|
const u8 *sc_asn1_find_tag(struct sc_context *ctx, const u8 * buf,
|
||||||
const u8 *sc_asn1_verify_tag(const u8 * buf, int buflen, int tag, int *taglen);
|
size_t buflen, unsigned int tag, size_t *taglen);
|
||||||
const u8 *sc_asn1_skip_tag(const u8 ** buf, int *buflen, int tag, int *taglen);
|
const u8 *sc_asn1_verify_tag(struct sc_context *ctx, const u8 * buf,
|
||||||
|
size_t buflen, unsigned int tag, size_t *taglen);
|
||||||
|
const u8 *sc_asn1_skip_tag(struct sc_context *ctx, const u8 ** buf,
|
||||||
|
size_t *buflen, unsigned int tag, size_t *taglen);
|
||||||
|
|
||||||
/* DER encoding */
|
/* DER encoding */
|
||||||
|
|
||||||
|
@ -82,10 +85,12 @@ int sc_asn1_decode_object_id(const u8 * inbuf, int inlen,
|
||||||
|
|
||||||
#define SC_ASN1_PRESENT 0x00000001
|
#define SC_ASN1_PRESENT 0x00000001
|
||||||
#define SC_ASN1_OPTIONAL 0x00000002
|
#define SC_ASN1_OPTIONAL 0x00000002
|
||||||
|
#define SC_ASN1_ALLOC 0x00000004
|
||||||
|
|
||||||
#define SC_ASN1_BOOLEAN 1
|
#define SC_ASN1_BOOLEAN 1
|
||||||
#define SC_ASN1_INTEGER 2
|
#define SC_ASN1_INTEGER 2
|
||||||
#define SC_ASN1_BIT_STRING 3
|
#define SC_ASN1_BIT_STRING 3
|
||||||
|
#define SC_ASN1_BIT_STRING_NI 128
|
||||||
#define SC_ASN1_OCTET_STRING 4
|
#define SC_ASN1_OCTET_STRING 4
|
||||||
#define SC_ASN1_NULL 5
|
#define SC_ASN1_NULL 5
|
||||||
#define SC_ASN1_OBJECT 6
|
#define SC_ASN1_OBJECT 6
|
||||||
|
@ -98,14 +103,17 @@ int sc_asn1_decode_object_id(const u8 * inbuf, int inlen,
|
||||||
#define SC_ASN1_GENERALIZEDTIME 24
|
#define SC_ASN1_GENERALIZEDTIME 24
|
||||||
|
|
||||||
/* internal structures */
|
/* internal structures */
|
||||||
#define SC_ASN1_STRUCT 128
|
#define SC_ASN1_STRUCT 129
|
||||||
#define SC_ASN1_CHOICE 129
|
#define SC_ASN1_CHOICE 130
|
||||||
|
|
||||||
/* 'complex' structures */
|
/* 'complex' structures */
|
||||||
#define SC_ASN1_PATH 256
|
#define SC_ASN1_PATH 256
|
||||||
#define SC_ASN1_PKCS15_ID 257
|
#define SC_ASN1_PKCS15_ID 257
|
||||||
#define SC_ASN1_PKCS15_OBJECT 258
|
#define SC_ASN1_PKCS15_OBJECT 258
|
||||||
|
|
||||||
|
/* use callback function */
|
||||||
|
#define SC_ASN1_CALLBACK 384
|
||||||
|
|
||||||
#define ASN1_TAG_CLASS 0xC0
|
#define ASN1_TAG_CLASS 0xC0
|
||||||
#define ASN1_TAG_UNIVERSAL 0x00
|
#define ASN1_TAG_UNIVERSAL 0x00
|
||||||
#define ASN1_TAG_APPLICATION 0x40
|
#define ASN1_TAG_APPLICATION 0x40
|
||||||
|
|
Loading…
Reference in New Issue