From 033a46dd374728a1bd36675f995a00612a98930f Mon Sep 17 00:00:00 2001 From: daniel_peintner Date: Wed, 23 Jan 2019 08:10:50 +0000 Subject: [PATCH] fix: add support for big integer (see X509SerialNumber in ISO1) git-svn-id: https://svn.code.sf.net/p/openv2g/code/trunk@112 d9f2db14-54d0-4bde-b00c-16405c910529 --- src/codec/DecoderChannel.c | 206 ++++++++++++++++++++++++++++- src/codec/DecoderChannel.h | 38 +++++- src/codec/EXITypes.h | 7 +- src/codec/EncoderChannel.c | 87 ++++++++++++ src/codec/EncoderChannel.h | 38 +++++- src/iso1/iso1EXIDatatypes.h | 15 ++- src/iso1/iso1EXIDatatypesDecoder.c | 2 +- src/iso1/iso1EXIDatatypesEncoder.c | 3 +- 8 files changed, 379 insertions(+), 17 deletions(-) diff --git a/src/codec/DecoderChannel.c b/src/codec/DecoderChannel.c index 69732da..3b8b63a 100644 --- a/src/codec/DecoderChannel.c +++ b/src/codec/DecoderChannel.c @@ -167,7 +167,7 @@ int decodeUnsignedInteger(bitstream_t* stream, exi_integer_t* iv) { int decodeUnsignedInteger16(bitstream_t* stream, uint16_t* uint16) { unsigned int mShift = 0; int errn = 0; - uint8_t b; + uint8_t b = 0; *uint16 = 0; do { @@ -190,7 +190,7 @@ int decodeUnsignedInteger32(bitstream_t* stream, uint32_t* uint32) { /* 0XXXXXXX ... 1XXXXXXX 1XXXXXXX */ unsigned int mShift = 0; int errn = 0; - uint8_t b; + uint8_t b = 0; *uint32 = 0; do { @@ -261,7 +261,183 @@ int decodeUnsignedInteger64(bitstream_t* stream, uint64_t* uint64) { return errn; } - + + +void _reverseArray(uint8_t *array, int number) { + int x, t; + number--; + + for(x = 0; x < number; x ++, number --) { + t = array[x]; + array[x] = array[number]; + array[number] = t; + } +} + +/** + * Decode an arbitrary precision non negative integer using a sequence of + * octets. The most significant bit of the last octet is set to zero to + * indicate sequence termination. Only seven bits per octet are used to + * store the integer's value. + */ +int decodeUnsignedIntegerBig(bitstream_t* stream, size_t size, uint8_t* data, size_t* len) { + int errn = 0; + uint8_t b = 0; + unsigned int mShift1 = 0; + unsigned int mShift2 = 0; + unsigned int mShift3 = 0; + unsigned int mShift4 = 0; + unsigned int nBytesRead = 0; + unsigned int nBitsAvailable = 0; + uint64_t uint64_1 = 0; + uint64_t uint64_2 = 0; + uint64_t uint64_3 = 0; + uint64_t uint64_4 = 0; + + *len = 0; + + do { + errn = decode(stream, &b); + nBytesRead++; + nBitsAvailable += 7; + + if(nBytesRead <= 8) { + uint64_1 += ((uint64_t) (b & 127)) << mShift1; + mShift1 += 7; + } else if(nBytesRead <= 16) { + uint64_2 += ((uint64_t) (b & 127)) << mShift2; + mShift2 += 7; + } else if(nBytesRead <= 24) { + uint64_3 += ((uint64_t) (b & 127)) << mShift3; + mShift3 += 7; + } else if(nBytesRead <= 32) { + uint64_4 += ((uint64_t) (b & 127)) << mShift4; + mShift4 += 7; + } else { + return -1; // too large + } + } while (errn == 0 && (b >> 7) == 1); + + // shift actual data into array + if(uint64_4 != 0) { + // 7 octets for uint64_1 + data[(*len)++] = (uint8_t)(uint64_1 & 0xFF); // 1 + uint64_1 >>= 8; + data[(*len)++] = (uint8_t)(uint64_1 & 0xFF); // 2 + uint64_1 >>= 8; + data[(*len)++] = (uint8_t)(uint64_1 & 0xFF); // 3 + uint64_1 >>= 8; + data[(*len)++] = (uint8_t)(uint64_1 & 0xFF); // 4 + uint64_1 >>= 8; + data[(*len)++] = (uint8_t)(uint64_1 & 0xFF); // 5 + uint64_1 >>= 8; + data[(*len)++] = (uint8_t)(uint64_1 & 0xFF); // 6 + uint64_1 >>= 8; + data[(*len)++] = (uint8_t)(uint64_1 & 0xFF); // 7 + + // 7 octets for uint64_2 + data[(*len)++] = (uint8_t)(uint64_2 & 0xFF); // 1 + uint64_2 >>= 8; + data[(*len)++] = (uint8_t)(uint64_2 & 0xFF); // 2 + uint64_2 >>= 8; + data[(*len)++] = (uint8_t)(uint64_2 & 0xFF); // 3 + uint64_2 >>= 8; + data[(*len)++] = (uint8_t)(uint64_2 & 0xFF); // 4 + uint64_2 >>= 8; + data[(*len)++] = (uint8_t)(uint64_2 & 0xFF); // 5 + uint64_2 >>= 8; + data[(*len)++] = (uint8_t)(uint64_2 & 0xFF); // 6 + uint64_2 >>= 8; + data[(*len)++] = (uint8_t)(uint64_2 & 0xFF); // 7 + + // 7 octets for uint64_3 + data[(*len)++] = (uint8_t)(uint64_3 & 0xFF); // 1 + uint64_3 >>= 8; + data[(*len)++] = (uint8_t)(uint64_3 & 0xFF); // 2 + uint64_3 >>= 8; + data[(*len)++] = (uint8_t)(uint64_3 & 0xFF); // 3 + uint64_3 >>= 8; + data[(*len)++] = (uint8_t)(uint64_3 & 0xFF); // 4 + uint64_3 >>= 8; + data[(*len)++] = (uint8_t)(uint64_3 & 0xFF); // 5 + uint64_3 >>= 8; + data[(*len)++] = (uint8_t)(uint64_3 & 0xFF); // 6 + uint64_3 >>= 8; + data[(*len)++] = (uint8_t)(uint64_3 & 0xFF); // 7 + + // remaining octets of uint64_4 + while (uint64_4 != 0 && errn == 0) { + data[(*len)++] = uint64_4 & 0xFF; + uint64_4 >>= 8; + } + } else if(uint64_3 != 0) { + // 7 octets for uint64_1 + data[(*len)++] = (uint8_t)(uint64_1 & 0xFF); // 1 + uint64_1 >>= 8; + data[(*len)++] = (uint8_t)(uint64_1 & 0xFF); // 2 + uint64_1 >>= 8; + data[(*len)++] = (uint8_t)(uint64_1 & 0xFF); // 3 + uint64_1 >>= 8; + data[(*len)++] = (uint8_t)(uint64_1 & 0xFF); // 4 + uint64_1 >>= 8; + data[(*len)++] = (uint8_t)(uint64_1 & 0xFF); // 5 + uint64_1 >>= 8; + data[(*len)++] = (uint8_t)(uint64_1 & 0xFF); // 6 + uint64_1 >>= 8; + data[(*len)++] = (uint8_t)(uint64_1 & 0xFF); // 7 + + // 7 octets for uint64_2 + data[(*len)++] = (uint8_t)(uint64_2 & 0xFF); // 1 + uint64_2 >>= 8; + data[(*len)++] = (uint8_t)(uint64_2 & 0xFF); // 2 + uint64_2 >>= 8; + data[(*len)++] = (uint8_t)(uint64_2 & 0xFF); // 3 + uint64_2 >>= 8; + data[(*len)++] = (uint8_t)(uint64_2 & 0xFF); // 4 + uint64_2 >>= 8; + data[(*len)++] = (uint8_t)(uint64_2 & 0xFF); // 5 + uint64_2 >>= 8; + data[(*len)++] = (uint8_t)(uint64_2 & 0xFF); // 6 + uint64_2 >>= 8; + data[(*len)++] = (uint8_t)(uint64_2 & 0xFF); // 7 + + // remaining octets of uint64_3 + while (uint64_3 != 0 && errn == 0) { + data[(*len)++] = uint64_3 & 0xFF; + uint64_3 >>= 8; + } + + } else if(uint64_2 != 0) { + // 7 octets for uint64_1 + data[(*len)++] = (uint8_t)(uint64_1 & 0xFF); // 1 + uint64_1 >>= 8; + data[(*len)++] = (uint8_t)(uint64_1 & 0xFF); // 2 + uint64_1 >>= 8; + data[(*len)++] = (uint8_t)(uint64_1 & 0xFF); // 3 + uint64_1 >>= 8; + data[(*len)++] = (uint8_t)(uint64_1 & 0xFF); // 4 + uint64_1 >>= 8; + data[(*len)++] = (uint8_t)(uint64_1 & 0xFF); // 5 + uint64_1 >>= 8; + data[(*len)++] = (uint8_t)(uint64_1 & 0xFF); // 6 + uint64_1 >>= 8; + data[(*len)++] = (uint8_t)(uint64_1 & 0xFF); // 7 + // remaining octets of uint64_2 + while (uint64_2 != 0 && errn == 0) { + data[(*len)++] = uint64_2 & 0xFF; + uint64_2 >>= 8; + } + } else if(uint64_1 != 0) { + while (uint64_1 != 0 && errn == 0) { + data[(*len)++] = uint64_1 & 0xFF; + uint64_1 >>= 8; + } + } + + _reverseArray(data, *len); + + return errn; +} int decodeInteger(bitstream_t* stream, exi_integer_t* iv) { int b; @@ -353,6 +529,28 @@ int decodeInteger64(bitstream_t* stream, int64_t* int64) { } return errn; +} + +/** + * Decode an arbitrary precision integer using a sign bit followed by a + * sequence of octets. The most significant bit of the last octet is set to + * zero to indicate sequence termination. Only seven bits per octet are used + * to store the integer's value. + */ +int decodeIntegerBig(bitstream_t* stream, int* negative, size_t size, uint8_t* data, size_t* len) { + int errn = decodeBoolean(stream, negative); + + if (errn == 0) { + if (*negative) { + /* For negative values, the Unsigned Integer holds the + * magnitude of the value minus 1 */ + } else { + /* positive */ + } + errn = decodeUnsignedIntegerBig(stream, size, data, len); + } + + return errn; } /** @@ -554,7 +752,7 @@ int decodeBinary(bitstream_t* stream, exi_bytes_t* bytes) { int decodeBytes(bitstream_t* stream, size_t len, uint8_t* data) { unsigned int i; int errn = 0; - uint8_t b; + uint8_t b = 0; for (i = 0; i < len && errn == 0; i++) { errn = decode(stream, &b); diff --git a/src/codec/DecoderChannel.h b/src/codec/DecoderChannel.h index d0bdfb6..41e34f8 100644 --- a/src/codec/DecoderChannel.h +++ b/src/codec/DecoderChannel.h @@ -161,7 +161,24 @@ int decodeUnsignedIntegerSizeT(bitstream_t* stream, size_t* sizeT); * \return Error-Code <> 0 * */ -int decodeUnsignedInteger64(bitstream_t* stream, uint64_t* uint64); +int decodeUnsignedInteger64(bitstream_t* stream, uint64_t* uint64); + +/** + * \brief Decode unsigned integer + * + * Decode an arbitrary precision non negative integer using + * a sequence of octets. The most significant bit of the last + * octet is set to zero to indicate sequence termination. + * Only seven bits per octet are used to store the integer's value. + * + * \param stream Input Stream + * \param size size array + * \param data data array + * \param len length array + * \return Error-Code <> 0 + * + */ +int decodeUnsignedIntegerBig(bitstream_t* stream, size_t size, uint8_t* data, size_t* len); /** @@ -226,7 +243,24 @@ int decodeInteger32(bitstream_t* stream, int32_t* int32); * */ int decodeInteger64(bitstream_t* stream, int64_t* int64); - + +/** + * \brief Decode integer + * + * Decode an arbitrary precision integer using a sign bit + * followed by a sequence of octets. The most significant bit + * of the last octet is set to zero to indicate sequence termination. + * Only seven bits per octet are used to store the integer's value. + * + * \param stream Input Stream + * \param negative negative integer + * \param size size array + * \param data data array + * \param len length array + * \return Error-Code <> 0 + * + */ +int decodeIntegerBig(bitstream_t* stream, int* negative, size_t size, uint8_t* data, size_t* len); /** * \brief Decode float diff --git a/src/codec/EXITypes.h b/src/codec/EXITypes.h index b8a2b45..6a81706 100644 --- a/src/codec/EXITypes.h +++ b/src/codec/EXITypes.h @@ -436,15 +436,10 @@ typedef struct { /** LocalName */ exi_name_entry_t localName; } exi_qname_t; - - + /*TODO Doxygen Documentation */ - - - - /* ==================================== */ /* URI and LocalName Entries */ typedef struct exiNameTablePrepopulated { diff --git a/src/codec/EncoderChannel.c b/src/codec/EncoderChannel.c index d15d52a..00e0305 100644 --- a/src/codec/EncoderChannel.c +++ b/src/codec/EncoderChannel.c @@ -203,6 +203,69 @@ int encodeUnsignedInteger64(bitstream_t* stream, uint64_t n) { } return errn; +} + +void _shiftRight7(uint8_t* buf, int len) { + const int shift = 7; + unsigned char tmp = 0x00, tmp2 = 0x00; + for (int k = 0; k <= len; k++) { + if (k == 0) { + tmp = buf[k]; + buf[k] >>= shift; + } else { + tmp2 = buf[k]; + buf[k] >>= shift; + buf[k] |= ((tmp & 0x7F) << (8 - shift)); + + if (k != len) { + tmp = tmp2; + } + } + } +} + +/** + * Encode an arbitrary precision non negative integer using a sequence of + * octets. The most significant bit of the last octet is set to zero to + * indicate sequence termination. Only seven bits per octet are used to + * store the integer's value. + */ +int encodeUnsignedIntegerBig(bitstream_t* stream, size_t size, uint8_t* data, size_t len) { + int errn = 0; + int i; + int lenM1 = len - 1; + const int MAX_BIGINT_ARRAY = 25; + uint8_t lastEncode = 0; + uint8_t bytesToShift[MAX_BIGINT_ARRAY]; // MAXIMUM + size_t bitsToEncode = len * 8; + + if(MAX_BIGINT_ARRAY <= len) { + return -1; + } + + /* init */ + for(i=0; i 7) { + lastEncode = bytesToShift[lenM1]; + lastEncode = lastEncode | 128; + errn = encode(stream, lastEncode); + _shiftRight7(bytesToShift, len); + bitsToEncode -= 7; + } + + if (errn == 0) { + errn = encode(stream, bytesToShift[lenM1]); + } + + return errn; } int encodeInteger(bitstream_t* stream, exi_integer_t* iv) { @@ -312,6 +375,30 @@ int encodeInteger64(bitstream_t* stream, int64_t n) { errn = encodeUnsignedInteger64(stream, (uint64_t)n); } return errn; +} + + +/** + * Encode an arbitrary precision integer using a sign bit followed by a + * sequence of octets. The most significant bit of the last octet is set to + * zero to indicate sequence termination. Only seven bits per octet are used + * to store the integer's value. + */ +int encodeIntegerBig(bitstream_t* stream, int negative, size_t size, uint8_t* data, size_t len) { + int errn; + /* signalize sign */ + if (negative) { + errn = encodeBoolean(stream, 1); + /* For negative values, the Unsigned Integer holds the + * magnitude of the value minus 1 */ + /* n = (-n) - 1; */ + } else { + errn = encodeBoolean(stream, 0); + } + if (errn == 0) { + errn = encodeUnsignedIntegerBig(stream, size, data, len); + } + return errn; } /** diff --git a/src/codec/EncoderChannel.h b/src/codec/EncoderChannel.h index 9523d5d..762b14a 100644 --- a/src/codec/EncoderChannel.h +++ b/src/codec/EncoderChannel.h @@ -146,7 +146,24 @@ int encodeUnsignedInteger32(bitstream_t* stream, uint32_t n); * \return Error-Code <> 0 * */ -int encodeUnsignedInteger64(bitstream_t* stream, uint64_t n); +int encodeUnsignedInteger64(bitstream_t* stream, uint64_t n); + +/** + * \brief Encode unsigned integer + * + * Encode an arbitrary precision non negative integer using + * a sequence of octets. The most significant bit of the last + * octet is set to zero to indicate sequence termination. + * Only seven bits per octet are used to store the integer's value. + * + * \param stream Output Stream + * \param size size array + * \param data data array + * \param len length array + * \return Error-Code <> 0 + * + */ +int encodeUnsignedIntegerBig(bitstream_t* stream, size_t size, uint8_t* data, size_t len); /** @@ -210,7 +227,24 @@ int encodeInteger32(bitstream_t* stream, int32_t n); * */ int encodeInteger64(bitstream_t* stream, int64_t n); - + +/** + * \brief Encode integer + * + * Encode an arbitrary precision integer using a sign boolean + * followed by a sequence of octets. The most significant bit + * of the last octet is set to zero to indicate sequence termination. + * Only seven bits per octet are used to store the integer's value. + * + * \param stream Output Stream + * \param negative negative integer + * \param size size array + * \param data data array + * \param len length array + * \return Error-Code <> 0 + * + */ +int encodeIntegerBig(bitstream_t* stream, int negative, size_t size, uint8_t* data, size_t len); /** * \brief Encode float diff --git a/src/iso1/iso1EXIDatatypes.h b/src/iso1/iso1EXIDatatypes.h index cc22a45..6fe64a4 100644 --- a/src/iso1/iso1EXIDatatypes.h +++ b/src/iso1/iso1EXIDatatypes.h @@ -464,6 +464,7 @@ struct iso1KeyValueType { /* Complex type name='http://www.w3.org/2000/09/xmldsig#,X509IssuerSerialType', base type name='anyType', content type='ELEMENT', isAbstract='false', hasTypeId='false', final='0', block='0', particle='("http://www.w3.org/2000/09/xmldsig#":X509IssuerName,"http://www.w3.org/2000/09/xmldsig#":X509SerialNumber)', derivedBy='RESTRICTION'. */ #define iso1X509IssuerSerialType_X509IssuerName_CHARACTERS_SIZE 50 + EXTRA_CHAR +uint8_t characters[20]; struct iso1X509IssuerSerialType { /* element: "http://www.w3.org/2000/09/xmldsig#":X509IssuerName, http://www.w3.org/2001/XMLSchema,string */ struct { @@ -471,7 +472,19 @@ struct iso1X509IssuerSerialType { uint16_t charactersLen; } X509IssuerName ; /* element: "http://www.w3.org/2000/09/xmldsig#":X509SerialNumber, http://www.w3.org/2001/XMLSchema,integer */ - int64_t X509SerialNumber ; + /* int64_t X509SerialNumber; */ + struct { + /** a sign value */ + int negative; + /* container size */ + size_t size; + /** array data container */ + /* For negative values, the Unsigned Integer holds the + * magnitude of the value minus 1 */ + uint8_t* data; + /** array length (len <= size) */ + size_t len; + } X509SerialNumber; }; typedef enum { diff --git a/src/iso1/iso1EXIDatatypesDecoder.c b/src/iso1/iso1EXIDatatypesDecoder.c index 9a76ca2..ba4ade9 100644 --- a/src/iso1/iso1EXIDatatypesDecoder.c +++ b/src/iso1/iso1EXIDatatypesDecoder.c @@ -8060,7 +8060,7 @@ static int decode_iso1X509IssuerSerialType(bitstream_t* stream, struct iso1X509I errn = decodeNBitUnsignedInteger(stream, 1, &eventCode); if(errn == 0) { if(eventCode == 0) { - errn = decodeInteger64(stream, &iso1X509IssuerSerialType->X509SerialNumber); + errn = decodeIntegerBig(stream, &iso1X509IssuerSerialType->X509SerialNumber.negative, iso1X509IssuerSerialType->X509SerialNumber.size, iso1X509IssuerSerialType->X509SerialNumber.data, &iso1X509IssuerSerialType->X509SerialNumber.len); } else { /* Second level event (e.g., xsi:type, xsi:nil, ...) */ errn = EXI_UNSUPPORTED_EVENT_CODE_CHARACTERISTICS; diff --git a/src/iso1/iso1EXIDatatypesEncoder.c b/src/iso1/iso1EXIDatatypesEncoder.c index a54ab28..4c2db21 100644 --- a/src/iso1/iso1EXIDatatypesEncoder.c +++ b/src/iso1/iso1EXIDatatypesEncoder.c @@ -5814,7 +5814,8 @@ static int encode_iso1X509IssuerSerialType(bitstream_t* stream, struct iso1X509I /* First(xsi:type)StartTag[CHARACTERS[INTEGER]] */ errn = encodeNBitUnsignedInteger(stream, 1, 0); if(errn == 0) { - errn = encodeInteger64(stream, iso1X509IssuerSerialType->X509SerialNumber); + /* errn = encodeInteger64(stream, iso1X509IssuerSerialType->X509SerialNumber); */ + errn = encodeIntegerBig(stream, iso1X509IssuerSerialType->X509SerialNumber.negative, iso1X509IssuerSerialType->X509SerialNumber.size, iso1X509IssuerSerialType->X509SerialNumber.data, iso1X509IssuerSerialType->X509SerialNumber.len); /* valid EE */ errn = encodeNBitUnsignedInteger(stream, 1, 0); }