From 1accc4d5c84bc10e9c116e76d04785377e40fff4 Mon Sep 17 00:00:00 2001 From: Mikael Magnusson Date: Tue, 31 Aug 2021 13:02:13 +0200 Subject: Bytestring: implement bytestring literals and constants Implement byte string literals on the format b"xxx" and b64"xxx" which can be used as literals and in constants. The format b"xxx" supports character data and octal and hexadecimal data using C escapes (\n, \nn, \nnn, \xn and \xnn). The format b64"xxx" supports base64 encoded strings (RFC1341). --- conf/cf-lex.l | 59 +++++++++++++++++++- conf/confbase.Y | 9 +++ filter/config.Y | 1 + filter/data.h | 2 + lib/Makefile | 2 +- lib/README.base64 | 62 +++++++++++++++++++++ lib/base64.c | 163 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/base64.h | 11 ++++ 8 files changed, 307 insertions(+), 2 deletions(-) create mode 100644 lib/README.base64 create mode 100644 lib/base64.c create mode 100644 lib/base64.h diff --git a/conf/cf-lex.l b/conf/cf-lex.l index 9025a84d..176c1432 100644 --- a/conf/cf-lex.l +++ b/conf/cf-lex.l @@ -50,6 +50,7 @@ #include "conf/cf-parse.tab.h" #include "lib/string.h" #include "lib/hash.h" +#include "lib/base64.h" struct keyword { byte *name; @@ -124,10 +125,11 @@ static enum yytokentype cf_lex_symbol(const char *data); %option nounput %option noreject -%x COMMENT CCOMM CLI QUOTED APOSTROPHED INCLUDE +%x COMMENT CCOMM CLI QUOTED BQUOTED B64QUOTED APOSTROPHED INCLUDE ALPHA [a-zA-Z_] DIGIT [0-9] +OIGIT [0-7] XIGIT [0-9a-fA-F] ALNUM [a-zA-Z_0-9] WHITE [ \t] @@ -372,6 +374,61 @@ else: { . BUFFER_PUSH(quoted_buffer) = yytext[0]; +[b]["] { + BEGIN(BQUOTED); + quoted_buffer_init(); +} + +\n cf_error("Unterminated byte string"); +<> cf_error("Unterminated byte string"); +["] { + BEGIN(INITIAL); + struct bytestring *bytes; + + bytes = cfg_allocz(sizeof(*bytes) + quoted_buffer.used); + memcpy(bytes->data, quoted_buffer.data, quoted_buffer.used); + bytes->length = quoted_buffer.used; + + cf_lval.bs = bytes; + return BYTESTRING; +} + +. BUFFER_PUSH(quoted_buffer) = yytext[0]; + +[\\]({OIGIT}|{OIGIT}{OIGIT}|{OIGIT}{OIGIT}{OIGIT}) { + char buf[4]; + char *end = NULL; + memcpy(buf, yytext + 1, yyleng); + buf[yyleng] = 0; + BUFFER_PUSH(quoted_buffer) = bstrtoul10(buf, &end); +} + +[\\][x]({XIGIT}|{XIGIT}{XIGIT}) { + char buf[3]; + char *end = NULL; + memcpy(buf, yytext + 2, yyleng); + buf[yyleng] = 0; + BUFFER_PUSH(quoted_buffer) = bstrtoul16(buf, &end); +} + +[b][6][4]["] { + BEGIN(B64QUOTED); + quoted_buffer_init(); +} + +\n cf_error("Unterminated base64 string"); +<> cf_error("Unterminated base64 string"); +["] { + BEGIN(INITIAL); + cf_lval.bs = base64_decode_bs(cfg_mem, quoted_buffer.data, quoted_buffer.used, NULL); + if (!cf_lval.bs) + cf_error("Invalid base64 string"); + + return BYTESTRING; +} + +. BUFFER_PUSH(quoted_buffer) = yytext[0]; + <> { if (check_eof()) return END; } {WHITE}+ diff --git a/conf/confbase.Y b/conf/confbase.Y index 3dd5fed7..0c53f7ec 100644 --- a/conf/confbase.Y +++ b/conf/confbase.Y @@ -117,6 +117,7 @@ CF_DECLS %type label_stack_start label_stack %type text opttext +%type bytestring %type symbol %type kw_sym @@ -395,6 +396,14 @@ opttext: | /* empty */ { $$ = NULL; } ; +bytestring: + BYTESTRING + | CF_SYM_KNOWN { + if ($1->class != (SYM_CONSTANT | T_BYTESTRING)) cf_error("Bytestring constant expected"); + $$ = SYM_VAL($1).bs; + } + ; + CF_CODE diff --git a/filter/config.Y b/filter/config.Y index a1e5e9f1..1d7763ff 100644 --- a/filter/config.Y +++ b/filter/config.Y @@ -729,6 +729,7 @@ constant: } | '[' fprefix_set ']' { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_PREFIX_SET, .val.ti = $2, }); } | ENUM { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = $1 >> 16, .val.i = $1 & 0xffff, }); } + | BYTESTRING { $$ = f_new_inst(FI_CONSTANT, (struct f_val) { .type = T_BYTESTRING, .val.bs = $1, }); } ; constructor: diff --git a/filter/data.h b/filter/data.h index b3767f7b..091b3963 100644 --- a/filter/data.h +++ b/filter/data.h @@ -58,6 +58,7 @@ enum f_type { T_LCLIST = 0x29, /* Large community list */ T_RD = 0x2a, /* Route distinguisher for VPN addresses */ T_PATH_MASK_ITEM = 0x2b, /* Path mask item for path mask constructors */ + T_BYTESTRING = 0x2c, T_SET = 0x80, T_PREFIX_SET = 0x81, @@ -78,6 +79,7 @@ struct f_val { const struct adata *ad; const struct f_path_mask *path_mask; struct f_path_mask_item pmi; + const struct bytestring *bs; } val; }; diff --git a/lib/Makefile b/lib/Makefile index 812f721c..0310eca2 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -1,4 +1,4 @@ -src := bitmap.c bitops.c blake2s.c blake2b.c checksum.c event.c flowspec.c idm.c ip.c lists.c mac.c md5.c mempool.c net.c patmatch.c printf.c resource.c sha1.c sha256.c sha512.c slab.c slists.c strtoul.c tbf.c timer.c xmalloc.c +src := base64.c bitmap.c bitops.c blake2s.c blake2b.c checksum.c event.c flowspec.c idm.c ip.c lists.c mac.c md5.c mempool.c net.c patmatch.c printf.c resource.c sha1.c sha256.c sha512.c slab.c slists.c strtoul.c tbf.c timer.c xmalloc.c obj := $(src-o-files) $(all-daemon) diff --git a/lib/README.base64 b/lib/README.base64 new file mode 100644 index 00000000..0c131123 --- /dev/null +++ b/lib/README.base64 @@ -0,0 +1,62 @@ +base64.c was downloaded on 31 Aug 2021 from +http://web.mit.edu/freebsd/head/contrib/wpa/src/utils/base64.c + +and the following text on 31 Aug 2021 from +http://web.mit.edu/freebsd/head/contrib/wpa/ + +wpa_supplicant and hostapd +-------------------------- + +Copyright (c) 2002-2012, Jouni Malinen and contributors +All Rights Reserved. + +These programs are licensed under the BSD license (the one with +advertisement clause removed). + +If you are submitting changes to the project, please see CONTRIBUTIONS +file for more instructions. + + +This package may include either wpa_supplicant, hostapd, or both. See +README file respective subdirectories (wpa_supplicant/README or +hostapd/README) for more details. + +Source code files were moved around in v0.6.x releases and compared to +earlier releases, the programs are now built by first going to a +subdirectory (wpa_supplicant or hostapd) and creating build +configuration (.config) and running 'make' there (for Linux/BSD/cygwin +builds). + + +License +------- + +This software may be distributed, used, and modified under the terms of +BSD license: + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +3. Neither the name(s) of the above-listed copyright holder(s) nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/lib/base64.c b/lib/base64.c new file mode 100644 index 00000000..d5f3ae9b --- /dev/null +++ b/lib/base64.c @@ -0,0 +1,163 @@ +/* + * Base64 encoding/decoding (RFC1341) + * Copyright (c) 2005-2011, Jouni Malinen + * + * This software may be distributed under the terms of the BSD license. + * See README.base64 for more details. + */ + +#include "nest/bird.h" +#include "conf/conf.h" +#include "lib/resource.h" +#include "lib/base64.h" + +static const unsigned char base64_table[65] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +/** + * base64_encode - Base64 encode + * @src: Data to be encoded + * @len: Length of the data to be encoded + * @out_len: Pointer to output length variable, or %NULL if not used + * Returns: Allocated buffer of out_len bytes of encoded data, + * or %NULL on failure + * + * Caller is responsible for freeing the returned buffer. Returned buffer is + * nul terminated to make it easier to use as a C string. The nul terminator is + * not included in out_len. + */ +struct bytestring * base64_encode(linpool *pool, + const unsigned char *src, size_t len, + size_t *out_len) +{ + unsigned char *pos; + struct bytestring *out; + const unsigned char *end, *in; + size_t olen; + int line_len; + + olen = len * 4 / 3 + 4; /* 3-byte blocks to 4-byte */ + olen += olen / 72; /* line feeds */ + olen++; /* nul termination */ + if (olen < len) + return NULL; /* integer overflow */ + out = lp_alloc(pool, sizeof(struct bytestring) + olen); + if (out == NULL) + return NULL; + + end = src + len; + in = src; + pos = out->data; + line_len = 0; + while (end - in >= 3) { + *pos++ = base64_table[in[0] >> 2]; + *pos++ = base64_table[((in[0] & 0x03) << 4) | (in[1] >> 4)]; + *pos++ = base64_table[((in[1] & 0x0f) << 2) | (in[2] >> 6)]; + *pos++ = base64_table[in[2] & 0x3f]; + in += 3; + line_len += 4; + if (line_len >= 72) { + *pos++ = '\n'; + line_len = 0; + } + } + + if (end - in) { + *pos++ = base64_table[in[0] >> 2]; + if (end - in == 1) { + *pos++ = base64_table[(in[0] & 0x03) << 4]; + *pos++ = '='; + } else { + *pos++ = base64_table[((in[0] & 0x03) << 4) | + (in[1] >> 4)]; + *pos++ = base64_table[(in[1] & 0x0f) << 2]; + } + *pos++ = '='; + line_len += 4; + } + + if (line_len) + *pos++ = '\n'; + + *pos = '\0'; + out->length = pos - out->data; + if (out_len) + *out_len = out->length; + return out; +} + + +/** + * base64_decode - Base64 decode + * @src: Data to be decoded + * @len: Length of the data to be decoded + * @out_len: Pointer to output length variable + * Returns: Allocated buffer of out_len bytes of decoded data, + * or %NULL on failure + * + * Caller is responsible for freeing the returned buffer. + */ +struct bytestring * base64_decode_bs(linpool *pool, + const unsigned char *src, size_t len, + size_t *out_len) +{ + unsigned char dtable[256], *pos, block[4], tmp; + size_t i, count, olen; + int pad = 0; + struct bytestring *out; + + memset(dtable, 0x80, 256); + for (i = 0; i < sizeof(base64_table) - 1; i++) + dtable[base64_table[i]] = (unsigned char) i; + dtable['='] = 0; + + count = 0; + for (i = 0; i < len; i++) { + if (dtable[src[i]] != 0x80) + count++; + } + + if (count == 0 || count % 4) + return NULL; + + olen = count / 4 * 3; + out = lp_alloc(pool, sizeof(struct bytestring) + olen); + if (out == NULL) + return NULL; + pos = out->data; + + count = 0; + for (i = 0; i < len; i++) { + tmp = dtable[src[i]]; + if (tmp == 0x80) + continue; + + if (src[i] == '=') + pad++; + block[count] = tmp; + count++; + if (count == 4) { + *pos++ = (block[0] << 2) | (block[1] >> 4); + *pos++ = (block[1] << 4) | (block[2] >> 2); + *pos++ = (block[2] << 6) | block[3]; + count = 0; + if (pad) { + if (pad == 1) + pos--; + else if (pad == 2) + pos -= 2; + else { + /* Invalid padding */ + //os_free(out); + return NULL; + } + break; + } + } + } + + out->length = pos - out->data; + if (out_len) + *out_len = out->length; + return out; +} diff --git a/lib/base64.h b/lib/base64.h new file mode 100644 index 00000000..8ca4dd9b --- /dev/null +++ b/lib/base64.h @@ -0,0 +1,11 @@ +#ifndef _BIRD_BASE64_H_ +#define _BIRD_BASE64_H_ + +#include "lib/resource.h" + +struct bytestring * base64_encode_bs(linpool *pool, const unsigned char *src, size_t len, + size_t *out_len); +struct bytestring * base64_decode_bs(linpool *pool, const unsigned char *src, size_t len, + size_t *out_len); + +#endif /* _BIRD_BASE64_H_ */ -- cgit v1.2.3