xref: /dragonfly/contrib/tcpdump/print-esp.c (revision 0ca59c34)
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
25 static 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
59 struct 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
71 struct 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  */
90 int 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 
140 static 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 
161 static 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 
175 static 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  */
186 static
187 int 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 
215 static int
216 espprint_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  */
285 static int
286 espprint_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 
305 static 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  */
369 static 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 
480 static 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 
487 void 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 
515 int
516 esp_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 
685 fail:
686 	return -1;
687 }
688 
689 /*
690  * Local Variables:
691  * c-style: whitesmith
692  * c-basic-offset: 8
693  * End:
694  */
695