ssh_decode_sequence_multi.c 4.6 KB

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