ssh_encode_sequence_multi.c 4.7 KB

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