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