1 /* $OpenBSD: encoding.c,v 1.10 2021/11/24 15:24:16 claudio Exp $ */ 2 /* 3 * Copyright (c) 2020 Claudio Jeker <claudio@openbsd.org> 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 <sys/stat.h> 18 19 #include <err.h> 20 #include <errno.h> 21 #include <ctype.h> 22 #include <fcntl.h> 23 #include <limits.h> 24 #include <stdlib.h> 25 #include <string.h> 26 #include <unistd.h> 27 28 #include <openssl/evp.h> 29 30 #include "extern.h" 31 32 /* 33 * Load file from disk and return the buffer and size. 34 */ 35 unsigned char * 36 load_file(const char *name, size_t *len) 37 { 38 unsigned char *buf = NULL; 39 struct stat st; 40 ssize_t n; 41 size_t size; 42 int fd, saved_errno; 43 44 *len = 0; 45 46 if ((fd = open(name, O_RDONLY)) == -1) 47 return NULL; 48 if (fstat(fd, &st) != 0) 49 goto err; 50 if (st.st_size <= 0 || st.st_size > MAX_FILE_SIZE) { 51 errno = EFBIG; 52 goto err; 53 } 54 size = (size_t)st.st_size; 55 if ((buf = malloc(size)) == NULL) 56 goto err; 57 n = read(fd, buf, size); 58 if (n == -1) 59 goto err; 60 if ((size_t)n != size) { 61 errno = EIO; 62 goto err; 63 } 64 close(fd); 65 *len = size; 66 return buf; 67 68 err: 69 saved_errno = errno; 70 close(fd); 71 free(buf); 72 errno = saved_errno; 73 return NULL; 74 } 75 76 /* 77 * Return the size of the data blob in outlen for an inlen sized base64 buffer. 78 * Returns 0 on success and -1 if inlen would overflow an int. 79 */ 80 int 81 base64_decode_len(size_t inlen, size_t *outlen) 82 { 83 *outlen = 0; 84 if (inlen >= INT_MAX - 3) 85 return -1; 86 *outlen = ((inlen + 3) / 4) * 3 + 1; 87 return 0; 88 } 89 90 /* 91 * Decode base64 encoded string into binary buffer returned in out. 92 * The out buffer size is stored in outlen. 93 * Returns 0 on success or -1 for any errors. 94 */ 95 int 96 base64_decode(const unsigned char *in, size_t inlen, 97 unsigned char **out, size_t *outlen) 98 { 99 static EVP_ENCODE_CTX *ctx; 100 unsigned char *to; 101 size_t tolen; 102 int evplen; 103 104 if (ctx == NULL && (ctx = EVP_ENCODE_CTX_new()) == NULL) 105 err(1, "EVP_ENCODE_CTX_new"); 106 107 *out = NULL; 108 *outlen = 0; 109 110 if (base64_decode_len(inlen, &tolen) == -1) 111 return -1; 112 if ((to = malloc(tolen)) == NULL) 113 return -1; 114 115 evplen = tolen; 116 EVP_DecodeInit(ctx); 117 if (EVP_DecodeUpdate(ctx, to, &evplen, in, inlen) == -1) 118 goto fail; 119 *outlen = evplen; 120 if (EVP_DecodeFinal(ctx, to + evplen, &evplen) == -1) 121 goto fail; 122 *outlen += evplen; 123 *out = to; 124 return 0; 125 126 fail: 127 free(to); 128 return -1; 129 } 130 131 /* 132 * Return the size of the base64 blob in outlen for a inlen sized binary buffer. 133 * Returns 0 on success and -1 if inlen would overflow the calculation. 134 */ 135 int 136 base64_encode_len(size_t inlen, size_t *outlen) 137 { 138 *outlen = 0; 139 if (inlen >= INT_MAX / 2) 140 return -1; 141 *outlen = ((inlen + 2) / 3) * 4 + 1; 142 return 0; 143 } 144 145 /* 146 * Encode a binary buffer into a base64 encoded string returned in out. 147 * Returns 0 on success or -1 for any errors. 148 */ 149 int 150 base64_encode(const unsigned char *in, size_t inlen, char **out) 151 { 152 unsigned char *to; 153 size_t tolen; 154 155 *out = NULL; 156 157 if (base64_encode_len(inlen, &tolen) == -1) 158 return -1; 159 if ((to = malloc(tolen)) == NULL) 160 return -1; 161 162 EVP_EncodeBlock(to, in, inlen); 163 *out = to; 164 return 0; 165 } 166 167 /* 168 * Convert binary buffer of size dsz into an upper-case hex-string. 169 * Returns pointer to the newly allocated string. Function can't fail. 170 */ 171 char * 172 hex_encode(const unsigned char *in, size_t insz) 173 { 174 const char hex[] = "0123456789ABCDEF"; 175 size_t i; 176 char *out; 177 178 if ((out = calloc(2, insz + 1)) == NULL) 179 err(1, NULL); 180 181 for (i = 0; i < insz; i++) { 182 out[i * 2] = hex[in[i] >> 4]; 183 out[i * 2 + 1] = hex[in[i] & 0xf]; 184 } 185 out[i * 2] = '\0'; 186 187 return out; 188 } 189 190 /* 191 * Hex decode hexstring into the supplied buffer. 192 * Return 0 on success else -1, if buffer too small or bad encoding. 193 */ 194 int 195 hex_decode(const char *hexstr, char *buf, size_t len) 196 { 197 unsigned char ch, r; 198 size_t pos = 0; 199 int i; 200 201 while (*hexstr) { 202 r = 0; 203 for (i = 0; i < 2; i++) { 204 ch = hexstr[i]; 205 if (isdigit(ch)) 206 ch -= '0'; 207 else if (islower(ch)) 208 ch -= ('a' - 10); 209 else if (isupper(ch)) 210 ch -= ('A' - 10); 211 else 212 return -1; 213 if (ch > 0xf) 214 return -1; 215 r = r << 4 | ch; 216 } 217 if (pos < len) 218 buf[pos++] = r; 219 else 220 return -1; 221 222 hexstr += 2; 223 } 224 return 0; 225 } 226 227