print-esp.c revision 147900
137446Srnordier/*	$NetBSD: print-ah.c,v 1.4 1996/05/20 00:41:16 fvdl Exp $	*/
237446Srnordier
337446Srnordier/*
437446Srnordier * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994
537446Srnordier *	The Regents of the University of California.  All rights reserved.
637446Srnordier *
737446Srnordier * Redistribution and use in source and binary forms, with or without
837446Srnordier * modification, are permitted provided that: (1) source code distributions
937446Srnordier * retain the above copyright notice and this paragraph in its entirety, (2)
1037446Srnordier * distributions including binary code include the above copyright notice and
1137446Srnordier * this paragraph in its entirety in the documentation or other materials
1237446Srnordier * provided with the distribution, and (3) all advertising materials mentioning
1337446Srnordier * features or use of this software display the following acknowledgement:
1437446Srnordier * ``This product includes software developed by the University of California,
1537446Srnordier * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
1637446Srnordier * the University nor the names of its contributors may be used to endorse
1737446Srnordier * or promote products derived from this software without specific prior
1837446Srnordier * written permission.
1937446Srnordier * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
2037446Srnordier * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
2137446Srnordier * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
2237446Srnordier */
2337446Srnordier
2437446Srnordier#ifndef lint
2537446Srnordierstatic const char rcsid[] _U_ =
2637446Srnordier    "@(#) $Header: /tcpdump/master/tcpdump/print-esp.c,v 1.55.2.1 2005/04/21 06:44:57 guy Exp $ (LBL)";
2737446Srnordier#endif
2837446Srnordier
2937446Srnordier#ifdef HAVE_CONFIG_H
3050476Speter#include "config.h"
3137446Srnordier#endif
3237446Srnordier
3337446Srnordier#include <string.h>
34106372Sscottl
35106372Sscottl#include <tcpdump-stdinc.h>
3637446Srnordier
3737446Srnordier#include <stdlib.h>
3866907Swollman
3966907Swollman#ifdef HAVE_LIBCRYPTO
4037446Srnordier#ifdef HAVE_OPENSSL_EVP_H
4137446Srnordier#include <openssl/evp.h>
4237446Srnordier#endif
4337446Srnordier#endif
4437446Srnordier
45185594Smlaier#include <stdio.h>
4637446Srnordier
47223945Sae#include "ip.h"
4837446Srnordier#include "esp.h"
4937446Srnordier#ifdef INET6
5037446Srnordier#include "ip6.h"
5166907Swollman#endif
5237446Srnordier
5337446Srnordier#include "netdissect.h"
5437446Srnordier#include "addrtoname.h"
5537446Srnordier#include "extract.h"
5637446Srnordier
5737446Srnordier#ifndef HAVE_SOCKADDR_STORAGE
5837446Srnordier#ifdef INET6
59170166Strhodesstruct sockaddr_storage {
6037446Srnordier	union {
6137446Srnordier		struct sockaddr_in sin;
6237446Srnordier		struct sockaddr_in6 sin6;
6337446Srnordier	} un;
6437446Srnordier};
6537446Srnordier#else
66203868Skib#define sockaddr_storage sockaddr
67203868Skib#endif
68203868Skib#endif /* HAVE_SOCKADDR_STORAGE */
69229550Spfg
70203868Skib#ifdef HAVE_LIBCRYPTO
71203868Skibstruct sa_list {
7237446Srnordier	struct sa_list	*next;
7337446Srnordier	struct sockaddr_storage daddr;
7437446Srnordier	u_int32_t	spi;
7537446Srnordier	const EVP_CIPHER *evp;
7637446Srnordier	int		ivlen;
7737446Srnordier	int		authlen;
7837446Srnordier	u_char		secret[256];  /* is that big enough for all secrets? */
7937446Srnordier	int		secretlen;
8037446Srnordier};
8137446Srnordier
8237446Srnordierstatic void esp_print_addsa(netdissect_options *ndo,
8337446Srnordier			    struct sa_list *sa, int sa_def)
8437446Srnordier{
8537446Srnordier	/* copy the "sa" */
8637446Srnordier
8737446Srnordier	struct sa_list *nsa;
8837446Srnordier
8937446Srnordier	nsa = (struct sa_list *)malloc(sizeof(struct sa_list));
9037446Srnordier	if (nsa == NULL)
9137446Srnordier		(*ndo->ndo_error)(ndo, "ran out of memory to allocate sa structure");
9237446Srnordier
9337446Srnordier	*nsa = *sa;
9437446Srnordier
9537446Srnordier	if (sa_def)
9637446Srnordier		ndo->ndo_sa_default = nsa;
9737446Srnordier
9837446Srnordier	nsa->next = ndo->ndo_sa_list_head;
9937446Srnordier	ndo->ndo_sa_list_head = nsa;
100229550Spfg}
101203869Skib
102231162Sdelphij
10337446Srnordierstatic u_int hexdigit(netdissect_options *ndo, char hex)
10437446Srnordier{
105203869Skib	if (hex >= '0' && hex <= '9')
106203869Skib		return (hex - '0');
107203869Skib	else if (hex >= 'A' && hex <= 'F')
108203869Skib		return (hex - 'A' + 10);
109203869Skib	else if (hex >= 'a' && hex <= 'f')
110203869Skib		return (hex - 'a' + 10);
111203869Skib	else {
112203869Skib		(*ndo->ndo_error)(ndo, "invalid hex digit %c in espsecret\n", hex);
113203869Skib		return 0;
114203869Skib	}
115203869Skib}
116203869Skib
117231162Sdelphijstatic u_int hex2byte(netdissect_options *ndo, char *hexstring)
11837446Srnordier{
11937446Srnordier	u_int byte;
120203869Skib
121203869Skib	byte = (hexdigit(ndo, hexstring[0]) << 4) + hexdigit(ndo, hexstring[1]);
122203869Skib	return byte;
123203869Skib}
124203869Skib
125203869Skib/*
126229550Spfg * decode the form:    SPINUM@IP <tab> ALGONAME:0xsecret
127231162Sdelphij *
12837446Srnordier * special form: file /name
12937446Srnordier * causes us to go read from this file instead.
130203869Skib *
131203869Skib */
132203869Skibstatic void esp_print_decode_onesecret(netdissect_options *ndo, char *line)
133203869Skib{
134203869Skib	struct sa_list sa1;
135203869Skib	int sa_def;
136231162Sdelphij
13737446Srnordier	char *spikey;
13837446Srnordier	char *decode;
139229550Spfg
140229550Spfg	spikey = strsep(&line, " \t");
141229550Spfg	sa_def = 0;
142229550Spfg	memset(&sa1, 0, sizeof(struct sa_list));
143229550Spfg
144229550Spfg	/* if there is only one token, then it is an algo:key token */
145229550Spfg	if (line == NULL) {
146231162Sdelphij		decode = spikey;
14737446Srnordier		spikey = NULL;
14837446Srnordier		/* memset(&sa1.daddr, 0, sizeof(sa1.daddr)); */
149203869Skib		/* sa1.spi = 0; */
150203869Skib		sa_def    = 1;
151203869Skib	} else
152203869Skib		decode = line;
153203869Skib
154203869Skib	if (spikey && strcasecmp(spikey, "file") == 0) {
155203869Skib		/* open file and read it */
156203869Skib		FILE *secretfile;
157203869Skib		char  fileline[1024];
158203869Skib		char  *nl;
159203869Skib
160203869Skib		secretfile = fopen(line, FOPEN_READ_TXT);
161203869Skib		if (secretfile == NULL) {
162203869Skib			perror(line);
163229550Spfg			exit(3);
164229550Spfg		}
16537446Srnordier
16637446Srnordier		while (fgets(fileline, sizeof(fileline)-1, secretfile) != NULL) {
167140384Sdelphij			/* remove newline from the line */
168140384Sdelphij			nl = strchr(fileline, '\n');
16937446Srnordier			if (nl)
17037446Srnordier				*nl = '\0';
17137446Srnordier			if (fileline[0] == '#') continue;
172190927Sed			if (fileline[0] == '\0') continue;
173229550Spfg
174229550Spfg			esp_print_decode_onesecret(ndo, fileline);
175229550Spfg		}
176229550Spfg		fclose(secretfile);
177229550Spfg
178229550Spfg		return;
179229550Spfg	}
180229550Spfg
181229550Spfg	if (spikey) {
182229550Spfg		char *spistr, *foo;
18337446Srnordier		u_int32_t spino;
18437446Srnordier		struct sockaddr_in *sin;
185190927Sed#ifdef INET6
18637446Srnordier		struct sockaddr_in6 *sin6;
18737446Srnordier#endif
18837446Srnordier
18937446Srnordier		spistr = strsep(&spikey, "@");
19037446Srnordier
19137446Srnordier		spino = strtoul(spistr, &foo, 0);
19237446Srnordier		if (spistr == foo || !spikey) {
19337446Srnordier			(*ndo->ndo_warning)(ndo, "print_esp: failed to decode spi# %s\n", foo);
19437446Srnordier			return;
19537446Srnordier		}
19637446Srnordier
19737446Srnordier		sa1.spi = spino;
19837446Srnordier
19937446Srnordier		sin = (struct sockaddr_in *)&sa1.daddr;
20037446Srnordier#ifdef INET6
20137446Srnordier		sin6 = (struct sockaddr_in6 *)&sa1.daddr;
20237446Srnordier		if (inet_pton(AF_INET6, spikey, &sin6->sin6_addr) == 1) {
20337446Srnordier#ifdef HAVE_SOCKADDR_SA_LEN
20437446Srnordier			sin6->sin6_len = sizeof(struct sockaddr_in6);
20537446Srnordier#endif
20637446Srnordier			sin6->sin6_family = AF_INET6;
20737446Srnordier		} else
20837446Srnordier#endif
20937446Srnordier		if (inet_pton(AF_INET, spikey, &sin->sin_addr) == 1) {
21037446Srnordier#ifdef HAVE_SOCKADDR_SA_LEN
21137446Srnordier			sin->sin_len = sizeof(struct sockaddr_in);
21237446Srnordier#endif
21337446Srnordier			sin->sin_family = AF_INET;
21437446Srnordier		} else {
21537446Srnordier			(*ndo->ndo_warning)(ndo, "print_esp: can not decode IP# %s\n", spikey);
21637446Srnordier			return;
217223945Sae		}
218223945Sae	}
219223945Sae
22037446Srnordier	if (decode) {
22137446Srnordier		char *colon, *p;
22237446Srnordier		u_char espsecret_key[256];
22337446Srnordier		int len;
22437446Srnordier		size_t i;
22537446Srnordier		const EVP_CIPHER *evp;
22637446Srnordier		int authlen = 0;
227185587Sluigi
22837446Srnordier		/* skip any blank spaces */
22937446Srnordier		while (isspace((unsigned char)*decode))
23037446Srnordier			decode++;
23137446Srnordier
23237446Srnordier		colon = strchr(decode, ':');
23337446Srnordier		if (colon == NULL) {
234102231Strhodes			(*ndo->ndo_warning)(ndo, "failed to decode espsecret: %s\n", decode);
23537446Srnordier			return;
23637446Srnordier		}
23737446Srnordier		*colon = '\0';
23837446Srnordier
239190927Sed		len = colon - decode;
240190927Sed		if (strlen(decode) > strlen("-hmac96") &&
241190927Sed		    !strcmp(decode + strlen(decode) - strlen("-hmac96"),
242190927Sed		    "-hmac96")) {
243190927Sed			p = strstr(decode, "-hmac96");
244190927Sed			*p = '\0';
245190927Sed			authlen = 12;
24637446Srnordier		}
247223945Sae		if (strlen(decode) > strlen("-cbc") &&
24837446Srnordier		    !strcmp(decode + strlen(decode) - strlen("-cbc"), "-cbc")) {
24937446Srnordier			p = strstr(decode, "-cbc");
25037446Srnordier			*p = '\0';
25137446Srnordier		}
25237446Srnordier		evp = EVP_get_cipherbyname(decode);
25337446Srnordier		if (!evp) {
25437446Srnordier			(*ndo->ndo_warning)(ndo, "failed to find cipher algo %s\n", decode);
25537446Srnordier			sa1.evp = NULL;
25637446Srnordier			sa1.authlen = 0;
25737446Srnordier			sa1.ivlen = 0;
25837446Srnordier			return;
25937446Srnordier		}
26040487Sbde
26137446Srnordier		sa1.evp = evp;
26237446Srnordier		sa1.authlen = authlen;
263190927Sed		sa1.ivlen = EVP_CIPHER_iv_length(evp);
26437446Srnordier
26537446Srnordier		colon++;
26637446Srnordier		if (colon[0] == '0' && colon[1] == 'x') {
267185587Sluigi			/* decode some hex! */
268185587Sluigi			colon += 2;
269185587Sluigi			len = strlen(colon) / 2;
27037446Srnordier
27137446Srnordier			if (len > 256) {
27237446Srnordier				(*ndo->ndo_warning)(ndo, "secret is too big: %d\n", len);
27337446Srnordier				return;
27437446Srnordier			}
27537446Srnordier
276185587Sluigi			i = 0;
277185587Sluigi			while (colon[0] != '\0' && colon[1]!='\0') {
278185587Sluigi				espsecret_key[i] = hex2byte(ndo, colon);
27937446Srnordier				colon += 2;
28037446Srnordier				i++;
28137446Srnordier			}
28237446Srnordier
28337446Srnordier			memcpy(sa1.secret, espsecret_key, i);
28437446Srnordier			sa1.secretlen = i;
28537446Srnordier		} else {
28637446Srnordier			i = strlen(colon);
28737446Srnordier
28837446Srnordier			if (i < sizeof(sa1.secret)) {
28937446Srnordier				memcpy(sa1.secret, colon, i);
29037446Srnordier				sa1.secretlen = i;
29137446Srnordier			} else {
29237446Srnordier				memcpy(sa1.secret, colon, sizeof(sa1.secret));
29337446Srnordier				sa1.secretlen = sizeof(sa1.secret);
29437446Srnordier			}
29537446Srnordier		}
29637446Srnordier	}
29737446Srnordier
29837446Srnordier	esp_print_addsa(ndo, &sa1, sa_def);
29937446Srnordier}
30037446Srnordier
30137446Srnordierstatic void esp_print_decodesecret(netdissect_options *ndo)
30237446Srnordier{
30337446Srnordier	char *line;
30437446Srnordier	char *p;
30537446Srnordier
30637446Srnordier	p = ndo->ndo_espsecret;
30737446Srnordier
30837446Srnordier	while (ndo->ndo_espsecret && ndo->ndo_espsecret[0] != '\0') {
30937446Srnordier		/* pick out the first line or first thing until a comma */
31037446Srnordier		if ((line = strsep(&ndo->ndo_espsecret, "\n,")) == NULL) {
31137446Srnordier			line = ndo->ndo_espsecret;
31237446Srnordier			ndo->ndo_espsecret = NULL;
31337446Srnordier		}
31437446Srnordier
31537446Srnordier		esp_print_decode_onesecret(ndo, line);
31637446Srnordier	}
31737446Srnordier}
31837446Srnordier
31937446Srnordierstatic void esp_init(netdissect_options *ndo _U_)
32037446Srnordier{
32137446Srnordier
32237446Srnordier	OpenSSL_add_all_algorithms();
32337446Srnordier	EVP_add_cipher_alias(SN_des_ede3_cbc, "3des");
32437446Srnordier}
32537446Srnordier#endif
32637446Srnordier
32737446Srnordierint
32837446Srnordieresp_print(netdissect_options *ndo,
32937446Srnordier	  const u_char *bp, const int length, const u_char *bp2
33037446Srnordier#ifndef HAVE_LIBCRYPTO
33137446Srnordier	_U_
33237446Srnordier#endif
33337446Srnordier	,
33437446Srnordier	int *nhdr
33537446Srnordier#ifndef HAVE_LIBCRYPTO
33637446Srnordier	_U_
33737446Srnordier#endif
33837446Srnordier	,
33937446Srnordier	int *padlen
34037446Srnordier#ifndef HAVE_LIBCRYPTO
34137446Srnordier	_U_
34237446Srnordier#endif
34337446Srnordier	)
344102231Strhodes{
34537446Srnordier	register const struct newesp *esp;
34637446Srnordier	register const u_char *ep;
34737446Srnordier#ifdef HAVE_LIBCRYPTO
34837446Srnordier	struct ip *ip;
34937446Srnordier	struct sa_list *sa = NULL;
35037446Srnordier	int espsecret_keylen;
35137446Srnordier#ifdef INET6
35237446Srnordier	struct ip6_hdr *ip6 = NULL;
35337446Srnordier#endif
35437446Srnordier	int advance;
35537446Srnordier	int len;
35637446Srnordier	u_char *secret;
357190932Sed	int ivlen = 0;
35863892Sasmodai	u_char *ivoff;
35937446Srnordier	u_char *p;
36037446Srnordier	EVP_CIPHER_CTX ctx;
36137446Srnordier	int blocksz;
36237446Srnordier	static int initialized = 0;
363185587Sluigi#endif
364185587Sluigi
365185587Sluigi	esp = (struct newesp *)bp;
366185587Sluigi
367185587Sluigi#ifdef HAVE_LIBCRYPTO
368185587Sluigi	secret = NULL;
369190929Sed	advance = 0;
370185594Smlaier
371190930Sed	if (!initialized) {
37237446Srnordier		esp_init(ndo);
373190930Sed		initialized = 1;
374190930Sed	}
375190931Sed#endif
376190931Sed
377190931Sed#if 0
378190931Sed	/* keep secret out of a register */
379190931Sed	p = (u_char *)&secret;
380190931Sed#endif
381190931Sed
38237446Srnordier	/* 'ep' points to the end of available data. */
38337446Srnordier	ep = ndo->ndo_snapend;
384185587Sluigi
385185594Smlaier	if ((u_char *)(esp + 1) >= ep) {
38637446Srnordier		fputs("[|ESP]", stdout);
38737446Srnordier		goto fail;
38837446Srnordier	}
389203869Skib	(*ndo->ndo_printf)(ndo, "ESP(spi=0x%08x", EXTRACT_32BITS(&esp->esp_spi));
390203869Skib	(*ndo->ndo_printf)(ndo, ",seq=0x%x)", EXTRACT_32BITS(&esp->esp_seq));
391203869Skib        (*ndo->ndo_printf)(ndo, ", length %u", length);
392203869Skib
39337446Srnordier#ifndef HAVE_LIBCRYPTO
39437446Srnordier	goto fail;
395203869Skib#else
39637446Srnordier	/* initiailize SAs */
397203869Skib	if (ndo->ndo_sa_list_head == NULL) {
39837446Srnordier		if (!ndo->ndo_espsecret)
399203869Skib			goto fail;
40037446Srnordier
401203869Skib		esp_print_decodesecret(ndo);
40237446Srnordier	}
403203869Skib
404185587Sluigi	if (ndo->ndo_sa_list_head == NULL)
405185587Sluigi		goto fail;
40637446Srnordier
407203869Skib	ip = (struct ip *)bp2;
408203869Skib	switch (IP_V(ip)) {
409185587Sluigi#ifdef INET6
410185587Sluigi	case 6:
411203869Skib		ip6 = (struct ip6_hdr *)bp2;
412203869Skib		/* we do not attempt to decrypt jumbograms */
413185587Sluigi		if (!EXTRACT_16BITS(&ip6->ip6_plen))
414203869Skib			goto fail;
415203869Skib		/* if we can't get nexthdr, we do not need to decrypt it */
416203869Skib		len = sizeof(struct ip6_hdr) + EXTRACT_16BITS(&ip6->ip6_plen);
417203869Skib
418203869Skib		/* see if we can find the SA, and if so, decode it */
419203869Skib		for (sa = ndo->ndo_sa_list_head; sa != NULL; sa = sa->next) {
420203869Skib			struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&sa->daddr;
421203869Skib			if (sa->spi == ntohl(esp->esp_spi) &&
422203869Skib			    sin6->sin6_family == AF_INET6 &&
423185587Sluigi			    memcmp(&sin6->sin6_addr, &ip6->ip6_dst,
424203869Skib				   sizeof(struct in6_addr)) == 0) {
425185587Sluigi				break;
426185587Sluigi			}
427203869Skib		}
428203869Skib		break;
429203869Skib#endif /*INET6*/
43037446Srnordier	case 4:
431203869Skib		/* nexthdr & padding are in the last fragment */
43248954Sbillf		if (EXTRACT_16BITS(&ip->ip_off) & IP_MF)
43337446Srnordier			goto fail;
43437446Srnordier		len = EXTRACT_16BITS(&ip->ip_len);
43537446Srnordier
43637446Srnordier		/* see if we can find the SA, and if so, decode it */
43748954Sbillf		for (sa = ndo->ndo_sa_list_head; sa != NULL; sa = sa->next) {
43837446Srnordier			struct sockaddr_in *sin = (struct sockaddr_in *)&sa->daddr;
43937446Srnordier			if (sa->spi == ntohl(esp->esp_spi) &&
44037446Srnordier			    sin->sin_family == AF_INET &&
44137446Srnordier			    sin->sin_addr.s_addr == ip->ip_dst.s_addr) {
44237446Srnordier				break;
443203869Skib			}
44437446Srnordier		}
44537446Srnordier		break;
44637446Srnordier	default:
447203869Skib		goto fail;
44837446Srnordier	}
449203869Skib
450203869Skib	/* if we didn't find the specific one, then look for
45137446Srnordier	 * an unspecified one.
452203869Skib	 */
453203869Skib	if (sa == NULL)
45437446Srnordier		sa = ndo->ndo_sa_default;
45537446Srnordier
45637446Srnordier	/* if not found fail */
45737446Srnordier	if (sa == NULL)
458203869Skib		goto fail;
45937446Srnordier
46037446Srnordier	/* if we can't get nexthdr, we do not need to decrypt it */
461203869Skib	if (ep - bp2 < len)
46237446Srnordier		goto fail;
46337446Srnordier	if (ep - bp2 > len) {
46437446Srnordier		/* FCS included at end of frame (NetBSD 1.6 or later) */
46537446Srnordier		ep = bp2 + len;
466203869Skib	}
46737446Srnordier
46837446Srnordier	ivoff = (u_char *)(esp + 1) + 0;
469203869Skib	ivlen = sa->ivlen;
47037446Srnordier	secret = sa->secret;
47137446Srnordier	espsecret_keylen = sa->secretlen;
47241586Srnordier	ep = ep - sa->authlen;
473203869Skib
47437446Srnordier	if (sa->evp) {
47537446Srnordier		memset(&ctx, 0, sizeof(ctx));
476203869Skib		if (EVP_CipherInit(&ctx, sa->evp, secret, NULL, 0) < 0)
47737446Srnordier			(*ndo->ndo_warning)(ndo, "espkey init failed");
478203869Skib
47937446Srnordier		blocksz = EVP_CIPHER_CTX_block_size(&ctx);
480203869Skib
48137446Srnordier		p = ivoff;
48237446Srnordier		EVP_CipherInit(&ctx, NULL, NULL, p, 0);
48337446Srnordier		EVP_Cipher(&ctx, p + ivlen, p + ivlen, ep - (p + ivlen));
48437446Srnordier		advance = ivoff - (u_char *)esp + ivlen;
48537446Srnordier	} else
48637446Srnordier		advance = sizeof(struct newesp);
48742261Sjkh
48837446Srnordier	/* sanity check for pad length */
48937446Srnordier	if (ep - bp < *(ep - 2))
49037446Srnordier		goto fail;
49137446Srnordier
49237446Srnordier	if (padlen)
493203869Skib		*padlen = *(ep - 2) + 2;
494229550Spfg
495229550Spfg	if (nhdr)
49637446Srnordier		*nhdr = *(ep - 1);
497203869Skib
49837446Srnordier	(ndo->ndo_printf)(ndo, ": ");
499203869Skib	return advance;
500203869Skib#endif
50148954Sbillf
502203869Skibfail:
503203869Skib	return -1;
504229550Spfg}
505229550Spfg
506203869Skib/*
507203869Skib * Local Variables:
508203869Skib * c-style: whitesmith
509203869Skib * c-basic-offset: 8
510229550Spfg * End:
511229550Spfg */
51237446Srnordier