winpr asn1: fixes and more features

This patches adds support for octet string containers that are used by SPNego
(a subfield is contained in an octet string record).
It also adds a performance test to test reallocations in asn1 encoder.
It fixes reallocation problems for both chunks and containers.
This commit is contained in:
David Fort
2022-07-01 09:24:27 +02:00
committed by akallabeth
parent cbda255dcd
commit bddb71230e
3 changed files with 81 additions and 5 deletions

View File

@@ -154,6 +154,9 @@ extern "C"
WINPR_API BOOL WinPrAsn1EncSetContainer(WinPrAsn1Encoder* enc);
WINPR_API BOOL WinPrAsn1EncContextualSetContainer(WinPrAsn1Encoder* enc, WinPrAsn1_tagId tagId);
WINPR_API BOOL WinPrAsn1EncContextualContainer(WinPrAsn1Encoder* enc, WinPrAsn1_tagId tagId);
WINPR_API BOOL WinPrAsn1EncOctetStringContainer(WinPrAsn1Encoder* enc);
WINPR_API BOOL WinPrAsn1EncContextualOctetStringContainer(WinPrAsn1Encoder* enc,
WinPrAsn1_tagId tagId);
WINPR_API size_t WinPrAsn1EncEndContainer(WinPrAsn1Encoder* enc);
WINPR_API size_t WinPrAsn1EncInteger(WinPrAsn1Encoder* enc, WinPrAsn1_INTEGER integer);

View File

