xref: /freebsd/contrib/tcpdump/print-esp.c (revision 27df3f5dddcc52e19be97c5e876161208987d4f1)
1b0453382SBill Fenner /*	$NetBSD: print-ah.c,v 1.4 1996/05/20 00:41:16 fvdl Exp $	*/
2b0453382SBill Fenner 
3b0453382SBill Fenner /*
4b0453382SBill Fenner  * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994
5b0453382SBill Fenner  *	The Regents of the University of California.  All rights reserved.
6b0453382SBill Fenner  *
7b0453382SBill Fenner  * Redistribution and use in source and binary forms, with or without
8b0453382SBill Fenner  * modification, are permitted provided that: (1) source code distributions
9b0453382SBill Fenner  * retain the above copyright notice and this paragraph in its entirety, (2)
10b0453382SBill Fenner  * distributions including binary code include the above copyright notice and
11b0453382SBill Fenner  * this paragraph in its entirety in the documentation or other materials
12b0453382SBill Fenner  * provided with the distribution, and (3) all advertising materials mentioning
13b0453382SBill Fenner  * features or use of this software display the following acknowledgement:
14b0453382SBill Fenner  * ``This product includes software developed by the University of California,
15b0453382SBill Fenner  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
16b0453382SBill Fenner  * the University nor the names of its contributors may be used to endorse
17b0453382SBill Fenner  * or promote products derived from this software without specific prior
18b0453382SBill Fenner  * written permission.
19b0453382SBill Fenner  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
20b0453382SBill Fenner  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
21b0453382SBill Fenner  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
22b0453382SBill Fenner  */
23b0453382SBill Fenner 
24b0453382SBill Fenner #ifndef lint
255b0fe478SBruce M Simpson static const char rcsid[] _U_ =
26*27df3f5dSRui Paulo     "@(#) $Header: /tcpdump/master/tcpdump/print-esp.c,v 1.58 2007-12-07 00:03:07 mcr Exp $ (LBL)";
27b0453382SBill Fenner #endif
28b0453382SBill Fenner 
29b0453382SBill Fenner #ifdef HAVE_CONFIG_H
30b0453382SBill Fenner #include "config.h"
31b0453382SBill Fenner #endif
32b0453382SBill Fenner 
33b0453382SBill Fenner #include <string.h>
345b0fe478SBruce M Simpson 
355b0fe478SBruce M Simpson #include <tcpdump-stdinc.h>
365b0fe478SBruce M Simpson 
379afd0c29SBill Fenner #include <stdlib.h>
38b0453382SBill Fenner 
39685295f4SBill Fenner #ifdef HAVE_LIBCRYPTO
405b0fe478SBruce M Simpson #ifdef HAVE_OPENSSL_EVP_H
415b0fe478SBruce M Simpson #include <openssl/evp.h>
42b0453382SBill Fenner #endif
43b0453382SBill Fenner #endif
44b0453382SBill Fenner 
45b0453382SBill Fenner #include <stdio.h>
46b0453382SBill Fenner 
47685295f4SBill Fenner #include "ip.h"
48685295f4SBill Fenner #include "esp.h"
49b0453382SBill Fenner #ifdef INET6
50685295f4SBill Fenner #include "ip6.h"
51b0453382SBill Fenner #endif
52b0453382SBill Fenner 
531de50e9fSSam Leffler #include "netdissect.h"
54b0453382SBill Fenner #include "addrtoname.h"
555b0fe478SBruce M Simpson #include "extract.h"
56b0453382SBill Fenner 
575b0fe478SBruce M Simpson #ifndef HAVE_SOCKADDR_STORAGE
585b0fe478SBruce M Simpson #ifdef INET6
595b0fe478SBruce M Simpson struct sockaddr_storage {
605b0fe478SBruce M Simpson 	union {
615b0fe478SBruce M Simpson 		struct sockaddr_in sin;
625b0fe478SBruce M Simpson 		struct sockaddr_in6 sin6;
635b0fe478SBruce M Simpson 	} un;
645b0fe478SBruce M Simpson };
655b0fe478SBruce M Simpson #else
665b0fe478SBruce M Simpson #define sockaddr_storage sockaddr
675b0fe478SBruce M Simpson #endif
685b0fe478SBruce M Simpson #endif /* HAVE_SOCKADDR_STORAGE */
69a90e161bSBill Fenner 
705b0fe478SBruce M Simpson #ifdef HAVE_LIBCRYPTO
715b0fe478SBruce M Simpson struct sa_list {
725b0fe478SBruce M Simpson 	struct sa_list	*next;
735b0fe478SBruce M Simpson 	struct sockaddr_storage daddr;
74*27df3f5dSRui Paulo 	u_int32_t	spi;          /* if == 0, then IKEv2 */
75*27df3f5dSRui Paulo 	int             initiator;
76*27df3f5dSRui Paulo 	u_char          spii[8];      /* for IKEv2 */
77*27df3f5dSRui Paulo 	u_char          spir[8];
785b0fe478SBruce M Simpson 	const EVP_CIPHER *evp;
79a90e161bSBill Fenner 	int		ivlen;
80a90e161bSBill Fenner 	int		authlen;
81*27df3f5dSRui Paulo 	u_char          authsecret[256];
82*27df3f5dSRui Paulo 	int             authsecret_len;
83f4d0c64aSSam Leffler 	u_char		secret[256];  /* is that big enough for all secrets? */
845b0fe478SBruce M Simpson 	int		secretlen;
85a90e161bSBill Fenner };
86a90e161bSBill Fenner 
87*27df3f5dSRui Paulo /*
88*27df3f5dSRui Paulo  * this will adjust ndo_packetp and ndo_snapend to new buffer!
89*27df3f5dSRui Paulo  */
90*27df3f5dSRui Paulo int esp_print_decrypt_buffer_by_ikev2(netdissect_options *ndo,
91*27df3f5dSRui Paulo 				      int initiator,
92*27df3f5dSRui Paulo 				      u_char spii[8], u_char spir[8],
93*27df3f5dSRui Paulo 				      u_char *buf, u_char *end)
94*27df3f5dSRui Paulo {
95*27df3f5dSRui Paulo 	struct sa_list *sa;
96*27df3f5dSRui Paulo 	u_char *iv;
97*27df3f5dSRui Paulo 	int len;
98*27df3f5dSRui Paulo 	EVP_CIPHER_CTX ctx;
99*27df3f5dSRui Paulo 
100*27df3f5dSRui Paulo 	/* initiator arg is any non-zero value */
101*27df3f5dSRui Paulo 	if(initiator) initiator=1;
102*27df3f5dSRui Paulo 
103*27df3f5dSRui Paulo 	/* see if we can find the SA, and if so, decode it */
104*27df3f5dSRui Paulo 	for (sa = ndo->ndo_sa_list_head; sa != NULL; sa = sa->next) {
105*27df3f5dSRui Paulo 		if (sa->spi == 0
106*27df3f5dSRui Paulo 		    && initiator == sa->initiator
107*27df3f5dSRui Paulo 		    && memcmp(spii, sa->spii, 8) == 0
108*27df3f5dSRui Paulo 		    && memcmp(spir, sa->spir, 8) == 0)
109*27df3f5dSRui Paulo 			break;
110*27df3f5dSRui Paulo 	}
111*27df3f5dSRui Paulo 
112*27df3f5dSRui Paulo 	if(sa == NULL) return 0;
113*27df3f5dSRui Paulo 	if(sa->evp == NULL) return 0;
114*27df3f5dSRui Paulo 
115*27df3f5dSRui Paulo 	/*
116*27df3f5dSRui Paulo 	 * remove authenticator, and see if we still have something to
117*27df3f5dSRui Paulo 	 * work with
118*27df3f5dSRui Paulo 	 */
119*27df3f5dSRui Paulo 	end = end - sa->authlen;
120*27df3f5dSRui Paulo 	iv  = buf;
121*27df3f5dSRui Paulo 	buf = buf + sa->ivlen;
122*27df3f5dSRui Paulo 	len = end-buf;
123*27df3f5dSRui Paulo 
124*27df3f5dSRui Paulo 	if(end <= buf) return 0;
125*27df3f5dSRui Paulo 
126*27df3f5dSRui Paulo 	memset(&ctx, 0, sizeof(ctx));
127*27df3f5dSRui Paulo 	if (EVP_CipherInit(&ctx, sa->evp, sa->secret, NULL, 0) < 0)
128*27df3f5dSRui Paulo 		(*ndo->ndo_warning)(ndo, "espkey init failed");
129*27df3f5dSRui Paulo 	EVP_CipherInit(&ctx, NULL, NULL, iv, 0);
130*27df3f5dSRui Paulo 	EVP_Cipher(&ctx, buf, buf, len);
131*27df3f5dSRui Paulo 	EVP_CIPHER_CTX_cleanup(&ctx);
132*27df3f5dSRui Paulo 
133*27df3f5dSRui Paulo 	ndo->ndo_packetp = buf;
134*27df3f5dSRui Paulo 	ndo->ndo_snapend = end;
135*27df3f5dSRui Paulo 
136*27df3f5dSRui Paulo 	return 1;
137*27df3f5dSRui Paulo 
138*27df3f5dSRui Paulo }
139*27df3f5dSRui Paulo 
1401de50e9fSSam Leffler static void esp_print_addsa(netdissect_options *ndo,
1411de50e9fSSam Leffler 			    struct sa_list *sa, int sa_def)
1425b0fe478SBruce M Simpson {
1435b0fe478SBruce M Simpson 	/* copy the "sa" */
1445b0fe478SBruce M Simpson 
1455b0fe478SBruce M Simpson 	struct sa_list *nsa;
1465b0fe478SBruce M Simpson 
1475b0fe478SBruce M Simpson 	nsa = (struct sa_list *)malloc(sizeof(struct sa_list));
1485b0fe478SBruce M Simpson 	if (nsa == NULL)
1491de50e9fSSam Leffler 		(*ndo->ndo_error)(ndo, "ran out of memory to allocate sa structure");
1505b0fe478SBruce M Simpson 
1515b0fe478SBruce M Simpson 	*nsa = *sa;
1525b0fe478SBruce M Simpson 
1535b0fe478SBruce M Simpson 	if (sa_def)
1541de50e9fSSam Leffler 		ndo->ndo_sa_default = nsa;
1555b0fe478SBruce M Simpson 
1561de50e9fSSam Leffler 	nsa->next = ndo->ndo_sa_list_head;
1571de50e9fSSam Leffler 	ndo->ndo_sa_list_head = nsa;
1585b0fe478SBruce M Simpson }
1595b0fe478SBruce M Simpson 
160a90e161bSBill Fenner 
161f4d0c64aSSam Leffler static u_int hexdigit(netdissect_options *ndo, char hex)
162a90e161bSBill Fenner {
1635b0fe478SBruce M Simpson 	if (hex >= '0' && hex <= '9')
164a90e161bSBill Fenner 		return (hex - '0');
1655b0fe478SBruce M Simpson 	else if (hex >= 'A' && hex <= 'F')
166a90e161bSBill Fenner 		return (hex - 'A' + 10);
1675b0fe478SBruce M Simpson 	else if (hex >= 'a' && hex <= 'f')
168a90e161bSBill Fenner 		return (hex - 'a' + 10);
1695b0fe478SBruce M Simpson 	else {
1701de50e9fSSam Leffler 		(*ndo->ndo_error)(ndo, "invalid hex digit %c in espsecret\n", hex);
171a90e161bSBill Fenner 		return 0;
172a90e161bSBill Fenner 	}
173a90e161bSBill Fenner }
174a90e161bSBill Fenner 
175f4d0c64aSSam Leffler static u_int hex2byte(netdissect_options *ndo, char *hexstring)
176a90e161bSBill Fenner {
177f4d0c64aSSam Leffler 	u_int byte;
178a90e161bSBill Fenner 
1791de50e9fSSam Leffler 	byte = (hexdigit(ndo, hexstring[0]) << 4) + hexdigit(ndo, hexstring[1]);
180a90e161bSBill Fenner 	return byte;
181a90e161bSBill Fenner }
182a90e161bSBill Fenner 
1835b0fe478SBruce M Simpson /*
184*27df3f5dSRui Paulo  * returns size of binary, 0 on failure.
185*27df3f5dSRui Paulo  */
186*27df3f5dSRui Paulo static
187*27df3f5dSRui Paulo int espprint_decode_hex(netdissect_options *ndo,
188*27df3f5dSRui Paulo 			u_char *binbuf, unsigned int binbuf_len,
189*27df3f5dSRui Paulo 			char *hex)
190*27df3f5dSRui Paulo {
191*27df3f5dSRui Paulo 	unsigned int len;
192*27df3f5dSRui Paulo 	int i;
193*27df3f5dSRui Paulo 
194*27df3f5dSRui Paulo 	len = strlen(hex) / 2;
195*27df3f5dSRui Paulo 
196*27df3f5dSRui Paulo 	if (len > binbuf_len) {
197*27df3f5dSRui Paulo 		(*ndo->ndo_warning)(ndo, "secret is too big: %d\n", len);
198*27df3f5dSRui Paulo 		return 0;
199*27df3f5dSRui Paulo 	}
200*27df3f5dSRui Paulo 
201*27df3f5dSRui Paulo 	i = 0;
202*27df3f5dSRui Paulo 	while (hex[0] != '\0' && hex[1]!='\0') {
203*27df3f5dSRui Paulo 		binbuf[i] = hex2byte(ndo, hex);
204*27df3f5dSRui Paulo 		hex += 2;
205*27df3f5dSRui Paulo 		i++;
206*27df3f5dSRui Paulo 	}
207*27df3f5dSRui Paulo 
208*27df3f5dSRui Paulo 	return i;
209*27df3f5dSRui Paulo }
210*27df3f5dSRui Paulo 
211*27df3f5dSRui Paulo /*
2125b0fe478SBruce M Simpson  * decode the form:    SPINUM@IP <tab> ALGONAME:0xsecret
213*27df3f5dSRui Paulo  */
214*27df3f5dSRui Paulo 
215*27df3f5dSRui Paulo static int
216*27df3f5dSRui Paulo espprint_decode_encalgo(netdissect_options *ndo,
217*27df3f5dSRui Paulo 			char *decode, struct sa_list *sa)
218*27df3f5dSRui Paulo {
219*27df3f5dSRui Paulo 	int len;
220*27df3f5dSRui Paulo 	size_t i;
221*27df3f5dSRui Paulo 	const EVP_CIPHER *evp;
222*27df3f5dSRui Paulo 	int authlen = 0;
223*27df3f5dSRui Paulo 	char *colon, *p;
224*27df3f5dSRui Paulo 
225*27df3f5dSRui Paulo 	colon = strchr(decode, ':');
226*27df3f5dSRui Paulo 	if (colon == NULL) {
227*27df3f5dSRui Paulo 		(*ndo->ndo_warning)(ndo, "failed to decode espsecret: %s\n", decode);
228*27df3f5dSRui Paulo 		return 0;
229*27df3f5dSRui Paulo 	}
230*27df3f5dSRui Paulo 	*colon = '\0';
231*27df3f5dSRui Paulo 
232*27df3f5dSRui Paulo 	len = colon - decode;
233*27df3f5dSRui Paulo 	if (strlen(decode) > strlen("-hmac96") &&
234*27df3f5dSRui Paulo 	    !strcmp(decode + strlen(decode) - strlen("-hmac96"),
235*27df3f5dSRui Paulo 		    "-hmac96")) {
236*27df3f5dSRui Paulo 		p = strstr(decode, "-hmac96");
237*27df3f5dSRui Paulo 		*p = '\0';
238*27df3f5dSRui Paulo 		authlen = 12;
239*27df3f5dSRui Paulo 	}
240*27df3f5dSRui Paulo 	if (strlen(decode) > strlen("-cbc") &&
241*27df3f5dSRui Paulo 	    !strcmp(decode + strlen(decode) - strlen("-cbc"), "-cbc")) {
242*27df3f5dSRui Paulo 		p = strstr(decode, "-cbc");
243*27df3f5dSRui Paulo 		*p = '\0';
244*27df3f5dSRui Paulo 	}
245*27df3f5dSRui Paulo 	evp = EVP_get_cipherbyname(decode);
246*27df3f5dSRui Paulo 
247*27df3f5dSRui Paulo 	if (!evp) {
248*27df3f5dSRui Paulo 		(*ndo->ndo_warning)(ndo, "failed to find cipher algo %s\n", decode);
249*27df3f5dSRui Paulo 		sa->evp = NULL;
250*27df3f5dSRui Paulo 		sa->authlen = 0;
251*27df3f5dSRui Paulo 		sa->ivlen = 0;
252*27df3f5dSRui Paulo 		return 0;
253*27df3f5dSRui Paulo 	}
254*27df3f5dSRui Paulo 
255*27df3f5dSRui Paulo 	sa->evp = evp;
256*27df3f5dSRui Paulo 	sa->authlen = authlen;
257*27df3f5dSRui Paulo 	sa->ivlen = EVP_CIPHER_iv_length(evp);
258*27df3f5dSRui Paulo 
259*27df3f5dSRui Paulo 	colon++;
260*27df3f5dSRui Paulo 	if (colon[0] == '0' && colon[1] == 'x') {
261*27df3f5dSRui Paulo 		/* decode some hex! */
262*27df3f5dSRui Paulo 
263*27df3f5dSRui Paulo 		colon += 2;
264*27df3f5dSRui Paulo 		sa->secretlen = espprint_decode_hex(ndo, sa->secret, sizeof(sa->secret), colon);
265*27df3f5dSRui Paulo 		if(sa->secretlen == 0) return 0;
266*27df3f5dSRui Paulo 	} else {
267*27df3f5dSRui Paulo 		i = strlen(colon);
268*27df3f5dSRui Paulo 
269*27df3f5dSRui Paulo 		if (i < sizeof(sa->secret)) {
270*27df3f5dSRui Paulo 			memcpy(sa->secret, colon, i);
271*27df3f5dSRui Paulo 			sa->secretlen = i;
272*27df3f5dSRui Paulo 		} else {
273*27df3f5dSRui Paulo 			memcpy(sa->secret, colon, sizeof(sa->secret));
274*27df3f5dSRui Paulo 			sa->secretlen = sizeof(sa->secret);
275*27df3f5dSRui Paulo 		}
276*27df3f5dSRui Paulo 	}
277*27df3f5dSRui Paulo 
278*27df3f5dSRui Paulo 	return 1;
279*27df3f5dSRui Paulo }
280*27df3f5dSRui Paulo 
281*27df3f5dSRui Paulo /*
282*27df3f5dSRui Paulo  * for the moment, ignore the auth algorith, just hard code the authenticator
283*27df3f5dSRui Paulo  * length. Need to research how openssl looks up HMAC stuff.
284*27df3f5dSRui Paulo  */
285*27df3f5dSRui Paulo static int
286*27df3f5dSRui Paulo espprint_decode_authalgo(netdissect_options *ndo,
287*27df3f5dSRui Paulo 			 char *decode, struct sa_list *sa)
288*27df3f5dSRui Paulo {
289*27df3f5dSRui Paulo 	char *colon;
290*27df3f5dSRui Paulo 
291*27df3f5dSRui Paulo 	colon = strchr(decode, ':');
292*27df3f5dSRui Paulo 	if (colon == NULL) {
293*27df3f5dSRui Paulo 		(*ndo->ndo_warning)(ndo, "failed to decode espsecret: %s\n", decode);
294*27df3f5dSRui Paulo 		return 0;
295*27df3f5dSRui Paulo 	}
296*27df3f5dSRui Paulo 	*colon = '\0';
297*27df3f5dSRui Paulo 
298*27df3f5dSRui Paulo 	if(strcasecmp(colon,"sha1") == 0 ||
299*27df3f5dSRui Paulo 	   strcasecmp(colon,"md5") == 0) {
300*27df3f5dSRui Paulo 		sa->authlen = 12;
301*27df3f5dSRui Paulo 	}
302*27df3f5dSRui Paulo 	return 1;
303*27df3f5dSRui Paulo }
304*27df3f5dSRui Paulo 
305*27df3f5dSRui Paulo static void esp_print_decode_ikeline(netdissect_options *ndo, char *line,
306*27df3f5dSRui Paulo 				     const char *file, int lineno)
307*27df3f5dSRui Paulo {
308*27df3f5dSRui Paulo 	/* it's an IKEv2 secret, store it instead */
309*27df3f5dSRui Paulo 	struct sa_list sa1;
310*27df3f5dSRui Paulo 
311*27df3f5dSRui Paulo 	char *init;
312*27df3f5dSRui Paulo 	char *icookie, *rcookie;
313*27df3f5dSRui Paulo 	int   ilen, rlen;
314*27df3f5dSRui Paulo 	char *authkey;
315*27df3f5dSRui Paulo 	char *enckey;
316*27df3f5dSRui Paulo 
317*27df3f5dSRui Paulo 	init = strsep(&line, " \t");
318*27df3f5dSRui Paulo 	icookie = strsep(&line, " \t");
319*27df3f5dSRui Paulo 	rcookie = strsep(&line, " \t");
320*27df3f5dSRui Paulo 	authkey = strsep(&line, " \t");
321*27df3f5dSRui Paulo 	enckey  = strsep(&line, " \t");
322*27df3f5dSRui Paulo 
323*27df3f5dSRui Paulo 	/* if any fields are missing */
324*27df3f5dSRui Paulo 	if(!init || !icookie || !rcookie || !authkey || !enckey) {
325*27df3f5dSRui Paulo 		(*ndo->ndo_warning)(ndo, "print_esp: failed to find all fields for ikev2 at %s:%u",
326*27df3f5dSRui Paulo 				    file, lineno);
327*27df3f5dSRui Paulo 
328*27df3f5dSRui Paulo 		return;
329*27df3f5dSRui Paulo 	}
330*27df3f5dSRui Paulo 
331*27df3f5dSRui Paulo 	ilen = strlen(icookie);
332*27df3f5dSRui Paulo 	rlen = strlen(rcookie);
333*27df3f5dSRui Paulo 
334*27df3f5dSRui Paulo 	if((init[0]!='I' && init[0]!='R')
335*27df3f5dSRui Paulo 	   || icookie[0]!='0' || icookie[1]!='x'
336*27df3f5dSRui Paulo 	   || rcookie[0]!='0' || rcookie[1]!='x'
337*27df3f5dSRui Paulo 	   || ilen!=18
338*27df3f5dSRui Paulo 	   || rlen!=18) {
339*27df3f5dSRui Paulo 		(*ndo->ndo_warning)(ndo, "print_esp: line %s:%u improperly formatted.",
340*27df3f5dSRui Paulo 				    file, lineno);
341*27df3f5dSRui Paulo 
342*27df3f5dSRui Paulo 		(*ndo->ndo_warning)(ndo, "init=%s icookie=%s(%u) rcookie=%s(%u)",
343*27df3f5dSRui Paulo 				    init, icookie, ilen, rcookie, rlen);
344*27df3f5dSRui Paulo 
345*27df3f5dSRui Paulo 		return;
346*27df3f5dSRui Paulo 	}
347*27df3f5dSRui Paulo 
348*27df3f5dSRui Paulo 	sa1.spi = 0;
349*27df3f5dSRui Paulo 	sa1.initiator = (init[0] == 'I');
350*27df3f5dSRui Paulo 	if(espprint_decode_hex(ndo, sa1.spii, sizeof(sa1.spii), icookie+2)!=8)
351*27df3f5dSRui Paulo 		return;
352*27df3f5dSRui Paulo 
353*27df3f5dSRui Paulo 	if(espprint_decode_hex(ndo, sa1.spir, sizeof(sa1.spir), rcookie+2)!=8)
354*27df3f5dSRui Paulo 		return;
355*27df3f5dSRui Paulo 
356*27df3f5dSRui Paulo 	if(!espprint_decode_encalgo(ndo, enckey, &sa1)) return;
357*27df3f5dSRui Paulo 
358*27df3f5dSRui Paulo 	if(!espprint_decode_authalgo(ndo, authkey, &sa1)) return;
359*27df3f5dSRui Paulo 
360*27df3f5dSRui Paulo 	esp_print_addsa(ndo, &sa1, FALSE);
361*27df3f5dSRui Paulo }
362*27df3f5dSRui Paulo 
363*27df3f5dSRui Paulo /*
3645b0fe478SBruce M Simpson  *
3655b0fe478SBruce M Simpson  * special form: file /name
3665b0fe478SBruce M Simpson  * causes us to go read from this file instead.
3675b0fe478SBruce M Simpson  *
3685b0fe478SBruce M Simpson  */
369*27df3f5dSRui Paulo static void esp_print_decode_onesecret(netdissect_options *ndo, char *line,
370*27df3f5dSRui Paulo 				       const char *file, int lineno)
371a90e161bSBill Fenner {
3725b0fe478SBruce M Simpson 	struct sa_list sa1;
3735b0fe478SBruce M Simpson 	int sa_def;
374a90e161bSBill Fenner 
3755b0fe478SBruce M Simpson 	char *spikey;
3765b0fe478SBruce M Simpson 	char *decode;
3775b0fe478SBruce M Simpson 
3785b0fe478SBruce M Simpson 	spikey = strsep(&line, " \t");
3795b0fe478SBruce M Simpson 	sa_def = 0;
3805b0fe478SBruce M Simpson 	memset(&sa1, 0, sizeof(struct sa_list));
3815b0fe478SBruce M Simpson 
3825b0fe478SBruce M Simpson 	/* if there is only one token, then it is an algo:key token */
3835b0fe478SBruce M Simpson 	if (line == NULL) {
3845b0fe478SBruce M Simpson 		decode = spikey;
3855b0fe478SBruce M Simpson 		spikey = NULL;
3865b0fe478SBruce M Simpson 		/* memset(&sa1.daddr, 0, sizeof(sa1.daddr)); */
3875b0fe478SBruce M Simpson 		/* sa1.spi = 0; */
3885b0fe478SBruce M Simpson 		sa_def    = 1;
3895b0fe478SBruce M Simpson 	} else
3905b0fe478SBruce M Simpson 		decode = line;
3915b0fe478SBruce M Simpson 
3925b0fe478SBruce M Simpson 	if (spikey && strcasecmp(spikey, "file") == 0) {
3935b0fe478SBruce M Simpson 		/* open file and read it */
3945b0fe478SBruce M Simpson 		FILE *secretfile;
3955b0fe478SBruce M Simpson 		char  fileline[1024];
396*27df3f5dSRui Paulo 		int   lineno=0;
3975b0fe478SBruce M Simpson 		char  *nl;
398*27df3f5dSRui Paulo 		char *filename = line;
3995b0fe478SBruce M Simpson 
400*27df3f5dSRui Paulo 		secretfile = fopen(filename, FOPEN_READ_TXT);
4015b0fe478SBruce M Simpson 		if (secretfile == NULL) {
402*27df3f5dSRui Paulo 			perror(filename);
4035b0fe478SBruce M Simpson 			exit(3);
4045b0fe478SBruce M Simpson 		}
4055b0fe478SBruce M Simpson 
4065b0fe478SBruce M Simpson 		while (fgets(fileline, sizeof(fileline)-1, secretfile) != NULL) {
407*27df3f5dSRui Paulo 			lineno++;
4085b0fe478SBruce M Simpson 			/* remove newline from the line */
4095b0fe478SBruce M Simpson 			nl = strchr(fileline, '\n');
4105b0fe478SBruce M Simpson 			if (nl)
4115b0fe478SBruce M Simpson 				*nl = '\0';
4125b0fe478SBruce M Simpson 			if (fileline[0] == '#') continue;
4135b0fe478SBruce M Simpson 			if (fileline[0] == '\0') continue;
4145b0fe478SBruce M Simpson 
415*27df3f5dSRui Paulo 			esp_print_decode_onesecret(ndo, fileline, filename, lineno);
4165b0fe478SBruce M Simpson 		}
4175b0fe478SBruce M Simpson 		fclose(secretfile);
4185b0fe478SBruce M Simpson 
419a90e161bSBill Fenner 		return;
420a90e161bSBill Fenner 	}
421a90e161bSBill Fenner 
422*27df3f5dSRui Paulo 	if (spikey && strcasecmp(spikey, "ikev2") == 0) {
423*27df3f5dSRui Paulo 		esp_print_decode_ikeline(ndo, line, file, lineno);
424*27df3f5dSRui Paulo 		return;
425*27df3f5dSRui Paulo 	}
426*27df3f5dSRui Paulo 
4275b0fe478SBruce M Simpson 	if (spikey) {
428*27df3f5dSRui Paulo 
4295b0fe478SBruce M Simpson 		char *spistr, *foo;
4305b0fe478SBruce M Simpson 		u_int32_t spino;
4315b0fe478SBruce M Simpson 		struct sockaddr_in *sin;
4325b0fe478SBruce M Simpson #ifdef INET6
4335b0fe478SBruce M Simpson 		struct sockaddr_in6 *sin6;
4345b0fe478SBruce M Simpson #endif
4355b0fe478SBruce M Simpson 
4365b0fe478SBruce M Simpson 		spistr = strsep(&spikey, "@");
4375b0fe478SBruce M Simpson 
4385b0fe478SBruce M Simpson 		spino = strtoul(spistr, &foo, 0);
4395b0fe478SBruce M Simpson 		if (spistr == foo || !spikey) {
4401de50e9fSSam Leffler 			(*ndo->ndo_warning)(ndo, "print_esp: failed to decode spi# %s\n", foo);
441a90e161bSBill Fenner 			return;
442a90e161bSBill Fenner 		}
443a90e161bSBill Fenner 
4445b0fe478SBruce M Simpson 		sa1.spi = spino;
4455b0fe478SBruce M Simpson 
4465b0fe478SBruce M Simpson 		sin = (struct sockaddr_in *)&sa1.daddr;
4475b0fe478SBruce M Simpson #ifdef INET6
4485b0fe478SBruce M Simpson 		sin6 = (struct sockaddr_in6 *)&sa1.daddr;
4495b0fe478SBruce M Simpson 		if (inet_pton(AF_INET6, spikey, &sin6->sin6_addr) == 1) {
4505b0fe478SBruce M Simpson #ifdef HAVE_SOCKADDR_SA_LEN
4515b0fe478SBruce M Simpson 			sin6->sin6_len = sizeof(struct sockaddr_in6);
4525b0fe478SBruce M Simpson #endif
4535b0fe478SBruce M Simpson 			sin6->sin6_family = AF_INET6;
4545b0fe478SBruce M Simpson 		} else
4555b0fe478SBruce M Simpson #endif
4565b0fe478SBruce M Simpson 			if (inet_pton(AF_INET, spikey, &sin->sin_addr) == 1) {
4575b0fe478SBruce M Simpson #ifdef HAVE_SOCKADDR_SA_LEN
4585b0fe478SBruce M Simpson 				sin->sin_len = sizeof(struct sockaddr_in);
4595b0fe478SBruce M Simpson #endif
4605b0fe478SBruce M Simpson 				sin->sin_family = AF_INET;
4615b0fe478SBruce M Simpson 			} else {
4621de50e9fSSam Leffler 				(*ndo->ndo_warning)(ndo, "print_esp: can not decode IP# %s\n", spikey);
4635b0fe478SBruce M Simpson 				return;
4645b0fe478SBruce M Simpson 			}
4655b0fe478SBruce M Simpson 	}
4665b0fe478SBruce M Simpson 
4675b0fe478SBruce M Simpson 	if (decode) {
4685b0fe478SBruce M Simpson 		/* skip any blank spaces */
4695b0fe478SBruce M Simpson 		while (isspace((unsigned char)*decode))
4705b0fe478SBruce M Simpson 			decode++;
4715b0fe478SBruce M Simpson 
472*27df3f5dSRui Paulo 		if(!espprint_decode_encalgo(ndo, decode, &sa1)) {
473a90e161bSBill Fenner 			return;
474a90e161bSBill Fenner 		}
475a90e161bSBill Fenner 	}
476a90e161bSBill Fenner 
4771de50e9fSSam Leffler 	esp_print_addsa(ndo, &sa1, sa_def);
4785b0fe478SBruce M Simpson }
4795b0fe478SBruce M Simpson 
4801de50e9fSSam Leffler static void esp_init(netdissect_options *ndo _U_)
4815b0fe478SBruce M Simpson {
4825b0fe478SBruce M Simpson 
4835b0fe478SBruce M Simpson 	OpenSSL_add_all_algorithms();
4845b0fe478SBruce M Simpson 	EVP_add_cipher_alias(SN_des_ede3_cbc, "3des");
4855b0fe478SBruce M Simpson }
486*27df3f5dSRui Paulo 
487*27df3f5dSRui Paulo void esp_print_decodesecret(netdissect_options *ndo)
488*27df3f5dSRui Paulo {
489*27df3f5dSRui Paulo 	char *line;
490*27df3f5dSRui Paulo 	char *p;
491*27df3f5dSRui Paulo 	static int initialized = 0;
492*27df3f5dSRui Paulo 
493*27df3f5dSRui Paulo 	if (!initialized) {
494*27df3f5dSRui Paulo 		esp_init(ndo);
495*27df3f5dSRui Paulo 		initialized = 1;
496*27df3f5dSRui Paulo 	}
497*27df3f5dSRui Paulo 
498*27df3f5dSRui Paulo 	p = ndo->ndo_espsecret;
499*27df3f5dSRui Paulo 
500*27df3f5dSRui Paulo 	while (p && p[0] != '\0') {
501*27df3f5dSRui Paulo 		/* pick out the first line or first thing until a comma */
502*27df3f5dSRui Paulo 		if ((line = strsep(&p, "\n,")) == NULL) {
503*27df3f5dSRui Paulo 			line = p;
504*27df3f5dSRui Paulo 			p = NULL;
505*27df3f5dSRui Paulo 		}
506*27df3f5dSRui Paulo 
507*27df3f5dSRui Paulo 		esp_print_decode_onesecret(ndo, line, "cmdline", 0);
508*27df3f5dSRui Paulo 	}
509*27df3f5dSRui Paulo 
510*27df3f5dSRui Paulo 	ndo->ndo_espsecret = NULL;
511*27df3f5dSRui Paulo }
512*27df3f5dSRui Paulo 
5135b0fe478SBruce M Simpson #endif
5145b0fe478SBruce M Simpson 
5155b0fe478SBruce M Simpson int
5161de50e9fSSam Leffler esp_print(netdissect_options *ndo,
5171de50e9fSSam Leffler 	  const u_char *bp, const int length, const u_char *bp2
5185b0fe478SBruce M Simpson #ifndef HAVE_LIBCRYPTO
5195b0fe478SBruce M Simpson 	_U_
5205b0fe478SBruce M Simpson #endif
5215b0fe478SBruce M Simpson 	,
5225b0fe478SBruce M Simpson 	int *nhdr
5235b0fe478SBruce M Simpson #ifndef HAVE_LIBCRYPTO
5245b0fe478SBruce M Simpson 	_U_
5255b0fe478SBruce M Simpson #endif
5265b0fe478SBruce M Simpson 	,
5275b0fe478SBruce M Simpson 	int *padlen
5285b0fe478SBruce M Simpson #ifndef HAVE_LIBCRYPTO
5295b0fe478SBruce M Simpson 	_U_
5305b0fe478SBruce M Simpson #endif
5315b0fe478SBruce M Simpson 	)
5325b0fe478SBruce M Simpson {
5335b0fe478SBruce M Simpson 	register const struct newesp *esp;
534b0453382SBill Fenner 	register const u_char *ep;
5355b0fe478SBruce M Simpson #ifdef HAVE_LIBCRYPTO
5365b0fe478SBruce M Simpson 	struct ip *ip;
5375b0fe478SBruce M Simpson 	struct sa_list *sa = NULL;
5385b0fe478SBruce M Simpson 	int espsecret_keylen;
539b0453382SBill Fenner #ifdef INET6
540b0453382SBill Fenner 	struct ip6_hdr *ip6 = NULL;
541b0453382SBill Fenner #endif
542b0453382SBill Fenner 	int advance;
543b0453382SBill Fenner 	int len;
544f4d0c64aSSam Leffler 	u_char *secret;
545b0453382SBill Fenner 	int ivlen = 0;
546b0453382SBill Fenner 	u_char *ivoff;
5471de50e9fSSam Leffler 	u_char *p;
5485b0fe478SBruce M Simpson 	EVP_CIPHER_CTX ctx;
5495b0fe478SBruce M Simpson 	int blocksz;
5505b0fe478SBruce M Simpson #endif
551b0453382SBill Fenner 
5525b0fe478SBruce M Simpson 	esp = (struct newesp *)bp;
5535b0fe478SBruce M Simpson 
5545b0fe478SBruce M Simpson #ifdef HAVE_LIBCRYPTO
555a90e161bSBill Fenner 	secret = NULL;
5565b0fe478SBruce M Simpson 	advance = 0;
5575b0fe478SBruce M Simpson #endif
558a90e161bSBill Fenner 
559a90e161bSBill Fenner #if 0
560a90e161bSBill Fenner 	/* keep secret out of a register */
561a90e161bSBill Fenner 	p = (u_char *)&secret;
562a90e161bSBill Fenner #endif
563b0453382SBill Fenner 
564685295f4SBill Fenner 	/* 'ep' points to the end of available data. */
5651de50e9fSSam Leffler 	ep = ndo->ndo_snapend;
566b0453382SBill Fenner 
5675b0fe478SBruce M Simpson 	if ((u_char *)(esp + 1) >= ep) {
568b0453382SBill Fenner 		fputs("[|ESP]", stdout);
569b0453382SBill Fenner 		goto fail;
570b0453382SBill Fenner 	}
5711de50e9fSSam Leffler 	(*ndo->ndo_printf)(ndo, "ESP(spi=0x%08x", EXTRACT_32BITS(&esp->esp_spi));
5721de50e9fSSam Leffler 	(*ndo->ndo_printf)(ndo, ",seq=0x%x)", EXTRACT_32BITS(&esp->esp_seq));
5731de50e9fSSam Leffler         (*ndo->ndo_printf)(ndo, ", length %u", length);
574b0453382SBill Fenner 
5755b0fe478SBruce M Simpson #ifndef HAVE_LIBCRYPTO
5765b0fe478SBruce M Simpson 	goto fail;
5775b0fe478SBruce M Simpson #else
5785b0fe478SBruce M Simpson 	/* initiailize SAs */
5791de50e9fSSam Leffler 	if (ndo->ndo_sa_list_head == NULL) {
5801de50e9fSSam Leffler 		if (!ndo->ndo_espsecret)
581b0453382SBill Fenner 			goto fail;
582b0453382SBill Fenner 
5831de50e9fSSam Leffler 		esp_print_decodesecret(ndo);
584a90e161bSBill Fenner 	}
5855b0fe478SBruce M Simpson 
5861de50e9fSSam Leffler 	if (ndo->ndo_sa_list_head == NULL)
587a90e161bSBill Fenner 		goto fail;
588b0453382SBill Fenner 
589b0453382SBill Fenner 	ip = (struct ip *)bp2;
590685295f4SBill Fenner 	switch (IP_V(ip)) {
591b0453382SBill Fenner #ifdef INET6
592b0453382SBill Fenner 	case 6:
593b0453382SBill Fenner 		ip6 = (struct ip6_hdr *)bp2;
594b0453382SBill Fenner 		/* we do not attempt to decrypt jumbograms */
5955b0fe478SBruce M Simpson 		if (!EXTRACT_16BITS(&ip6->ip6_plen))
596b0453382SBill Fenner 			goto fail;
597b0453382SBill Fenner 		/* if we can't get nexthdr, we do not need to decrypt it */
5985b0fe478SBruce M Simpson 		len = sizeof(struct ip6_hdr) + EXTRACT_16BITS(&ip6->ip6_plen);
5995b0fe478SBruce M Simpson 
6005b0fe478SBruce M Simpson 		/* see if we can find the SA, and if so, decode it */
6011de50e9fSSam Leffler 		for (sa = ndo->ndo_sa_list_head; sa != NULL; sa = sa->next) {
6025b0fe478SBruce M Simpson 			struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&sa->daddr;
603*27df3f5dSRui Paulo 			if (sa->spi == EXTRACT_32BITS(&esp->esp_spi) &&
6045b0fe478SBruce M Simpson 			    sin6->sin6_family == AF_INET6 &&
6055b0fe478SBruce M Simpson 			    memcmp(&sin6->sin6_addr, &ip6->ip6_dst,
6065b0fe478SBruce M Simpson 				   sizeof(struct in6_addr)) == 0) {
6075b0fe478SBruce M Simpson 				break;
6085b0fe478SBruce M Simpson 			}
6095b0fe478SBruce M Simpson 		}
610b0453382SBill Fenner 		break;
611b0453382SBill Fenner #endif /*INET6*/
612b0453382SBill Fenner 	case 4:
613a90e161bSBill Fenner 		/* nexthdr & padding are in the last fragment */
6145b0fe478SBruce M Simpson 		if (EXTRACT_16BITS(&ip->ip_off) & IP_MF)
615a90e161bSBill Fenner 			goto fail;
6165b0fe478SBruce M Simpson 		len = EXTRACT_16BITS(&ip->ip_len);
6175b0fe478SBruce M Simpson 
6185b0fe478SBruce M Simpson 		/* see if we can find the SA, and if so, decode it */
6191de50e9fSSam Leffler 		for (sa = ndo->ndo_sa_list_head; sa != NULL; sa = sa->next) {
6205b0fe478SBruce M Simpson 			struct sockaddr_in *sin = (struct sockaddr_in *)&sa->daddr;
621*27df3f5dSRui Paulo 			if (sa->spi == EXTRACT_32BITS(&esp->esp_spi) &&
6225b0fe478SBruce M Simpson 			    sin->sin_family == AF_INET &&
6235b0fe478SBruce M Simpson 			    sin->sin_addr.s_addr == ip->ip_dst.s_addr) {
6245b0fe478SBruce M Simpson 				break;
6255b0fe478SBruce M Simpson 			}
6265b0fe478SBruce M Simpson 		}
627b0453382SBill Fenner 		break;
628b0453382SBill Fenner 	default:
629b0453382SBill Fenner 		goto fail;
630b0453382SBill Fenner 	}
631b0453382SBill Fenner 
6325b0fe478SBruce M Simpson 	/* if we didn't find the specific one, then look for
6335b0fe478SBruce M Simpson 	 * an unspecified one.
6345b0fe478SBruce M Simpson 	 */
6355b0fe478SBruce M Simpson 	if (sa == NULL)
6361de50e9fSSam Leffler 		sa = ndo->ndo_sa_default;
6375b0fe478SBruce M Simpson 
6385b0fe478SBruce M Simpson 	/* if not found fail */
6395b0fe478SBruce M Simpson 	if (sa == NULL)
6405b0fe478SBruce M Simpson 		goto fail;
6415b0fe478SBruce M Simpson 
642b0453382SBill Fenner 	/* if we can't get nexthdr, we do not need to decrypt it */
643b0453382SBill Fenner 	if (ep - bp2 < len)
644b0453382SBill Fenner 		goto fail;
6455b0fe478SBruce M Simpson 	if (ep - bp2 > len) {
6465b0fe478SBruce M Simpson 		/* FCS included at end of frame (NetBSD 1.6 or later) */
6475b0fe478SBruce M Simpson 		ep = bp2 + len;
648b0453382SBill Fenner 	}
649b0453382SBill Fenner 
6505b0fe478SBruce M Simpson 	ivoff = (u_char *)(esp + 1) + 0;
6515b0fe478SBruce M Simpson 	ivlen = sa->ivlen;
6525b0fe478SBruce M Simpson 	secret = sa->secret;
6535b0fe478SBruce M Simpson 	espsecret_keylen = sa->secretlen;
6541de50e9fSSam Leffler 	ep = ep - sa->authlen;
655b0453382SBill Fenner 
6565b0fe478SBruce M Simpson 	if (sa->evp) {
6575b0fe478SBruce M Simpson 		memset(&ctx, 0, sizeof(ctx));
6585b0fe478SBruce M Simpson 		if (EVP_CipherInit(&ctx, sa->evp, secret, NULL, 0) < 0)
6591de50e9fSSam Leffler 			(*ndo->ndo_warning)(ndo, "espkey init failed");
6605b0fe478SBruce M Simpson 
6615b0fe478SBruce M Simpson 		blocksz = EVP_CIPHER_CTX_block_size(&ctx);
6625b0fe478SBruce M Simpson 
6635b0fe478SBruce M Simpson 		p = ivoff;
6645b0fe478SBruce M Simpson 		EVP_CipherInit(&ctx, NULL, NULL, p, 0);
6655b0fe478SBruce M Simpson 		EVP_Cipher(&ctx, p + ivlen, p + ivlen, ep - (p + ivlen));
666*27df3f5dSRui Paulo 		EVP_CIPHER_CTX_cleanup(&ctx);
667b0453382SBill Fenner 		advance = ivoff - (u_char *)esp + ivlen;
6685b0fe478SBruce M Simpson 	} else
6695b0fe478SBruce M Simpson 		advance = sizeof(struct newesp);
670b0453382SBill Fenner 
671b0453382SBill Fenner 	/* sanity check for pad length */
672b0453382SBill Fenner 	if (ep - bp < *(ep - 2))
673b0453382SBill Fenner 		goto fail;
674b0453382SBill Fenner 
675a90e161bSBill Fenner 	if (padlen)
676a90e161bSBill Fenner 		*padlen = *(ep - 2) + 2;
677a90e161bSBill Fenner 
678b0453382SBill Fenner 	if (nhdr)
679b0453382SBill Fenner 		*nhdr = *(ep - 1);
680b0453382SBill Fenner 
6811de50e9fSSam Leffler 	(ndo->ndo_printf)(ndo, ": ");
682b0453382SBill Fenner 	return advance;
6835b0fe478SBruce M Simpson #endif
684b0453382SBill Fenner 
685b0453382SBill Fenner fail:
6865b0fe478SBruce M Simpson 	return -1;
687b0453382SBill Fenner }
6881de50e9fSSam Leffler 
6891de50e9fSSam Leffler /*
6901de50e9fSSam Leffler  * Local Variables:
6911de50e9fSSam Leffler  * c-style: whitesmith
6921de50e9fSSam Leffler  * c-basic-offset: 8
6931de50e9fSSam Leffler  * End:
6941de50e9fSSam Leffler  */
695