utils.c (14050B)
1 /*
2 * Copyright (c) 2013-2022 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 <ctype.h>
21 #include <stdio.h>
22 #include <stdarg.h>
23 #include <string.h>
24 #include <stdlib.h>
25 #include <time.h>
26 #include <limits.h>
27
28 #include "kore.h"
29
30 static struct {
31 char *name;
32 int value;
33 } month_names[] = {
34 { "Jan", 0 },
35 { "Feb", 1 },
36 { "Mar", 2 },
37 { "Apr", 3 },
38 { "May", 4 },
39 { "Jun", 5 },
40 { "Jul", 6 },
41 { "Aug", 7 },
42 { "Sep", 8 },
43 { "Oct", 9 },
44 { "Nov", 10 },
45 { "Dec", 11 },
46 { NULL, 0 },
47 };
48
49 static void fatal_log(const char *, va_list);
50 static int utils_base64_encode(const void *, size_t, char **,
51 const char *, int);
52 static int utils_base64_decode(const char *, u_int8_t **,
53 size_t *, const char *, int);
54 static int utils_x509name_tobuf(void *, int, int, const char *,
55 const void *, size_t, int);
56
57 static char b64_table[] = \
58 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
59
60 static char b64url_table[] = \
61 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
62
63 /* b64_table and b64url_table are the same size. */
64 #define B64_TABLE_LEN (sizeof(b64_table))
65
66 size_t
67 kore_strlcpy(char *dst, const char *src, const size_t len)
68 {
69 char *d = dst;
70 const char *s = src;
71 const char *end = dst + len - 1;
72
73 if (len == 0)
74 fatal("kore_strlcpy: len == 0");
75
76 while ((*d = *s) != '\0') {
77 if (d == end) {
78 *d = '\0';
79 break;
80 }
81
82 d++;
83 s++;
84 }
85
86 while (*s != '\0')
87 s++;
88
89 return (s - src);
90 }
91
92 int
93 kore_snprintf(char *str, size_t size, int *len, const char *fmt, ...)
94 {
95 int l;
96 va_list args;
97
98 va_start(args, fmt);
99 l = vsnprintf(str, size, fmt, args);
100 va_end(args);
101
102 if (l == -1 || (size_t)l >= size)
103 return (KORE_RESULT_ERROR);
104
105 if (len != NULL)
106 *len = l;
107
108 return (KORE_RESULT_OK);
109 }
110
111 long long
112 kore_strtonum(const char *str, int base, long long min, long long max, int *err)
113 {
114 long long l;
115 char *ep;
116
117 if (min > max) {
118 *err = KORE_RESULT_ERROR;
119 return (0);
120 }
121
122 errno = 0;
123 l = strtoll(str, &ep, base);
124 if (errno != 0 || str == ep || *ep != '\0') {
125 *err = KORE_RESULT_ERROR;
126 return (0);
127 }
128
129 if (l < min) {
130 *err = KORE_RESULT_ERROR;
131 return (0);
132 }
133
134 if (l > max) {
135 *err = KORE_RESULT_ERROR;
136 return (0);
137 }
138
139 *err = KORE_RESULT_OK;
140 return (l);
141 }
142
143 u_int64_t
144 kore_strtonum64(const char *str, int sign, int *err)
145 {
146 u_int64_t l;
147 long long ll;
148 char *ep;
149 int check;
150
151 l = 0;
152 check = 1;
153
154 ll = strtoll(str, &ep, 10);
155 if ((errno == EINVAL || errno == ERANGE) &&
156 (ll == LLONG_MIN || ll == LLONG_MAX)) {
157 if (sign) {
158 *err = KORE_RESULT_ERROR;
159 return (0);
160 }
161
162 check = 0;
163 }
164
165 if (!sign) {
166 l = strtoull(str, &ep, 10);
167 if ((errno == EINVAL || errno == ERANGE) && l == ULONG_MAX) {
168 *err = KORE_RESULT_ERROR;
169 return (0);
170 }
171
172 if (check && ll < 0) {
173 *err = KORE_RESULT_ERROR;
174 return (0);
175 }
176 }
177
178 if (str == ep || *ep != '\0') {
179 *err = KORE_RESULT_ERROR;
180 return (0);
181 }
182
183 *err = KORE_RESULT_OK;
184 return ((sign) ? (u_int64_t)ll : l);
185 }
186
187 double
188 kore_strtodouble(const char *str, long double min, long double max, int *err)
189 {
190 double d;
191 char *ep;
192
193 if (min > max) {
194 *err = KORE_RESULT_ERROR;
195 return (0);
196 }
197
198 errno = 0;
199 d = strtod(str, &ep);
200 if (errno == ERANGE || str == ep || *ep != '\0') {
201 *err = KORE_RESULT_ERROR;
202 return (0);
203 }
204
205 if (d < min) {
206 *err = KORE_RESULT_ERROR;
207 return (0);
208 }
209
210 if (d > max) {
211 *err = KORE_RESULT_ERROR;
212 return (0);
213 }
214
215 *err = KORE_RESULT_OK;
216 return (d);
217 }
218
219 int
220 kore_split_string(char *input, const char *delim, char **out, size_t ele)
221 {
222 int count;
223 char **ap;
224
225 if (ele == 0)
226 return (0);
227
228 count = 0;
229 for (ap = out; ap < &out[ele - 1] &&
230 (*ap = strsep(&input, delim)) != NULL;) {
231 if (**ap != '\0') {
232 ap++;
233 count++;
234 }
235 }
236
237 *ap = NULL;
238 return (count);
239 }
240
241 void
242 kore_strip_chars(const char *in, const char strip, char **out)
243 {
244 char *p;
245 const char *s;
246 u_int32_t len;
247
248 len = strlen(in);
249 *out = kore_malloc(len + 1);
250 p = *out;
251
252 for (s = in; s < (in + len); s++) {
253 if (*s == strip)
254 continue;
255
256 *p++ = *s;
257 }
258
259 *p = '\0';
260 }
261
262 time_t
263 kore_date_to_time(const char *http_date)
264 {
265 time_t t;
266 int err, i;
267 struct tm tm, *ltm;
268 char *args[7], *tbuf[5], *sdup;
269
270 time(&t);
271 ltm = localtime(&t);
272 sdup = kore_strdup(http_date);
273
274 t = KORE_RESULT_ERROR;
275
276 if (kore_split_string(sdup, " ", args, 7) != 6) {
277 kore_log(LOG_WARNING, "misformed http-date: '%s'", http_date);
278 goto out;
279 }
280
281 memset(&tm, 0, sizeof(tm));
282
283 tm.tm_year = kore_strtonum(args[3], 10, 1900, 2068, &err) - 1900;
284 if (err == KORE_RESULT_ERROR) {
285 kore_log(LOG_WARNING, "misformed year in http-date: '%s'",
286 http_date);
287 goto out;
288 }
289
290 for (i = 0; month_names[i].name != NULL; i++) {
291 if (!strcmp(month_names[i].name, args[2])) {
292 tm.tm_mon = month_names[i].value;
293 break;
294 }
295 }
296
297 if (month_names[i].name == NULL) {
298 kore_log(LOG_WARNING, "misformed month in http-date: '%s'",
299 http_date);
300 goto out;
301 }
302
303 tm.tm_mday = kore_strtonum(args[1], 10, 1, 31, &err);
304 if (err == KORE_RESULT_ERROR) {
305 kore_log(LOG_WARNING, "misformed mday in http-date: '%s'",
306 http_date);
307 goto out;
308 }
309
310 if (kore_split_string(args[4], ":", tbuf, 5) != 3) {
311 kore_log(LOG_WARNING, "misformed HH:MM:SS in http-date: '%s'",
312 http_date);
313 goto out;
314 }
315
316 tm.tm_hour = kore_strtonum(tbuf[0], 10, 0, 23, &err);
317 if (err == KORE_RESULT_ERROR) {
318 kore_log(LOG_WARNING, "misformed hour in http-date: '%s'",
319 http_date);
320 goto out;
321 }
322
323 tm.tm_min = kore_strtonum(tbuf[1], 10, 0, 59, &err);
324 if (err == KORE_RESULT_ERROR) {
325 kore_log(LOG_WARNING, "misformed minutes in http-date: '%s'",
326 http_date);
327 goto out;
328 }
329
330 tm.tm_sec = kore_strtonum(tbuf[2], 10, 0, 60, &err);
331 if (err == KORE_RESULT_ERROR) {
332 kore_log(LOG_WARNING, "misformed seconds in http-date: '%s'",
333 http_date);
334 goto out;
335 }
336
337 tm.tm_isdst = ltm->tm_isdst;
338 t = mktime(&tm) + ltm->tm_gmtoff;
339 if (t == -1) {
340 t = 0;
341 kore_log(LOG_WARNING, "mktime() on '%s' failed", http_date);
342 }
343
344 out:
345 kore_free(sdup);
346 return (t);
347 }
348
349 char *
350 kore_time_to_date(time_t now)
351 {
352 struct tm *tm;
353 static time_t last = 0;
354 static char tbuf[32];
355
356 if (now != last) {
357 last = now;
358
359 tm = gmtime(&now);
360 if (!strftime(tbuf, sizeof(tbuf), "%a, %d %b %Y %T GMT", tm))
361 return (NULL);
362 }
363
364 return (tbuf);
365 }
366
367 u_int64_t
368 kore_time_ms(void)
369 {
370 struct timespec ts;
371
372 (void)clock_gettime(CLOCK_MONOTONIC, &ts);
373
374 return ((u_int64_t)(ts.tv_sec * 1000 + (ts.tv_nsec / 1000000)));
375 }
376
377 int
378 kore_base64url_encode(const void *data, size_t len, char **out, int flags)
379 {
380 return (utils_base64_encode(data, len, out, b64url_table, flags));
381 }
382
383 int
384 kore_base64_encode(const void *data, size_t len, char **out)
385 {
386 return (utils_base64_encode(data, len, out, b64_table, 0));
387 }
388
389 int
390 kore_base64url_decode(const char *in, u_int8_t **out, size_t *olen, int flags)
391 {
392 return (utils_base64_decode(in, out, olen, b64url_table, flags));
393 }
394
395 int
396 kore_base64_decode(const char *in, u_int8_t **out, size_t *olen)
397 {
398 return (utils_base64_decode(in, out, olen, b64_table, 0));
399 }
400
401 void *
402 kore_mem_find(void *src, size_t slen, const void *needle, size_t len)
403 {
404 size_t pos;
405
406 for (pos = 0; pos < slen; pos++) {
407 if ( *((u_int8_t *)src + pos) != *(const u_int8_t *)needle)
408 continue;
409
410 if ((slen - pos) < len)
411 return (NULL);
412
413 if (!memcmp((u_int8_t *)src + pos, needle, len))
414 return ((u_int8_t *)src + pos);
415 }
416
417 return (NULL);
418 }
419
420 char *
421 kore_text_trim(char *string, size_t len)
422 {
423 char *end;
424
425 if (len == 0)
426 return (string);
427
428 end = (string + len) - 1;
429 while (isspace(*(unsigned char *)string) && string < end)
430 string++;
431
432 while (isspace(*(unsigned char *)end) && end > string)
433 *(end)-- = '\0';
434
435 return (string);
436 }
437
438 char *
439 kore_read_line(FILE *fp, char *in, size_t len)
440 {
441 char *p, *t;
442
443 if (fgets(in, len, fp) == NULL)
444 return (NULL);
445
446 p = in;
447 in[strcspn(in, "\n")] = '\0';
448
449 while (isspace(*(unsigned char *)p))
450 p++;
451
452 if (p[0] == '#' || p[0] == '\0') {
453 p[0] = '\0';
454 return (p);
455 }
456
457 for (t = p; *t != '\0'; t++) {
458 if (*t == '\t')
459 *t = ' ';
460 }
461
462 return (p);
463 }
464
465 const char *
466 kore_worker_name(int id)
467 {
468 static char buf[64];
469
470 switch (id) {
471 case KORE_WORKER_KEYMGR:
472 (void)snprintf(buf, sizeof(buf), "[keymgr]");
473 break;
474 case KORE_WORKER_ACME:
475 (void)snprintf(buf, sizeof(buf), "[acme]");
476 break;
477 default:
478 (void)snprintf(buf, sizeof(buf), "[wrk %d]", id);
479 break;
480 }
481
482 return (buf);
483 }
484
485 int
486 kore_x509_issuer_name(struct connection *c, char **out, int flags)
487 {
488 struct kore_buf buf;
489 KORE_X509_NAMES *name;
490
491 if ((name = kore_tls_x509_issuer_name(c)) == NULL)
492 return (KORE_RESULT_ERROR);
493
494 kore_buf_init(&buf, 1024);
495
496 if (!kore_tls_x509name_foreach(name, flags, &buf,
497 utils_x509name_tobuf)) {
498 kore_buf_cleanup(&buf);
499 return (KORE_RESULT_ERROR);
500 }
501
502 *out = kore_buf_stringify(&buf, NULL);
503
504 buf.offset = 0;
505 buf.data = NULL;
506
507 return (KORE_RESULT_OK);
508 }
509
510 int
511 kore_x509_subject_name(struct connection *c, char **out, int flags)
512 {
513 struct kore_buf buf;
514 KORE_X509_NAMES *name;
515
516 if ((name = kore_tls_x509_subject_name(c)) == NULL)
517 return (KORE_RESULT_ERROR);
518
519 kore_buf_init(&buf, 1024);
520
521 if (!kore_tls_x509name_foreach(name, flags, &buf,
522 utils_x509name_tobuf)) {
523 kore_buf_cleanup(&buf);
524 return (KORE_RESULT_ERROR);
525 }
526
527 *out = kore_buf_stringify(&buf, NULL);
528
529 buf.offset = 0;
530 buf.data = NULL;
531
532 return (KORE_RESULT_OK);
533 }
534
535 void
536 fatal(const char *fmt, ...)
537 {
538 va_list args;
539
540 va_start(args, fmt);
541 fatal_log(fmt, args);
542 va_end(args);
543
544 exit(1);
545 }
546
547 void
548 fatalx(const char *fmt, ...)
549 {
550 va_list args;
551
552 /* In case people call fatalx() from the parent context. */
553 if (worker != NULL)
554 kore_msg_send(KORE_MSG_PARENT, KORE_MSG_FATALX, NULL, 0);
555
556 va_start(args, fmt);
557 fatal_log(fmt, args);
558 va_end(args);
559
560 exit(1);
561 }
562
563 static void
564 fatal_log(const char *fmt, va_list args)
565 {
566 char buf[2048];
567
568 (void)vsnprintf(buf, sizeof(buf), fmt, args);
569 kore_log(LOG_ERR, "fatal: %s", buf);
570
571 if (worker != NULL && worker->id == KORE_WORKER_KEYMGR)
572 kore_keymgr_cleanup(1);
573 }
574
575 static int
576 utils_x509name_tobuf(void *udata, int islast, int nid, const char *field,
577 const void *data, size_t len, int flags)
578 {
579 struct kore_buf *buf = udata;
580
581 if (flags & KORE_X509_COMMON_NAME_ONLY) {
582 if (nid == KORE_X509_NAME_COMMON_NAME)
583 kore_buf_append(buf, data, len);
584 } else {
585 kore_buf_appendf(buf, "%s=", field);
586 kore_buf_append(buf, data, len);
587 if (!islast)
588 kore_buf_appendf(buf, " ");
589 }
590
591 return (KORE_RESULT_OK);
592 }
593
594 static int
595 utils_base64_encode(const void *data, size_t len, char **out,
596 const char *table, int flags)
597 {
598 u_int8_t n;
599 size_t nb;
600 const u_int8_t *ptr;
601 u_int32_t bytes;
602 struct kore_buf result;
603
604 nb = 0;
605 ptr = data;
606 kore_buf_init(&result, (len / 3) * 4);
607
608 while (len > 0) {
609 if (len > 2) {
610 nb = 3;
611 bytes = *ptr++ << 16;
612 bytes |= *ptr++ << 8;
613 bytes |= *ptr++;
614 } else if (len > 1) {
615 nb = 2;
616 bytes = *ptr++ << 16;
617 bytes |= *ptr++ << 8;
618 } else if (len == 1) {
619 nb = 1;
620 bytes = *ptr++ << 16;
621 } else {
622 kore_buf_cleanup(&result);
623 return (KORE_RESULT_ERROR);
624 }
625
626 n = (bytes >> 18) & 0x3f;
627 kore_buf_append(&result, &(table[n]), 1);
628 n = (bytes >> 12) & 0x3f;
629 kore_buf_append(&result, &(table[n]), 1);
630 if (nb > 1) {
631 n = (bytes >> 6) & 0x3f;
632 kore_buf_append(&result, &(table[n]), 1);
633 if (nb > 2) {
634 n = bytes & 0x3f;
635 kore_buf_append(&result, &(table[n]), 1);
636 }
637 }
638
639 len -= nb;
640 }
641
642 if (!(flags & KORE_BASE64_RAW)) {
643 switch (nb) {
644 case 1:
645 kore_buf_appendf(&result, "==");
646 break;
647 case 2:
648 kore_buf_appendf(&result, "=");
649 break;
650 case 3:
651 break;
652 default:
653 kore_buf_cleanup(&result);
654 return (KORE_RESULT_ERROR);
655 }
656 }
657
658 /* result.data gets taken over so no need to cleanup result. */
659 *out = kore_buf_stringify(&result, NULL);
660
661 return (KORE_RESULT_OK);
662 }
663
664 static int
665 utils_base64_decode(const char *in, u_int8_t **out, size_t *olen,
666 const char *table, int flags)
667 {
668 int i, c;
669 u_int8_t d, n, o;
670 struct kore_buf *res, buf;
671 const char *ptr, *pad;
672 u_int32_t b, len, plen, idx;
673
674 i = 4;
675 b = 0;
676 d = 0;
677 c = 0;
678 len = strlen(in);
679 memset(&buf, 0, sizeof(buf));
680
681 if (flags & KORE_BASE64_RAW) {
682 switch (len % 4) {
683 case 2:
684 plen = 2;
685 pad = "==";
686 break;
687 case 3:
688 plen = 1;
689 pad = "=";
690 break;
691 default:
692 return (KORE_RESULT_ERROR);
693 }
694
695 kore_buf_init(&buf, len + plen);
696 kore_buf_append(&buf, in, len);
697 kore_buf_append(&buf, pad, plen);
698
699 len = len + plen;
700 ptr = (const char *)buf.data;
701 } else {
702 ptr = in;
703 }
704
705 res = kore_buf_alloc(len);
706
707 for (idx = 0; idx < len; idx++) {
708 c = ptr[idx];
709 if (c == '=')
710 break;
711
712 for (o = 0; o < B64_TABLE_LEN; o++) {
713 if (table[o] == c) {
714 d = o;
715 break;
716 }
717 }
718
719 if (o == B64_TABLE_LEN) {
720 *out = NULL;
721 kore_buf_free(res);
722 kore_buf_cleanup(&buf);
723 return (KORE_RESULT_ERROR);
724 }
725
726 b |= (d & 0x3f) << ((i - 1) * 6);
727 i--;
728 if (i == 0) {
729 for (i = 2; i >= 0; i--) {
730 n = (b >> (8 * i));
731 kore_buf_append(res, &n, 1);
732 }
733
734 b = 0;
735 i = 4;
736 }
737 }
738
739 if (c == '=') {
740 if (i > 2) {
741 *out = NULL;
742 kore_buf_free(res);
743 kore_buf_cleanup(&buf);
744 return (KORE_RESULT_ERROR);
745 }
746
747 o = i;
748 for (i = 2; i >= o; i--) {
749 n = (b >> (8 * i));
750 kore_buf_append(res, &n, 1);
751 }
752 }
753
754 kore_buf_cleanup(&buf);
755 *out = kore_buf_release(res, olen);
756
757 return (KORE_RESULT_OK);
758 }