diff --git a/src/libopensc/Makefile.am b/src/libopensc/Makefile.am index 68df64d559..050c08b3c5 100644 --- a/src/libopensc/Makefile.am +++ b/src/libopensc/Makefile.am @@ -8,7 +8,7 @@ libopensc_la_SOURCES = asn1.c base64.c defaults.c \ pkcs15.c pkcs15-cert.c pkcs15-pin.c \ pkcs15-prkey.c pkcs15-defaults.c \ pkcs15-sec.c \ - card-setec.c card-multiflex.c \ + card-setec.c card-flex.c \ card-emv.c card-default.c libopensc_la_LDFLAGS = -version-info 0:4:0 libopensc_la_LIBADD = @LIBPCSC@ diff --git a/src/libopensc/asn1.c b/src/libopensc/asn1.c index 22c6bf4653..dccd43d648 100644 --- a/src/libopensc/asn1.c +++ b/src/libopensc/asn1.c @@ -28,9 +28,11 @@ #include -static int asn1_decode(struct sc_context *ctx, struct sc_asn1_struct *asn1, - const u8 *in, size_t len, const u8 **newp, size_t *len_left, - int choice, int depth); +static int asn1_decode(struct sc_context *ctx, struct sc_asn1_entry *asn1, + const u8 *in, size_t len, const u8 **newp, size_t *len_left, + int choice, int depth); +static int asn1_encode(struct sc_context *ctx, const struct sc_asn1_entry *asn1, + u8 **ptr, size_t *size, int depth); const char *tag2str(int tag) { @@ -94,6 +96,26 @@ static int read_tag(const u8 ** buf, size_t buflen, unsigned int *cla_out, return -1; } +void sc_format_asn1_entry(struct sc_asn1_entry *entry, void *parm, void *arg, + int set_present) +{ + entry->parm = parm; + entry->arg = arg; + if (set_present) + entry->flags |= SC_ASN1_PRESENT; +} + +void sc_copy_asn1_entry(const struct sc_asn1_entry *src, + struct sc_asn1_entry *dest) +{ + do { + *dest = *src; + dest++; + src++; + } while (src->name != NULL); + dest->name = NULL; +} + static void sc_asn1_print_octet_string(const u8 * buf, size_t buflen) { int i; @@ -381,6 +403,12 @@ int sc_asn1_decode_bit_string_ni(const u8 * inbuf, size_t inlen, return decode_bit_string(inbuf, inlen, outbuf, outlen, 0); } +static int encode_bit_string(const u8 * inbuf, size_t inlen, u8 **outbuf, + size_t *outlen, int invert) +{ + return SC_ERROR_NOT_SUPPORTED; +} + int sc_asn1_decode_integer(const u8 * inbuf, size_t inlen, int *out) { int i, a = 0; @@ -395,6 +423,23 @@ int sc_asn1_decode_integer(const u8 * inbuf, size_t inlen, int *out) return 0; } +static int asn1_encode_integer(int in, u8 ** obj, size_t * objsize) +{ + int i = sizeof(in) * 8; + u8 *p; + + *obj = p = malloc(sizeof(in)); + if (*obj == NULL) + return SC_ERROR_OUT_OF_MEMORY; + *objsize = sizeof(in); + do { + i -= 8; + *p++ = (in >> i) & 0xFF; + } while (i > 0); + + return 0; +} + int sc_asn1_decode_object_id(const u8 * inbuf, size_t inlen, struct sc_object_id *id) { @@ -430,7 +475,38 @@ int sc_asn1_decode_object_id(const u8 * inbuf, size_t inlen, return 0; } -int sc_asn1_decode_utf8string(const u8 * inbuf, size_t inlen, +int sc_asn1_encode_object_id(const struct sc_object_id *id, u8 **buf, + size_t *buflen) +{ +#if 0 + u8 buf[128], *p = buf; + size_t count = 0 + int *valuep = id->value, i = 0; + + for (i = 0; *valuep != -1 && i < SC_MAX_OBJECT_ID_OCTETS; i++) { + int c = 0; + switch (i) { + case 0: + if (*valuep > 2) + return SC_ERROR_INVALID_ARGUMENTS; + *p = *valuep * 40; + break; + case 1: + if (*valuep > 39) + return SC_ERROR_INVALID_ARGUMENTS; + *p++ += *valuep; + break; + default: + /* FIXME: CODEME */ + } + } + return 0; +#else + return SC_ERROR_NOT_SUPPORTED; +#endif +} + +int sc_asn1_decode_utf8string(const u8 *inbuf, size_t inlen, u8 *out, size_t *outlen) { if (inlen+1 > *outlen) @@ -463,52 +539,171 @@ int sc_asn1_put_tag(int tag, const u8 * data, int datalen, u8 * out, int outlen, return 0; } +int asn1_write_element(struct sc_context *ctx, unsigned int tag, const u8 * data, + size_t datalen, u8 ** out, size_t * outlen) +{ + u8 t; + u8 *buf, *p; + int c = 0; + + t = tag & 0x1F; + if (t != (tag & SC_ASN1_TAG_MASK)) { + error(ctx, "Long tags not supported\n"); + return SC_ERROR_INVALID_ARGUMENTS; + } + switch (tag & SC_ASN1_CLASS_MASK) { + case SC_ASN1_UNI: + break; + case SC_ASN1_APP: + t |= ASN1_TAG_APPLICATION; + break; + case SC_ASN1_CTX: + t |= ASN1_TAG_CONTEXT; + break; + case SC_ASN1_PRV: + t |= ASN1_TAG_PRIVATE; + break; + } + if (tag & SC_ASN1_CONS) + t |= ASN1_TAG_CONSTRUCTED; + if (datalen > 127) { + c = 1; + while (datalen >> (c << 3)) + c++; + } + *outlen = 2 + c + datalen; + buf = malloc(*outlen); + if (buf == NULL) + SC_FUNC_RETURN(ctx, 1, SC_ERROR_OUT_OF_MEMORY); + *out = p = buf; + *p++ = t; + if (c) { + *p++ = 0x80 | c; + while (c--) + *p++ = (datalen >> (c << 3)) & 0xFF; + } else + *p++ = datalen & 0x7F; + memcpy(p, data, datalen); + + return 0; +} + +static const struct sc_asn1_entry c_asn1_path[3] = { + { "path", SC_ASN1_OCTET_STRING, ASN1_OCTET_STRING, 0, NULL }, + { "index", SC_ASN1_INTEGER, ASN1_INTEGER, SC_ASN1_OPTIONAL, NULL }, + { NULL } +}; + static int asn1_decode_path(struct sc_context *ctx, const u8 *in, size_t len, struct sc_path *path, int depth) { int idx, r; - struct sc_asn1_struct asn1_path[] = { - { "path", SC_ASN1_OCTET_STRING, ASN1_OCTET_STRING, 0, &path->value, &path->len }, - { "index", SC_ASN1_INTEGER, ASN1_INTEGER, SC_ASN1_OPTIONAL, &idx }, - { NULL } - }; + struct sc_asn1_entry asn1_path[3]; + + sc_copy_asn1_entry(c_asn1_path, asn1_path); + sc_format_asn1_entry(asn1_path + 0, &path->value, &path->len, 0); + sc_format_asn1_entry(asn1_path + 1, &idx, NULL, 0); path->len = SC_MAX_PATH_SIZE; r = asn1_decode(ctx, asn1_path, in, len, NULL, NULL, 0, depth + 1); if (r) return r; path->type = SC_PATH_TYPE_PATH; - + if (asn1_path[1].flags & SC_ASN1_PRESENT) + path->index = idx; + else + path->index = 0; return 0; } +static int asn1_encode_path(struct sc_context *ctx, const struct sc_path *path, + u8 **buf, size_t *bufsize, int depth) +{ + int r; + struct sc_asn1_entry asn1_path[3]; + + sc_copy_asn1_entry(c_asn1_path, asn1_path); + sc_format_asn1_entry(asn1_path + 0, (void *) &path->value, (void *) &path->len, 1); + if (path->index) + sc_format_asn1_entry(asn1_path + 1, (void *) &path->index, NULL, 1); + r = asn1_encode(ctx, asn1_path, buf, bufsize, depth + 1); + return r; +} + +static const struct sc_asn1_entry c_asn1_com_obj_attr[6] = { + { "label", SC_ASN1_UTF8STRING, ASN1_UTF8STRING, SC_ASN1_OPTIONAL, NULL }, + { "flags", SC_ASN1_BIT_STRING, ASN1_BIT_STRING, SC_ASN1_OPTIONAL, NULL }, + { "authId", SC_ASN1_PKCS15_ID, ASN1_OCTET_STRING, SC_ASN1_OPTIONAL, NULL }, + { "userConsent", SC_ASN1_INTEGER, ASN1_INTEGER, SC_ASN1_OPTIONAL, NULL }, + { "accessControlRules", SC_ASN1_STRUCT, ASN1_SEQUENCE | SC_ASN1_CONS, SC_ASN1_OPTIONAL, NULL }, + { NULL } +}; + +static const struct sc_asn1_entry c_asn1_p15_obj[5] = { + { "commonObjectAttributes", SC_ASN1_STRUCT, ASN1_SEQUENCE | SC_ASN1_CONS, 0, NULL }, + { "classAttributes", SC_ASN1_STRUCT, ASN1_SEQUENCE | SC_ASN1_CONS, 0, NULL }, + { "subClassAttributes", SC_ASN1_STRUCT, SC_ASN1_CTX | 0 | SC_ASN1_CONS, SC_ASN1_OPTIONAL, NULL }, + { "typeAttributes", SC_ASN1_STRUCT, SC_ASN1_CTX | 1 | SC_ASN1_CONS, 0, NULL }, + { NULL } +}; + static int asn1_decode_p15_object(struct sc_context *ctx, const u8 *in, size_t len, struct sc_pkcs15_object *obj, int depth) { int r; struct sc_pkcs15_common_obj_attr *com_attr = obj->com_attr; + struct sc_asn1_entry asn1_c_attr[6], asn1_p15_obj[5]; size_t flags_len = sizeof(com_attr->flags); size_t label_len = sizeof(com_attr->label); - struct sc_asn1_struct asn1_com_obj_attr[] = { - { "label", SC_ASN1_UTF8STRING, ASN1_UTF8STRING, SC_ASN1_OPTIONAL, com_attr->label, &label_len }, - { "flags", SC_ASN1_BIT_STRING, ASN1_BIT_STRING, SC_ASN1_OPTIONAL, &com_attr->flags, &flags_len }, - { "authId", SC_ASN1_PKCS15_ID, ASN1_OCTET_STRING, SC_ASN1_OPTIONAL, &com_attr->auth_id }, - { "userConsent", SC_ASN1_INTEGER, ASN1_INTEGER, SC_ASN1_OPTIONAL, &com_attr->user_consent }, - { "accessControlRules", SC_ASN1_STRUCT, ASN1_SEQUENCE | SC_ASN1_CONS, SC_ASN1_OPTIONAL, NULL }, - { NULL } - }; - struct sc_asn1_struct asn1_p15_obj[] = { - { "commonObjectAttributes", SC_ASN1_STRUCT, ASN1_SEQUENCE | SC_ASN1_CONS, 0, asn1_com_obj_attr }, - { "classAttributes", SC_ASN1_STRUCT, ASN1_SEQUENCE | SC_ASN1_CONS, 0, obj->asn1_class_attr }, - { "subClassAttributes", SC_ASN1_STRUCT, SC_ASN1_CTX | 0 | SC_ASN1_CONS, SC_ASN1_OPTIONAL, obj->asn1_subclass_attr }, - { "typeAttributes", SC_ASN1_STRUCT, SC_ASN1_CTX | 1 | SC_ASN1_CONS, 0, obj->asn1_type_attr }, - { NULL } - }; + + sc_copy_asn1_entry(c_asn1_com_obj_attr, asn1_c_attr); + sc_copy_asn1_entry(c_asn1_p15_obj, asn1_p15_obj); + sc_format_asn1_entry(asn1_c_attr + 0, com_attr->label, &label_len, 0); + sc_format_asn1_entry(asn1_c_attr + 1, &com_attr->flags, &flags_len, 0); + sc_format_asn1_entry(asn1_c_attr + 2, &com_attr->auth_id, NULL, 0); + sc_format_asn1_entry(asn1_c_attr + 3, &com_attr->user_consent, NULL, 0); + /* FIXME: encode accessControlRules */ + sc_format_asn1_entry(asn1_c_attr + 4, NULL, NULL, 0); + sc_format_asn1_entry(asn1_p15_obj + 0, asn1_c_attr, NULL, 0); + sc_format_asn1_entry(asn1_p15_obj + 1, obj->asn1_class_attr, NULL, 0); + sc_format_asn1_entry(asn1_p15_obj + 2, obj->asn1_subclass_attr, NULL, 0); + sc_format_asn1_entry(asn1_p15_obj + 3, obj->asn1_type_attr, NULL, 0); + r = asn1_decode(ctx, asn1_p15_obj, in, len, NULL, NULL, 0, depth + 1); return r; } -static int asn1_decode_entry(struct sc_context *ctx, struct sc_asn1_struct *entry, +static int asn1_encode_p15_object(struct sc_context *ctx, const struct sc_pkcs15_object *obj, + u8 **buf, size_t *bufsize, int depth) +{ + int r; + const struct sc_pkcs15_common_obj_attr *com_attr = obj->com_attr; + struct sc_asn1_entry asn1_c_attr[6], asn1_p15_obj[5]; + size_t flags_len = sizeof(com_attr->flags); + size_t label_len = strlen(com_attr->label); + + sc_copy_asn1_entry(c_asn1_com_obj_attr, asn1_c_attr); + sc_copy_asn1_entry(c_asn1_p15_obj, asn1_p15_obj); + if (label_len != 0) + sc_format_asn1_entry(asn1_c_attr + 0, (void *) com_attr->label, &label_len, 1); + if (com_attr->flags) + sc_format_asn1_entry(asn1_c_attr + 1, (void *) &com_attr->flags, &flags_len, 1); + if (com_attr->auth_id.len) + sc_format_asn1_entry(asn1_c_attr + 2, (void *) &com_attr->auth_id, NULL, 1); + if (com_attr->user_consent) + sc_format_asn1_entry(asn1_c_attr + 3, (void *) &com_attr->user_consent, NULL, 1); + /* FIXME: decode accessControlRules */ + sc_format_asn1_entry(asn1_p15_obj + 0, asn1_c_attr, NULL, 1); + sc_format_asn1_entry(asn1_p15_obj + 1, obj->asn1_class_attr, NULL, 1); + if (obj->asn1_subclass_attr != NULL) + sc_format_asn1_entry(asn1_p15_obj + 2, obj->asn1_subclass_attr, NULL, 1); + sc_format_asn1_entry(asn1_p15_obj + 3, obj->asn1_type_attr, NULL, 1); + + r = asn1_encode(ctx, asn1_p15_obj, buf, bufsize, depth + 1); + return r; +} + +static int asn1_decode_entry(struct sc_context *ctx, struct sc_asn1_entry *entry, const u8 *obj, size_t objlen, int depth) { void *parm = entry->parm; @@ -534,7 +729,7 @@ static int asn1_decode_entry(struct sc_context *ctx, struct sc_asn1_struct *entr switch (entry->type) { case SC_ASN1_STRUCT: if (parm != NULL) - r = asn1_decode(ctx, (struct sc_asn1_struct *) parm, obj, + r = asn1_decode(ctx, (struct sc_asn1_entry *) parm, obj, objlen, NULL, NULL, 0, depth + 1); break; case SC_ASN1_BOOLEAN: @@ -651,13 +846,13 @@ static int asn1_decode_entry(struct sc_context *ctx, struct sc_asn1_struct *entr return 0; } -static int asn1_decode(struct sc_context *ctx, struct sc_asn1_struct *asn1, +static int asn1_decode(struct sc_context *ctx, struct sc_asn1_entry *asn1, const u8 *in, size_t len, const u8 **newp, size_t *len_left, int choice, int depth) { int r, idx = 0; const u8 *p = in, *obj; - struct sc_asn1_struct *entry = asn1; + struct sc_asn1_entry *entry = asn1; size_t left = len, objlen; if (ctx->debug >= 3) @@ -710,48 +905,163 @@ static int asn1_decode(struct sc_context *ctx, struct sc_asn1_struct *asn1, SC_FUNC_RETURN(ctx, 3, 0); } -int sc_asn1_decode(struct sc_context *ctx, struct sc_asn1_struct *asn1, +int sc_asn1_decode(struct sc_context *ctx, struct sc_asn1_entry *asn1, const u8 *in, size_t len, const u8 **newp, size_t *len_left) { return asn1_decode(ctx, asn1, in, len, newp, len_left, 0, 0); } -int sc_asn1_decode_choice(struct sc_context *ctx, struct sc_asn1_struct *asn1, +int sc_asn1_decode_choice(struct sc_context *ctx, struct sc_asn1_entry *asn1, const u8 *in, size_t len, const u8 **newp, size_t *len_left) { return asn1_decode(ctx, asn1, in, len, newp, len_left, 1, 0); } -int sc_asn1_encode(struct sc_context *ctx, const struct sc_asn1_struct *asn1, - u8 *buf, size_t bufleft, size_t *objsize_out) +static int asn1_encode_entry(struct sc_context *ctx, const struct sc_asn1_entry *entry, + u8 **obj, size_t *objlen, int depth) +{ + void *parm = entry->parm; + int (*callback_func)(struct sc_context *ctx, void *arg, u8 **obj, + size_t *objlen, int depth) = + (int (*)(struct sc_context *, void *, u8 **, size_t *, int)) parm; + const size_t *len = (const size_t *) entry->arg; + int r = 0; + u8 * buf = NULL; + size_t buflen = 0; + + if (ctx->debug >= 3) { + u8 line[128], *linep = line; + int i; + + line[0] = 0; + for (i = 0; i < depth; i++) { + strcpy((char *) linep, " "); + linep += 2; + } + sprintf((char *) linep, "encoding '%s'\n", entry->name); + debug(ctx, (char *) line); + } + + assert(parm != NULL); + switch (entry->type) { + case SC_ASN1_STRUCT: + r = asn1_encode(ctx, (const struct sc_asn1_entry *) parm, &buf, + &buflen, depth + 1); + break; + case SC_ASN1_BOOLEAN: + buf = malloc(1); + if (buf == NULL) { + r = SC_ERROR_OUT_OF_MEMORY; + break; + } + buf[0] = *((u8 *) parm) ? 0xFF : 0; + buflen = 1; + break; + case SC_ASN1_INTEGER: + case SC_ASN1_ENUMERATED: + r = asn1_encode_integer(*((int *) entry->parm), &buf, &buflen); + break; + case SC_ASN1_BIT_STRING_NI: + case SC_ASN1_BIT_STRING: + assert(len != NULL); + if (entry->type == SC_ASN1_BIT_STRING_NI) + r = encode_bit_string((const u8 *) parm, *len, &buf, &buflen, 1); + else + r = encode_bit_string((const u8 *) parm, *len, &buf, &buflen, 0); + break; + case SC_ASN1_OCTET_STRING: + case SC_ASN1_UTF8STRING: + assert(len != NULL); + buf = malloc(*len); + if (buf == NULL) { + r = SC_ERROR_OUT_OF_MEMORY; + break; + } + buflen = *len; + memcpy(buf, parm, buflen); + break; +#if 0 + case SC_ASN1_OBJECT: + if (parm != NULL) + r = sc_asn1_decode_object_id(obj, objlen, (struct sc_object_id *) parm); + break; +#endif + case SC_ASN1_PATH: + r = asn1_encode_path(ctx, (const struct sc_path *) parm, &buf, &buflen, depth); + break; + case SC_ASN1_PKCS15_ID: + if (entry->parm != NULL) { + const struct sc_pkcs15_id *id = parm; + + buf = malloc(id->len); + if (buf == NULL) { + r = SC_ERROR_OUT_OF_MEMORY; + break; + } + memcpy(buf, id->value, id->len); + buflen = id->len; + } + break; + case SC_ASN1_PKCS15_OBJECT: + r = asn1_encode_p15_object(ctx, (const struct sc_pkcs15_object *) parm, &buf, &buflen, depth); + break; + case SC_ASN1_CALLBACK: + r = callback_func(ctx, entry->arg, &buf, &buflen, depth); + break; + default: + error(ctx, "invalid ASN.1 type: %d\n", entry->type); + assert(0); + } + if (r) { + error(ctx, "decoding of ASN.1 object '%s' failed: %s\n", entry->name, + sc_strerror(r)); + if (buf) + free(buf); + return r; + } + r = asn1_write_element(ctx, entry->tag, buf, buflen, obj, objlen); + free(buf); + if (r) { + error(ctx, "error writing ASN.1 tag and length: %s\n", sc_strerror(r)); + return r; + } + return 0; +} + + +static int asn1_encode(struct sc_context *ctx, const struct sc_asn1_entry *asn1, + u8 **ptr, size_t *size, int depth) { -#if 0 int r, idx = 0; - const u8 *p = buf; - const struct sc_asn1_struct *entry = asn1; + u8 *obj, *buf = NULL; + const struct sc_asn1_entry *entry = asn1; size_t total = 0, objsize; if (ctx->debug >= 3) debug(ctx, "called, depth %d\n", depth); - if (left < 2) - return SC_ERROR_ASN1_END_OF_CONTENTS; for (idx = 0; asn1[idx].name != NULL; idx++) { entry = &asn1[idx]; if (!(entry->flags & SC_ASN1_PRESENT)) continue; - r = asn1_encode_entry(ctx, entry, p, bufleft, &objsize); - if (r) + r = asn1_encode_entry(ctx, entry, &obj, &objsize, depth); + if (r) { + if (buf != NULL) + free(buf); return r; + } + buf = realloc(buf, total + objsize); + memcpy(buf + total, obj, objsize); + free(obj); total += objsize; - p += objsize; - assert(bufleft >= objsize); - bufleft -= objsize; } - if (objsize_out != NULL) - *objsize_out = total; + *ptr = buf; + *size = total; SC_FUNC_RETURN(ctx, 3, 0); -#else - return SC_ERROR_NOT_SUPPORTED; -#endif +} + +int sc_asn1_encode(struct sc_context *ctx, const struct sc_asn1_entry *asn1, + u8 **ptr, size_t *size) +{ + return asn1_encode(ctx, asn1, ptr, size, 0); } diff --git a/src/libopensc/asn1.h b/src/libopensc/asn1.h index 019d2bff67..620b1b06b0 100644 --- a/src/libopensc/asn1.h +++ b/src/libopensc/asn1.h @@ -24,7 +24,7 @@ #include "opensc.h" #include "opensc-pkcs15.h" -struct sc_asn1_struct { +struct sc_asn1_entry { const char *name; unsigned int type; unsigned int tag; @@ -35,19 +35,24 @@ struct sc_asn1_struct { struct sc_pkcs15_object { struct sc_pkcs15_common_obj_attr *com_attr; - struct sc_asn1_struct *asn1_class_attr; - struct sc_asn1_struct *asn1_subclass_attr; - struct sc_asn1_struct *asn1_type_attr; + struct sc_asn1_entry *asn1_class_attr; + struct sc_asn1_entry *asn1_subclass_attr; + struct sc_asn1_entry *asn1_type_attr; }; +/* Utility functions */ +void sc_format_asn1_entry(struct sc_asn1_entry *entry, void *parm, void *arg, + int set_present); +void sc_copy_asn1_entry(const struct sc_asn1_entry *src, + struct sc_asn1_entry *dest); + /* DER tag and length parsing */ - -int sc_asn1_decode(struct sc_context *ctx, struct sc_asn1_struct *asn1, +int sc_asn1_decode(struct sc_context *ctx, struct sc_asn1_entry *asn1, const u8 *in, size_t len, const u8 **newp, size_t *left); -int sc_asn1_decode_choice(struct sc_context *ctx, struct sc_asn1_struct *asn1, +int sc_asn1_decode_choice(struct sc_context *ctx, struct sc_asn1_entry *asn1, const u8 *in, size_t len, const u8 **newp, size_t *left); -int sc_asn1_encode(struct sc_context *ctx, const struct sc_asn1_struct *asn1, - u8 *buf, size_t bufsize, size_t *obj_size); +int sc_asn1_encode(struct sc_context *ctx, const struct sc_asn1_entry *asn1, + u8 **buf, size_t *bufsize); const u8 *sc_asn1_find_tag(struct sc_context *ctx, const u8 * buf, size_t buflen, unsigned int tag, size_t *taglen); diff --git a/src/libopensc/card-default.c b/src/libopensc/card-default.c index d3e6f35172..d2f2e98264 100644 --- a/src/libopensc/card-default.c +++ b/src/libopensc/card-default.c @@ -95,7 +95,7 @@ static int autodetect_class(struct sc_card *card) const struct sc_card_driver *drv; if (card->ctx->debug >= 2) debug(card->ctx, "SELECT FILE seems to return Schlumberger 'flex stuff\n"); - drv = sc_get_mflex_driver(); + drv = sc_get_flex_driver(); card->ops->select_file = drv->ops->select_file; return 0; } diff --git a/src/libopensc/card-multiflex.c b/src/libopensc/card-flex.c similarity index 86% rename from src/libopensc/card-multiflex.c rename to src/libopensc/card-flex.c index 6bac45c40e..7016324d1e 100644 --- a/src/libopensc/card-multiflex.c +++ b/src/libopensc/card-flex.c @@ -1,5 +1,5 @@ /* - * card-multiflex.c: Support for Multiflex cards by Schlumberger + * card-flex.c: Support for Schlumberger cards * * Copyright (C) 2001 Juha Yrjölä * @@ -21,33 +21,33 @@ #include "sc-internal.h" #include "sc-log.h" -static const char *mflex_atrs[] = { +static const char *flex_atrs[] = { "3B:95:94:40:FF:63:01:01:02:01", /* CryptoFlex 16k */ "3B:19:14:55:90:01:02:02:00:05:04:B0", NULL }; -static struct sc_card_operations mflex_ops; -static const struct sc_card_driver mflex_drv = { +static struct sc_card_operations flex_ops; +static const struct sc_card_driver flex_drv = { NULL, - "Multiflex/Schlumberger", - "mflex", - &mflex_ops + "Schlumberger Multiflex/CryptoFlex", + "slb", + &flex_ops }; -static int mflex_finish(struct sc_card *card) +static int flex_finish(struct sc_card *card) { return 0; } -static int mflex_match_card(struct sc_card *card) +static int flex_match_card(struct sc_card *card) { int i, match = -1; - for (i = 0; mflex_atrs[i] != NULL; i++) { + for (i = 0; flex_atrs[i] != NULL; i++) { u8 defatr[SC_MAX_ATR_SIZE]; size_t len = sizeof(defatr); - const char *atrp = mflex_atrs[i]; + const char *atrp = flex_atrs[i]; if (sc_hex_to_bin(atrp, defatr, &len)) continue; @@ -64,7 +64,7 @@ static int mflex_match_card(struct sc_card *card) return 1; } -static int mflex_init(struct sc_card *card) +static int flex_init(struct sc_card *card) { card->ops_data = NULL; card->cla = 0xC0; @@ -160,7 +160,7 @@ static int parse_flex_sf_reply(struct sc_context *ctx, const u8 *buf, int buflen return 0; } -static int mflex_select_file(struct sc_card *card, const struct sc_path *path, +static int flex_select_file(struct sc_card *card, const struct sc_path *path, struct sc_file *file) { int r, i; @@ -188,7 +188,7 @@ static int mflex_select_file(struct sc_card *card, const struct sc_path *path, SC_TEST_RET(card->ctx, r, "sc_lock() failed"); if (memcmp(pathptr, "\x3F\x00", 2) != 0) { sc_format_path("I3F00", &tmppath); - r = mflex_select_file(card, &tmppath, NULL); + r = flex_select_file(card, &tmppath, NULL); if (r) sc_unlock(card); SC_TEST_RET(card->ctx, r, "Unable to select Master File (MF)"); @@ -196,7 +196,7 @@ static int mflex_select_file(struct sc_card *card, const struct sc_path *path, while (pathlen > 2) { memcpy(tmppath.value, pathptr, 2); tmppath.len = 2; - r = mflex_select_file(card, &tmppath, NULL); + r = flex_select_file(card, &tmppath, NULL); if (r) sc_unlock(card); SC_TEST_RET(card->ctx, r, "Unable to select DF"); @@ -251,7 +251,7 @@ static int mflex_select_file(struct sc_card *card, const struct sc_path *path, return parse_flex_sf_reply(card->ctx, apdu.resp, apdu.resplen, file); } -static int mflex_list_files(struct sc_card *card, u8 *buf, size_t buflen) +static int flex_list_files(struct sc_card *card, u8 *buf, size_t buflen) { struct sc_apdu apdu; u8 rbuf[4]; @@ -288,18 +288,18 @@ static const struct sc_card_driver * sc_get_driver(void) { const struct sc_card_driver *iso_drv = sc_get_iso7816_driver(); - mflex_ops = *iso_drv->ops; - mflex_ops.match_card = mflex_match_card; - mflex_ops.init = mflex_init; - mflex_ops.finish = mflex_finish; - mflex_ops.select_file = mflex_select_file; - mflex_ops.list_files = mflex_list_files; + flex_ops = *iso_drv->ops; + flex_ops.match_card = flex_match_card; + flex_ops.init = flex_init; + flex_ops.finish = flex_finish; + flex_ops.select_file = flex_select_file; + flex_ops.list_files = flex_list_files; - return &mflex_drv; + return &flex_drv; } #if 1 -const struct sc_card_driver * sc_get_mflex_driver(void) +const struct sc_card_driver * sc_get_flex_driver(void) { return sc_get_driver(); } diff --git a/src/libopensc/card.c b/src/libopensc/card.c index 5af5c9ea04..e27c957209 100644 --- a/src/libopensc/card.c +++ b/src/libopensc/card.c @@ -374,8 +374,8 @@ int sc_connect_card(struct sc_context *ctx, memcpy(card->atr, rgReaderStates[0].rgbAtr, i); card->atr_len = i; - if (ctx->default_driver != NULL) { - card->driver = ctx->default_driver; + if (ctx->forced_driver != NULL) { + card->driver = ctx->forced_driver; memcpy(card->ops, card->driver->ops, sizeof(struct sc_card_operations)); if (card->ops->init != NULL) { r = card->ops->init(card); diff --git a/src/libopensc/opensc-pkcs15.h b/src/libopensc/opensc-pkcs15.h index 84afcd6a5d..bea3c9dbd4 100644 --- a/src/libopensc/opensc-pkcs15.h +++ b/src/libopensc/opensc-pkcs15.h @@ -176,10 +176,14 @@ struct sc_pkcs15_defaults { int arg; }; -/* Binds a card object to a PKCS#15 card object and initializes - * a new PKCS#15 card object */ +/* sc_pkcs15_bind: Binds a card object to a PKCS #15 card object + * and initializes a new PKCS#15 card object. Will return + * SC_ERROR_PKCS15_APP_NOT_FOUND, if the card hasn't got a + * valid PKCS #15 file structure. */ int sc_pkcs15_bind(struct sc_card *card, struct sc_pkcs15_card **pkcs15_card); +/* sc_pkcs_unbind: Releases a PKCS #15 card object, and frees any + * memory allocations done on the card object. */ int sc_pkcs15_unbind(struct sc_pkcs15_card *card); int sc_pkcs15_decipher(struct sc_pkcs15_card *p15card, @@ -205,6 +209,12 @@ void sc_pkcs15_free_certificate(struct sc_pkcs15_cert *cert); int sc_pkcs15_find_cert_by_id(struct sc_pkcs15_card *card, const struct sc_pkcs15_id *id, struct sc_pkcs15_cert_info **out); +/* sc_pkcs15_create_cdf: Creates a new certificate DF on a card pointed + * by . Information about the file, such as the file ID, is read + * from . has to be NULL-terminated. */ +int sc_pkcs15_create_cdf(struct sc_pkcs15_card *card, + struct sc_file *file, + const struct sc_pkcs15_cert_info **certs); void sc_pkcs15_print_prkey_info(const struct sc_pkcs15_prkey_info *prkey); int sc_pkcs15_enum_private_keys(struct sc_pkcs15_card *card); diff --git a/src/libopensc/opensc.h b/src/libopensc/opensc.h index 99f5b7e0d5..60b9109b17 100644 --- a/src/libopensc/opensc.h +++ b/src/libopensc/opensc.h @@ -45,7 +45,7 @@ extern "C" { #define SC_ERROR_TRANSMIT_FAILED -1004 #define SC_ERROR_FILE_NOT_FOUND -1005 #define SC_ERROR_INVALID_ARGUMENTS -1006 -#define SC_ERROR_PKCS15_CARD_NOT_FOUND -1007 +#define SC_ERROR_PKCS15_APP_NOT_FOUND -1007 #define SC_ERROR_REQUIRED_PARAMETER_NOT_FOUND -1008 #define SC_ERROR_OUT_OF_MEMORY -1009 #define SC_ERROR_NO_READERS_FOUND -1010 @@ -330,7 +330,7 @@ struct sc_context { int use_std_output, use_cache; const struct sc_card_driver *card_drivers[SC_MAX_CARD_DRIVERS+1]; - const struct sc_card_driver *default_driver; + const struct sc_card_driver *forced_driver; pthread_mutex_t mutex; }; @@ -359,7 +359,7 @@ void sc_format_apdu(struct sc_card *card, struct sc_apdu *apdu, int cse, int ins int sc_establish_context(struct sc_context **ctx); int sc_destroy_context(struct sc_context *ctx); -int sc_set_default_card_driver(struct sc_context *ctx, const char *short_name); +int sc_set_card_driver(struct sc_context *ctx, const char *short_name); int sc_connect_card(struct sc_context *ctx, int reader, struct sc_card **card); int sc_disconnect_card(struct sc_card *card); @@ -424,7 +424,7 @@ extern const char *sc_version; extern const struct sc_card_driver *sc_get_iso7816_driver(void); extern const struct sc_card_driver *sc_get_emv_driver(void); extern const struct sc_card_driver *sc_get_setec_driver(void); -extern const struct sc_card_driver *sc_get_mflex_driver(void); +extern const struct sc_card_driver *sc_get_flex_driver(void); extern const struct sc_card_driver *sc_get_default_driver(void); #ifdef __cplusplus diff --git a/src/libopensc/pkcs15-cert.c b/src/libopensc/pkcs15-cert.c index bc8ed77e45..e1a5884473 100644 --- a/src/libopensc/pkcs15-cert.c +++ b/src/libopensc/pkcs15-cert.c @@ -33,7 +33,7 @@ static int parse_rsa_pubkey(struct sc_context *ctx, struct sc_pkcs15_rsa_pubkey *key) { - struct sc_asn1_struct asn1_rsa_pubkey[] = { + struct sc_asn1_entry asn1_rsa_pubkey[] = { { "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 } @@ -62,7 +62,7 @@ static int parse_algorithm_id(struct sc_context *ctx, void *arg, const u8 *obj, size_t objlen, int depth) { struct asn1_algorithm_id *alg_id = (struct asn1_algorithm_id *) arg; - struct sc_asn1_struct asn1_alg_id[] = { + struct sc_asn1_entry asn1_alg_id[] = { { "algorithm", SC_ASN1_OBJECT, ASN1_OBJECT, 0, &alg_id->id }, { "parameters", SC_ASN1_STRUCT, 0, SC_ASN1_OPTIONAL, NULL }, { NULL } @@ -82,16 +82,16 @@ static int parse_x509_cert(struct sc_context *ctx, const u8 *buf, size_t buflen, struct asn1_algorithm_id pk_alg, sig_alg; u8 *pk = NULL; size_t pklen = 0; - struct sc_asn1_struct asn1_version[] = { + struct sc_asn1_entry asn1_version[] = { { "version", SC_ASN1_INTEGER, ASN1_INTEGER, 0, &cert->version }, { NULL } }; - struct sc_asn1_struct asn1_pkinfo[] = { + struct sc_asn1_entry asn1_pkinfo[] = { { "algorithm", SC_ASN1_CALLBACK, ASN1_SEQUENCE | SC_ASN1_CONS, 0, (void *) 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[] = { + struct sc_asn1_entry 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 }, @@ -101,7 +101,7 @@ static int parse_x509_cert(struct sc_context *ctx, const u8 *buf, size_t buflen, { "subjectPublicKeyInfo",SC_ASN1_STRUCT, ASN1_SEQUENCE | SC_ASN1_CONS, 0, asn1_pkinfo }, { NULL } }; - struct sc_asn1_struct asn1_cert[] = { + struct sc_asn1_entry asn1_cert[] = { { "tbsCertificate", SC_ASN1_STRUCT, ASN1_SEQUENCE | SC_ASN1_CONS, 0, asn1_tbscert }, { "signatureAlgorithm", SC_ASN1_CALLBACK, ASN1_SEQUENCE | SC_ASN1_CONS, 0, (void *) parse_algorithm_id, &sig_alg }, { "signatureValue", SC_ASN1_BIT_STRING,ASN1_BIT_STRING, 0, NULL, 0 }, @@ -277,45 +277,122 @@ int sc_pkcs15_read_certificate(struct sc_pkcs15_card *p15card, return 0; } +static const struct sc_asn1_entry c_asn1_cred_ident[] = { + { "idType", SC_ASN1_INTEGER, ASN1_INTEGER, 0, NULL }, + { "idValue", SC_ASN1_OCTET_STRING, ASN1_OCTET_STRING, 0, NULL }, + { NULL } +}; +static const struct sc_asn1_entry c_asn1_com_cert_attr[] = { + { "iD", SC_ASN1_PKCS15_ID, ASN1_OCTET_STRING, 0, NULL }, + { "authority", SC_ASN1_BOOLEAN, ASN1_BOOLEAN, SC_ASN1_OPTIONAL, NULL }, + { "identifier", SC_ASN1_STRUCT, ASN1_SEQUENCE | SC_ASN1_CONS, SC_ASN1_OPTIONAL, NULL }, + /* FIXME: Add rest of the optional fields */ + { NULL } +}; +static const struct sc_asn1_entry c_asn1_x509_cert_attr[] = { + { "value", SC_ASN1_PATH, ASN1_SEQUENCE | SC_ASN1_CONS, 0, NULL }, + { NULL } +}; +static const struct sc_asn1_entry c_asn1_type_cert_attr[] = { + { "x509CertificateAttributes", SC_ASN1_STRUCT, ASN1_SEQUENCE | SC_ASN1_CONS, 0, NULL }, + { NULL } +}; +static const struct sc_asn1_entry c_asn1_cert[] = { + { "x509Certificate", SC_ASN1_PKCS15_OBJECT, ASN1_SEQUENCE | SC_ASN1_CONS, 0, NULL }, + { NULL } +}; + static int parse_x509_cert_info(struct sc_context *ctx, struct sc_pkcs15_cert_info *cert, const u8 ** buf, size_t *buflen) { + struct sc_asn1_entry asn1_cred_ident[3], asn1_com_cert_attr[4], + asn1_x509_cert_attr[2], asn1_type_cert_attr[2], + asn1_cert[2]; + struct sc_pkcs15_object cert_obj = { &cert->com_attr, asn1_com_cert_attr, NULL, + asn1_type_cert_attr }; u8 id_value[128]; int id_type, id_value_len = sizeof(id_value); int r; + + cert->authority = 0; - struct sc_asn1_struct asn1_cred_ident[] = { - { "idType", SC_ASN1_INTEGER, ASN1_INTEGER, 0, &id_type }, - { "idValue", SC_ASN1_OCTET_STRING, ASN1_OCTET_STRING, 0, &id_value, &id_value_len }, - { NULL } - }; - struct sc_asn1_struct asn1_com_cert_attr[] = { - { "iD", SC_ASN1_PKCS15_ID, ASN1_OCTET_STRING, 0, &cert->id, NULL }, - { "authority", SC_ASN1_BOOLEAN, ASN1_BOOLEAN, SC_ASN1_OPTIONAL, &cert->authority, NULL }, - { "identifier", SC_ASN1_STRUCT, ASN1_SEQUENCE | SC_ASN1_CONS, 0, asn1_cred_ident }, - { NULL } - }; - struct sc_asn1_struct asn1_x509_cert_attr[] = { - { "value", SC_ASN1_PATH, ASN1_SEQUENCE | SC_ASN1_CONS, 0, &cert->path }, - { NULL } - }; - struct sc_asn1_struct asn1_type_cert_attr[] = { - { "x509CertificateAttributes", SC_ASN1_STRUCT, ASN1_SEQUENCE | SC_ASN1_CONS, 0, asn1_x509_cert_attr }, - { NULL } - }; - struct sc_pkcs15_object cert_obj = { &cert->com_attr, asn1_com_cert_attr, NULL, - asn1_type_cert_attr }; - struct sc_asn1_struct asn1_cert[] = { - { "x509Certificate", SC_ASN1_PKCS15_OBJECT, ASN1_SEQUENCE | SC_ASN1_CONS, 0, &cert_obj }, - { NULL } - }; + sc_copy_asn1_entry(c_asn1_cred_ident, asn1_cred_ident); + sc_copy_asn1_entry(c_asn1_com_cert_attr, asn1_com_cert_attr); + sc_copy_asn1_entry(c_asn1_x509_cert_attr, asn1_x509_cert_attr); + sc_copy_asn1_entry(c_asn1_type_cert_attr, asn1_type_cert_attr); + sc_copy_asn1_entry(c_asn1_cert, asn1_cert); + + sc_format_asn1_entry(asn1_cred_ident + 0, &id_type, NULL, 0); + sc_format_asn1_entry(asn1_cred_ident + 1, &id_value, &id_value_len, 0); + sc_format_asn1_entry(asn1_com_cert_attr + 0, &cert->id, NULL, 0); + sc_format_asn1_entry(asn1_com_cert_attr + 1, &cert->authority, NULL, 0); + sc_format_asn1_entry(asn1_com_cert_attr + 2, asn1_cred_ident, NULL, 0); + sc_format_asn1_entry(asn1_x509_cert_attr + 0, &cert->path, NULL, 0); + sc_format_asn1_entry(asn1_type_cert_attr + 0, asn1_x509_cert_attr, NULL, 0); + sc_format_asn1_entry(asn1_cert + 0, &cert_obj, NULL, 0); r = sc_asn1_decode(ctx, asn1_cert, *buf, *buflen, buf, buflen); return r; } +static int encode_x509_cert_info(struct sc_context *ctx, + struct sc_pkcs15_cert_info *cert, + u8 ** buf, size_t *buflen) +{ + struct sc_asn1_entry asn1_cred_ident[3], asn1_com_cert_attr[4], + asn1_x509_cert_attr[2], asn1_type_cert_attr[2], + asn1_cert[2]; + const struct sc_pkcs15_object cert_obj = { &cert->com_attr, asn1_com_cert_attr, NULL, + asn1_type_cert_attr }; + int r; + + sc_copy_asn1_entry(c_asn1_cred_ident, asn1_cred_ident); + sc_copy_asn1_entry(c_asn1_com_cert_attr, asn1_com_cert_attr); + sc_copy_asn1_entry(c_asn1_x509_cert_attr, asn1_x509_cert_attr); + sc_copy_asn1_entry(c_asn1_type_cert_attr, asn1_type_cert_attr); + sc_copy_asn1_entry(c_asn1_cert, asn1_cert); + + sc_format_asn1_entry(asn1_com_cert_attr + 0, (void *) &cert->id, NULL, 1); + if (cert->authority) + sc_format_asn1_entry(asn1_com_cert_attr + 1, (void *) &cert->authority, NULL, 1); + sc_format_asn1_entry(asn1_x509_cert_attr + 0, (void *) &cert->path, NULL, 1); + sc_format_asn1_entry(asn1_type_cert_attr + 0, (void *) asn1_x509_cert_attr, NULL, 1); + sc_format_asn1_entry(asn1_cert + 0, (void *) &cert_obj, NULL, 1); + + r = sc_asn1_encode(ctx, asn1_cert, buf, buflen); + + return r; +} + +int sc_pkcs15_create_cdf(struct sc_pkcs15_card *p15card, + struct sc_file *file, + const struct sc_pkcs15_cert_info **certs) +{ + u8 *buf = NULL, *tmp; + size_t bufsize = 0, tmpsize; + int i = 0, r; + const struct sc_pkcs15_cert_info *cert; + u8 str[10240]; + + for (i = 0; (cert = certs[i]) != NULL; i++) { + r = encode_x509_cert_info(p15card->card->ctx, + (struct sc_pkcs15_cert_info *) cert, + &tmp, &tmpsize); + if (r) { + free(buf); + return r; + } + buf = realloc(buf, bufsize + tmpsize); + memcpy(buf + bufsize, tmp, tmpsize); + bufsize += tmpsize; + } + sc_hex_dump(p15card->card->ctx, buf, bufsize, str, sizeof(str)); + printf("\n%s\n", str); + return 0; +} + void sc_pkcs15_print_cert_info(const struct sc_pkcs15_cert_info *cert) { int i; diff --git a/src/libopensc/pkcs15-pin.c b/src/libopensc/pkcs15-pin.c index db8d255f62..ae9f5cc651 100644 --- a/src/libopensc/pkcs15-pin.c +++ b/src/libopensc/pkcs15-pin.c @@ -1,5 +1,5 @@ /* - * sc-pkcs15-pin.c: PKCS#15 PIN functions + * pkcs15-pin.c: PKCS#15 PIN functions * * Copyright (C) 2001 Juha Yrjölä * @@ -32,13 +32,13 @@ static int parse_pin_info(struct sc_context *ctx, const u8 ** buf, size_t *buflen) { int r; - struct sc_asn1_struct asn1_com_ao_attr[] = { + struct sc_asn1_entry asn1_com_ao_attr[] = { { "authId", SC_ASN1_PKCS15_ID, ASN1_OCTET_STRING, 0, &pin->auth_id }, { NULL } }; int flags_len = sizeof(pin->flags); int padchar_len = 1; - struct sc_asn1_struct asn1_pin_attr[] = { + struct sc_asn1_entry asn1_pin_attr[] = { { "pinFlags", SC_ASN1_BIT_STRING, ASN1_BIT_STRING, 0, &pin->flags, &flags_len}, { "pinType", SC_ASN1_ENUMERATED, ASN1_ENUMERATED, 0, &pin->type }, { "minLength", SC_ASN1_INTEGER, ASN1_INTEGER, 0, &pin->min_length }, @@ -50,13 +50,13 @@ static int parse_pin_info(struct sc_context *ctx, { "path", SC_ASN1_PATH, ASN1_SEQUENCE | SC_ASN1_CONS, SC_ASN1_OPTIONAL, &pin->path }, { NULL } }; - struct sc_asn1_struct asn1_type_pin_attr[] = { + struct sc_asn1_entry asn1_type_pin_attr[] = { { "pinAttributes", SC_ASN1_STRUCT, ASN1_SEQUENCE | SC_ASN1_CONS, 0, asn1_pin_attr}, { NULL } }; struct sc_pkcs15_object pin_obj = { &pin->com_attr, asn1_com_ao_attr, NULL, asn1_type_pin_attr }; - struct sc_asn1_struct asn1_pin[] = { + struct sc_asn1_entry asn1_pin[] = { { "pin", SC_ASN1_PKCS15_OBJECT, ASN1_SEQUENCE | SC_ASN1_CONS, 0, &pin_obj }, { NULL } }; diff --git a/src/libopensc/pkcs15-prkey.c b/src/libopensc/pkcs15-prkey.c index aacaac4780..df8965837c 100644 --- a/src/libopensc/pkcs15-prkey.c +++ b/src/libopensc/pkcs15-prkey.c @@ -1,5 +1,5 @@ /* - * sc-pkcs15-prkey.c: PKCS#15 private key functions + * pkcs15-prkey.c: PKCS#15 private key functions * * Copyright (C) 2001 Juha Yrjölä * @@ -55,7 +55,7 @@ static int parse_rsa_prkey_info(struct sc_context *ctx, int r; int usage_len = sizeof(prkey->usage); int af_len = sizeof(prkey->access_flags); - struct sc_asn1_struct asn1_com_key_attr[] = { + struct sc_asn1_entry asn1_com_key_attr[] = { { "iD", SC_ASN1_PKCS15_ID, ASN1_OCTET_STRING, 0, &prkey->id, NULL }, { "usage", SC_ASN1_BIT_STRING, ASN1_BIT_STRING, 0, &prkey->usage, &usage_len }, { "native", SC_ASN1_BOOLEAN, ASN1_BOOLEAN, SC_ASN1_OPTIONAL, &prkey->native }, @@ -63,23 +63,23 @@ static int parse_rsa_prkey_info(struct sc_context *ctx, { "keyReference",SC_ASN1_INTEGER, ASN1_INTEGER, SC_ASN1_OPTIONAL, &prkey->key_reference }, { NULL } }; - struct sc_asn1_struct asn1_com_prkey_attr[] = { + struct sc_asn1_entry asn1_com_prkey_attr[] = { { NULL } }; - struct sc_asn1_struct asn1_rsakey_attr[] = { + struct sc_asn1_entry asn1_rsakey_attr[] = { { "value", SC_ASN1_PATH, ASN1_SEQUENCE | SC_ASN1_CONS, 0, &prkey->file_id }, { "modulusLength", SC_ASN1_INTEGER, ASN1_INTEGER, 0, &prkey->modulus_length }, { "keyInfo", SC_ASN1_INTEGER, ASN1_INTEGER, SC_ASN1_OPTIONAL, NULL }, { NULL } }; - struct sc_asn1_struct asn1_type_attr[] = { + struct sc_asn1_entry asn1_type_attr[] = { { "publicRSAKeyAttributes", SC_ASN1_STRUCT, ASN1_SEQUENCE | SC_ASN1_CONS, 0, asn1_rsakey_attr }, { NULL } }; struct sc_pkcs15_object prkey_obj = { &prkey->com_attr, asn1_com_key_attr, asn1_com_prkey_attr, asn1_type_attr }; - struct sc_asn1_struct asn1_prkey[] = { + struct sc_asn1_entry asn1_prkey[] = { { "privateRSAKey", SC_ASN1_PKCS15_OBJECT, ASN1_SEQUENCE | SC_ASN1_CONS, 0, &prkey_obj }, { NULL } }; diff --git a/src/libopensc/pkcs15-sec.c b/src/libopensc/pkcs15-sec.c index 41bb133cf8..a82bd5b4c9 100644 --- a/src/libopensc/pkcs15-sec.c +++ b/src/libopensc/pkcs15-sec.c @@ -1,5 +1,5 @@ /* - * sc-pkcs15-sec.c: PKCS#15 cryptography functions + * pkcs15-sec.c: PKCS#15 cryptography functions * * Copyright (C) 2001 Juha Yrjölä * diff --git a/src/libopensc/pkcs15.c b/src/libopensc/pkcs15.c index 5baecab564..7f6b571dad 100644 --- a/src/libopensc/pkcs15.c +++ b/src/libopensc/pkcs15.c @@ -1,5 +1,5 @@ /* - * sc-pkcs15.c: PKCS#15 general functions + * pkcs15.c: PKCS#15 general functions * * Copyright (C) 2001 Juha Yrjölä * @@ -64,7 +64,7 @@ void parse_tokeninfo(struct sc_pkcs15_card *card, const u8 * buf, size_t buflen) int mnfid_len = sizeof(mnfid); int flags_len = sizeof(card->flags); - struct sc_asn1_struct asn1_tokeninfo[] = { + struct sc_asn1_entry asn1_tokeninfo[] = { { "version", SC_ASN1_INTEGER, ASN1_INTEGER, 0, &card->version }, { "serialNumber", SC_ASN1_OCTET_STRING, ASN1_OCTET_STRING, 0, serial, &serial_len }, { "manufacturerID", SC_ASN1_UTF8STRING, ASN1_UTF8STRING, SC_ASN1_OPTIONAL, mnfid, &mnfid_len }, @@ -119,14 +119,14 @@ static int parse_dir(const u8 * buf, size_t buflen, struct sc_pkcs15_card *card) int aid_len = sizeof(aid), label_len = sizeof(label), path_len = sizeof(path); - struct sc_asn1_struct asn1_ddo[] = { + struct sc_asn1_entry asn1_ddo[] = { { "oid", SC_ASN1_OBJECT, ASN1_OBJECT, 0, NULL }, { "odfPath", SC_ASN1_PATH, SC_ASN1_CONS | ASN1_SEQUENCE, SC_ASN1_OPTIONAL, &card->file_odf.path }, { "tokenInfoPath", SC_ASN1_PATH, SC_ASN1_CONS | SC_ASN1_CTX | 0, SC_ASN1_OPTIONAL, &card->file_tokeninfo.path }, { "unusedPath", SC_ASN1_PATH, SC_ASN1_CONS | SC_ASN1_CTX | 1, SC_ASN1_OPTIONAL, NULL }, { NULL } }; - struct sc_asn1_struct asn1_dir[] = { + struct sc_asn1_entry asn1_dir[] = { { "aid", SC_ASN1_OCTET_STRING, SC_ASN1_APP | 15, 0, aid, &aid_len }, { "label", SC_ASN1_UTF8STRING, SC_ASN1_APP | 16, SC_ASN1_OPTIONAL, label, &label_len }, { "path", SC_ASN1_OCTET_STRING, SC_ASN1_APP | 17, 0, path, &path_len }, @@ -168,11 +168,11 @@ static int parse_odf(const u8 * buf, int buflen, struct sc_pkcs15_card *card) size_t left = buflen; int r; struct sc_path path; - struct sc_asn1_struct asn1_obj_or_path[] = { + struct sc_asn1_entry asn1_obj_or_path[] = { { "path", SC_ASN1_PATH, SC_ASN1_CONS | SC_ASN1_SEQUENCE, 0, &path }, { NULL } }; - struct sc_asn1_struct asn1_odf[] = { + struct sc_asn1_entry asn1_odf[] = { { "privateKeys", SC_ASN1_STRUCT, SC_ASN1_CTX | 0 | SC_ASN1_CONS, 0, asn1_obj_or_path }, { "certificates", SC_ASN1_STRUCT, SC_ASN1_CTX | 4 | SC_ASN1_CONS, 0, asn1_obj_or_path }, { "trustedCertificates", SC_ASN1_STRUCT, SC_ASN1_CTX | 5 | SC_ASN1_CONS, 0, asn1_obj_or_path }, @@ -254,7 +254,7 @@ int sc_pkcs15_bind(struct sc_card *card, err = sc_select_file(card, &tmppath, &p15card->file_dir); if (err) { error(ctx, "Error selecting EF(DIR): %s\n", sc_strerror(err)); - err = SC_ERROR_PKCS15_CARD_NOT_FOUND; + err = SC_ERROR_PKCS15_APP_NOT_FOUND; goto error; } err = sc_read_binary(card, 0, buf, p15card->file_dir.size, 0); @@ -263,13 +263,13 @@ int sc_pkcs15_bind(struct sc_card *card, goto error; } if (err <= 2) { - err = SC_ERROR_PKCS15_CARD_NOT_FOUND; + err = SC_ERROR_PKCS15_APP_NOT_FOUND; error(ctx, "Error reading EF(DIR): too few bytes read\n"); goto error; } len = err; if (parse_dir(buf, len, p15card)) { - err = SC_ERROR_PKCS15_CARD_NOT_FOUND; + err = SC_ERROR_PKCS15_APP_NOT_FOUND; error(ctx, "Error parsing EF(DIR)\n"); goto error; } @@ -290,12 +290,12 @@ int sc_pkcs15_bind(struct sc_card *card, if (err < 0) goto error; if (err < 2) { - err = SC_ERROR_PKCS15_CARD_NOT_FOUND; + err = SC_ERROR_PKCS15_APP_NOT_FOUND; goto error; } len = err; if (parse_odf(buf, len, p15card)) { - err = SC_ERROR_PKCS15_CARD_NOT_FOUND; + err = SC_ERROR_PKCS15_APP_NOT_FOUND; goto error; } if (p15card->file_tokeninfo.path.len == 0) { @@ -315,7 +315,7 @@ int sc_pkcs15_bind(struct sc_card *card, if (err < 0) goto error; if (err <= 2) { - err = SC_ERROR_PKCS15_CARD_NOT_FOUND; + err = SC_ERROR_PKCS15_APP_NOT_FOUND; goto error; } parse_tokeninfo(p15card, buf, err); diff --git a/src/libopensc/pkcs15.h b/src/libopensc/pkcs15.h index 84afcd6a5d..bea3c9dbd4 100644 --- a/src/libopensc/pkcs15.h +++ b/src/libopensc/pkcs15.h @@ -176,10 +176,14 @@ struct sc_pkcs15_defaults { int arg; }; -/* Binds a card object to a PKCS#15 card object and initializes - * a new PKCS#15 card object */ +/* sc_pkcs15_bind: Binds a card object to a PKCS #15 card object + * and initializes a new PKCS#15 card object. Will return + * SC_ERROR_PKCS15_APP_NOT_FOUND, if the card hasn't got a + * valid PKCS #15 file structure. */ int sc_pkcs15_bind(struct sc_card *card, struct sc_pkcs15_card **pkcs15_card); +/* sc_pkcs_unbind: Releases a PKCS #15 card object, and frees any + * memory allocations done on the card object. */ int sc_pkcs15_unbind(struct sc_pkcs15_card *card); int sc_pkcs15_decipher(struct sc_pkcs15_card *p15card, @@ -205,6 +209,12 @@ void sc_pkcs15_free_certificate(struct sc_pkcs15_cert *cert); int sc_pkcs15_find_cert_by_id(struct sc_pkcs15_card *card, const struct sc_pkcs15_id *id, struct sc_pkcs15_cert_info **out); +/* sc_pkcs15_create_cdf: Creates a new certificate DF on a card pointed + * by . Information about the file, such as the file ID, is read + * from . has to be NULL-terminated. */ +int sc_pkcs15_create_cdf(struct sc_pkcs15_card *card, + struct sc_file *file, + const struct sc_pkcs15_cert_info **certs); void sc_pkcs15_print_prkey_info(const struct sc_pkcs15_prkey_info *prkey); int sc_pkcs15_enum_private_keys(struct sc_pkcs15_card *card); diff --git a/src/libopensc/sc-asn1.h b/src/libopensc/sc-asn1.h index 019d2bff67..620b1b06b0 100644 --- a/src/libopensc/sc-asn1.h +++ b/src/libopensc/sc-asn1.h @@ -24,7 +24,7 @@ #include "opensc.h" #include "opensc-pkcs15.h" -struct sc_asn1_struct { +struct sc_asn1_entry { const char *name; unsigned int type; unsigned int tag; @@ -35,19 +35,24 @@ struct sc_asn1_struct { struct sc_pkcs15_object { struct sc_pkcs15_common_obj_attr *com_attr; - struct sc_asn1_struct *asn1_class_attr; - struct sc_asn1_struct *asn1_subclass_attr; - struct sc_asn1_struct *asn1_type_attr; + struct sc_asn1_entry *asn1_class_attr; + struct sc_asn1_entry *asn1_subclass_attr; + struct sc_asn1_entry *asn1_type_attr; }; +/* Utility functions */ +void sc_format_asn1_entry(struct sc_asn1_entry *entry, void *parm, void *arg, + int set_present); +void sc_copy_asn1_entry(const struct sc_asn1_entry *src, + struct sc_asn1_entry *dest); + /* DER tag and length parsing */ - -int sc_asn1_decode(struct sc_context *ctx, struct sc_asn1_struct *asn1, +int sc_asn1_decode(struct sc_context *ctx, struct sc_asn1_entry *asn1, const u8 *in, size_t len, const u8 **newp, size_t *left); -int sc_asn1_decode_choice(struct sc_context *ctx, struct sc_asn1_struct *asn1, +int sc_asn1_decode_choice(struct sc_context *ctx, struct sc_asn1_entry *asn1, const u8 *in, size_t len, const u8 **newp, size_t *left); -int sc_asn1_encode(struct sc_context *ctx, const struct sc_asn1_struct *asn1, - u8 *buf, size_t bufsize, size_t *obj_size); +int sc_asn1_encode(struct sc_context *ctx, const struct sc_asn1_entry *asn1, + u8 **buf, size_t *bufsize); const u8 *sc_asn1_find_tag(struct sc_context *ctx, const u8 * buf, size_t buflen, unsigned int tag, size_t *taglen); diff --git a/src/libopensc/sc.c b/src/libopensc/sc.c index 0963308d52..20b65807dd 100644 --- a/src/libopensc/sc.c +++ b/src/libopensc/sc.c @@ -172,6 +172,7 @@ int sc_establish_context(struct sc_context **ctx_out) } while (p < (reader_buf + reader_buf_size - 1)); free(reader_buf); pthread_mutex_init(&ctx->mutex, NULL); + ctx->forced_driver = NULL; for (i = 0; i < SC_MAX_CARD_DRIVERS+1; i++) ctx->card_drivers[i] = NULL; i = 0; @@ -179,7 +180,7 @@ int sc_establish_context(struct sc_context **ctx_out) ctx->card_drivers[i++] = sc_get_setec_driver(); #endif #if 1 - ctx->card_drivers[i++] = sc_get_mflex_driver(); + ctx->card_drivers[i++] = sc_get_flex_driver(); #endif #if 1 ctx->card_drivers[i++] = sc_get_iso7816_driver(); @@ -208,19 +209,19 @@ int sc_destroy_context(struct sc_context *ctx) return 0; } -int sc_set_default_card_driver(struct sc_context *ctx, const char *short_name) +int sc_set_card_driver(struct sc_context *ctx, const char *short_name) { int i = 0, match = 0; pthread_mutex_lock(&ctx->mutex); if (short_name == NULL) { - ctx->default_driver = NULL; + ctx->forced_driver = NULL; match = 1; } else while (ctx->card_drivers[i] != NULL && i < SC_MAX_CARD_DRIVERS) { const struct sc_card_driver *drv = ctx->card_drivers[i]; if (strcmp(short_name, drv->short_name) == 0) { - ctx->default_driver = drv; + ctx->forced_driver = drv; match = 1; break; } diff --git a/src/libopensc/sec.c b/src/libopensc/sec.c index b66058dba1..9c7cea87ee 100644 --- a/src/libopensc/sec.c +++ b/src/libopensc/sec.c @@ -1,5 +1,5 @@ /* - * sc-sec.c: Cryptography and security (ISO7816-8) functions + * sec.c: Cryptography and security (ISO7816-8) functions * * Copyright (C) 2001 Juha Yrjölä * diff --git a/src/pam/pam_pkcs15.c b/src/pam/pam_pkcs15.c index 1a309856c4..510951d843 100644 --- a/src/pam/pam_pkcs15.c +++ b/src/pam/pam_pkcs15.c @@ -280,7 +280,7 @@ PAM_EXTERN int pam_sm_authenticate(pam_handle_t * pamh, int flags, int argc, con printf("%s\n", argv[i]); #ifdef TEST - user = "root"; + user = "jey"; #else r = pam_get_user(pamh, &user, NULL); if (r != PAM_SUCCESS) diff --git a/src/tools/opensc-explorer.c b/src/tools/opensc-explorer.c index 7f39de00b8..037febc5fd 100644 --- a/src/tools/opensc-explorer.c +++ b/src/tools/opensc-explorer.c @@ -186,6 +186,15 @@ int do_cd(const char *arg) check_ret(r, SC_AC_OP_SELECT, "unable to select DF", ¤t_file); return -1; } + if (file.type != SC_FILE_TYPE_DF) { + printf("Error: file is not a DF.\n"); + r = sc_select_file(card, ¤t_path, NULL); + if (r) { + printf("unable to select parent file: %s\n", sc_strerror(r)); + die(1); + } + return -1; + } memcpy(current_path.value + current_path.len, path.value, path.len); current_path.len += path.len; current_file = file; diff --git a/src/tools/opensc-tool.c b/src/tools/opensc-tool.c index d6df18ea5c..e00e3c5f0f 100644 --- a/src/tools/opensc-tool.c +++ b/src/tools/opensc-tool.c @@ -393,7 +393,7 @@ int main(int argc, char * const argv[]) goto end; } if (opt_driver != NULL) { - err = sc_set_default_card_driver(ctx, opt_driver); + err = sc_set_card_driver(ctx, opt_driver); if (err) { fprintf(stderr, "Driver '%s' not found!\n", opt_driver); err = 1;