[patch] Add TCP-MD5 authentication option for RPKI protocol
Job Snijders
job at fastly.com
Tue Oct 1 17:27:19 CEST 2024
Dear BIRD community,
I think many of us use good ole' TCP-MD5 to authenticate IBGP sessions,
even if TCP-MD5 is imperfect from key rolling perspective. TCP-MD5 is
easy to configure, and supported on a broad range of platforms, and
beats doing nothing.
RPKI-To-Router (RTR) sessions seem to be similar security-sensitivity as
IBGP sessions, but at the moment of writing BIRD offers a choice of
either "plain TCP" (meh) or "SSH" (secure, albeit a bit more hassle to
set up than TCP-MD5). I'd like to add TCP-MD5 as another option.
TCP-MD5 for RTR is specified through RFC 6810 section 7.3 and RFC 8210
section 9.3.
Minimal bird.conf:
router id 10.0.0.1;
roa4 table r4;
roa6 table r6;
protocol rpki rpki1 {
roa4 { table r4; };
roa6 { table r6; };
remote 165.254.255.17 port 8282;
transport tcp password "test"; /* password keyword is new here! */
debug all;
}
This config was tested on Linux against a WIP based on StayRTR, tcpdump
suggests this works as expected.
job at josephine:~/bird$ ./birdc -s /tmp/bird show protocols all
BIRD v2.15.1-29-g35f74c4b-x ready.
Name Proto Table State Since Info
rpki1 RPKI --- up 15:16:41.677 Established
Cache server: 165.254.255.17
Cache port: 8282
Status: Established
Transport: TCP-MD5
I can leave the server at 165.254.255.17 port 8282 with TCP-MD5
authentication password "test" running for a bit so others can more
easily test the below patch without having to compile/run StayRTR.
Below is a changeset for your consideration! Feedback is welcome.
Kind regards,
Job
ps. It seems TCP-MD5 for BGP doesn't work out-of-the-box on OpenBSD,
downstream porters apply a few minimal patches:
https://github.com/openbsd/ports/tree/master/net/bird/2/patches
perhaps these can be upstreamed so that we can work towards TCP-MD5 RTR
support in BIRD on OpenBSD as well? :-)
Author: Job Snijders <job at fastly.com>
Date: Wed Sep 18 10:46:06 2024 +0000
Add RTR TCP-MD5 authentication support
diff --git a/doc/bird.sgml b/doc/bird.sgml
index e2050c13..07bedef9 100644
--- a/doc/bird.sgml
+++ b/doc/bird.sgml
@@ -5735,7 +5735,7 @@ protocol rpki [<name>] {
refresh [keep] <num>;
retry [keep] <num>;
expire [keep] <num>;
- transport tcp;
+ transport tcp [password <m/string/];
transport ssh {
bird private key "</path/to/id_rsa>";
remote public key "</path/to/known_host>";
@@ -5791,9 +5791,10 @@ specify both channels.
instead. This may be useful for implementing loose RPKI check for
blackholes. Default: disabled.
- <tag>transport tcp</tag> Unprotected transport over TCP. It's a default
- transport. Should be used only on secure private networks.
- Default: tcp
+ <tag>transport tcp [password <m/string/]</tag> transport over TCP. It's
+ the default transport. Should be used only on secure private networks.
+ If a password is specified, the session is authenticated using TCP-MD5
+ (<rfc id="2385">). Default: tcp, no authentication.
<tag>transport ssh { <m/SSH transport options.../ }</tag> It enables a
SSHv2 transport encryption. Cannot be combined with a TCP transport.
diff --git a/proto/rpki/config.Y b/proto/rpki/config.Y
index 769ebb2c..a0b678be 100644
--- a/proto/rpki/config.Y
+++ b/proto/rpki/config.Y
@@ -32,7 +32,8 @@ rpki_check_unused_transport(void)
CF_DECLS
CF_KEYWORDS(RPKI, REMOTE, BIRD, PRIVATE, PUBLIC, KEY, TCP, SSH, TRANSPORT, USER,
- RETRY, REFRESH, EXPIRE, KEEP, IGNORE, MAX, LENGTH, LOCAL, ADDRESS)
+ RETRY, REFRESH, EXPIRE, KEEP, IGNORE, MAX, LENGTH, LOCAL, ADDRESS,
+ PASSWORD)
%type <i> rpki_keep_interval
@@ -109,6 +110,7 @@ rpki_cache_addr: text_or_ipa
rpki_transport:
TCP rpki_transport_tcp_init
+ | TCP PASSWORD text rpki_transport_tcp_init { RPKI_CFG->password = $3; }
| SSH rpki_transport_ssh_init '{' rpki_transport_ssh_opts '}' rpki_transport_ssh_check
;
diff --git a/proto/rpki/rpki.c b/proto/rpki/rpki.c
index 4ec48e3b..d793ee56 100644
--- a/proto/rpki/rpki.c
+++ b/proto/rpki/rpki.c
@@ -673,6 +673,12 @@ rpki_reconfigure_cache(struct rpki_proto *p UNUSED, struct rpki_cache *cache, st
return NEED_RESTART;
}
+ if (old->password != new->password)
+ {
+ CACHE_TRACE(D_EVENTS, cache, "MD5 authentication changed");
+ return NEED_RESTART;
+ }
+
if (old->tr_config.type != new->tr_config.type)
{
CACHE_TRACE(D_EVENTS, cache, "Transport type changed");
@@ -843,7 +849,10 @@ rpki_show_proto_info(struct proto *P)
break;
#endif
case RPKI_TR_TCP:
- transport_name = "Unprotected over TCP";
+ if (cf->password == NULL)
+ transport_name = "Unprotected over TCP";
+ else
+ transport_name = "TCP-MD5";
default_port = RPKI_TCP_PORT;
break;
};
diff --git a/proto/rpki/rpki.h b/proto/rpki/rpki.h
index e67eb0e3..d8fd72ce 100644
--- a/proto/rpki/rpki.h
+++ b/proto/rpki/rpki.h
@@ -127,6 +127,7 @@ struct rpki_config {
u8 keep_retry_interval:1; /* Do not overwrite retry interval by cache server update */
u8 keep_expire_interval:1; /* Do not overwrite expire interval by cache server update */
u8 ignore_max_length:1; /* Ignore received max length and use MAX_PREFIX_LENGTH instead */
+ const char *password; /* Password used for MD5 authentication */
};
void rpki_check_config(struct rpki_config *cf);
diff --git a/proto/rpki/transport.c b/proto/rpki/transport.c
index 26571977..46b00822 100644
--- a/proto/rpki/transport.c
+++ b/proto/rpki/transport.c
@@ -88,6 +88,9 @@ rpki_tr_open(struct rpki_tr_sock *tr)
sk->tos = IP_PREC_INTERNET_CONTROL;
sk->vrf = cache->p->p.vrf;
+ if (cf->tr_config.type == RPKI_TR_TCP && cf->password != NULL)
+ sk->password = cf->password;
+
if (ipa_zero(sk->daddr) && sk->host)
{
const char *err_msg;
More information about the Bird-users
mailing list