Verified Commit 7381cbdc authored by Karel Koci's avatar Karel Koci 🤘
Browse files

lib: replace libb64 with openssl

We have problem with libb64 on ARM (it effectively does not work).
Updater is already linked against OpenSSL so why not use it for that as
well. The API for it is not exactly clean so it is wrapped in its own
file but otherwise it is clean solution as it removes dependency and
reuses existing one.
parent f0917aec
......@@ -18,16 +18,6 @@ RUN \
lua5.1-dev \
asciidoc bash
# libb64
RUN \
wget "https://sourceforge.net/projects/libb64/files/libb64-1.2.1.zip" && \
unzip "libb64-1.2.1.zip" && rm "libb64-1.2.1.zip" && \
cd "libb64-1.2.1" && \
CFLAGS=-fPIC make -C src && \
cp src/libb64.a /usr/lib/ && \
cp -r include/b64 /usr/include/ && \
cd .. && rm -rf "libb64-1.2.1"
# argp-standalone with -fPIC
RUN \
wget "http://www.lysator.liu.se/~nisse/misc/argp-standalone-1.3.tar.gz" && \
......
......@@ -12,7 +12,7 @@ RUN \
make cmake pkg-config gcc \
libcurl4-openssl-dev libevent-dev libssl-dev liburiparser-dev \
libarchive-dev \
libb64-dev uthash-dev \
uthash-dev \
liblua5.1-0-dev \
libfile-slurp-perl \
&& \
......
......@@ -14,7 +14,7 @@ RUN \
check cppcheck lua-check valgrind \
libcurl4-openssl-dev libevent-dev libssl-dev liburiparser-dev \
libarchive-dev \
libb64-dev uthash-dev \
uthash-dev \
liblua5.1-0-dev \
asciidoc lcov markdown libcommon-sense-perl libfile-slurp-perl \
&& \
......
......@@ -10,7 +10,6 @@ Binary dependencies:
* Lua 5.1
* libcurl
* libevent2
* libb64
* uthash
* liburiparser
* libarchive
......
......@@ -30,7 +30,6 @@ PKG_CHECK_MODULES([LIBARCHIVE], [libarchive])
PKG_CHECK_MODULES([LIBCURL], [libcurl])
PKG_CHECK_MODULES([LIBCRYPTO], [libcrypto])
PKG_CHECK_MODULES([LIBURIPARSER], [liburiparser >= 0.9])
AC_CHECK_HEADERS([b64/cdecode.h],, AC_MSG_ERROR([Missing libb64]))
AC_LINK_IFELSE(
[AC_LANG_PROGRAM([#include <argp.h>],[argp_parse(0,1,NULL,0,0,0);])],,
AC_CHECK_LIB([argp], [argp_parse], , AC_MSG_ERROR([Missing libargp]))
......
......@@ -3,6 +3,7 @@ lib_LTLIBRARIES += libupdater.la
libupdater_la_SOURCES = \
%reldir%/archive.c \
%reldir%/arguments.c \
%reldir%/base64.c \
%reldir%/download.c \
%reldir%/embed_types.c \
%reldir%/events.c \
......@@ -55,7 +56,7 @@ libupdater_la_LDFLAGS = \
$(LIBCRYPTO_LIBS) \
$(LIBURIPARSER_LIBS) \
$(CODE_COVERAGE_LIBS) \
-lb64 -ldl
-ldl
##################################################################################
......
/*
* Copyright 2020, CZ.NIC z.s.p.o. (http://www.nic.cz/)
*
* This file is part of the Turris Updater.
*
* Updater is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Updater is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Updater. If not, see <http://www.gnu.org/licenses/>.
*/
#include "base64.h"
#include <openssl/bio.h>
#include <openssl/evp.h>
#include <openssl/err.h>
#include "logging.h"
static bool base64_is_valid_char(const char c) {
return \
(c >= '0' && c <= '9') || \
(c >= 'A' && c <= 'Z') || \
(c >= 'a' && c <= 'z') || \
(c == '+' || c == '/' || c == '=');
}
unsigned base64_valid(const char *data, size_t len) {
// TODO this is only minimal verification, we should do more some times in future
for (size_t i = 0; i < len; i++)
if (!base64_is_valid_char(data[i]))
return i;
return len;
}
size_t base64_decode_len(const char *data, size_t len) {
size_t padding = 0;
if (data != NULL)
padding = data[len - 1] == '=' ? (data[len - 2] == '=' ? 2 : 1) : 0;
return (len * 3 / 4) - padding;
}
size_t base64_decode_allocate(const char *data, size_t len, uint8_t **buff) {
size_t decode_len = base64_decode_len(data, len);
// Note: calloc here is intentional. OpenSSL behaves interestingly and
// valgrind because of that reports that some bytes are not initialized. This
// way we zero them all thanks to that make it all initialized.
*buff = calloc(decode_len + 1, 1);
return decode_len;
}
bool base64_decode(const char *data, size_t data_len, uint8_t *buff) {
BIO *bio= BIO_new_mem_buf(data, data_len);
BIO *b64 = BIO_new(BIO_f_base64());
bio = BIO_push(b64, bio);
BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL);
int len = BIO_read(bio, buff, base64_decode_len(data, data_len));
BIO_free_all(bio);
if (len <= 0 && would_log(LL_TRACE))
TRACE("base64 decode failed (%.*s): %s", (int)data_len, data,
ERR_error_string(ERR_get_error(), NULL));
return len > 0;
}
/*
* Copyright 2018-2020, CZ.NIC z.s.p.o. (http://www.nic.cz/)
*
* This file is part of the turris updater.
*
* Updater is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Updater is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Updater. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef UPDATER_BASE64_H
#define UPDATER_BASE64_H
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
// This is OpenSSL based base64 decoding utility
// Verify if given data are encoded in base64 format
// data: pointer to start of data
// len: size of data
// It returns len if data are valid base64 format, it returns index of problematic
// character otherwise.
unsigned base64_valid(const char *data, size_t len);
// Analyze provided data and return appropriate buffer size
// data: pointer to data start (can be NULL and in that case maximal required
// buffer for len length of string is returned)
// len: size of data (use strlen for string or just specify exact size)
// Returns exact output size for provided string or maximum size for NULL
size_t base64_decode_len(const char *data, size_t len);
// base64_decode_len variant that allocates appropriately sized buffer with one
// additional byte set to zero at the end.
// User should free returned memory after use.
size_t base64_decode_allocate(const char *data, size_t len, uint8_t **buff);
// Decode base64 encoded data in data to buff
// data: pointer to start of base64 encoded data
// data_len: size of data string
// buff: buffer of at least base64_decode_len provided length to write data to.
// Returns true if decoding was successful and false otherwise.
bool base64_decode(const char *data, size_t data_len, uint8_t *buff);
#endif
......@@ -19,10 +19,10 @@
#include "signature.h"
#include <string.h>
#include <fcntl.h>
#include <b64/cdecode.h>
#include <openssl/evp.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include "base64.h"
#include "logging.h"
#define PUBLIC_KEY_SIZE 32
......@@ -68,10 +68,13 @@ static bool key_load_generic(const uint8_t *data, size_t len, void *key, size_t
data_end = data + len;
size_t size = data_end - data_start;
char *buff = malloc((size * 3 / 4) + 1);
base64_decodestate s;
base64_init_decodestate(&s);
size_t cnt = base64_decode_block((const void*)(data_start), size, buff, &s);
uint8_t *buff;
size_t cnt = base64_decode_allocate((const char*)data_start, size, &buff);
if (!base64_decode((const char*)data_start, size, buff)) {
TRACE("Key decode failed for key: %.*s", (int)size, data_start);
sign_errno = SIGN_ERR_KEY_FORMAT;
return false;
}
if (cnt != key_len) {
free(buff);
......
......@@ -18,6 +18,7 @@
*/
#include "uri.h"
#include "signature.h"
#include "base64.h"
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
......@@ -395,11 +396,13 @@ static bool uri_finish_data(struct uri *uri) {
// We ignore any unsupported arguments just for compatibility
start = next + 1;
}
size_t len = strlen(start);
if (is_base64) {
uint8_t *buf;
size_t buf_size;
base64_decode(start, &buf, &buf_size);
size_t buf_size = base64_decode_allocate(start, len, &buf);
ASSERT_MSG(base64_decode(start, len, buf),
"base64 decode should be successful as we are checking data for validity on URI creation");
size_t written = fwrite(buf, 1, buf_size, uri->output);
free(buf);
if (written != buf_size) {
......
/*
* Copyright 2016-2018, CZ.NIC z.s.p.o. (http://www.nic.cz/)
* Copyright 2016-2020, CZ.NIC z.s.p.o. (http://www.nic.cz/)
*
* This file is part of the turris updater.
*
......@@ -31,7 +31,6 @@
#include <dirent.h>
#include <signal.h>
#include <poll.h>
#include <b64/cdecode.h>
bool dump2file (const char *file, const char *text) {
FILE *f = fopen(file, "w");
......@@ -106,37 +105,6 @@ void exec_hook(const char *dir, const char *message) {
free(namelist);
}
static bool base64_is_valid_char(const char c) {
return \
(c >= '0' && c <= '9') || \
(c >= 'A' && c <= 'Z') || \
(c >= 'a' && c <= 'z') || \
(c == '+' || c == '/' || c == '=');
}
unsigned base64_valid(const char *data) {
// TODO this is only minimal verification, we should do more some times in future
int check_off = 0;
while (data[check_off] != '\0')
if (!base64_is_valid_char(data[check_off++]))
return check_off;
return 0;
}
void base64_decode(const char *data, uint8_t **buf, size_t *len) {
size_t data_len = strlen(data);
size_t buff_len = (data_len * 3 / 4) + 2;
*buf = malloc(sizeof(uint8_t) * buff_len);
base64_decodestate s;
base64_init_decodestate(&s);
int cnt = base64_decode_block(data, data_len, (char*)*buf, &s);
ASSERT(cnt >= 0);
*len = cnt;
ASSERT_MSG((*len + 1) < buff_len, "Output buffer was too small, this should not happen!");
(*buf)[*len] = '\0'; // Terminate this with \0 so if it is string it can be used as such
}
static bool cleanup_registered = false;
static struct {
size_t size, allocated;
......
/*
* Copyright 2016-2018, CZ.NIC z.s.p.o. (http://www.nic.cz/)
* Copyright 2016-2020, CZ.NIC z.s.p.o. (http://www.nic.cz/)
*
* This file is part of the turris updater.
*
......@@ -46,17 +46,6 @@ bool statfile(const char *file, int mode);
// Executes all executable files in given directory
void exec_hook(const char *dir, const char *message) __attribute__((nonnull));
// Verify if given data are encoded in base64 format (this is only minimal check,
// not complete one)
// It returns 0 if data are valid base64 format, it returns index+1 of problematic
// character otherwise.
unsigned base64_valid(const char *data);
// Decode given string as a base64 encoded data
// This function allocates buffer of appropriate size to buf argument and sets
// size of that buffer to len.
void base64_decode(const char *data, uint8_t **buf, size_t *len) __attribute__((nonnull));
// Using these functions you can register/unregister cleanup function. Note that
// they are called in reverse order of insertion. This is implemented using atexit
// function.
......
# Test binaries
archive
base64
util
syscnf
path_utils
......
TESTS += \
%reldir%/archive \
%reldir%/base64 \
%reldir%/util \
%reldir%/syscnf \
%reldir%/path_utils \
......@@ -11,6 +12,7 @@ TESTS += \
check_PROGRAMS += \
%reldir%/archive \
%reldir%/base64 \
%reldir%/util \
%reldir%/syscnf \
%reldir%/path_utils \
......@@ -20,6 +22,7 @@ check_PROGRAMS += \
%reldir%/uri \
%reldir%/interpreter
%canon_reldir%_archive_LDADD = %reldir%/libctest.la
%canon_reldir%_base64_LDADD = %reldir%/libctest.la
%canon_reldir%_util_LDADD = %reldir%/libctest.la
%canon_reldir%_syscnf_LDADD = %reldir%/libctest.la
%canon_reldir%_path_utils_LDADD = %reldir%/libctest.la
......@@ -29,6 +32,7 @@ check_PROGRAMS += \
%canon_reldir%_uri_LDADD = %reldir%/libctest.la
%canon_reldir%_interpreter_LDADD = %reldir%/libctest.la
%canon_reldir%_archive_CFLAGS = -I $(srcdir)/src/lib $(libupdater_la_CFLAGS)
%canon_reldir%_base64_CFLAGS = -I $(srcdir)/src/lib $(libupdater_la_CFLAGS)
%canon_reldir%_util_CFLAGS = -I $(srcdir)/src/lib $(libupdater_la_CFLAGS)
%canon_reldir%_syscnf_CFLAGS = -I $(srcdir)/src/lib $(libupdater_la_CFLAGS)
%canon_reldir%_path_utils_CFLAGS = -I $(srcdir)/src/lib $(libupdater_la_CFLAGS)
......
/*
* Copyright 2020, CZ.NIC z.s.p.o. (http://www.nic.cz/)
*
* This file is part of the turris updater.
*
* Updater is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Updater is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Updater. If not, see <http://www.gnu.org/licenses/>.
*/
#include "ctest.h"
#include <base64.h>
#include <stdlib.h>
#define BASE64_PLAIN "Hello\n"
#define BASE64_ENCOD "SGVsbG8K"
#define BASE64_INVALID "SGvs$bG8L"
START_TEST(base64_is_valid) {
ck_assert_int_eq(8, base64_valid(BASE64_ENCOD, strlen(BASE64_ENCOD)));
ck_assert_int_eq(4, base64_valid(BASE64_INVALID, strlen(BASE64_INVALID)));
}
END_TEST
START_TEST(base64) {
size_t len = strlen(BASE64_ENCOD);
uint8_t *result;
size_t result_len = base64_decode_allocate(BASE64_ENCOD, len, &result);
ck_assert_int_eq(6, result_len);
ck_assert(base64_decode(BASE64_ENCOD, len, result));
ck_assert_str_eq(BASE64_PLAIN, (char*)result);
free(result);
}
END_TEST
Suite *gen_test_suite(void) {
Suite *result = suite_create("base64");
TCase *cs = tcase_create("base64");
tcase_add_test(cs, base64_is_valid);
tcase_add_test(cs, base64);
suite_add_tcase(result, cs);
return result;
}
/*
* Copyright 2018, CZ.NIC z.s.p.o. (http://www.nic.cz/)
* Copyright 2018-2020, CZ.NIC z.s.p.o. (http://www.nic.cz/)
*
* This file is part of the turris updater.
*
......@@ -21,25 +21,6 @@
#include <stdbool.h>
#define BASE64_PLAIN "Hello\n"
#define BASE64_ENCOD "SGVsbG8K"
START_TEST(base64_is_valid) {
ck_assert_int_eq(0, base64_valid(BASE64_ENCOD));
ck_assert_int_eq(5, base64_valid("SGvs$bG8L"));
}
END_TEST
START_TEST(base64) {
uint8_t *result;
size_t result_len;
base64_decode(BASE64_ENCOD, &result, &result_len);
ck_assert_int_eq(6, result_len);
ck_assert_str_eq(BASE64_PLAIN, (char*)result);
free(result);
}
END_TEST
static int cleaned;
static void cleanup_func(void *data) {
......@@ -105,8 +86,6 @@ Suite *gen_test_suite(void) {
Suite *result = suite_create("Util");
TCase *util = tcase_create("util");
tcase_set_timeout(util, 30);
tcase_add_test(util, base64_is_valid);
tcase_add_test(util, base64);
tcase_add_test(util, cleanup_multi);
tcase_add_test(util, cleanup_single);
tcase_add_test(util, cleanup_by_data);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment