xref: /freebsd/contrib/libfido2/tools/base64.c (revision 3c4ba5f55438f7afd4f4b0b56f88f2bb505fd6a6)
1 /*
2  * Copyright (c) 2018 Yubico AB. All rights reserved.
3  * Use of this source code is governed by a BSD-style
4  * license that can be found in the LICENSE file.
5  */
6 
7 #include <openssl/bio.h>
8 #include <openssl/evp.h>
9 
10 #include <limits.h>
11 #include <stdint.h>
12 #include <string.h>
13 
14 #include "../openbsd-compat/openbsd-compat.h"
15 #include "extern.h"
16 
17 int
18 base64_encode(const void *ptr, size_t len, char **out)
19 {
20 	BIO  *bio_b64 = NULL;
21 	BIO  *bio_mem = NULL;
22 	char *b64_ptr = NULL;
23 	long  b64_len;
24 	int   n;
25 	int   ok = -1;
26 
27 	if (ptr == NULL || out == NULL || len > INT_MAX)
28 		return (-1);
29 
30 	*out = NULL;
31 
32 	if ((bio_b64 = BIO_new(BIO_f_base64())) == NULL)
33 		goto fail;
34 	if ((bio_mem = BIO_new(BIO_s_mem())) == NULL)
35 		goto fail;
36 
37 	BIO_set_flags(bio_b64, BIO_FLAGS_BASE64_NO_NL);
38 	BIO_push(bio_b64, bio_mem);
39 
40 	n = BIO_write(bio_b64, ptr, (int)len);
41 	if (n < 0 || (size_t)n != len)
42 		goto fail;
43 
44 	if (BIO_flush(bio_b64) < 0)
45 		goto fail;
46 
47 	b64_len = BIO_get_mem_data(bio_b64, &b64_ptr);
48 	if (b64_len < 0 || (size_t)b64_len == SIZE_MAX || b64_ptr == NULL)
49 		goto fail;
50 	if ((*out = calloc(1, (size_t)b64_len + 1)) == NULL)
51 		goto fail;
52 
53 	memcpy(*out, b64_ptr, (size_t)b64_len);
54 	ok = 0;
55 
56 fail:
57 	BIO_free(bio_b64);
58 	BIO_free(bio_mem);
59 
60 	return (ok);
61 }
62 
63 int
64 base64_decode(const char *in, void **ptr, size_t *len)
65 {
66 	BIO    *bio_mem = NULL;
67 	BIO    *bio_b64 = NULL;
68 	size_t  alloc_len;
69 	int     n;
70 	int     ok = -1;
71 
72 	if (in == NULL || ptr == NULL || len == NULL || strlen(in) > INT_MAX)
73 		return (-1);
74 
75 	*ptr = NULL;
76 	*len = 0;
77 
78 	if ((bio_b64 = BIO_new(BIO_f_base64())) == NULL)
79 		goto fail;
80 	if ((bio_mem = BIO_new_mem_buf((const void *)in, -1)) == NULL)
81 		goto fail;
82 
83 	BIO_set_flags(bio_b64, BIO_FLAGS_BASE64_NO_NL);
84 	BIO_push(bio_b64, bio_mem);
85 
86 	alloc_len = strlen(in);
87 	if ((*ptr = calloc(1, alloc_len)) == NULL)
88 		goto fail;
89 
90 	n = BIO_read(bio_b64, *ptr, (int)alloc_len);
91 	if (n <= 0 || BIO_eof(bio_b64) == 0)
92 		goto fail;
93 
94 	*len = (size_t)n;
95 	ok = 0;
96 
97 fail:
98 	BIO_free(bio_b64);
99 	BIO_free(bio_mem);
100 
101 	if (ok < 0) {
102 		free(*ptr);
103 		*ptr = NULL;
104 		*len = 0;
105 	}
106 
107 	return (ok);
108 }
109 
110 int
111 base64_read(FILE *f, struct blob *out)
112 {
113 	char *line = NULL;
114 	size_t linesize = 0;
115 	ssize_t n;
116 
117 	out->ptr = NULL;
118 	out->len = 0;
119 
120 	if ((n = getline(&line, &linesize, f)) <= 0 ||
121 	    (size_t)n != strlen(line)) {
122 		free(line); /* XXX should be free'd _even_ if getline() fails */
123 		return (-1);
124 	}
125 
126 	if (base64_decode(line, (void **)&out->ptr, &out->len) < 0) {
127 		free(line);
128 		return (-1);
129 	}
130 
131 	free(line);
132 
133 	return (0);
134 }
135