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