20 #include <winpr/config.h>
22 #include <winpr/asn1.h>
23 #include <winpr/wlog.h>
24 #include <winpr/crt.h>
26 #include "../../log.h"
27 #define TAG WINPR_TAG("asn1")
36 #define MAX_STATIC_ITEMS 50
44 ASN1_CONTAINER_CONTEXT_ONLY,
45 ASN1_CONTAINER_OCTETSTRING,
48 typedef struct WinPrAsn1EncContainer WinPrAsn1EncContainer;
50 struct WinPrAsn1EncContainer
55 ContainerType containerType;
59 struct 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);
146 WinPrAsn1Encoder* WinPrAsn1Encoder_New(WinPrAsn1EncodingRule encoding)
148 WinPrAsn1Encoder* enc = calloc(1,
sizeof(*enc));
152 enc->encoding = encoding;
153 enc->pool = Stream_New(NULL, 1024);
160 enc->containers = &enc->staticContainers[0];
161 enc->chunks = &enc->staticChunks[0];
162 enc->chunksCapacity = MAX_STATIC_ITEMS;
163 enc->freeContainerIndex = 0;
167 void WinPrAsn1Encoder_Reset(WinPrAsn1Encoder* enc)
171 enc->freeContainerIndex = 0;
172 enc->freeChunkId = 0;
174 ZeroMemory(enc->chunks,
sizeof(*enc->chunks) * enc->chunksCapacity);
177 void WinPrAsn1Encoder_Free(WinPrAsn1Encoder** penc)
179 WinPrAsn1Encoder* enc = NULL;
185 if (enc->containers != &enc->staticContainers[0])
186 free(enc->containers);
188 if (enc->chunks != &enc->staticChunks[0])
191 Stream_Free(enc->pool, TRUE);
197 static Asn1Chunk* asn1enc_get_free_chunk(WinPrAsn1Encoder* enc,
size_t chunkSz, BOOL commit,
200 Asn1Chunk* ret = NULL;
202 WINPR_ASSERT(chunkSz);
208 size_t lastChunk = enc->freeChunkId ? enc->freeChunkId - 1 : 0;
209 ret = &enc->chunks[lastChunk];
210 if (ret->capacity && ret->capacity == ret->used)
212 if (!Stream_EnsureRemainingCapacity(enc->pool, chunkSz))
215 Stream_Seek(enc->pool, chunkSz);
216 ret->capacity += chunkSz;
217 ret->used += chunkSz;
224 if (enc->freeChunkId == enc->chunksCapacity)
227 Asn1Chunk* src = (enc->chunks != &enc->staticChunks[0]) ? enc->chunks : NULL;
228 Asn1Chunk* tmp = realloc(src, (enc->chunksCapacity + 10) *
sizeof(*src));
232 if (enc->chunks == &enc->staticChunks[0])
233 memcpy(tmp, &enc->staticChunks[0], enc->chunksCapacity *
sizeof(*src));
235 memset(tmp + enc->freeChunkId, 0,
sizeof(*tmp) * 10);
238 enc->chunksCapacity += 10;
240 if (enc->freeChunkId == enc->chunksCapacity)
243 if (!Stream_EnsureRemainingCapacity(enc->pool, chunkSz))
246 ret = &enc->chunks[enc->freeChunkId];
247 ret->poolOffset = Stream_GetPosition(enc->pool);
248 ret->capacity = chunkSz;
249 ret->used = commit ? chunkSz : 0;
251 *
id = enc->freeChunkId;
254 Stream_Seek(enc->pool, chunkSz);
258 static WinPrAsn1EncContainer* asn1enc_get_free_container(WinPrAsn1Encoder* enc,
size_t*
id)
260 WinPrAsn1EncContainer* ret = NULL;
263 if (enc->freeContainerIndex == enc->containerCapacity)
266 WinPrAsn1EncContainer* src =
267 (enc->containers != &enc->staticContainers[0]) ? enc->containers : NULL;
268 WinPrAsn1EncContainer* tmp = realloc(src, (enc->containerCapacity + 10) *
sizeof(*src));
272 if (enc->containers == &enc->staticContainers[0])
273 memcpy(tmp, &enc->staticContainers[0], enc->containerCapacity *
sizeof(*src));
275 enc->containers = tmp;
276 enc->containerCapacity += 10;
278 if (enc->freeContainerIndex == enc->containerCapacity)
281 ret = &enc->containers[enc->freeContainerIndex];
282 *
id = enc->freeContainerIndex;
284 enc->freeContainerIndex++;
288 static size_t lenBytes(
size_t len)
302 static void asn1WriteLen(
wStream* s,
size_t len)
306 Stream_Write_UINT8(s, (UINT8)len);
308 else if (len < (1 << 8))
310 Stream_Write_UINT8(s, 0x81);
311 Stream_Write_UINT8(s, (UINT8)len);
313 else if (len < (1 << 16))
315 Stream_Write_UINT8(s, 0x82);
316 Stream_Write_UINT16_BE(s, (UINT16)len);
318 else if (len < (1 << 24))
320 Stream_Write_UINT8(s, 0x83);
321 Stream_Write_UINT24_BE(s, (UINT32)len);
325 WINPR_ASSERT(len <= UINT32_MAX);
326 Stream_Write_UINT8(s, 0x84);
327 Stream_Write_UINT32_BE(s, (UINT32)len);
331 static WinPrAsn1EncContainer* getAsn1Container(WinPrAsn1Encoder* enc, ContainerType ctype,
332 WinPrAsn1_tag tag, BOOL contextual,
size_t maxLen)
336 WinPrAsn1EncContainer* container = NULL;
338 Asn1Chunk* chunk = asn1enc_get_free_chunk(enc, maxLen, FALSE, &chunkId);
342 container = asn1enc_get_free_container(enc, &ret);
343 container->containerType = ctype;
344 container->tag = tag;
345 container->contextual = contextual;
346 container->headerChunkId = chunkId;
350 BOOL WinPrAsn1EncAppContainer(WinPrAsn1Encoder* enc, WinPrAsn1_tagId tagId)
352 WINPR_ASSERT_VALID_TAG(tagId);
353 return getAsn1Container(enc, ASN1_CONTAINER_APP, tagId, FALSE, 6) != NULL;
356 BOOL WinPrAsn1EncSeqContainer(WinPrAsn1Encoder* enc)
358 return getAsn1Container(enc, ASN1_CONTAINER_SEQ, 0, FALSE, 6) != NULL;
361 BOOL WinPrAsn1EncSetContainer(WinPrAsn1Encoder* enc)
363 return getAsn1Container(enc, ASN1_CONTAINER_SET, 0, FALSE, 6) != NULL;
366 BOOL WinPrAsn1EncContextualSeqContainer(WinPrAsn1Encoder* enc, WinPrAsn1_tagId tagId)
368 return getAsn1Container(enc, ASN1_CONTAINER_SEQ, tagId, TRUE, 6 + 6) != NULL;
371 BOOL WinPrAsn1EncContextualSetContainer(WinPrAsn1Encoder* enc, WinPrAsn1_tagId tagId)
373 return getAsn1Container(enc, ASN1_CONTAINER_SET, tagId, TRUE, 6 + 6) != NULL;
376 BOOL WinPrAsn1EncContextualContainer(WinPrAsn1Encoder* enc, WinPrAsn1_tagId tagId)
378 return getAsn1Container(enc, ASN1_CONTAINER_CONTEXT_ONLY, tagId, TRUE, 6) != NULL;
381 BOOL WinPrAsn1EncOctetStringContainer(WinPrAsn1Encoder* enc)
383 return getAsn1Container(enc, ASN1_CONTAINER_OCTETSTRING, 0, FALSE, 6) != NULL;
386 BOOL WinPrAsn1EncContextualOctetStringContainer(WinPrAsn1Encoder* enc, WinPrAsn1_tagId tagId)
388 return getAsn1Container(enc, ASN1_CONTAINER_OCTETSTRING, tagId, TRUE, 6 + 6) != NULL;
391 size_t WinPrAsn1EncEndContainer(WinPrAsn1Encoder* enc)
395 size_t innerHeaderBytes = 0;
396 size_t outerHeaderBytes = 0;
397 BYTE containerByte = 0;
398 WinPrAsn1EncContainer* container = NULL;
399 Asn1Chunk* chunk = NULL;
404 WINPR_ASSERT(enc->freeContainerIndex);
407 container = &enc->containers[enc->freeContainerIndex - 1];
409 for (
size_t i = container->headerChunkId + 1; i < enc->freeChunkId; i++)
410 innerLen += enc->chunks[i].used;
413 switch (container->containerType)
415 case ASN1_CONTAINER_SEQ:
416 containerByte = ER_TAG_SEQUENCE;
417 innerHeaderBytes = 1 + lenBytes(innerLen);
419 case ASN1_CONTAINER_SET:
420 containerByte = ER_TAG_SET;
421 innerHeaderBytes = 1 + lenBytes(innerLen);
423 case ASN1_CONTAINER_OCTETSTRING:
424 containerByte = ER_TAG_OCTET_STRING;
425 innerHeaderBytes = 1 + lenBytes(innerLen);
427 case ASN1_CONTAINER_APP:
428 containerByte = ER_TAG_APP | container->tag;
429 innerHeaderBytes = 1 + lenBytes(innerLen);
431 case ASN1_CONTAINER_CONTEXT_ONLY:
432 innerHeaderBytes = 0;
435 WLog_ERR(TAG,
"invalid containerType");
439 outerHeaderBytes = innerHeaderBytes;
440 if (container->contextual)
442 outerHeaderBytes = 1 + lenBytes(innerHeaderBytes + innerLen) + innerHeaderBytes;
447 chunk = &enc->chunks[container->headerChunkId];
448 unused = chunk->capacity - outerHeaderBytes;
449 chunk->poolOffset += unused;
450 chunk->capacity = chunk->used = outerHeaderBytes;
452 Stream_StaticInit(s, Stream_Buffer(enc->pool) + chunk->poolOffset, outerHeaderBytes);
453 if (container->contextual)
455 Stream_Write_UINT8(s, ER_TAG_CONTEXTUAL | container->tag);
456 asn1WriteLen(s, innerHeaderBytes + innerLen);
459 switch (container->containerType)
461 case ASN1_CONTAINER_SEQ:
462 case ASN1_CONTAINER_SET:
463 case ASN1_CONTAINER_OCTETSTRING:
464 case ASN1_CONTAINER_APP:
465 Stream_Write_UINT8(s, containerByte);
466 asn1WriteLen(s, innerLen);
468 case ASN1_CONTAINER_CONTEXT_ONLY:
471 WLog_ERR(TAG,
"invalid containerType");
476 enc->freeContainerIndex--;
477 return outerHeaderBytes + innerLen;
480 static BOOL asn1_getWriteStream(WinPrAsn1Encoder* enc,
size_t len,
wStream* s)
483 Asn1Chunk* chunk = asn1enc_get_free_chunk(enc, len, TRUE, NULL);
487 dest = Stream_Buffer(enc->pool) + chunk->poolOffset + chunk->capacity - len;
488 Stream_StaticInit(s, dest, len);
500 if (!asn1_getWriteStream(enc, c->len, s))
503 Stream_Write(s, c->data, c->len);
507 size_t WinPrAsn1EncContextualRawContent(WinPrAsn1Encoder* enc, WinPrAsn1_tagId tagId,
515 WINPR_ASSERT_VALID_TAG(tagId);
517 size_t len = 1 + lenBytes(c->len) + c->len;
518 if (!asn1_getWriteStream(enc, len, s))
521 Stream_Write_UINT8(s, ER_TAG_CONTEXTUAL | tagId);
522 asn1WriteLen(s, c->len);
524 Stream_Write(s, c->data, c->len);
528 static size_t asn1IntegerLen(WinPrAsn1_INTEGER value)
530 if (value <= 127 && value >= -128)
532 else if (value <= 32767 && value >= -32768)
538 static size_t WinPrAsn1EncIntegerLike(WinPrAsn1Encoder* enc, WinPrAsn1_tag b,
539 WinPrAsn1_INTEGER value)
544 const size_t len = asn1IntegerLen(value);
545 if (!asn1_getWriteStream(enc, 1 + len, s))
548 Stream_Write_UINT8(s, b);
552 Stream_Write_UINT8(s, 1);
553 Stream_Write_INT8(s, (INT8)value);
556 Stream_Write_UINT8(s, 2);
557 Stream_Write_INT16_BE(s, (INT16)value);
560 Stream_Write_UINT8(s, 4);
561 Stream_Write_INT32_BE(s, (INT32)value);
569 size_t WinPrAsn1EncInteger(WinPrAsn1Encoder* enc, WinPrAsn1_INTEGER value)
571 return WinPrAsn1EncIntegerLike(enc, ER_TAG_INTEGER, value);
574 size_t WinPrAsn1EncEnumerated(WinPrAsn1Encoder* enc, WinPrAsn1_ENUMERATED value)
576 return WinPrAsn1EncIntegerLike(enc, ER_TAG_ENUMERATED, value);
579 static size_t WinPrAsn1EncContextualIntegerLike(WinPrAsn1Encoder* enc, WinPrAsn1_tag tag,
580 WinPrAsn1_tagId tagId, WinPrAsn1_INTEGER value)
586 WINPR_ASSERT_VALID_TAG(tagId);
588 const size_t len = asn1IntegerLen(value);
589 const size_t outLen = 1 + lenBytes(1 + len) + (1 + len);
590 if (!asn1_getWriteStream(enc, outLen, s))
593 Stream_Write_UINT8(s, ER_TAG_CONTEXTUAL | tagId);
594 asn1WriteLen(s, 1 + len);
596 Stream_Write_UINT8(s, tag);
600 Stream_Write_UINT8(s, 1);
601 Stream_Write_INT8(s, (INT8)value);
604 Stream_Write_UINT8(s, 2);
605 Stream_Write_INT16_BE(s, (INT16)value);
608 Stream_Write_UINT8(s, 4);
609 Stream_Write_INT32_BE(s, value);
617 size_t WinPrAsn1EncContextualInteger(WinPrAsn1Encoder* enc, WinPrAsn1_tagId tagId,
618 WinPrAsn1_INTEGER value)
620 return WinPrAsn1EncContextualIntegerLike(enc, ER_TAG_INTEGER, tagId, value);
623 size_t WinPrAsn1EncContextualEnumerated(WinPrAsn1Encoder* enc, WinPrAsn1_tagId tagId,
624 WinPrAsn1_ENUMERATED value)
626 return WinPrAsn1EncContextualIntegerLike(enc, ER_TAG_ENUMERATED, tagId, value);
629 size_t WinPrAsn1EncBoolean(WinPrAsn1Encoder* enc, WinPrAsn1_BOOL b)
634 if (!asn1_getWriteStream(enc, 3, s))
637 Stream_Write_UINT8(s, ER_TAG_BOOLEAN);
638 Stream_Write_UINT8(s, 1);
639 Stream_Write_UINT8(s, b ? 0xff : 0);
644 size_t WinPrAsn1EncContextualBoolean(WinPrAsn1Encoder* enc, WinPrAsn1_tagId tagId, WinPrAsn1_BOOL b)
650 WINPR_ASSERT_VALID_TAG(tagId);
652 if (!asn1_getWriteStream(enc, 5, s))
655 Stream_Write_UINT8(s, ER_TAG_CONTEXTUAL | tagId);
656 Stream_Write_UINT8(s, 3);
658 Stream_Write_UINT8(s, ER_TAG_BOOLEAN);
659 Stream_Write_UINT8(s, 1);
660 Stream_Write_UINT8(s, b ? 0xff : 0);
665 static size_t WinPrAsn1EncMemoryChunk(WinPrAsn1Encoder* enc, BYTE wireType,
672 WINPR_ASSERT(mchunk);
673 len = 1 + lenBytes(mchunk->len) + mchunk->len;
675 if (!asn1_getWriteStream(enc, len, &s))
678 Stream_Write_UINT8(&s, wireType);
679 asn1WriteLen(&s, mchunk->len);
680 Stream_Write(&s, mchunk->data, mchunk->len);
684 size_t WinPrAsn1EncOID(WinPrAsn1Encoder* enc,
const WinPrAsn1_OID* oid)
686 return WinPrAsn1EncMemoryChunk(enc, ER_TAG_OBJECT_IDENTIFIER, oid);
691 return WinPrAsn1EncMemoryChunk(enc, ER_TAG_OCTET_STRING, octets);
694 size_t WinPrAsn1EncIA5String(WinPrAsn1Encoder* enc, WinPrAsn1_IA5STRING ia5)
698 chunk.data = (BYTE*)ia5;
699 chunk.len = strlen(ia5);
700 return WinPrAsn1EncMemoryChunk(enc, ER_TAG_IA5STRING, &chunk);
703 size_t WinPrAsn1EncGeneralString(WinPrAsn1Encoder* enc, WinPrAsn1_STRING str)
707 chunk.data = (BYTE*)str;
708 chunk.len = strlen(str);
709 return WinPrAsn1EncMemoryChunk(enc, ER_TAG_GENERAL_STRING, &chunk);
712 static size_t WinPrAsn1EncContextualMemoryChunk(WinPrAsn1Encoder* enc, BYTE wireType,
713 WinPrAsn1_tagId tagId,
721 WINPR_ASSERT_VALID_TAG(tagId);
722 WINPR_ASSERT(mchunk);
723 len = 1 + lenBytes(mchunk->len) + mchunk->len;
725 outLen = 1 + lenBytes(len) + len;
726 if (!asn1_getWriteStream(enc, outLen, &s))
729 Stream_Write_UINT8(&s, ER_TAG_CONTEXTUAL | tagId);
730 asn1WriteLen(&s, len);
732 Stream_Write_UINT8(&s, wireType);
733 asn1WriteLen(&s, mchunk->len);
734 Stream_Write(&s, mchunk->data, mchunk->len);
738 size_t WinPrAsn1EncContextualOID(WinPrAsn1Encoder* enc, WinPrAsn1_tagId tagId,
741 return WinPrAsn1EncContextualMemoryChunk(enc, ER_TAG_OBJECT_IDENTIFIER, tagId, oid);
744 size_t WinPrAsn1EncContextualOctetString(WinPrAsn1Encoder* enc, WinPrAsn1_tagId tagId,
747 return WinPrAsn1EncContextualMemoryChunk(enc, ER_TAG_OCTET_STRING, tagId, octets);
750 size_t WinPrAsn1EncContextualIA5String(WinPrAsn1Encoder* enc, WinPrAsn1_tagId tagId,
751 WinPrAsn1_IA5STRING ia5)
755 chunk.data = (BYTE*)ia5;
756 chunk.len = strlen(ia5);
758 return WinPrAsn1EncContextualMemoryChunk(enc, ER_TAG_IA5STRING, tagId, &chunk);
761 static void write2digit(
wStream* s, UINT8 v)
763 Stream_Write_UINT8(s,
'0' + (v / 10));
764 Stream_Write_UINT8(s,
'0' + (v % 10));
774 WINPR_ASSERT(utc->year >= 2000);
776 if (!asn1_getWriteStream(enc, 15, s))
779 Stream_Write_UINT8(s, ER_TAG_UTCTIME);
780 Stream_Write_UINT8(s, 13);
782 write2digit(s, (UINT8)(utc->year - 2000));
783 write2digit(s, utc->month);
784 write2digit(s, utc->day);
785 write2digit(s, utc->hour);
786 write2digit(s, utc->minute);
787 write2digit(s, utc->second);
788 Stream_Write_INT8(s, utc->tz);
792 size_t WinPrAsn1EncContextualUtcTime(WinPrAsn1Encoder* enc, WinPrAsn1_tagId tagId,
799 WINPR_ASSERT_VALID_TAG(tagId);
801 WINPR_ASSERT(utc->year >= 2000);
802 WINPR_ASSERT(utc->year < 2256);
804 if (!asn1_getWriteStream(enc, 17, s))
807 Stream_Write_UINT8(s, ER_TAG_CONTEXTUAL | tagId);
808 Stream_Write_UINT8(s, 15);
810 Stream_Write_UINT8(s, ER_TAG_UTCTIME);
811 Stream_Write_UINT8(s, 13);
813 write2digit(s, (UINT8)(utc->year - 2000));
814 write2digit(s, utc->month);
815 write2digit(s, utc->day);
816 write2digit(s, utc->hour);
817 write2digit(s, utc->minute);
818 write2digit(s, utc->second);
819 Stream_Write_INT8(s, utc->tz);
824 BOOL WinPrAsn1EncStreamSize(WinPrAsn1Encoder* enc,
size_t* s)
826 size_t finalSize = 0;
831 if (enc->freeContainerIndex != 0)
833 WLog_ERR(TAG,
"some container have not been closed");
837 for (
size_t i = 0; i < enc->freeChunkId; i++)
838 finalSize += enc->chunks[i].used;
843 BOOL WinPrAsn1EncToStream(WinPrAsn1Encoder* enc,
wStream* s)
845 size_t finalSize = 0;
850 if (!WinPrAsn1EncStreamSize(enc, &finalSize))
853 if (!Stream_EnsureRemainingCapacity(s, finalSize))
856 for (
size_t i = 0; i < enc->freeChunkId; i++)
858 BYTE* src = Stream_Buffer(enc->pool) + enc->chunks[i].poolOffset;
859 Stream_Write(s, src, enc->chunks[i].used);
865 void WinPrAsn1Decoder_Init(
WinPrAsn1Decoder* decoder, WinPrAsn1EncodingRule encoding,
868 WINPR_ASSERT(decoder);
869 WINPR_ASSERT(source);
871 decoder->encoding = encoding;
872 memcpy(&decoder->source, source,
sizeof(*source));
875 void WinPrAsn1Decoder_InitMem(
WinPrAsn1Decoder* decoder, WinPrAsn1EncodingRule encoding,
876 const BYTE* source,
size_t len)
878 WINPR_ASSERT(decoder);
879 WINPR_ASSERT(source);
881 decoder->encoding = encoding;
882 Stream_StaticConstInit(&decoder->source, source, len);
890 if (Stream_GetRemainingLength(&dec->source) < 1)
892 Stream_Peek(&dec->source, tag, 1);
896 static size_t readLen(
wStream* s,
size_t* len, BOOL derCheck)
901 if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
904 Stream_Read_UINT8(s, retLen);
909 size_t nBytes = (retLen & 0x7f);
911 if (!Stream_CheckAndLogRequiredLength(TAG, s, nBytes))
915 for (retLen = 0; nBytes; nBytes--)
917 Stream_Read_UINT8(s, tmp);
918 retLen = (retLen << 8) + tmp;
924 if (ret > 1 && retLen < 128)
937 if (Stream_GetRemainingLength(s) < 1)
940 Stream_Read(s, tag, 1);
941 lenBytes = readLen(s, len, (dec->encoding == WINPR_ASN1_DER));
948 size_t WinPrAsn1DecReadTagAndLen(
WinPrAsn1Decoder* dec, WinPrAsn1_tag* tag,
size_t* len)
954 return readTagAndLen(dec, &dec->source, tag, len);
957 size_t WinPrAsn1DecPeekTagAndLen(
WinPrAsn1Decoder* dec, WinPrAsn1_tag* tag,
size_t* len)
964 Stream_StaticConstInit(s, Stream_ConstPointer(&dec->source),
965 Stream_GetRemainingLength(&dec->source));
966 return readTagAndLen(dec, s, tag, len);
969 size_t WinPrAsn1DecReadTagLenValue(
WinPrAsn1Decoder* dec, WinPrAsn1_tag* tag,
size_t* len,
978 ret = readTagAndLen(dec, &dec->source, tag, len);
982 if (!Stream_CheckAndLogRequiredLength(TAG, &dec->source, *len))
985 value->encoding = dec->encoding;
986 Stream_StaticInit(&value->source, Stream_Pointer(&dec->source), *len);
987 Stream_Seek(&dec->source, *len);
991 size_t WinPrAsn1DecReadBoolean(
WinPrAsn1Decoder* dec, WinPrAsn1_BOOL* target)
994 WinPrAsn1_tag tag = 0;
999 WINPR_ASSERT(target);
1001 ret = readTagAndLen(dec, &dec->source, &tag, &len);
1002 if (!ret || tag != ER_TAG_BOOLEAN)
1004 if (Stream_GetRemainingLength(&dec->source) < len || len != 1)
1007 Stream_Read_UINT8(&dec->source, v);
1012 static size_t WinPrAsn1DecReadIntegerLike(
WinPrAsn1Decoder* dec, WinPrAsn1_tag expectedTag,
1013 WinPrAsn1_INTEGER* target)
1015 WinPrAsn1_tag tag = 0;
1019 WINPR_ASSERT(target);
1021 size_t ret = readTagAndLen(dec, &dec->source, &tag, &len);
1022 if (!ret || (tag != expectedTag))
1024 if (len == 0 || Stream_GetRemainingLength(&dec->source) < len || (len > 4))
1030 Stream_Read_UINT8(&dec->source, v);
1036 BOOL isNegative = (v & 0x80);
1041 for (
size_t x = 1; x < len; x++)
1043 Stream_Read_UINT8(&dec->source, v);
1048 *target = (WinPrAsn1_INTEGER)uval;
1055 size_t WinPrAsn1DecReadInteger(
WinPrAsn1Decoder* dec, WinPrAsn1_INTEGER* target)
1057 return WinPrAsn1DecReadIntegerLike(dec, ER_TAG_INTEGER, target);
1060 size_t WinPrAsn1DecReadEnumerated(
WinPrAsn1Decoder* dec, WinPrAsn1_ENUMERATED* target)
1062 return WinPrAsn1DecReadIntegerLike(dec, ER_TAG_ENUMERATED, target);
1065 static size_t WinPrAsn1DecReadMemoryChunkLike(
WinPrAsn1Decoder* dec, WinPrAsn1_tag expectedTag,
1068 WinPrAsn1_tag tag = 0;
1073 WINPR_ASSERT(target);
1075 ret = readTagAndLen(dec, &dec->source, &tag, &len);
1076 if (!ret || tag != expectedTag)
1078 if (!Stream_CheckAndLogRequiredLength(TAG, &dec->source, len))
1086 target->data = malloc(len);
1089 Stream_Read(&dec->source, target->data, len);
1093 target->data = Stream_Pointer(&dec->source);
1094 Stream_Seek(&dec->source, len);
1102 return WinPrAsn1DecReadMemoryChunkLike(dec, ER_TAG_OBJECT_IDENTIFIER,
1109 return WinPrAsn1DecReadMemoryChunkLike(dec, ER_TAG_OCTET_STRING, target, allocate);
1112 size_t WinPrAsn1DecReadIA5String(
WinPrAsn1Decoder* dec, WinPrAsn1_IA5STRING* target)
1114 WinPrAsn1_tag tag = 0;
1117 WinPrAsn1_IA5STRING s = NULL;
1120 WINPR_ASSERT(target);
1122 ret = readTagAndLen(dec, &dec->source, &tag, &len);
1123 if (!ret || tag != ER_TAG_IA5STRING)
1125 if (!Stream_CheckAndLogRequiredLength(TAG, &dec->source, len))
1130 s = malloc(len + 1);
1133 Stream_Read(&dec->source, s, len);
1139 size_t WinPrAsn1DecReadGeneralString(
WinPrAsn1Decoder* dec, WinPrAsn1_STRING* target)
1141 WinPrAsn1_tag tag = 0;
1144 WinPrAsn1_IA5STRING s = NULL;
1147 WINPR_ASSERT(target);
1149 ret = readTagAndLen(dec, &dec->source, &tag, &len);
1150 if (!ret || tag != ER_TAG_GENERAL_STRING)
1152 if (!Stream_CheckAndLogRequiredLength(TAG, &dec->source, len))
1157 s = malloc(len + 1);
1160 Stream_Read(&dec->source, s, len);
1166 static int read2digits(
wStream* s)
1171 Stream_Read_UINT8(s, c);
1172 if (c < '0' || c >
'9')
1175 ret = (c -
'0') * 10;
1177 Stream_Read_UINT8(s, c);
1178 if (c < '0' || c >
'9')
1187 WinPrAsn1_tag tag = 0;
1195 WINPR_ASSERT(target);
1197 ret = readTagAndLen(dec, &dec->source, &tag, &len);
1198 if (!ret || tag != ER_TAG_UTCTIME)
1200 if (!Stream_CheckAndLogRequiredLength(TAG, &dec->source, len) || len < 12)
1203 Stream_StaticConstInit(s, Stream_ConstPointer(&dec->source), len);
1208 target->year = 2000 + v;
1235 if (Stream_GetRemainingLength(s) >= 1)
1237 Stream_Read_UINT8(s, target->tz);
1240 Stream_Seek(&dec->source, len);
1248 WinPrAsn1_tag tag = 0;
1254 ret = readTagAndLen(dec, &dec->source, &tag, &len);
1255 if (!ret || tag != ER_TAG_NULL || len)
1267 ret = readTagAndLen(dec, s, tag, &len);
1268 if (!ret || !Stream_CheckAndLogRequiredLength(TAG, s, len))
1271 target->encoding = dec->encoding;
1272 Stream_StaticConstInit(&target->source, Stream_ConstPointer(s), len);
1273 Stream_Seek(s, len);
1279 WinPrAsn1_tag tag = 0;
1283 WINPR_ASSERT(target);
1285 ret = readConstructed(dec, &dec->source, &tag, target);
1286 if ((tag & ER_TAG_APP) != ER_TAG_APP)
1289 *tagId = (tag & ER_TAG_MASK);
1295 WinPrAsn1_tag tag = 0;
1299 WINPR_ASSERT(target);
1301 ret = readConstructed(dec, &dec->source, &tag, target);
1302 if (tag != ER_TAG_SEQUENCE)
1310 WinPrAsn1_tag tag = 0;
1314 WINPR_ASSERT(target);
1316 ret = readConstructed(dec, &dec->source, &tag, target);
1317 if (tag != ER_TAG_SET)
1327 WinPrAsn1_tag ftag = 0;
1329 ret = readConstructed(dec, s, &ftag, ctxtDec);
1333 if ((ftag & ER_TAG_CONTEXTUAL) != ER_TAG_CONTEXTUAL)
1336 *tagId = (ftag & ER_TAG_MASK);
1340 size_t WinPrAsn1DecReadContextualTag(
WinPrAsn1Decoder* dec, WinPrAsn1_tagId* tagId,
1344 WINPR_ASSERT(tagId);
1345 WINPR_ASSERT(ctxtDec);
1347 return readContextualTag(dec, &dec->source, tagId, ctxtDec);
1350 size_t WinPrAsn1DecPeekContextualTag(
WinPrAsn1Decoder* dec, WinPrAsn1_tagId* tagId,
1356 Stream_StaticConstInit(&staticS, Stream_ConstPointer(&dec->source),
1357 Stream_GetRemainingLength(&dec->source));
1358 return readContextualTag(dec, &staticS, tagId, ctxtDec);
1361 static size_t readContextualHeader(
WinPrAsn1Decoder* dec, WinPrAsn1_tagId tagId, BOOL* error,
1364 WinPrAsn1_tag ftag = 0;
1368 WINPR_ASSERT(error);
1369 WINPR_ASSERT(content);
1372 ret = WinPrAsn1DecPeekContextualTag(dec, &ftag, content);
1386 size_t WinPrAsn1DecReadContextualBool(
WinPrAsn1Decoder* dec, WinPrAsn1_tagId tagId, BOOL* error,
1387 WinPrAsn1_BOOL* target)
1393 ret = readContextualHeader(dec, tagId, error, &content);
1397 ret2 = WinPrAsn1DecReadBoolean(&content, target);
1404 Stream_Seek(&dec->source, ret);
1408 size_t WinPrAsn1DecReadContextualInteger(
WinPrAsn1Decoder* dec, WinPrAsn1_tagId tagId, BOOL* error,
1409 WinPrAsn1_INTEGER* target)
1415 ret = readContextualHeader(dec, tagId, error, &content);
1419 ret2 = WinPrAsn1DecReadInteger(&content, target);
1426 Stream_Seek(&dec->source, ret);
1430 size_t WinPrAsn1DecReadContextualOID(
WinPrAsn1Decoder* dec, WinPrAsn1_tagId tagId, BOOL* error,
1437 ret = readContextualHeader(dec, tagId, error, &content);
1441 ret2 = WinPrAsn1DecReadOID(&content, target, allocate);
1448 Stream_Seek(&dec->source, ret);
1452 size_t WinPrAsn1DecReadContextualOctetString(
WinPrAsn1Decoder* dec, WinPrAsn1_tagId tagId,
1460 ret = readContextualHeader(dec, tagId, error, &content);
1464 ret2 = WinPrAsn1DecReadOctetString(&content, target, allocate);
1471 Stream_Seek(&dec->source, ret);
1475 size_t WinPrAsn1DecReadContextualSequence(
WinPrAsn1Decoder* dec, WinPrAsn1_tagId tagId, BOOL* error,
1482 ret = readContextualHeader(dec, tagId, error, &content);
1486 ret2 = WinPrAsn1DecReadSequence(&content, target);
1493 Stream_Seek(&dec->source, ret);
1502 Stream_StaticConstInit(&s, Stream_ConstPointer(&dec->source),
1503 Stream_GetRemainingLength(&dec->source));