On Wed, 2010-10-06 at 23:12 +0300, Martin Paljak wrote: > Hello, > > On Oct 6, 2010, at 7:10 PM, Douglas E. Engert wrote: > > PROPOSAL: > > > > I would like to do the following to cleanup some of the duplication: > > > > Replace sc_pkcs15_pubkey_from_cert with non OpenSSL code, that would > > use the sc_asn1_decode_algorithm_id, and other code from parse_x509_cert > > to get the algorithm, its parameter, and the pubkey. > OK. This helps with reducing OpenSSL dependancies and reduce duplicated > functionality.
Attached is some prototyping stuff related to x509 parsing. Maybe it could be helpful. Execute the following command to get the required attributes from a certificate: cat cert.der | tools/cert-tool
Index: src/tools/Makefile.am =================================================================== --- src/tools/Makefile.am (revision 4798) +++ src/tools/Makefile.am (working copy) @@ -5,7 +5,7 @@ noinst_HEADERS = util.h bin_PROGRAMS = opensc-tool opensc-explorer pkcs15-tool pkcs15-crypt \ - pkcs11-tool cardos-tool eidenv rutoken-tool + pkcs11-tool cardos-tool eidenv rutoken-tool cert-tool if ENABLE_OPENSSL bin_PROGRAMS += cryptoflex-tool pkcs15-init netkey-tool piv-tool westcos-tool endif @@ -41,6 +41,7 @@ rutoken_tool_LDADD = $(OPTIONAL_OPENSSL_LIBS) westcos_tool_SOURCES = westcos-tool.c util.c westcos_tool_LDADD = $(OPTIONAL_OPENSSL_LIBS) +cert_tool_SOURCES = cert-tool.c if WIN32 opensc_tool_SOURCES += $(top_builddir)/win32/versioninfo.rc Index: src/libopensc/pkcs15.h =================================================================== --- src/libopensc/pkcs15.h (revision 4798) +++ src/libopensc/pkcs15.h (working copy) @@ -208,6 +208,10 @@ size_t crl_len; struct sc_pkcs15_pubkey key; + + sc_pkcs15_der_t subjectPublicKeyInfo; + sc_pkcs15_der_t extensions; + u8 *data; /* DER encoded raw cert */ size_t data_len; }; Index: src/libopensc/pkcs15-cert.c =================================================================== --- src/libopensc/pkcs15-cert.c (revision 4798) +++ src/libopensc/pkcs15-cert.c (working copy) @@ -68,8 +68,8 @@ { "issuer", SC_ASN1_OCTET_STRING, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, SC_ASN1_ALLOC, &cert->issuer, &cert->issuer_len }, { "validity", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, 0, NULL, NULL }, { "subject", SC_ASN1_OCTET_STRING, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, SC_ASN1_ALLOC, &cert->subject, &cert->subject_len }, - { "subjectPublicKeyInfo",SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, 0, asn1_pkinfo, NULL }, - { "extensions", SC_ASN1_STRUCT, SC_ASN1_CTX | 3 | SC_ASN1_CONS, SC_ASN1_OPTIONAL, asn1_extensions, NULL }, + { "subjectPublicKeyInfo",SC_ASN1_TLV, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, SC_ASN1_ALLOC, &cert->subjectPublicKeyInfo.value, &cert->subjectPublicKeyInfo.len}, + { "extensions", SC_ASN1_TLV, SC_ASN1_CTX | 3 | SC_ASN1_CONS, SC_ASN1_OPTIONAL | SC_ASN1_ALLOC, &cert->extensions.value, &cert->extensions.len}, { NULL, 0, 0, 0, NULL, NULL } }; struct sc_asn1_entry asn1_cert[] = { @@ -98,6 +98,10 @@ cert->version++; + if (cert->subjectPublicKeyInfo.value[1] & 0x80) r = 2 + (cert->subjectPublicKeyInfo.value[1] & 0x7F); + else r = 2; + r = sc_asn1_decode(ctx, asn1_pkinfo, cert->subjectPublicKeyInfo.value+r, cert->subjectPublicKeyInfo.len-r, NULL, NULL); + cert->key.algorithm = pk_alg.algorithm; pk.len >>= 3; /* convert number of bits to bytes */ cert->key.data = pk; Index: src/libopensc/asn1.c =================================================================== --- src/libopensc/asn1.c (revision 4798) +++ src/libopensc/asn1.c (working copy) @@ -1196,6 +1196,51 @@ if (entry->parm != NULL) r = callback_func(ctx, entry->arg, obj, objlen, depth); break; + case SC_ASN1_TLV: + if (entry->parm != NULL) { + + /*** works only for ONE octet tags ***/ + + u8 **buf = (u8**) entry->parm; + int _len = 1, i; + if (objlen < 128) + _len += 1; + else if (objlen < 256) + _len += 2; + else if (objlen < 256 * 256) + _len += 3; + else + _len += 4; + + if (entry->flags & SC_ASN1_ALLOC) { + *buf = malloc(_len + objlen); + if (*buf == NULL) + return SC_ERROR_OUT_OF_MEMORY; + } else if (*len < _len + objlen) { + return SC_ERROR_BUFFER_TOO_SMALL; + } + + *len = _len + objlen; + memcpy((*buf) + _len, obj, objlen); + + *((*buf) + 0) = entry->tag & 0xFF; + if (entry->tag & SC_ASN1_CTX) + *((*buf) + 0) |= SC_ASN1_TAG_CONTEXT; + if (entry->tag & SC_ASN1_APP) + *((*buf) + 0) |= SC_ASN1_TAG_APPLICATION; + if (entry->tag & SC_ASN1_CONS) + *((*buf) + 0) |= SC_ASN1_TAG_CONSTRUCTED; + if (_len == 2) { + *((*buf) + 1) = objlen & 0x7F; + } else { + *((*buf) + 1) = 0x80 | (_len - 2); + for (i = _len - 2; i > 0; i--) { + *((*buf) + 1 + i) = objlen & 0xFF; + objlen >>= 8; + } + } + } + break; default: sc_debug(ctx, SC_LOG_DEBUG_ASN1, "invalid ASN.1 type: %d\n", entry->type); return SC_ERROR_INVALID_ASN1_OBJECT; @@ -1257,6 +1302,34 @@ goto decode_ok; } + /* Special case TAG_ANY matches every tag */ + if (entry->tag == SC_ASN1_TAG_ANY) { + if ((p[0] & 0x1F) != 0x1F) { + // one octet tag + entry->tag = p[0] & 0x1F; + } else { + // multi octet tag + if (len == 1) + SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_ASN1, SC_ERROR_INVALID_ASN1_OBJECT); + + int i = 1; + entry->tag = 0; + while ((i < len - 1) && (i < 3) && (p[i] & 0x80)) { + entry->tag |= p[i] & 0x7F; + entry->tag <<= 7; + i++; + } + entry->tag |= p[i]; + } + + if (p[0] & SC_ASN1_TAG_CONTEXT) + entry->tag |= SC_ASN1_CTX; + if (p[0] & SC_ASN1_TAG_APPLICATION) + entry->tag |= SC_ASN1_APP; + if (p[0] & SC_ASN1_TAG_CONSTRUCTED) + entry->tag |= SC_ASN1_CONS; + } + obj = sc_asn1_skip_tag(ctx, &p, &left, entry->tag, &objlen); if (obj == NULL) { sc_debug(ctx, SC_LOG_DEBUG_ASN1, "not present\n"); Index: src/libopensc/asn1.h =================================================================== --- src/libopensc/asn1.h (revision 4798) +++ src/libopensc/asn1.h (working copy) @@ -145,6 +145,7 @@ #define SC_ASN1_STRUCT 129 #define SC_ASN1_CHOICE 130 #define SC_ASN1_BIT_FIELD 131 /* bit string as integer */ +#define SC_ASN1_TLV 132 /* 'complex' structures */ #define SC_ASN1_PATH 256 @@ -165,7 +166,7 @@ #define SC_ASN1_TAG_CONSTRUCTED 0x20 #define SC_ASN1_TAG_PRIMITIVE 0x1F -#define SC_ASN1_TAG_EOC 0 +#define SC_ASN1_TAG_ANY 0 #define SC_ASN1_TAG_BOOLEAN 1 #define SC_ASN1_TAG_INTEGER 2 #define SC_ASN1_TAG_BIT_STRING 3
#include <stdio.h> #include <stdlib.h> #include "libopensc/asn1.h" #include "libopensc/pkcs15.h" int sc_x509_decode_SubjectPublicKeyInfo(sc_pkcs15_der_t SubjectPublicKeyInfo, // type sc_pkcs15_der_t *algorithm, // attribute 1 sc_pkcs15_der_t *subjectPublicKey) // attribute 2 { sc_context_t *ctx = NULL; int r; r = sc_context_create(&ctx, NULL); if (r != SC_SUCCESS) return r; struct sc_asn1_entry DEF_SubjectPublicKeyInfo[] = { { "algorithm", SC_ASN1_TLV, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, SC_ASN1_ALLOC, &algorithm->value, &algorithm->len }, { "subjectPublicKey", SC_ASN1_TLV, SC_ASN1_TAG_BIT_STRING, SC_ASN1_ALLOC, &subjectPublicKey->value, &subjectPublicKey->len }, { NULL, 0, 0, 0, NULL, NULL } }; struct sc_asn1_entry asn1_SubjectPublicKeyInfo[] = { { "", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, 0, DEF_SubjectPublicKeyInfo, NULL}, { NULL, 0, 0, 0, NULL, NULL } }; return sc_asn1_decode(ctx,asn1_SubjectPublicKeyInfo,SubjectPublicKeyInfo.value,SubjectPublicKeyInfo.len,NULL,NULL); } int sc_x509_decode_AlgorithmIdentifier(sc_pkcs15_der_t AlgorithmIdentifier, // type sc_pkcs15_der_t *algorithm, // attribute 1 sc_pkcs15_der_t *parameters) // attribute 2 { sc_context_t *ctx = NULL; int r; r = sc_context_create(&ctx, NULL); if (r != SC_SUCCESS) return r; struct sc_asn1_entry DEF_AlgorithmIdentifier[] = { { "algorithm", SC_ASN1_TLV, SC_ASN1_TAG_OBJECT, SC_ASN1_ALLOC, &algorithm->value, &algorithm->len }, { "parameters", SC_ASN1_TLV, SC_ASN1_TAG_ANY, SC_ASN1_ALLOC | SC_ASN1_OPTIONAL, ¶meters->value, ¶meters->len }, { NULL, 0, 0, 0, NULL, NULL }, }; struct sc_asn1_entry asn1_AlgorithmIdentifier[] = { { "", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, 0, DEF_AlgorithmIdentifier, NULL }, { NULL, 0, 0, 0, NULL, NULL }, }; r = sc_asn1_decode(ctx,asn1_AlgorithmIdentifier,AlgorithmIdentifier.value,AlgorithmIdentifier.len,NULL,NULL); if (r == SC_SUCCESS && (DEF_AlgorithmIdentifier[1].flags & SC_ASN1_PRESENT) == 0) parameters->len = 0; return r; } int main(int argc, char **argv) { int BUF_LEN = 16 * 1024, r; u8 buf[BUF_LEN]; sc_context_t *ctx = NULL; sc_card_t *card = calloc(1, sizeof(sc_card_t)); sc_pkcs15_card_t *p15card = calloc(1, sizeof(sc_pkcs15_card_t)); sc_pkcs15_cert_t *cert = NULL; sc_pkcs15_cert_info_t *cert_info = calloc(1, sizeof(sc_pkcs15_cert_info_t)); sc_pkcs15_der_t SubjectPublicKeyInfo, AlgorithmIdentifier, algorithm, parameters, subjectPublicKey; size_t len; if (sc_context_create(&ctx, NULL) != SC_SUCCESS) return 1; card->ctx = ctx; p15card->card = card; len = fread(buf, 1, BUF_LEN, stdin); printf("len: %d\n\n", len); cert_info->value.value = buf; cert_info->value.len = len; sc_pkcs15_read_certificate(p15card, cert_info, &cert); /* SubjectPublicKeyInfo ::= SEQUENCE { * algorithm AlgorithmIdentifier, * subjectPublicKey BIT STRING } * * AlgorithmIdentifier ::= SEQUENCE { * algorithm OBJECT IDENTIFIER, * parameters ANY DEFINED BY algorithm OPTIONAL } */ SubjectPublicKeyInfo = cert->subjectPublicKeyInfo; // begin parsing at SubjectPublicKeyInfo // (also could be TBSCertificate or Certificate) r = sc_x509_decode_SubjectPublicKeyInfo(SubjectPublicKeyInfo, &AlgorithmIdentifier, &subjectPublicKey); if (r != SC_SUCCESS) { printf("ERROR on SubjectPublicKeyInfo: %d\n", r); return 1; } r = sc_x509_decode_AlgorithmIdentifier(AlgorithmIdentifier, &algorithm, ¶meters); if (r != SC_SUCCESS) { printf("ERROR on AlgorithmIdentifier: %d\n", r); return 1; } // sc_hex_dump(ctx, 0, SubjectPublicKeyInfo.value, SubjectPublicKeyInfo.len, buf, BUF_LEN); // printf("subjectPublicKeyInfo:\n%s\n", buf); sc_hex_dump(ctx, 0, algorithm.value, algorithm.len, buf, BUF_LEN); printf("algorithm:\n%s\n", buf); sc_hex_dump(ctx, 0, parameters.value, parameters.len, buf, BUF_LEN); printf("parameters:\n%s\n", buf); sc_hex_dump(ctx, 0, subjectPublicKey.value, subjectPublicKey.len, buf, BUF_LEN); printf("subjectPublicKey:\n%s\n", buf); // sc_hex_dump(ctx, 0, cert->extensions.value, cert->extensions.len, buf, BUF_LEN); // printf("extensions:\n%s\n", buf); return 0; }
_______________________________________________ opensc-devel mailing list opensc-devel@lists.opensc-project.org http://www.opensc-project.org/mailman/listinfo/opensc-devel