ber_tlv_length.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. /*-
  2. * Copyright (c) 2003, 2004 Lev Walkin <vlm@lionet.info>. All rights reserved.
  3. * Redistribution and modifications are permitted subject to BSD license.
  4. */
  5. #include <asn_internal.h>
  6. #include <ber_tlv_length.h>
  7. #include <ber_tlv_tag.h>
  8. ssize_t
  9. ber_fetch_length(int _is_constructed, const void *bufptr, size_t size,
  10. ber_tlv_len_t *len_r) {
  11. const uint8_t *buf = (const uint8_t *)bufptr;
  12. unsigned oct;
  13. if(size == 0)
  14. return 0; /* Want more */
  15. oct = *(const uint8_t *)buf;
  16. if((oct & 0x80) == 0) {
  17. /*
  18. * Short definite length.
  19. */
  20. *len_r = oct; /* & 0x7F */
  21. return 1;
  22. } else {
  23. ber_tlv_len_t len;
  24. size_t skipped;
  25. if(_is_constructed && oct == 0x80) {
  26. *len_r = -1; /* Indefinite length */
  27. return 1;
  28. }
  29. if(oct == 0xff) {
  30. /* Reserved in standard for future use. */
  31. return -1;
  32. }
  33. oct &= 0x7F; /* Leave only the 7 LS bits */
  34. for(len = 0, buf++, skipped = 1;
  35. oct && (++skipped <= size); buf++, oct--) {
  36. /* Verify that we won't overflow. */
  37. if(!(len >> ((8 * sizeof(len)) - (8+1)))) {
  38. len = (len << 8) | *buf;
  39. } else {
  40. /* Too large length value. */
  41. return -1;
  42. }
  43. }
  44. if(oct == 0) {
  45. if(len < 0 || len > RSSIZE_MAX) {
  46. /* Length value out of sane range. */
  47. return -1;
  48. }
  49. *len_r = len;
  50. return skipped;
  51. }
  52. return 0; /* Want more */
  53. }
  54. }
  55. ssize_t
  56. ber_skip_length(const asn_codec_ctx_t *opt_codec_ctx,
  57. int _is_constructed, const void *ptr, size_t size) {
  58. ber_tlv_len_t vlen; /* Length of V in TLV */
  59. ssize_t tl; /* Length of L in TLV */
  60. ssize_t ll; /* Length of L in TLV */
  61. size_t skip;
  62. /*
  63. * Make sure we didn't exceed the maximum stack size.
  64. */
  65. if(ASN__STACK_OVERFLOW_CHECK(opt_codec_ctx))
  66. return -1;
  67. /*
  68. * Determine the size of L in TLV.
  69. */
  70. ll = ber_fetch_length(_is_constructed, ptr, size, &vlen);
  71. if(ll <= 0) return ll;
  72. /*
  73. * Definite length.
  74. */
  75. if(vlen >= 0) {
  76. skip = ll + vlen;
  77. if(skip > size)
  78. return 0; /* Want more */
  79. return skip;
  80. }
  81. /*
  82. * Indefinite length!
  83. */
  84. ASN_DEBUG("Skipping indefinite length");
  85. for(skip = ll, ptr = ((const char *)ptr) + ll, size -= ll;;) {
  86. ber_tlv_tag_t tag;
  87. /* Fetch the tag */
  88. tl = ber_fetch_tag(ptr, size, &tag);
  89. if(tl <= 0) return tl;
  90. ll = ber_skip_length(opt_codec_ctx,
  91. BER_TLV_CONSTRUCTED(ptr),
  92. ((const char *)ptr) + tl, size - tl);
  93. if(ll <= 0) return ll;
  94. skip += tl + ll;
  95. /*
  96. * This may be the end of the indefinite length structure,
  97. * two consecutive 0 octets.
  98. * Check if it is true.
  99. */
  100. if(((const uint8_t *)ptr)[0] == 0
  101. && ((const uint8_t *)ptr)[1] == 0)
  102. return skip;
  103. ptr = ((const char *)ptr) + tl + ll;
  104. size -= tl + ll;
  105. }
  106. /* UNREACHABLE */
  107. }
  108. size_t
  109. der_tlv_length_serialize(ber_tlv_len_t len, void *bufp, size_t size) {
  110. size_t required_size; /* Size of len encoding */
  111. uint8_t *buf = (uint8_t *)bufp;
  112. uint8_t *end;
  113. int i;
  114. if(len <= 127) {
  115. /* Encoded in 1 octet */
  116. if(size) *buf = (uint8_t)len;
  117. return 1;
  118. }
  119. /*
  120. * Compute the size of the subsequent bytes.
  121. */
  122. for(required_size = 1, i = 8; i < 8 * (int)sizeof(len); i += 8) {
  123. if(len >> i)
  124. required_size++;
  125. else
  126. break;
  127. }
  128. if(size <= required_size)
  129. return required_size + 1;
  130. *buf++ = (uint8_t)(0x80 | required_size); /* Length of the encoding */
  131. /*
  132. * Produce the len encoding, space permitting.
  133. */
  134. end = buf + required_size;
  135. for(i -= 8; buf < end; i -= 8, buf++)
  136. *buf = (uint8_t)(len >> i);
  137. return required_size + 1;
  138. }