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