]> The Tcpdump Group git mirrors - tcpdump/commitdiff
add infrastructure for verifiying the HMAC-MD5 digest in routing protocols.
authorhannes <hannes>
Sat, 16 Aug 2008 11:36:20 +0000 (11:36 +0000)
committerhannes <hannes>
Sat, 16 Aug 2008 11:36:20 +0000 (11:36 +0000)
The shared secret is passed using the already existing -M option which is
used for TCP-MD5 checking.

add initial supoort for RSVP Integrity object verification.

Makefile.in
interface.h
netdissect.h
print-rsvp.c
print-tcp.c
signature.c [new file with mode: 0644]
signature.h [new file with mode: 0644]
tcpdump.1
tcpdump.c

index 6f1685554e02d9c5edff1c7293f193e4551372a7..307b1fc118dd1f13b35f4e35de18efb1f0655c1d 100644 (file)
@@ -17,7 +17,7 @@
 #  WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
 #  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 #
-# @(#) $Header: /tcpdump/master/tcpdump/Makefile.in,v 1.322 2008-05-27 07:13:21 guy Exp $ (LBL)
+# @(#) $Header: /tcpdump/master/tcpdump/Makefile.in,v 1.323 2008-08-16 11:36:20 hannes Exp $ (LBL)
 
 #
 # Various configurable paths (remember to edit Makefile.in, not Makefile)
@@ -90,7 +90,7 @@ CSRC =        addrtoname.c af.c checksum.c cpack.c gmpls.c oui.c gmt2local.c ipproto.c
        print-symantec.c print-syslog.c print-tcp.c print-telnet.c print-tftp.c \
        print-timed.c print-token.c print-udld.c print-udp.c \
        print-vjc.c print-vqp.c print-vrrp.c print-vtp.c \
-       print-wb.c print-zephyr.c setsignal.c tcpdump.c util.c
+       print-wb.c print-zephyr.c signature.c setsignal.c tcpdump.c util.c
 
 LIBNETDISSECT_SRC=print-isakmp.c
 LIBNETDISSECT_OBJ=$(LIBNETDISSECT_SRC:.c=.o)
index a94a0ffbec99ffd185ddd1ec769ec91c6e7189fb..a27d00204fd2c1d7e61a97d7c620b61da2415e91 100644 (file)
@@ -18,7 +18,7 @@
  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  *
