20#include <winpr/config.h>
22#include <winpr/asn1.h>
23#include <winpr/wlog.h>
27#define TAG WINPR_TAG("asn1")
36#define MAX_STATIC_ITEMS 50
44 ASN1_CONTAINER_CONTEXT_ONLY,
45 ASN1_CONTAINER_OCTETSTRING,
48typedef struct WinPrAsn1EncContainer WinPrAsn1EncContainer;
50struct WinPrAsn1EncContainer
55 ContainerType containerType;
59struct WinPrAsn1Encoder
61 WinPrAsn1EncodingRule encoding;
65 Asn1Chunk staticChunks[MAX_STATIC_ITEMS];
67 size_t chunksCapacity;
69 WinPrAsn1EncContainer* containers;
70 WinPrAsn1EncContainer staticContainers[MAX_STATIC_ITEMS];
71 size_t freeContainerIndex;
72 size_t containerCapacity;
75#define WINPR_ASSERT_VALID_TAG(t) WINPR_ASSERT((t) < 64)
89 if (octets->data && octets->len > 0)
90 memset(octets->data, 0, octets->len);
91 WinPrAsn1FreeOID(octets);
150WinPrAsn1Encoder* WinPrAsn1Encoder_New(WinPrAsn1EncodingRule encoding)
152 WinPrAsn1Encoder* enc = calloc(1,
sizeof(*enc));
156 enc->encoding = encoding;
157 enc->pool = Stream_New(
nullptr, 1024);
164 enc->containers = &enc->staticContainers[0];
165 enc->chunks = &enc->staticChunks[0];
166 enc->chunksCapacity = MAX_STATIC_ITEMS;
167 enc->freeContainerIndex = 0;
171void WinPrAsn1Encoder_Reset(WinPrAsn1Encoder* enc)
175 enc->freeContainerIndex = 0;
176 enc->freeChunkId = 0;
178 ZeroMemory(enc->chunks,
sizeof(*enc->chunks) * enc->chunksCapacity);
181void WinPrAsn1Encoder_Free(WinPrAsn1Encoder** penc)
184 WinPrAsn1Encoder_FreeNoNull(*penc);
188void WinPrAsn1Encoder_FreeNoNull(WinPrAsn1Encoder* enc)
192 if (enc->containers != &enc->staticContainers[0])
193 free(enc->containers);
195 if (enc->chunks != &enc->staticChunks[0])
198 Stream_Free(enc->pool, TRUE);
203static Asn1Chunk* asn1enc_get_free_chunk(WinPrAsn1Encoder* enc,
size_t chunkSz, BOOL commit,
206 Asn1Chunk* ret =
nullptr;
208 WINPR_ASSERT(chunkSz);
214 size_t lastChunk = enc->freeChunkId ? enc->freeChunkId - 1 : 0;
215 ret = &enc->chunks[lastChunk];
216 if (ret->capacity && ret->capacity == ret->used)
218 if (!Stream_EnsureRemainingCapacity(enc->pool, chunkSz))
221 Stream_Seek(enc->pool, chunkSz);
222 ret->capacity += chunkSz;
223 ret->used += chunkSz;
230 if (enc->freeChunkId == enc->chunksCapacity)
233 Asn1Chunk* src = (enc->chunks != &enc->staticChunks[0]) ? enc->chunks : nullptr;
234 Asn1Chunk* tmp = realloc(src, (enc->chunksCapacity + 10) *
sizeof(*src));
238 if (enc->chunks == &enc->staticChunks[0])
239 memcpy(tmp, &enc->staticChunks[0], enc->chunksCapacity *
sizeof(*src));
241 memset(tmp + enc->freeChunkId, 0,
sizeof(*tmp) * 10);
244 enc->chunksCapacity += 10;
246 if (enc->freeChunkId == enc->chunksCapacity)
249 if (!Stream_EnsureRemainingCapacity(enc->pool, chunkSz))
252 ret = &enc->chunks[enc->freeChunkId];
253 ret->poolOffset = Stream_GetPosition(enc->pool);
254 ret->capacity = chunkSz;
255 ret->used = commit ? chunkSz : 0;
257 *
id = enc->freeChunkId;
260 Stream_Seek(enc->pool, chunkSz);
264static WinPrAsn1EncContainer* asn1enc_get_free_container(WinPrAsn1Encoder* enc,
size_t*
id)
266 WinPrAsn1EncContainer* ret =
nullptr;
269 if (enc->freeContainerIndex == enc->containerCapacity)
272 WinPrAsn1EncContainer* src =
273 (enc->containers != &enc->staticContainers[0]) ? enc->containers : nullptr;
274 WinPrAsn1EncContainer* tmp = realloc(src, (enc->containerCapacity + 10) *
sizeof(*src));
278 if (enc->containers == &enc->staticContainers[0])
279 memcpy(tmp, &enc->staticContainers[0], enc->containerCapacity *
sizeof(*src));
281 enc->containers = tmp;
282 enc->containerCapacity += 10;
284 if (enc->freeContainerIndex == enc->containerCapacity)
287 ret = &enc->containers[enc->freeContainerIndex];
288 *
id = enc->freeContainerIndex;
290 enc->freeContainerIndex++;
294static size_t lenBytes(
size_t len)
300 if (len < (1u << 16))
302 if (len < (1u << 24))
308static void asn1WriteLen(
wStream* s,
size_t len)
312 Stream_Write_UINT8(s, (UINT8)len);
314 else if (len < (1u << 8))
316 Stream_Write_UINT8(s, 0x81);
317 Stream_Write_UINT8(s, (UINT8)len);
319 else if (len < (1u << 16))
321 Stream_Write_UINT8(s, 0x82);
322 Stream_Write_UINT16_BE(s, (UINT16)len);
324 else if (len < (1u << 24))
326 Stream_Write_UINT8(s, 0x83);
327 Stream_Write_UINT24_BE(s, (UINT32)len);
331 WINPR_ASSERT(len <= UINT32_MAX);
332 Stream_Write_UINT8(s, 0x84);
333 Stream_Write_UINT32_BE(s, (UINT32)len);
337static WinPrAsn1EncContainer* getAsn1Container(WinPrAsn1Encoder* enc, ContainerType ctype,
338 WinPrAsn1_tag tag, BOOL contextual,
size_t maxLen)
342 WinPrAsn1EncContainer* container =
nullptr;
344 Asn1Chunk* chunk = asn1enc_get_free_chunk(enc, maxLen, FALSE, &chunkId);
348 container = asn1enc_get_free_container(enc, &ret);
349 container->containerType = ctype;
350 container->tag = tag;
351 container->contextual = contextual;
352 container->headerChunkId = chunkId;
356BOOL WinPrAsn1EncAppContainer(WinPrAsn1Encoder* enc, WinPrAsn1_tagId tagId)
358 WINPR_ASSERT_VALID_TAG(tagId);
359 return getAsn1Container(enc, ASN1_CONTAINER_APP, tagId, FALSE, 6) !=
nullptr;
362BOOL WinPrAsn1EncSeqContainer(WinPrAsn1Encoder* enc)
364 return getAsn1Container(enc, ASN1_CONTAINER_SEQ, 0, FALSE, 6) !=
nullptr;
367BOOL WinPrAsn1EncSetContainer(WinPrAsn1Encoder* enc)
369 return getAsn1Container(enc, ASN1_CONTAINER_SET, 0, FALSE, 6) !=
nullptr;
372BOOL WinPrAsn1EncContextualSeqContainer(WinPrAsn1Encoder* enc, WinPrAsn1_tagId tagId)
374 return getAsn1Container(enc, ASN1_CONTAINER_SEQ, tagId, TRUE, 6 + 6) !=
nullptr;
377BOOL WinPrAsn1EncContextualSetContainer(WinPrAsn1Encoder* enc, WinPrAsn1_tagId tagId)
379 return getAsn1Container(enc, ASN1_CONTAINER_SET, tagId, TRUE, 6 + 6) !=
nullptr;
382BOOL WinPrAsn1EncContextualContainer(WinPrAsn1Encoder* enc, WinPrAsn1_tagId tagId)
384 return getAsn1Container(enc, ASN1_CONTAINER_CONTEXT_ONLY, tagId, TRUE, 6) !=
nullptr;
387BOOL WinPrAsn1EncOctetStringContainer(WinPrAsn1Encoder* enc)
389 return getAsn1Container(enc, ASN1_CONTAINER_OCTETSTRING, 0, FALSE, 6) !=
nullptr;
392BOOL WinPrAsn1EncContextualOctetStringContainer(WinPrAsn1Encoder* enc, WinPrAsn1_tagId tagId)
394 return getAsn1Container(enc, ASN1_CONTAINER_OCTETSTRING, tagId, TRUE, 6 + 6) !=
nullptr;
397size_t WinPrAsn1EncEndContainer(WinPrAsn1Encoder* enc)
401 size_t innerHeaderBytes = 0;
402 size_t outerHeaderBytes = 0;
403 BYTE containerByte = 0;
404 WinPrAsn1EncContainer* container =
nullptr;
405 Asn1Chunk* chunk =
nullptr;
410 WINPR_ASSERT(enc->freeContainerIndex);
413 container = &enc->containers[enc->freeContainerIndex - 1];
415 for (
size_t i = container->headerChunkId + 1; i < enc->freeChunkId; i++)
416 innerLen += enc->chunks[i].used;
419 switch (container->containerType)
421 case ASN1_CONTAINER_SEQ:
422 containerByte = ER_TAG_SEQUENCE;
423 innerHeaderBytes = 1 + lenBytes(innerLen);
425 case ASN1_CONTAINER_SET:
426 containerByte = ER_TAG_SET;
427 innerHeaderBytes = 1 + lenBytes(innerLen);
429 case ASN1_CONTAINER_OCTETSTRING:
430 containerByte = ER_TAG_OCTET_STRING;
431 innerHeaderBytes = 1 + lenBytes(innerLen);
433 case ASN1_CONTAINER_APP:
434 containerByte = ER_TAG_APP | container->tag;
435 innerHeaderBytes = 1 + lenBytes(innerLen);
437 case ASN1_CONTAINER_CONTEXT_ONLY:
438 innerHeaderBytes = 0;
441 WLog_ERR(TAG,
"invalid containerType");
445 outerHeaderBytes = innerHeaderBytes;
446 if (container->contextual)
448 outerHeaderBytes = 1 + lenBytes(innerHeaderBytes + innerLen) + innerHeaderBytes;
453 chunk = &enc->chunks[container->headerChunkId];
454 unused = chunk->capacity - outerHeaderBytes;
455 chunk->poolOffset += unused;
456 chunk->capacity = chunk->used = outerHeaderBytes;
458 Stream_StaticInit(s, Stream_Buffer(enc->pool) + chunk->poolOffset, outerHeaderBytes);
459 if (container->contextual)
461 Stream_Write_UINT8(s, ER_TAG_CONTEXTUAL | container->tag);
462 asn1WriteLen(s, innerHeaderBytes + innerLen);
465 switch (container->containerType)
467 case ASN1_CONTAINER_SEQ:
468 case ASN1_CONTAINER_SET:
469 case ASN1_CONTAINER_OCTETSTRING:
470 case ASN1_CONTAINER_APP:
471 Stream_Write_UINT8(s, containerByte);
472 asn1WriteLen(s, innerLen);
474 case ASN1_CONTAINER_CONTEXT_ONLY:
477 WLog_ERR(TAG,
"invalid containerType");
482 enc->freeContainerIndex--;
483 return outerHeaderBytes + innerLen;
486static BOOL asn1_getWriteStream(WinPrAsn1Encoder* enc,
size_t len,
wStream* s)
488 BYTE* dest =
nullptr;
489 Asn1Chunk* chunk = asn1enc_get_free_chunk(enc, len, TRUE,
nullptr);
493 dest = Stream_Buffer(enc->pool) + chunk->poolOffset + chunk->capacity - len;
494 Stream_StaticInit(s, dest, len);
506 if (!asn1_getWriteStream(enc, c->len, s))
509 Stream_Write(s, c->data, c->len);
513size_t WinPrAsn1EncContextualRawContent(WinPrAsn1Encoder* enc, WinPrAsn1_tagId tagId,
521 WINPR_ASSERT_VALID_TAG(tagId);
523 size_t len = 1 + lenBytes(c->len) + c->len;
524 if (!asn1_getWriteStream(enc, len, s))
527 Stream_Write_UINT8(s, ER_TAG_CONTEXTUAL | tagId);
528 asn1WriteLen(s, c->len);
530 Stream_Write(s, c->data, c->len);
534static size_t asn1IntegerLen(WinPrAsn1_INTEGER value)
536 if (value <= 127 && value >= -128)
538 else if (value <= 32767 && value >= -32768)
544static size_t WinPrAsn1EncIntegerLike(WinPrAsn1Encoder* enc, WinPrAsn1_tag b,
545 WinPrAsn1_INTEGER value)
547 wStream staticS = WINPR_C_ARRAY_INIT;
550 const size_t len = asn1IntegerLen(value);
551 if (!asn1_getWriteStream(enc, 1 + len, s))
554 Stream_Write_UINT8(s, b);
558 Stream_Write_UINT8(s, 1);
559 Stream_Write_INT8(s, (INT8)value);
562 Stream_Write_UINT8(s, 2);
563 Stream_Write_INT16_BE(s, (INT16)value);
566 Stream_Write_UINT8(s, 4);
567 Stream_Write_INT32_BE(s, (INT32)value);
575size_t WinPrAsn1EncInteger(WinPrAsn1Encoder* enc, WinPrAsn1_INTEGER integer)
577 return WinPrAsn1EncIntegerLike(enc, ER_TAG_INTEGER, integer);
580size_t WinPrAsn1EncEnumerated(WinPrAsn1Encoder* enc, WinPrAsn1_ENUMERATED value)
582 return WinPrAsn1EncIntegerLike(enc, ER_TAG_ENUMERATED, value);
585static size_t WinPrAsn1EncContextualIntegerLike(WinPrAsn1Encoder* enc, WinPrAsn1_tag tag,
586 WinPrAsn1_tagId tagId, WinPrAsn1_INTEGER value)
588 wStream staticS = WINPR_C_ARRAY_INIT;
592 WINPR_ASSERT_VALID_TAG(tagId);
594 const size_t len = asn1IntegerLen(value);
595 const size_t outLen = 1 + lenBytes(1 + len) + (1 + len);
596 if (!asn1_getWriteStream(enc, outLen, s))
599 Stream_Write_UINT8(s, ER_TAG_CONTEXTUAL | tagId);
600 asn1WriteLen(s, 1 + len);
602 Stream_Write_UINT8(s, tag);
606 Stream_Write_UINT8(s, 1);
607 Stream_Write_INT8(s, (INT8)value);
610 Stream_Write_UINT8(s, 2);
611 Stream_Write_INT16_BE(s, (INT16)value);
614 Stream_Write_UINT8(s, 4);
615 Stream_Write_INT32_BE(s, value);
623size_t WinPrAsn1EncContextualInteger(WinPrAsn1Encoder* enc, WinPrAsn1_tagId tagId,
624 WinPrAsn1_INTEGER integer)
626 return WinPrAsn1EncContextualIntegerLike(enc, ER_TAG_INTEGER, tagId, integer);
629size_t WinPrAsn1EncContextualEnumerated(WinPrAsn1Encoder* enc, WinPrAsn1_tagId tagId,
630 WinPrAsn1_ENUMERATED value)
632 return WinPrAsn1EncContextualIntegerLike(enc, ER_TAG_ENUMERATED, tagId, value);
635size_t WinPrAsn1EncBoolean(WinPrAsn1Encoder* enc, WinPrAsn1_BOOL b)
640 if (!asn1_getWriteStream(enc, 3, s))
643 Stream_Write_UINT8(s, ER_TAG_BOOLEAN);
644 Stream_Write_UINT8(s, 1);
645 Stream_Write_UINT8(s, b ? 0xff : 0);
650size_t WinPrAsn1EncContextualBoolean(WinPrAsn1Encoder* enc, WinPrAsn1_tagId tagId, WinPrAsn1_BOOL b)
656 WINPR_ASSERT_VALID_TAG(tagId);
658 if (!asn1_getWriteStream(enc, 5, s))
661 Stream_Write_UINT8(s, ER_TAG_CONTEXTUAL | tagId);
662 Stream_Write_UINT8(s, 3);
664 Stream_Write_UINT8(s, ER_TAG_BOOLEAN);
665 Stream_Write_UINT8(s, 1);
666 Stream_Write_UINT8(s, b ? 0xff : 0);
671static size_t WinPrAsn1EncMemoryChunk(WinPrAsn1Encoder* enc, BYTE wireType,
678 WINPR_ASSERT(mchunk);
679 len = 1 + lenBytes(mchunk->len) + mchunk->len;
681 if (!asn1_getWriteStream(enc, len, &s))
684 Stream_Write_UINT8(&s, wireType);
685 asn1WriteLen(&s, mchunk->len);
686 Stream_Write(&s, mchunk->data, mchunk->len);
690size_t WinPrAsn1EncOID(WinPrAsn1Encoder* enc,
const WinPrAsn1_OID* oid)
692 return WinPrAsn1EncMemoryChunk(enc, ER_TAG_OBJECT_IDENTIFIER, oid);
697 return WinPrAsn1EncMemoryChunk(enc, ER_TAG_OCTET_STRING, octetstring);
700size_t WinPrAsn1EncIA5String(WinPrAsn1Encoder* enc, WinPrAsn1_IA5STRING ia5)
704 chunk.data = (BYTE*)ia5;
705 chunk.len = strlen(ia5);
706 return WinPrAsn1EncMemoryChunk(enc, ER_TAG_IA5STRING, &chunk);
709size_t WinPrAsn1EncGeneralString(WinPrAsn1Encoder* enc, WinPrAsn1_STRING str)
713 chunk.data = (BYTE*)str;
714 chunk.len = strlen(str);
715 return WinPrAsn1EncMemoryChunk(enc, ER_TAG_GENERAL_STRING, &chunk);
718static size_t WinPrAsn1EncContextualMemoryChunk(WinPrAsn1Encoder* enc, BYTE wireType,
719 WinPrAsn1_tagId tagId,
727 WINPR_ASSERT_VALID_TAG(tagId);
728 WINPR_ASSERT(mchunk);
729 len = 1 + lenBytes(mchunk->len) + mchunk->len;
731 outLen = 1 + lenBytes(len) + len;
732 if (!asn1_getWriteStream(enc, outLen, &s))
735 Stream_Write_UINT8(&s, ER_TAG_CONTEXTUAL | tagId);
736 asn1WriteLen(&s, len);
738 Stream_Write_UINT8(&s, wireType);
739 asn1WriteLen(&s, mchunk->len);
740 Stream_Write(&s, mchunk->data, mchunk->len);
744size_t WinPrAsn1EncContextualOID(WinPrAsn1Encoder* enc, WinPrAsn1_tagId tagId,
747 return WinPrAsn1EncContextualMemoryChunk(enc, ER_TAG_OBJECT_IDENTIFIER, tagId, oid);
750size_t WinPrAsn1EncContextualOctetString(WinPrAsn1Encoder* enc, WinPrAsn1_tagId tagId,
753 return WinPrAsn1EncContextualMemoryChunk(enc, ER_TAG_OCTET_STRING, tagId, octetstring);
756size_t WinPrAsn1EncContextualIA5String(WinPrAsn1Encoder* enc, WinPrAsn1_tagId tagId,
757 WinPrAsn1_IA5STRING ia5)
761 chunk.data = (BYTE*)ia5;
762 chunk.len = strlen(ia5);
764 return WinPrAsn1EncContextualMemoryChunk(enc, ER_TAG_IA5STRING, tagId, &chunk);
767static void write2digit(
wStream* s, UINT8 v)
769 Stream_Write_UINT8(s,
'0' + (v / 10));
770 Stream_Write_UINT8(s,
'0' + (v % 10));
775 wStream staticS = WINPR_C_ARRAY_INIT;
780 WINPR_ASSERT(utc->year >= 2000);
782 if (!asn1_getWriteStream(enc, 15, s))
785 Stream_Write_UINT8(s, ER_TAG_UTCTIME);
786 Stream_Write_UINT8(s, 13);
788 write2digit(s, (UINT8)(utc->year - 2000));
789 write2digit(s, utc->month);
790 write2digit(s, utc->day);
791 write2digit(s, utc->hour);
792 write2digit(s, utc->minute);
793 write2digit(s, utc->second);
794 Stream_Write_INT8(s, utc->tz);
798size_t WinPrAsn1EncContextualUtcTime(WinPrAsn1Encoder* enc, WinPrAsn1_tagId tagId,
805 WINPR_ASSERT_VALID_TAG(tagId);
807 WINPR_ASSERT(utc->year >= 2000);
808 WINPR_ASSERT(utc->year < 2256);
810 if (!asn1_getWriteStream(enc, 17, s))
813 Stream_Write_UINT8(s, ER_TAG_CONTEXTUAL | tagId);
814 Stream_Write_UINT8(s, 15);
816 Stream_Write_UINT8(s, ER_TAG_UTCTIME);
817 Stream_Write_UINT8(s, 13);
819 write2digit(s, (UINT8)(utc->year - 2000));
820 write2digit(s, utc->month);
821 write2digit(s, utc->day);
822 write2digit(s, utc->hour);
823 write2digit(s, utc->minute);
824 write2digit(s, utc->second);
825 Stream_Write_INT8(s, utc->tz);
830BOOL WinPrAsn1EncStreamSize(WinPrAsn1Encoder* enc,
size_t* s)
832 size_t finalSize = 0;
837 if (enc->freeContainerIndex != 0)
839 WLog_ERR(TAG,
"some container have not been closed");
843 for (
size_t i = 0; i < enc->freeChunkId; i++)
844 finalSize += enc->chunks[i].used;
849BOOL WinPrAsn1EncToStream(WinPrAsn1Encoder* enc,
wStream* s)
851 size_t finalSize = 0;
856 if (!WinPrAsn1EncStreamSize(enc, &finalSize))
859 if (!Stream_EnsureRemainingCapacity(s, finalSize))
862 for (
size_t i = 0; i < enc->freeChunkId; i++)
864 BYTE* src = Stream_Buffer(enc->pool) + enc->chunks[i].poolOffset;
865 Stream_Write(s, src, enc->chunks[i].used);
871void WinPrAsn1Decoder_Init(
WinPrAsn1Decoder* decoder, WinPrAsn1EncodingRule encoding,
874 WINPR_ASSERT(decoder);
875 WINPR_ASSERT(source);
877 decoder->encoding = encoding;
878 memcpy(&decoder->source, source,
sizeof(*source));
881void WinPrAsn1Decoder_InitMem(
WinPrAsn1Decoder* decoder, WinPrAsn1EncodingRule encoding,
882 const BYTE* source,
size_t len)
884 WINPR_ASSERT(decoder);
885 WINPR_ASSERT(source);
887 decoder->encoding = encoding;
888 Stream_StaticConstInit(&decoder->source, source, len);
896 if (Stream_GetRemainingLength(&dec->source) < 1)
898 Stream_Peek(&dec->source, tag, 1);
902static size_t readLen(
wStream* s,
size_t* len, BOOL derCheck)
907 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
910 Stream_Read_UINT8(s, retLen);
915 size_t nBytes = (retLen & 0x7f);
917 if (!Stream_CheckAndLogRequiredLength(TAG, s, nBytes))
921 for (retLen = 0; nBytes; nBytes--)
923 Stream_Read_UINT8(s, tmp);
924 retLen = (retLen << 8) + tmp;
930 if (ret > 1 && retLen < 128)
943 if (Stream_GetRemainingLength(s) < 1)
946 Stream_Read(s, tag, 1);
947 lenBytes = readLen(s, len, (dec->encoding == WINPR_ASN1_DER));
954size_t WinPrAsn1DecReadTagAndLen(
WinPrAsn1Decoder* dec, WinPrAsn1_tag* tag,
size_t* len)
960 return readTagAndLen(dec, &dec->source, tag, len);
963size_t WinPrAsn1DecPeekTagAndLen(
WinPrAsn1Decoder* dec, WinPrAsn1_tag* tag,
size_t* len)
965 wStream staticS = WINPR_C_ARRAY_INIT;
969 wStream* s = Stream_StaticConstInit(&staticS, Stream_ConstPointer(&dec->source),
970 Stream_GetRemainingLength(&dec->source));
971 return readTagAndLen(dec, s, tag, len);
974size_t WinPrAsn1DecReadTagLenValue(
WinPrAsn1Decoder* dec, WinPrAsn1_tag* tag,
size_t* len,
983 ret = readTagAndLen(dec, &dec->source, tag, len);
987 if (!Stream_CheckAndLogRequiredLength(TAG, &dec->source, *len))
990 value->encoding = dec->encoding;
991 Stream_StaticInit(&value->source, Stream_Pointer(&dec->source), *len);
992 Stream_Seek(&dec->source, *len);
996size_t WinPrAsn1DecReadBoolean(
WinPrAsn1Decoder* dec, WinPrAsn1_BOOL* target)
999 WinPrAsn1_tag tag = 0;
1004 WINPR_ASSERT(target);
1006 ret = readTagAndLen(dec, &dec->source, &tag, &len);
1007 if (!ret || tag != ER_TAG_BOOLEAN)
1009 if (Stream_GetRemainingLength(&dec->source) < len || len != 1)
1012 Stream_Read_UINT8(&dec->source, v);
1017static size_t WinPrAsn1DecReadIntegerLike(
WinPrAsn1Decoder* dec, WinPrAsn1_tag expectedTag,
1018 WinPrAsn1_INTEGER* target)
1020 WinPrAsn1_tag tag = 0;
1024 WINPR_ASSERT(target);
1026 size_t ret = readTagAndLen(dec, &dec->source, &tag, &len);
1027 if (!ret || (tag != expectedTag))
1029 if (len == 0 || Stream_GetRemainingLength(&dec->source) < len || (len > 4))
1035 Stream_Read_UINT8(&dec->source, v);
1041 BOOL isNegative = (v & 0x80);
1046 for (
size_t x = 1; x < len; x++)
1048 Stream_Read_UINT8(&dec->source, v);
1053 *target = (WinPrAsn1_INTEGER)uval;
1060size_t WinPrAsn1DecReadInteger(
WinPrAsn1Decoder* dec, WinPrAsn1_INTEGER* target)
1062 return WinPrAsn1DecReadIntegerLike(dec, ER_TAG_INTEGER, target);
1065size_t WinPrAsn1DecReadEnumerated(
WinPrAsn1Decoder* dec, WinPrAsn1_ENUMERATED* target)
1067 return WinPrAsn1DecReadIntegerLike(dec, ER_TAG_ENUMERATED, target);
1070static size_t WinPrAsn1DecReadMemoryChunkLike(
WinPrAsn1Decoder* dec, WinPrAsn1_tag expectedTag,
1073 WinPrAsn1_tag tag = 0;
1078 WINPR_ASSERT(target);
1080 ret = readTagAndLen(dec, &dec->source, &tag, &len);
1081 if (!ret || tag != expectedTag)
1083 if (!Stream_CheckAndLogRequiredLength(TAG, &dec->source, len))
1089 if (allocate && (len > 0))
1091 target->data = malloc(len);
1094 Stream_Read(&dec->source, target->data, len);
1098 target->data = Stream_Pointer(&dec->source);
1099 Stream_Seek(&dec->source, len);
1107 return WinPrAsn1DecReadMemoryChunkLike(dec, ER_TAG_OBJECT_IDENTIFIER,
1114 return WinPrAsn1DecReadMemoryChunkLike(dec, ER_TAG_OCTET_STRING, target, allocate);
1117size_t WinPrAsn1DecReadIA5String(
WinPrAsn1Decoder* dec, WinPrAsn1_IA5STRING* target)
1119 WinPrAsn1_tag tag = 0;
1122 WinPrAsn1_IA5STRING s =
nullptr;
1125 WINPR_ASSERT(target);
1127 ret = readTagAndLen(dec, &dec->source, &tag, &len);
1128 if (!ret || tag != ER_TAG_IA5STRING)
1130 if (!Stream_CheckAndLogRequiredLength(TAG, &dec->source, len))
1135 s = malloc(len + 1);
1138 Stream_Read(&dec->source, s, len);
1144size_t WinPrAsn1DecReadGeneralString(
WinPrAsn1Decoder* dec, WinPrAsn1_STRING* target)
1146 WinPrAsn1_tag tag = 0;
1149 WinPrAsn1_IA5STRING s =
nullptr;
1152 WINPR_ASSERT(target);
1154 ret = readTagAndLen(dec, &dec->source, &tag, &len);
1155 if (!ret || tag != ER_TAG_GENERAL_STRING)
1157 if (!Stream_CheckAndLogRequiredLength(TAG, &dec->source, len))
1162 s = malloc(len + 1);
1165 Stream_Read(&dec->source, s, len);
1171static int read2digits(
wStream* s)
1176 Stream_Read_INT8(s, c);
1177 if (c <
'0' || c >
'9')
1180 ret = (c -
'0') * 10;
1182 Stream_Read_INT8(s, c);
1183 if (c <
'0' || c >
'9')
1192 WinPrAsn1_tag tag = 0;
1200 WINPR_ASSERT(target);
1202 ret = readTagAndLen(dec, &dec->source, &tag, &len);
1203 if (!ret || tag != ER_TAG_UTCTIME)
1205 if (!Stream_CheckAndLogRequiredLength(TAG, &dec->source, len) || len < 12)
1208 Stream_StaticConstInit(s, Stream_ConstPointer(&dec->source), len);
1211 if ((v <= 0) || (v >= UINT16_MAX - 2000))
1213 target->year = (UINT16)(2000 + v);
1216 if ((v <= 0) || (v > UINT8_MAX))
1218 target->month = (UINT8)v;
1221 if ((v <= 0) || (v > UINT8_MAX))
1223 target->day = (UINT8)v;
1226 if ((v <= 0) || (v > UINT8_MAX))
1228 target->hour = (UINT8)v;
1231 if ((v <= 0) || (v > UINT8_MAX))
1233 target->minute = (UINT8)v;
1236 if ((v <= 0) || (v > UINT8_MAX))
1238 target->second = (UINT8)v;
1240 if (Stream_GetRemainingLength(s) >= 1)
1242 Stream_Read_INT8(s, target->tz);
1245 Stream_Seek(&dec->source, len);
1253 WinPrAsn1_tag tag = 0;
1259 ret = readTagAndLen(dec, &dec->source, &tag, &len);
1260 if (!ret || tag != ER_TAG_NULL || len)
1272 ret = readTagAndLen(dec, s, tag, &len);
1273 if (!ret || !Stream_CheckAndLogRequiredLength(TAG, s, len))
1276 target->encoding = dec->encoding;
1277 Stream_StaticConstInit(&target->source, Stream_ConstPointer(s), len);
1278 Stream_Seek(s, len);
1284 WinPrAsn1_tag tag = 0;
1288 WINPR_ASSERT(setDec);
1290 ret = readConstructed(dec, &dec->source, &tag, setDec);
1291 if ((tag & ER_TAG_APP) != ER_TAG_APP)
1294 *tagId = (tag & ER_TAG_MASK);
1300 WinPrAsn1_tag tag = 0;
1304 WINPR_ASSERT(seqDec);
1306 ret = readConstructed(dec, &dec->source, &tag, seqDec);
1307 if (tag != ER_TAG_SEQUENCE)
1315 WinPrAsn1_tag tag = 0;
1319 WINPR_ASSERT(setDec);
1321 ret = readConstructed(dec, &dec->source, &tag, setDec);
1322 if (tag != ER_TAG_SET)
1332 WinPrAsn1_tag ftag = 0;
1334 ret = readConstructed(dec, s, &ftag, ctxtDec);
1338 if ((ftag & ER_TAG_CONTEXTUAL) != ER_TAG_CONTEXTUAL)
1341 *tagId = (ftag & ER_TAG_MASK);
1345size_t WinPrAsn1DecReadContextualTag(
WinPrAsn1Decoder* dec, WinPrAsn1_tagId* tagId,
1349 WINPR_ASSERT(tagId);
1350 WINPR_ASSERT(ctxtDec);
1352 return readContextualTag(dec, &dec->source, tagId, ctxtDec);
1355size_t WinPrAsn1DecPeekContextualTag(
WinPrAsn1Decoder* dec, WinPrAsn1_tagId* tagId,
1361 Stream_StaticConstInit(&staticS, Stream_ConstPointer(&dec->source),
1362 Stream_GetRemainingLength(&dec->source));
1363 return readContextualTag(dec, &staticS, tagId, ctxtDec);
1366static size_t readContextualHeader(
WinPrAsn1Decoder* dec, WinPrAsn1_tagId tagId, BOOL* error,
1369 WinPrAsn1_tag ftag = 0;
1373 WINPR_ASSERT(error);
1374 WINPR_ASSERT(content);
1377 ret = WinPrAsn1DecPeekContextualTag(dec, &ftag, content);
1391size_t WinPrAsn1DecReadContextualBool(
WinPrAsn1Decoder* dec, WinPrAsn1_tagId tagId, BOOL* error,
1392 WinPrAsn1_BOOL* target)
1398 ret = readContextualHeader(dec, tagId, error, &content);
1402 ret2 = WinPrAsn1DecReadBoolean(&content, target);
1409 Stream_Seek(&dec->source, ret);
1413size_t WinPrAsn1DecReadContextualInteger(
WinPrAsn1Decoder* dec, WinPrAsn1_tagId tagId, BOOL* error,
1414 WinPrAsn1_INTEGER* target)
1420 ret = readContextualHeader(dec, tagId, error, &content);
1424 ret2 = WinPrAsn1DecReadInteger(&content, target);
1431 Stream_Seek(&dec->source, ret);
1435size_t WinPrAsn1DecReadContextualOID(
WinPrAsn1Decoder* dec, WinPrAsn1_tagId tagId, BOOL* error,
1442 ret = readContextualHeader(dec, tagId, error, &content);
1446 ret2 = WinPrAsn1DecReadOID(&content, target, allocate);
1453 Stream_Seek(&dec->source, ret);
1457size_t WinPrAsn1DecReadContextualOctetString(
WinPrAsn1Decoder* dec, WinPrAsn1_tagId tagId,
1465 ret = readContextualHeader(dec, tagId, error, &content);
1469 ret2 = WinPrAsn1DecReadOctetString(&content, target, allocate);
1476 Stream_Seek(&dec->source, ret);
1480size_t WinPrAsn1DecReadContextualSequence(
WinPrAsn1Decoder* dec, WinPrAsn1_tagId tagId, BOOL* error,
1487 ret = readContextualHeader(dec, tagId, error, &content);
1491 ret2 = WinPrAsn1DecReadSequence(&content, target);
1498 Stream_Seek(&dec->source, ret);
1504 wStream s = WINPR_C_ARRAY_INIT;
1507 Stream_StaticConstInit(&s, Stream_ConstPointer(&dec->source),
1508 Stream_GetRemainingLength(&dec->source));