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.
This commit is contained in:
Toke Høiland-Jørgensen 2021-04-14 21:39:43 +02:00 committed by Ondrej Zajicek (work)
parent f1a824190c
commit 35f88b305a
7 changed files with 93 additions and 18 deletions

View file

@ -255,6 +255,37 @@ WHITE [ \t]
return IP4; 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}+) { ({XIGIT}*::|({XIGIT}*:){3,})({XIGIT}*|{DIGIT}+\.{DIGIT}+\.{DIGIT}+\.{DIGIT}+) {
if (!ip6_pton(yytext, &cf_lval.ip6)) if (!ip6_pton(yytext, &cf_lval.ip6))
cf_error("Invalid IPv6 address %s", yytext); cf_error("Invalid IPv6 address %s", yytext);

View file

@ -136,6 +136,11 @@ struct sym_scope {
int active; /* Currently entered */ int active; /* Currently entered */
}; };
struct bytestring {
size_t length;
byte data[];
};
#define SYM_MAX_LEN 64 #define SYM_MAX_LEN 64
/* Remember to update cf_symbol_class_name() */ /* Remember to update cf_symbol_class_name() */

View file

@ -92,6 +92,7 @@ CF_DECLS
struct channel_limit cl; struct channel_limit cl;
struct timeformat *tf; struct timeformat *tf;
mpls_label_stack *mls; mpls_label_stack *mls;
struct bytestring *bs;
} }
%token END CLI_MARKER INVALID_TOKEN ELSECOL DDOT %token END CLI_MARKER INVALID_TOKEN ELSECOL DDOT
@ -103,6 +104,7 @@ CF_DECLS
%token <i64> VPN_RD %token <i64> VPN_RD
%token <s> CF_SYM_KNOWN CF_SYM_UNDEFINED %token <s> CF_SYM_KNOWN CF_SYM_UNDEFINED
%token <t> TEXT %token <t> TEXT
%token <bs> BYTESTRING
%type <iface> ipa_scope %type <iface> ipa_scope
%type <i> expr bool pxlen4 %type <i> expr bool pxlen4

View file

@ -776,7 +776,7 @@ agreement").
protocol packets are processed in the local TX queues. This option is protocol packets are processed in the local TX queues. This option is
Linux specific. Default value is 7 (highest priority, privileged traffic). 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 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. key. Password option can be used more times to specify more passwords.
If more passwords are specified, it is a protocol-dependent decision 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, authentication is enabled, authentication can be enabled by separate,
protocol-dependent <cf/authentication/ option. 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 This option is allowed in BFD, OSPF and RIP protocols. BGP has also
<cf/password/ option, but it is slightly different and described <cf/password/ option, but it is slightly different and described
separately. separately.

View file

@ -26,6 +26,7 @@ void buffer_puts(buffer *buf, const char *str);
u64 bstrtoul10(const char *str, char **end); u64 bstrtoul10(const char *str, char **end);
u64 bstrtoul16(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); int patmatch(const byte *pat, const byte *str);

View file

@ -59,3 +59,30 @@ bstrtoul16(const char *str, char **end)
errno = ERANGE; errno = ERANGE;
return UINT64_MAX; 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;
}

View file

@ -37,6 +37,25 @@ iface_patt_check(void)
cf_error("Interface name/mask expected, not IP prefix"); 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 static inline void
reset_passwords(void) reset_passwords(void)
@ -490,23 +509,8 @@ password_item:
; ;
password_item_begin: password_item_begin:
PASSWORD text { PASSWORD text { init_password($2, strlen($2), password_id++); }
if (!this_p_list) { | PASSWORD BYTESTRING { init_password($2->data, $2->length, password_id++); }
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_item_params: password_item_params: