Hello, I attached an improved version of my ASN1 test tool. You give a number and the tool displays the encoding and decoding using both the old and new code.
2009/12/13 Andreas Jellinghaus <a...@dungeon.inka.de>: > Am Sonntag 13 Dezember 2009 14:49:31 schrieb Ludovic Rousseau: >> 2009/12/13 Andreas Jellinghaus <a...@dungeon.inka.de>: >> > I tried all four combinations of old/new code for init and for signing. >> > >> > only cards initialized with old code and signing with new code is broken, >> > so we could as quick fix revert the change. >> >> I remember doing this patch. >> The problem was that the ASN.1 encoder/decoder routines were bogus. >> Negative values and "special" values like 128 were not encoded >> correctly. > > can you explain how the encoding rules exactly are? > I saw that the old code encodes 145 = 0x91 as integer as > "02 01 91" (02 = integer tag, 01 = length byte), while the > new code uses "02 02 00 91" (02 = integer tag, 02 = length byte, > 00 91 = value 0x0091 = 145). > > do the encoding rules give us any clue, maybe "91" is an illegal > payload? 0x91 is a legal payload but is the encoding of -111. $ ./asn1 145 converting: 145 (old code) objsize: 1 byte(s) 91 145 (new code -111) converting: 145 (new code) objsize: 2 byte(s) 00 91 145 (old code 145) The 7th bit of the first byte is the sign. The sign bit was not correctly managed by the previous code. $ ./asn1 -1 converting: -1 (old code) objsize: 4 byte(s) FF FF FF FF -1 (new code -1) converting: -1 (new code) objsize: 1 byte(s) FF -1 (old code 255) > or does anyone know if for example keyReference needs to be a > positive integer, so we can run a "fixup" later? > > we would need to check all integer in all asn.1 encodings I fear, > as the same bug could be in all of them. hmm, not possible a grep > shows 36 entries :( > > so I wonder how we can detect the problem and fix it. The problem is that you can't tell (except one case, see bellow) if an encoding is using the old or new encoding without knowing that output values are illegal, like negative values for a keyReference. > worst case: for starcos our "guess" is keyReference should > be positive if it is set, so for every value from -2 to -128 > we could simply add 128. Add 256 instead of 128. $ ./asn1 -2 converting: -2 (old code) objsize: 4 byte(s) FF FF FF FE -2 (new code -2) converting: -2 (new code) objsize: 1 byte(s) FE -2 (old code 254) $ ./asn1 -128 converting: -128 (old code) objsize: 4 byte(s) FF FF FF 80 -128 (new code -128) converting: -128 (new code) objsize: 1 byte(s) 80 -128 (old code 128) $ ./asn1 128 converting: 128 (old code) objsize: 1 byte(s) 80 128 (new code -128) converting: 128 (new code) objsize: 2 byte(s) 00 80 128 (old code 128) $ ./asn1 255 converting: 255 (old code) objsize: 1 byte(s) FF 255 (new code -1) converting: 255 (new code) objsize: 2 byte(s) 00 FF 255 (old code 255) > (I'm no starcos expert, at least I hope that key Reference is > a positive value) > > ah, SPK2.4 manual page 28, dummy values are 000xxxxxb, > real values 100xxxxxb. > > So we can implement a hack for key ID, if we find no generic solution. > > any ideas for a generic one? An encoding on more than 1 byte and starting with 0x00 is using the new/corrected encoder. And it should be correctly decoded by both decoders. On the other cases I don't think you can differentiate the encoding. OpenSC would try to decode using both the old and new code. And decide which values to use using heuristics (like negative values are forbidden) but I guess that will soon be a nightmare to maintain. Sorry for all the problems because of my change. Regards, -- Dr. Ludovic Rousseau
#include <stdio.h> #include <stdlib.h> typedef unsigned char u8; #define SC_ERROR_OUT_OF_MEMORY 1 #define SC_ERROR_INVALID_ASN1_OBJECT 2 u8 OBJ[10]; static int old_sc_asn1_decode_integer(const u8 * inbuf, size_t inlen, int *out) { int a = 0; size_t i; if (inlen > sizeof(int)) return SC_ERROR_INVALID_ASN1_OBJECT; for (i = 0; i < inlen; i++) { a <<= 8; a |= *inbuf++; } *out = a; return 0; } static int old_asn1_encode_integer(int in, u8 ** obj, size_t * objsize) { int i = sizeof(in) * 8, skip = 1; u8 *p, b; *obj = p = (u8 *) malloc(sizeof(in)); if (*obj == NULL) return SC_ERROR_OUT_OF_MEMORY; do { i -= 8; b = in >> i; if (b == 0 && skip) continue; skip = 0; *p++ = b; } while (i > 0); *objsize = p - *obj; if (*objsize == 0) { *objsize = 1; (*obj)[0] = 0; } return 0; } static int sc_asn1_decode_integer(const u8 * inbuf, size_t inlen, int *out) { int a = 0; size_t i; if (inlen > sizeof(int)) return SC_ERROR_INVALID_ASN1_OBJECT; if (inbuf[0] & 0x80) a = -1; for (i = 0; i < inlen; i++) { a <<= 8; a |= *inbuf++; } *out = a; return 0; } static int asn1_encode_integer(int in, u8 ** obj, size_t * objsize) { int i = sizeof(in) * 8, skip_zero, skip_sign; u8 *p, b; if (in < 0) { skip_sign = 1; skip_zero= 0; } else { skip_sign = 0; skip_zero= 1; } *obj = p = (u8 *) malloc(sizeof(in)+1); if (*obj == NULL) return SC_ERROR_OUT_OF_MEMORY; do { i -= 8; b = in >> i; if (skip_sign) { if (b != 0xff) skip_sign = 0; if (b & 0x80) { *p = b; if (0xff == b) continue; } else { p++; skip_sign = 0; } } if (b == 0 && skip_zero) continue; if (skip_zero) { skip_zero = 0; /* prepend 0x00 if MSb is 1 and integer positive */ if ((b & 0x80) != 0 && in > 0) *p++ = 0; } *p++ = b; } while (i > 0); if (skip_sign) p++; *objsize = p - *obj; if (*objsize == 0) { *objsize = 1; (*obj)[0] = 0; } return 0; } int main(int argc, char *argv[]) { u8 *obj; size_t objsize = 0; int i, n; if (argc != 2) { printf("usage: %s integer\n", argv[0]); return -1; } //while(1) { n = atoi(argv[1]); //n = rand(); printf("converting: %d (old code)\n", n); old_asn1_encode_integer(n, &obj, &objsize); printf("objsize: %d byte(s)\n", objsize); for (i=0; i<objsize; i++) printf("%02X ", obj[i]); printf("\n"); old_sc_asn1_decode_integer(obj, objsize, &i); printf("%d ", i); sc_asn1_decode_integer(obj, objsize, &i); printf("(new code %d)\n", i); printf("converting: %d (new code)\n", n); asn1_encode_integer(n, &obj, &objsize); printf("objsize: %d byte(s)\n", objsize); for (i=0; i<objsize; i++) printf("%02X ", obj[i]); printf("\n"); sc_asn1_decode_integer(obj, objsize, &i); printf("%d ", i); old_sc_asn1_decode_integer(obj, objsize, &i); printf("(old code %d)\n", i); #if 0 if (i != n) printf("ERROR %d %d\n", i, n); #endif } return 0; }
_______________________________________________ opensc-devel mailing list opensc-devel@lists.opensc-project.org http://www.opensc-project.org/mailman/listinfo/opensc-devel