xref: /openbsd-src/usr.sbin/rpki-client/encoding.c (revision d89ec533011f513df1010f142a111086a0785f09)
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