summaryrefslogtreecommitdiffstats
path: root/tools/base64.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/base64.c')
-rw-r--r--tools/base64.c135
1 files changed, 135 insertions, 0 deletions
diff --git a/tools/base64.c b/tools/base64.c
new file mode 100644
index 0000000..2cfa98d
--- /dev/null
+++ b/tools/base64.c
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2018 Yubico AB. All rights reserved.
+ * Use of this source code is governed by a BSD-style
+ * license that can be found in the LICENSE file.
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <openssl/bio.h>
+#include <openssl/evp.h>
+
+#include <limits.h>
+#include <stdint.h>
+#include <string.h>
+
+#include "../openbsd-compat/openbsd-compat.h"
+#include "extern.h"
+
+int
+base64_encode(const void *ptr, size_t len, char **out)
+{
+ BIO *bio_b64 = NULL;
+ BIO *bio_mem = NULL;
+ char *b64_ptr = NULL;
+ long b64_len;
+ int n;
+ int ok = -1;
+
+ if (ptr == NULL || out == NULL || len > INT_MAX)
+ return (-1);
+
+ *out = NULL;
+
+ if ((bio_b64 = BIO_new(BIO_f_base64())) == NULL)
+ goto fail;
+ if ((bio_mem = BIO_new(BIO_s_mem())) == NULL)
+ goto fail;
+
+ BIO_set_flags(bio_b64, BIO_FLAGS_BASE64_NO_NL);
+ BIO_push(bio_b64, bio_mem);
+
+ n = BIO_write(bio_b64, ptr, (int)len);
+ if (n < 0 || (size_t)n != len)
+ goto fail;
+
+ if (BIO_flush(bio_b64) < 0)
+ goto fail;
+
+ b64_len = BIO_get_mem_data(bio_b64, &b64_ptr);
+ if (b64_len < 0 || (size_t)b64_len == SIZE_MAX || b64_ptr == NULL)
+ goto fail;
+ if ((*out = calloc(1, (size_t)b64_len + 1)) == NULL)
+ goto fail;
+
+ memcpy(*out, b64_ptr, (size_t)b64_len);
+ ok = 0;
+
+fail:
+ BIO_free(bio_b64);
+ BIO_free(bio_mem);
+
+ return (ok);
+}
+
+int
+base64_decode(const char *in, void **ptr, size_t *len)
+{
+ BIO *bio_mem = NULL;
+ BIO *bio_b64 = NULL;
+ size_t alloc_len;
+ int n;
+ int ok = -1;
+
+ if (in == NULL || ptr == NULL || len == NULL || strlen(in) > INT_MAX)
+ return (-1);
+
+ *ptr = NULL;
+ *len = 0;
+
+ if ((bio_b64 = BIO_new(BIO_f_base64())) == NULL)
+ goto fail;
+ if ((bio_mem = BIO_new_mem_buf((const void *)in, -1)) == NULL)
+ goto fail;
+
+ BIO_set_flags(bio_b64, BIO_FLAGS_BASE64_NO_NL);
+ BIO_push(bio_b64, bio_mem);
+
+ alloc_len = strlen(in);
+ if ((*ptr = calloc(1, alloc_len)) == NULL)
+ goto fail;
+
+ n = BIO_read(bio_b64, *ptr, (int)alloc_len);
+ if (n <= 0 || BIO_eof(bio_b64) == 0)
+ goto fail;
+
+ *len = (size_t)n;
+ ok = 0;
+
+fail:
+ BIO_free(bio_b64);
+ BIO_free(bio_mem);
+
+ if (ok < 0) {
+ free(*ptr);
+ *ptr = NULL;
+ *len = 0;
+ }
+
+ return (ok);
+}
+
+int
+base64_read(FILE *f, struct blob *out)
+{
+ char *line = NULL;
+ size_t linesize = 0;
+ ssize_t n;
+
+ out->ptr = NULL;
+ out->len = 0;
+
+ if ((n = getline(&line, &linesize, f)) <= 0 ||
+ (size_t)n != strlen(line)) {
+ free(line); /* XXX should be free'd _even_ if getline() fails */
+ return (-1);
+ }
+
+ if (base64_decode(line, (void **)&out->ptr, &out->len) < 0) {
+ free(line);
+ return (-1);
+ }
+
+ free(line);
+
+ return (0);
+}