From 8dc2a36ae545d13fdf201b0891185f98852584ee Mon Sep 17 00:00:00 2001 From: Job Snijders Date: Thu, 3 Oct 2024 15:43:12 +0200 Subject: [PATCH] RPKI: Add TCP-MD5 authentication option RPKI-To-Router (RTR) sessions seem to be similar security-sensitivity as IBGP sessions. BIRD already offered a choice of either "plain TCP" (meh) or "SSH" (secure, albeit a bit more hassle to set up than TCP-MD5). The patch adds TCP-MD5 as another option. TCP-MD5 for RTR is specified through RFC 6810 section 7.3 and RFC 8210 section 9.3. Minor changes by committer. --- doc/bird.sgml | 23 +++++++++++++++++++---- proto/rpki/config.Y | 28 ++++++++++++++++++++++++++-- proto/rpki/rpki.c | 26 ++++++++++++++++++++++++-- proto/rpki/tcp_transport.c | 6 ++++++ proto/rpki/transport.h | 9 ++++++++- 5 files changed, 83 insertions(+), 9 deletions(-) diff --git a/doc/bird.sgml b/doc/bird.sgml index e2050c13..5d578b74 100644 --- a/doc/bird.sgml +++ b/doc/bird.sgml @@ -5735,7 +5735,10 @@ protocol rpki [<name>] { refresh [keep] <num>; retry [keep] <num>; expire [keep] <num>; - transport tcp; + transport tcp { + authentication none|md5; + password "<text>"; + }; transport ssh { bird private key "</path/to/id_rsa>"; remote public key "</path/to/known_host>"; @@ -5791,15 +5794,27 @@ specify both channels. instead. This may be useful for implementing loose RPKI check for blackholes. Default: disabled. - transport tcp Unprotected transport over TCP. It's a default - transport. Should be used only on secure private networks. - Default: tcp + transport tcp { Transport over + TCP, it's the default transport. Cannot be combined with a SSH transport. + Default: TCP, no authentication. transport ssh { It enables a SSHv2 transport encryption. Cannot be combined with a TCP transport. Default: off +TCP transport options +

+ + authentication none|md5 + Select authentication method to be used. ). + Default: no authentication. + + password "text" + Use this password for TCP-MD5 authentication of the RPKI-To-Router session. + + SSH transport options

diff --git a/proto/rpki/config.Y b/proto/rpki/config.Y index 769ebb2c..60a4b9f0 100644 --- a/proto/rpki/config.Y +++ b/proto/rpki/config.Y @@ -13,6 +13,7 @@ CF_HDR CF_DEFINES #define RPKI_CFG ((struct rpki_config *) this_proto) +#define RPKI_TR_TCP_CFG ((struct rpki_tr_tcp_config *) RPKI_CFG->tr_config.spec) #define RPKI_TR_SSH_CFG ((struct rpki_tr_ssh_config *) RPKI_CFG->tr_config.spec) static void @@ -32,7 +33,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, + AUTHENTICATION, NONE, MD5, PASSWORD) %type rpki_keep_interval @@ -108,7 +110,7 @@ rpki_cache_addr: text_or_ipa }; rpki_transport: - TCP rpki_transport_tcp_init + TCP rpki_transport_tcp_init rpki_transport_tcp_opts_list rpki_transport_tcp_check | SSH rpki_transport_ssh_init '{' rpki_transport_ssh_opts '}' rpki_transport_ssh_check ; @@ -119,6 +121,28 @@ rpki_transport_tcp_init: RPKI_CFG->tr_config.type = RPKI_TR_TCP; }; +rpki_transport_tcp_opts_list: + /* empty */ + | '{' rpki_transport_tcp_opts '}' + ; + +rpki_transport_tcp_opts: + /* empty */ + | rpki_transport_tcp_opts rpki_transport_tcp_item ';' + ; + +rpki_transport_tcp_item: + AUTHENTICATION NONE { RPKI_TR_TCP_CFG->auth_type = RPKI_TCP_AUTH_NONE; } + | AUTHENTICATION MD5 { RPKI_TR_TCP_CFG->auth_type = RPKI_TCP_AUTH_MD5; } + | PASSWORD text { RPKI_TR_TCP_CFG->password = $2; } + ; + +rpki_transport_tcp_check: +{ + if (!RPKI_TR_TCP_CFG->auth_type != !RPKI_TR_TCP_CFG->password) + cf_error("Authentication and password options should be used together"); +}; + rpki_transport_ssh_init: { #if HAVE_LIBSSH diff --git a/proto/rpki/rpki.c b/proto/rpki/rpki.c index 4ec48e3b..cbd94492 100644 --- a/proto/rpki/rpki.c +++ b/proto/rpki/rpki.c @@ -685,6 +685,24 @@ rpki_reconfigure_cache(struct rpki_proto *p UNUSED, struct rpki_cache *cache, st try_reset = 1; } + if (new->tr_config.type == RPKI_TR_TCP) + { + struct rpki_tr_tcp_config *tcp_old = (void *) old->tr_config.spec; + struct rpki_tr_tcp_config *tcp_new = (void *) new->tr_config.spec; + + if (tcp_old->auth_type != tcp_new->auth_type) + { + CACHE_TRACE(D_EVENTS, cache, "Authentication type changed"); + return NEED_RESTART; + } + + if (bstrcmp(tcp_old->password, tcp_new->password)) + { + CACHE_TRACE(D_EVENTS, cache, "MD5 password changed"); + return NEED_RESTART; + } + } + #if HAVE_LIBSSH else if (new->tr_config.type == RPKI_TR_SSH) { @@ -842,8 +860,12 @@ rpki_show_proto_info(struct proto *P) default_port = RPKI_SSH_PORT; break; #endif - case RPKI_TR_TCP: - transport_name = "Unprotected over TCP"; + case RPKI_TR_TCP:; + struct rpki_tr_tcp_config *tcp_cf = (void *) cf->tr_config.spec; + if (tcp_cf->auth_type == RPKI_TCP_AUTH_MD5) + transport_name = "TCP-MD5"; + else + transport_name = "Unprotected over TCP"; default_port = RPKI_TCP_PORT; break; }; diff --git a/proto/rpki/tcp_transport.c b/proto/rpki/tcp_transport.c index 132f8e2d..87451c94 100644 --- a/proto/rpki/tcp_transport.c +++ b/proto/rpki/tcp_transport.c @@ -24,10 +24,16 @@ static int rpki_tr_tcp_open(struct rpki_tr_sock *tr) { + struct rpki_cache *cache = tr->cache; + struct rpki_config *cf = (void *) cache->p->p.cf; + struct rpki_tr_tcp_config *tcp_cf = (void *) cf->tr_config.spec; sock *sk = tr->sk; sk->type = SK_TCP_ACTIVE; + if (tcp_cf->auth_type == RPKI_TCP_AUTH_MD5) + sk->password = tcp_cf->password; + if (sk_open(sk) != 0) return RPKI_TR_ERROR; diff --git a/proto/rpki/transport.h b/proto/rpki/transport.h index bb8d41eb..10e9acb7 100644 --- a/proto/rpki/transport.h +++ b/proto/rpki/transport.h @@ -56,6 +56,12 @@ enum rpki_tr_type { #endif }; +/* TCP authentication types */ +enum rpki_tcp_auth { + RPKI_TCP_AUTH_NONE, + RPKI_TCP_AUTH_MD5 +}; + /* Common configure structure for transports */ struct rpki_tr_config { enum rpki_tr_type type; /* RPKI_TR_TCP or RPKI_TR_SSH */ @@ -63,7 +69,8 @@ struct rpki_tr_config { }; struct rpki_tr_tcp_config { - /* No internal configuration data */ + enum rpki_tcp_auth auth_type; /* Authentication type */ + const char *password; /* Password used for authentication */ }; struct rpki_tr_ssh_config {