sshbuf-getput-basic.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634
  1. /* $OpenBSD: sshbuf-getput-basic.c,v 1.11 2020/06/05 03:25:35 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. #define SSHBUF_INTERNAL
  18. #include "includes.h"
  19. #include <sys/types.h>
  20. #include <stdarg.h>
  21. #include <stdlib.h>
  22. #include <stdio.h>
  23. #include <string.h>
  24. #ifdef HAVE_STDINT_H
  25. # include <stdint.h>
  26. #endif
  27. #include "ssherr.h"
  28. #include "sshbuf.h"
  29. int
  30. sshbuf_get(struct sshbuf *buf, void *v, size_t len)
  31. {
  32. const u_char *p = sshbuf_ptr(buf);
  33. int r;
  34. if ((r = sshbuf_consume(buf, len)) < 0)
  35. return r;
  36. if (v != NULL && len != 0)
  37. memcpy(v, p, len);
  38. return 0;
  39. }
  40. int
  41. sshbuf_get_u64(struct sshbuf *buf, u_int64_t *valp)
  42. {
  43. const u_char *p = sshbuf_ptr(buf);
  44. int r;
  45. if ((r = sshbuf_consume(buf, 8)) < 0)
  46. return r;
  47. if (valp != NULL)
  48. *valp = PEEK_U64(p);
  49. return 0;
  50. }
  51. int
  52. sshbuf_get_u32(struct sshbuf *buf, u_int32_t *valp)
  53. {
  54. const u_char *p = sshbuf_ptr(buf);
  55. int r;
  56. if ((r = sshbuf_consume(buf, 4)) < 0)
  57. return r;
  58. if (valp != NULL)
  59. *valp = PEEK_U32(p);
  60. return 0;
  61. }
  62. int
  63. sshbuf_get_u16(struct sshbuf *buf, u_int16_t *valp)
  64. {
  65. const u_char *p = sshbuf_ptr(buf);
  66. int r;
  67. if ((r = sshbuf_consume(buf, 2)) < 0)
  68. return r;
  69. if (valp != NULL)
  70. *valp = PEEK_U16(p);
  71. return 0;
  72. }
  73. int
  74. sshbuf_get_u8(struct sshbuf *buf, u_char *valp)
  75. {
  76. const u_char *p = sshbuf_ptr(buf);
  77. int r;
  78. if ((r = sshbuf_consume(buf, 1)) < 0)
  79. return r;
  80. if (valp != NULL)
  81. *valp = (u_int8_t)*p;
  82. return 0;
  83. }
  84. static int
  85. check_offset(const struct sshbuf *buf, int wr, size_t offset, size_t len)
  86. {
  87. if (sshbuf_ptr(buf) == NULL) /* calls sshbuf_check_sanity() */
  88. return SSH_ERR_INTERNAL_ERROR;
  89. if (offset >= SIZE_MAX - len)
  90. return SSH_ERR_INVALID_ARGUMENT;
  91. if (offset + len > sshbuf_len(buf)) {
  92. return wr ?
  93. SSH_ERR_NO_BUFFER_SPACE : SSH_ERR_MESSAGE_INCOMPLETE;
  94. }
  95. return 0;
  96. }
  97. static int
  98. check_roffset(const struct sshbuf *buf, size_t offset, size_t len,
  99. const u_char **p)
  100. {
  101. int r;
  102. *p = NULL;
  103. if ((r = check_offset(buf, 0, offset, len)) != 0)
  104. return r;
  105. *p = sshbuf_ptr(buf) + offset;
  106. return 0;
  107. }
  108. int
  109. sshbuf_peek_u64(const struct sshbuf *buf, size_t offset, u_int64_t *valp)
  110. {
  111. const u_char *p = NULL;
  112. int r;
  113. if (valp != NULL)
  114. *valp = 0;
  115. if ((r = check_roffset(buf, offset, 8, &p)) != 0)
  116. return r;
  117. if (valp != NULL)
  118. *valp = PEEK_U64(p);
  119. return 0;
  120. }
  121. int
  122. sshbuf_peek_u32(const struct sshbuf *buf, size_t offset, u_int32_t *valp)
  123. {
  124. const u_char *p = NULL;
  125. int r;
  126. if (valp != NULL)
  127. *valp = 0;
  128. if ((r = check_roffset(buf, offset, 4, &p)) != 0)
  129. return r;
  130. if (valp != NULL)
  131. *valp = PEEK_U32(p);
  132. return 0;
  133. }
  134. int
  135. sshbuf_peek_u16(const struct sshbuf *buf, size_t offset, u_int16_t *valp)
  136. {
  137. const u_char *p = NULL;
  138. int r;
  139. if (valp != NULL)
  140. *valp = 0;
  141. if ((r = check_roffset(buf, offset, 2, &p)) != 0)
  142. return r;
  143. if (valp != NULL)
  144. *valp = PEEK_U16(p);
  145. return 0;
  146. }
  147. int
  148. sshbuf_peek_u8(const struct sshbuf *buf, size_t offset, u_char *valp)
  149. {
  150. const u_char *p = NULL;
  151. int r;
  152. if (valp != NULL)
  153. *valp = 0;
  154. if ((r = check_roffset(buf, offset, 1, &p)) != 0)
  155. return r;
  156. if (valp != NULL)
  157. *valp = *p;
  158. return 0;
  159. }
  160. int
  161. sshbuf_get_string(struct sshbuf *buf, u_char **valp, size_t *lenp)
  162. {
  163. const u_char *val;
  164. size_t len;
  165. int r;
  166. if (valp != NULL)
  167. *valp = NULL;
  168. if (lenp != NULL)
  169. *lenp = 0;
  170. if ((r = sshbuf_get_string_direct(buf, &val, &len)) < 0)
  171. return r;
  172. if (valp != NULL) {
  173. if ((*valp = malloc(len + 1)) == NULL) {
  174. SSHBUF_DBG(("SSH_ERR_ALLOC_FAIL"));
  175. return SSH_ERR_ALLOC_FAIL;
  176. }
  177. if (len != 0)
  178. memcpy(*valp, val, len);
  179. (*valp)[len] = '\0';
  180. }
  181. if (lenp != NULL)
  182. *lenp = len;
  183. return 0;
  184. }
  185. int
  186. sshbuf_get_string_direct(struct sshbuf *buf, const u_char **valp, size_t *lenp)
  187. {
  188. size_t len;
  189. const u_char *p;
  190. int r;
  191. if (valp != NULL)
  192. *valp = NULL;
  193. if (lenp != NULL)
  194. *lenp = 0;
  195. if ((r = sshbuf_peek_string_direct(buf, &p, &len)) < 0)
  196. return r;
  197. if (valp != NULL)
  198. *valp = p;
  199. if (lenp != NULL)
  200. *lenp = len;
  201. if (sshbuf_consume(buf, len + 4) != 0) {
  202. /* Shouldn't happen */
  203. SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR"));
  204. SSHBUF_ABORT();
  205. return SSH_ERR_INTERNAL_ERROR;
  206. }
  207. return 0;
  208. }
  209. int
  210. sshbuf_peek_string_direct(const struct sshbuf *buf, const u_char **valp,
  211. size_t *lenp)
  212. {
  213. u_int32_t len;
  214. const u_char *p = sshbuf_ptr(buf);
  215. if (valp != NULL)
  216. *valp = NULL;
  217. if (lenp != NULL)
  218. *lenp = 0;
  219. if (sshbuf_len(buf) < 4) {
  220. SSHBUF_DBG(("SSH_ERR_MESSAGE_INCOMPLETE"));
  221. return SSH_ERR_MESSAGE_INCOMPLETE;
  222. }
  223. len = PEEK_U32(p);
  224. if (len > SSHBUF_SIZE_MAX - 4) {
  225. SSHBUF_DBG(("SSH_ERR_STRING_TOO_LARGE"));
  226. return SSH_ERR_STRING_TOO_LARGE;
  227. }
  228. if (sshbuf_len(buf) - 4 < len) {
  229. SSHBUF_DBG(("SSH_ERR_MESSAGE_INCOMPLETE"));
  230. return SSH_ERR_MESSAGE_INCOMPLETE;
  231. }
  232. if (valp != NULL)
  233. *valp = p + 4;
  234. if (lenp != NULL)
  235. *lenp = len;
  236. return 0;
  237. }
  238. int
  239. sshbuf_get_cstring(struct sshbuf *buf, char **valp, size_t *lenp)
  240. {
  241. size_t len;
  242. const u_char *p, *z;
  243. int r;
  244. if (valp != NULL)
  245. *valp = NULL;
  246. if (lenp != NULL)
  247. *lenp = 0;
  248. if ((r = sshbuf_peek_string_direct(buf, &p, &len)) != 0)
  249. return r;
  250. /* Allow a \0 only at the end of the string */
  251. if (len > 0 &&
  252. (z = memchr(p , '\0', len)) != NULL && z < p + len - 1) {
  253. SSHBUF_DBG(("SSH_ERR_INVALID_FORMAT"));
  254. return SSH_ERR_INVALID_FORMAT;
  255. }
  256. if ((r = sshbuf_skip_string(buf)) != 0)
  257. return -1;
  258. if (valp != NULL) {
  259. if ((*valp = malloc(len + 1)) == NULL) {
  260. SSHBUF_DBG(("SSH_ERR_ALLOC_FAIL"));
  261. return SSH_ERR_ALLOC_FAIL;
  262. }
  263. if (len != 0)
  264. memcpy(*valp, p, len);
  265. (*valp)[len] = '\0';
  266. }
  267. if (lenp != NULL)
  268. *lenp = (size_t)len;
  269. return 0;
  270. }
  271. int
  272. sshbuf_get_stringb(struct sshbuf *buf, struct sshbuf *v)
  273. {
  274. u_int32_t len;
  275. u_char *p;
  276. int r;
  277. /*
  278. * Use sshbuf_peek_string_direct() to figure out if there is
  279. * a complete string in 'buf' and copy the string directly
  280. * into 'v'.
  281. */
  282. if ((r = sshbuf_peek_string_direct(buf, NULL, NULL)) != 0 ||
  283. (r = sshbuf_get_u32(buf, &len)) != 0 ||
  284. (r = sshbuf_reserve(v, len, &p)) != 0 ||
  285. (r = sshbuf_get(buf, p, len)) != 0)
  286. return r;
  287. return 0;
  288. }
  289. int
  290. sshbuf_put(struct sshbuf *buf, const void *v, size_t len)
  291. {
  292. u_char *p;
  293. int r;
  294. if ((r = sshbuf_reserve(buf, len, &p)) < 0)
  295. return r;
  296. if (len != 0)
  297. memcpy(p, v, len);
  298. return 0;
  299. }
  300. int
  301. sshbuf_putb(struct sshbuf *buf, const struct sshbuf *v)
  302. {
  303. if (v == NULL)
  304. return 0;
  305. return sshbuf_put(buf, sshbuf_ptr(v), sshbuf_len(v));
  306. }
  307. int
  308. sshbuf_putf(struct sshbuf *buf, const char *fmt, ...)
  309. {
  310. va_list ap;
  311. int r;
  312. va_start(ap, fmt);
  313. r = sshbuf_putfv(buf, fmt, ap);
  314. va_end(ap);
  315. return r;
  316. }
  317. int
  318. sshbuf_putfv(struct sshbuf *buf, const char *fmt, va_list ap)
  319. {
  320. va_list ap2;
  321. int r, len;
  322. u_char *p;
  323. VA_COPY(ap2, ap);
  324. if ((len = vsnprintf(NULL, 0, fmt, ap2)) < 0) {
  325. r = SSH_ERR_INVALID_ARGUMENT;
  326. goto out;
  327. }
  328. if (len == 0) {
  329. r = 0;
  330. goto out; /* Nothing to do */
  331. }
  332. va_end(ap2);
  333. VA_COPY(ap2, ap);
  334. if ((r = sshbuf_reserve(buf, (size_t)len + 1, &p)) < 0)
  335. goto out;
  336. if ((r = vsnprintf((char *)p, len + 1, fmt, ap2)) != len) {
  337. r = SSH_ERR_INTERNAL_ERROR;
  338. goto out; /* Shouldn't happen */
  339. }
  340. /* Consume terminating \0 */
  341. if ((r = sshbuf_consume_end(buf, 1)) != 0)
  342. goto out;
  343. r = 0;
  344. out:
  345. va_end(ap2);
  346. return r;
  347. }
  348. int
  349. sshbuf_put_u64(struct sshbuf *buf, u_int64_t val)
  350. {
  351. u_char *p;
  352. int r;
  353. if ((r = sshbuf_reserve(buf, 8, &p)) < 0)
  354. return r;
  355. POKE_U64(p, val);
  356. return 0;
  357. }
  358. int
  359. sshbuf_put_u32(struct sshbuf *buf, u_int32_t val)
  360. {
  361. u_char *p;
  362. int r;
  363. if ((r = sshbuf_reserve(buf, 4, &p)) < 0)
  364. return r;
  365. POKE_U32(p, val);
  366. return 0;
  367. }
  368. int
  369. sshbuf_put_u16(struct sshbuf *buf, u_int16_t val)
  370. {
  371. u_char *p;
  372. int r;
  373. if ((r = sshbuf_reserve(buf, 2, &p)) < 0)
  374. return r;
  375. POKE_U16(p, val);
  376. return 0;
  377. }
  378. int
  379. sshbuf_put_u8(struct sshbuf *buf, u_char val)
  380. {
  381. u_char *p;
  382. int r;
  383. if ((r = sshbuf_reserve(buf, 1, &p)) < 0)
  384. return r;
  385. p[0] = val;
  386. return 0;
  387. }
  388. static int
  389. check_woffset(struct sshbuf *buf, size_t offset, size_t len, u_char **p)
  390. {
  391. int r;
  392. *p = NULL;
  393. if ((r = check_offset(buf, 1, offset, len)) != 0)
  394. return r;
  395. if (sshbuf_mutable_ptr(buf) == NULL)
  396. return SSH_ERR_BUFFER_READ_ONLY;
  397. *p = sshbuf_mutable_ptr(buf) + offset;
  398. return 0;
  399. }
  400. int
  401. sshbuf_poke_u64(struct sshbuf *buf, size_t offset, u_int64_t val)
  402. {
  403. u_char *p = NULL;
  404. int r;
  405. if ((r = check_woffset(buf, offset, 8, &p)) != 0)
  406. return r;
  407. POKE_U64(p, val);
  408. return 0;
  409. }
  410. int
  411. sshbuf_poke_u32(struct sshbuf *buf, size_t offset, u_int32_t val)
  412. {
  413. u_char *p = NULL;
  414. int r;
  415. if ((r = check_woffset(buf, offset, 4, &p)) != 0)
  416. return r;
  417. POKE_U32(p, val);
  418. return 0;
  419. }
  420. int
  421. sshbuf_poke_u16(struct sshbuf *buf, size_t offset, u_int16_t val)
  422. {
  423. u_char *p = NULL;
  424. int r;
  425. if ((r = check_woffset(buf, offset, 2, &p)) != 0)
  426. return r;
  427. POKE_U16(p, val);
  428. return 0;
  429. }
  430. int
  431. sshbuf_poke_u8(struct sshbuf *buf, size_t offset, u_char val)
  432. {
  433. u_char *p = NULL;
  434. int r;
  435. if ((r = check_woffset(buf, offset, 1, &p)) != 0)
  436. return r;
  437. *p = val;
  438. return 0;
  439. }
  440. int
  441. sshbuf_poke(struct sshbuf *buf, size_t offset, void *v, size_t len)
  442. {
  443. u_char *p = NULL;
  444. int r;
  445. if ((r = check_woffset(buf, offset, len, &p)) != 0)
  446. return r;
  447. memcpy(p, v, len);
  448. return 0;
  449. }
  450. int
  451. sshbuf_put_string(struct sshbuf *buf, const void *v, size_t len)
  452. {
  453. u_char *d;
  454. int r;
  455. if (len > SSHBUF_SIZE_MAX - 4) {
  456. SSHBUF_DBG(("SSH_ERR_NO_BUFFER_SPACE"));
  457. return SSH_ERR_NO_BUFFER_SPACE;
  458. }
  459. if ((r = sshbuf_reserve(buf, len + 4, &d)) < 0)
  460. return r;
  461. POKE_U32(d, len);
  462. if (len != 0)
  463. memcpy(d + 4, v, len);
  464. return 0;
  465. }
  466. int
  467. sshbuf_put_cstring(struct sshbuf *buf, const char *v)
  468. {
  469. return sshbuf_put_string(buf, v, v == NULL ? 0 : strlen(v));
  470. }
  471. int
  472. sshbuf_put_stringb(struct sshbuf *buf, const struct sshbuf *v)
  473. {
  474. if (v == NULL)
  475. return sshbuf_put_string(buf, NULL, 0);
  476. return sshbuf_put_string(buf, sshbuf_ptr(v), sshbuf_len(v));
  477. }
  478. int
  479. sshbuf_froms(struct sshbuf *buf, struct sshbuf **bufp)
  480. {
  481. const u_char *p;
  482. size_t len;
  483. struct sshbuf *ret;
  484. int r;
  485. if (buf == NULL || bufp == NULL)
  486. return SSH_ERR_INVALID_ARGUMENT;
  487. *bufp = NULL;
  488. if ((r = sshbuf_peek_string_direct(buf, &p, &len)) != 0)
  489. return r;
  490. if ((ret = sshbuf_from(p, len)) == NULL)
  491. return SSH_ERR_ALLOC_FAIL;
  492. if ((r = sshbuf_consume(buf, len + 4)) != 0 || /* Shouldn't happen */
  493. (r = sshbuf_set_parent(ret, buf)) != 0) {
  494. sshbuf_free(ret);
  495. return r;
  496. }
  497. *bufp = ret;
  498. return 0;
  499. }
  500. int
  501. sshbuf_put_bignum2_bytes(struct sshbuf *buf, const void *v, size_t len)
  502. {
  503. u_char *d;
  504. const u_char *s = (const u_char *)v;
  505. int r, prepend;
  506. if (len > SSHBUF_SIZE_MAX - 5) {
  507. SSHBUF_DBG(("SSH_ERR_NO_BUFFER_SPACE"));
  508. return SSH_ERR_NO_BUFFER_SPACE;
  509. }
  510. /* Skip leading zero bytes */
  511. for (; len > 0 && *s == 0; len--, s++)
  512. ;
  513. /*
  514. * If most significant bit is set then prepend a zero byte to
  515. * avoid interpretation as a negative number.
  516. */
  517. prepend = len > 0 && (s[0] & 0x80) != 0;
  518. if ((r = sshbuf_reserve(buf, len + 4 + prepend, &d)) < 0)
  519. return r;
  520. POKE_U32(d, len + prepend);
  521. if (prepend)
  522. d[4] = 0;
  523. if (len != 0)
  524. memcpy(d + 4 + prepend, s, len);
  525. return 0;
  526. }
  527. int
  528. sshbuf_get_bignum2_bytes_direct(struct sshbuf *buf,
  529. const u_char **valp, size_t *lenp)
  530. {
  531. const u_char *d;
  532. size_t len, olen;
  533. int r;
  534. if ((r = sshbuf_peek_string_direct(buf, &d, &olen)) < 0)
  535. return r;
  536. len = olen;
  537. /* Refuse negative (MSB set) bignums */
  538. if ((len != 0 && (*d & 0x80) != 0))
  539. return SSH_ERR_BIGNUM_IS_NEGATIVE;
  540. /* Refuse overlong bignums, allow prepended \0 to avoid MSB set */
  541. if (len > SSHBUF_MAX_BIGNUM + 1 ||
  542. (len == SSHBUF_MAX_BIGNUM + 1 && *d != 0))
  543. return SSH_ERR_BIGNUM_TOO_LARGE;
  544. /* Trim leading zeros */
  545. while (len > 0 && *d == 0x00) {
  546. d++;
  547. len--;
  548. }
  549. if (valp != NULL)
  550. *valp = d;
  551. if (lenp != NULL)
  552. *lenp = len;
  553. if (sshbuf_consume(buf, olen + 4) != 0) {
  554. /* Shouldn't happen */
  555. SSHBUF_DBG(("SSH_ERR_INTERNAL_ERROR"));
  556. SSHBUF_ABORT();
  557. return SSH_ERR_INTERNAL_ERROR;
  558. }
  559. return 0;
  560. }