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, &parameters->value, &parameters->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, &parameters);
	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

Reply via email to