summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorhannes <hannes>2008-08-16 11:36:20 +0000
committerhannes <hannes>2008-08-16 11:36:20 +0000
commit3d3c70fbe9b13dd569ea7d37c6c33d7a7cd0d936 (patch)
tree9f8b4d3fd70fb2f0faff2ea1c546762ca92ba2eb
parentc695e7fee4bca70a7a0ab7991b9395e0041daa66 (diff)
downloadtcpdump-3d3c70fbe9b13dd569ea7d37c6c33d7a7cd0d936.tar.gz
add infrastructure for verifiying the HMAC-MD5 digest in routing protocols.
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.
-rw-r--r--Makefile.in4
-rw-r--r--interface.h4
-rw-r--r--netdissect.h4
-rw-r--r--print-rsvp.c45
-rw-r--r--print-tcp.c11
-rw-r--r--signature.c159
-rw-r--r--signature.h26
-rw-r--r--tcpdump.15
-rw-r--r--tcpdump.c4
9 files changed, 234 insertions, 28 deletions
diff --git a/Makefile.in b/Makefile.in
index 6f168555..307b1fc1 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -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)
diff --git a/interface.h b/interface.h
index a94a0ffb..a27d0020 100644
--- a/interface.h
+++ b/interface.h
@@ -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
diff --git a/netdissect.h b/netdissect.h
index 386a4e92..3a70661e 100644
--- a/netdissect.h
+++ b/netdissect.h
@@ -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;
diff --git a/print-rsvp.c b/print-rsvp.c
index c8bc74f7..346ff384 100644
--- a/print-rsvp.c
+++ b/print-rsvp.c
@@ -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;
diff --git a/print-tcp.c b/print-tcp.c
index d939a2ce..baa0ee6e 100644
--- a/print-tcp.c
+++ b/print-tcp.c
@@ -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
index 00000000..6a94ad93
--- /dev/null
+++ b/signature.c
@@ -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 (hannes@juniper.net)
+ */
+
+#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
index 00000000..33f8924a
--- /dev/null
+++ b/signature.h
@@ -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 (hannes@juniper.net)
+ */
+
+/* @(#) $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 *);
diff --git a/tcpdump.1 b/tcpdump.1
index 8f7b337d..6f8cd814 100644
--- 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.
diff --git a/tcpdump.c b/tcpdump.c
index 8f9ada1a..74c86419 100644
--- 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':