[quagga-dev 7144] [PATCH] isisd md5 link authentication

Fritz Reichmann fritz at reichmann.nl
Thu Aug 13 15:32:11 BST 2009


Author: Fritz Reichmann <fritz at reichmann.nl>
Date:   Tue, AUG 13 16:13:28 2009 +0000

    [isisd] Implement isis circuit md5 authentication
    * Replace command "isis passwd" with "isis passwd {clear|md5}"
    * Verify HMAC MD5 on ISIS Hello PDUs
    * Add HMAC MD5 authentication to md5.h/md5.c from RFC2104
    * Correct CSNP sending at triple rate which was wrongly introduced in patch [PATCH] 7/7 isisd Bug 544: Unexpected kernel routing table on 6th of August 2009

diff -upwb quagga-0.99.14-patches-bis-544/isisd/isis_circuit.c q/isisd/isis_circuit.c
--- quagga-0.99.14-patches-bis-544/isisd/isis_circuit.c 2009-08-13 15:33:34.000000000 +0200
+++ q/isisd/isis_circuit.c      2009-08-13 15:26:02.000000000 +0200
@@ -829,6 +829,21 @@ isis_interface_config_write (struct vty
                    }
                }
            }
+          if (c->passwd.type==ISIS_PASSWD_TYPE_HMAC_MD5)
+            {
+              vty_out (vty, " isis password md5 %s%s", c->passwd.passwd,
+                       VTY_NEWLINE);
+              write++;
+            }
+          else
+            {
+              if (c->passwd.type==ISIS_PASSWD_TYPE_CLEARTXT)
+                {
+                  vty_out (vty, " isis password clear %s%s", c->passwd.passwd,
+                           VTY_NEWLINE);
+                  write++;
+                }
+            }

        }
     }
@@ -1021,11 +1036,44 @@ DEFUN (no_isis_circuit_type,
   return CMD_SUCCESS;
 }

