FreeRDP
asn1.c
1 
20 #include <winpr/config.h>
21 
22 #include <winpr/asn1.h>
23 #include <winpr/wlog.h>
24 #include <winpr/crt.h>
25 
26 #include "../../log.h"
27 #define TAG WINPR_TAG("asn1")
28 
29 typedef struct
30 {
31  size_t poolOffset;
32  size_t capacity;
33  size_t used;
34 } Asn1Chunk;
35 
36 #define MAX_STATIC_ITEMS 50
37 
39 typedef enum
40 {
41  ASN1_CONTAINER_SEQ,
42  ASN1_CONTAINER_SET,
43  ASN1_CONTAINER_APP,
44  ASN1_CONTAINER_CONTEXT_ONLY,
45  ASN1_CONTAINER_OCTETSTRING,
46 } ContainerType;
47 
48 typedef struct WinPrAsn1EncContainer WinPrAsn1EncContainer;
50 struct WinPrAsn1EncContainer
51 {
52  size_t headerChunkId;
53  BOOL contextual;
54  WinPrAsn1_tag tag;
55  ContainerType containerType;
56 };
57 
59 struct WinPrAsn1Encoder
60 {
61  WinPrAsn1EncodingRule encoding;
62  wStream* pool;
63 
64  Asn1Chunk* chunks;
65  Asn1Chunk staticChunks[MAX_STATIC_ITEMS];
66  size_t freeChunkId;
67  size_t chunksCapacity;
68 
69  WinPrAsn1EncContainer* containers;
70  WinPrAsn1EncContainer staticContainers[MAX_STATIC_ITEMS];
71  size_t freeContainerIndex;
72  size_t containerCapacity;
73 };
74 
75 #define WINPR_ASSERT_VALID_TAG(t) WINPR_ASSERT((t) < 64)
76 
77 void WinPrAsn1FreeOID(WinPrAsn1_OID* poid)
78 {
79  WINPR_ASSERT(poid);
80  free(poid->data);
81  poid->data = NULL;
82  poid->len = 0;
83 }
84 
85 void WinPrAsn1FreeOctetString(WinPrAsn1_OctetString* octets)
86 {
87  WinPrAsn1FreeOID(octets);
88 }
89 
146 WinPrAsn1Encoder* WinPrAsn1Encoder_New(WinPrAsn1EncodingRule encoding)
147 {
148  WinPrAsn1Encoder* enc = calloc(1, sizeof(*enc));
149  if (!enc)
150  return NULL;
151 
152  enc->encoding = encoding;
153  enc->pool = Stream_New(NULL, 1024);
154  if (!enc->pool)
155  {
156  free(enc);
157  return NULL;
158  }
159 
160  enc->containers = &enc->staticContainers[0];
161  enc->chunks = &enc->staticChunks[0];
162  enc->chunksCapacity = MAX_STATIC_ITEMS;
163  enc->freeContainerIndex = 0;
164  return enc;
165 }
166 
167 void WinPrAsn1Encoder_Reset(WinPrAsn1Encoder* enc)
168 {
169  WINPR_ASSERT(enc);
170 
171  enc->freeContainerIndex = 0;
172  enc->freeChunkId = 0;
173 
174  ZeroMemory(enc->chunks, sizeof(*enc->chunks) * enc->chunksCapacity);
175 }
176 
177 void WinPrAsn1Encoder_Free(WinPrAsn1Encoder** penc)
178 {
179  WinPrAsn1Encoder* enc = NULL;
180 
181  WINPR_ASSERT(penc);
182  enc = *penc;
183  if (enc)
184  {
185  if (enc->containers != &enc->staticContainers[0])
186  free(enc->containers);
187 
188  if (enc->chunks != &enc->staticChunks[0])
189  free(enc->chunks);
190 
191  Stream_Free(enc->pool, TRUE);
192  free(enc);
193  }
194  *penc = NULL;
195 }
196 
197 static Asn1Chunk* asn1enc_get_free_chunk(WinPrAsn1Encoder* enc, size_t chunkSz, BOOL commit,
198  size_t* id)
199 {
200  Asn1Chunk* ret = NULL;
201  WINPR_ASSERT(enc);
202  WINPR_ASSERT(chunkSz);
203 
204  if (commit)
205  {
206  /* if it's not a reservation let's see if the last chunk is not a reservation and can be
207  * expanded */
208  size_t lastChunk = enc->freeChunkId ? enc->freeChunkId - 1 : 0;
209  ret = &enc->chunks[lastChunk];
210  if (ret->capacity && ret->capacity == ret->used)
211  {
212  if (!Stream_EnsureRemainingCapacity(enc->pool, chunkSz))
213  return NULL;
214 
215  Stream_Seek(enc->pool, chunkSz);
216  ret->capacity += chunkSz;
217  ret->used += chunkSz;
218  if (id)
219  *id = lastChunk;
220  return ret;
221  }
222  }
223 
224  if (enc->freeChunkId == enc->chunksCapacity)
225  {
226  /* chunks need a resize */
227  Asn1Chunk* src = (enc->chunks != &enc->staticChunks[0]) ? enc->chunks : NULL;
228  Asn1Chunk* tmp = realloc(src, (enc->chunksCapacity + 10) * sizeof(*src));
229  if (!tmp)
230  return NULL;
231 
232  if (enc->chunks == &enc->staticChunks[0])
233  memcpy(tmp, &enc->staticChunks[0], enc->chunksCapacity * sizeof(*src));
234  else
235  memset(tmp + enc->freeChunkId, 0, sizeof(*tmp) * 10);
236 
237  enc->chunks = tmp;
238  enc->chunksCapacity += 10;
239  }
240  if (enc->freeChunkId == enc->chunksCapacity)
241  return NULL;
242 
243  if (!Stream_EnsureRemainingCapacity(enc->pool, chunkSz))
244  return NULL;
245 
246  ret = &enc->chunks[enc->freeChunkId];
247  ret->poolOffset = Stream_GetPosition(enc->pool);
248  ret->capacity = chunkSz;
249  ret->used = commit ? chunkSz : 0;
250  if (id)
251  *id = enc->freeChunkId;
252 
253  enc->freeChunkId++;
254  Stream_Seek(enc->pool, chunkSz);
255  return ret;
256 }
257 
258 static WinPrAsn1EncContainer* asn1enc_get_free_container(WinPrAsn1Encoder* enc, size_t* id)
259 {
260  WinPrAsn1EncContainer* ret = NULL;
261  WINPR_ASSERT(enc);
262 
263  if (enc->freeContainerIndex == enc->containerCapacity)
264  {
265  /* containers need a resize (or switch from static to dynamic) */
266  WinPrAsn1EncContainer* src =
267  (enc->containers != &enc->staticContainers[0]) ? enc->containers : NULL;
268  WinPrAsn1EncContainer* tmp = realloc(src, (enc->containerCapacity + 10) * sizeof(*src));
269  if (!tmp)
270  return NULL;
271 
272  if (enc->containers == &enc->staticContainers[0])
273  memcpy(tmp, &enc->staticContainers[0], enc->containerCapacity * sizeof(*src));
274 
275  enc->containers = tmp;
276  enc->containerCapacity += 10;
277  }
278  if (enc->freeContainerIndex == enc->containerCapacity)
279  return NULL;
280 
281  ret = &enc->containers[enc->freeContainerIndex];
282  *id = enc->freeContainerIndex;
283 
284  enc->freeContainerIndex++;
285  return ret;
286 }
287 
288 static size_t lenBytes(size_t len)
289 {
290  if (len < 128)
291  return 1;
292  if (len < (1 << 8))
293  return 2;
294  if (len < (1 << 16))
295  return 3;
296  if (len < (1 << 24))
297  return 4;
298 
299  return 5;
300 }
301 
302 static void asn1WriteLen(wStream* s, size_t len)
303 {
304  if (len < 128)
305  {
306  Stream_Write_UINT8(s, (UINT8)len);
307  }
308  else if (len < (1 << 8))
309  {
310  Stream_Write_UINT8(s, 0x81);
311  Stream_Write_UINT8(s, (UINT8)len);
312  }
313  else if (len < (1 << 16))
314  {
315  Stream_Write_UINT8(s, 0x82);
316  Stream_Write_UINT16_BE(s, (UINT16)len);
317  }
318  else if (len < (1 << 24))
319  {
320  Stream_Write_UINT8(s, 0x83);
321  Stream_Write_UINT24_BE(s, (UINT32)len);
322  }
323  else
324  {
325  WINPR_ASSERT(len <= UINT32_MAX);
326  Stream_Write_UINT8(s, 0x84);
327  Stream_Write_UINT32_BE(s, (UINT32)len);
328  }
329 }
330 
331 static WinPrAsn1EncContainer* getAsn1Container(WinPrAsn1Encoder* enc, ContainerType ctype,
332  WinPrAsn1_tag tag, BOOL contextual, size_t maxLen)
333 {
334  size_t ret = 0;
335  size_t chunkId = 0;
336  WinPrAsn1EncContainer* container = NULL;
337 
338  Asn1Chunk* chunk = asn1enc_get_free_chunk(enc, maxLen, FALSE, &chunkId);
339  if (!chunk)
340  return NULL;
341 
342  container = asn1enc_get_free_container(enc, &ret);
343  container->containerType = ctype;
344  container->tag = tag;
345  container->contextual = contextual;
346  container->headerChunkId = chunkId;
347  return container;
348 }
349 
350 BOOL WinPrAsn1EncAppContainer(WinPrAsn1Encoder* enc, WinPrAsn1_tagId tagId)
351 {
352  WINPR_ASSERT_VALID_TAG(tagId);
353  return getAsn1Container(enc, ASN1_CONTAINER_APP, tagId, FALSE, 6) != NULL;
354 }
355 
356 BOOL WinPrAsn1EncSeqContainer(WinPrAsn1Encoder* enc)
357 {
358  return getAsn1Container(enc, ASN1_CONTAINER_SEQ, 0, FALSE, 6) != NULL;
359 }
360 
361 BOOL WinPrAsn1EncSetContainer(WinPrAsn1Encoder* enc)
362 {
363  return getAsn1Container(enc, ASN1_CONTAINER_SET, 0, FALSE, 6) != NULL;
364 }
365 
366 BOOL WinPrAsn1EncContextualSeqContainer(WinPrAsn1Encoder* enc, WinPrAsn1_tagId tagId)
367 {
368  return getAsn1Container(enc, ASN1_CONTAINER_SEQ, tagId, TRUE, 6 + 6) != NULL;
369 }
370 
371 BOOL WinPrAsn1EncContextualSetContainer(WinPrAsn1Encoder* enc, WinPrAsn1_tagId tagId)
372 {
373  return getAsn1Container(enc, ASN1_CONTAINER_SET, tagId, TRUE, 6 + 6) != NULL;
374 }
375 
376 BOOL WinPrAsn1EncContextualContainer(WinPrAsn1Encoder* enc, WinPrAsn1_tagId tagId)
377 {
378  return getAsn1Container(enc, ASN1_CONTAINER_CONTEXT_ONLY, tagId, TRUE, 6) != NULL;
379 }
380 
381 BOOL WinPrAsn1EncOctetStringContainer(WinPrAsn1Encoder* enc)
382 {
383  return getAsn1Container(enc, ASN1_CONTAINER_OCTETSTRING, 0, FALSE, 6) != NULL;
384 }
385 
386 BOOL WinPrAsn1EncContextualOctetStringContainer(WinPrAsn1Encoder* enc, WinPrAsn1_tagId tagId)
387 {
388  return getAsn1Container(enc, ASN1_CONTAINER_OCTETSTRING, tagId, TRUE, 6 + 6) != NULL;
389 }
390 
391 size_t WinPrAsn1EncEndContainer(WinPrAsn1Encoder* enc)
392 {
393  size_t innerLen = 0;
394  size_t unused = 0;
395  size_t innerHeaderBytes = 0;
396  size_t outerHeaderBytes = 0;
397  BYTE containerByte = 0;
398  WinPrAsn1EncContainer* container = NULL;
399  Asn1Chunk* chunk = NULL;
400  wStream staticS;
401  wStream* s = &staticS;
402 
403  WINPR_ASSERT(enc);
404  WINPR_ASSERT(enc->freeContainerIndex);
405 
406  /* compute inner length */
407  container = &enc->containers[enc->freeContainerIndex - 1];
408  innerLen = 0;
409  for (size_t i = container->headerChunkId + 1; i < enc->freeChunkId; i++)
410  innerLen += enc->chunks[i].used;
411 
412  /* compute effective headerLength */
413  switch (container->containerType)
414  {
415  case ASN1_CONTAINER_SEQ:
416  containerByte = ER_TAG_SEQUENCE;
417  innerHeaderBytes = 1 + lenBytes(innerLen);
418  break;
419  case ASN1_CONTAINER_SET:
420  containerByte = ER_TAG_SET;
421  innerHeaderBytes = 1 + lenBytes(innerLen);
422  break;
423  case ASN1_CONTAINER_OCTETSTRING:
424  containerByte = ER_TAG_OCTET_STRING;
425  innerHeaderBytes = 1 + lenBytes(innerLen);
426  break;
427  case ASN1_CONTAINER_APP:
428  containerByte = ER_TAG_APP | container->tag;
429  innerHeaderBytes = 1 + lenBytes(innerLen);
430  break;
431  case ASN1_CONTAINER_CONTEXT_ONLY:
432  innerHeaderBytes = 0;
433  break;
434  default:
435  WLog_ERR(TAG, "invalid containerType");
436  return 0;
437  }
438 
439  outerHeaderBytes = innerHeaderBytes;
440  if (container->contextual)
441  {
442  outerHeaderBytes = 1 + lenBytes(innerHeaderBytes + innerLen) + innerHeaderBytes;
443  }
444 
445  /* we write the headers at the end of the reserved space and we adjust
446  * the chunk to be a non reserved chunk */
447  chunk = &enc->chunks[container->headerChunkId];
448  unused = chunk->capacity - outerHeaderBytes;
449  chunk->poolOffset += unused;
450  chunk->capacity = chunk->used = outerHeaderBytes;
451 
452  Stream_StaticInit(s, Stream_Buffer(enc->pool) + chunk->poolOffset, outerHeaderBytes);
453  if (container->contextual)
454  {
455  Stream_Write_UINT8(s, ER_TAG_CONTEXTUAL | container->tag);
456  asn1WriteLen(s, innerHeaderBytes + innerLen);
457  }
458 
459  switch (container->containerType)
460  {
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);
467  break;
468  case ASN1_CONTAINER_CONTEXT_ONLY:
469  break;
470  default:
471  WLog_ERR(TAG, "invalid containerType");
472  return 0;
473  }
474 
475  /* TODO: here there is place for packing chunks */
476  enc->freeContainerIndex--;
477  return outerHeaderBytes + innerLen;
478 }
479 
480 static BOOL asn1_getWriteStream(WinPrAsn1Encoder* enc, size_t len, wStream* s)
481 {
482  BYTE* dest = NULL;
483  Asn1Chunk* chunk = asn1enc_get_free_chunk(enc, len, TRUE, NULL);
484  if (!chunk)
485  return FALSE;
486 
487  dest = Stream_Buffer(enc->pool) + chunk->poolOffset + chunk->capacity - len;
488  Stream_StaticInit(s, dest, len);
489  return TRUE;
490 }
491 
492 size_t WinPrAsn1EncRawContent(WinPrAsn1Encoder* enc, const WinPrAsn1_MemoryChunk* c)
493 {
494  wStream staticS;
495  wStream* s = &staticS;
496 
497  WINPR_ASSERT(enc);
498  WINPR_ASSERT(c);
499 
500  if (!asn1_getWriteStream(enc, c->len, s))
501  return 0;
502 
503  Stream_Write(s, c->data, c->len);
504  return c->len;
505 }
506 
507 size_t WinPrAsn1EncContextualRawContent(WinPrAsn1Encoder* enc, WinPrAsn1_tagId tagId,
508  const WinPrAsn1_MemoryChunk* c)
509 {
510  wStream staticS;
511  wStream* s = &staticS;
512 
513  WINPR_ASSERT(enc);
514  WINPR_ASSERT(c);
515  WINPR_ASSERT_VALID_TAG(tagId);
516 
517  size_t len = 1 + lenBytes(c->len) + c->len;
518  if (!asn1_getWriteStream(enc, len, s))
519  return 0;
520 
521  Stream_Write_UINT8(s, ER_TAG_CONTEXTUAL | tagId);
522  asn1WriteLen(s, c->len);
523 
524  Stream_Write(s, c->data, c->len);
525  return len;
526 }
527 
528 static size_t asn1IntegerLen(WinPrAsn1_INTEGER value)
529 {
530  if (value <= 127 && value >= -128)
531  return 2;
532  else if (value <= 32767 && value >= -32768)
533  return 3;
534  else
535  return 5;
536 }
537 
538 static size_t WinPrAsn1EncIntegerLike(WinPrAsn1Encoder* enc, WinPrAsn1_tag b,
539  WinPrAsn1_INTEGER value)
540 {
541  wStream staticS = { 0 };
542  wStream* s = &staticS;
543 
544  const size_t len = asn1IntegerLen(value);
545  if (!asn1_getWriteStream(enc, 1 + len, s))
546  return 0;
547 
548  Stream_Write_UINT8(s, b);
549  switch (len)
550  {
551  case 2:
552  Stream_Write_UINT8(s, 1);
553  Stream_Write_INT8(s, (INT8)value);
554  break;
555  case 3:
556  Stream_Write_UINT8(s, 2);
557  Stream_Write_INT16_BE(s, (INT16)value);
558  break;
559  case 5:
560  Stream_Write_UINT8(s, 4);
561  Stream_Write_INT32_BE(s, (INT32)value);
562  break;
563  default:
564  return 0;
565  }
566  return 1 + len;
567 }
568 
569 size_t WinPrAsn1EncInteger(WinPrAsn1Encoder* enc, WinPrAsn1_INTEGER value)
570 {
571  return WinPrAsn1EncIntegerLike(enc, ER_TAG_INTEGER, value);
572 }
573 
574 size_t WinPrAsn1EncEnumerated(WinPrAsn1Encoder* enc, WinPrAsn1_ENUMERATED value)
575 {
576  return WinPrAsn1EncIntegerLike(enc, ER_TAG_ENUMERATED, value);
577 }
578 
579 static size_t WinPrAsn1EncContextualIntegerLike(WinPrAsn1Encoder* enc, WinPrAsn1_tag tag,
580  WinPrAsn1_tagId tagId, WinPrAsn1_INTEGER value)
581 {
582  wStream staticS = { 0 };
583  wStream* s = &staticS;
584 
585  WINPR_ASSERT(enc);
586  WINPR_ASSERT_VALID_TAG(tagId);
587 
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))
591  return 0;
592 
593  Stream_Write_UINT8(s, ER_TAG_CONTEXTUAL | tagId);
594  asn1WriteLen(s, 1 + len);
595 
596  Stream_Write_UINT8(s, tag);
597  switch (len)
598  {
599  case 2:
600  Stream_Write_UINT8(s, 1);
601  Stream_Write_INT8(s, (INT8)value);
602  break;
603  case 3:
604  Stream_Write_UINT8(s, 2);
605  Stream_Write_INT16_BE(s, (INT16)value);
606  break;
607  case 5:
608  Stream_Write_UINT8(s, 4);
609  Stream_Write_INT32_BE(s, value);
610  break;
611  default:
612  return 0;
613  }
614  return outLen;
615 }
616 
617 size_t WinPrAsn1EncContextualInteger(WinPrAsn1Encoder* enc, WinPrAsn1_tagId tagId,
618  WinPrAsn1_INTEGER value)
619 {
620  return WinPrAsn1EncContextualIntegerLike(enc, ER_TAG_INTEGER, tagId, value);
621 }
622 
623 size_t WinPrAsn1EncContextualEnumerated(WinPrAsn1Encoder* enc, WinPrAsn1_tagId tagId,
624  WinPrAsn1_ENUMERATED value)
625 {
626  return WinPrAsn1EncContextualIntegerLike(enc, ER_TAG_ENUMERATED, tagId, value);
627 }
628 
629 size_t WinPrAsn1EncBoolean(WinPrAsn1Encoder* enc, WinPrAsn1_BOOL b)
630 {
631  wStream staticS;
632  wStream* s = &staticS;
633 
634  if (!asn1_getWriteStream(enc, 3, s))
635  return 0;
636 
637  Stream_Write_UINT8(s, ER_TAG_BOOLEAN);
638  Stream_Write_UINT8(s, 1);
639  Stream_Write_UINT8(s, b ? 0xff : 0);
640 
641  return 3;
642 }
643 
644 size_t WinPrAsn1EncContextualBoolean(WinPrAsn1Encoder* enc, WinPrAsn1_tagId tagId, WinPrAsn1_BOOL b)
645 {
646  wStream staticS;
647  wStream* s = &staticS;
648 
649  WINPR_ASSERT(enc);
650  WINPR_ASSERT_VALID_TAG(tagId);
651 
652  if (!asn1_getWriteStream(enc, 5, s))
653  return 0;
654 
655  Stream_Write_UINT8(s, ER_TAG_CONTEXTUAL | tagId);
656  Stream_Write_UINT8(s, 3);
657 
658  Stream_Write_UINT8(s, ER_TAG_BOOLEAN);
659  Stream_Write_UINT8(s, 1);
660  Stream_Write_UINT8(s, b ? 0xff : 0);
661 
662  return 5;
663 }
664 
665 static size_t WinPrAsn1EncMemoryChunk(WinPrAsn1Encoder* enc, BYTE wireType,
666  const WinPrAsn1_MemoryChunk* mchunk)
667 {
668  wStream s;
669  size_t len = 0;
670 
671  WINPR_ASSERT(enc);
672  WINPR_ASSERT(mchunk);
673  len = 1 + lenBytes(mchunk->len) + mchunk->len;
674 
675  if (!asn1_getWriteStream(enc, len, &s))
676  return 0;
677 
678  Stream_Write_UINT8(&s, wireType);
679  asn1WriteLen(&s, mchunk->len);
680  Stream_Write(&s, mchunk->data, mchunk->len);
681  return len;
682 }
683 
684 size_t WinPrAsn1EncOID(WinPrAsn1Encoder* enc, const WinPrAsn1_OID* oid)
685 {
686  return WinPrAsn1EncMemoryChunk(enc, ER_TAG_OBJECT_IDENTIFIER, oid);
687 }
688 
689 size_t WinPrAsn1EncOctetString(WinPrAsn1Encoder* enc, const WinPrAsn1_OctetString* octets)
690 {
691  return WinPrAsn1EncMemoryChunk(enc, ER_TAG_OCTET_STRING, octets);
692 }
693 
694 size_t WinPrAsn1EncIA5String(WinPrAsn1Encoder* enc, WinPrAsn1_IA5STRING ia5)
695 {
696  WinPrAsn1_MemoryChunk chunk;
697  WINPR_ASSERT(ia5);
698  chunk.data = (BYTE*)ia5;
699  chunk.len = strlen(ia5);
700  return WinPrAsn1EncMemoryChunk(enc, ER_TAG_IA5STRING, &chunk);
701 }
702 
703 size_t WinPrAsn1EncGeneralString(WinPrAsn1Encoder* enc, WinPrAsn1_STRING str)
704 {
705  WinPrAsn1_MemoryChunk chunk;
706  WINPR_ASSERT(str);
707  chunk.data = (BYTE*)str;
708  chunk.len = strlen(str);
709  return WinPrAsn1EncMemoryChunk(enc, ER_TAG_GENERAL_STRING, &chunk);
710 }
711 
712 static size_t WinPrAsn1EncContextualMemoryChunk(WinPrAsn1Encoder* enc, BYTE wireType,
713  WinPrAsn1_tagId tagId,
714  const WinPrAsn1_MemoryChunk* mchunk)
715 {
716  wStream s;
717  size_t len = 0;
718  size_t outLen = 0;
719 
720  WINPR_ASSERT(enc);
721  WINPR_ASSERT_VALID_TAG(tagId);
722  WINPR_ASSERT(mchunk);
723  len = 1 + lenBytes(mchunk->len) + mchunk->len;
724 
725  outLen = 1 + lenBytes(len) + len;
726  if (!asn1_getWriteStream(enc, outLen, &s))
727  return 0;
728 
729  Stream_Write_UINT8(&s, ER_TAG_CONTEXTUAL | tagId);
730  asn1WriteLen(&s, len);
731 
732  Stream_Write_UINT8(&s, wireType);
733  asn1WriteLen(&s, mchunk->len);
734  Stream_Write(&s, mchunk->data, mchunk->len);
735  return outLen;
736 }
737 
738 size_t WinPrAsn1EncContextualOID(WinPrAsn1Encoder* enc, WinPrAsn1_tagId tagId,
739  const WinPrAsn1_OID* oid)
740 {
741  return WinPrAsn1EncContextualMemoryChunk(enc, ER_TAG_OBJECT_IDENTIFIER, tagId, oid);
742 }
743 
744 size_t WinPrAsn1EncContextualOctetString(WinPrAsn1Encoder* enc, WinPrAsn1_tagId tagId,
745  const WinPrAsn1_OctetString* octets)
746 {
747  return WinPrAsn1EncContextualMemoryChunk(enc, ER_TAG_OCTET_STRING, tagId, octets);
748 }
749 
750 size_t WinPrAsn1EncContextualIA5String(WinPrAsn1Encoder* enc, WinPrAsn1_tagId tagId,
751  WinPrAsn1_IA5STRING ia5)
752 {
753  WinPrAsn1_MemoryChunk chunk;
754  WINPR_ASSERT(ia5);
755  chunk.data = (BYTE*)ia5;
756  chunk.len = strlen(ia5);
757 
758  return WinPrAsn1EncContextualMemoryChunk(enc, ER_TAG_IA5STRING, tagId, &chunk);
759 }
760 
761 static void write2digit(wStream* s, UINT8 v)
762 {
763  Stream_Write_UINT8(s, '0' + (v / 10));
764  Stream_Write_UINT8(s, '0' + (v % 10));
765 }
766 
767 size_t WinPrAsn1EncUtcTime(WinPrAsn1Encoder* enc, const WinPrAsn1_UTCTIME* utc)
768 {
769  wStream staticS = { 0 };
770  wStream* s = &staticS;
771 
772  WINPR_ASSERT(enc);
773  WINPR_ASSERT(utc);
774  WINPR_ASSERT(utc->year >= 2000);
775 
776  if (!asn1_getWriteStream(enc, 15, s))
777  return 0;
778 
779  Stream_Write_UINT8(s, ER_TAG_UTCTIME);
780  Stream_Write_UINT8(s, 13);
781 
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);
789  return 15;
790 }
791 
792 size_t WinPrAsn1EncContextualUtcTime(WinPrAsn1Encoder* enc, WinPrAsn1_tagId tagId,
793  const WinPrAsn1_UTCTIME* utc)
794 {
795  wStream staticS;
796  wStream* s = &staticS;
797 
798  WINPR_ASSERT(enc);
799  WINPR_ASSERT_VALID_TAG(tagId);
800  WINPR_ASSERT(utc);
801  WINPR_ASSERT(utc->year >= 2000);
802  WINPR_ASSERT(utc->year < 2256);
803 
804  if (!asn1_getWriteStream(enc, 17, s))
805  return 0;
806 
807  Stream_Write_UINT8(s, ER_TAG_CONTEXTUAL | tagId);
808  Stream_Write_UINT8(s, 15);
809 
810  Stream_Write_UINT8(s, ER_TAG_UTCTIME);
811  Stream_Write_UINT8(s, 13);
812 
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);
820 
821  return 17;
822 }
823 
824 BOOL WinPrAsn1EncStreamSize(WinPrAsn1Encoder* enc, size_t* s)
825 {
826  size_t finalSize = 0;
827 
828  WINPR_ASSERT(enc);
829  WINPR_ASSERT(s);
830 
831  if (enc->freeContainerIndex != 0)
832  {
833  WLog_ERR(TAG, "some container have not been closed");
834  return FALSE;
835  }
836 
837  for (size_t i = 0; i < enc->freeChunkId; i++)
838  finalSize += enc->chunks[i].used;
839  *s = finalSize;
840  return TRUE;
841 }
842 
843 BOOL WinPrAsn1EncToStream(WinPrAsn1Encoder* enc, wStream* s)
844 {
845  size_t finalSize = 0;
846 
847  WINPR_ASSERT(enc);
848  WINPR_ASSERT(s);
849 
850  if (!WinPrAsn1EncStreamSize(enc, &finalSize))
851  return FALSE;
852 
853  if (!Stream_EnsureRemainingCapacity(s, finalSize))
854  return FALSE;
855 
856  for (size_t i = 0; i < enc->freeChunkId; i++)
857  {
858  BYTE* src = Stream_Buffer(enc->pool) + enc->chunks[i].poolOffset;
859  Stream_Write(s, src, enc->chunks[i].used);
860  }
861 
862  return TRUE;
863 }
864 
865 void WinPrAsn1Decoder_Init(WinPrAsn1Decoder* decoder, WinPrAsn1EncodingRule encoding,
866  wStream* source)
867 {
868  WINPR_ASSERT(decoder);
869  WINPR_ASSERT(source);
870 
871  decoder->encoding = encoding;
872  memcpy(&decoder->source, source, sizeof(*source));
873 }
874 
875 void WinPrAsn1Decoder_InitMem(WinPrAsn1Decoder* decoder, WinPrAsn1EncodingRule encoding,
876  const BYTE* source, size_t len)
877 {
878  WINPR_ASSERT(decoder);
879  WINPR_ASSERT(source);
880 
881  decoder->encoding = encoding;
882  Stream_StaticConstInit(&decoder->source, source, len);
883 }
884 
885 BOOL WinPrAsn1DecPeekTag(WinPrAsn1Decoder* dec, WinPrAsn1_tag* tag)
886 {
887  WINPR_ASSERT(dec);
888  WINPR_ASSERT(tag);
889 
890  if (Stream_GetRemainingLength(&dec->source) < 1)
891  return FALSE;
892  Stream_Peek(&dec->source, tag, 1);
893  return TRUE;
894 }
895 
896 static size_t readLen(wStream* s, size_t* len, BOOL derCheck)
897 {
898  size_t retLen = 0;
899  size_t ret = 0;
900 
901  if (!Stream_CheckAndLogRequiredLength(TAG, s, 1))
902  return 0;
903 
904  Stream_Read_UINT8(s, retLen);
905  ret++;
906  if (retLen & 0x80)
907  {
908  BYTE tmp = 0;
909  size_t nBytes = (retLen & 0x7f);
910 
911  if (!Stream_CheckAndLogRequiredLength(TAG, s, nBytes))
912  return 0;
913 
914  ret += nBytes;
915  for (retLen = 0; nBytes; nBytes--)
916  {
917  Stream_Read_UINT8(s, tmp);
918  retLen = (retLen << 8) + tmp;
919  }
920 
921  if (derCheck)
922  {
923  /* check that the DER rule is respected, and that length encoding is optimal */
924  if (ret > 1 && retLen < 128)
925  return 0;
926  }
927  }
928 
929  *len = retLen;
930  return ret;
931 }
932 
933 static size_t readTagAndLen(WinPrAsn1Decoder* dec, wStream* s, WinPrAsn1_tag* tag, size_t* len)
934 {
935  size_t lenBytes = 0;
936 
937  if (Stream_GetRemainingLength(s) < 1)
938  return 0;
939 
940  Stream_Read(s, tag, 1);
941  lenBytes = readLen(s, len, (dec->encoding == WINPR_ASN1_DER));
942  if (lenBytes == 0)
943  return 0;
944 
945  return 1 + lenBytes;
946 }
947 
948 size_t WinPrAsn1DecReadTagAndLen(WinPrAsn1Decoder* dec, WinPrAsn1_tag* tag, size_t* len)
949 {
950  WINPR_ASSERT(dec);
951  WINPR_ASSERT(tag);
952  WINPR_ASSERT(len);
953 
954  return readTagAndLen(dec, &dec->source, tag, len);
955 }
956 
957 size_t WinPrAsn1DecPeekTagAndLen(WinPrAsn1Decoder* dec, WinPrAsn1_tag* tag, size_t* len)
958 {
959  wStream staticS;
960  wStream* s = &staticS;
961 
962  WINPR_ASSERT(dec);
963 
964  Stream_StaticConstInit(s, Stream_ConstPointer(&dec->source),
965  Stream_GetRemainingLength(&dec->source));
966  return readTagAndLen(dec, s, tag, len);
967 }
968 
969 size_t WinPrAsn1DecReadTagLenValue(WinPrAsn1Decoder* dec, WinPrAsn1_tag* tag, size_t* len,
970  WinPrAsn1Decoder* value)
971 {
972  size_t ret = 0;
973  WINPR_ASSERT(dec);
974  WINPR_ASSERT(tag);
975  WINPR_ASSERT(len);
976  WINPR_ASSERT(value);
977 
978  ret = readTagAndLen(dec, &dec->source, tag, len);
979  if (!ret)
980  return 0;
981 
982  if (!Stream_CheckAndLogRequiredLength(TAG, &dec->source, *len))
983  return 0;
984 
985  value->encoding = dec->encoding;
986  Stream_StaticInit(&value->source, Stream_Pointer(&dec->source), *len);
987  Stream_Seek(&dec->source, *len);
988  return ret + *len;
989 }
990 
991 size_t WinPrAsn1DecReadBoolean(WinPrAsn1Decoder* dec, WinPrAsn1_BOOL* target)
992 {
993  BYTE v = 0;
994  WinPrAsn1_tag tag = 0;
995  size_t len = 0;
996  size_t ret = 0;
997 
998  WINPR_ASSERT(dec);
999  WINPR_ASSERT(target);
1000 
1001  ret = readTagAndLen(dec, &dec->source, &tag, &len);
1002  if (!ret || tag != ER_TAG_BOOLEAN)
1003  return 0;
1004  if (Stream_GetRemainingLength(&dec->source) < len || len != 1)
1005  return 0;
1006 
1007  Stream_Read_UINT8(&dec->source, v);
1008  *target = !!v;
1009  return ret;
1010 }
1011 
1012 static size_t WinPrAsn1DecReadIntegerLike(WinPrAsn1Decoder* dec, WinPrAsn1_tag expectedTag,
1013  WinPrAsn1_INTEGER* target)
1014 {
1015  WinPrAsn1_tag tag = 0;
1016  size_t len = 0;
1017 
1018  WINPR_ASSERT(dec);
1019  WINPR_ASSERT(target);
1020 
1021  size_t ret = readTagAndLen(dec, &dec->source, &tag, &len);
1022  if (!ret || (tag != expectedTag))
1023  return 0;
1024  if (len == 0 || Stream_GetRemainingLength(&dec->source) < len || (len > 4))
1025  return 0;
1026 
1027  UINT32 uval = 0;
1028  UINT8 v = 0;
1029 
1030  Stream_Read_UINT8(&dec->source, v);
1031 
1032  /* extract sign from first byte.
1033  * the ASN integer might be smaller than 32bit so we need to set the initial
1034  * value to FF for all unused bytes (e.g. all except the lowest one we just read)
1035  */
1036  BOOL isNegative = (v & 0x80);
1037  if (isNegative)
1038  uval = 0xFFFFFF00;
1039  uval |= v;
1040 
1041  for (size_t x = 1; x < len; x++)
1042  {
1043  Stream_Read_UINT8(&dec->source, v);
1044  uval <<= 8;
1045  uval |= v;
1046  }
1047 
1048  *target = (WinPrAsn1_INTEGER)uval;
1049  ret += len;
1050 
1051  /* TODO: check ber/der rules */
1052  return ret;
1053 }
1054 
1055 size_t WinPrAsn1DecReadInteger(WinPrAsn1Decoder* dec, WinPrAsn1_INTEGER* target)
1056 {
1057  return WinPrAsn1DecReadIntegerLike(dec, ER_TAG_INTEGER, target);
1058 }
1059 
1060 size_t WinPrAsn1DecReadEnumerated(WinPrAsn1Decoder* dec, WinPrAsn1_ENUMERATED* target)
1061 {
1062  return WinPrAsn1DecReadIntegerLike(dec, ER_TAG_ENUMERATED, target);
1063 }
1064 
1065 static size_t WinPrAsn1DecReadMemoryChunkLike(WinPrAsn1Decoder* dec, WinPrAsn1_tag expectedTag,
1066  WinPrAsn1_MemoryChunk* target, BOOL allocate)
1067 {
1068  WinPrAsn1_tag tag = 0;
1069  size_t len = 0;
1070  size_t ret = 0;
1071 
1072  WINPR_ASSERT(dec);
1073  WINPR_ASSERT(target);
1074 
1075  ret = readTagAndLen(dec, &dec->source, &tag, &len);
1076  if (!ret || tag != expectedTag)
1077  return 0;
1078  if (!Stream_CheckAndLogRequiredLength(TAG, &dec->source, len))
1079  return 0;
1080 
1081  ret += len;
1082 
1083  target->len = len;
1084  if (allocate)
1085  {
1086  target->data = malloc(len);
1087  if (!target->data)
1088  return 0;
1089  Stream_Read(&dec->source, target->data, len);
1090  }
1091  else
1092  {
1093  target->data = Stream_Pointer(&dec->source);
1094  Stream_Seek(&dec->source, len);
1095  }
1096 
1097  return ret;
1098 }
1099 
1100 size_t WinPrAsn1DecReadOID(WinPrAsn1Decoder* dec, WinPrAsn1_OID* target, BOOL allocate)
1101 {
1102  return WinPrAsn1DecReadMemoryChunkLike(dec, ER_TAG_OBJECT_IDENTIFIER,
1103  (WinPrAsn1_MemoryChunk*)target, allocate);
1104 }
1105 
1106 size_t WinPrAsn1DecReadOctetString(WinPrAsn1Decoder* dec, WinPrAsn1_OctetString* target,
1107  BOOL allocate)
1108 {
1109  return WinPrAsn1DecReadMemoryChunkLike(dec, ER_TAG_OCTET_STRING, target, allocate);
1110 }
1111 
1112 size_t WinPrAsn1DecReadIA5String(WinPrAsn1Decoder* dec, WinPrAsn1_IA5STRING* target)
1113 {
1114  WinPrAsn1_tag tag = 0;
1115  size_t len = 0;
1116  size_t ret = 0;
1117  WinPrAsn1_IA5STRING s = NULL;
1118 
1119  WINPR_ASSERT(dec);
1120  WINPR_ASSERT(target);
1121 
1122  ret = readTagAndLen(dec, &dec->source, &tag, &len);
1123  if (!ret || tag != ER_TAG_IA5STRING)
1124  return 0;
1125  if (!Stream_CheckAndLogRequiredLength(TAG, &dec->source, len))
1126  return 0;
1127 
1128  ret += len;
1129 
1130  s = malloc(len + 1);
1131  if (!s)
1132  return 0;
1133  Stream_Read(&dec->source, s, len);
1134  s[len] = 0;
1135  *target = s;
1136  return ret;
1137 }
1138 
1139 size_t WinPrAsn1DecReadGeneralString(WinPrAsn1Decoder* dec, WinPrAsn1_STRING* target)
1140 {
1141  WinPrAsn1_tag tag = 0;
1142  size_t len = 0;
1143  size_t ret = 0;
1144  WinPrAsn1_IA5STRING s = NULL;
1145 
1146  WINPR_ASSERT(dec);
1147  WINPR_ASSERT(target);
1148 
1149  ret = readTagAndLen(dec, &dec->source, &tag, &len);
1150  if (!ret || tag != ER_TAG_GENERAL_STRING)
1151  return 0;
1152  if (!Stream_CheckAndLogRequiredLength(TAG, &dec->source, len))
1153  return 0;
1154 
1155  ret += len;
1156 
1157  s = malloc(len + 1);
1158  if (!s)
1159  return 0;
1160  Stream_Read(&dec->source, s, len);
1161  s[len] = 0;
1162  *target = s;
1163  return ret;
1164 }
1165 
1166 static int read2digits(wStream* s)
1167 {
1168  int ret = 0;
1169  char c = 0;
1170 
1171  Stream_Read_UINT8(s, c);
1172  if (c < '0' || c > '9')
1173  return -1;
1174 
1175  ret = (c - '0') * 10;
1176 
1177  Stream_Read_UINT8(s, c);
1178  if (c < '0' || c > '9')
1179  return -1;
1180 
1181  ret += (c - '0');
1182  return ret;
1183 }
1184 
1185 size_t WinPrAsn1DecReadUtcTime(WinPrAsn1Decoder* dec, WinPrAsn1_UTCTIME* target)
1186 {
1187  WinPrAsn1_tag tag = 0;
1188  size_t len = 0;
1189  size_t ret = 0;
1190  int v = 0;
1191  wStream sub;
1192  wStream* s = &sub;
1193 
1194  WINPR_ASSERT(dec);
1195  WINPR_ASSERT(target);
1196 
1197  ret = readTagAndLen(dec, &dec->source, &tag, &len);
1198  if (!ret || tag != ER_TAG_UTCTIME)
1199  return 0;
1200  if (!Stream_CheckAndLogRequiredLength(TAG, &dec->source, len) || len < 12)
1201  return 0;
1202 
1203  Stream_StaticConstInit(s, Stream_ConstPointer(&dec->source), len);
1204 
1205  v = read2digits(s);
1206  if (v <= 0)
1207  return 0;
1208  target->year = 2000 + v;
1209 
1210  v = read2digits(s);
1211  if (v <= 0)
1212  return 0;
1213  target->month = v;
1214 
1215  v = read2digits(s);
1216  if (v <= 0)
1217  return 0;
1218  target->day = v;
1219 
1220  v = read2digits(s);
1221  if (v <= 0)
1222  return 0;
1223  target->hour = v;
1224 
1225  v = read2digits(s);
1226  if (v <= 0)
1227  return 0;
1228  target->minute = v;
1229 
1230  v = read2digits(s);
1231  if (v <= 0)
1232  return 0;
1233  target->second = v;
1234 
1235  if (Stream_GetRemainingLength(s) >= 1)
1236  {
1237  Stream_Read_UINT8(s, target->tz);
1238  }
1239 
1240  Stream_Seek(&dec->source, len);
1241  ret += len;
1242 
1243  return ret;
1244 }
1245 
1246 size_t WinPrAsn1DecReadNull(WinPrAsn1Decoder* dec)
1247 {
1248  WinPrAsn1_tag tag = 0;
1249  size_t len = 0;
1250  size_t ret = 0;
1251 
1252  WINPR_ASSERT(dec);
1253 
1254  ret = readTagAndLen(dec, &dec->source, &tag, &len);
1255  if (!ret || tag != ER_TAG_NULL || len)
1256  return 0;
1257 
1258  return ret;
1259 }
1260 
1261 static size_t readConstructed(WinPrAsn1Decoder* dec, wStream* s, WinPrAsn1_tag* tag,
1262  WinPrAsn1Decoder* target)
1263 {
1264  size_t len = 0;
1265  size_t ret = 0;
1266 
1267  ret = readTagAndLen(dec, s, tag, &len);
1268  if (!ret || !Stream_CheckAndLogRequiredLength(TAG, s, len))
1269  return 0;
1270 
1271  target->encoding = dec->encoding;
1272  Stream_StaticConstInit(&target->source, Stream_ConstPointer(s), len);
1273  Stream_Seek(s, len);
1274  return ret + len;
1275 }
1276 
1277 size_t WinPrAsn1DecReadApp(WinPrAsn1Decoder* dec, WinPrAsn1_tagId* tagId, WinPrAsn1Decoder* target)
1278 {
1279  WinPrAsn1_tag tag = 0;
1280  size_t ret = 0;
1281 
1282  WINPR_ASSERT(dec);
1283  WINPR_ASSERT(target);
1284 
1285  ret = readConstructed(dec, &dec->source, &tag, target);
1286  if ((tag & ER_TAG_APP) != ER_TAG_APP)
1287  return 0;
1288 
1289  *tagId = (tag & ER_TAG_MASK);
1290  return ret;
1291 }
1292 
1293 size_t WinPrAsn1DecReadSequence(WinPrAsn1Decoder* dec, WinPrAsn1Decoder* target)
1294 {
1295  WinPrAsn1_tag tag = 0;
1296  size_t ret = 0;
1297 
1298  WINPR_ASSERT(dec);
1299  WINPR_ASSERT(target);
1300 
1301  ret = readConstructed(dec, &dec->source, &tag, target);
1302  if (tag != ER_TAG_SEQUENCE)
1303  return 0;
1304 
1305  return ret;
1306 }
1307 
1308 size_t WinPrAsn1DecReadSet(WinPrAsn1Decoder* dec, WinPrAsn1Decoder* target)
1309 {
1310  WinPrAsn1_tag tag = 0;
1311  size_t ret = 0;
1312 
1313  WINPR_ASSERT(dec);
1314  WINPR_ASSERT(target);
1315 
1316  ret = readConstructed(dec, &dec->source, &tag, target);
1317  if (tag != ER_TAG_SET)
1318  return 0;
1319 
1320  return ret;
1321 }
1322 
1323 static size_t readContextualTag(WinPrAsn1Decoder* dec, wStream* s, WinPrAsn1_tagId* tagId,
1324  WinPrAsn1Decoder* ctxtDec)
1325 {
1326  size_t ret = 0;
1327  WinPrAsn1_tag ftag = 0;
1328 
1329  ret = readConstructed(dec, s, &ftag, ctxtDec);
1330  if (!ret)
1331  return 0;
1332 
1333  if ((ftag & ER_TAG_CONTEXTUAL) != ER_TAG_CONTEXTUAL)
1334  return 0;
1335 
1336  *tagId = (ftag & ER_TAG_MASK);
1337  return ret;
1338 }
1339 
1340 size_t WinPrAsn1DecReadContextualTag(WinPrAsn1Decoder* dec, WinPrAsn1_tagId* tagId,
1341  WinPrAsn1Decoder* ctxtDec)
1342 {
1343  WINPR_ASSERT(dec);
1344  WINPR_ASSERT(tagId);
1345  WINPR_ASSERT(ctxtDec);
1346 
1347  return readContextualTag(dec, &dec->source, tagId, ctxtDec);
1348 }
1349 
1350 size_t WinPrAsn1DecPeekContextualTag(WinPrAsn1Decoder* dec, WinPrAsn1_tagId* tagId,
1351  WinPrAsn1Decoder* ctxtDec)
1352 {
1353  wStream staticS;
1354  WINPR_ASSERT(dec);
1355 
1356  Stream_StaticConstInit(&staticS, Stream_ConstPointer(&dec->source),
1357  Stream_GetRemainingLength(&dec->source));
1358  return readContextualTag(dec, &staticS, tagId, ctxtDec);
1359 }
1360 
1361 static size_t readContextualHeader(WinPrAsn1Decoder* dec, WinPrAsn1_tagId tagId, BOOL* error,
1362  WinPrAsn1Decoder* content)
1363 {
1364  WinPrAsn1_tag ftag = 0;
1365  size_t ret = 0;
1366 
1367  WINPR_ASSERT(dec);
1368  WINPR_ASSERT(error);
1369  WINPR_ASSERT(content);
1370 
1371  *error = TRUE;
1372  ret = WinPrAsn1DecPeekContextualTag(dec, &ftag, content);
1373  if (!ret)
1374  return 0;
1375 
1376  if (ftag != tagId)
1377  {
1378  *error = FALSE;
1379  return 0;
1380  }
1381 
1382  *error = FALSE;
1383  return ret;
1384 }
1385 
1386 size_t WinPrAsn1DecReadContextualBool(WinPrAsn1Decoder* dec, WinPrAsn1_tagId tagId, BOOL* error,
1387  WinPrAsn1_BOOL* target)
1388 {
1389  size_t ret = 0;
1390  size_t ret2 = 0;
1391  WinPrAsn1Decoder content;
1392 
1393  ret = readContextualHeader(dec, tagId, error, &content);
1394  if (!ret)
1395  return 0;
1396 
1397  ret2 = WinPrAsn1DecReadBoolean(&content, target);
1398  if (!ret2)
1399  {
1400  *error = TRUE;
1401  return 0;
1402  }
1403 
1404  Stream_Seek(&dec->source, ret);
1405  return ret;
1406 }
1407 
1408 size_t WinPrAsn1DecReadContextualInteger(WinPrAsn1Decoder* dec, WinPrAsn1_tagId tagId, BOOL* error,
1409  WinPrAsn1_INTEGER* target)
1410 {
1411  size_t ret = 0;
1412  size_t ret2 = 0;
1413  WinPrAsn1Decoder content;
1414 
1415  ret = readContextualHeader(dec, tagId, error, &content);
1416  if (!ret)
1417  return 0;
1418 
1419  ret2 = WinPrAsn1DecReadInteger(&content, target);
1420  if (!ret2)
1421  {
1422  *error = TRUE;
1423  return 0;
1424  }
1425 
1426  Stream_Seek(&dec->source, ret);
1427  return ret;
1428 }
1429 
1430 size_t WinPrAsn1DecReadContextualOID(WinPrAsn1Decoder* dec, WinPrAsn1_tagId tagId, BOOL* error,
1431  WinPrAsn1_OID* target, BOOL allocate)
1432 {
1433  size_t ret = 0;
1434  size_t ret2 = 0;
1435  WinPrAsn1Decoder content;
1436 
1437  ret = readContextualHeader(dec, tagId, error, &content);
1438  if (!ret)
1439  return 0;
1440 
1441  ret2 = WinPrAsn1DecReadOID(&content, target, allocate);
1442  if (!ret2)
1443  {
1444  *error = TRUE;
1445  return 0;
1446  }
1447 
1448  Stream_Seek(&dec->source, ret);
1449  return ret;
1450 }
1451 
1452 size_t WinPrAsn1DecReadContextualOctetString(WinPrAsn1Decoder* dec, WinPrAsn1_tagId tagId,
1453  BOOL* error, WinPrAsn1_OctetString* target,
1454  BOOL allocate)
1455 {
1456  size_t ret = 0;
1457  size_t ret2 = 0;
1458  WinPrAsn1Decoder content;
1459 
1460  ret = readContextualHeader(dec, tagId, error, &content);
1461  if (!ret)
1462  return 0;
1463 
1464  ret2 = WinPrAsn1DecReadOctetString(&content, target, allocate);
1465  if (!ret2)
1466  {
1467  *error = TRUE;
1468  return 0;
1469  }
1470 
1471  Stream_Seek(&dec->source, ret);
1472  return ret;
1473 }
1474 
1475 size_t WinPrAsn1DecReadContextualSequence(WinPrAsn1Decoder* dec, WinPrAsn1_tagId tagId, BOOL* error,
1476  WinPrAsn1Decoder* target)
1477 {
1478  size_t ret = 0;
1479  size_t ret2 = 0;
1480  WinPrAsn1Decoder content;
1481 
1482  ret = readContextualHeader(dec, tagId, error, &content);
1483  if (!ret)
1484  return 0;
1485 
1486  ret2 = WinPrAsn1DecReadSequence(&content, target);
1487  if (!ret2)
1488  {
1489  *error = TRUE;
1490  return 0;
1491  }
1492 
1493  Stream_Seek(&dec->source, ret);
1494  return ret;
1495 }
1496 
1497 wStream WinPrAsn1DecGetStream(WinPrAsn1Decoder* dec)
1498 {
1499  wStream s = { 0 };
1500  WINPR_ASSERT(dec);
1501 
1502  Stream_StaticConstInit(&s, Stream_ConstPointer(&dec->source),
1503  Stream_GetRemainingLength(&dec->source));
1504  return s;
1505 }