1*0cbfa66cSDaniel Fojt /* $OpenBSD: sshbuf-misc.c,v 1.14 2020/02/26 13:40:09 jsg Exp $ */ 236e94dc5SPeter Avalos /* 336e94dc5SPeter Avalos * Copyright (c) 2011 Damien Miller 436e94dc5SPeter Avalos * 536e94dc5SPeter Avalos * Permission to use, copy, modify, and distribute this software for any 636e94dc5SPeter Avalos * purpose with or without fee is hereby granted, provided that the above 736e94dc5SPeter Avalos * copyright notice and this permission notice appear in all copies. 836e94dc5SPeter Avalos * 936e94dc5SPeter Avalos * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1036e94dc5SPeter Avalos * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1136e94dc5SPeter Avalos * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1236e94dc5SPeter Avalos * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1336e94dc5SPeter Avalos * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1436e94dc5SPeter Avalos * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1536e94dc5SPeter Avalos * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1636e94dc5SPeter Avalos */ 1736e94dc5SPeter Avalos 1836e94dc5SPeter Avalos #include "includes.h" 1936e94dc5SPeter Avalos 2036e94dc5SPeter Avalos #include <sys/types.h> 2136e94dc5SPeter Avalos #include <sys/socket.h> 2236e94dc5SPeter Avalos #include <netinet/in.h> 2336e94dc5SPeter Avalos #include <errno.h> 2436e94dc5SPeter Avalos #include <stdlib.h> 25e9778795SPeter Avalos #ifdef HAVE_STDINT_H 26e9778795SPeter Avalos # include <stdint.h> 27e9778795SPeter Avalos #endif 2836e94dc5SPeter Avalos #include <stdio.h> 2936e94dc5SPeter Avalos #include <limits.h> 3036e94dc5SPeter Avalos #include <string.h> 3136e94dc5SPeter Avalos #include <resolv.h> 3236e94dc5SPeter Avalos #include <ctype.h> 3336e94dc5SPeter Avalos 3436e94dc5SPeter Avalos #include "ssherr.h" 3536e94dc5SPeter Avalos #define SSHBUF_INTERNAL 3636e94dc5SPeter Avalos #include "sshbuf.h" 3736e94dc5SPeter Avalos 3836e94dc5SPeter Avalos void 3936e94dc5SPeter Avalos sshbuf_dump_data(const void *s, size_t len, FILE *f) 4036e94dc5SPeter Avalos { 4136e94dc5SPeter Avalos size_t i, j; 4236e94dc5SPeter Avalos const u_char *p = (const u_char *)s; 4336e94dc5SPeter Avalos 4436e94dc5SPeter Avalos for (i = 0; i < len; i += 16) { 45e9778795SPeter Avalos fprintf(f, "%.4zu: ", i); 4636e94dc5SPeter Avalos for (j = i; j < i + 16; j++) { 4736e94dc5SPeter Avalos if (j < len) 4836e94dc5SPeter Avalos fprintf(f, "%02x ", p[j]); 4936e94dc5SPeter Avalos else 5036e94dc5SPeter Avalos fprintf(f, " "); 5136e94dc5SPeter Avalos } 5236e94dc5SPeter Avalos fprintf(f, " "); 5336e94dc5SPeter Avalos for (j = i; j < i + 16; j++) { 5436e94dc5SPeter Avalos if (j < len) { 5536e94dc5SPeter Avalos if (isascii(p[j]) && isprint(p[j])) 5636e94dc5SPeter Avalos fprintf(f, "%c", p[j]); 5736e94dc5SPeter Avalos else 5836e94dc5SPeter Avalos fprintf(f, "."); 5936e94dc5SPeter Avalos } 6036e94dc5SPeter Avalos } 6136e94dc5SPeter Avalos fprintf(f, "\n"); 6236e94dc5SPeter Avalos } 6336e94dc5SPeter Avalos } 6436e94dc5SPeter Avalos 6536e94dc5SPeter Avalos void 6636e94dc5SPeter Avalos sshbuf_dump(struct sshbuf *buf, FILE *f) 6736e94dc5SPeter Avalos { 6836e94dc5SPeter Avalos fprintf(f, "buffer %p len = %zu\n", buf, sshbuf_len(buf)); 6936e94dc5SPeter Avalos sshbuf_dump_data(sshbuf_ptr(buf), sshbuf_len(buf), f); 7036e94dc5SPeter Avalos } 7136e94dc5SPeter Avalos 7236e94dc5SPeter Avalos char * 7336e94dc5SPeter Avalos sshbuf_dtob16(struct sshbuf *buf) 7436e94dc5SPeter Avalos { 7536e94dc5SPeter Avalos size_t i, j, len = sshbuf_len(buf); 7636e94dc5SPeter Avalos const u_char *p = sshbuf_ptr(buf); 7736e94dc5SPeter Avalos char *ret; 7836e94dc5SPeter Avalos const char hex[] = "0123456789abcdef"; 7936e94dc5SPeter Avalos 8036e94dc5SPeter Avalos if (len == 0) 8136e94dc5SPeter Avalos return strdup(""); 8236e94dc5SPeter Avalos if (SIZE_MAX / 2 <= len || (ret = malloc(len * 2 + 1)) == NULL) 8336e94dc5SPeter Avalos return NULL; 8436e94dc5SPeter Avalos for (i = j = 0; i < len; i++) { 8536e94dc5SPeter Avalos ret[j++] = hex[(p[i] >> 4) & 0xf]; 8636e94dc5SPeter Avalos ret[j++] = hex[p[i] & 0xf]; 8736e94dc5SPeter Avalos } 8836e94dc5SPeter Avalos ret[j] = '\0'; 8936e94dc5SPeter Avalos return ret; 9036e94dc5SPeter Avalos } 9136e94dc5SPeter Avalos 92*0cbfa66cSDaniel Fojt int 93*0cbfa66cSDaniel Fojt sshbuf_dtob64(const struct sshbuf *d, struct sshbuf *b64, int wrap) 9436e94dc5SPeter Avalos { 95*0cbfa66cSDaniel Fojt size_t i, slen = 0; 96*0cbfa66cSDaniel Fojt char *s = NULL; 9736e94dc5SPeter Avalos int r; 9836e94dc5SPeter Avalos 99*0cbfa66cSDaniel Fojt if (d == NULL || b64 == NULL || sshbuf_len(d) >= SIZE_MAX / 2) 100*0cbfa66cSDaniel Fojt return SSH_ERR_INVALID_ARGUMENT; 101*0cbfa66cSDaniel Fojt if (sshbuf_len(d) == 0) 102*0cbfa66cSDaniel Fojt return 0; 103*0cbfa66cSDaniel Fojt slen = ((sshbuf_len(d) + 2) / 3) * 4 + 1; 104*0cbfa66cSDaniel Fojt if ((s = malloc(slen)) == NULL) 105*0cbfa66cSDaniel Fojt return SSH_ERR_ALLOC_FAIL; 106*0cbfa66cSDaniel Fojt if (b64_ntop(sshbuf_ptr(d), sshbuf_len(d), s, slen) == -1) { 107*0cbfa66cSDaniel Fojt r = SSH_ERR_INTERNAL_ERROR; 108*0cbfa66cSDaniel Fojt goto fail; 109*0cbfa66cSDaniel Fojt } 110*0cbfa66cSDaniel Fojt if (wrap) { 111*0cbfa66cSDaniel Fojt for (i = 0; s[i] != '\0'; i++) { 112*0cbfa66cSDaniel Fojt if ((r = sshbuf_put_u8(b64, s[i])) != 0) 113*0cbfa66cSDaniel Fojt goto fail; 114*0cbfa66cSDaniel Fojt if (i % 70 == 69 && (r = sshbuf_put_u8(b64, '\n')) != 0) 115*0cbfa66cSDaniel Fojt goto fail; 116*0cbfa66cSDaniel Fojt } 117*0cbfa66cSDaniel Fojt if ((i - 1) % 70 != 69 && (r = sshbuf_put_u8(b64, '\n')) != 0) 118*0cbfa66cSDaniel Fojt goto fail; 119*0cbfa66cSDaniel Fojt } else { 120*0cbfa66cSDaniel Fojt if ((r = sshbuf_put(b64, s, strlen(s))) != 0) 121*0cbfa66cSDaniel Fojt goto fail; 122*0cbfa66cSDaniel Fojt } 123*0cbfa66cSDaniel Fojt /* Success */ 124*0cbfa66cSDaniel Fojt r = 0; 125*0cbfa66cSDaniel Fojt fail: 126*0cbfa66cSDaniel Fojt freezero(s, slen); 127*0cbfa66cSDaniel Fojt return r; 128*0cbfa66cSDaniel Fojt } 129*0cbfa66cSDaniel Fojt 130*0cbfa66cSDaniel Fojt char * 131*0cbfa66cSDaniel Fojt sshbuf_dtob64_string(const struct sshbuf *buf, int wrap) 132*0cbfa66cSDaniel Fojt { 133*0cbfa66cSDaniel Fojt struct sshbuf *tmp; 134*0cbfa66cSDaniel Fojt char *ret; 135*0cbfa66cSDaniel Fojt 136*0cbfa66cSDaniel Fojt if ((tmp = sshbuf_new()) == NULL) 13736e94dc5SPeter Avalos return NULL; 138*0cbfa66cSDaniel Fojt if (sshbuf_dtob64(buf, tmp, wrap) != 0) { 139*0cbfa66cSDaniel Fojt sshbuf_free(tmp); 14036e94dc5SPeter Avalos return NULL; 14136e94dc5SPeter Avalos } 142*0cbfa66cSDaniel Fojt ret = sshbuf_dup_string(tmp); 143*0cbfa66cSDaniel Fojt sshbuf_free(tmp); 14436e94dc5SPeter Avalos return ret; 14536e94dc5SPeter Avalos } 14636e94dc5SPeter Avalos 14736e94dc5SPeter Avalos int 14836e94dc5SPeter Avalos sshbuf_b64tod(struct sshbuf *buf, const char *b64) 14936e94dc5SPeter Avalos { 15036e94dc5SPeter Avalos size_t plen = strlen(b64); 15136e94dc5SPeter Avalos int nlen, r; 15236e94dc5SPeter Avalos u_char *p; 15336e94dc5SPeter Avalos 15436e94dc5SPeter Avalos if (plen == 0) 15536e94dc5SPeter Avalos return 0; 15636e94dc5SPeter Avalos if ((p = malloc(plen)) == NULL) 15736e94dc5SPeter Avalos return SSH_ERR_ALLOC_FAIL; 15836e94dc5SPeter Avalos if ((nlen = b64_pton(b64, p, plen)) < 0) { 159*0cbfa66cSDaniel Fojt freezero(p, plen); 16036e94dc5SPeter Avalos return SSH_ERR_INVALID_FORMAT; 16136e94dc5SPeter Avalos } 16236e94dc5SPeter Avalos if ((r = sshbuf_put(buf, p, nlen)) < 0) { 163*0cbfa66cSDaniel Fojt freezero(p, plen); 16436e94dc5SPeter Avalos return r; 16536e94dc5SPeter Avalos } 166*0cbfa66cSDaniel Fojt freezero(p, plen); 16736e94dc5SPeter Avalos return 0; 16836e94dc5SPeter Avalos } 16936e94dc5SPeter Avalos 170e9778795SPeter Avalos char * 171e9778795SPeter Avalos sshbuf_dup_string(struct sshbuf *buf) 172e9778795SPeter Avalos { 173e9778795SPeter Avalos const u_char *p = NULL, *s = sshbuf_ptr(buf); 174e9778795SPeter Avalos size_t l = sshbuf_len(buf); 175e9778795SPeter Avalos char *r; 176e9778795SPeter Avalos 177e9778795SPeter Avalos if (s == NULL || l > SIZE_MAX) 178e9778795SPeter Avalos return NULL; 179e9778795SPeter Avalos /* accept a nul only as the last character in the buffer */ 180e9778795SPeter Avalos if (l > 0 && (p = memchr(s, '\0', l)) != NULL) { 181e9778795SPeter Avalos if (p != s + l - 1) 182e9778795SPeter Avalos return NULL; 183e9778795SPeter Avalos l--; /* the nul is put back below */ 184e9778795SPeter Avalos } 185e9778795SPeter Avalos if ((r = malloc(l + 1)) == NULL) 186e9778795SPeter Avalos return NULL; 187e9778795SPeter Avalos if (l > 0) 188e9778795SPeter Avalos memcpy(r, s, l); 189e9778795SPeter Avalos r[l] = '\0'; 190e9778795SPeter Avalos return r; 191e9778795SPeter Avalos } 192e9778795SPeter Avalos 193*0cbfa66cSDaniel Fojt int 194*0cbfa66cSDaniel Fojt sshbuf_cmp(const struct sshbuf *b, size_t offset, 195*0cbfa66cSDaniel Fojt const void *s, size_t len) 196*0cbfa66cSDaniel Fojt { 197*0cbfa66cSDaniel Fojt if (sshbuf_ptr(b) == NULL) 198*0cbfa66cSDaniel Fojt return SSH_ERR_INTERNAL_ERROR; 199*0cbfa66cSDaniel Fojt if (offset > SSHBUF_SIZE_MAX || len > SSHBUF_SIZE_MAX || len == 0) 200*0cbfa66cSDaniel Fojt return SSH_ERR_INVALID_ARGUMENT; 201*0cbfa66cSDaniel Fojt if (offset + len > sshbuf_len(b)) 202*0cbfa66cSDaniel Fojt return SSH_ERR_MESSAGE_INCOMPLETE; 203*0cbfa66cSDaniel Fojt if (timingsafe_bcmp(sshbuf_ptr(b) + offset, s, len) != 0) 204*0cbfa66cSDaniel Fojt return SSH_ERR_INVALID_FORMAT; 205*0cbfa66cSDaniel Fojt return 0; 206*0cbfa66cSDaniel Fojt } 207*0cbfa66cSDaniel Fojt 208*0cbfa66cSDaniel Fojt int 209*0cbfa66cSDaniel Fojt sshbuf_find(const struct sshbuf *b, size_t start_offset, 210*0cbfa66cSDaniel Fojt const void *s, size_t len, size_t *offsetp) 211*0cbfa66cSDaniel Fojt { 212*0cbfa66cSDaniel Fojt void *p; 213*0cbfa66cSDaniel Fojt 214*0cbfa66cSDaniel Fojt if (offsetp != NULL) 215*0cbfa66cSDaniel Fojt *offsetp = 0; 216*0cbfa66cSDaniel Fojt if (sshbuf_ptr(b) == NULL) 217*0cbfa66cSDaniel Fojt return SSH_ERR_INTERNAL_ERROR; 218*0cbfa66cSDaniel Fojt if (start_offset > SSHBUF_SIZE_MAX || len > SSHBUF_SIZE_MAX || len == 0) 219*0cbfa66cSDaniel Fojt return SSH_ERR_INVALID_ARGUMENT; 220*0cbfa66cSDaniel Fojt if (start_offset > sshbuf_len(b) || start_offset + len > sshbuf_len(b)) 221*0cbfa66cSDaniel Fojt return SSH_ERR_MESSAGE_INCOMPLETE; 222*0cbfa66cSDaniel Fojt if ((p = memmem(sshbuf_ptr(b) + start_offset, 223*0cbfa66cSDaniel Fojt sshbuf_len(b) - start_offset, s, len)) == NULL) 224*0cbfa66cSDaniel Fojt return SSH_ERR_INVALID_FORMAT; 225*0cbfa66cSDaniel Fojt if (offsetp != NULL) 226*0cbfa66cSDaniel Fojt *offsetp = (const u_char *)p - sshbuf_ptr(b); 227*0cbfa66cSDaniel Fojt return 0; 228*0cbfa66cSDaniel Fojt } 229