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)
87 WinPrAsn1FreeOID(octets);
146WinPrAsn1Encoder* WinPrAsn1Encoder_New(WinPrAsn1EncodingRule encoding)
148 WinPrAsn1Encoder* enc = calloc(1,
sizeof(*enc));
152 enc->encoding = encoding;
153 enc->pool = Stream_New(
nullptr, 1024);
160 enc->containers = &enc->staticContainers[0];
161 enc->chunks = &enc->staticChunks[0];
162 enc->chunksCapacity = MAX_STATIC_ITEMS;
163 enc->freeContainerIndex = 0;
167void WinPrAsn1Encoder_Reset(WinPrAsn1Encoder* enc)
171 enc->freeContainerIndex = 0;
172 enc->freeChunkId = 0;
174 ZeroMemory(enc->chunks,
sizeof(*enc->chunks) * enc->chunksCapacity);
177void WinPrAsn1Encoder_Free(WinPrAsn1Encoder** penc)
180 WinPrAsn1Encoder_FreeNoNull(*penc);
184void WinPrAsn1Encoder_FreeNoNull(WinPrAsn1Encoder* enc)
188 if (enc->containers != &enc->staticContainers[0])
189 free(enc->containers);
191 if (enc->chunks != &enc->staticChunks[0])
194 Stream_Free(enc->pool, TRUE);
199static Asn1Chunk* asn1enc_get_free_chunk(WinPrAsn1Encoder* enc,
size_t chunkSz, BOOL commit,
202 Asn1Chunk* ret =
nullptr;
204 WINPR_ASSERT(chunkSz);
210 size_t lastChunk = enc->freeChunkId ? enc->freeChunkId - 1 : 0;
211 ret = &enc->chunks[lastChunk];
212 if (ret->capacity && ret->capacity == ret->used)
214 if (!Stream_EnsureRemainingCapacity(enc->pool, chunkSz))
217 Stream_Seek(enc->pool, chunkSz);
218 ret->capacity += chunkSz;
219 ret->used += chunkSz;
226 if (enc->freeChunkId == enc->chunksCapacity)
229 Asn1Chunk* src = (enc->chunks != &enc->staticChunks[0]) ? enc->chunks : nullptr;
230 Asn1Chunk* tmp = realloc(src, (enc->chunksCapacity + 10) *
sizeof(*src));
234 if (enc->chunks == &enc->staticChunks[0])
235 memcpy(tmp, &enc->staticChunks[0], enc->chunksCapacity *
sizeof(*src));
237 memset(tmp + enc->freeChunkId, 0,
sizeof(*tmp) * 10);
240 enc->chunksCapacity += 10;
242 if (enc->freeChunkId == enc->chunksCapacity)
245 if (!Stream_EnsureRemainingCapacity(enc->pool, chunkSz))
248 ret = &enc->chunks[enc->freeChunkId];
249 ret->poolOffset = Stream_GetPosition(enc->pool);
250 ret->capacity = chunkSz;
251 ret->used = commit ? chunkSz : 0;
253 *
id = enc->freeChunkId;
256 Stream_Seek(enc->pool, chunkSz);
260static WinPrAsn1EncContainer* asn1enc_get_free_container(WinPrAsn1Encoder* enc,
size_t*
id)
262 WinPrAsn1EncContainer* ret =
nullptr;
265 if (enc->freeContainerIndex == enc->containerCapacity)
268 WinPrAsn1EncContainer* src =
269 (enc->containers != &enc->staticContainers[0]) ? enc->containers : nullptr;
270 WinPrAsn1EncContainer* tmp = realloc(src, (enc->containerCapacity + 10) *
sizeof(*src));
274 if (enc->containers == &enc->staticContainers[0])
275 memcpy(tmp, &enc->staticContainers[0], enc->containerCapacity *
sizeof(*src));
277 enc->containers = tmp;
278 enc->containerCapacity += 10;
280 if (enc->freeContainerIndex == enc->containerCapacity)
283 ret = &enc->containers[enc->freeContainerIndex];
284 *
id = enc->freeContainerIndex;
286 enc->freeContainerIndex++;
290static size_t lenBytes(
size_t len)
304static void asn1WriteLen(
wStream* s,
size_t len)
308 Stream_Write_UINT8(s, (UINT8)len);
310 else if (len < (1 << 8))
312 Stream_Write_UINT8(s, 0x81);
313 Stream_Write_UINT8(s, (UINT8)len);
315 else if (len < (1 << 16))
317 Stream_Write_UINT8(s, 0x82);
318 Stream_Write_UINT16_BE(s, (UINT16)len);
320 else if (len < (1 << 24))
322 Stream_Write_UINT8(s, 0x83);
323 Stream_Write_UINT24_BE(s, (UINT32)len);
327 WINPR_ASSERT(len <= UINT32_MAX);
328 Stream_Write_UINT8(s, 0x84);
329 Stream_Write_UINT32_BE(s, (UINT32)len);
333static WinPrAsn1EncContainer* getAsn1Container(WinPrAsn1Encoder* enc, ContainerType ctype,
334 WinPrAsn1_tag tag, BOOL contextual,
size_t maxLen)
338 WinPrAsn1EncContainer* container =
nullptr;
340 Asn1Chunk* chunk = asn1enc_get_free_chunk(enc, maxLen, FALSE, &chunkId);
344 container = asn1enc_get_free_container(enc, &ret);
345 container->containerType = ctype;
346 container->tag = tag;
347 container->contextual = contextual;
348 container->headerChunkId = chunkId;
352BOOL WinPrAsn1EncAppContainer(WinPrAsn1Encoder* enc, WinPrAsn1_tagId tagId)
354 WINPR_ASSERT_VALID_TAG(tagId);
355 return getAsn1Container(enc, ASN1_CONTAINER_APP, tagId, FALSE, 6) !=
nullptr;
358BOOL WinPrAsn1EncSeqContainer(WinPrAsn1Encoder* enc)
360 return getAsn1Container(enc, ASN1_CONTAINER_SEQ, 0, FALSE, 6) !=
nullptr;
363BOOL WinPrAsn1EncSetContainer(WinPrAsn1Encoder* enc)
365 return getAsn1Container(enc, ASN1_CONTAINER_SET, 0, FALSE, 6) !=
nullptr;
368BOOL WinPrAsn1EncContextualSeqContainer(WinPrAsn1Encoder* enc, WinPrAsn1_tagId tagId)
370 return getAsn1Container(enc, ASN1_CONTAINER_SEQ, tagId, TRUE, 6 + 6) !=
nullptr;
373BOOL WinPrAsn1EncContextualSetContainer(WinPrAsn1Encoder* enc, WinPrAsn1_tagId tagId)
375 return getAsn1Container(enc, ASN1_CONTAINER_SET, tagId, TRUE, 6 + 6) !=
nullptr;
378BOOL WinPrAsn1EncContextualContainer(WinPrAsn1Encoder* enc, WinPrAsn1_tagId tagId)
380 return getAsn1Container(enc, ASN1_CONTAINER_CONTEXT_ONLY, tagId, TRUE, 6) !=
nullptr;
383BOOL WinPrAsn1EncOctetStringContainer(WinPrAsn1Encoder* enc)
385 return getAsn1Container(enc, ASN1_CONTAINER_OCTETSTRING, 0, FALSE, 6) !=
nullptr;
388BOOL WinPrAsn1EncContextualOctetStringContainer(WinPrAsn1Encoder* enc, WinPrAsn1_tagId tagId)
390 return getAsn1Container(enc, ASN1_CONTAINER_OCTETSTRING, tagId, TRUE, 6 + 6) !=
nullptr;
393size_t WinPrAsn1EncEndContainer(WinPrAsn1Encoder* enc)
397 size_t innerHeaderBytes = 0;
398 size_t outerHeaderBytes = 0;
399 BYTE containerByte = 0;
400 WinPrAsn1EncContainer* container =
nullptr;
401 Asn1Chunk* chunk =
nullptr;
406 WINPR_ASSERT(enc->freeContainerIndex);
409 container = &enc->containers[enc->freeContainerIndex - 1];
411 for (
size_t i = container->headerChunkId + 1; i < enc->freeChunkId; i++)
412 innerLen += enc->chunks[i].used;
415 switch (container->containerType)
417 case ASN1_CONTAINER_SEQ:
418 containerByte = ER_TAG_SEQUENCE;
419 innerHeaderBytes = 1 + lenBytes(innerLen);
421 case ASN1_CONTAINER_SET:
422 containerByte = ER_TAG_SET;
423 innerHeaderBytes = 1 + lenBytes(innerLen);
425 case ASN1_CONTAINER_OCTETSTRING:
426 containerByte = ER_TAG_OCTET_STRING;
427 innerHeaderBytes = 1 + lenBytes(innerLen);
429 case ASN1_CONTAINER_APP:
430 containerByte = ER_TAG_APP | container->tag;
431 innerHeaderBytes = 1 + lenBytes(innerLen);
433 case ASN1_CONTAINER_CONTEXT_ONLY:
434 innerHeaderBytes = 0;
437 WLog_ERR(TAG,
"invalid containerType");
441 outerHeaderBytes = innerHeaderBytes;
442 if (container->contextual)
444 outerHeaderBytes = 1 + lenBytes(innerHeaderBytes + innerLen) + innerHeaderBytes;
449 chunk = &enc->chunks[container->headerChunkId];
450 unused = chunk->capacity - outerHeaderBytes;
451 chunk->poolOffset += unused;
452 chunk->capacity = chunk->used = outerHeaderBytes;
454 Stream_StaticInit(s, Stream_Buffer(enc->pool) + chunk->poolOffset, outerHeaderBytes);
455 if (container->contextual)
457 Stream_Write_UINT8(s, ER_TAG_CONTEXTUAL | container->tag);
458 asn1WriteLen(s, innerHeaderBytes + innerLen);
461 switch (container->containerType)
463 case ASN1_CONTAINER_SEQ:
464 case ASN1_CONTAINER_SET:
465 case ASN1_CONTAINER_OCTETSTRING:
466 case ASN1_CONTAINER_APP:
467 Stream_Write_UINT8(s, containerByte);
468 asn1WriteLen(s, innerLen);
470 case ASN1_CONTAINER_CONTEXT_ONLY:
473 WLog_ERR(TAG,
"invalid containerType");
478 enc->freeContainerIndex--;
479 return outerHeaderBytes + innerLen;
482static BOOL asn1_getWriteStream(WinPrAsn1Encoder* enc,
size_t len,
wStream* s)
484 BYTE* dest =
nullptr;
485 Asn1Chunk* chunk = asn1enc_get_free_chunk(enc, len, TRUE,
nullptr);
489 dest = Stream_Buffer(enc->pool) + chunk->poolOffset + chunk->capacity - len;
490 Stream_StaticInit(s, dest, len);
502 if (!asn1_getWriteStream(enc, c->len, s))
505 Stream_Write(s, c->data, c->len);
509size_t WinPrAsn1EncContextualRawContent(WinPrAsn1Encoder* enc, WinPrAsn1_tagId tagId,
517 WINPR_ASSERT_VALID_TAG(tagId);
519 size_t len = 1 + lenBytes(c->len) + c->len;
520 if (!asn1_getWriteStream(enc, len, s))
523 Stream_Write_UINT8(s, ER_TAG_CONTEXTUAL | tagId);
524 asn1WriteLen(s, c->len);
526 Stream_Write(s, c->data, c->len);
530static size_t asn1IntegerLen(WinPrAsn1_INTEGER value)
532 if (value <= 127 && value >= -128)
534 else if (value <= 32767 && value >= -32768)
540static size_t WinPrAsn1EncIntegerLike(WinPrAsn1Encoder* enc, WinPrAsn1_tag b,
541 WinPrAsn1_INTEGER value)
543 wStream staticS = WINPR_C_ARRAY_INIT;
546 const size_t len = asn1IntegerLen(value);
547 if (!asn1_getWriteStream(enc, 1 + len, s))
550 Stream_Write_UINT8(s, b);
554 Stream_Write_UINT8(s, 1);
555 Stream_Write_INT8(s, (INT8)value);
558 Stream_Write_UINT8(s, 2);
559 Stream_Write_INT16_BE(s, (INT16)value);
562 Stream_Write_UINT8(s, 4);
563 Stream_Write_INT32_BE(s, (INT32)value);
571size_t WinPrAsn1EncInteger(WinPrAsn1Encoder* enc, WinPrAsn1_INTEGER integer)
573 return WinPrAsn1EncIntegerLike(enc, ER_TAG_INTEGER, integer);
576size_t WinPrAsn1EncEnumerated(WinPrAsn1Encoder* enc, WinPrAsn1_ENUMERATED value)
578 return WinPrAsn1EncIntegerLike(enc, ER_TAG_ENUMERATED, value);
581static size_t WinPrAsn1EncContextualIntegerLike(WinPrAsn1Encoder* enc, WinPrAsn1_tag tag,
582 WinPrAsn1_tagId tagId, WinPrAsn1_INTEGER value)
584 wStream staticS = WINPR_C_ARRAY_INIT;
588 WINPR_ASSERT_VALID_TAG(tagId);
590 const size_t len = asn1IntegerLen(value);
591 const size_t outLen = 1 + lenBytes(1 + len) + (1 + len);
592 if (!asn1_getWriteStream(enc, outLen, s))
595 Stream_Write_UINT8(s, ER_TAG_CONTEXTUAL | tagId);
596 asn1WriteLen(s, 1 + len);
598 Stream_Write_UINT8(s, tag);
602 Stream_Write_UINT8(s, 1);
603 Stream_Write_INT8(s, (INT8)value);
606 Stream_Write_UINT8(s, 2);
607 Stream_Write_INT16_BE(s, (INT16)value);
610 Stream_Write_UINT8(s, 4);
611 Stream_Write_INT32_BE(s, value);
619size_t WinPrAsn1EncContextualInteger(WinPrAsn1Encoder* enc, WinPrAsn1_tagId tagId,
620 WinPrAsn1_INTEGER integer)
622 return WinPrAsn1EncContextualIntegerLike(enc, ER_TAG_INTEGER, tagId, integer);
625size_t WinPrAsn1EncContextualEnumerated(WinPrAsn1Encoder* enc, WinPrAsn1_tagId tagId,
626 WinPrAsn1_ENUMERATED value)
628 return WinPrAsn1EncContextualIntegerLike(enc, ER_TAG_ENUMERATED, tagId, value);
631size_t WinPrAsn1EncBoolean(WinPrAsn1Encoder* enc, WinPrAsn1_BOOL b)
636 if (!asn1_getWriteStream(enc, 3, s))
639 Stream_Write_UINT8(s, ER_TAG_BOOLEAN);
640 Stream_Write_UINT8(s, 1);
641 Stream_Write_UINT8(s, b ? 0xff : 0);
646size_t WinPrAsn1EncContextualBoolean(WinPrAsn1Encoder* enc, WinPrAsn1_tagId tagId, WinPrAsn1_BOOL b)
652 WINPR_ASSERT_VALID_TAG(tagId);
654 if (!asn1_getWriteStream(enc, 5, s))
657 Stream_Write_UINT8(s, ER_TAG_CONTEXTUAL | tagId);
658 Stream_Write_UINT8(s, 3);
660 Stream_Write_UINT8(s, ER_TAG_BOOLEAN);
661 Stream_Write_UINT8(s, 1);
662 Stream_Write_UINT8(s, b ? 0xff : 0);
667static size_t WinPrAsn1EncMemoryChunk(WinPrAsn1Encoder* enc, BYTE wireType,
674 WINPR_ASSERT(mchunk);
675 len = 1 + lenBytes(mchunk->len) + mchunk->len;
677 if (!asn1_getWriteStream(enc, len, &s))
680 Stream_Write_UINT8(&s, wireType);
681 asn1WriteLen(&s, mchunk->len);
682 Stream_Write(&s, mchunk->data, mchunk->len);
686size_t WinPrAsn1EncOID(WinPrAsn1Encoder* enc,
const WinPrAsn1_OID* oid)
688 return WinPrAsn1EncMemoryChunk(enc, ER_TAG_OBJECT_IDENTIFIER, oid);
693 return WinPrAsn1EncMemoryChunk(enc, ER_TAG_OCTET_STRING, octetstring);
696size_t WinPrAsn1EncIA5String(WinPrAsn1Encoder* enc, WinPrAsn1_IA5STRING ia5)
700 chunk.data = (BYTE*)ia5;
701 chunk.len = strlen(ia5);
702 return WinPrAsn1EncMemoryChunk(enc, ER_TAG_IA5STRING, &chunk);
705size_t WinPrAsn1EncGeneralString(WinPrAsn1Encoder* enc, WinPrAsn1_STRING str)
709 chunk.data = (BYTE*)str;
710 chunk.len = strlen(str);
711 return WinPrAsn1EncMemoryChunk(enc, ER_TAG_GENERAL_STRING, &chunk);
714static size_t WinPrAsn1EncContextualMemoryChunk(WinPrAsn1Encoder* enc, BYTE wireType,
715 WinPrAsn1_tagId tagId,
723 WINPR_ASSERT_VALID_TAG(tagId);
724 WINPR_ASSERT(mchunk);
725 len = 1 + lenBytes(mchunk->len) + mchunk->len;
727 outLen = 1 + lenBytes(len) + len;
728 if (!asn1_getWriteStream(enc, outLen, &s))
731 Stream_Write_UINT8(&s, ER_TAG_CONTEXTUAL | tagId);
732 asn1WriteLen(&s, len);
734 Stream_Write_UINT8(&s, wireType);
735 asn1WriteLen(&s, mchunk->len);
736 Stream_Write(&s, mchunk->data, mchunk->len);
740size_t WinPrAsn1EncContextualOID(WinPrAsn1Encoder* enc, WinPrAsn1_tagId tagId,
743 return WinPrAsn1EncContextualMemoryChunk(enc, ER_TAG_OBJECT_IDENTIFIER, tagId, oid);
746size_t WinPrAsn1EncContextualOctetString(WinPrAsn1Encoder* enc, WinPrAsn1_tagId tagId,
749 return WinPrAsn1EncContextualMemoryChunk(enc, ER_TAG_OCTET_STRING, tagId, octetstring);
752size_t WinPrAsn1EncContextualIA5String(WinPrAsn1Encoder* enc, WinPrAsn1_tagId tagId,
753 WinPrAsn1_IA5STRING ia5)
757 chunk.data = (BYTE*)ia5;
758 chunk.len = strlen(ia5);
760 return WinPrAsn1EncContextualMemoryChunk(enc, ER_TAG_IA5STRING, tagId, &chunk);
763static void write2digit(
wStream* s, UINT8 v)
765 Stream_Write_UINT8(s,
'0' + (v / 10));
766 Stream_Write_UINT8(s,
'0' + (v % 10));
771 wStream staticS = WINPR_C_ARRAY_INIT;
776 WINPR_ASSERT(utc->year >= 2000);
778 if (!asn1_getWriteStream(enc, 15, s))
781 Stream_Write_UINT8(s, ER_TAG_UTCTIME);
782 Stream_Write_UINT8(s, 13);
784 write2digit(s, (UINT8)(utc->year - 2000));
785 write2digit(s, utc->month);
786 write2digit(s, utc->day);
787 write2digit(s, utc->hour);
788 write2digit(s, utc->minute);
789 write2digit(s, utc->second);
790 Stream_Write_INT8(s, utc->tz);
794size_t WinPrAsn1EncContextualUtcTime(WinPrAsn1Encoder* enc, WinPrAsn1_tagId tagId,
801 WINPR_ASSERT_VALID_TAG(tagId);
803 WINPR_ASSERT(utc->year >= 2000);
804 WINPR_ASSERT(utc->year < 2256);
806 if (!asn1_getWriteStream(enc, 17, s))
809 Stream_Write_UINT8(s, ER_TAG_CONTEXTUAL | tagId);
810 Stream_Write_UINT8(s, 15);
812 Stream_Write_UINT8(s, ER_TAG_UTCTIME);
813 Stream_Write_UINT8(s, 13);
815 write2digit(s, (UINT8)(utc->year - 2000));
816 write2digit(s, utc->month);
817 write2digit(s, utc->day);
818 write2digit(s, utc->hour);
819 write2digit(s, utc->minute);
820 write2digit(s, utc->second);
821 Stream_Write_INT8(s, utc->tz);
826BOOL WinPrAsn1EncStreamSize(WinPrAsn1Encoder* enc,
size_t* s)
828 size_t finalSize = 0;
833 if (enc->freeContainerIndex != 0)
835 WLog_ERR(TAG,
"some container have not been closed");
839 for (
size_t i = 0; i < enc->freeChunkId; i++)
840 finalSize += enc->chunks[i].used;
845BOOL WinPrAsn1EncToStream(WinPrAsn1Encoder* enc,
wStream* s)
847 size_t finalSize = 0;
852 if (!WinPrAsn1EncStreamSize(enc, &finalSize))
855 if (!Stream_EnsureRemainingCapacity(s, finalSize))
858 for (
size_t i = 0; i < enc->freeChunkId; i++)
860 BYTE* src = Stream_Buffer(enc->pool) + enc->chunks[i].poolOffset;
861 Stream_Write(s, src, enc->chunks[i].used);
867void WinPrAsn1Decoder_Init(
WinPrAsn1Decoder* decoder, WinPrAsn1EncodingRule encoding,
870 WINPR_ASSERT(decoder);
871 WINPR_ASSERT(source);
873 decoder->encoding = encoding;
874 memcpy(&decoder->source, source,
sizeof(*source));
877void WinPrAsn1Decoder_InitMem(
WinPrAsn1Decoder* decoder, WinPrAsn1EncodingRule encoding,
878 const BYTE* source,
size_t len)
880 WINPR_ASSERT(decoder);
881 WINPR_ASSERT(source);
883 decoder->encoding = encoding;
884 Stream_StaticConstInit(&decoder->source, source, len);
892 if (Stream_GetRemainingLength(&dec->source) < 1)
894 Stream_Peek(&dec->source, tag, 1);
898static size_t readLen(
wStream* s,
size_t* len, BOOL derCheck)
903 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
906 Stream_Read_UINT8(s, retLen);
911 size_t nBytes = (retLen & 0x7f);
913 if (!Stream_CheckAndLogRequiredLength(TAG, s, nBytes))
917 for (retLen = 0; nBytes; nBytes--)
919 Stream_Read_UINT8(s, tmp);
920 retLen = (retLen << 8) + tmp;
926 if (ret > 1 && retLen < 128)
939 if (Stream_GetRemainingLength(s) < 1)
942 Stream_Read(s, tag, 1);
943 lenBytes = readLen(s, len, (dec->encoding == WINPR_ASN1_DER));
950size_t WinPrAsn1DecReadTagAndLen(
WinPrAsn1Decoder* dec, WinPrAsn1_tag* tag,
size_t* len)
956 return readTagAndLen(dec, &dec->source, tag, len);
959size_t WinPrAsn1DecPeekTagAndLen(
WinPrAsn1Decoder* dec, WinPrAsn1_tag* tag,
size_t* len)
961 wStream staticS = WINPR_C_ARRAY_INIT;
965 wStream* s = Stream_StaticConstInit(&staticS, Stream_ConstPointer(&dec->source),
966 Stream_GetRemainingLength(&dec->source));
967 return readTagAndLen(dec, s, tag, len);
970size_t WinPrAsn1DecReadTagLenValue(
WinPrAsn1Decoder* dec, WinPrAsn1_tag* tag,
size_t* len,
979 ret = readTagAndLen(dec, &dec->source, tag, len);
983 if (!Stream_CheckAndLogRequiredLength(TAG, &dec->source, *len))
986 value->encoding = dec->encoding;
987 Stream_StaticInit(&value->source, Stream_Pointer(&dec->source), *len);
988 Stream_Seek(&dec->source, *len);
992size_t WinPrAsn1DecReadBoolean(
WinPrAsn1Decoder* dec, WinPrAsn1_BOOL* target)
995 WinPrAsn1_tag tag = 0;
1000 WINPR_ASSERT(target);
1002 ret = readTagAndLen(dec, &dec->source, &tag, &len);
1003 if (!ret || tag != ER_TAG_BOOLEAN)
1005 if (Stream_GetRemainingLength(&dec->source) < len || len != 1)
1008 Stream_Read_UINT8(&dec->source, v);
1013static size_t WinPrAsn1DecReadIntegerLike(
WinPrAsn1Decoder* dec, WinPrAsn1_tag expectedTag,
1014 WinPrAsn1_INTEGER* target)
1016 WinPrAsn1_tag tag = 0;
1020 WINPR_ASSERT(target);
1022 size_t ret = readTagAndLen(dec, &dec->source, &tag, &len);
1023 if (!ret || (tag != expectedTag))
1025 if (len == 0 || Stream_GetRemainingLength(&dec->source) < len || (len > 4))
1031 Stream_Read_UINT8(&dec->source, v);
1037 BOOL isNegative = (v & 0x80);
1042 for (
size_t x = 1; x < len; x++)
1044 Stream_Read_UINT8(&dec->source, v);
1049 *target = (WinPrAsn1_INTEGER)uval;
1056size_t WinPrAsn1DecReadInteger(
WinPrAsn1Decoder* dec, WinPrAsn1_INTEGER* target)
1058 return WinPrAsn1DecReadIntegerLike(dec, ER_TAG_INTEGER, target);
1061size_t WinPrAsn1DecReadEnumerated(
WinPrAsn1Decoder* dec, WinPrAsn1_ENUMERATED* target)
1063 return WinPrAsn1DecReadIntegerLike(dec, ER_TAG_ENUMERATED, target);
1066static size_t WinPrAsn1DecReadMemoryChunkLike(
WinPrAsn1Decoder* dec, WinPrAsn1_tag expectedTag,
1069 WinPrAsn1_tag tag = 0;
1074 WINPR_ASSERT(target);
1076 ret = readTagAndLen(dec, &dec->source, &tag, &len);
1077 if (!ret || tag != expectedTag)
1079 if (!Stream_CheckAndLogRequiredLength(TAG, &dec->source, len))
1085 if (allocate && (len > 0))
1087 target->data = malloc(len);
1090 Stream_Read(&dec->source, target->data, len);
1094 target->data = Stream_Pointer(&dec->source);
1095 Stream_Seek(&dec->source, len);
1103 return WinPrAsn1DecReadMemoryChunkLike(dec, ER_TAG_OBJECT_IDENTIFIER,
1110 return WinPrAsn1DecReadMemoryChunkLike(dec, ER_TAG_OCTET_STRING, target, allocate);
1113size_t WinPrAsn1DecReadIA5String(
WinPrAsn1Decoder* dec, WinPrAsn1_IA5STRING* target)
1115 WinPrAsn1_tag tag = 0;
1118 WinPrAsn1_IA5STRING s =
nullptr;
1121 WINPR_ASSERT(target);
1123 ret = readTagAndLen(dec, &dec->source, &tag, &len);
1124 if (!ret || tag != ER_TAG_IA5STRING)
1126 if (!Stream_CheckAndLogRequiredLength(TAG, &dec->source, len))
1131 s = malloc(len + 1);
1134 Stream_Read(&dec->source, s, len);
1140size_t WinPrAsn1DecReadGeneralString(
WinPrAsn1Decoder* dec, WinPrAsn1_STRING* target)
1142 WinPrAsn1_tag tag = 0;
1145 WinPrAsn1_IA5STRING s =
nullptr;
1148 WINPR_ASSERT(target);
1150 ret = readTagAndLen(dec, &dec->source, &tag, &len);
1151 if (!ret || tag != ER_TAG_GENERAL_STRING)
1153 if (!Stream_CheckAndLogRequiredLength(TAG, &dec->source, len))
1158 s = malloc(len + 1);
1161 Stream_Read(&dec->source, s, len);
1167static int read2digits(
wStream* s)
1172 Stream_Read_INT8(s, c);
1173 if (c <
'0' || c >
'9')
1176 ret = (c -
'0') * 10;
1178 Stream_Read_INT8(s, c);
1179 if (c <
'0' || c >
'9')
1188 WinPrAsn1_tag tag = 0;
1196 WINPR_ASSERT(target);
1198 ret = readTagAndLen(dec, &dec->source, &tag, &len);
1199 if (!ret || tag != ER_TAG_UTCTIME)
1201 if (!Stream_CheckAndLogRequiredLength(TAG, &dec->source, len) || len < 12)
1204 Stream_StaticConstInit(s, Stream_ConstPointer(&dec->source), len);
1207 if ((v <= 0) || (v >= UINT16_MAX - 2000))
1209 target->year = (UINT16)(2000 + v);
1212 if ((v <= 0) || (v > UINT8_MAX))
1214 target->month = (UINT8)v;
1217 if ((v <= 0) || (v > UINT8_MAX))
1219 target->day = (UINT8)v;
1222 if ((v <= 0) || (v > UINT8_MAX))
1224 target->hour = (UINT8)v;
1227 if ((v <= 0) || (v > UINT8_MAX))
1229 target->minute = (UINT8)v;
1232 if ((v <= 0) || (v > UINT8_MAX))
1234 target->second = (UINT8)v;
1236 if (Stream_GetRemainingLength(s) >= 1)
1238 Stream_Read_INT8(s, target->tz);
1241 Stream_Seek(&dec->source, len);
1249 WinPrAsn1_tag tag = 0;
1255 ret = readTagAndLen(dec, &dec->source, &tag, &len);
1256 if (!ret || tag != ER_TAG_NULL || len)
1268 ret = readTagAndLen(dec, s, tag, &len);
1269 if (!ret || !Stream_CheckAndLogRequiredLength(TAG, s, len))
1272 target->encoding = dec->encoding;
1273 Stream_StaticConstInit(&target->source, Stream_ConstPointer(s), len);
1274 Stream_Seek(s, len);
1280 WinPrAsn1_tag tag = 0;
1284 WINPR_ASSERT(setDec);
1286 ret = readConstructed(dec, &dec->source, &tag, setDec);
1287 if ((tag & ER_TAG_APP) != ER_TAG_APP)
1290 *tagId = (tag & ER_TAG_MASK);
1296 WinPrAsn1_tag tag = 0;
1300 WINPR_ASSERT(seqDec);
1302 ret = readConstructed(dec, &dec->source, &tag, seqDec);
1303 if (tag != ER_TAG_SEQUENCE)
1311 WinPrAsn1_tag tag = 0;
1315 WINPR_ASSERT(setDec);
1317 ret = readConstructed(dec, &dec->source, &tag, setDec);
1318 if (tag != ER_TAG_SET)
1328 WinPrAsn1_tag ftag = 0;
1330 ret = readConstructed(dec, s, &ftag, ctxtDec);
1334 if ((ftag & ER_TAG_CONTEXTUAL) != ER_TAG_CONTEXTUAL)
1337 *tagId = (ftag & ER_TAG_MASK);
1341size_t WinPrAsn1DecReadContextualTag(
WinPrAsn1Decoder* dec, WinPrAsn1_tagId* tagId,
1345 WINPR_ASSERT(tagId);
1346 WINPR_ASSERT(ctxtDec);
1348 return readContextualTag(dec, &dec->source, tagId, ctxtDec);
1351size_t WinPrAsn1DecPeekContextualTag(
WinPrAsn1Decoder* dec, WinPrAsn1_tagId* tagId,
1357 Stream_StaticConstInit(&staticS, Stream_ConstPointer(&dec->source),
1358 Stream_GetRemainingLength(&dec->source));
1359 return readContextualTag(dec, &staticS, tagId, ctxtDec);
1362static size_t readContextualHeader(
WinPrAsn1Decoder* dec, WinPrAsn1_tagId tagId, BOOL* error,
1365 WinPrAsn1_tag ftag = 0;
1369 WINPR_ASSERT(error);
1370 WINPR_ASSERT(content);
1373 ret = WinPrAsn1DecPeekContextualTag(dec, &ftag, content);
1387size_t WinPrAsn1DecReadContextualBool(
WinPrAsn1Decoder* dec, WinPrAsn1_tagId tagId, BOOL* error,
1388 WinPrAsn1_BOOL* target)
1394 ret = readContextualHeader(dec, tagId, error, &content);
1398 ret2 = WinPrAsn1DecReadBoolean(&content, target);
1405 Stream_Seek(&dec->source, ret);
1409size_t WinPrAsn1DecReadContextualInteger(
WinPrAsn1Decoder* dec, WinPrAsn1_tagId tagId, BOOL* error,
1410 WinPrAsn1_INTEGER* target)
1416 ret = readContextualHeader(dec, tagId, error, &content);
1420 ret2 = WinPrAsn1DecReadInteger(&content, target);
1427 Stream_Seek(&dec->source, ret);
1431size_t WinPrAsn1DecReadContextualOID(
WinPrAsn1Decoder* dec, WinPrAsn1_tagId tagId, BOOL* error,
1438 ret = readContextualHeader(dec, tagId, error, &content);
1442 ret2 = WinPrAsn1DecReadOID(&content, target, allocate);
1449 Stream_Seek(&dec->source, ret);
1453size_t WinPrAsn1DecReadContextualOctetString(
WinPrAsn1Decoder* dec, WinPrAsn1_tagId tagId,
1461 ret = readContextualHeader(dec, tagId, error, &content);
1465 ret2 = WinPrAsn1DecReadOctetString(&content, target, allocate);
1472 Stream_Seek(&dec->source, ret);
1476size_t WinPrAsn1DecReadContextualSequence(
WinPrAsn1Decoder* dec, WinPrAsn1_tagId tagId, BOOL* error,
1483 ret = readContextualHeader(dec, tagId, error, &content);
1487 ret2 = WinPrAsn1DecReadSequence(&content, target);
1494 Stream_Seek(&dec->source, ret);
1500 wStream s = WINPR_C_ARRAY_INIT;
1503 Stream_StaticConstInit(&s, Stream_ConstPointer(&dec->source),
1504 Stream_GetRemainingLength(&dec->source));