From: hannes Date: Sat, 16 Aug 2008 11:36:20 +0000 (+0000) Subject: add infrastructure for verifiying the HMAC-MD5 digest in routing protocols. X-Git-Tag: tcpdump-4.1.0~162 X-Git-Url: https://git.tcpdump.org/tcpdump/commitdiff_plain/3d3c70fbe9b13dd569ea7d37c6c33d7a7cd0d936 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. --- 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 - -#define SIGNATURE_VALID 0 -#define SIGNATURE_INVALID 1 -#define CANT_CHECK_SIGNATURE 2 +#include 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 + +#include + +#include "interface.h" +#include "signature.h" + +#ifdef HAVE_LIBCRYPTO +#include +#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':