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