diff options
author | Toke Høiland-Jørgensen <toke@toke.dk> | 2021-04-14 21:39:43 +0200 |
---|---|---|
committer | Ondrej Zajicek (work) <santiago@crfreenet.org> | 2021-06-06 16:28:18 +0200 |
commit | 35f88b305ab6a0e27b5ff1b445f63f544986e14e (patch) | |
tree | 76051c919ed62297191e1b18eab1525429b43068 | |
parent | f1a824190c22f8159ad0f9378c2dd23e521eaf61 (diff) |
Nest: Allow specifying security keys as hex bytes as well as strings
Add support for specifying a password in hexadecimal format, 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.
-rw-r--r-- | conf/cf-lex.l | 31 | ||||
-rw-r--r-- | conf/conf.h | 5 | ||||
-rw-r--r-- | conf/confbase.Y | 2 | ||||
-rw-r--r-- | doc/bird.sgml | 7 | ||||
-rw-r--r-- | lib/string.h | 1 | ||||
-rw-r--r-- | lib/strtoul.c | 27 | ||||
-rw-r--r-- | nest/config.Y | 38 |
7 files changed, 93 insertions, 18 deletions
diff --git a/conf/cf-lex.l b/conf/cf-lex.l index 05288b1a..704a1750 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->length = len; + b = &bytes->data[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.bs = bytes; + return BYTESTRING; +} + ({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 860d267a..3bc37959 100644 --- a/conf/conf.h +++ b/conf/conf.h @@ -136,6 +136,11 @@ struct sym_scope { int active; /* Currently entered */ }; +struct bytestring { + size_t length; + byte data[]; +}; + #define SYM_MAX_LEN 64 /* Remember to update cf_symbol_class_name() */ diff --git a/conf/confbase.Y b/conf/confbase.Y index d98f0fee..6985783b 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 *bs; } %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 <bs> BYTESTRING %type <iface> ipa_scope %type <i> expr bool pxlen4 diff --git a/doc/bird.sgml b/doc/bird.sgml index bd1ed7ed..01725128 100644 --- a/doc/bird.sgml +++ b/doc/bird.sgml @@ -776,7 +776,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/hex_key/ [ { <m>password options</m> } ] </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 @@ -784,6 +784,11 @@ 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. <m/hex_key/ is a + sequence of hexadecimal digit pairs, optionally colon-separated. A key + specified this way must be at least 16 bytes (32 digits) 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 0f650178..976b1c24 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 44a1bb1d..a5b11f68 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 98820646..8bd89de0 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(const void *key, uint length, uint id) +{ + 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 = key; + this_p_item->length = length; + 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 = id; + this_p_item->alg = ALG_UNDEFINED; + add_tail(this_p_list, &this_p_item->n); +} static inline void reset_passwords(void) @@ -490,23 +509,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($2, strlen($2), password_id++); } + | PASSWORD BYTESTRING { init_password($2->data, $2->length, password_id++); } ; password_item_params: |