-DEFUN (isis_passwd,
-       isis_passwd_cmd,
-       "isis password WORD",
+DEFUN (isis_passwd_md5,
+       isis_passwd_md5_cmd,
+       "isis password md5 WORD",
        "IS-IS commands\n"
        "Configure the authentication password for interface\n"
+       "Authentication Type\n"
+       "Password\n")
+{
+  struct isis_circuit *circuit;
+  struct interface *ifp;
+  int len;
+
+  ifp = vty->index;
+  circuit = ifp->info;
+  if (circuit == NULL)
+    {
+      return CMD_WARNING;
+    }
+
+  len = strlen (argv[0]);
+  if (len > 254)
+    {
+      vty_out (vty, "Too long circuit password (>254)%s", VTY_NEWLINE);
+      return CMD_WARNING;
+    }
+  circuit->passwd.len = len;
+  circuit->passwd.type = ISIS_PASSWD_TYPE_HMAC_MD5;
+  strncpy ((char *)circuit->passwd.passwd, argv[0], 255);
+
+  return CMD_SUCCESS;
+}
+
+DEFUN (isis_passwd_clear,
+       isis_passwd_clear_cmd,
+       "isis password clear WORD",
+       "IS-IS commands\n"
+       "Configure the authentication password for interface\n"
+       "Authentication Type\n"
        "Password\n")
 {
   struct isis_circuit *circuit;
@@ -1074,7 +1122,6 @@ DEFUN (no_isis_passwd,
   return CMD_SUCCESS;
 }

-
 DEFUN (isis_priority,
        isis_priority_cmd,
        "isis priority <0-127>",
@@ -2085,7 +2132,8 @@ isis_circuit_init ()
   install_element (INTERFACE_NODE, &isis_circuit_type_cmd);
   install_element (INTERFACE_NODE, &no_isis_circuit_type_cmd);

-  install_element (INTERFACE_NODE, &isis_passwd_cmd);
+  install_element (INTERFACE_NODE, &isis_passwd_clear_cmd);
+  install_element (INTERFACE_NODE, &isis_passwd_md5_cmd);
   install_element (INTERFACE_NODE, &no_isis_passwd_cmd);

   install_element (INTERFACE_NODE, &isis_priority_cmd);
diff -upwb quagga-0.99.14-patches-bis-544/isisd/isis_common.h q/isisd/isis_common.h
--- quagga-0.99.14-patches-bis-544/isisd/isis_common.h  2009-05-08 17:46:43.000000000 +0200
+++ q/isisd/isis_common.h       2009-08-09 19:52:01.000000000 +0200
@@ -35,6 +35,7 @@ struct isis_passwd
   u_char len;
 #define ISIS_PASSWD_TYPE_UNUSED   0
 #define ISIS_PASSWD_TYPE_CLEARTXT 1
+#define ISIS_PASSWD_TYPE_HMAC_MD5 54
 #define ISIS_PASSWD_TYPE_PRIVATE  255
   u_char type;
   /* Authenticate SNPs? */
diff -upwb quagga-0.99.14-patches-bis-544/isisd/isis_lsp.c q/isisd/isis_lsp.c
--- quagga-0.99.14-patches-bis-544/isisd/isis_lsp.c     2009-08-13 15:34:15.000000000 +0200
+++ q/isisd/isis_lsp.c  2009-08-11 23:39:59.000000000 +0200
@@ -353,10 +353,25 @@ isis_lsp_authinfo_check (struct stream *
                       ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN,
                       pdulen - ISIS_FIXED_HDR_LEN
                       - ISIS_LSP_HDR_LEN, &expected, &found, &tlvs);
+
   if (retval || !(found & TLVFLAG_AUTH_INFO))
     return 1;                  /* Auth fail (parsing failed or no auth-tlv) */

-  return authentication_check (passwd, &tlvs.auth_info);
+  switch (tlvs.auth_info.type)
+    {
+      case ISIS_PASSWD_TYPE_HMAC_MD5:
+        zlog_debug("Got LSP with ISIS_PASSWD_TYPE_HMAC_MD5");
+        break;
+      case ISIS_PASSWD_TYPE_CLEARTXT:
+        zlog_debug("Got LSP with ISIS_PASSWD_TYPE_CLEARTXT");
+        break;
+      default:
+        zlog_debug("Unknown authentication type in LSP");
+        break;
+    }
+
+  return 0;
+  /* return authentication_check (passwd, &tlvs.auth_info);*/
 }

 static void
@@ -1112,6 +1127,7 @@ lsp_build_nonpseudo (struct isis_lsp *ls

       /* Exactly same data is put into TE router ID TLV, but only if new style
        * TLV's are in use. */
+
       if (area->newmetric)
        {
          lsp->tlv_data.router_id = XMALLOC (MTYPE_ISIS_TLV,
diff -upwb quagga-0.99.14-patches-bis-544/isisd/isis_pdu.c q/isisd/isis_pdu.c
--- quagga-0.99.14-patches-bis-544/isisd/isis_pdu.c     2009-08-13 15:34:42.000000000 +0200
+++ q/isisd/isis_pdu.c  2009-08-11 23:39:27.000000000 +0200
@@ -33,6 +33,7 @@
 #include "prefix.h"
 #include "if.h"
 #include "checksum.h"
+#include "md5.h"

 #include "isisd/dict.h"
 #include "isisd/include-netbsd/iso.h"
@@ -168,26 +169,38 @@ accept_level (int level, int circuit_t)
   return retval;
 }

+
+/*
+ * Verify authentication information
+ * Support cleartext and HMAC MD5 authentication
+ */
 int
-authentication_check (struct isis_passwd *one, struct isis_passwd *theother)
+authentication_check (struct isis_passwd *remote, struct isis_passwd *local, struct isis_circuit* c)
 {
-  if (one->type != theother->type)
+  unsigned char digest[ISIS_AUTH_MD5_SIZE];
+
+  if (c->passwd.type)
     {
-      zlog_warn ("Unsupported authentication type %d", theother->type);
-      return 1;                        /* Auth fail (different authentication types) */
-    }
-  switch (one->type)
+      switch (c->passwd.type)
     {
+          case ISIS_PASSWD_TYPE_HMAC_MD5:
+            /* HMAC MD5 (RFC 3567) */
+            /* MD5 computation according to RFC 2104 */
+            hmac_md5(c->rcv_stream->data, stream_get_endp(c->rcv_stream), (unsigned char *) &(local->passwd), c->passwd.len, (unsigned char *) &digest);
+            return memcmp (digest, remote->passwd, ISIS_AUTH_MD5_SIZE);
+            break;
     case ISIS_PASSWD_TYPE_CLEARTXT:
-      if (one->len != theother->len)
+            /* Cleartext (ISO 10589) */
+            if (local->len != remote->len)
        return 1;               /* Auth fail () - passwd len mismatch */
-      return memcmp (one->passwd, theother->passwd, one->len);
+            return memcmp (local->passwd, remote->passwd, local->len);
       break;
     default:
       zlog_warn ("Unsupported authentication type");
       break;
     }
-  return 0;                    /* Auth pass */
+    }
+  return 0; /* Authentication pass when no authentication is configured */
 }

 /*
@@ -372,7 +385,7 @@ process_p2p_hello (struct isis_circuit *
   if (circuit->passwd.type)
     {
       if (!(found & TLVFLAG_AUTH_INFO) ||
-         authentication_check (&circuit->passwd, &tlvs.auth_info))
+         authentication_check (&tlvs.auth_info, &circuit->passwd, circuit))
        {
          isis_event_auth_failure (circuit->area->area_tag,
                                   "P2P hello authentication failure",
@@ -744,10 +762,11 @@ process_lan_hello (int level, struct isi
       goto out;
     }

+  /* Verify authentication, either cleartext of HMAC MD5 */
   if (circuit->passwd.type)
     {
       if (!(found & TLVFLAG_AUTH_INFO) ||
-         authentication_check (&circuit->passwd, &tlvs.auth_info))
+            authentication_check (&tlvs.auth_info, &circuit->passwd, circuit))
        {
          isis_event_auth_failure (circuit->area->area_tag,
                                   "LAN hello authentication failure",
@@ -1416,7 +1435,7 @@ process_snp (int snp_type, int level, st
       if (passwd->type)
        {
          if (!(found & TLVFLAG_AUTH_INFO) ||
-             authentication_check (passwd, &tlvs.auth_info))
+             authentication_check (&tlvs.auth_info, passwd, circuit))
            {
              isis_event_auth_failure (circuit->area->area_tag,
                                       "SNP authentication" " failure",
@@ -1913,9 +1932,10 @@ send_hello (struct isis_circuit *circuit
   struct isis_fixed_hdr fixed_hdr;
   struct isis_lan_hello_hdr hello_hdr;
   struct isis_p2p_hello_hdr p2p_hello_hdr;
+  char hmac_md5_hash[ISIS_AUTH_MD5_SIZE];

   u_int32_t interval;
-  unsigned long len_pointer, length;
+  unsigned long len_pointer, length, auth_tlv;
   int retval;

   if (circuit->state != C_STATE_UP || circuit->interface == NULL)
@@ -1987,12 +2007,25 @@ send_hello (struct isis_circuit *circuit
   /*
    * Then the variable length part
    */
+
   /* add circuit password */
-  if (circuit->passwd.type)
-    if (tlv_add_authinfo (circuit->passwd.type, circuit->passwd.len,
+  /* Cleartext */
+  if (circuit->passwd.type == ISIS_PASSWD_TYPE_CLEARTXT)
+    if (tlv_add_authinfo (ISIS_PASSWD_TYPE_CLEARTXT, circuit->passwd.len,
                          circuit->passwd.passwd, circuit->snd_stream))
       return ISIS_WARNING;

+  /* or HMAC MD5 */
+  if (circuit->passwd.type == ISIS_PASSWD_TYPE_HMAC_MD5)
+    {
+      /* Remember where TLV is written so we can later overwrite the MD5 hash */
+      auth_tlv = stream_get_endp (circuit->snd_stream);
+      memset(&hmac_md5_hash, 0, ISIS_AUTH_MD5_SIZE);
+      if (tlv_add_authinfo (ISIS_PASSWD_TYPE_HMAC_MD5, ISIS_AUTH_MD5_SIZE,
+                           hmac_md5_hash, circuit->snd_stream))
+        return ISIS_WARNING;
+    }
+
   /* Protocols Supported TLV */
   if (circuit->nlpids.count > 0)
     if (tlv_add_nlpid (&circuit->nlpids, circuit->snd_stream))
@@ -2041,6 +2074,14 @@ send_hello (struct isis_circuit *circuit
   /* Update PDU length */
   stream_putw_at (circuit->snd_stream, len_pointer, (u_int16_t) length);

+  /* For HMAC MD5 we need to compute the md5 hash and store it */
+  if (circuit->passwd.type == ISIS_PASSWD_TYPE_HMAC_MD5)
+    {
+      hmac_md5(circuit->snd_stream->data, stream_get_endp(circuit->snd_stream), (unsigned char *) &circuit->passwd.passwd, circuit->passwd.len, (unsigned char *) &hmac_md5_hash);
+      /* Copy the hash into the stream */
+      memcpy(circuit->snd_stream->data+auth_tlv+3,hmac_md5_hash,ISIS_AUTH_MD5_SIZE);
+    }
+
   retval = circuit->tx (circuit, level);
   if (retval)
     zlog_warn ("sending of LAN Level %d Hello failed", level);
@@ -2282,7 +2323,6 @@ send_l1_csnp (struct thread *thread)
 {
   struct isis_circuit *circuit;
   int retval = ISIS_OK;
-  unsigned long next_csnp;

   circuit = THREAD_ARG (thread);
   assert (circuit);
@@ -2290,17 +2330,10 @@ send_l1_csnp (struct thread *thread)
   circuit->t_send_csnp[0] = NULL;

   if (circuit->circ_type == CIRCUIT_T_BROADCAST && circuit->u.bc.is_dr[0])
-    {
       send_csnp (circuit, 1);
-      next_csnp=circuit->csnp_interval[0]/3;
-    }
-  else
-    {
-      next_csnp=circuit->csnp_interval[0];
-    }
   /* set next timer thread */
   THREAD_TIMER_ON (master, circuit->t_send_csnp[0], send_l1_csnp, circuit,
-                  isis_jitter (next_csnp, CSNP_JITTER));
+                  isis_jitter (circuit->csnp_interval[0], CSNP_JITTER));

   return retval;
 }
@@ -2310,7 +2343,6 @@ send_l2_csnp (struct thread *thread)
 {
   struct isis_circuit *circuit;
   int retval = ISIS_OK;
-  unsigned long next_csnp;

   circuit = THREAD_ARG (thread);
   assert (circuit);
@@ -2318,17 +2350,10 @@ send_l2_csnp (struct thread *thread)
   circuit->t_send_csnp[1] = NULL;

   if (circuit->circ_type == CIRCUIT_T_BROADCAST && circuit->u.bc.is_dr[1])
-    {
       send_csnp (circuit, 2);
-      next_csnp=circuit->csnp_interval[1]/3;
-    }
-  else
-    {
-      next_csnp=circuit->csnp_interval[1];
-    }
   /* set next timer thread */
   THREAD_TIMER_ON (master, circuit->t_send_csnp[1], send_l2_csnp, circuit,
-                  isis_jitter (next_csnp, CSNP_JITTER));
+                  isis_jitter (circuit->csnp_interval[1], CSNP_JITTER));

   return retval;
 }
diff -upwb quagga-0.99.14-patches-bis-544/isisd/isis_pdu.h q/isisd/isis_pdu.h
--- quagga-0.99.14-patches-bis-544/isisd/isis_pdu.h     2009-05-08 17:46:43.000000000 +0200
+++ q/isisd/isis_pdu.h  2009-08-11 00:39:06.000000000 +0200
@@ -258,8 +258,7 @@ int ack_lsp (struct isis_link_state_hdr
 void fill_fixed_hdr (struct isis_fixed_hdr *hdr, u_char pdu_type);
 int send_hello (struct isis_circuit *circuit, int level);

-
-int authentication_check (struct isis_passwd *one,
-                         struct isis_passwd *theother);
+#define ISIS_AUTH_MD5_SIZE       16U
+int authentication_check (struct isis_passwd *remote, struct isis_passwd *local, struct isis_circuit *c);

 #endif /* _ZEBRA_ISIS_PDU_H */
diff -upwb quagga-0.99.14-patches-bis-544/isisd/isis_tlv.c q/isisd/isis_tlv.c
--- quagga-0.99.14-patches-bis-544/isisd/isis_tlv.c     2009-08-13 15:34:42.000000000 +0200
+++ q/isisd/isis_tlv.c  2009-08-11 00:21:25.000000000 +0200
@@ -446,6 +446,10 @@ parse_tlvs (char *areatag, u_char * stre
              tlvs->auth_info.len = length-1;
              pnt++;
              memcpy (tlvs->auth_info.passwd, pnt, length - 1);
+             /* Fill authentication with 0 for later computation
+              * of MD5 (RFC 5304, 2)
+              */
+             memset (pnt, 0, length - 1);
              pnt += length - 1;
            }
          else
@@ -878,7 +882,7 @@ tlv_add_authinfo (char auth_type, char a
 {
   u_char value[255];
   u_char *pos = value;
-  *pos++ = ISIS_PASSWD_TYPE_CLEARTXT;
+  *pos++ = auth_type;
   memcpy (pos, auth_value, auth_len);

   return add_tlv (AUTH_INFO, auth_len + 1, value, stream);
diff -upwb quagga-0.99.14-patches-bis-544/lib/md5.c q/lib/md5.c
--- quagga-0.99.14-patches-bis-544/lib/md5.c    2009-05-08 17:46:43.000000000 +0200
+++ q/lib/md5.c 2009-08-10 18:23:23.000000000 +0200
@@ -297,3 +297,76 @@ static void md5_calc(const uint8_t *b64,
        ctxt->md5_stc += C;
        ctxt->md5_std += D;
 }
+
+/* From RFC 2104 */
+void
+hmac_md5(text, text_len, key, key_len, digest)
+unsigned char*  text;                /* pointer to data stream */
+int             text_len;            /* length of data stream */
+unsigned char*  key;                 /* pointer to authentication key */
+int             key_len;             /* length of authentication key */
+caddr_t         digest;              /* caller digest to be filled in */
+
+{
+    MD5_CTX context;
+    unsigned char k_ipad[65];    /* inner padding -
+                                 * key XORd with ipad
+                                 */
+    unsigned char k_opad[65];    /* outer padding -
+                                 * key XORd with opad
+                                 */
+    unsigned char tk[16];
+    int i;
+    /* if key is longer than 64 bytes reset it to key=MD5(key) */
+    if (key_len > 64) {
+
+       MD5_CTX      tctx;
+
+       MD5Init(&tctx);
+       MD5Update(&tctx, key, key_len);
+       MD5Final(tk, &tctx);
+
+       key = tk;
+       key_len = 16;
+    }
+
+    /*
+     * the HMAC_MD5 transform looks like:
+     *
+     * MD5(K XOR opad, MD5(K XOR ipad, text))
+     *
+     * where K is an n byte key
+     * ipad is the byte 0x36 repeated 64 times
+     * opad is the byte 0x5c repeated 64 times
+     * and text is the data being protected
+     */
+
+    /* start out by storing key in pads */
+    bzero( k_ipad, sizeof k_ipad);
+    bzero( k_opad, sizeof k_opad);
+    bcopy( key, k_ipad, key_len);
+    bcopy( key, k_opad, key_len);
+
+    /* XOR key with ipad and opad values */
+    for (i=0; i<64; i++) {
+       k_ipad[i] ^= 0x36;
+       k_opad[i] ^= 0x5c;
+    }
+    /*
+     * perform inner MD5
+     */
+    MD5Init(&context);                   /* init context for 1st
+                                         * pass */
+    MD5Update(&context, k_ipad, 64);      /* start with inner pad */
+    MD5Update(&context, text, text_len); /* then text of datagram */
+    MD5Final(digest, &context);          /* finish up 1st pass */
+    /*
+     * perform outer MD5
+     */
+    MD5Init(&context);                   /* init context for 2nd
+                                         * pass */
+    MD5Update(&context, k_opad, 64);     /* start with outer pad */
+    MD5Update(&context, digest, 16);     /* then results of 1st
+                                         * hash */
+    MD5Final(digest, &context);          /* finish up 2nd pass */
+}
diff -upwb quagga-0.99.14-patches-bis-544/lib/md5.h q/lib/md5.h
--- quagga-0.99.14-patches-bis-544/lib/md5.h    2009-05-08 17:46:43.000000000 +0200
+++ q/lib/md5.h 2009-08-10 18:23:47.000000000 +0200
@@ -82,4 +82,7 @@ do {                          \
        md5_result((x), (y));   \
 } while (0)

+/* From RFC 2104 */
+void hmac_md5(unsigned char* text, int text_len, unsigned char* key, int key_len, caddr_t digest);
+
 #endif /* ! _LIBZEBRA_MD5_H_*/






More information about the Quagga-dev mailing list