diff --git a/winpr/include/winpr/asn1.h b/winpr/include/winpr/asn1.h index 2583383e8..1d13b6d14 100644 --- a/winpr/include/winpr/asn1.h +++ b/winpr/include/winpr/asn1.h @@ -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); diff --git a/winpr/libwinpr/utils/asn1/asn1.c b/winpr/libwinpr/utils/asn1/asn1.c index 1cb3c2ae9..07dd72ab2 100644 --- a/winpr/libwinpr/utils/asn1/asn1.c +++ b/winpr/libwinpr/utils/asn1/asn1.c @@ -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); diff --git a/winpr/libwinpr/utils/test/TestASN1.c b/winpr/libwinpr/utils/test/TestASN1.c index 57fce41ba..aec4a4750 100644 --- a/winpr/libwinpr/utils/test/TestASN1.c +++ b/winpr/libwinpr/utils/test/TestASN1.c @@ -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);