]> git.proxmox.com Git - mirror_frr.git/commitdiff
isisd: implement MD5 circuit authentication
authorFritz Reichmann <fritz@reichmann.nl>
Sat, 1 Oct 2011 13:49:48 +0000 (17:49 +0400)
committerDenis Ovsienko <infrastation@yandex.ru>
Mon, 13 Feb 2012 23:06:36 +0000 (03:06 +0400)
* 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

isisd/isis_circuit.c
isisd/isis_common.h
isisd/isis_lsp.c
isisd/isis_pdu.c
isisd/isis_pdu.h
isisd/isis_tlv.c
lib/md5.c
lib/md5.h

index e34d491a6eaaf3f403e63d5e7f40f6d7c9981342..99e2bf6f2c4e683cd980b59eaaa057701a0ce34c 100644 (file)
@@ -830,6 +830,21 @@ isis_interface_config_write (struct vty *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++;
+               }
+           }
 
        }
     }
@@ -1022,11 +1037,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;
@@ -1075,7 +1123,6 @@ DEFUN (no_isis_passwd,
   return CMD_SUCCESS;
 }
 
-
 DEFUN (isis_priority,
        isis_priority_cmd,
        "isis priority <0-127>",
@@ -2086,7 +2133,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);
index 263385560910884be919807a1a92254b28aa706d..334d33940f64cb1cba646d2c5aecd443c2e6769c 100644 (file)
@@ -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? */
index 9db0db9da38e2dba8c047b1ee9e94a1331f68376..fd40bb37277c00931e779e3a718f4523359bfa10 100644 (file)
@@ -353,10 +353,25 @@ isis_lsp_authinfo_check (struct stream *stream, struct isis_area *area,
                       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
index dfc613cf2e4b30920eb64c608e67227824bafb14..d67df31baa9bad99f98986b14d95d81ccd07d8a6 100644 (file)
@@ -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 *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 +757,11 @@ process_lan_hello (int level, struct isis_circuit *circuit, u_char * ssnpa)
       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 +1430,7 @@ process_snp (int snp_type, int level, struct isis_circuit *circuit,
       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 +1927,10 @@ send_hello (struct isis_circuit *circuit, int level)
   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 +2002,25 @@ send_hello (struct isis_circuit *circuit, int level)
   /*
    * 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 +2069,14 @@ send_hello (struct isis_circuit *circuit, int level)
   /* 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);
index 95c1ee4ffb2ee38ff3829cad9399a4eaa2207869..c4c38e22a2d5e1ecf11b34b0ad79b4658943bd16 100644 (file)
@@ -258,8 +258,7 @@ int ack_lsp (struct isis_link_state_hdr *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 */
index 9fffef5131b936ffd87e7e8c311151131f28b2fc..3fc717e34845879aa55f047fe5174be04694ab35 100644 (file)
@@ -446,6 +446,10 @@ parse_tlvs (char *areatag, u_char * stream, int size, u_int32_t * expected,
              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 auth_len, u_char *auth_value,
 {
   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);
index 894de648b3de056660d122c66421c0730680c260..2fc36e179b8a3cbb6f42966549e8151d3d50c6f2 100644 (file)
--- a/lib/md5.c
+++ b/lib/md5.c
@@ -298,3 +298,76 @@ static void md5_calc(const uint8_t *b64, md5_ctxt * ctxt)
        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 */
+}
index 89b9a32093d4b47252735138dfe6c43135b0eb0f..3ce83a63aca18829a5f0399b3d2442cd7f196c5d 100644 (file)
--- a/lib/md5.h
+++ b/lib/md5.h
@@ -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_*/