sshbuf-misc.c 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. /* $OpenBSD: sshbuf-misc.c,v 1.16 2020/06/22 05:54:10 djm Exp $ */
  2. /*
  3. * Copyright (c) 2011 Damien Miller
  4. *
  5. * Permission to use, copy, modify, and distribute this software for any
  6. * purpose with or without fee is hereby granted, provided that the above
  7. * copyright notice and this permission notice appear in all copies.
  8. *
  9. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  10. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  11. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  12. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  13. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  14. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  15. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  16. */
  17. #include "includes.h"
  18. #include <sys/types.h>
  19. #include <sys/socket.h>
  20. #include <netinet/in.h>
  21. #include <errno.h>
  22. #include <stdlib.h>
  23. #ifdef HAVE_STDINT_H
  24. # include <stdint.h>
  25. #endif
  26. #include <stdio.h>
  27. #include <limits.h>
  28. #include <string.h>
  29. #include <resolv.h>
  30. #include <ctype.h>
  31. #include "ssherr.h"
  32. #define SSHBUF_INTERNAL
  33. #include "sshbuf.h"
  34. void
  35. sshbuf_dump_data(const void *s, size_t len, FILE *f)
  36. {
  37. size_t i, j;
  38. const u_char *p = (const u_char *)s;
  39. for (i = 0; i < len; i += 16) {
  40. fprintf(f, "%.4zu: ", i);
  41. for (j = i; j < i + 16; j++) {
  42. if (j < len)
  43. fprintf(f, "%02x ", p[j]);
  44. else
  45. fprintf(f, " ");
  46. }
  47. fprintf(f, " ");
  48. for (j = i; j < i + 16; j++) {
  49. if (j < len) {
  50. if (isascii(p[j]) && isprint(p[j]))
  51. fprintf(f, "%c", p[j]);
  52. else
  53. fprintf(f, ".");
  54. }
  55. }
  56. fprintf(f, "\n");
  57. }
  58. }
  59. void
  60. sshbuf_dump(const struct sshbuf *buf, FILE *f)
  61. {
  62. fprintf(f, "buffer %p len = %zu\n", buf, sshbuf_len(buf));
  63. sshbuf_dump_data(sshbuf_ptr(buf), sshbuf_len(buf), f);
  64. }
  65. char *
  66. sshbuf_dtob16(struct sshbuf *buf)
  67. {
  68. size_t i, j, len = sshbuf_len(buf);
  69. const u_char *p = sshbuf_ptr(buf);
  70. char *ret;
  71. const char hex[] = "0123456789abcdef";
  72. if (len == 0)
  73. return strdup("");
  74. if (SIZE_MAX / 2 <= len || (ret = malloc(len * 2 + 1)) == NULL)
  75. return NULL;
  76. for (i = j = 0; i < len; i++) {
  77. ret[j++] = hex[(p[i] >> 4) & 0xf];
  78. ret[j++] = hex[p[i] & 0xf];
  79. }
  80. ret[j] = '\0';
  81. return ret;
  82. }
  83. int
  84. sshbuf_dtob64(const struct sshbuf *d, struct sshbuf *b64, int wrap)
  85. {
  86. size_t i, slen = 0;
  87. char *s = NULL;
  88. int r;
  89. if (d == NULL || b64 == NULL || sshbuf_len(d) >= SIZE_MAX / 2)
  90. return SSH_ERR_INVALID_ARGUMENT;
  91. if (sshbuf_len(d) == 0)
  92. return 0;
  93. slen = ((sshbuf_len(d) + 2) / 3) * 4 + 1;
  94. if ((s = malloc(slen)) == NULL)
  95. return SSH_ERR_ALLOC_FAIL;
  96. if (b64_ntop(sshbuf_ptr(d), sshbuf_len(d), s, slen) == -1) {
  97. r = SSH_ERR_INTERNAL_ERROR;
  98. goto fail;
  99. }
  100. if (wrap) {
  101. for (i = 0; s[i] != '\0'; i++) {
  102. if ((r = sshbuf_put_u8(b64, s[i])) != 0)
  103. goto fail;
  104. if (i % 70 == 69 && (r = sshbuf_put_u8(b64, '\n')) != 0)
  105. goto fail;
  106. }
  107. if ((i - 1) % 70 != 69 && (r = sshbuf_put_u8(b64, '\n')) != 0)
  108. goto fail;
  109. } else {
  110. if ((r = sshbuf_put(b64, s, strlen(s))) != 0)
  111. goto fail;
  112. }
  113. /* Success */
  114. r = 0;
  115. fail:
  116. freezero(s, slen);
  117. return r;
  118. }
  119. char *
  120. sshbuf_dtob64_string(const struct sshbuf *buf, int wrap)
  121. {
  122. struct sshbuf *tmp;
  123. char *ret;
  124. if ((tmp = sshbuf_new()) == NULL)
  125. return NULL;
  126. if (sshbuf_dtob64(buf, tmp, wrap) != 0) {
  127. sshbuf_free(tmp);
  128. return NULL;
  129. }
  130. ret = sshbuf_dup_string(tmp);
  131. sshbuf_free(tmp);
  132. return ret;
  133. }
  134. int
  135. sshbuf_b64tod(struct sshbuf *buf, const char *b64)
  136. {
  137. size_t plen = strlen(b64);
  138. int nlen, r;
  139. u_char *p;
  140. if (plen == 0)
  141. return 0;
  142. if ((p = malloc(plen)) == NULL)
  143. return SSH_ERR_ALLOC_FAIL;
  144. if ((nlen = b64_pton(b64, p, plen)) < 0) {
  145. freezero(p, plen);
  146. return SSH_ERR_INVALID_FORMAT;
  147. }
  148. if ((r = sshbuf_put(buf, p, nlen)) < 0) {
  149. freezero(p, plen);
  150. return r;
  151. }
  152. freezero(p, plen);
  153. return 0;
  154. }
  155. int
  156. sshbuf_dtourlb64(const struct sshbuf *d, struct sshbuf *b64, int wrap)
  157. {
  158. int r = SSH_ERR_INTERNAL_ERROR;
  159. u_char *p;
  160. struct sshbuf *b = NULL;
  161. size_t i, l;
  162. if ((b = sshbuf_new()) == NULL)
  163. return SSH_ERR_ALLOC_FAIL;
  164. /* Encode using regular base64; we'll transform it once done */
  165. if ((r = sshbuf_dtob64(d, b, wrap)) != 0)
  166. goto out;
  167. /* remove padding from end of encoded string*/
  168. for (;;) {
  169. l = sshbuf_len(b);
  170. if (l <= 1 || sshbuf_ptr(b) == NULL) {
  171. r = SSH_ERR_INTERNAL_ERROR;
  172. goto out;
  173. }
  174. if (sshbuf_ptr(b)[l - 1] != '=')
  175. break;
  176. if ((r = sshbuf_consume_end(b, 1)) != 0)
  177. goto out;
  178. }
  179. /* Replace characters with rfc4648 equivalents */
  180. l = sshbuf_len(b);
  181. if ((p = sshbuf_mutable_ptr(b)) == NULL) {
  182. r = SSH_ERR_INTERNAL_ERROR;
  183. goto out;
  184. }
  185. for (i = 0; i < l; i++) {
  186. if (p[i] == '+')
  187. p[i] = '-';
  188. else if (p[i] == '/')
  189. p[i] = '_';
  190. }
  191. r = sshbuf_putb(b64, b);
  192. out:
  193. sshbuf_free(b);
  194. return r;
  195. }
  196. char *
  197. sshbuf_dup_string(struct sshbuf *buf)
  198. {
  199. const u_char *p = NULL, *s = sshbuf_ptr(buf);
  200. size_t l = sshbuf_len(buf);
  201. char *r;
  202. if (s == NULL || l > SIZE_MAX)
  203. return NULL;
  204. /* accept a nul only as the last character in the buffer */
  205. if (l > 0 && (p = memchr(s, '\0', l)) != NULL) {
  206. if (p != s + l - 1)
  207. return NULL;
  208. l--; /* the nul is put back below */
  209. }
  210. if ((r = malloc(l + 1)) == NULL)
  211. return NULL;
  212. if (l > 0)
  213. memcpy(r, s, l);
  214. r[l] = '\0';
  215. return r;
  216. }
  217. int
  218. sshbuf_cmp(const struct sshbuf *b, size_t offset,
  219. const void *s, size_t len)
  220. {
  221. if (sshbuf_ptr(b) == NULL)
  222. return SSH_ERR_INTERNAL_ERROR;
  223. if (offset > SSHBUF_SIZE_MAX || len > SSHBUF_SIZE_MAX || len == 0)
  224. return SSH_ERR_INVALID_ARGUMENT;
  225. if (offset + len > sshbuf_len(b))
  226. return SSH_ERR_MESSAGE_INCOMPLETE;
  227. if (timingsafe_bcmp(sshbuf_ptr(b) + offset, s, len) != 0)
  228. return SSH_ERR_INVALID_FORMAT;
  229. return 0;
  230. }
  231. int
  232. sshbuf_find(const struct sshbuf *b, size_t start_offset,
  233. const void *s, size_t len, size_t *offsetp)
  234. {
  235. void *p;
  236. if (offsetp != NULL)
  237. *offsetp = 0;
  238. if (sshbuf_ptr(b) == NULL)
  239. return SSH_ERR_INTERNAL_ERROR;
  240. if (start_offset > SSHBUF_SIZE_MAX || len > SSHBUF_SIZE_MAX || len == 0)
  241. return SSH_ERR_INVALID_ARGUMENT;
  242. if (start_offset > sshbuf_len(b) || start_offset + len > sshbuf_len(b))
  243. return SSH_ERR_MESSAGE_INCOMPLETE;
  244. if ((p = memmem(sshbuf_ptr(b) + start_offset,
  245. sshbuf_len(b) - start_offset, s, len)) == NULL)
  246. return SSH_ERR_INVALID_FORMAT;
  247. if (offsetp != NULL)
  248. *offsetp = (const u_char *)p - sshbuf_ptr(b);
  249. return 0;
  250. }