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