summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorToke Høiland-Jørgensen <toke@toke.dk>2021-04-14 21:39:43 +0200
committerOndrej Zajicek (work) <santiago@crfreenet.org>2021-06-06 16:28:18 +0200
commit35f88b305ab6a0e27b5ff1b445f63f544986e14e (patch)
tree76051c919ed62297191e1b18eab1525429b43068
parentf1a824190c22f8159ad0f9378c2dd23e521eaf61 (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.l31
-rw-r--r--conf/conf.h5
-rw-r--r--conf/confbase.Y2
-rw-r--r--doc/bird.sgml7
-rw-r--r--lib/string.h1
-rw-r--r--lib/strtoul.c27
-rw-r--r--nest/config.Y38
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: