[esnacc-dev] [RFC PATCH 3/4] cxx/asn-int: fix integer encoding/decoding
Aaron Conole
aconole at bytheb.org
Tue Aug 7 17:36:56 UTC 2018
This code was poorly written and broken by previous refactoring of the
integer class.
Signed-off-by: Aaron Conole <aconole at redhat.com>
---
cxx-lib/src/asn-int.cpp | 115 +++++++++++++++++++++++++++++-------------------
1 file changed, 69 insertions(+), 46 deletions(-)
diff --git a/cxx-lib/src/asn-int.cpp b/cxx-lib/src/asn-int.cpp
index e0c210b..25fbe3b 100644
--- a/cxx-lib/src/asn-int.cpp
+++ b/cxx-lib/src/asn-int.cpp
@@ -119,11 +119,17 @@ void AsnInt::BDecContent (const AsnBuf &b, AsnTag, AsnLen elmtLen,
if (elmtLen == INDEFINITE_LEN)
throw EXCEPT("indefinite length on primitive", DECODE_ERROR);
- delete[] m_bytes;
- m_bytes = new unsigned char[elmtLen + 1];
- m_len = elmtLen;
- b.GetSeg((char *)m_bytes, elmtLen);
+ unsigned char *bytes = new unsigned char[elmtLen];
+
+ bool isNeg = false;
+ b.GetSeg((char *)bytes, elmtLen);
bytesDecoded += elmtLen;
+
+ if ((bytes[0] & 0x80)) {
+ isNeg = true;
+ }
+
+ storeDERInteger(bytes, elmtLen, !isNeg);
}
AsnInt::AsnInt (const AsnInt &that)
@@ -183,19 +189,32 @@ AsnInt::AsnInt(const char *str, bool unsignedFlag)
radix = 16;
}
- AsnIntType t;
+
if (unsignedFlag) {
- t = strtoul(useStr, &errstr, radix);
+ unsigned char s[sizeof(AsnUIntType)];
+ AsnUIntType t = strtoul(useStr, &errstr, radix);
+ size_t l = sizeof(t) - 1;
+ for (length = 0; length < sizeof(t); ++length)
+ s[l-length] = (unsigned char)((t >> (8*length)) & 0xff);
+ storeDERInteger(s, sizeof(s), true);
} else {
- t = strtol(useStr, &errstr, radix);
+ unsigned char s[sizeof(AsnIntType)];
+ AsnIntType t = strtol(useStr, &errstr, radix);
+ size_t l = sizeof(t) - 1;
+ for (length = 0; length < sizeof(t); ++length)
+ s[l-length] = (unsigned char)((t >> (8*length)) & 0xff);
+ storeDERInteger(s, sizeof(s), (t >= 0));
}
if ((errstr && *errstr == '\0') ||
!errstr ||
- (*errstr == '\'' && radix == 16))
- Set(t);
-
- throw EXCEPT("UNKNOWN INPUT BYTES.", INTEGER_ERROR);
+ (*errstr == '\'' && radix == 16)) {
+ ; /* the set happens in the prior blocks. */
+ } else {
+ char s[512];
+ snprintf(s, 512, "Invalid bytes: %s", errstr);
+ throw EXCEPT(strdup(s), INTEGER_ERROR);
+ }
}
AsnInt::~AsnInt()
@@ -207,6 +226,7 @@ void AsnInt::storeDERInteger(const unsigned char *pData, long dataLen, bool unsi
{
m_len = 0;
delete [] m_bytes;
+ m_bytes = 0;
/* IF the application generates an r,s,p,q,g or y value in which the
* first 9 bits are all set to 0, then the encoding software deletes the
@@ -216,12 +236,11 @@ void AsnInt::storeDERInteger(const unsigned char *pData, long dataLen, bool unsi
*/
if (unsignedFlag) {
// Check for leading nine bits all zero
- if (dataLen > 1) {
- while (dataLen > 1 && !((pData[0] & 0xFF) || (pData[1] & 0x80))) {
+ while (dataLen > 1 && (pData[0] & 0xFF) == 0x00 &&
+ (pData[1] & 0x80) == 0x0) {
++pData;
--dataLen;
}
- }
m_bytes = new unsigned char[dataLen + 1];
m_len = dataLen;
@@ -230,13 +249,15 @@ void AsnInt::storeDERInteger(const unsigned char *pData, long dataLen, bool unsi
* MSB is set to 1, THEN the software prepends a single octet in which
* all bits are set to 0.
*/
+ unsigned char *cwrite = m_bytes;
if (*pData & 0x80) {
// Prepend a leading octet
- memcpy(m_bytes + 1, pData, dataLen);
- *m_bytes = '\0';
+ *m_bytes = 0;
m_len++;
- } else
- memcpy(m_bytes, pData, dataLen);
+ cwrite++;
+ }
+ memcpy(cwrite, pData, dataLen);
+
} else if (dataLen > 1 ) {
/* check for first first 9 bits all ones
@@ -245,16 +266,20 @@ void AsnInt::storeDERInteger(const unsigned char *pData, long dataLen, bool unsi
++pData;
--dataLen;
}
-
+
/* check for first 9 bits all zeros
*/
while ((dataLen > 1) && (pData[0] == 0) && ((pData[1] & 0x80) == 0)) {
- ++pData;
- --dataLen;
- }
+ ++pData;
+ --dataLen;
+ }
m_bytes = new unsigned char[dataLen + 1];
m_len = dataLen;
memcpy(m_bytes, pData, dataLen);
+ } else {
+ m_bytes = new unsigned char [1];
+ m_len = 1;
+ m_bytes[0] = *pData;
}
}
@@ -278,16 +303,21 @@ void AsnInt::Set (const unsigned char *pData, size_t len, bool unsignedFlag)
storeDERInteger(pData, len, unsignedFlag);
}
+template <class T>
+void endswap(T *objp)
+{
+ unsigned char *memp = reinterpret_cast<unsigned char*>(objp);
+ std::reverse(memp, memp + sizeof(T));
+}
+
// Set AsnInt from a AsnIntType
//
void AsnInt::Set(AsnIntType iIn)
{
- AsnIntType iTmp;
unsigned char cTmp[sizeof(iIn)];
- iTmp = iIn;
for (unsigned long i=0; i < sizeof(iIn); i++)
- cTmp[3-i] = (unsigned char)((iTmp >> (8*i)) & 0xff);
+ cTmp[(sizeof(iIn)-1)-i] = (unsigned char)((iIn >> (8*i)) & 0xff);
storeDERInteger(cTmp, sizeof(iIn), (iIn >= 0));
}
@@ -295,7 +325,7 @@ void AsnInt::Set(AsnIntType iIn)
void AsnInt::getPadded(unsigned char *&bigIntDataOut, size_t &bigIntLen,
const size_t padToSize) const
{
- FUNC("AsnInt::GetUnSignedBitExtendedData()");
+ FUNC("AsnInt::GetUnSignedBitExtendedData()");
bigIntLen = m_len;
const unsigned char *bigIntData = m_bytes;
@@ -303,48 +333,41 @@ void AsnInt::getPadded(unsigned char *&bigIntDataOut, size_t &bigIntLen,
/* This is fix to determine if the r,s,p,q,g, or y value is of the correct
* length.
*/
- if (padToSize > 0)
- {
+ if (padToSize > 0) {
/* if bigint length is less than the expected number of octets
* the decoding software ensures that the MSB is 0 and, if so, it
* prepends the appropriate number of octets in which every bit is
* set to 0 to the decoded value to obtain the value supplied to
* Fortezza Card.
*/
- if ( bigIntLen < padToSize )
- {
+ if (bigIntLen < padToSize) {
long prepend = 0;
unsigned char *tmpInt;
prepend = padToSize - bigIntLen;
tmpInt = (unsigned char *) calloc(1, bigIntLen + prepend);
- memset( tmpInt, 0, prepend);
- memcpy( &tmpInt[prepend], bigIntData , bigIntLen);
+ memset(tmpInt, 0, prepend);
+ memcpy(&tmpInt[prepend], bigIntData , bigIntLen);
bigIntDataOut = tmpInt;
bigIntLen += prepend;
- }
+ } else if (bigIntLen > padToSize) {
/* If the encoded values includes an "extra" octet THEN the
* decoding software ensures that every bit in the initial octets is
* set to 0 and, if so, deletes the initial octet from the decoded value
* to obtain the value to be supplied to the Fortezza Card. If the
* extra octet contains a bit set to 1, then an error is reported.
*/
- else if (bigIntLen > padToSize)
- {
- if (bigIntData[0] != 0)
- {
+ if (bigIntData[0] != 0) {
throw EXCEPT("Extra octet is not zero.", INTEGER_ERROR);
- }
- bigIntLen--;
- bigIntDataOut = (unsigned char *) calloc(1, bigIntLen);
- memcpy( &bigIntDataOut[0], &bigIntData[1], bigIntLen);
- }
- else // Exact length.
- {
- bigIntDataOut = (unsigned char *) calloc(1, bigIntLen);
- memcpy( &bigIntDataOut[0], &bigIntData[0], bigIntLen);
+ }
+ bigIntLen--;
+ bigIntDataOut = (unsigned char *) calloc(1, bigIntLen);
+ memcpy( &bigIntDataOut[0], &bigIntData[1], bigIntLen);
+ } else { // Exact length.
+ bigIntDataOut = (unsigned char *) calloc(1, bigIntLen);
+ memcpy( &bigIntDataOut[0], &bigIntData[0], bigIntLen);
}
}
// bigIntData AND bigIntLen contain the results.
--
2.14.3
More information about the dev
mailing list