ssh_decode_sequence_multi.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. /* LibTomCrypt, modular cryptographic library -- Tom St Denis */
  2. /* SPDX-License-Identifier: Unlicense */
  3. #include "tomcrypt_private.h"
  4. #include <stdarg.h>
  5. /**
  6. @file ssh_decode_sequence_multi.c
  7. SSH data type representation as per RFC4251, Russ Williams
  8. */
  9. #ifdef LTC_SSH
  10. /**
  11. Decode a SSH sequence using a VA list
  12. @param in The input buffer
  13. @param inlen [in/out] The length of the input buffer and on output the amount of decoded data
  14. @remark <...> is of the form <type, data*> (int, <unsigned char*,ulong32*,ulong64*>) except for string&name-list <type, data, size*> (int, void*, unsigned long*)
  15. @return CRYPT_OK on success
  16. */
  17. int ssh_decode_sequence_multi(const unsigned char *in, unsigned long *inlen, ...)
  18. {
  19. int err;
  20. va_list args;
  21. ssh_data_type type;
  22. void *vdata;
  23. unsigned char *cdata;
  24. char *sdata;
  25. ulong32 *u32data;
  26. ulong64 *u64data;
  27. unsigned long *bufsize;
  28. ulong32 size;
  29. unsigned long remaining;
  30. LTC_ARGCHK(in != NULL);
  31. LTC_ARGCHK(inlen != NULL);
  32. remaining = *inlen;
  33. /* Decode values from buffer */
  34. va_start(args, inlen);
  35. while ((type = (ssh_data_type)va_arg(args, int)) != LTC_SSHDATA_EOL) {
  36. /* Size of length field */
  37. if (type == LTC_SSHDATA_STRING ||
  38. type == LTC_SSHDATA_NAMELIST ||
  39. type == LTC_SSHDATA_MPINT)
  40. {
  41. /* Check we'll not read too far */
  42. if (remaining < 4) {
  43. err = CRYPT_BUFFER_OVERFLOW;
  44. goto error;
  45. }
  46. }
  47. /* Calculate (or read) length of data */
  48. size = 0xFFFFFFFFU;
  49. switch (type) {
  50. case LTC_SSHDATA_BYTE:
  51. case LTC_SSHDATA_BOOLEAN:
  52. size = 1;
  53. break;
  54. case LTC_SSHDATA_UINT32:
  55. size = 4;
  56. break;
  57. case LTC_SSHDATA_UINT64:
  58. size = 8;
  59. break;
  60. case LTC_SSHDATA_STRING:
  61. case LTC_SSHDATA_NAMELIST:
  62. case LTC_SSHDATA_MPINT:
  63. LOAD32H(size, in);
  64. in += 4;
  65. remaining -= 4;
  66. break;
  67. case LTC_SSHDATA_EOL:
  68. /* Should never get here */
  69. err = CRYPT_INVALID_ARG;
  70. goto error;
  71. }
  72. /* Check we'll not read too far */
  73. if (remaining < size) {
  74. err = CRYPT_BUFFER_OVERFLOW;
  75. goto error;
  76. } else {
  77. remaining -= size;
  78. }
  79. vdata = va_arg(args, void*);
  80. if (vdata == NULL) {
  81. err = CRYPT_INVALID_ARG;
  82. goto error;
  83. }
  84. /* Read data */
  85. switch (type) {
  86. case LTC_SSHDATA_BYTE:
  87. cdata = vdata;
  88. *cdata = *in++;
  89. break;
  90. case LTC_SSHDATA_BOOLEAN:
  91. cdata = vdata;
  92. /*
  93. The value 0 represents FALSE, and the value 1 represents TRUE. All non-zero values MUST be
  94. interpreted as TRUE; however, applications MUST NOT store values other than 0 and 1.
  95. */
  96. *cdata = (*in++)?1:0;
  97. break;
  98. case LTC_SSHDATA_UINT32:
  99. u32data = vdata;
  100. LOAD32H(*u32data, in);
  101. in += 4;
  102. break;
  103. case LTC_SSHDATA_UINT64:
  104. u64data = vdata;
  105. LOAD64H(*u64data, in);
  106. in += 8;
  107. break;
  108. case LTC_SSHDATA_STRING:
  109. case LTC_SSHDATA_NAMELIST:
  110. sdata = vdata;
  111. bufsize = va_arg(args, unsigned long*);
  112. if (bufsize == NULL) {
  113. err = CRYPT_INVALID_ARG;
  114. goto error;
  115. }
  116. if (size + 1 >= *bufsize) {
  117. err = CRYPT_BUFFER_OVERFLOW;
  118. goto error;
  119. }
  120. if (size > 0) {
  121. XMEMCPY(sdata, (const char *)in, size);
  122. }
  123. sdata[size] = '\0';
  124. *bufsize = size;
  125. in += size;
  126. break;
  127. case LTC_SSHDATA_MPINT:
  128. if (size == 0) {
  129. if ((err = mp_set(vdata, 0)) != CRYPT_OK) { goto error; }
  130. } else if ((in[0] & 0x80) != 0) {
  131. /* Negative number - not supported */
  132. err = CRYPT_INVALID_PACKET;
  133. goto error;
  134. } else {
  135. if ((err = mp_read_unsigned_bin(vdata, in, size)) != CRYPT_OK) { goto error; }
  136. }
  137. in += size;
  138. break;
  139. case LTC_SSHDATA_EOL:
  140. /* Should never get here */
  141. err = CRYPT_INVALID_ARG;
  142. goto error;
  143. }
  144. }
  145. err = CRYPT_OK;
  146. *inlen -= remaining;
  147. error:
  148. va_end(args);
  149. return err;
  150. }
  151. #endif