@@ -40,7 +40,8 @@ typedef enum
ASN1_CONTAINER_SEQ,
ASN1_CONTAINER_SET,
ASN1_CONTAINER_APP,
ASN1_CONTAINER_CONTEXT_ONLY
ASN1_CONTAINER_CONTEXT_ONLY,
ASN1_CONTAINER_OCTETSTRING,
} ContainerType;
typedef struct WinPrAsn1EncContainer WinPrAsn1EncContainer;
@@ -228,7 +229,7 @@ static Asn1Chunk* asn1enc_get_free_chunk(WinPrAsn1Encoder* enc, size_t chunkSz,
return NULL;
if (enc->chunks == &enc->staticChunks[0])
memcpy(tmp, src, enc->chunksCapacity * sizeof(*src));
memcpy(tmp, &enc->staticChunks[0], enc->chunksCapacity * sizeof(*src));
else
memset(tmp + enc->freeChunkId, 0, sizeof(*tmp) * 10);
@@ -268,7 +269,7 @@ static WinPrAsn1EncContainer* asn1enc_get_free_container(WinPrAsn1Encoder* enc,
return NULL;
if (enc->containers == &enc->staticContainers[0])
memcpy(tmp, src, enc->containerCapacity * sizeof(*src));
memcpy(tmp, &enc->staticContainers[0], enc->containerCapacity * sizeof(*src));
enc->containers = tmp;
enc->containerCapacity += 10;
@@ -375,6 +376,16 @@ BOOL WinPrAsn1EncContextualContainer(WinPrAsn1Encoder* enc, WinPrAsn1_tagId tagI
return getAsn1Container(enc, ASN1_CONTAINER_CONTEXT_ONLY, tagId, TRUE, 6) != NULL;
}
BOOL WinPrAsn1EncOctetStringContainer(WinPrAsn1Encoder* enc)
{
return getAsn1Container(enc, ASN1_CONTAINER_OCTETSTRING, 0, FALSE, 6) != NULL;
}
BOOL WinPrAsn1EncContextualOctetStringContainer(WinPrAsn1Encoder* enc, WinPrAsn1_tagId tagId)
{
return getAsn1Container(enc, ASN1_CONTAINER_OCTETSTRING, tagId, TRUE, 6 + 6) != NULL;
}
size_t WinPrAsn1EncEndContainer(WinPrAsn1Encoder* enc)
{
size_t innerLen, i, unused;
@@ -405,6 +416,10 @@ size_t WinPrAsn1EncEndContainer(WinPrAsn1Encoder* enc)
containerByte = ER_TAG_SET;
innerHeaderBytes = 1 + lenBytes(innerLen);
break;
case ASN1_CONTAINER_OCTETSTRING:
containerByte = ER_TAG_OCTET_STRING;
innerHeaderBytes = 1 + lenBytes(innerLen);
break;
case ASN1_CONTAINER_APP:
containerByte = ER_TAG_APP | container->tag;
innerHeaderBytes = 1 + lenBytes(innerLen);
@@ -441,6 +456,7 @@ size_t WinPrAsn1EncEndContainer(WinPrAsn1Encoder* enc)
{
case ASN1_CONTAINER_SEQ:
case ASN1_CONTAINER_SET:
case ASN1_CONTAINER_OCTETSTRING:
case ASN1_CONTAINER_APP:
Stream_Write_UINT8(s, containerByte);
asn1WriteLen(s, innerLen);

View File

@@ -137,6 +137,7 @@ static WinPrAsn1_OID oid4 = { sizeof(oid4_val), oid4_val };
int TestASN1Write(int argc, char* argv[])
{
size_t i;
wStream* s = NULL;
size_t expectedOuputSz;
int retCode = 100;
@@ -159,6 +160,9 @@ int TestASN1Write(int argc, char* argv[])
* [6] SEQ (empty)
* [7] UTC time (2016-03-17 16:40:41 UTC)
* [8] IA5String(test)
* [9] OctetString
* SEQ(empty)
*
*/
/* APP(3) */
@@ -240,8 +244,27 @@ int TestASN1Write(int argc, char* argv[])
if (WinPrAsn1EncEndContainer(enc) != 8)
goto out;
/* [9] OctetString
* SEQ(empty)
*/
retCode = 121;
if (!WinPrAsn1EncContextualOctetStringContainer(enc, 9))
goto out;
retCode = 122;
if (!WinPrAsn1EncSeqContainer(enc))
goto out;
retCode = 123;
if (WinPrAsn1EncEndContainer(enc) != 2)
goto out;
retCode = 124;
if (WinPrAsn1EncEndContainer(enc) != 6)
goto out;
/* close APP */
expectedOuputSz = 24 + 6 + 4 + 17 + 8;
expectedOuputSz = 24 + 6 + 4 + 17 + 8 + 6;
retCode = 200;
if (WinPrAsn1EncEndContainer(enc) != expectedOuputSz)
goto out;
@@ -255,9 +278,43 @@ int TestASN1Write(int argc, char* argv[])
retCode = 202;
if (!WinPrAsn1EncToStream(enc, s) || Stream_GetPosition(s) != expectedOuputSz)
goto out;
/* winpr_HexDump("", WLOG_ERROR, Stream_Buffer(s), Stream_GetPosition(s));*/
/*
* let's perform a mini-performance test, where we encode an ASN1 message with a big depth,
* so that we trigger reallocation routines in the encoder. We're gonna encode something like
* SEQ1
* SEQ2
* SEQ3
* ...
* SEQ1000
* INTEGER(2)
*
* As static chunks and containers are 50, a depth of 1000 should be enough
*
*/
WinPrAsn1Encoder_Reset(enc);
retCode = 203;
for (i = 0; i < 1000; i++)
{
if (!WinPrAsn1EncSeqContainer(enc))
goto out;
}
retCode = 204;
if (WinPrAsn1EncInteger(enc, 2) != 3)
goto out;
retCode = 205;
for (i = 0; i < 1000; i++)
{
if (!WinPrAsn1EncEndContainer(enc))
goto out;
}
retCode = 0;
/*winpr_HexDump("", WLOG_ERROR, Stream_Buffer(s), Stream_GetPosition(s));*/
out:
if (s)
Stream_Free(s, TRUE);