Annotation of src/usr.bin/ssh/sshbuf-misc.c, Revision 1.12
1.12 ! djm 1: /* $OpenBSD: sshbuf-misc.c,v 1.11 2019/07/30 05:04:49 djm Exp $ */
1.1 djm 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:
18: #include <sys/types.h>
19: #include <sys/socket.h>
1.12 ! djm 20: #include <sys/stat.h>
1.1 djm 21: #include <netinet/in.h>
1.12 ! djm 22:
! 23: #include <ctype.h>
1.1 djm 24: #include <errno.h>
1.12 ! djm 25: #include <fcntl.h>
! 26: #include <limits.h>
! 27: #include <resolv.h>
1.3 millert 28: #include <stdint.h>
1.1 djm 29: #include <stdio.h>
1.12 ! djm 30: #include <stdlib.h>
1.1 djm 31: #include <string.h>
1.12 ! djm 32: #include <unistd.h>
1.1 djm 33:
34: #include "ssherr.h"
35: #define SSHBUF_INTERNAL
36: #include "sshbuf.h"
1.12 ! djm 37: #include "atomicio.h"
1.1 djm 38:
39: void
1.2 djm 40: sshbuf_dump_data(const void *s, size_t len, FILE *f)
1.1 djm 41: {
1.2 djm 42: size_t i, j;
43: const u_char *p = (const u_char *)s;
1.1 djm 44:
45: for (i = 0; i < len; i += 16) {
1.4 markus 46: fprintf(f, "%.4zu: ", i);
1.1 djm 47: for (j = i; j < i + 16; j++) {
48: if (j < len)
49: fprintf(f, "%02x ", p[j]);
50: else
51: fprintf(f, " ");
52: }
53: fprintf(f, " ");
54: for (j = i; j < i + 16; j++) {
55: if (j < len) {
56: if (isascii(p[j]) && isprint(p[j]))
57: fprintf(f, "%c", p[j]);
58: else
59: fprintf(f, ".");
60: }
61: }
62: fprintf(f, "\n");
63: }
1.2 djm 64: }
65:
66: void
67: sshbuf_dump(struct sshbuf *buf, FILE *f)
68: {
69: fprintf(f, "buffer %p len = %zu\n", buf, sshbuf_len(buf));
70: sshbuf_dump_data(sshbuf_ptr(buf), sshbuf_len(buf), f);
1.1 djm 71: }
72:
73: char *
74: sshbuf_dtob16(struct sshbuf *buf)
75: {
76: size_t i, j, len = sshbuf_len(buf);
77: const u_char *p = sshbuf_ptr(buf);
78: char *ret;
79: const char hex[] = "0123456789abcdef";
80:
81: if (len == 0)
82: return strdup("");
83: if (SIZE_MAX / 2 <= len || (ret = malloc(len * 2 + 1)) == NULL)
84: return NULL;
85: for (i = j = 0; i < len; i++) {
86: ret[j++] = hex[(p[i] >> 4) & 0xf];
87: ret[j++] = hex[p[i] & 0xf];
88: }
89: ret[j] = '\0';
90: return ret;
91: }
92:
1.9 djm 93: int
94: sshbuf_dtob64(const struct sshbuf *d, struct sshbuf *b64, int wrap)
95: {
96: size_t i, slen = 0;
97: char *s = NULL;
98: int r;
99:
100: if (d == NULL || b64 == NULL || sshbuf_len(d) >= SIZE_MAX / 2)
101: return SSH_ERR_INVALID_ARGUMENT;
102: if (sshbuf_len(d) == 0)
103: return 0;
104: slen = ((sshbuf_len(d) + 2) / 3) * 4 + 1;
105: if ((s = malloc(slen)) == NULL)
106: return SSH_ERR_ALLOC_FAIL;
107: if (b64_ntop(sshbuf_ptr(d), sshbuf_len(d), s, slen) == -1) {
108: r = SSH_ERR_INTERNAL_ERROR;
109: goto fail;
110: }
111: if (wrap) {
112: for (i = 0; s[i] != '\0'; i++) {
113: if ((r = sshbuf_put_u8(b64, s[i])) != 0)
114: goto fail;
115: if (i % 70 == 69 && (r = sshbuf_put_u8(b64, '\n')) != 0)
116: goto fail;
117: }
1.10 djm 118: if ((i - 1) % 70 != 69 && (r = sshbuf_put_u8(b64, '\n')) != 0)
1.9 djm 119: goto fail;
120: } else {
121: if ((r = sshbuf_put(b64, s, strlen(s))) != 0)
122: goto fail;
123: }
124: /* Success */
125: r = 0;
126: fail:
127: freezero(s, slen);
128: return r;
129: }
130:
1.1 djm 131: char *
1.9 djm 132: sshbuf_dtob64_string(const struct sshbuf *buf, int wrap)
1.1 djm 133: {
1.9 djm 134: struct sshbuf *tmp;
1.1 djm 135: char *ret;
136:
1.9 djm 137: if ((tmp = sshbuf_new()) == NULL)
1.1 djm 138: return NULL;
1.9 djm 139: if (sshbuf_dtob64(buf, tmp, wrap) != 0) {
140: sshbuf_free(tmp);
1.1 djm 141: return NULL;
142: }
1.9 djm 143: ret = sshbuf_dup_string(tmp);
144: sshbuf_free(tmp);
1.1 djm 145: return ret;
146: }
147:
148: int
149: sshbuf_b64tod(struct sshbuf *buf, const char *b64)
150: {
151: size_t plen = strlen(b64);
152: int nlen, r;
153: u_char *p;
154:
155: if (plen == 0)
156: return 0;
157: if ((p = malloc(plen)) == NULL)
158: return SSH_ERR_ALLOC_FAIL;
159: if ((nlen = b64_pton(b64, p, plen)) < 0) {
1.5 djm 160: explicit_bzero(p, plen);
1.1 djm 161: free(p);
162: return SSH_ERR_INVALID_FORMAT;
163: }
164: if ((r = sshbuf_put(buf, p, nlen)) < 0) {
1.5 djm 165: explicit_bzero(p, plen);
1.1 djm 166: free(p);
167: return r;
168: }
1.5 djm 169: explicit_bzero(p, plen);
1.1 djm 170: free(p);
171: return 0;
1.6 djm 172: }
173:
174: char *
175: sshbuf_dup_string(struct sshbuf *buf)
176: {
177: const u_char *p = NULL, *s = sshbuf_ptr(buf);
178: size_t l = sshbuf_len(buf);
179: char *r;
180:
181: if (s == NULL || l > SIZE_MAX)
182: return NULL;
183: /* accept a nul only as the last character in the buffer */
184: if (l > 0 && (p = memchr(s, '\0', l)) != NULL) {
185: if (p != s + l - 1)
186: return NULL;
187: l--; /* the nul is put back below */
188: }
189: if ((r = malloc(l + 1)) == NULL)
190: return NULL;
191: if (l > 0)
192: memcpy(r, s, l);
193: r[l] = '\0';
194: return r;
1.1 djm 195: }
196:
1.8 djm 197: int
198: sshbuf_cmp(const struct sshbuf *b, size_t offset,
1.11 djm 199: const void *s, size_t len)
1.8 djm 200: {
201: if (sshbuf_ptr(b) == NULL)
202: return SSH_ERR_INTERNAL_ERROR;
203: if (offset > SSHBUF_SIZE_MAX || len > SSHBUF_SIZE_MAX || len == 0)
204: return SSH_ERR_INVALID_ARGUMENT;
205: if (offset + len > sshbuf_len(b))
206: return SSH_ERR_MESSAGE_INCOMPLETE;
207: if (timingsafe_bcmp(sshbuf_ptr(b) + offset, s, len) != 0)
208: return SSH_ERR_INVALID_FORMAT;
209: return 0;
210: }
211:
212: int
213: sshbuf_find(const struct sshbuf *b, size_t start_offset,
1.11 djm 214: const void *s, size_t len, size_t *offsetp)
1.8 djm 215: {
216: void *p;
217:
218: if (offsetp != NULL)
219: *offsetp = 0;
220: if (sshbuf_ptr(b) == NULL)
221: return SSH_ERR_INTERNAL_ERROR;
222: if (start_offset > SSHBUF_SIZE_MAX || len > SSHBUF_SIZE_MAX || len == 0)
223: return SSH_ERR_INVALID_ARGUMENT;
224: if (start_offset > sshbuf_len(b) || start_offset + len > sshbuf_len(b))
225: return SSH_ERR_MESSAGE_INCOMPLETE;
226: if ((p = memmem(sshbuf_ptr(b) + start_offset,
227: sshbuf_len(b) - start_offset, s, len)) == NULL)
228: return SSH_ERR_INVALID_FORMAT;
229: if (offsetp != NULL)
230: *offsetp = (const u_char *)p - sshbuf_ptr(b);
231: return 0;
232: }