1 /*
2  * Copyright (c) 2013-2021 Joris Vink <joris@coders.se>
3  *
4  * Permission to use, copy, modify, and distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 #include <sys/types.h>
18 #include <sys/time.h>
19 
20 #include <openssl/evp.h>
21 #include <openssl/rsa.h>
22 
23 #include <ctype.h>
24 #include <stdio.h>
25 #include <stdarg.h>
26 #include <string.h>
27 #include <stdlib.h>
28 #include <time.h>
29 #include <limits.h>
30 
31 #include "kore.h"
32 
33 static struct {
34 	char		*name;
35 	int		value;
36 } month_names[] = {
37 	{ "Jan",	0 },
38 	{ "Feb",	1 },
39 	{ "Mar",	2 },
40 	{ "Apr",	3 },
41 	{ "May",	4 },
42 	{ "Jun",	5 },
43 	{ "Jul",	6 },
44 	{ "Aug",	7 },
45 	{ "Sep",	8 },
46 	{ "Oct",	9 },
47 	{ "Nov",	10 },
48 	{ "Dec",	11 },
49 	{ NULL,		0 },
50 };
51 
52 static void	fatal_log(const char *, va_list);
53 static int	utils_base64_encode(const void *, size_t, char **,
54 		    const char *, int);
55 static int	utils_base64_decode(const char *, u_int8_t **,
56 		    size_t *, const char *, int);
57 
58 static char b64_table[] = 	\
59     "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
60 
61 static char b64url_table[] = 	\
62     "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
63 
64 /* b64_table and b64url_table are the same size. */
65 #define B64_TABLE_LEN		(sizeof(b64_table))
66 
67 #if defined(KORE_DEBUG)
68 void
kore_debug_internal(char * file,int line,const char * fmt,...)69 kore_debug_internal(char *file, int line, const char *fmt, ...)
70 {
71 	va_list		args;
72 	char		buf[2048];
73 
74 	va_start(args, fmt);
75 	(void)vsnprintf(buf, sizeof(buf), fmt, args);
76 	va_end(args);
77 
78 	printf("[%d] %s:%d - %s\n", kore_pid, file, line, buf);
79 }
80 #endif
81 
82 void
kore_log_init(void)83 kore_log_init(void)
84 {
85 #if defined(KORE_SINGLE_BINARY)
86 	extern const char	*__progname;
87 	const char		*name = kore_strdup(__progname);
88 #else
89 	const char		*name = "kore";
90 #endif
91 
92 	if (!kore_foreground)
93 		openlog(name, LOG_NDELAY | LOG_PID, LOG_DAEMON);
94 }
95 
96 void
kore_log(int prio,const char * fmt,...)97 kore_log(int prio, const char *fmt, ...)
98 {
99 	va_list		args;
100 	const char	*name;
101 	char		buf[2048];
102 
103 	va_start(args, fmt);
104 	(void)vsnprintf(buf, sizeof(buf), fmt, args);
105 	va_end(args);
106 
107 	if (worker != NULL) {
108 		name = kore_worker_name(worker->id);
109 
110 		if (kore_foreground)
111 			printf("%s: %s\n", name, buf);
112 		else
113 			syslog(prio, "%s: %s", name, buf);
114 	} else {
115 		if (kore_foreground)
116 			printf("[parent]: %s\n", buf);
117 		else
118 			syslog(prio, "[parent]: %s", buf);
119 	}
120 }
121 
122 size_t
kore_strlcpy(char * dst,const char * src,const size_t len)123 kore_strlcpy(char *dst, const char *src, const size_t len)
124 {
125 	char		*d = dst;
126 	const char	*s = src;
127 	const char	*end = dst + len - 1;
128 
129 	if (len == 0)
130 		fatal("kore_strlcpy: len == 0");
131 
132 	while ((*d = *s) != '\0') {
133 		if (d == end) {
134 			*d = '\0';
135 			break;
136 		}
137 
138 		d++;
139 		s++;
140 	}
141 
142 	while (*s != '\0')
143 		s++;
144 
145 	return (s - src);
146 }
147 
148 int
kore_snprintf(char * str,size_t size,int * len,const char * fmt,...)149 kore_snprintf(char *str, size_t size, int *len, const char *fmt, ...)
150 {
151 	int		l;
152 	va_list		args;
153 
154 	va_start(args, fmt);
155 	l = vsnprintf(str, size, fmt, args);
156 	va_end(args);
157 
158 	if (l == -1 || (size_t)l >= size)
159 		return (KORE_RESULT_ERROR);
160 
161 	if (len != NULL)
162 		*len = l;
163 
164 	return (KORE_RESULT_OK);
165 }
166 
167 long long
kore_strtonum(const char * str,int base,long long min,long long max,int * err)168 kore_strtonum(const char *str, int base, long long min, long long max, int *err)
169 {
170 	long long	l;
171 	char		*ep;
172 
173 	if (min > max) {
174 		*err = KORE_RESULT_ERROR;
175 		return (0);
176 	}
177 
178 	errno = 0;
179 	l = strtoll(str, &ep, base);
180 	if (errno != 0 || str == ep || *ep != '\0') {
181 		*err = KORE_RESULT_ERROR;
182 		return (0);
183 	}
184 
185 	if (l < min) {
186 		*err = KORE_RESULT_ERROR;
187 		return (0);
188 	}
189 
190 	if (l > max) {
191 		*err = KORE_RESULT_ERROR;
192 		return (0);
193 	}
194 
195 	*err = KORE_RESULT_OK;
196 	return (l);
197 }
198 
199 u_int64_t
kore_strtonum64(const char * str,int sign,int * err)200 kore_strtonum64(const char *str, int sign, int *err)
201 {
202 	u_int64_t	l;
203 	long long	ll;
204 	char		*ep;
205 	int		check;
206 
207 	l = 0;
208 	check = 1;
209 
210 	ll = strtoll(str, &ep, 10);
211 	if ((errno == EINVAL || errno == ERANGE) &&
212 	    (ll == LLONG_MIN || ll == LLONG_MAX)) {
213 		if (sign) {
214 			*err = KORE_RESULT_ERROR;
215 			return (0);
216 		}
217 
218 		check = 0;
219 	}
220 
221 	if (!sign) {
222 		l = strtoull(str, &ep, 10);
223 		if ((errno == EINVAL || errno == ERANGE) && l == ULONG_MAX) {
224 			*err = KORE_RESULT_ERROR;
225 			return (0);
226 		}
227 
228 		if (check && ll < 0) {
229 			*err = KORE_RESULT_ERROR;
230 			return (0);
231 		}
232 	}
233 
234 	if (str == ep || *ep != '\0') {
235 		*err = KORE_RESULT_ERROR;
236 		return (0);
237 	}
238 
239 	*err = KORE_RESULT_OK;
240 	return ((sign) ? (u_int64_t)ll : l);
241 }
242 
243 double
kore_strtodouble(const char * str,long double min,long double max,int * err)244 kore_strtodouble(const char *str, long double min, long double max, int *err)
245 {
246 	double		d;
247 	char		*ep;
248 
249 	if (min > max) {
250 		*err = KORE_RESULT_ERROR;
251 		return (0);
252 	}
253 
254 	errno = 0;
255 	d = strtod(str, &ep);
256 	if (errno == ERANGE || str == ep || *ep != '\0') {
257 		*err = KORE_RESULT_ERROR;
258 		return (0);
259 	}
260 
261 	if (d < min) {
262 		*err = KORE_RESULT_ERROR;
263 		return (0);
264 	}
265 
266 	if (d > max) {
267 		*err = KORE_RESULT_ERROR;
268 		return (0);
269 	}
270 
271 	*err = KORE_RESULT_OK;
272 	return (d);
273 }
274 
275 int
kore_split_string(char * input,const char * delim,char ** out,size_t ele)276 kore_split_string(char *input, const char *delim, char **out, size_t ele)
277 {
278 	int		count;
279 	char		**ap;
280 
281 	if (ele == 0)
282 		return (0);
283 
284 	count = 0;
285 	for (ap = out; ap < &out[ele - 1] &&
286 	    (*ap = strsep(&input, delim)) != NULL;) {
287 		if (**ap != '\0') {
288 			ap++;
289 			count++;
290 		}
291 	}
292 
293 	*ap = NULL;
294 	return (count);
295 }
296 
297 void
kore_strip_chars(char * in,const char strip,char ** out)298 kore_strip_chars(char *in, const char strip, char **out)
299 {
300 	u_int32_t	len;
301 	char		*s, *p;
302 
303 	len = strlen(in);
304 	*out = kore_malloc(len + 1);
305 	p = *out;
306 
307 	for (s = in; s < (in + len); s++) {
308 		if (*s == strip)
309 			continue;
310 
311 		*p++ = *s;
312 	}
313 
314 	*p = '\0';
315 }
316 
317 time_t
kore_date_to_time(const char * http_date)318 kore_date_to_time(const char *http_date)
319 {
320 	time_t			t;
321 	int			err, i;
322 	struct tm		tm, *ltm;
323 	char			*args[7], *tbuf[5], *sdup;
324 
325 	time(&t);
326 	ltm = localtime(&t);
327 	sdup = kore_strdup(http_date);
328 
329 	t = KORE_RESULT_ERROR;
330 
331 	if (kore_split_string(sdup, " ", args, 7) != 6) {
332 		kore_debug("misformed http-date: '%s'", http_date);
333 		goto out;
334 	}
335 
336 	memset(&tm, 0, sizeof(tm));
337 
338 	tm.tm_year = kore_strtonum(args[3], 10, 1900, 2068, &err) - 1900;
339 	if (err == KORE_RESULT_ERROR) {
340 		kore_debug("misformed year in http-date: '%s'", http_date);
341 		goto out;
342 	}
343 
344 	for (i = 0; month_names[i].name != NULL; i++) {
345 		if (!strcmp(month_names[i].name, args[2])) {
346 			tm.tm_mon = month_names[i].value;
347 			break;
348 		}
349 	}
350 
351 	if (month_names[i].name == NULL) {
352 		kore_debug("misformed month in http-date: '%s'", http_date);
353 		goto out;
354 	}
355 
356 	tm.tm_mday = kore_strtonum(args[1], 10, 1, 31, &err);
357 	if (err == KORE_RESULT_ERROR) {
358 		kore_debug("misformed mday in http-date: '%s'", http_date);
359 		goto out;
360 	}
361 
362 	if (kore_split_string(args[4], ":", tbuf, 5) != 3) {
363 		kore_debug("misformed HH:MM:SS in http-date: '%s'", http_date);
364 		goto out;
365 	}
366 
367 	tm.tm_hour = kore_strtonum(tbuf[0], 10, 0, 23, &err);
368 	if (err == KORE_RESULT_ERROR) {
369 		kore_debug("misformed hour in http-date: '%s'", http_date);
370 		goto out;
371 	}
372 
373 	tm.tm_min = kore_strtonum(tbuf[1], 10, 0, 59, &err);
374 	if (err == KORE_RESULT_ERROR) {
375 		kore_debug("misformed minutes in http-date: '%s'", http_date);
376 		goto out;
377 	}
378 
379 	tm.tm_sec = kore_strtonum(tbuf[2], 10, 0, 60, &err);
380 	if (err == KORE_RESULT_ERROR) {
381 		kore_debug("misformed seconds in http-date: '%s'", http_date);
382 		goto out;
383 	}
384 
385 	tm.tm_isdst = ltm->tm_isdst;
386 	t = mktime(&tm) + ltm->tm_gmtoff;
387 	if (t == -1) {
388 		t = 0;
389 		kore_debug("mktime() on '%s' failed", http_date);
390 	}
391 
392 out:
393 	kore_free(sdup);
394 	return (t);
395 }
396 
397 char *
kore_time_to_date(time_t now)398 kore_time_to_date(time_t now)
399 {
400 	struct tm		*tm;
401 	static time_t		last = 0;
402 	static char		tbuf[32];
403 
404 	if (now != last) {
405 		last = now;
406 
407 		tm = gmtime(&now);
408 		if (!strftime(tbuf, sizeof(tbuf), "%a, %d %b %Y %T GMT", tm)) {
409 			kore_debug("strftime() gave us NULL (%ld)", now);
410 			return (NULL);
411 		}
412 	}
413 
414 	return (tbuf);
415 }
416 
417 u_int64_t
kore_time_ms(void)418 kore_time_ms(void)
419 {
420 	struct timespec		ts;
421 
422 	(void)clock_gettime(CLOCK_MONOTONIC, &ts);
423 
424 	return ((u_int64_t)(ts.tv_sec * 1000 + (ts.tv_nsec / 1000000)));
425 }
426 
427 int
kore_base64url_encode(const void * data,size_t len,char ** out,int flags)428 kore_base64url_encode(const void *data, size_t len, char **out, int flags)
429 {
430 	return (utils_base64_encode(data, len, out, b64url_table, flags));
431 }
432 
433 int
kore_base64_encode(const void * data,size_t len,char ** out)434 kore_base64_encode(const void *data, size_t len, char **out)
435 {
436 	return (utils_base64_encode(data, len, out, b64_table, 0));
437 }
438 
439 int
kore_base64url_decode(const char * in,u_int8_t ** out,size_t * olen,int flags)440 kore_base64url_decode(const char *in, u_int8_t **out, size_t *olen, int flags)
441 {
442 	return (utils_base64_decode(in, out, olen, b64url_table, flags));
443 }
444 
445 int
kore_base64_decode(const char * in,u_int8_t ** out,size_t * olen)446 kore_base64_decode(const char *in, u_int8_t **out, size_t *olen)
447 {
448 	return (utils_base64_decode(in, out, olen, b64_table, 0));
449 }
450 
451 void *
kore_mem_find(void * src,size_t slen,const void * needle,size_t len)452 kore_mem_find(void *src, size_t slen, const void *needle, size_t len)
453 {
454 	size_t		pos;
455 
456 	for (pos = 0; pos < slen; pos++) {
457 		if ( *((u_int8_t *)src + pos) != *(const u_int8_t *)needle)
458 			continue;
459 
460 		if ((slen - pos) < len)
461 			return (NULL);
462 
463 		if (!memcmp((u_int8_t *)src + pos, needle, len))
464 			return ((u_int8_t *)src + pos);
465 	}
466 
467 	return (NULL);
468 }
469 
470 char *
kore_text_trim(char * string,size_t len)471 kore_text_trim(char *string, size_t len)
472 {
473 	char		*end;
474 
475 	if (len == 0)
476 		return (string);
477 
478 	end = (string + len) - 1;
479 	while (isspace(*(unsigned char *)string) && string < end)
480 		string++;
481 
482 	while (isspace(*(unsigned char *)end) && end > string)
483 		*(end)-- = '\0';
484 
485 	return (string);
486 }
487 
488 char *
kore_read_line(FILE * fp,char * in,size_t len)489 kore_read_line(FILE *fp, char *in, size_t len)
490 {
491 	char	*p, *t;
492 
493 	if (fgets(in, len, fp) == NULL)
494 		return (NULL);
495 
496 	p = in;
497 	in[strcspn(in, "\n")] = '\0';
498 
499 	while (isspace(*(unsigned char *)p))
500 		p++;
501 
502 	if (p[0] == '#' || p[0] == '\0') {
503 		p[0] = '\0';
504 		return (p);
505 	}
506 
507 	for (t = p; *t != '\0'; t++) {
508 		if (*t == '\t')
509 			*t = ' ';
510 	}
511 
512 	return (p);
513 }
514 
515 EVP_PKEY *
kore_rsakey_load(const char * path)516 kore_rsakey_load(const char *path)
517 {
518 	FILE		*fp;
519 	EVP_PKEY	*pkey;
520 
521 	if (access(path, R_OK) == -1)
522 		return (NULL);
523 
524 	if ((fp = fopen(path, "r")) == NULL)
525 		fatalx("%s(%s): %s", __func__, path, errno_s);
526 
527 	if ((pkey = PEM_read_PrivateKey(fp, NULL, NULL, NULL)) == NULL)
528 		fatalx("PEM_read_PrivateKey: %s", ssl_errno_s);
529 
530 	fclose(fp);
531 
532 	return (pkey);
533 }
534 
535 EVP_PKEY *
kore_rsakey_generate(const char * path)536 kore_rsakey_generate(const char *path)
537 {
538 	FILE			*fp;
539 	EVP_PKEY_CTX		*ctx;
540 	EVP_PKEY		*pkey;
541 
542 	if ((ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL)) == NULL)
543 		fatalx("EVP_PKEY_CTX_new_id: %s", ssl_errno_s);
544 
545 	if (EVP_PKEY_keygen_init(ctx) <= 0)
546 		fatalx("EVP_PKEY_keygen_init: %s", ssl_errno_s);
547 
548 	if (EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, KORE_RSAKEY_BITS) <= 0)
549 		fatalx("EVP_PKEY_CTX_set_rsa_keygen_bits: %s", ssl_errno_s);
550 
551 	pkey = NULL;
552 	if (EVP_PKEY_keygen(ctx, &pkey) <= 0)
553 		fatalx("EVP_PKEY_keygen: %s", ssl_errno_s);
554 
555 	if (path != NULL) {
556 		if ((fp = fopen(path, "w")) == NULL)
557 			fatalx("fopen(%s): %s", path, errno_s);
558 
559 		if (!PEM_write_PrivateKey(fp, pkey, NULL, NULL, 0, NULL, NULL))
560 			fatalx("PEM_write_PrivateKey: %s", ssl_errno_s);
561 
562 		fclose(fp);
563 	}
564 
565 	return (pkey);
566 }
567 
568 const char *
kore_worker_name(int id)569 kore_worker_name(int id)
570 {
571 	static char	buf[64];
572 
573 	switch (id) {
574 	case KORE_WORKER_KEYMGR:
575 		(void)snprintf(buf, sizeof(buf), "[keymgr]");
576 		break;
577 	case KORE_WORKER_ACME:
578 		(void)snprintf(buf, sizeof(buf), "[acme]");
579 		break;
580 	default:
581 		(void)snprintf(buf, sizeof(buf), "[wrk %d]", id);
582 		break;
583 	}
584 
585 	return (buf);
586 }
587 
588 int
kore_x509_subject_name(struct connection * c,char ** out,int flags)589 kore_x509_subject_name(struct connection *c, char **out, int flags)
590 {
591 	struct kore_buf		buf;
592 	u_int8_t		*data;
593 	ASN1_STRING		*astr;
594 	X509_NAME		*name;
595 	X509_NAME_ENTRY		*entry;
596 	const char		*field;
597 	int			ret, idx, namelen, nid, len;
598 
599 	data = NULL;
600 	ret = KORE_RESULT_ERROR;
601 
602 	kore_buf_init(&buf, 1024);
603 
604 	if (c->cert == NULL)
605 		goto cleanup;
606 
607 	if ((name = X509_get_subject_name(c->cert)) == NULL)
608 		goto cleanup;
609 
610 	namelen = X509_NAME_entry_count(name);
611 	if (namelen == 0)
612 		goto cleanup;
613 
614 	for (idx = 0; idx < namelen; idx++) {
615 		entry = X509_NAME_get_entry(name, idx);
616 		if (entry == NULL)
617 			goto cleanup;
618 
619 		nid = OBJ_obj2nid(X509_NAME_ENTRY_get_object(entry));
620 		if ((field = OBJ_nid2sn(nid)) == NULL)
621 			goto cleanup;
622 
623 		if ((astr = X509_NAME_ENTRY_get_data(entry)) == NULL)
624 			goto cleanup;
625 
626 		data = NULL;
627 		if ((len = ASN1_STRING_to_UTF8(&data, astr)) < 0)
628 			goto cleanup;
629 
630 		if (flags & KORE_X509_COMMON_NAME_ONLY) {
631 			if (nid == NID_commonName) {
632 				kore_buf_append(&buf, data, len);
633 				break;
634 			}
635 		} else {
636 			kore_buf_appendf(&buf, "%s=", field);
637 			kore_buf_append(&buf, data, len);
638 			if (idx != (namelen - 1))
639 				kore_buf_appendf(&buf, " ");
640 		}
641 
642 		OPENSSL_free(data);
643 		data = NULL;
644 	}
645 
646 	ret = KORE_RESULT_OK;
647 	*out = kore_buf_stringify(&buf, NULL);
648 
649 	buf.offset = 0;
650 	buf.data = NULL;
651 
652 cleanup:
653 	if (data != NULL)
654 		OPENSSL_free(data);
655 
656 	kore_buf_cleanup(&buf);
657 	return (ret);
658 }
659 
660 void
fatal(const char * fmt,...)661 fatal(const char *fmt, ...)
662 {
663 	va_list		args;
664 
665 	va_start(args, fmt);
666 	fatal_log(fmt, args);
667 	va_end(args);
668 
669 	exit(1);
670 }
671 
672 void
fatalx(const char * fmt,...)673 fatalx(const char *fmt, ...)
674 {
675 	va_list		args;
676 
677 	/* In case people call fatalx() from the parent context. */
678 	if (worker != NULL)
679 		kore_msg_send(KORE_MSG_PARENT, KORE_MSG_SHUTDOWN, NULL, 0);
680 
681 	va_start(args, fmt);
682 	fatal_log(fmt, args);
683 	va_end(args);
684 
685 	exit(1);
686 }
687 
688 static void
fatal_log(const char * fmt,va_list args)689 fatal_log(const char *fmt, va_list args)
690 {
691 	char			buf[2048];
692 	extern const char	*kore_progname;
693 
694 	(void)vsnprintf(buf, sizeof(buf), fmt, args);
695 
696 	if (!kore_foreground)
697 		kore_log(LOG_ERR, "%s", buf);
698 
699 	if (worker != NULL && worker->id == KORE_WORKER_KEYMGR)
700 		kore_keymgr_cleanup(1);
701 
702 	printf("%s: %s\n", kore_progname, buf);
703 }
704 
705 static int
utils_base64_encode(const void * data,size_t len,char ** out,const char * table,int flags)706 utils_base64_encode(const void *data, size_t len, char **out,
707     const char *table, int flags)
708 {
709 	u_int8_t		n;
710 	size_t			nb;
711 	const u_int8_t		*ptr;
712 	u_int32_t		bytes;
713 	struct kore_buf		result;
714 
715 	nb = 0;
716 	ptr = data;
717 	kore_buf_init(&result, (len / 3) * 4);
718 
719 	while (len > 0) {
720 		if (len > 2) {
721 			nb = 3;
722 			bytes = *ptr++ << 16;
723 			bytes |= *ptr++ << 8;
724 			bytes |= *ptr++;
725 		} else if (len > 1) {
726 			nb = 2;
727 			bytes = *ptr++ << 16;
728 			bytes |= *ptr++ << 8;
729 		} else if (len == 1) {
730 			nb = 1;
731 			bytes = *ptr++ << 16;
732 		} else {
733 			kore_buf_cleanup(&result);
734 			return (KORE_RESULT_ERROR);
735 		}
736 
737 		n = (bytes >> 18) & 0x3f;
738 		kore_buf_append(&result, &(table[n]), 1);
739 		n = (bytes >> 12) & 0x3f;
740 		kore_buf_append(&result, &(table[n]), 1);
741 		if (nb > 1) {
742 			n = (bytes >> 6) & 0x3f;
743 			kore_buf_append(&result, &(table[n]), 1);
744 			if (nb > 2) {
745 				n = bytes & 0x3f;
746 				kore_buf_append(&result, &(table[n]), 1);
747 			}
748 		}
749 
750 		len -= nb;
751 	}
752 
753 	if (!(flags & KORE_BASE64_RAW)) {
754 		switch (nb) {
755 		case 1:
756 			kore_buf_appendf(&result, "==");
757 			break;
758 		case 2:
759 			kore_buf_appendf(&result, "=");
760 			break;
761 		case 3:
762 			break;
763 		default:
764 			kore_buf_cleanup(&result);
765 			return (KORE_RESULT_ERROR);
766 		}
767 	}
768 
769 	/* result.data gets taken over so no need to cleanup result. */
770 	*out = kore_buf_stringify(&result, NULL);
771 
772 	return (KORE_RESULT_OK);
773 }
774 
775 static int
utils_base64_decode(const char * in,u_int8_t ** out,size_t * olen,const char * table,int flags)776 utils_base64_decode(const char *in, u_int8_t **out, size_t *olen,
777     const char *table, int flags)
778 {
779 	int			i, c;
780 	u_int8_t		d, n, o;
781 	struct kore_buf		*res, buf;
782 	const char		*ptr, *pad;
783 	u_int32_t		b, len, plen, idx;
784 
785 	i = 4;
786 	b = 0;
787 	d = 0;
788 	c = 0;
789 	len = strlen(in);
790 	memset(&buf, 0, sizeof(buf));
791 
792 	if (flags & KORE_BASE64_RAW) {
793 		switch (len % 4) {
794 		case 2:
795 			plen = 2;
796 			pad = "==";
797 			break;
798 		case 3:
799 			plen = 1;
800 			pad = "=";
801 			break;
802 		default:
803 			return (KORE_RESULT_ERROR);
804 		}
805 
806 		kore_buf_init(&buf, len + plen);
807 		kore_buf_append(&buf, in, len);
808 		kore_buf_append(&buf, pad, plen);
809 
810 		len = len + plen;
811 		ptr = (const char *)buf.data;
812 	} else {
813 		ptr = in;
814 	}
815 
816 	res = kore_buf_alloc(len);
817 
818 	for (idx = 0; idx < len; idx++) {
819 		c = ptr[idx];
820 		if (c == '=')
821 			break;
822 
823 		for (o = 0; o < B64_TABLE_LEN; o++) {
824 			if (table[o] == c) {
825 				d = o;
826 				break;
827 			}
828 		}
829 
830 		if (o == B64_TABLE_LEN) {
831 			*out = NULL;
832 			kore_buf_free(res);
833 			kore_buf_cleanup(&buf);
834 			return (KORE_RESULT_ERROR);
835 		}
836 
837 		b |= (d & 0x3f) << ((i - 1) * 6);
838 		i--;
839 		if (i == 0) {
840 			for (i = 2; i >= 0; i--) {
841 				n = (b >> (8 * i));
842 				kore_buf_append(res, &n, 1);
843 			}
844 
845 			b = 0;
846 			i = 4;
847 		}
848 	}
849 
850 	if (c == '=') {
851 		if (i > 2) {
852 			*out = NULL;
853 			kore_buf_free(res);
854 			kore_buf_cleanup(&buf);
855 			return (KORE_RESULT_ERROR);
856 		}
857 
858 		o = i;
859 		for (i = 2; i >= o; i--) {
860 			n = (b >> (8 * i));
861 			kore_buf_append(res, &n, 1);
862 		}
863 	}
864 
865 	kore_buf_cleanup(&buf);
866 	*out = kore_buf_release(res, olen);
867 
868 	return (KORE_RESULT_OK);
869 }
870