[PATCH v4 4/8] nest: Allow specifying security keys as hex bytes as well as strings
Toke Høiland-Jørgensen
toke at toke.dk
Fri Jan 15 16:52:53 CET 2021
From: Toke Høiland-Jørgensen <toke at toke.dk>
This adds support for specifying a password in raw hexadecimal bytes form,
via the 'key' keyword. The result is the same whether a password is
specified as a quoted string or a hex-encoded byte string, this just makes
it more convenient to input high-entropy byte strings as MAC keys.
This means that the config string:
password "test" { algorithm hmac sha256; };
is equivalent to:
key 74:65:73:74 { algorithm hmac sha256; };
or
key 74657374 { algorithm hmac sha256; };
Signed-off-by: Toke Høiland-Jørgensen <toke at toke.dk>
---
conf/cf-lex.l | 31 +++++++++++++++++++++++++++++++
conf/conf.h | 5 +++++
conf/confbase.Y | 2 ++
doc/bird.sgml | 9 ++++++++-
lib/string.h | 1 +
lib/strtoul.c | 27 +++++++++++++++++++++++++++
nest/config.Y | 40 ++++++++++++++++++++++------------------
7 files changed, 96 insertions(+), 19 deletions(-)
diff --git a/conf/cf-lex.l b/conf/cf-lex.l
index 05288b1a5416..8c88fcaa35ef 100644
--- a/conf/cf-lex.l
+++ b/conf/cf-lex.l
@@ -255,6 +255,37 @@ WHITE [ \t]
return IP4;
}
+{XIGIT}{2}(:{XIGIT}{2}|{XIGIT}{2}){15,} {
+ char *s = yytext;
+ size_t len = 0, i;
+ struct bytestring *bytes;
+ byte *b;
+
+ while (*s) {
+ len++;
+ s += 2;
+ if (*s == ':')
+ s++;
+ }
+ bytes = cfg_allocz(sizeof(*bytes) + len);
+
+ bytes->sz = len;
+ b = &bytes->b[0];
+ s = yytext;
+ errno = 0;
+ for (i = 0; i < len; i++) {
+ *b = bstrtobyte16(s);
+ if (errno == ERANGE)
+ cf_error("Invalid hex string");
+ b++;
+ s += 2;
+ if (*s == ':')
+ s++;
+ }
+ cf_lval.b = bytes;
+ return BYTES;
+}
+
({XIGIT}*::|({XIGIT}*:){3,})({XIGIT}*|{DIGIT}+\.{DIGIT}+\.{DIGIT}+\.{DIGIT}+) {
if (!ip6_pton(yytext, &cf_lval.ip6))
cf_error("Invalid IPv6 address %s", yytext);
diff --git a/conf/conf.h b/conf/conf.h
index 3e47c9185469..eecfae94ca43 100644
--- a/conf/conf.h
+++ b/conf/conf.h
@@ -128,6 +128,11 @@ struct symbol {
char name[0];
};
+struct bytestring {
+ size_t sz;
+ byte b[];
+};
+
struct sym_scope {
struct sym_scope *next; /* Next on scope stack */
struct symbol *name; /* Name of this scope */
diff --git a/conf/confbase.Y b/conf/confbase.Y
index d98f0feeb811..8a9aec083a06 100644
--- a/conf/confbase.Y
+++ b/conf/confbase.Y
@@ -92,6 +92,7 @@ CF_DECLS
struct channel_limit cl;
struct timeformat *tf;
mpls_label_stack *mls;
+ struct bytestring *b;
}
%token END CLI_MARKER INVALID_TOKEN ELSECOL DDOT
@@ -103,6 +104,7 @@ CF_DECLS
%token <i64> VPN_RD
%token <s> CF_SYM_KNOWN CF_SYM_UNDEFINED
%token <t> TEXT
+%token <b> BYTES
%type <iface> ipa_scope
%type <i> expr bool pxlen4
diff --git a/doc/bird.sgml b/doc/bird.sgml
index bebe1ebe7709..da109dbba3a2 100644
--- a/doc/bird.sgml
+++ b/doc/bird.sgml
@@ -765,7 +765,7 @@ agreement").
protocol packets are processed in the local TX queues. This option is
Linux specific. Default value is 7 (highest priority, privileged traffic).
- <tag><label id="proto-pass">password "<m/password/" [ { <m>password options</m> } ]</tag>
+ <tag><label id="proto-pass">password "<m/password/" [ { <m>password options</m> } ] | key <m/hex_key/ </tag>
Specifies a password that can be used by the protocol as a shared secret
key. Password option can be used more times to specify more passwords.
If more passwords are specified, it is a protocol-dependent decision
@@ -773,6 +773,13 @@ agreement").
authentication is enabled, authentication can be enabled by separate,
protocol-dependent <cf/authentication/ option.
+ A password can also be specified as a hexadecimal key using the
+ <cf/key/ option, with the hexadecimal key following the option unquoted.
+ The same sub-options can be used in both cases. The bytes in the hex_key
+ can optionally be colon-separated, and a key specified this way must be
+ at least 16 bytes long (although specific algorithms can impose other
+ restrictions).
+
This option is allowed in BFD, OSPF and RIP protocols. BGP has also
<cf/password/ option, but it is slightly different and described
separately.
diff --git a/lib/string.h b/lib/string.h
index 0f650178de66..976b1c247111 100644
--- a/lib/string.h
+++ b/lib/string.h
@@ -26,6 +26,7 @@ void buffer_puts(buffer *buf, const char *str);
u64 bstrtoul10(const char *str, char **end);
u64 bstrtoul16(const char *str, char **end);
+byte bstrtobyte16(const char *str);
int patmatch(const byte *pat, const byte *str);
diff --git a/lib/strtoul.c b/lib/strtoul.c
index 44a1bb1dd76a..a5b11f68d5ff 100644
--- a/lib/strtoul.c
+++ b/lib/strtoul.c
@@ -59,3 +59,30 @@ bstrtoul16(const char *str, char **end)
errno = ERANGE;
return UINT64_MAX;
}
+
+byte
+bstrtobyte16(const char *str)
+{
+ byte out = 0;
+ for (int i=0; i<2; i++) {
+ switch (str[i]) {
+ case '0' ... '9':
+ out *= 16;
+ out += str[i] - '0';
+ break;
+ case 'a' ... 'f':
+ out *= 16;
+ out += str[i] + 10 - 'a';
+ break;
+ case 'A' ... 'F':
+ out *= 16;
+ out += str[i] + 10 - 'A';
+ break;
+ default:
+ errno = ERANGE;
+ return -1;
+ }
+ }
+
+ return out;
+}
diff --git a/nest/config.Y b/nest/config.Y
index 4622b41ef12d..992075e754cd 100644
--- a/nest/config.Y
+++ b/nest/config.Y
@@ -37,6 +37,25 @@ iface_patt_check(void)
cf_error("Interface name/mask expected, not IP prefix");
}
+static inline void
+init_password(void *data, size_t sz)
+{
+ if (!this_p_list) {
+ this_p_list = cfg_allocz(sizeof(list));
+ init_list(this_p_list);
+ password_id = 1;
+ }
+ this_p_item = cfg_allocz(sizeof (struct password_item));
+ this_p_item->password = data;
+ this_p_item->length = sz;
+ this_p_item->genfrom = 0;
+ this_p_item->gento = TIME_INFINITY;
+ this_p_item->accfrom = 0;
+ this_p_item->accto = TIME_INFINITY;
+ this_p_item->id = password_id++;
+ this_p_item->alg = ALG_UNDEFINED;
+ add_tail(this_p_list, &this_p_item->n);
+}
static inline void
reset_passwords(void)
@@ -99,7 +118,7 @@ CF_KEYWORDS(RELOAD, IN, OUT, MRTDUMP, MESSAGES, RESTRICT, MEMORY, IGP_METRIC, CL
CF_KEYWORDS(TIMEFORMAT, ISO, SHORT, LONG, ROUTE, PROTOCOL, BASE, LOG, S, MS, US)
CF_KEYWORDS(GRACEFUL, RESTART, WAIT, MAX, FLUSH, AS)
CF_KEYWORDS(MIN, IDLE, RX, TX, INTERVAL, MULTIPLIER, PASSIVE)
-CF_KEYWORDS(CHECK, LINK)
+CF_KEYWORDS(CHECK, LINK, KEY)
/* For r_args_channel */
CF_KEYWORDS(IPV4, IPV4_MC, IPV4_MPLS, IPV6, IPV6_MC, IPV6_MPLS, IPV6_SADR, VPN4, VPN4_MC, VPN4_MPLS, VPN6, VPN6_MC, VPN6_MPLS, ROA4, ROA6, FLOW4, FLOW6, MPLS, PRI, SEC)
@@ -485,23 +504,8 @@ password_item:
;
password_item_begin:
- PASSWORD text {
- if (!this_p_list) {
- this_p_list = cfg_allocz(sizeof(list));
- init_list(this_p_list);
- password_id = 1;
- }
- this_p_item = cfg_allocz(sizeof(struct password_item));
- this_p_item->password = $2;
- this_p_item->length = strlen($2);
- this_p_item->genfrom = 0;
- this_p_item->gento = TIME_INFINITY;
- this_p_item->accfrom = 0;
- this_p_item->accto = TIME_INFINITY;
- this_p_item->id = password_id++;
- this_p_item->alg = ALG_UNDEFINED;
- add_tail(this_p_list, &this_p_item->n);
- }
+ PASSWORD text { init_password((void *)$2, strlen($2)); }
+ | KEY BYTES { init_password($2->b, $2->sz); }
;
password_item_params:
More information about the Bird-users
mailing list