xref: /freebsd/contrib/tcpdump/print-esp.c (revision 6b3455a7665208c366849f0b2b3bc916fb97516e)
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.44.2.4 2003/11/19 05:36:40 guy 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 #if defined(__MINGW32__) || defined(__WATCOMC__)
54 extern char *strsep(char **stringp, const char *delim); /* Missing/strsep.c */
55 #endif
56 
57 #include "interface.h"
58 #include "addrtoname.h"
59 #include "extract.h"
60 
61 #ifndef HAVE_SOCKADDR_STORAGE
62 #ifdef INET6
63 struct sockaddr_storage {
64 	union {
65 		struct sockaddr_in sin;
66 		struct sockaddr_in6 sin6;
67 	} un;
68 };
69 #else
70 #define sockaddr_storage sockaddr
71 #endif
72 #endif /* HAVE_SOCKADDR_STORAGE */
73 
74 #ifdef HAVE_LIBCRYPTO
75 struct sa_list {
76 	struct sa_list	*next;
77 	struct sockaddr_storage daddr;
78 	u_int32_t	spi;
79 	const EVP_CIPHER *evp;
80 	int		ivlen;
81 	int		authlen;
82 	char		secret[256];  /* is that big enough for all secrets? */
83 	int		secretlen;
84 };
85 
86 static struct sa_list *sa_list_head = NULL;
87 static struct sa_list *sa_default = NULL;
88 
89 static void esp_print_addsa(struct sa_list *sa, int sa_def)
90 {
91 	/* copy the "sa" */
92 
93 	struct sa_list *nsa;
94 
95 	nsa = (struct sa_list *)malloc(sizeof(struct sa_list));
96 	if (nsa == NULL)
97 		error("ran out of memory to allocate sa structure");
98 
99 	*nsa = *sa;
100 
101 	if (sa_def)
102 		sa_default = nsa;
103 
104 	nsa->next = sa_list_head;
105 	sa_list_head = nsa;
106 }
107 
108 
109 static int hexdigit(char hex)
110 {
111 	if (hex >= '0' && hex <= '9')
112 		return (hex - '0');
113 	else if (hex >= 'A' && hex <= 'F')
114 		return (hex - 'A' + 10);
115 	else if (hex >= 'a' && hex <= 'f')
116 		return (hex - 'a' + 10);
117 	else {
118 		printf("invalid hex digit %c in espsecret\n", hex);
119 		return 0;
120 	}
121 }
122 
123 static int hex2byte(char *hexstring)
124 {
125 	int byte;
126 
127 	byte = (hexdigit(hexstring[0]) << 4) + hexdigit(hexstring[1]);
128 	return byte;
129 }
130 
131 /*
132  * decode the form:    SPINUM@IP <tab> ALGONAME:0xsecret
133  *
134  * special form: file /name
135  * causes us to go read from this file instead.
136  *
137  */
138 static void esp_print_decode_onesecret(char *line)
139 {
140 	struct sa_list sa1;
141 	int sa_def;
142 
143 	char *spikey;
144 	char *decode;
145 
146 	spikey = strsep(&line, " \t");
147 	sa_def = 0;
148 	memset(&sa1, 0, sizeof(struct sa_list));
149 
150 	/* if there is only one token, then it is an algo:key token */
151 	if (line == NULL) {
152 		decode = spikey;
153 		spikey = NULL;
154 		/* memset(&sa1.daddr, 0, sizeof(sa1.daddr)); */
155 		/* sa1.spi = 0; */
156 		sa_def    = 1;
157 	} else
158 		decode = line;
159 
160 	if (spikey && strcasecmp(spikey, "file") == 0) {
161 		/* open file and read it */
162 		FILE *secretfile;
163 		char  fileline[1024];
164 		char  *nl;
165 
166 		secretfile = fopen(line, FOPEN_READ_TXT);
167 		if (secretfile == NULL) {
168 			perror(line);
169 			exit(3);
170 		}
171 
172 		while (fgets(fileline, sizeof(fileline)-1, secretfile) != NULL) {
173 			/* remove newline from the line */
174 			nl = strchr(fileline, '\n');
175 			if (nl)
176 				*nl = '\0';
177 			if (fileline[0] == '#') continue;
178 			if (fileline[0] == '\0') continue;
179 
180 			esp_print_decode_onesecret(fileline);
181 		}
182 		fclose(secretfile);
183 
184 		return;
185 	}
186 
187 	if (spikey) {
188 		char *spistr, *foo;
189 		u_int32_t spino;
190 		struct sockaddr_in *sin;
191 #ifdef INET6
192 		struct sockaddr_in6 *sin6;
193 #endif
194 
195 		spistr = strsep(&spikey, "@");
196 
197 		spino = strtoul(spistr, &foo, 0);
198 		if (spistr == foo || !spikey) {
199 			printf("print_esp: failed to decode spi# %s\n", foo);
200 			return;
201 		}
202 
203 		sa1.spi = spino;
204 
205 		sin = (struct sockaddr_in *)&sa1.daddr;
206 #ifdef INET6
207 		sin6 = (struct sockaddr_in6 *)&sa1.daddr;
208 		if (inet_pton(AF_INET6, spikey, &sin6->sin6_addr) == 1) {
209 #ifdef HAVE_SOCKADDR_SA_LEN
210 			sin6->sin6_len = sizeof(struct sockaddr_in6);
211 #endif
212 			sin6->sin6_family = AF_INET6;
213 		} else
214 #endif
215 		if (inet_pton(AF_INET, spikey, &sin->sin_addr) == 1) {
216 #ifdef HAVE_SOCKADDR_SA_LEN
217 			sin->sin_len = sizeof(struct sockaddr_in);
218 #endif
219 			sin->sin_family = AF_INET;
220 		} else {
221 			printf("print_esp: can not decode IP# %s\n", spikey);
222 			return;
223 		}
224 	}
225 
226 	if (decode) {
227 		char *colon, *p;
228 		char  espsecret_key[256];
229 		int len;
230 		size_t i;
231 		const EVP_CIPHER *evp;
232 		int ivlen = 8;
233 		int authlen = 0;
234 
235 		/* skip any blank spaces */
236 		while (isspace((unsigned char)*decode))
237 			decode++;
238 
239 		colon = strchr(decode, ':');
240 		if (colon == NULL) {
241 			printf("failed to decode espsecret: %s\n", decode);
242 			return;
243 		}
244 		*colon = '\0';
245 
246 		len = colon - decode;
247 		if (strlen(decode) > strlen("-hmac96") &&
248 		    !strcmp(decode + strlen(decode) - strlen("-hmac96"),
249 		    "-hmac96")) {
250 			p = strstr(decode, "-hmac96");
251 			*p = '\0';
252 			authlen = 12;
253 		}
254 		if (strlen(decode) > strlen("-cbc") &&
255 		    !strcmp(decode + strlen(decode) - strlen("-cbc"), "-cbc")) {
256 			p = strstr(decode, "-cbc");
257 			*p = '\0';
258 		}
259 		evp = EVP_get_cipherbyname(decode);
260 		if (!evp) {
261 			printf("failed to find cipher algo %s\n", decode);
262 			sa1.evp = NULL;
263 			sa1.authlen = 0;
264 			sa1.ivlen = 0;
265 			return;
266 		}
267 
268 		sa1.evp = evp;
269 		sa1.authlen = authlen;
270 		sa1.ivlen = ivlen;
271 
272 		colon++;
273 		if (colon[0] == '0' && colon[1] == 'x') {
274 			/* decode some hex! */
275 			colon += 2;
276 			len = strlen(colon) / 2;
277 
278 			if (len > 256) {
279 				printf("secret is too big: %d\n", len);
280 				return;
281 			}
282 
283 			i = 0;
284 			while (colon[0] != '\0' && colon[1]!='\0') {
285 				espsecret_key[i] = hex2byte(colon);
286 				colon += 2;
287 				i++;
288 			}
289 
290 			memcpy(sa1.secret, espsecret_key, i);
291 			sa1.secretlen = i;
292 		} else {
293 			i = strlen(colon);
294 
295 			if (i < sizeof(sa1.secret)) {
296 				memcpy(sa1.secret, colon, i);
297 				sa1.secretlen = i;
298 			} else {
299 				memcpy(sa1.secret, colon, sizeof(sa1.secret));
300 				sa1.secretlen = sizeof(sa1.secret);
301 			}
302 		}
303 	}
304 
305 	esp_print_addsa(&sa1, sa_def);
306 }
307 
308 static void esp_print_decodesecret(void)
309 {
310 	char *line;
311 	char *p;
312 
313 	p = espsecret;
314 
315 	while (espsecret && espsecret[0] != '\0') {
316 		/* pick out the first line or first thing until a comma */
317 		if ((line = strsep(&espsecret, "\n,")) == NULL) {
318 			line = espsecret;
319 			espsecret = NULL;
320 		}
321 
322 		esp_print_decode_onesecret(line);
323 	}
324 }
325 
326 static void esp_init(void)
327 {
328 
329 	OpenSSL_add_all_algorithms();
330 	EVP_add_cipher_alias(SN_des_ede3_cbc, "3des");
331 }
332 #endif
333 
334 int
335 esp_print(const u_char *bp, const u_char *bp2
336 #ifndef HAVE_LIBCRYPTO
337 	_U_
338 #endif
339 	,
340 	int *nhdr
341 #ifndef HAVE_LIBCRYPTO
342 	_U_
343 #endif
344 	,
345 	int *padlen
346 #ifndef HAVE_LIBCRYPTO
347 	_U_
348 #endif
349 	)
350 {
351 	register const struct newesp *esp;
352 	register const u_char *ep;
353 #ifdef HAVE_LIBCRYPTO
354 	struct ip *ip;
355 	struct sa_list *sa = NULL;
356 	int espsecret_keylen;
357 #ifdef INET6
358 	struct ip6_hdr *ip6 = NULL;
359 #endif
360 	int advance;
361 	int len;
362 	char *secret;
363 	int ivlen = 0;
364 	u_char *ivoff;
365 	const u_char *p;
366 	EVP_CIPHER_CTX ctx;
367 	int blocksz;
368 	static int initialized = 0;
369 #endif
370 
371 	esp = (struct newesp *)bp;
372 
373 #ifdef HAVE_LIBCRYPTO
374 	secret = NULL;
375 	advance = 0;
376 
377 	if (!initialized) {
378 		esp_init();
379 		initialized = 1;
380 	}
381 #endif
382 
383 #if 0
384 	/* keep secret out of a register */
385 	p = (u_char *)&secret;
386 #endif
387 
388 	/* 'ep' points to the end of available data. */
389 	ep = snapend;
390 
391 	if ((u_char *)(esp + 1) >= ep) {
392 		fputs("[|ESP]", stdout);
393 		goto fail;
394 	}
395 	printf("ESP(spi=0x%08x", EXTRACT_32BITS(&esp->esp_spi));
396 	printf(",seq=0x%x", EXTRACT_32BITS(&esp->esp_seq));
397 	printf(")");
398 
399 #ifndef HAVE_LIBCRYPTO
400 	goto fail;
401 #else
402 	/* initiailize SAs */
403 	if (sa_list_head == NULL) {
404 		if (!espsecret)
405 			goto fail;
406 
407 		esp_print_decodesecret();
408 	}
409 
410 	if (sa_list_head == NULL)
411 		goto fail;
412 
413 	ip = (struct ip *)bp2;
414 	switch (IP_V(ip)) {
415 #ifdef INET6
416 	case 6:
417 		ip6 = (struct ip6_hdr *)bp2;
418 		/* we do not attempt to decrypt jumbograms */
419 		if (!EXTRACT_16BITS(&ip6->ip6_plen))
420 			goto fail;
421 		/* if we can't get nexthdr, we do not need to decrypt it */
422 		len = sizeof(struct ip6_hdr) + EXTRACT_16BITS(&ip6->ip6_plen);
423 
424 		/* see if we can find the SA, and if so, decode it */
425 		for (sa = sa_list_head; sa != NULL; sa = sa->next) {
426 			struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&sa->daddr;
427 			if (sa->spi == ntohl(esp->esp_spi) &&
428 			    sin6->sin6_family == AF_INET6 &&
429 			    memcmp(&sin6->sin6_addr, &ip6->ip6_dst,
430 				   sizeof(struct in6_addr)) == 0) {
431 				break;
432 			}
433 		}
434 		break;
435 #endif /*INET6*/
436 	case 4:
437 		/* nexthdr & padding are in the last fragment */
438 		if (EXTRACT_16BITS(&ip->ip_off) & IP_MF)
439 			goto fail;
440 		len = EXTRACT_16BITS(&ip->ip_len);
441 
442 		/* see if we can find the SA, and if so, decode it */
443 		for (sa = sa_list_head; sa != NULL; sa = sa->next) {
444 			struct sockaddr_in *sin = (struct sockaddr_in *)&sa->daddr;
445 			if (sa->spi == ntohl(esp->esp_spi) &&
446 			    sin->sin_family == AF_INET &&
447 			    sin->sin_addr.s_addr == ip->ip_dst.s_addr) {
448 				break;
449 			}
450 		}
451 		break;
452 	default:
453 		goto fail;
454 	}
455 
456 	/* if we didn't find the specific one, then look for
457 	 * an unspecified one.
458 	 */
459 	if (sa == NULL)
460 		sa = sa_default;
461 
462 	/* if not found fail */
463 	if (sa == NULL)
464 		goto fail;
465 
466 	/* if we can't get nexthdr, we do not need to decrypt it */
467 	if (ep - bp2 < len)
468 		goto fail;
469 	if (ep - bp2 > len) {
470 		/* FCS included at end of frame (NetBSD 1.6 or later) */
471 		ep = bp2 + len;
472 	}
473 
474 	ivoff = (u_char *)(esp + 1) + 0;
475 	ivlen = sa->ivlen;
476 	secret = sa->secret;
477 	espsecret_keylen = sa->secretlen;
478 
479 	if (sa->evp) {
480 		memset(&ctx, 0, sizeof(ctx));
481 		if (EVP_CipherInit(&ctx, sa->evp, secret, NULL, 0) < 0)
482 			printf("espkey init failed");
483 
484 		blocksz = EVP_CIPHER_CTX_block_size(&ctx);
485 
486 		p = ivoff;
487 		EVP_CipherInit(&ctx, NULL, NULL, p, 0);
488 		EVP_Cipher(&ctx, p + ivlen, p + ivlen, ep - (p + ivlen));
489 		advance = ivoff - (u_char *)esp + ivlen;
490 	} else
491 		advance = sizeof(struct newesp);
492 
493 	ep = ep - sa->authlen;
494 	/* sanity check for pad length */
495 	if (ep - bp < *(ep - 2))
496 		goto fail;
497 
498 	if (padlen)
499 		*padlen = *(ep - 2) + 2;
500 
501 	if (nhdr)
502 		*nhdr = *(ep - 1);
503 
504 	printf(": ");
505 	return advance;
506 #endif
507 
508 fail:
509 	return -1;
510 }
511