print-esp.c revision 225736
1/*	$NetBSD: print-ah.c,v 1.4 1996/05/20 00:41:16 fvdl Exp $	*/
2
3/*
4 * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994
5 *	The Regents of the University of California.  All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that: (1) source code distributions
9 * retain the above copyright notice and this paragraph in its entirety, (2)
10 * distributions including binary code include the above copyright notice and
11 * this paragraph in its entirety in the documentation or other materials
12 * provided with the distribution, and (3) all advertising materials mentioning
13 * features or use of this software display the following acknowledgement:
14 * ``This product includes software developed by the University of California,
15 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
16 * the University nor the names of its contributors may be used to endorse
17 * or promote products derived from this software without specific prior
18 * written permission.
19 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
20 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
21 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
22 */
23
24#ifndef lint
25static const char rcsid[] _U_ =
26    "@(#) $Header: /tcpdump/master/tcpdump/print-esp.c,v 1.58 2007-12-07 00:03:07 mcr Exp $ (LBL)";
27#endif
28
29#ifdef HAVE_CONFIG_H
30#include "config.h"
31#endif
32
33#include <string.h>
34
35#include <tcpdump-stdinc.h>
36
37#include <stdlib.h>
38
39#ifdef HAVE_LIBCRYPTO
40#ifdef HAVE_OPENSSL_EVP_H
41#include <openssl/evp.h>
42#endif
43#endif
44
45#include <stdio.h>
46
47#include "ip.h"
48#include "esp.h"
49#ifdef INET6
50#include "ip6.h"
51#endif
52
53#include "netdissect.h"
54#include "addrtoname.h"
55#include "extract.h"
56
57#ifndef HAVE_SOCKADDR_STORAGE
58#ifdef INET6
59struct sockaddr_storage {
60	union {
61		struct sockaddr_in sin;
62		struct sockaddr_in6 sin6;
63	} un;
64};
65#else
66#define sockaddr_storage sockaddr
67#endif
68#endif /* HAVE_SOCKADDR_STORAGE */
69
70#ifdef HAVE_LIBCRYPTO
71struct sa_list {
72	struct sa_list	*next;
73	struct sockaddr_storage daddr;
74	u_int32_t	spi;          /* if == 0, then IKEv2 */
75	int             initiator;
76	u_char          spii[8];      /* for IKEv2 */
77	u_char          spir[8];
78	const EVP_CIPHER *evp;
79	int		ivlen;
80	int		authlen;
81	u_char          authsecret[256];
82	int             authsecret_len;
83	u_char		secret[256];  /* is that big enough for all secrets? */
84	int		secretlen;
85};
86
87/*
88 * this will adjust ndo_packetp and ndo_snapend to new buffer!
89 */
90int esp_print_decrypt_buffer_by_ikev2(netdissect_options *ndo,
91				      int initiator,
92				      u_char spii[8], u_char spir[8],
93				      u_char *buf, u_char *end)
94{
95	struct sa_list *sa;
96	u_char *iv;
97	int len;
98	EVP_CIPHER_CTX ctx;
99
100	/* initiator arg is any non-zero value */
101	if(initiator) initiator=1;
102
103	/* see if we can find the SA, and if so, decode it */
104	for (sa = ndo->ndo_sa_list_head; sa != NULL; sa = sa->next) {
105		if (sa->spi == 0
106		    && initiator == sa->initiator
107		    && memcmp(spii, sa->spii, 8) == 0
108		    && memcmp(spir, sa->spir, 8) == 0)
109			break;
110	}
111
112	if(sa == NULL) return 0;
113	if(sa->evp == NULL) return 0;
114
115	/*
116	 * remove authenticator, and see if we still have something to
117	 * work with
118	 */
119	end = end - sa->authlen;
120	iv  = buf;
121	buf = buf + sa->ivlen;
122	len = end-buf;
123
124	if(end <= buf) return 0;
125
126	memset(&ctx, 0, sizeof(ctx));
127	if (EVP_CipherInit(&ctx, sa->evp, sa->secret, NULL, 0) < 0)
128		(*ndo->ndo_warning)(ndo, "espkey init failed");
129	EVP_CipherInit(&ctx, NULL, NULL, iv, 0);
130	EVP_Cipher(&ctx, buf, buf, len);
131	EVP_CIPHER_CTX_cleanup(&ctx);
132
133	ndo->ndo_packetp = buf;
134	ndo->ndo_snapend = end;
135
136	return 1;
137
138}
139
140static void esp_print_addsa(netdissect_options *ndo,
141			    struct sa_list *sa, int sa_def)
142{
143	/* copy the "sa" */
144
145	struct sa_list *nsa;
146
147	nsa = (struct sa_list *)malloc(sizeof(struct sa_list));
148	if (nsa == NULL)
149		(*ndo->ndo_error)(ndo, "ran out of memory to allocate sa structure");
150
151	*nsa = *sa;
152
153	if (sa_def)
154		ndo->ndo_sa_default = nsa;
155
156	nsa->next = ndo->ndo_sa_list_head;
157	ndo->ndo_sa_list_head = nsa;
158}
159
160
161static u_int hexdigit(netdissect_options *ndo, char hex)
162{
163	if (hex >= '0' && hex <= '9')
164		return (hex - '0');
165	else if (hex >= 'A' && hex <= 'F')
166		return (hex - 'A' + 10);
167	else if (hex >= 'a' && hex <= 'f')
168		return (hex - 'a' + 10);
169	else {
170		(*ndo->ndo_error)(ndo, "invalid hex digit %c in espsecret\n", hex);
171		return 0;
172	}
173}
174
175static u_int hex2byte(netdissect_options *ndo, char *hexstring)
176{
177	u_int byte;
178
179	byte = (hexdigit(ndo, hexstring[0]) << 4) + hexdigit(ndo, hexstring[1]);
180	return byte;
181}
182
183/*
184 * returns size of binary, 0 on failure.
185 */
186static
187int espprint_decode_hex(netdissect_options *ndo,
188			u_char *binbuf, unsigned int binbuf_len,
189			char *hex)
190{
191	unsigned int len;
192	int i;
193
194	len = strlen(hex) / 2;
195
196	if (len > binbuf_len) {
197		(*ndo->ndo_warning)(ndo, "secret is too big: %d\n", len);
198		return 0;
199	}
200
201	i = 0;
202	while (hex[0] != '\0' && hex[1]!='\0') {
203		binbuf[i] = hex2byte(ndo, hex);
204		hex += 2;
205		i++;
206	}
207
208	return i;
209}
210
211/*
212 * decode the form:    SPINUM@IP <tab> ALGONAME:0xsecret
213 */
214
215static int
216espprint_decode_encalgo(netdissect_options *ndo,
217			char *decode, struct sa_list *sa)
218{
219	int len;
220	size_t i;
221	const EVP_CIPHER *evp;
222	int authlen = 0;
223	char *colon, *p;
224
225	colon = strchr(decode, ':');
226	if (colon == NULL) {
227		(*ndo->ndo_warning)(ndo, "failed to decode espsecret: %s\n", decode);
228		return 0;
229	}
230	*colon = '\0';
231
232	len = colon - decode;
233	if (strlen(decode) > strlen("-hmac96") &&
234	    !strcmp(decode + strlen(decode) - strlen("-hmac96"),
235		    "-hmac96")) {
236		p = strstr(decode, "-hmac96");
237		*p = '\0';
238		authlen = 12;
239	}
240	if (strlen(decode) > strlen("-cbc") &&
241	    !strcmp(decode + strlen(decode) - strlen("-cbc"), "-cbc")) {
242		p = strstr(decode, "-cbc");
243		*p = '\0';
244	}
245	evp = EVP_get_cipherbyname(decode);
246
247	if (!evp) {
248		(*ndo->ndo_warning)(ndo, "failed to find cipher algo %s\n", decode);
249		sa->evp = NULL;
250		sa->authlen = 0;
251		sa->ivlen = 0;
252		return 0;
253	}
254
255	sa->evp = evp;
256	sa->authlen = authlen;
257	sa->ivlen = EVP_CIPHER_iv_length(evp);
258
259	colon++;
260	if (colon[0] == '0' && colon[1] == 'x') {
261		/* decode some hex! */
262
263		colon += 2;
264		sa->secretlen = espprint_decode_hex(ndo, sa->secret, sizeof(sa->secret), colon);
265		if(sa->secretlen == 0) return 0;
266	} else {
267		i = strlen(colon);
268
269		if (i < sizeof(sa->secret)) {
270			memcpy(sa->secret, colon, i);
271			sa->secretlen = i;
272		} else {
273			memcpy(sa->secret, colon, sizeof(sa->secret));
274			sa->secretlen = sizeof(sa->secret);
275		}
276	}
277
278	return 1;
279}
280
281/*
282 * for the moment, ignore the auth algorith, just hard code the authenticator
283 * length. Need to research how openssl looks up HMAC stuff.
284 */
285static int
286espprint_decode_authalgo(netdissect_options *ndo,
287			 char *decode, struct sa_list *sa)
288{
289	char *colon;
290
291	colon = strchr(decode, ':');
292	if (colon == NULL) {
293		(*ndo->ndo_warning)(ndo, "failed to decode espsecret: %s\n", decode);
294		return 0;
295	}
296	*colon = '\0';
297
298	if(strcasecmp(colon,"sha1") == 0 ||
299	   strcasecmp(colon,"md5") == 0) {
300		sa->authlen = 12;
301	}
302	return 1;
303}
304
305static void esp_print_decode_ikeline(netdissect_options *ndo, char *line,
306				     const char *file, int lineno)
307{
308	/* it's an IKEv2 secret, store it instead */
309	struct sa_list sa1;
310
311	char *init;
312	char *icookie, *rcookie;
313	int   ilen, rlen;
314	char *authkey;
315	char *enckey;
316
317	init = strsep(&line, " \t");
318	icookie = strsep(&line, " \t");
319	rcookie = strsep(&line, " \t");
320	authkey = strsep(&line, " \t");
321	enckey  = strsep(&line, " \t");
322
323	/* if any fields are missing */
324	if(!init || !icookie || !rcookie || !authkey || !enckey) {
325		(*ndo->ndo_warning)(ndo, "print_esp: failed to find all fields for ikev2 at %s:%u",
326				    file, lineno);
327
328		return;
329	}
330
331	ilen = strlen(icookie);
332	rlen = strlen(rcookie);
333
334	if((init[0]!='I' && init[0]!='R')
335	   || icookie[0]!='0' || icookie[1]!='x'
336	   || rcookie[0]!='0' || rcookie[1]!='x'
337	   || ilen!=18
338	   || rlen!=18) {
339		(*ndo->ndo_warning)(ndo, "print_esp: line %s:%u improperly formatted.",
340				    file, lineno);
341
342		(*ndo->ndo_warning)(ndo, "init=%s icookie=%s(%u) rcookie=%s(%u)",
343				    init, icookie, ilen, rcookie, rlen);
344
345		return;
346	}
347
348	sa1.spi = 0;
349	sa1.initiator = (init[0] == 'I');
350	if(espprint_decode_hex(ndo, sa1.spii, sizeof(sa1.spii), icookie+2)!=8)
351		return;
352
353	if(espprint_decode_hex(ndo, sa1.spir, sizeof(sa1.spir), rcookie+2)!=8)
354		return;
355
356	if(!espprint_decode_encalgo(ndo, enckey, &sa1)) return;
357
358	if(!espprint_decode_authalgo(ndo, authkey, &sa1)) return;
359
360	esp_print_addsa(ndo, &sa1, FALSE);
361}
362
363/*
364 *
365 * special form: file /name
366 * causes us to go read from this file instead.
367 *
368 */
369static void esp_print_decode_onesecret(netdissect_options *ndo, char *line,
370				       const char *file, int lineno)
371{
372	struct sa_list sa1;
373	int sa_def;
374
375	char *spikey;
376	char *decode;
377
378	spikey = strsep(&line, " \t");
379	sa_def = 0;
380	memset(&sa1, 0, sizeof(struct sa_list));
381
382	/* if there is only one token, then it is an algo:key token */
383	if (line == NULL) {
384		decode = spikey;
385		spikey = NULL;
386		/* memset(&sa1.daddr, 0, sizeof(sa1.daddr)); */
387		/* sa1.spi = 0; */
388		sa_def    = 1;
389	} else
390		decode = line;
391
392	if (spikey && strcasecmp(spikey, "file") == 0) {
393		/* open file and read it */
394		FILE *secretfile;
395		char  fileline[1024];
396		int   lineno=0;
397		char  *nl;
398		char *filename = line;
399
400		secretfile = fopen(filename, FOPEN_READ_TXT);
401		if (secretfile == NULL) {
402			perror(filename);
403			exit(3);
404		}
405
406		while (fgets(fileline, sizeof(fileline)-1, secretfile) != NULL) {
407			lineno++;
408			/* remove newline from the line */
409			nl = strchr(fileline, '\n');
410			if (nl)
411				*nl = '\0';
412			if (fileline[0] == '#') continue;
413			if (fileline[0] == '\0') continue;
414
415			esp_print_decode_onesecret(ndo, fileline, filename, lineno);
416		}
417		fclose(secretfile);
418
419		return;
420	}
421
422	if (spikey && strcasecmp(spikey, "ikev2") == 0) {
423		esp_print_decode_ikeline(ndo, line, file, lineno);
424		return;
425	}
426
427	if (spikey) {
428
429		char *spistr, *foo;
430		u_int32_t spino;
431		struct sockaddr_in *sin;
432#ifdef INET6
433		struct sockaddr_in6 *sin6;
434#endif
435
436		spistr = strsep(&spikey, "@");
437
438		spino = strtoul(spistr, &foo, 0);
439		if (spistr == foo || !spikey) {
440			(*ndo->ndo_warning)(ndo, "print_esp: failed to decode spi# %s\n", foo);
441			return;
442		}
443
444		sa1.spi = spino;
445
446		sin = (struct sockaddr_in *)&sa1.daddr;
447#ifdef INET6
448		sin6 = (struct sockaddr_in6 *)&sa1.daddr;
449		if (inet_pton(AF_INET6, spikey, &sin6->sin6_addr) == 1) {
450#ifdef HAVE_SOCKADDR_SA_LEN
451			sin6->sin6_len = sizeof(struct sockaddr_in6);
452#endif
453			sin6->sin6_family = AF_INET6;
454		} else
455#endif
456			if (inet_pton(AF_INET, spikey, &sin->sin_addr) == 1) {
457#ifdef HAVE_SOCKADDR_SA_LEN
458				sin->sin_len = sizeof(struct sockaddr_in);
459#endif
460				sin->sin_family = AF_INET;
461			} else {
462				(*ndo->ndo_warning)(ndo, "print_esp: can not decode IP# %s\n", spikey);
463				return;
464			}
465	}
466
467	if (decode) {
468		/* skip any blank spaces */
469		while (isspace((unsigned char)*decode))
470			decode++;
471
472		if(!espprint_decode_encalgo(ndo, decode, &sa1)) {
473			return;
474		}
475	}
476
477	esp_print_addsa(ndo, &sa1, sa_def);
478}
479
480static void esp_init(netdissect_options *ndo _U_)
481{
482
483	OpenSSL_add_all_algorithms();
484	EVP_add_cipher_alias(SN_des_ede3_cbc, "3des");
485}
486
487void esp_print_decodesecret(netdissect_options *ndo)
488{
489	char *line;
490	char *p;
491	static int initialized = 0;
492
493	if (!initialized) {
494		esp_init(ndo);
495		initialized = 1;
496	}
497
498	p = ndo->ndo_espsecret;
499
500	while (p && p[0] != '\0') {
501		/* pick out the first line or first thing until a comma */
502		if ((line = strsep(&p, "\n,")) == NULL) {
503			line = p;
504			p = NULL;
505		}
506
507		esp_print_decode_onesecret(ndo, line, "cmdline", 0);
508	}
509
510	ndo->ndo_espsecret = NULL;
511}
512
513#endif
514
515int
516esp_print(netdissect_options *ndo,
517	  const u_char *bp, const int length, const u_char *bp2
518#ifndef HAVE_LIBCRYPTO
519	_U_
520#endif
521	,
522	int *nhdr
523#ifndef HAVE_LIBCRYPTO
524	_U_
525#endif
526	,
527	int *padlen
528#ifndef HAVE_LIBCRYPTO
529	_U_
530#endif
531	)
532{
533	register const struct newesp *esp;
534	register const u_char *ep;
535#ifdef HAVE_LIBCRYPTO
536	struct ip *ip;
537	struct sa_list *sa = NULL;
538	int espsecret_keylen;
539#ifdef INET6
540	struct ip6_hdr *ip6 = NULL;
541#endif
542	int advance;
543	int len;
544	u_char *secret;
545	int ivlen = 0;
546	u_char *ivoff;
547	u_char *p;
548	EVP_CIPHER_CTX ctx;
549	int blocksz;
550#endif
551
552	esp = (struct newesp *)bp;
553
554#ifdef HAVE_LIBCRYPTO
555	secret = NULL;
556	advance = 0;
557#endif
558
559#if 0
560	/* keep secret out of a register */
561	p = (u_char *)&secret;
562#endif
563
564	/* 'ep' points to the end of available data. */
565	ep = ndo->ndo_snapend;
566
567	if ((u_char *)(esp + 1) >= ep) {
568		fputs("[|ESP]", stdout);
569		goto fail;
570	}
571	(*ndo->ndo_printf)(ndo, "ESP(spi=0x%08x", EXTRACT_32BITS(&esp->esp_spi));
572	(*ndo->ndo_printf)(ndo, ",seq=0x%x)", EXTRACT_32BITS(&esp->esp_seq));
573        (*ndo->ndo_printf)(ndo, ", length %u", length);
574
575#ifndef HAVE_LIBCRYPTO
576	goto fail;
577#else
578	/* initiailize SAs */
579	if (ndo->ndo_sa_list_head == NULL) {
580		if (!ndo->ndo_espsecret)
581			goto fail;
582
583		esp_print_decodesecret(ndo);
584	}
585
586	if (ndo->ndo_sa_list_head == NULL)
587		goto fail;
588
589	ip = (struct ip *)bp2;
590	switch (IP_V(ip)) {
591#ifdef INET6
592	case 6:
593		ip6 = (struct ip6_hdr *)bp2;
594		/* we do not attempt to decrypt jumbograms */
595		if (!EXTRACT_16BITS(&ip6->ip6_plen))
596			goto fail;
597		/* if we can't get nexthdr, we do not need to decrypt it */
598		len = sizeof(struct ip6_hdr) + EXTRACT_16BITS(&ip6->ip6_plen);
599
600		/* see if we can find the SA, and if so, decode it */
601		for (sa = ndo->ndo_sa_list_head; sa != NULL; sa = sa->next) {
602			struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&sa->daddr;
603			if (sa->spi == EXTRACT_32BITS(&esp->esp_spi) &&
604			    sin6->sin6_family == AF_INET6 &&
605			    memcmp(&sin6->sin6_addr, &ip6->ip6_dst,
606				   sizeof(struct in6_addr)) == 0) {
607				break;
608			}
609		}
610		break;
611#endif /*INET6*/
612	case 4:
613		/* nexthdr & padding are in the last fragment */
614		if (EXTRACT_16BITS(&ip->ip_off) & IP_MF)
615			goto fail;
616		len = EXTRACT_16BITS(&ip->ip_len);
617
618		/* see if we can find the SA, and if so, decode it */
619		for (sa = ndo->ndo_sa_list_head; sa != NULL; sa = sa->next) {
620			struct sockaddr_in *sin = (struct sockaddr_in *)&sa->daddr;
621			if (sa->spi == EXTRACT_32BITS(&esp->esp_spi) &&
622			    sin->sin_family == AF_INET &&
623			    sin->sin_addr.s_addr == ip->ip_dst.s_addr) {
624				break;
625			}
626		}
627		break;
628	default:
629		goto fail;
630	}
631
632	/* if we didn't find the specific one, then look for
633	 * an unspecified one.
634	 */
635	if (sa == NULL)
636		sa = ndo->ndo_sa_default;
637
638	/* if not found fail */
639	if (sa == NULL)
640		goto fail;
641
642	/* if we can't get nexthdr, we do not need to decrypt it */
643	if (ep - bp2 < len)
644		goto fail;
645	if (ep - bp2 > len) {
646		/* FCS included at end of frame (NetBSD 1.6 or later) */
647		ep = bp2 + len;
648	}
649
650	ivoff = (u_char *)(esp + 1) + 0;
651	ivlen = sa->ivlen;
652	secret = sa->secret;
653	espsecret_keylen = sa->secretlen;
654	ep = ep - sa->authlen;
655
656	if (sa->evp) {
657		memset(&ctx, 0, sizeof(ctx));
658		if (EVP_CipherInit(&ctx, sa->evp, secret, NULL, 0) < 0)
659			(*ndo->ndo_warning)(ndo, "espkey init failed");
660
661		blocksz = EVP_CIPHER_CTX_block_size(&ctx);
662
663		p = ivoff;
664		EVP_CipherInit(&ctx, NULL, NULL, p, 0);
665		EVP_Cipher(&ctx, p + ivlen, p + ivlen, ep - (p + ivlen));
666		EVP_CIPHER_CTX_cleanup(&ctx);
667		advance = ivoff - (u_char *)esp + ivlen;
668	} else
669		advance = sizeof(struct newesp);
670
671	/* sanity check for pad length */
672	if (ep - bp < *(ep - 2))
673		goto fail;
674
675	if (padlen)
676		*padlen = *(ep - 2) + 2;
677
678	if (nhdr)
679		*nhdr = *(ep - 1);
680
681	(ndo->ndo_printf)(ndo, ": ");
682	return advance;
683#endif
684
685fail:
686	return -1;
687}
688
689/*
690 * Local Variables:
691 * c-style: whitesmith
692 * c-basic-offset: 8
693 * End:
694 */
695