- * @(#) $Header: /tcpdump/master/tcpdump/interface.h,v 1.284 2008-04-04 19:42:11 guy Exp $ (LBL)
+ * @(#) $Header: /tcpdump/master/tcpdump/interface.h,v 1.285 2008-08-16 11:36:20 hannes Exp $ (LBL)
  */
 
 #ifndef tcpdump_interface_h
@@ -387,7 +387,7 @@ extern netdissect_options *gndo;
 #define Iflag gndo->ndo_Iflag 
 #define suppress_default_print gndo->ndo_suppress_default_print
 #define packettype gndo->ndo_packettype
-#define tcpmd5secret gndo->ndo_tcpmd5secret
+#define sigsecret gndo->ndo_sigsecret
 #define Wflag gndo->ndo_Wflag
 #define WflagChars gndo->ndo_WflagChars
 #define Cflag_count gndo->ndo_Cflag_count
index 386a4e92b3f83b8ba2a58bcf94208c25c2c19591..3a70661ef8c36cc0d5af54c119f69514c2703360 100644 (file)
@@ -21,7 +21,7 @@
  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  *
- * @(#) $Header: /tcpdump/master/tcpdump/netdissect.h,v 1.26 2008-04-04 19:42:11 guy Exp $ (LBL)
+ * @(#) $Header: /tcpdump/master/tcpdump/netdissect.h,v 1.27 2008-08-16 11:36:20 hannes Exp $ (LBL)
  */
 
 #ifndef netdissect_h
@@ -122,7 +122,7 @@ struct netdissect_options {
   struct sa_list *ndo_sa_list_head;  /* used by print-esp.c */
   struct sa_list *ndo_sa_default;
 
-  char *ndo_tcpmd5secret;      /* TCP-MD5 secret key */
+  char *ndo_sigsecret;         /* Signature verification secret key */
 
   struct esp_algorithm *ndo_espsecret_xform;   /* cache of decoded  */
   char                 *ndo_espsecret_key;
index c8bc74f77a0f56d79dc294451b5e3e82c0805224..346ff384caf858d3cbdf941992d4f05f5064e089 100644 (file)
@@ -17,7 +17,7 @@
 
 #ifndef lint
 static const char rcsid[] _U_ =
-    "@(#) $Header: /tcpdump/master/tcpdump/print-rsvp.c,v 1.49 2008-03-03 12:57:04 hannes Exp $";
+    "@(#) $Header: /tcpdump/master/tcpdump/print-rsvp.c,v 1.50 2008-08-16 11:36:20 hannes Exp $";
 #endif
 
 #ifdef HAVE_CONFIG_H
@@ -36,6 +36,7 @@ static const char rcsid[] _U_ =
 #include "ethertype.h"
 #include "gmpls.h"
 #include "af.h"
+#include "signature.h"
 
 /*
  * RFC 2205 common header
@@ -627,7 +628,8 @@ rsvp_intserv_print(const u_char *tptr, u_short obj_tlen) {
 }
 
 static int
-rsvp_obj_print (const u_char *tptr, const char *ident, u_int tlen) {
+rsvp_obj_print (const u_char *pptr, u_int plen, const u_char *tptr,
+                const char *ident, u_int tlen) {
 
     const struct rsvp_object_header *rsvp_obj_header;
     const u_char *obj_tptr;
@@ -637,7 +639,7 @@ rsvp_obj_print (const u_char *tptr, const char *ident, u_int tlen) {
     } obj_ptr;
 
     u_short rsvp_obj_len,rsvp_obj_ctype,obj_tlen,intserv_serv_tlen;
-    int hexdump,processed,padbytes,error_code,error_value,i;
+    int hexdump,processed,padbytes,error_code,error_value,i,sigcheck;
     union {
        float f;
        u_int32_t i;
@@ -1636,12 +1638,21 @@ rsvp_obj_print (const u_char *tptr, const char *ident, u_int tlen) {
                        bittok2str(rsvp_obj_integrity_flag_values,
                                   "none",
                                   obj_ptr.rsvp_obj_integrity->flags));
-                printf("%s  MD5-sum 0x%08x%08x%08x%08x (unverified)",
+                printf("%s  MD5-sum 0x%08x%08x%08x%08x ",
                        ident,
                        EXTRACT_32BITS(obj_ptr.rsvp_obj_integrity->digest),
                        EXTRACT_32BITS(obj_ptr.rsvp_obj_integrity->digest+4),
                        EXTRACT_32BITS(obj_ptr.rsvp_obj_integrity->digest+8),
                        EXTRACT_32BITS(obj_ptr.rsvp_obj_integrity->digest+12));
+
+#ifdef HAVE_LIBCRYPTO
+                sigcheck = signature_verify(pptr, plen, (unsigned char *)obj_ptr.\
+                                             rsvp_obj_integrity->digest);
+#else
+                sigcheck = CANT_CHECK_SIGNATURE;
+#endif
+                printf(" (%s)", tok2str(signature_check_values, "Unknown", sigcheck));
+
                 obj_tlen+=sizeof(struct rsvp_obj_integrity_t);
                 obj_tptr+=sizeof(struct rsvp_obj_integrity_t);
                 break;
@@ -1767,13 +1778,13 @@ trunc:
 void
 rsvp_print(register const u_char *pptr, register u_int len) {
 
-    const struct rsvp_common_header *rsvp_com_header;
+    struct rsvp_common_header *rsvp_com_header;
     const u_char *tptr,*subtptr;
-    u_short tlen,subtlen;
+    u_short plen, tlen, subtlen;
 
     tptr=pptr;
 
-    rsvp_com_header = (const struct rsvp_common_header *)pptr;
+    rsvp_com_header = (struct rsvp_common_header *)pptr;
     TCHECK(*rsvp_com_header);
 
     /*
@@ -1796,7 +1807,7 @@ rsvp_print(register const u_char *pptr, register u_int len) {
 
     /* ok they seem to want to know everything - lets fully decode it */
 
-    tlen=EXTRACT_16BITS(rsvp_com_header->length);
+    plen = tlen = EXTRACT_16BITS(rsvp_com_header->length);
 
     printf("\n\tRSVPv%u %s Message (%u), Flags: [%s], length: %u, ttl: %u, checksum: 0x%04x",
            RSVP_EXTRACT_VERSION(rsvp_com_header->version_flags),
@@ -1807,6 +1818,12 @@ rsvp_print(register const u_char *pptr, register u_int len) {
            rsvp_com_header->ttl,
            EXTRACT_16BITS(rsvp_com_header->checksum));
 
+    /*
+     * Clear checksum prior to signature verification.
+     */
+    rsvp_com_header->checksum[0] = 0;
+    rsvp_com_header->checksum[1] = 0;
+
     if (tlen < sizeof(const struct rsvp_common_header)) {
         printf("ERROR: common header too short %u < %lu", tlen,
                (unsigned long)sizeof(const struct rsvp_common_header));
@@ -1821,7 +1838,7 @@ rsvp_print(register const u_char *pptr, register u_int len) {
     case RSVP_MSGTYPE_AGGREGATE:
         while(tlen > 0) {
             subtptr=tptr;
-            rsvp_com_header = (const struct rsvp_common_header *)subtptr;
+            rsvp_com_header = (struct rsvp_common_header *)subtptr;
             TCHECK(*rsvp_com_header);
 
             /*
@@ -1842,6 +1859,12 @@ rsvp_print(register const u_char *pptr, register u_int len) {
                    subtlen,
                    rsvp_com_header->ttl,
                    EXTRACT_16BITS(rsvp_com_header->checksum));
+
+            /*
+             * Clear checksum prior to signature verification.
+             */
+            rsvp_com_header->checksum[0] = 0;
+            rsvp_com_header->checksum[1] = 0;
             
             if (subtlen < sizeof(const struct rsvp_common_header)) {
                 printf("ERROR: common header too short %u < %lu", subtlen,
@@ -1858,7 +1881,7 @@ rsvp_print(register const u_char *pptr, register u_int len) {
             subtptr+=sizeof(const struct rsvp_common_header);
             subtlen-=sizeof(const struct rsvp_common_header);
 
-            if (rsvp_obj_print(subtptr,"\n\t    ", subtlen) == -1)
+            if (rsvp_obj_print(pptr, plen, subtptr,"\n\t    ", subtlen) == -1)
                 return;
 
             tptr+=subtlen+sizeof(const struct rsvp_common_header);
@@ -1878,7 +1901,7 @@ rsvp_print(register const u_char *pptr, register u_int len) {
     case RSVP_MSGTYPE_HELLO:
     case RSVP_MSGTYPE_ACK:
     case RSVP_MSGTYPE_SREFRESH:
-        if (rsvp_obj_print(tptr,"\n\t  ", tlen) == -1)
+        if (rsvp_obj_print(pptr, plen, tptr,"\n\t  ", tlen) == -1)
             return;
         break;
 
index d939a2ced844993dc3c63f2e3f6ad3fe0bc5a568..baa0ee6e312ab910af4240702a0e817edd1ed51c 100644 (file)
@@ -25,7 +25,7 @@
 
 #ifndef lint
 static const char rcsid[] _U_ =
-"@(#) $Header: /tcpdump/master/tcpdump/print-tcp.c,v 1.133 2007-12-22 03:08:04 guy Exp $ (LBL)";
+"@(#) $Header: /tcpdump/master/tcpdump/print-tcp.c,v 1.134 2008-08-16 11:36:20 hannes Exp $ (LBL)";
   #else
 __RCSID("$NetBSD: print-tcp.c,v 1.8 2007/07/24 11:53:48 drochner Exp $");
 #endif
@@ -58,10 +58,7 @@ __RCSID("$NetBSD: print-tcp.c,v 1.8 2007/07/24 11:53:48 drochner Exp $");
 
 #ifdef HAVE_LIBCRYPTO
 #include <openssl/md5.h>
-
-#define SIGNATURE_VALID                0
-#define SIGNATURE_INVALID      1
-#define CANT_CHECK_SIGNATURE   2
+#include <signature.h>
 
 static int tcp_verify_signature(const struct ip *ip, const struct tcphdr *tp,
                                 const u_char *data, int length, const u_char *rcvsig);
@@ -752,7 +749,7 @@ tcp_verify_signature(const struct ip *ip, const struct tcphdr *tp,
 
         tp1 = *tp;
 
-        if (tcpmd5secret == NULL)
+        if (sigsecret == NULL)
                 return (CANT_CHECK_SIGNATURE);
 
         MD5_Init(&ctx);
@@ -800,7 +797,7 @@ tcp_verify_signature(const struct ip *ip, const struct tcphdr *tp,
         /*
          * Step 4: Update MD5 hash with shared secret.
          */
-        MD5_Update(&ctx, tcpmd5secret, strlen(tcpmd5secret));
+        MD5_Update(&ctx, sigsecret, strlen(sigsecret));
         MD5_Final(sig, &ctx);
 
         if (memcmp(rcvsig, sig, TCP_SIGLEN) == 0)
diff --git a/signature.c b/signature.c
new file mode 100644 (file)
index 0000000..6a94ad9
--- /dev/null
@@ -0,0 +1,159 @@
+/* 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code
+ * distributions retain the above copyright notice and this paragraph
+ * in its entirety, and (2) distributions including binary code include
+ * the above copyright notice and this paragraph in its entirety in
+ * the documentation or other materials provided with the distribution.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND
+ * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
+ * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE.
+ *
+ * Functions for signature and digest verification.
+ * 
+ * Original code by Hannes Gredler ([email protected])
+ */
+
+#ifndef lint
+static const char rcsid[] _U_ =
+    "@(#) $Header: /tcpdump/master/tcpdump/signature.c,v 1.1 2008-08-16 11:36:20 hannes Exp $ (LBL)";
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <tcpdump-stdinc.h>
+
+#include <string.h>
+
+#include "interface.h"
+#include "signature.h"
+
+#ifdef HAVE_LIBCRYPTO
+#include <openssl/md5.h>
+#endif
+
+struct tok signature_check_values[] = {
+    { SIGNATURE_VALID, "valid"},
+    { SIGNATURE_INVALID, "invalid"},
+    { CANT_CHECK_SIGNATURE, "unchecked"},
+    { 0, NULL }
+};
+
+
+#ifdef HAVE_LIBCRYPTO
+/*
+ * Compute a HMAC MD5 sum.
+ * Taken from rfc2104, Appendix.
+ */
+static void
+signature_compute_hmac_md5(const u_int8_t *text, int text_len, unsigned char *key,
+                           unsigned int key_len, u_int8_t *digest)
+{
+    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;
+
+        MD5_Init(&tctx);
+        MD5_Update(&tctx, key, key_len);
+        MD5_Final(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
+     */
+    MD5_Init(&context);                   /* init context for 1st pass */
+    MD5_Update(&context, k_ipad, 64);     /* start with inner pad */
+    MD5_Update(&context, text, text_len); /* then text of datagram */
+    MD5_Final(digest, &context);          /* finish up 1st pass */
+
+    /*
+     * perform outer MD5
+     */
+    MD5_Init(&context);                   /* init context for 2nd pass */
+    MD5_Update(&context, k_opad, 64);     /* start with outer pad */
+    MD5_Update(&context, digest, 16);     /* then results of 1st hash */
+    MD5_Final(digest, &context);          /* finish up 2nd pass */
+}
+#endif
+
+#ifdef HAVE_LIBCRYPTO
+/*
+ * Verify a cryptographic signature of the packet.
+ * Currently only MD5 is supported.
+ */
+int
+signature_verify (const u_char *pptr, u_int plen, u_char *sig_ptr)
+{
+    u_int8_t rcvsig[16];
+    u_int8_t sig[16];
+    unsigned int i;
+
+    /*
+     * Save the signature before clearing it.
+     */
+    bcopy(sig_ptr, rcvsig, sizeof(rcvsig));
+    bzero(sig_ptr, sizeof(rcvsig));
+
+    if (!sigsecret) {
+        return (CANT_CHECK_SIGNATURE);
+    }
+
+    signature_compute_hmac_md5(pptr, plen, (unsigned char *)sigsecret,
+                               strlen(sigsecret), sig);
+
+    if (memcmp(rcvsig, sig, sizeof(sig)) == 0) {
+        return (SIGNATURE_VALID);
+
+    } else {
+
+        for (i = 0; i < sizeof(sig); ++i) {
+            (void)printf("%02x", sig[i]);
+        }
+
+        return (SIGNATURE_INVALID);
+    }
+}
+#endif
+
+/*
+ * Local Variables:
+ * c-style: whitesmith
+ * c-basic-offset: 4
+ * End:
+ */
diff --git a/signature.h b/signature.h
new file mode 100644 (file)
index 0000000..33f8924
--- /dev/null
@@ -0,0 +1,26 @@
+/* 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that: (1) source code
+ * distributions retain the above copyright notice and this paragraph
+ * in its entirety, and (2) distributions including binary code include
+ * the above copyright notice and this paragraph in its entirety in
+ * the documentation or other materials provided with the distribution.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND
+ * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT
+ * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE.
+ *
+ * Functions for signature and digest verification.
+ *
+ * Original code by Hannes Gredler ([email protected])
+ */
+
+/* @(#) $Header: /tcpdump/master/tcpdump/signature.h,v 1.1 2008-08-16 11:36:20 hannes Exp $ (LBL) */
+
+/* signature checking result codes */
+#define SIGNATURE_VALID                0
+#define SIGNATURE_INVALID      1
+#define CANT_CHECK_SIGNATURE   2
+
+extern struct tok signature_check_values[];
+extern int signature_verify (const u_char *, u_int, u_char *);
index 8f7b337d153783b646849e3a809952b36a7f667b..6f8cd8146a9e56cdc0a353c26ec0a849c3c21ed5 100644 (file)
--- a/tcpdump.1
+++ b/tcpdump.1
@@ -1,4 +1,4 @@
-.\" @(#) $Header: /tcpdump/master/tcpdump/Attic/tcpdump.1,v 1.191 2008-05-30 01:37:41 guy Exp $ (LBL)
+.\" @(#) $Header: /tcpdump/master/tcpdump/Attic/tcpdump.1,v 1.192 2008-08-16 11:36:20 hannes Exp $ (LBL)
 .\"
 .\"    $NetBSD: tcpdump.8,v 1.9 2003/03/31 00:18:17 perry Exp $
 .\"
@@ -369,7 +369,8 @@ can be used several times to load several MIB modules into \fItcpdump\fP.
 .TP
 .B \-M
 Use \fIsecret\fP as a shared secret for validating the digests found in
-TCP segments with the TCP-MD5 option (RFC 2385), if present.
+Routing Protocols (RSVP) and TCP segments with the TCP-MD5 option
+(RFC 2385), if present.
 .TP
 .B \-n
 Don't convert addresses (i.e., host addresses, port numbers, etc.) to names.
index 8f9ada1a326e065248ef71601ad9331c3e71378e..74c86419807cac5d39c315e16b3862e9a5dfcb6a 100644 (file)
--- a/tcpdump.c
+++ b/tcpdump.c
@@ -30,7 +30,7 @@ static const char copyright[] _U_ =
     "@(#) Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 2000\n\
 The Regents of the University of California.  All rights reserved.\n";
 static const char rcsid[] _U_ =
-    "@(#) $Header: /tcpdump/master/tcpdump/tcpdump.c,v 1.281 2008-04-09 21:45:06 guy Exp $ (LBL)";
+    "@(#) $Header: /tcpdump/master/tcpdump/tcpdump.c,v 1.282 2008-08-16 11:36:20 hannes Exp $ (LBL)";
 #endif
 
 /*
@@ -708,7 +708,7 @@ main(int argc, char **argv)
 #ifndef HAVE_LIBCRYPTO
                        warning("crypto code not compiled in");
 #endif
-                       tcpmd5secret = optarg;
+                       sigsecret = optarg;
                        break;
 
                case 'n':