]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Nest: Allow specifying security keys as hex bytes as well as strings
authorToke Høiland-Jørgensen <toke@toke.dk>
Wed, 14 Apr 2021 19:39:43 +0000 (21:39 +0200)
committerOndrej Zajicek (work) <santiago@crfreenet.org>
Sun, 6 Jun 2021 14:28:18 +0000 (16:28 +0200)
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.

conf/cf-lex.l
conf/conf.h
conf/confbase.Y
doc/bird.sgml
lib/string.h
lib/strtoul.c
nest/config.Y

index 05288b1a54164ee06aac939c409ed9c9cc77700b..704a1750f010608a055b71fc3b988251426e8e83 100644 (file)
@@ -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);
index 860d267aa7b9f2cd5a635ac33c6bc44bd93b24d4..3bc37959ff54c5f52d4de6599afc0ac5cc7f95de 100644 (file)
@@ -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() */
index d98f0feeb811b03fa8320b81d8b01b7c0c613938..6985783b4531bf5ae23804a70210b80f4efaf176 100644 (file)
@@ -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
index bd1ed7ed2e670be33fb85c74420909caa6cd21dc..017251287a23017dd3a302286ed8d6e7099a78d0 100644 (file)
@@ -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.
index 0f650178de6697d0fc2e4ea403ff260d68edff9e..976b1c247111a8d3eed24f7aea9cf77aafe7ba81 100644 (file)
@@ -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);
 
index 44a1bb1dd76a5145a08538510659ba333586e91d..a5b11f68d5ff4d3231bf8dcd0ef96c5d77501b2e 100644 (file)
@@ -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;
+}
index 9882064682f12e9373c7df93c9c8ca12cb784344..8bd89de0a57c64948b3fcb449eb3ea783202e7d2 100644 (file)
@@ -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: