summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorValentin Bartenev <vbart@nginx.com>2021-10-26 15:43:44 +0300
committerValentin Bartenev <vbart@nginx.com>2021-10-26 15:43:44 +0300
commit7bf6253941d3b61e5eb3339fb5f68c84e9e68795 (patch)
treeff59b7a2c74d939c7eb3e08ef65246238bcb90d1
parent7503cc96df4f8c5637ac90dcf6095d93fd03296f (diff)
downloadunit-7bf6253941d3b61e5eb3339fb5f68c84e9e68795.tar.gz
unit-7bf6253941d3b61e5eb3339fb5f68c84e9e68795.tar.bz2
Custom implementation of Base64 decoding function.
Compared to the previous implementation based on OpenSSL, the new implementation has these advantages: 1. Strict and reliable detection of invalid strings, including strings with less than 4 bytes of garbage at the end; 2. Allows to use Base64 strings without '=' padding.
Diffstat (limited to '')
-rw-r--r--auto/sources1
-rw-r--r--src/nxt_conf_validation.c10
-rw-r--r--src/nxt_openssl.c76
-rw-r--r--src/nxt_string.c97
-rw-r--r--src/nxt_string.h2
-rw-r--r--src/nxt_tls.h2
-rw-r--r--src/test/nxt_base64_test.c98
-rw-r--r--src/test/nxt_tests.c4
-rw-r--r--src/test/nxt_tests.h1
9 files changed, 209 insertions, 82 deletions
diff --git a/auto/sources b/auto/sources
index 01fec6c1..990f5d11 100644
--- a/auto/sources
+++ b/auto/sources
@@ -170,6 +170,7 @@ NXT_TEST_SRCS=" \
src/test/nxt_rbtree1_test.c \
src/test/nxt_http_parse_test.c \
src/test/nxt_strverscmp_test.c \
+ src/test/nxt_base64_test.c \
"
diff --git a/src/nxt_conf_validation.c b/src/nxt_conf_validation.c
index 5701ae17..a090cd5f 100644
--- a/src/nxt_conf_validation.c
+++ b/src/nxt_conf_validation.c
@@ -517,8 +517,8 @@ static nxt_int_t
nxt_conf_vldt_ticket_key_element(nxt_conf_validation_t *vldt,
nxt_conf_value_t *value)
{
+ ssize_t ret;
nxt_str_t key;
- nxt_int_t ret;
if (nxt_conf_type(value) != NXT_CONF_STRING) {
return nxt_conf_vldt_error(vldt, "The \"key\" array must "
@@ -527,12 +527,8 @@ nxt_conf_vldt_ticket_key_element(nxt_conf_validation_t *vldt,
nxt_conf_get_string(value, &key);
- ret = nxt_openssl_base64_decode(NULL, 0, key.start, key.length);
- if (nxt_slow_path(ret == NXT_ERROR)) {
- return NXT_ERROR;
- }
-
- if (ret == NXT_DECLINED) {
+ ret = nxt_base64_decode(NULL, key.start, key.length);
+ if (ret == NXT_ERROR) {
return nxt_conf_vldt_error(vldt, "Invalid Base64 format for the ticket "
"key \"%V\".", &key);
}
diff --git a/src/nxt_openssl.c b/src/nxt_openssl.c
index d57928a4..1e08015e 100644
--- a/src/nxt_openssl.c
+++ b/src/nxt_openssl.c
@@ -621,8 +621,8 @@ static nxt_int_t
nxt_tls_ticket_keys(nxt_task_t *task, SSL_CTX *ctx, nxt_tls_init_t *tls_init,
nxt_mp_t *mp)
{
+ size_t len;
uint32_t i;
- nxt_int_t ret;
nxt_str_t value;
nxt_uint_t count;
nxt_conf_value_t *member, *tickets_conf;
@@ -686,14 +686,11 @@ nxt_tls_ticket_keys(nxt_task_t *task, SSL_CTX *ctx, nxt_tls_init_t *tls_init,
nxt_conf_get_string(member, &value);
- ret = nxt_openssl_base64_decode(buf, 80, value.start, value.length);
- if (nxt_slow_path(ret == NXT_ERROR)) {
- return NXT_ERROR;
- }
+ len = nxt_base64_decode(buf, value.start, value.length);
nxt_memcpy(ticket->name, buf, 16);
- if (ret == 48) {
+ if (len == 48) {
nxt_memcpy(ticket->aes_key, buf + 16, 16);
nxt_memcpy(ticket->hmac_key, buf + 32, 16);
ticket->size = 16;
@@ -1818,70 +1815,3 @@ nxt_openssl_copy_error(u_char *p, u_char *end)
return p;
}
-
-
-nxt_int_t
-nxt_openssl_base64_decode(u_char *d, size_t dlen, const u_char *s, size_t slen)
-{
- BIO *bio, *b64;
- nxt_int_t count, ret;
- u_char buf[128];
-
- b64 = BIO_new(BIO_f_base64());
- if (nxt_slow_path(b64 == NULL)) {
- goto error;
- }
-
- bio = BIO_new_mem_buf(s, slen);
- if (nxt_slow_path(bio == NULL)) {
- goto error;
- }
-
- bio = BIO_push(b64, bio);
-
- BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL);
-
- count = 0;
-
- if (d == NULL) {
-
- for ( ;; ) {
- ret = BIO_read(bio, buf, 128);
-
- if (ret < 0) {
- goto invalid;
- }
-
- count += ret;
-
- if (ret != 128) {
- break;
- }
- }
-
- } else {
- count = BIO_read(bio, d, dlen);
-
- if (count < 0) {
- goto invalid;
- }
- }
-
- BIO_free_all(bio);
-
- return count;
-
-error:
-
- BIO_vfree(b64);
- ERR_clear_error();
-
- return NXT_ERROR;
-
-invalid:
-
- BIO_free_all(bio);
- ERR_clear_error();
-
- return NXT_DECLINED;
-}
diff --git a/src/nxt_string.c b/src/nxt_string.c
index ab568990..b7aef79e 100644
--- a/src/nxt_string.c
+++ b/src/nxt_string.c
@@ -745,3 +745,100 @@ nxt_is_complex_uri_encoded(u_char *src, size_t length)
return 1;
}
+
+
+ssize_t
+nxt_base64_decode(u_char *dst, u_char *src, size_t length)
+{
+ u_char *end, *p;
+ size_t pad;
+ uint8_t v1, v2, v3, v4;
+
+ static const uint8_t decode[] = {
+ 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
+ 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
+ 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 62, 77, 77, 77, 63,
+ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 77, 77, 77, 77, 77, 77,
+ 77, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 77, 77, 77, 77, 77,
+ 77, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 77, 77, 77, 77, 77,
+
+ 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
+ 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
+ 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
+ 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
+ 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
+ 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
+ 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
+ 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77
+ };
+
+ end = src + length;
+ pad = (4 - (length % 4)) % 4;
+
+ if (dst == NULL) {
+ if (pad > 2) {
+ return NXT_ERROR;
+ }
+
+ while (src < end) {
+ if (decode[*src] != 77) {
+ src++;
+ continue;
+ }
+
+ if (pad == 0) {
+ pad = end - src;
+
+ if ((pad == 1 || (pad == 2 && src[1] == '=')) && src[0] == '=')
+ {
+ break;
+ }
+ }
+
+ return NXT_ERROR;
+ }
+
+ return (length + 3) / 4 * 3 - pad;
+ }
+
+ nxt_assert(length != 0);
+
+ if (pad == 0) {
+ pad = (end[-1] == '=') + (end[-2] == '=');
+ end -= (pad + 3) & 4;
+
+ } else {
+ end -= 4 - pad;
+ }
+
+ p = dst;
+
+ while (src < end) {
+ v1 = decode[src[0]];
+ v2 = decode[src[1]];
+ v3 = decode[src[2]];
+ v4 = decode[src[3]];
+
+ *p++ = (v1 << 2 | v2 >> 4);
+ *p++ = (v2 << 4 | v3 >> 2);
+ *p++ = (v3 << 6 | v4);
+
+ src += 4;
+ }
+
+ if (pad > 0) {
+ v1 = decode[src[0]];
+ v2 = decode[src[1]];
+
+ *p++ = (v1 << 2 | v2 >> 4);
+
+ if (pad == 1) {
+ v3 = decode[src[2]];
+ *p++ = (v2 << 4 | v3 >> 2);
+ }
+ }
+
+ return (p - dst);
+}
diff --git a/src/nxt_string.h b/src/nxt_string.h
index 7e02f59a..4d565e87 100644
--- a/src/nxt_string.h
+++ b/src/nxt_string.h
@@ -190,6 +190,8 @@ NXT_EXPORT uintptr_t nxt_encode_complex_uri(u_char *dst, u_char *src,
size_t length);
NXT_EXPORT nxt_bool_t nxt_is_complex_uri_encoded(u_char *s, size_t length);
+NXT_EXPORT ssize_t nxt_base64_decode(u_char *dst, u_char *src, size_t length);
+
extern const uint8_t nxt_hex2int[256];
diff --git a/src/nxt_tls.h b/src/nxt_tls.h
index e02a0aab..0667ade3 100644
--- a/src/nxt_tls.h
+++ b/src/nxt_tls.h
@@ -98,8 +98,6 @@ extern const nxt_tls_lib_t nxt_openssl_lib;
void nxt_cdecl nxt_openssl_log_error(nxt_task_t *task, nxt_uint_t level,
const char *fmt, ...);
u_char *nxt_openssl_copy_error(u_char *p, u_char *end);
-nxt_int_t nxt_openssl_base64_decode(u_char *d, size_t dlen, const u_char *s,
- size_t slen);
#endif
#if (NXT_HAVE_GNUTLS)
diff --git a/src/test/nxt_base64_test.c b/src/test/nxt_base64_test.c
new file mode 100644
index 00000000..13a772b6
--- /dev/null
+++ b/src/test/nxt_base64_test.c
@@ -0,0 +1,98 @@
+
+/*
+ * Copyright (C) NGINX, Inc.
+ */
+
+#include <nxt_main.h>
+#include "nxt_tests.h"
+
+
+nxt_int_t
+nxt_base64_test(nxt_thread_t *thr)
+{
+ ssize_t ret;
+ nxt_uint_t i;
+
+ static struct {
+ nxt_str_t enc;
+ nxt_str_t dec;
+
+ } tests[] = {
+ { nxt_string("ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz"
+ "0123456789+//+9876543210"
+ "zyxwvutsrqponmlkjihgfedcba"
+ "ZYXWVUTSRQPONMLKJIHGFEDCBA"),
+ nxt_string("\x00\x10\x83\x10\x51\x87\x20\x92\x8b\x30\xd3\x8f"
+ "\x41\x14\x93\x51\x55\x97\x61\x96\x9b\x71\xd7\x9f"
+ "\x82\x18\xa3\x92\x59\xa7\xa2\x9a\xab\xb2\xdb\xaf"
+ "\xc3\x1c\xb3\xd3\x5d\xb7\xe3\x9e\xbb\xf3\xdf\xbf"
+ "\xff\xef\x7c\xef\xae\x78\xdf\x6d\x74\xcf\x2c\x70"
+ "\xbe\xeb\x6c\xae\xaa\x68\x9e\x69\x64\x8e\x28\x60"
+ "\x7d\xe7\x5c\x6d\xa6\x58\x5d\x65\x54\x4d\x24\x50"
+ "\x3c\xe3\x4c\x2c\xa2\x48\x1c\x61\x44\x0c\x20\x40") },
+
+ { nxt_string("Aa=="),
+ nxt_string("\x01") },
+ { nxt_string("0Z"),
+ nxt_string("\xd1") },
+ { nxt_string("0aA="),
+ nxt_string("\xd1\xa0") },
+ { nxt_string("z/+"),
+ nxt_string("\xcf\xff") },
+ { nxt_string("z9+Npe=="),
+ nxt_string("\xcf\xdf\x8d\xa5") },
+ { nxt_string("/+98765"),
+ nxt_string("\xff\xef\x7c\xef\xae") },
+
+ { nxt_string("aBc_"),
+ nxt_null_string },
+ { nxt_string("5"),
+ nxt_null_string },
+ { nxt_string("M==="),
+ nxt_null_string },
+ { nxt_string("===="),
+ nxt_null_string },
+ { nxt_string("Ab="),
+ nxt_null_string },
+ { nxt_string("00=0"),
+ nxt_null_string },
+ { nxt_string("\0"),
+ nxt_null_string },
+ { nxt_string("\r\naaaa"),
+ nxt_null_string },
+ { nxt_string("=0000"),
+ nxt_null_string },
+ };
+
+ u_char buf[96];
+
+ nxt_thread_time_update(thr);
+
+ for (i = 0; i < nxt_nitems(tests); i++) {
+ ret = nxt_base64_decode(NULL, tests[i].enc.start, tests[i].enc.length);
+
+ if (ret == NXT_ERROR && tests[i].dec.start == NULL) {
+ continue;
+ }
+
+ if ((size_t) ret != tests[i].dec.length) {
+ nxt_log_alert(thr->log,
+ "nxt_base64_decode() test \"%V\" failed: incorrect "
+ "length of decoded string %z, expected %uz",
+ &tests[i].enc, ret, tests[i].dec.length);
+ return NXT_ERROR;
+ }
+
+ ret = nxt_base64_decode(buf, tests[i].enc.start, tests[i].enc.length);
+
+ if (!nxt_str_eq(&tests[i].dec, buf, (size_t) ret)) {
+ nxt_log_alert(thr->log, "nxt_base64_decode() test \"%V\" failed");
+ return NXT_ERROR;
+ }
+ }
+
+ nxt_log_error(NXT_LOG_NOTICE, thr->log, "nxt_base64_decode() test passed");
+
+ return NXT_OK;
+}
diff --git a/src/test/nxt_tests.c b/src/test/nxt_tests.c
index 901d76c3..f5a1cbd4 100644
--- a/src/test/nxt_tests.c
+++ b/src/test/nxt_tests.c
@@ -162,6 +162,10 @@ main(int argc, char **argv)
return 1;
}
+ if (nxt_base64_test(thr) != NXT_OK) {
+ return 1;
+ }
+
#if (NXT_HAVE_CLONE_NEWUSER)
if (nxt_clone_creds_test(thr) != NXT_OK) {
return 1;
diff --git a/src/test/nxt_tests.h b/src/test/nxt_tests.h
index d531cc7d..463dc851 100644
--- a/src/test/nxt_tests.h
+++ b/src/test/nxt_tests.h
@@ -64,6 +64,7 @@ nxt_int_t nxt_malloc_test(nxt_thread_t *thr);
nxt_int_t nxt_utf8_test(nxt_thread_t *thr);
nxt_int_t nxt_http_parse_test(nxt_thread_t *thr);
nxt_int_t nxt_strverscmp_test(nxt_thread_t *thr);
+nxt_int_t nxt_base64_test(nxt_thread_t *thr);
nxt_int_t nxt_clone_creds_test(nxt_thread_t *thr);