]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Fixes broken cryptographic authentication in OSPF
authorOndrej Zajicek <santiago@crfreenet.org>
Wed, 8 Apr 2009 18:15:01 +0000 (20:15 +0200)
committerOndrej Zajicek <santiago@crfreenet.org>
Wed, 8 Apr 2009 18:15:01 +0000 (20:15 +0200)
Cryptographic authentication in OSPF is defective by
design - there might be several packets independently
sent to the network (for example HELLO, LSUPD and LSACK)
where they might be reordered and that causes crypt.
sequence number error.

That can be workarounded by not incresing sequence number
too often. Now we update it only when last packet was sent
before at least one second. This can constitute a risk of
replay attacks, but RFC supposes something similar (like time
in seconds used as CSN).

nest/config.Y
proto/ospf/config.Y
proto/ospf/ospf.h
proto/ospf/packet.c

index 48940ffdb60f40d0d5c61b909eb34ddfc08bbe32..e84377708345a3d96bbfd849737b0c0365b5b399 100644 (file)
@@ -22,7 +22,13 @@ static list *this_p_list;
 static struct password_item *this_p_item;
 static int password_id;
 
-static list *
+static inline void
+reset_passwords(void)
+{
+ this_p_list = NULL;
+}
+
+static inline list *
 get_passwords(void)
 {
   list *rv = this_p_list;
index 00b6be7c9b439d860589c837f798c4c32647742a..bfe2d9c834c29cb152c1dc4c89a2c33df23ea7f2 100644 (file)
@@ -19,6 +19,18 @@ static struct iface_patt *this_ipatt;
 static struct nbma_node *this_nbma;
 static struct area_net_config *this_pref;
 
+static void
+finish_iface_config(struct ospf_iface_patt *ip)
+{
+  ip->passwords = get_passwords();
+
+  if ((ip->autype == OSPF_AUTH_CRYPT) && (ip->helloint < 5))
+    log(L_WARN "Hello or poll interval less that 5 makes cryptographic authenication prone to replay attacks");
+
+  if ((ip->autype == OSPF_AUTH_NONE) && (ip->passwords != NULL))
+    log(L_WARN "Password option without authentication option does not make sense");
+}
+
 CF_DECLS
 
 CF_KEYWORDS(OSPF, AREA, OSPF_METRIC1, OSPF_METRIC2, OSPF_TAG)
@@ -83,7 +95,7 @@ ospf_area_item:
  ;
 
 ospf_vlink:
-   ospf_vlink_start '{' ospf_vlink_opts '}' { OSPF_PATT->passwords = get_passwords(); }
+   ospf_vlink_start '{' ospf_vlink_opts '}' { finish_iface_config(OSPF_PATT); }
  | ospf_vlink_start
  ;
 
@@ -121,6 +133,7 @@ ospf_vlink_start: VIRTUAL LINK idval
   OSPF_PATT->type = OSPF_IT_VLINK;
   init_list(&OSPF_PATT->nbma_list);
   OSPF_PATT->autype = OSPF_AUTH_NONE;
+  reset_passwords();
  }
 ;
 
@@ -223,6 +236,7 @@ ospf_iface_start:
   OSPF_PATT->stub = 0;
   init_list(&OSPF_PATT->nbma_list);
   OSPF_PATT->autype = OSPF_AUTH_NONE;
+  reset_passwords();
  }
 ;
 
@@ -237,7 +251,7 @@ ospf_iface_opt_list:
  ;
 
 ospf_iface:
-  ospf_iface_start iface_patt ospf_iface_opt_list { OSPF_PATT->passwords = get_passwords(); }
+  ospf_iface_start iface_patt ospf_iface_opt_list { finish_iface_config(OSPF_PATT); }
  ;
 
 ospf_iface_list:
index 4e37c184819c0791233f9b6329a5d888bfce4d23..fb78af4e4f14f1df0dfb2a36e614d1b5f9e7ae4a 100644 (file)
@@ -161,7 +161,8 @@ struct ospf_iface
   u16 autype;
   u16 helloint;                        /* number of seconds between hello sending */
   list *passwords;
-  u32 csn;                      /* Crypt seq num. that will be sent net */
+  u32 csn;                      /* Last used crypt seq number */
+  bird_clock_t csn_use;         /* Last time when packet with that CSN was sent */
   ip_addr drip;                        /* Designated router */
   u32 drid;
   ip_addr bdrip;               /* Backup DR */
index c6b233f8ca5cce7ad24d972a1dbbc056500d74db..23785fe8f97ad90aad18002c73240ac61fc1d740 100644 (file)
@@ -75,13 +75,25 @@ ospf_pkt_finalize(struct ospf_iface *ifa, struct ospf_packet *pkt)
 
       pkt->checksum = 0;
 
+      /* Perhaps use random value to prevent replay attacks after
+        reboot when system does not have independent RTC? */
       if (!ifa->csn)
-        ifa->csn = (u32) time(NULL);
+       {
+         ifa->csn = (u32) now;
+         ifa->csn_use = now;
+       }
+
+      /* We must have sufficient delay between sending a packet and increasing 
+        CSN to prevent reordering of packets (in a network) with different CSNs */
+      if ((now - ifa->csn_use) > 1)
+       ifa->csn++;
+
+      ifa->csn_use = now;
 
       pkt->u.md5.keyid = passwd->id;
       pkt->u.md5.len = OSPF_AUTH_CRYPT_SIZE;
       pkt->u.md5.zero = 0;
-      pkt->u.md5.csn = htonl(ifa->csn++);
+      pkt->u.md5.csn = htonl(ifa->csn);
       tail = ((void *)pkt) + ntohs(pkt->length);
       MD5Init(&ctxt);
       MD5Update(&ctxt, (char *) pkt, ntohs(pkt->length));
@@ -184,12 +196,14 @@ ospf_pkt_checkauth(struct ospf_neighbor *n, struct ospf_iface *ifa, struct ospf_
 
       if (n)
       {
-        if(ntohs(pkt->u.md5.csn) < n->csn)
-        {
-          OSPF_TRACE(D_PACKETS, "OSPF_auth: lower sequence number");
-          return 0;
-        }
-        n->csn = ntohs(pkt->u.md5.csn);
+       u32 rcv_csn = ntohl(pkt->u.md5.csn);
+       if(rcv_csn < n->csn)
+       {
+         OSPF_TRACE(D_PACKETS, "OSPF_auth: lower sequence number (rcv %d, old %d)", rcv_csn, n->csn);
+         return 0;
+       }
+
+       n->csn = rcv_csn;
       }
 
       MD5Init(&ctxt);