*/
#ifndef lint
-static char rcsid[] =
- "@(#) Header: print-ah.c,v 1.37 94/06/10 17:01:42 mccanne Exp (LBL)";
+static const char rcsid[] =
+ "@(#) $Header: /tcpdump/master/tcpdump/print-esp.c,v 1.24 2002-04-07 02:16:03 guy Exp $ (LBL)";
#endif
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
#include <sys/param.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
+#include <stdlib.h>
#include <netinet/in.h>
-#include <netinet/in_systm.h>
-#include <netinet/ip.h>
-#include <netinet/ip_var.h>
-#include <netinet/udp.h>
-#include <netinet/udp_var.h>
-
-#undef NOERROR /* Solaris sucks */
-#include <arpa/nameser.h>
-#include <arpa/tftp.h>
-
-#ifdef SOLARIS
-#include <tiuser.h>
+
+#ifdef HAVE_LIBCRYPTO
+#include <openssl/des.h>
+#include <openssl/blowfish.h>
+#ifdef HAVE_OPENSSL_RC5_H
+#include <openssl/rc5.h>
+#endif
+#ifdef HAVE_OPENSSL_CAST_H
+#include <openssl/cast.h>
+#endif
#endif
-#include <rpc/rpc.h>
-#include <errno.h>
#include <stdio.h>
+#include "ip.h"
+#include "esp.h"
+#ifdef INET6
+#include "ip6.h"
+#endif
+
+#define AVOID_CHURN 1
#include "interface.h"
#include "addrtoname.h"
-#include "appletalk.h"
-#include "nfs.h"
-#include "bootp.h"
+static struct esp_algorithm *espsecret_xform=NULL; /* cache of decoded alg. */
+static char *espsecret_key=NULL;
-extern int packettype;
+enum cipher { NONE,
+ DESCBC,
+ BLOWFISH,
+ RC5,
+ CAST128,
+ DES3CBC};
+
+
+
+struct esp_algorithm {
+ char *name;
+ enum cipher algo;
+ int ivlen;
+ int authlen;
+ int replaysize;
+};
+
+struct esp_algorithm esp_xforms[]={
+ {"none", NONE, 0, 0, 0},
+ {"des-cbc", DESCBC, 8, 0, 0},
+ {"des-cbc-hmac96", DESCBC, 8, 12, 4},
+ {"blowfish-cbc", BLOWFISH,8, 0, 0},
+ {"blowfish-cbc-hmac96", BLOWFISH,8, 12, 4},
+ {"rc5-cbc", RC5, 8, 0, 0},
+ {"rc5-cbc-hmac96", RC5, 8, 12, 4},
+ {"cast128-cbc", CAST128, 8, 0, 0},
+ {"cast128-cbc-hmac96", CAST128, 8, 12, 4},
+ {"3des-cbc-hmac96", DES3CBC, 8, 12, 4},
+};
+
+static int hexdigit(char hex)
+{
+ if(hex >= '0' && hex <= '9') {
+ return (hex - '0');
+ } else if(hex >= 'A' && hex <= 'F') {
+ return (hex - 'A' + 10);
+ } else if(hex >= 'a' && hex <= 'f') {
+ return (hex - 'a' + 10);
+ } else {
+ printf("invalid hex digit %c in espsecret\n", hex);
+ return 0;
+ }
+}
+
+static int hex2byte(char *hexstring)
+{
+ int byte;
+
+ byte = (hexdigit(hexstring[0]) << 4) +
+ hexdigit(hexstring[1]);
+ return byte;
+}
+
+
+static void esp_print_decodesecret(void)
+{
+ char *colon;
+ int len, i;
+ struct esp_algorithm *xf;
+
+ if(espsecret == NULL) {
+ /* set to NONE transform */
+ espsecret_xform = esp_xforms;
+ return;
+ }
+
+ if(espsecret_key != NULL) {
+ return;
+ }
+
+ colon = strchr(espsecret, ':');
+ if(colon == NULL) {
+ printf("failed to decode espsecret: %s\n",
+ espsecret);
+ /* set to NONE transform */
+ espsecret_xform = esp_xforms;
+ }
+
+ len = colon - espsecret;
+ xf = esp_xforms;
+ while(xf->name && strncasecmp(espsecret, xf->name, len)!=0) {
+ xf++;
+ }
+ if(xf->name == NULL) {
+ printf("failed to find cipher algo %s\n",
+ espsecret);
+ espsecret_xform = esp_xforms;
+ return;
+ }
+ espsecret_xform = xf;
+
+ colon++;
+ if(colon[0]=='0' && colon[1]=='x') {
+ /* decode some hex! */
+ colon+=2;
+ len = strlen(colon) / 2;
+ espsecret_key = (char *)malloc(len);
+ if(espsecret_key == NULL) {
+ fprintf(stderr, "%s: ran out of memory (%d) to allocate secret key\n",
+ program_name, len);
+ exit(2);
+ }
+ i = 0;
+ while(colon[0] != '\0' && colon[1]!='\0') {
+ espsecret_key[i]=hex2byte(colon);
+ colon+=2;
+ i++;
+ }
+ } else {
+ espsecret_key = colon;
+ }
+}
-void
-esp_print(register const u_char *bp, int length, register const u_char *bp2)
+int
+esp_print(register const u_char *bp, register const u_char *bp2,
+ int *nhdr, int *padlen)
{
- register const struct ip *ip;
- register const u_char *cp, *nh;
- u_short ahlen, authlen;
- u_long spi, seqno;
+ register const struct esp *esp;
+ register const u_char *ep;
+ u_int32_t spi;
+ struct ip *ip = NULL;
+#ifdef INET6
+ struct ip6_hdr *ip6 = NULL;
+#endif
+ int advance;
+ int len;
+ char *secret;
+ int ivlen = 0;
+ u_char *ivoff;
+#ifdef HAVE_LIBCRYPTO
+ u_char *p;
+#endif
+
+ esp = (struct esp *)bp;
+ spi = (u_int32_t)ntohl(esp->esp_spi);
+ secret = NULL;
+
+#if 0
+ /* keep secret out of a register */
+ p = (u_char *)&secret;
+#endif
+
+ /* 'ep' points to the end of available data. */
+ ep = snapend;
+
+ if ((u_char *)(esp + 1) >= ep - sizeof(struct esp)) {
+ fputs("[|ESP]", stdout);
+ goto fail;
+ }
+ printf("ESP(spi=0x%08x", spi);
+ printf(",seq=0x%x", (u_int32_t)ntohl(*(u_int32_t *)(esp + 1)));
+ printf(")");
+
+ /* if we don't have decryption key, we can't decrypt this packet. */
+ if (!espsecret)
+ goto fail;
+
+ if(!espsecret_xform) {
+ esp_print_decodesecret();
+ }
+ if(espsecret_xform->algo == NONE) {
+ goto fail;
+ }
+
+ ip = (struct ip *)bp2;
+ switch (IP_V(ip)) {
+#ifdef INET6
+ case 6:
+ ip6 = (struct ip6_hdr *)bp2;
+ ip = NULL;
+ /* we do not attempt to decrypt jumbograms */
+ if (!ntohs(ip6->ip6_plen))
+ goto fail;
+ /* if we can't get nexthdr, we do not need to decrypt it */
+ len = sizeof(struct ip6_hdr) + ntohs(ip6->ip6_plen);
+ break;
+#endif /*INET6*/
+ case 4:
+ /* nexthdr & padding are in the last fragment */
+ if (ntohs(ip->ip_off) & IP_MF)
+ goto fail;
+#ifdef INET6
+ ip6 = NULL;
+#endif
+ len = ntohs(ip->ip_len);
+ break;
+ default:
+ goto fail;
+ }
+
+ /* if we can't get nexthdr, we do not need to decrypt it */
+ if (ep - bp2 < len)
+ goto fail;
+
+ ivoff = (u_char *)(esp + 1) + espsecret_xform->replaysize;
+ ivlen = espsecret_xform->ivlen;
+ secret = espsecret_key;
+
+ switch (espsecret_xform->algo) {
+ case DESCBC:
+#ifdef HAVE_LIBCRYPTO
+ {
+ u_char iv[8];
+ des_key_schedule schedule;
+
+ switch (ivlen) {
+ case 4:
+ memcpy(iv, ivoff, 4);
+ memcpy(&iv[4], ivoff, 4);
+ p = &iv[4];
+ *p++ ^= 0xff;
+ *p++ ^= 0xff;
+ *p++ ^= 0xff;
+ *p++ ^= 0xff;
+ break;
+ case 8:
+ memcpy(iv, ivoff, 8);
+ break;
+ default:
+ goto fail;
+ }
+
+ des_check_key = 0;
+ des_set_key((void *)secret, schedule);
+
+ p = ivoff + ivlen;
+ des_cbc_encrypt((void *)p, (void *)p,
+ (long)(ep - p), schedule, (void *)iv,
+ DES_DECRYPT);
+ advance = ivoff - (u_char *)esp + ivlen;
+ break;
+ }
+#else
+ goto fail;
+#endif /*HAVE_LIBCRYPTO*/
+
+ case BLOWFISH:
+#ifdef HAVE_LIBCRYPTO
+ {
+ BF_KEY schedule;
+
+ BF_set_key(&schedule, strlen(secret), secret);
+
+ p = ivoff + ivlen;
+ BF_cbc_encrypt(p, p, (long)(ep - p), &schedule, ivoff,
+ BF_DECRYPT);
+ advance = ivoff - (u_char *)esp + ivlen;
+ break;
+ }
+#else
+ goto fail;
+#endif /*HAVE_LIBCRYPTO*/
+
+ case RC5:
+#if defined(HAVE_LIBCRYPTO) && defined(HAVE_RC5_H)
+ {
+ RC5_32_KEY schedule;
+
+ RC5_32_set_key(&schedule, strlen(secret), secret,
+ RC5_16_ROUNDS);
+
+ p = ivoff + ivlen;
+ RC5_32_cbc_encrypt(p, p, (long)(ep - p), &schedule, ivoff,
+ RC5_DECRYPT);
+ advance = ivoff - (u_char *)esp + ivlen;
+ break;
+ }
+#else
+ goto fail;
+#endif /*HAVE_LIBCRYPTO*/
+
+ case CAST128:
+#if defined(HAVE_LIBCRYPTO) && defined(HAVE_CAST_H) && !defined(HAVE_BUGGY_CAST128)
+ {
+ CAST_KEY schedule;
+
+ CAST_set_key(&schedule, strlen(secret), secret);
+
+ p = ivoff + ivlen;
+ CAST_cbc_encrypt(p, p, (long)(ep - p), &schedule, ivoff,
+ CAST_DECRYPT);
+ advance = ivoff - (u_char *)esp + ivlen;
+ break;
+ }
+#else
+ goto fail;
+#endif /*HAVE_LIBCRYPTO*/
+
+ case DES3CBC:
+#if defined(HAVE_LIBCRYPTO)
+ {
+ des_key_schedule s1, s2, s3;
+
+ des_check_key = 1;
+ des_set_odd_parity((void *)secret);
+ des_set_odd_parity((void *)(secret + 8));
+ des_set_odd_parity((void *)(secret + 16));
+ if(des_set_key((void *)secret, s1) != 0) {
+ printf("failed to schedule key 1\n");
+ }
+ if(des_set_key((void *)(secret + 8), s2)!=0) {
+ printf("failed to schedule key 2\n");
+ }
+ if(des_set_key((void *)(secret + 16), s3)!=0) {
+ printf("failed to schedule key 3\n");
+ }
- ip = (struct ip *)bp2;
+ p = ivoff + ivlen;
+ des_ede3_cbc_encrypt((void *)p, (void *)p,
+ (long)(ep - p),
+ s1, s2, s3,
+ (void *)ivoff, DES_DECRYPT);
+ advance = ivoff - (u_char *)esp + ivlen;
+ break;
+ }
+#else
+ goto fail;
+#endif /*HAVE_LIBCRYPTO*/
- (void)printf("ESP %s > %s\n\t\t",
- ipaddr_string(&ip->ip_src),
- ipaddr_string(&ip->ip_dst));
+ case NONE:
+ default:
+ advance = sizeof(struct esp) + espsecret_xform->replaysize;
+ break;
+ }
- if (length < 8) {
- (void)printf(" [|esp] truncated-esp %d", length);
- return;
- }
+ ep = ep - espsecret_xform->authlen;
+ /* sanity check for pad length */
+ if (ep - bp < *(ep - 2))
+ goto fail;
- spi = ntohl(*((u_long *)(bp)));
- seqno = ntohl(*((u_long *)(bp+4)));
+ if (padlen)
+ *padlen = *(ep - 2) + 2;
- nh = bp+ahlen;
+ if (nhdr)
+ *nhdr = *(ep - 1);
- (void)printf("spi:%08x seqno:%d ciphertext: ", spi, seqno);
- (void)default_print_unaligned(bp+8, length-8);
+ printf(": ");
+ return advance;
- /* XXX it would be nice to decrypt! */
+fail:
+ if (nhdr)
+ *nhdr = -1;
+ return 65536;
}