oer_support.c 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. /*
  2. * Copyright (c) 2017 Lev Walkin <vlm@lionet.info>.
  3. * All rights reserved.
  4. * Redistribution and modifications are permitted subject to BSD license.
  5. */
  6. #include <asn_system.h>
  7. #include <asn_internal.h>
  8. #include <oer_support.h>
  9. /*
  10. * Fetch the length determinant (X.696 08/2015, #8.6) into *len_r.
  11. * RETURN VALUES:
  12. * 0: More data expected than bufptr contains.
  13. * -1: Fatal error deciphering length.
  14. * >0: Number of bytes used from bufptr.
  15. */
  16. ssize_t
  17. oer_fetch_length(const void *bufptr, size_t size, size_t *len_r) {
  18. uint8_t first_byte;
  19. size_t len_len; /* Length of the length determinant */
  20. const uint8_t *b;
  21. const uint8_t *bend;
  22. size_t len;
  23. if(size == 0) {
  24. *len_r = 0;
  25. return 0;
  26. }
  27. first_byte = *(const uint8_t *)bufptr;
  28. if((first_byte & 0x80) == 0) { /* Short form */
  29. *len_r = first_byte; /* 0..127 */
  30. return 1;
  31. }
  32. len_len = (first_byte & 0x7f);
  33. if((1 + len_len) > size) {
  34. *len_r = 0;
  35. return 0;
  36. }
  37. b = (const uint8_t *)bufptr + 1;
  38. bend = b + len_len;
  39. for(; b < bend && *b == 0; b++) {
  40. /* Skip the leading 0-bytes */
  41. }
  42. if((bend - b) > (ssize_t)sizeof(size_t)) {
  43. /* Length is not representable by the native size_t type */
  44. *len_r = 0;
  45. return -1;
  46. }
  47. for(len = 0; b < bend; b++) {
  48. len = (len << 8) + *b;
  49. }
  50. if(len > RSIZE_MAX) { /* A bit of C11 validation */
  51. *len_r = 0;
  52. return -1;
  53. }
  54. *len_r = len;
  55. assert(len_len + 1 == (size_t)(bend - (const uint8_t *)bufptr));
  56. return len_len + 1;
  57. }
  58. /*
  59. * Serialize OER length. Returns the number of bytes serialized
  60. * or -1 if a given callback returned with negative result.
  61. */
  62. ssize_t
  63. oer_serialize_length(size_t length, asn_app_consume_bytes_f *cb,
  64. void *app_key) {
  65. uint8_t scratch[1 + sizeof(length)];
  66. uint8_t *sp = scratch;
  67. int littleEndian = 1; /* Run-time detection */
  68. const uint8_t *pstart;
  69. const uint8_t *pend;
  70. const uint8_t *p;
  71. int add;
  72. if(length <= 127) {
  73. uint8_t b = length;
  74. if(cb(&b, 1, app_key) < 0) {
  75. return -1;
  76. }
  77. return 1;
  78. }
  79. if(*(char *)&littleEndian) {
  80. pstart = (const uint8_t *)&length + sizeof(length) - 1;
  81. pend = (const uint8_t *)&length;
  82. add = -1;
  83. } else {
  84. pstart = (const uint8_t *)&length;
  85. pend = pstart + sizeof(length);
  86. add = 1;
  87. }
  88. for(p = pstart; p != pend; p += add) {
  89. /* Skip leading zeros. */
  90. if(*p) break;
  91. }
  92. for(sp = scratch + 1; ; p += add) {
  93. *sp++ = *p;
  94. if(p == pend) break;
  95. }
  96. assert((sp - scratch) - 1 <= 0x7f);
  97. scratch[0] = 0x80 + ((sp - scratch) - 1);
  98. if(cb(scratch, sp - scratch, app_key) < 0) {
  99. return -1;
  100. }
  101. return sp - scratch;
  102. }