156893Sfenner/*	$NetBSD: print-ah.c,v 1.4 1996/05/20 00:41:16 fvdl Exp $	*/
256893Sfenner
356893Sfenner/*
456893Sfenner * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994
556893Sfenner *	The Regents of the University of California.  All rights reserved.
656893Sfenner *
756893Sfenner * Redistribution and use in source and binary forms, with or without
856893Sfenner * modification, are permitted provided that: (1) source code distributions
956893Sfenner * retain the above copyright notice and this paragraph in its entirety, (2)
1056893Sfenner * distributions including binary code include the above copyright notice and
1156893Sfenner * this paragraph in its entirety in the documentation or other materials
1256893Sfenner * provided with the distribution, and (3) all advertising materials mentioning
1356893Sfenner * features or use of this software display the following acknowledgement:
1456893Sfenner * ``This product includes software developed by the University of California,
1556893Sfenner * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
1656893Sfenner * the University nor the names of its contributors may be used to endorse
1756893Sfenner * or promote products derived from this software without specific prior
1856893Sfenner * written permission.
1956893Sfenner * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
2056893Sfenner * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
2156893Sfenner * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
2256893Sfenner */
2356893Sfenner
2456893Sfenner#ifndef lint
25127668Sbmsstatic const char rcsid[] _U_ =
26214478Srpaulo    "@(#) $Header: /tcpdump/master/tcpdump/print-esp.c,v 1.58 2007-12-07 00:03:07 mcr Exp $ (LBL)";
2756893Sfenner#endif
2856893Sfenner
2956893Sfenner#ifdef HAVE_CONFIG_H
3056893Sfenner#include "config.h"
3156893Sfenner#endif
3256893Sfenner
3356893Sfenner#include <string.h>
34127668Sbms
35127668Sbms#include <tcpdump-stdinc.h>
36127668Sbms
37111726Sfenner#include <stdlib.h>
3856893Sfenner
3975115Sfenner#ifdef HAVE_LIBCRYPTO
40127668Sbms#ifdef HAVE_OPENSSL_EVP_H
41127668Sbms#include <openssl/evp.h>
4256893Sfenner#endif
4356893Sfenner#endif
4456893Sfenner
4556893Sfenner#include <stdio.h>
4656893Sfenner
4775115Sfenner#include "ip.h"
4875115Sfenner#include "esp.h"
4956893Sfenner#ifdef INET6
5075115Sfenner#include "ip6.h"
5156893Sfenner#endif
5256893Sfenner
53146773Ssam#include "netdissect.h"
5456893Sfenner#include "addrtoname.h"
55127668Sbms#include "extract.h"
5656893Sfenner
57127668Sbms#ifndef HAVE_SOCKADDR_STORAGE
58127668Sbms#ifdef INET6
59127668Sbmsstruct sockaddr_storage {
60127668Sbms	union {
61127668Sbms		struct sockaddr_in sin;
62127668Sbms		struct sockaddr_in6 sin6;
63127668Sbms	} un;
64127668Sbms};
65127668Sbms#else
66127668Sbms#define sockaddr_storage sockaddr
67127668Sbms#endif
68127668Sbms#endif /* HAVE_SOCKADDR_STORAGE */
6998524Sfenner
70127668Sbms#ifdef HAVE_LIBCRYPTO
71127668Sbmsstruct sa_list {
72127668Sbms	struct sa_list	*next;
73127668Sbms	struct sockaddr_storage daddr;
74214478Srpaulo	u_int32_t	spi;          /* if == 0, then IKEv2 */
75214478Srpaulo	int             initiator;
76214478Srpaulo	u_char          spii[8];      /* for IKEv2 */
77214478Srpaulo	u_char          spir[8];
78127668Sbms	const EVP_CIPHER *evp;
79127668Sbms	int		ivlen;
80127668Sbms	int		authlen;
81214478Srpaulo	u_char          authsecret[256];
82214478Srpaulo	int             authsecret_len;
83147899Ssam	u_char		secret[256];  /* is that big enough for all secrets? */
84127668Sbms	int		secretlen;
85127668Sbms};
8698524Sfenner
87214478Srpaulo/*
88214478Srpaulo * this will adjust ndo_packetp and ndo_snapend to new buffer!
89214478Srpaulo */
90214478Srpauloint esp_print_decrypt_buffer_by_ikev2(netdissect_options *ndo,
91214478Srpaulo				      int initiator,
92214478Srpaulo				      u_char spii[8], u_char spir[8],
93214478Srpaulo				      u_char *buf, u_char *end)
94214478Srpaulo{
95214478Srpaulo	struct sa_list *sa;
96214478Srpaulo	u_char *iv;
97214478Srpaulo	int len;
98214478Srpaulo	EVP_CIPHER_CTX ctx;
99214478Srpaulo
100214478Srpaulo	/* initiator arg is any non-zero value */
101214478Srpaulo	if(initiator) initiator=1;
102214478Srpaulo
103214478Srpaulo	/* see if we can find the SA, and if so, decode it */
104214478Srpaulo	for (sa = ndo->ndo_sa_list_head; sa != NULL; sa = sa->next) {
105214478Srpaulo		if (sa->spi == 0
106214478Srpaulo		    && initiator == sa->initiator
107214478Srpaulo		    && memcmp(spii, sa->spii, 8) == 0
108214478Srpaulo		    && memcmp(spir, sa->spir, 8) == 0)
109214478Srpaulo			break;
110214478Srpaulo	}
111214478Srpaulo
112214478Srpaulo	if(sa == NULL) return 0;
113214478Srpaulo	if(sa->evp == NULL) return 0;
114214478Srpaulo
115214478Srpaulo	/*
116214478Srpaulo	 * remove authenticator, and see if we still have something to
117214478Srpaulo	 * work with
118214478Srpaulo	 */
119214478Srpaulo	end = end - sa->authlen;
120214478Srpaulo	iv  = buf;
121214478Srpaulo	buf = buf + sa->ivlen;
122214478Srpaulo	len = end-buf;
123214478Srpaulo
124214478Srpaulo	if(end <= buf) return 0;
125214478Srpaulo
126214478Srpaulo	memset(&ctx, 0, sizeof(ctx));
127214478Srpaulo	if (EVP_CipherInit(&ctx, sa->evp, sa->secret, NULL, 0) < 0)
128214478Srpaulo		(*ndo->ndo_warning)(ndo, "espkey init failed");
129214478Srpaulo	EVP_CipherInit(&ctx, NULL, NULL, iv, 0);
130214478Srpaulo	EVP_Cipher(&ctx, buf, buf, len);
131214478Srpaulo	EVP_CIPHER_CTX_cleanup(&ctx);
132214478Srpaulo
133214478Srpaulo	ndo->ndo_packetp = buf;
134214478Srpaulo	ndo->ndo_snapend = end;
135214478Srpaulo
136214478Srpaulo	return 1;
137214478Srpaulo
138214478Srpaulo}
139214478Srpaulo
140146773Ssamstatic void esp_print_addsa(netdissect_options *ndo,
141146773Ssam			    struct sa_list *sa, int sa_def)
142127668Sbms{
143127668Sbms	/* copy the "sa" */
14498524Sfenner
145127668Sbms	struct sa_list *nsa;
14698524Sfenner
147127668Sbms	nsa = (struct sa_list *)malloc(sizeof(struct sa_list));
148127668Sbms	if (nsa == NULL)
149146773Ssam		(*ndo->ndo_error)(ndo, "ran out of memory to allocate sa structure");
15098524Sfenner
151127668Sbms	*nsa = *sa;
15298524Sfenner
153127668Sbms	if (sa_def)
154146773Ssam		ndo->ndo_sa_default = nsa;
155127668Sbms
156146773Ssam	nsa->next = ndo->ndo_sa_list_head;
157146773Ssam	ndo->ndo_sa_list_head = nsa;
158127668Sbms}
159127668Sbms
160127668Sbms
161147899Ssamstatic u_int hexdigit(netdissect_options *ndo, char hex)
16298524Sfenner{
163127668Sbms	if (hex >= '0' && hex <= '9')
16498524Sfenner		return (hex - '0');
165127668Sbms	else if (hex >= 'A' && hex <= 'F')
16698524Sfenner		return (hex - 'A' + 10);
167127668Sbms	else if (hex >= 'a' && hex <= 'f')
16898524Sfenner		return (hex - 'a' + 10);
169127668Sbms	else {
170146773Ssam		(*ndo->ndo_error)(ndo, "invalid hex digit %c in espsecret\n", hex);
17198524Sfenner		return 0;
17298524Sfenner	}
17398524Sfenner}
17498524Sfenner
175147899Ssamstatic u_int hex2byte(netdissect_options *ndo, char *hexstring)
17698524Sfenner{
177147899Ssam	u_int byte;
17898524Sfenner
179146773Ssam	byte = (hexdigit(ndo, hexstring[0]) << 4) + hexdigit(ndo, hexstring[1]);
18098524Sfenner	return byte;
18198524Sfenner}
18298524Sfenner
183127668Sbms/*
184214478Srpaulo * returns size of binary, 0 on failure.
185214478Srpaulo */
186214478Srpaulostatic
187214478Srpauloint espprint_decode_hex(netdissect_options *ndo,
188214478Srpaulo			u_char *binbuf, unsigned int binbuf_len,
189214478Srpaulo			char *hex)
190214478Srpaulo{
191214478Srpaulo	unsigned int len;
192214478Srpaulo	int i;
193214478Srpaulo
194214478Srpaulo	len = strlen(hex) / 2;
195214478Srpaulo
196214478Srpaulo	if (len > binbuf_len) {
197214478Srpaulo		(*ndo->ndo_warning)(ndo, "secret is too big: %d\n", len);
198214478Srpaulo		return 0;
199214478Srpaulo	}
200214478Srpaulo
201214478Srpaulo	i = 0;
202214478Srpaulo	while (hex[0] != '\0' && hex[1]!='\0') {
203214478Srpaulo		binbuf[i] = hex2byte(ndo, hex);
204214478Srpaulo		hex += 2;
205214478Srpaulo		i++;
206214478Srpaulo	}
207214478Srpaulo
208214478Srpaulo	return i;
209214478Srpaulo}
210214478Srpaulo
211214478Srpaulo/*
212127668Sbms * decode the form:    SPINUM@IP <tab> ALGONAME:0xsecret
213214478Srpaulo */
214214478Srpaulo
215214478Srpaulostatic int
216214478Srpauloespprint_decode_encalgo(netdissect_options *ndo,
217214478Srpaulo			char *decode, struct sa_list *sa)
218214478Srpaulo{
219214478Srpaulo	int len;
220214478Srpaulo	size_t i;
221214478Srpaulo	const EVP_CIPHER *evp;
222214478Srpaulo	int authlen = 0;
223214478Srpaulo	char *colon, *p;
224214478Srpaulo
225214478Srpaulo	colon = strchr(decode, ':');
226214478Srpaulo	if (colon == NULL) {
227214478Srpaulo		(*ndo->ndo_warning)(ndo, "failed to decode espsecret: %s\n", decode);
228214478Srpaulo		return 0;
229214478Srpaulo	}
230214478Srpaulo	*colon = '\0';
231214478Srpaulo
232214478Srpaulo	len = colon - decode;
233214478Srpaulo	if (strlen(decode) > strlen("-hmac96") &&
234214478Srpaulo	    !strcmp(decode + strlen(decode) - strlen("-hmac96"),
235214478Srpaulo		    "-hmac96")) {
236214478Srpaulo		p = strstr(decode, "-hmac96");
237214478Srpaulo		*p = '\0';
238214478Srpaulo		authlen = 12;
239214478Srpaulo	}
240214478Srpaulo	if (strlen(decode) > strlen("-cbc") &&
241214478Srpaulo	    !strcmp(decode + strlen(decode) - strlen("-cbc"), "-cbc")) {
242214478Srpaulo		p = strstr(decode, "-cbc");
243214478Srpaulo		*p = '\0';
244214478Srpaulo	}
245214478Srpaulo	evp = EVP_get_cipherbyname(decode);
246214478Srpaulo
247214478Srpaulo	if (!evp) {
248214478Srpaulo		(*ndo->ndo_warning)(ndo, "failed to find cipher algo %s\n", decode);
249214478Srpaulo		sa->evp = NULL;
250214478Srpaulo		sa->authlen = 0;
251214478Srpaulo		sa->ivlen = 0;
252214478Srpaulo		return 0;
253214478Srpaulo	}
254214478Srpaulo
255214478Srpaulo	sa->evp = evp;
256214478Srpaulo	sa->authlen = authlen;
257214478Srpaulo	sa->ivlen = EVP_CIPHER_iv_length(evp);
258214478Srpaulo
259214478Srpaulo	colon++;
260214478Srpaulo	if (colon[0] == '0' && colon[1] == 'x') {
261214478Srpaulo		/* decode some hex! */
262214478Srpaulo
263214478Srpaulo		colon += 2;
264214478Srpaulo		sa->secretlen = espprint_decode_hex(ndo, sa->secret, sizeof(sa->secret), colon);
265214478Srpaulo		if(sa->secretlen == 0) return 0;
266214478Srpaulo	} else {
267214478Srpaulo		i = strlen(colon);
268214478Srpaulo
269214478Srpaulo		if (i < sizeof(sa->secret)) {
270214478Srpaulo			memcpy(sa->secret, colon, i);
271214478Srpaulo			sa->secretlen = i;
272214478Srpaulo		} else {
273214478Srpaulo			memcpy(sa->secret, colon, sizeof(sa->secret));
274214478Srpaulo			sa->secretlen = sizeof(sa->secret);
275214478Srpaulo		}
276214478Srpaulo	}
277214478Srpaulo
278214478Srpaulo	return 1;
279214478Srpaulo}
280214478Srpaulo
281214478Srpaulo/*
282214478Srpaulo * for the moment, ignore the auth algorith, just hard code the authenticator
283214478Srpaulo * length. Need to research how openssl looks up HMAC stuff.
284214478Srpaulo */
285214478Srpaulostatic int
286214478Srpauloespprint_decode_authalgo(netdissect_options *ndo,
287214478Srpaulo			 char *decode, struct sa_list *sa)
288214478Srpaulo{
289214478Srpaulo	char *colon;
290214478Srpaulo
291214478Srpaulo	colon = strchr(decode, ':');
292214478Srpaulo	if (colon == NULL) {
293214478Srpaulo		(*ndo->ndo_warning)(ndo, "failed to decode espsecret: %s\n", decode);
294214478Srpaulo		return 0;
295214478Srpaulo	}
296214478Srpaulo	*colon = '\0';
297214478Srpaulo
298214478Srpaulo	if(strcasecmp(colon,"sha1") == 0 ||
299214478Srpaulo	   strcasecmp(colon,"md5") == 0) {
300214478Srpaulo		sa->authlen = 12;
301214478Srpaulo	}
302214478Srpaulo	return 1;
303214478Srpaulo}
304214478Srpaulo
305214478Srpaulostatic void esp_print_decode_ikeline(netdissect_options *ndo, char *line,
306214478Srpaulo				     const char *file, int lineno)
307214478Srpaulo{
308214478Srpaulo	/* it's an IKEv2 secret, store it instead */
309214478Srpaulo	struct sa_list sa1;
310214478Srpaulo
311214478Srpaulo	char *init;
312214478Srpaulo	char *icookie, *rcookie;
313214478Srpaulo	int   ilen, rlen;
314214478Srpaulo	char *authkey;
315214478Srpaulo	char *enckey;
316214478Srpaulo
317214478Srpaulo	init = strsep(&line, " \t");
318214478Srpaulo	icookie = strsep(&line, " \t");
319214478Srpaulo	rcookie = strsep(&line, " \t");
320214478Srpaulo	authkey = strsep(&line, " \t");
321214478Srpaulo	enckey  = strsep(&line, " \t");
322214478Srpaulo
323214478Srpaulo	/* if any fields are missing */
324214478Srpaulo	if(!init || !icookie || !rcookie || !authkey || !enckey) {
325214478Srpaulo		(*ndo->ndo_warning)(ndo, "print_esp: failed to find all fields for ikev2 at %s:%u",
326214478Srpaulo				    file, lineno);
327214478Srpaulo
328214478Srpaulo		return;
329214478Srpaulo	}
330214478Srpaulo
331214478Srpaulo	ilen = strlen(icookie);
332214478Srpaulo	rlen = strlen(rcookie);
333214478Srpaulo
334214478Srpaulo	if((init[0]!='I' && init[0]!='R')
335214478Srpaulo	   || icookie[0]!='0' || icookie[1]!='x'
336214478Srpaulo	   || rcookie[0]!='0' || rcookie[1]!='x'
337214478Srpaulo	   || ilen!=18
338214478Srpaulo	   || rlen!=18) {
339214478Srpaulo		(*ndo->ndo_warning)(ndo, "print_esp: line %s:%u improperly formatted.",
340214478Srpaulo				    file, lineno);
341214478Srpaulo
342214478Srpaulo		(*ndo->ndo_warning)(ndo, "init=%s icookie=%s(%u) rcookie=%s(%u)",
343214478Srpaulo				    init, icookie, ilen, rcookie, rlen);
344214478Srpaulo
345214478Srpaulo		return;
346214478Srpaulo	}
347214478Srpaulo
348214478Srpaulo	sa1.spi = 0;
349214478Srpaulo	sa1.initiator = (init[0] == 'I');
350214478Srpaulo	if(espprint_decode_hex(ndo, sa1.spii, sizeof(sa1.spii), icookie+2)!=8)
351214478Srpaulo		return;
352214478Srpaulo
353214478Srpaulo	if(espprint_decode_hex(ndo, sa1.spir, sizeof(sa1.spir), rcookie+2)!=8)
354214478Srpaulo		return;
355214478Srpaulo
356214478Srpaulo	if(!espprint_decode_encalgo(ndo, enckey, &sa1)) return;
357214478Srpaulo
358214478Srpaulo	if(!espprint_decode_authalgo(ndo, authkey, &sa1)) return;
359214478Srpaulo
360214478Srpaulo	esp_print_addsa(ndo, &sa1, FALSE);
361214478Srpaulo}
362214478Srpaulo
363214478Srpaulo/*
364127668Sbms *
365127668Sbms * special form: file /name
366127668Sbms * causes us to go read from this file instead.
367127668Sbms *
368127668Sbms */
369214478Srpaulostatic void esp_print_decode_onesecret(netdissect_options *ndo, char *line,
370214478Srpaulo				       const char *file, int lineno)
37198524Sfenner{
372127668Sbms	struct sa_list sa1;
373127668Sbms	int sa_def;
37498524Sfenner
375127668Sbms	char *spikey;
376127668Sbms	char *decode;
37798524Sfenner
378127668Sbms	spikey = strsep(&line, " \t");
379127668Sbms	sa_def = 0;
380127668Sbms	memset(&sa1, 0, sizeof(struct sa_list));
381127668Sbms
382127668Sbms	/* if there is only one token, then it is an algo:key token */
383127668Sbms	if (line == NULL) {
384127668Sbms		decode = spikey;
385127668Sbms		spikey = NULL;
386127668Sbms		/* memset(&sa1.daddr, 0, sizeof(sa1.daddr)); */
387127668Sbms		/* sa1.spi = 0; */
388127668Sbms		sa_def    = 1;
389127668Sbms	} else
390127668Sbms		decode = line;
391127668Sbms
392127668Sbms	if (spikey && strcasecmp(spikey, "file") == 0) {
393127668Sbms		/* open file and read it */
394127668Sbms		FILE *secretfile;
395127668Sbms		char  fileline[1024];
396214478Srpaulo		int   lineno=0;
397127668Sbms		char  *nl;
398214478Srpaulo		char *filename = line;
399127668Sbms
400214478Srpaulo		secretfile = fopen(filename, FOPEN_READ_TXT);
401127668Sbms		if (secretfile == NULL) {
402214478Srpaulo			perror(filename);
403127668Sbms			exit(3);
404127668Sbms		}
405127668Sbms
406127668Sbms		while (fgets(fileline, sizeof(fileline)-1, secretfile) != NULL) {
407214478Srpaulo			lineno++;
408127668Sbms			/* remove newline from the line */
409127668Sbms			nl = strchr(fileline, '\n');
410127668Sbms			if (nl)
411127668Sbms				*nl = '\0';
412127668Sbms			if (fileline[0] == '#') continue;
413127668Sbms			if (fileline[0] == '\0') continue;
414127668Sbms
415214478Srpaulo			esp_print_decode_onesecret(ndo, fileline, filename, lineno);
416127668Sbms		}
417127668Sbms		fclose(secretfile);
418127668Sbms
41998524Sfenner		return;
42098524Sfenner	}
42198524Sfenner
422214478Srpaulo	if (spikey && strcasecmp(spikey, "ikev2") == 0) {
423214478Srpaulo		esp_print_decode_ikeline(ndo, line, file, lineno);
424214478Srpaulo		return;
425214478Srpaulo	}
426214478Srpaulo
427127668Sbms	if (spikey) {
428214478Srpaulo
429127668Sbms		char *spistr, *foo;
430127668Sbms		u_int32_t spino;
431127668Sbms		struct sockaddr_in *sin;
432127668Sbms#ifdef INET6
433127668Sbms		struct sockaddr_in6 *sin6;
434127668Sbms#endif
435214478Srpaulo
436127668Sbms		spistr = strsep(&spikey, "@");
437214478Srpaulo
438127668Sbms		spino = strtoul(spistr, &foo, 0);
439127668Sbms		if (spistr == foo || !spikey) {
440146773Ssam			(*ndo->ndo_warning)(ndo, "print_esp: failed to decode spi# %s\n", foo);
441127668Sbms			return;
442127668Sbms		}
443214478Srpaulo
444127668Sbms		sa1.spi = spino;
445214478Srpaulo
446127668Sbms		sin = (struct sockaddr_in *)&sa1.daddr;
447127668Sbms#ifdef INET6
448127668Sbms		sin6 = (struct sockaddr_in6 *)&sa1.daddr;
449127668Sbms		if (inet_pton(AF_INET6, spikey, &sin6->sin6_addr) == 1) {
450127668Sbms#ifdef HAVE_SOCKADDR_SA_LEN
451127668Sbms			sin6->sin6_len = sizeof(struct sockaddr_in6);
452127668Sbms#endif
453127668Sbms			sin6->sin6_family = AF_INET6;
454127668Sbms		} else
455127668Sbms#endif
456214478Srpaulo			if (inet_pton(AF_INET, spikey, &sin->sin_addr) == 1) {
457127668Sbms#ifdef HAVE_SOCKADDR_SA_LEN
458214478Srpaulo				sin->sin_len = sizeof(struct sockaddr_in);
459127668Sbms#endif
460214478Srpaulo				sin->sin_family = AF_INET;
461214478Srpaulo			} else {
462214478Srpaulo				(*ndo->ndo_warning)(ndo, "print_esp: can not decode IP# %s\n", spikey);
463214478Srpaulo				return;
464214478Srpaulo			}
46598524Sfenner	}
46698524Sfenner
467127668Sbms	if (decode) {
468127668Sbms		/* skip any blank spaces */
469127668Sbms		while (isspace((unsigned char)*decode))
470127668Sbms			decode++;
471214478Srpaulo
472214478Srpaulo		if(!espprint_decode_encalgo(ndo, decode, &sa1)) {
473127668Sbms			return;
47498524Sfenner		}
47598524Sfenner	}
476127668Sbms
477146773Ssam	esp_print_addsa(ndo, &sa1, sa_def);
47898524Sfenner}
47998524Sfenner
480214478Srpaulostatic void esp_init(netdissect_options *ndo _U_)
481127668Sbms{
482214478Srpaulo
483214478Srpaulo	OpenSSL_add_all_algorithms();
484214478Srpaulo	EVP_add_cipher_alias(SN_des_ede3_cbc, "3des");
485214478Srpaulo}
486214478Srpaulo
487214478Srpaulovoid esp_print_decodesecret(netdissect_options *ndo)
488214478Srpaulo{
489127668Sbms	char *line;
490127668Sbms	char *p;
491214478Srpaulo	static int initialized = 0;
492127668Sbms
493214478Srpaulo	if (!initialized) {
494214478Srpaulo		esp_init(ndo);
495214478Srpaulo		initialized = 1;
496214478Srpaulo	}
497214478Srpaulo
498146773Ssam	p = ndo->ndo_espsecret;
499127668Sbms
500214478Srpaulo	while (p && p[0] != '\0') {
501127668Sbms		/* pick out the first line or first thing until a comma */
502214478Srpaulo		if ((line = strsep(&p, "\n,")) == NULL) {
503214478Srpaulo			line = p;
504214478Srpaulo			p = NULL;
505127668Sbms		}
506127668Sbms
507214478Srpaulo		esp_print_decode_onesecret(ndo, line, "cmdline", 0);
508127668Sbms	}
509214478Srpaulo
510214478Srpaulo	ndo->ndo_espsecret = NULL;
511127668Sbms}
512127668Sbms
513127668Sbms#endif
514127668Sbms
51556893Sfennerint
516146773Ssamesp_print(netdissect_options *ndo,
517146773Ssam	  const u_char *bp, const int length, const u_char *bp2
518127668Sbms#ifndef HAVE_LIBCRYPTO
519127668Sbms	_U_
520127668Sbms#endif
521127668Sbms	,
522127668Sbms	int *nhdr
523127668Sbms#ifndef HAVE_LIBCRYPTO
524127668Sbms	_U_
525127668Sbms#endif
526127668Sbms	,
527127668Sbms	int *padlen
528127668Sbms#ifndef HAVE_LIBCRYPTO
529127668Sbms	_U_
530127668Sbms#endif
531127668Sbms	)
53256893Sfenner{
533127668Sbms	register const struct newesp *esp;
53456893Sfenner	register const u_char *ep;
535127668Sbms#ifdef HAVE_LIBCRYPTO
536127668Sbms	struct ip *ip;
537127668Sbms	struct sa_list *sa = NULL;
538127668Sbms	int espsecret_keylen;
53956893Sfenner#ifdef INET6
54056893Sfenner	struct ip6_hdr *ip6 = NULL;
54156893Sfenner#endif
54256893Sfenner	int advance;
54356893Sfenner	int len;
544147899Ssam	u_char *secret;
54556893Sfenner	int ivlen = 0;
54656893Sfenner	u_char *ivoff;
547146773Ssam	u_char *p;
548127668Sbms	EVP_CIPHER_CTX ctx;
549127668Sbms	int blocksz;
550127668Sbms#endif
551127668Sbms
552127668Sbms	esp = (struct newesp *)bp;
553127668Sbms
554127668Sbms#ifdef HAVE_LIBCRYPTO
55598524Sfenner	secret = NULL;
556127668Sbms	advance = 0;
557127668Sbms#endif
558127668Sbms
55998524Sfenner#if 0
56098524Sfenner	/* keep secret out of a register */
56198524Sfenner	p = (u_char *)&secret;
56298524Sfenner#endif
56398524Sfenner
56475115Sfenner	/* 'ep' points to the end of available data. */
565146773Ssam	ep = ndo->ndo_snapend;
56656893Sfenner
567127668Sbms	if ((u_char *)(esp + 1) >= ep) {
56856893Sfenner		fputs("[|ESP]", stdout);
56956893Sfenner		goto fail;
57056893Sfenner	}
571146773Ssam	(*ndo->ndo_printf)(ndo, "ESP(spi=0x%08x", EXTRACT_32BITS(&esp->esp_spi));
572146773Ssam	(*ndo->ndo_printf)(ndo, ",seq=0x%x)", EXTRACT_32BITS(&esp->esp_seq));
573146773Ssam        (*ndo->ndo_printf)(ndo, ", length %u", length);
57456893Sfenner
575127668Sbms#ifndef HAVE_LIBCRYPTO
576127668Sbms	goto fail;
577127668Sbms#else
578127668Sbms	/* initiailize SAs */
579146773Ssam	if (ndo->ndo_sa_list_head == NULL) {
580146773Ssam		if (!ndo->ndo_espsecret)
581127668Sbms			goto fail;
58256893Sfenner
583146773Ssam		esp_print_decodesecret(ndo);
58456893Sfenner	}
585127668Sbms
586146773Ssam	if (ndo->ndo_sa_list_head == NULL)
58798524Sfenner		goto fail;
58856893Sfenner
58956893Sfenner	ip = (struct ip *)bp2;
59075115Sfenner	switch (IP_V(ip)) {
59156893Sfenner#ifdef INET6
59256893Sfenner	case 6:
59356893Sfenner		ip6 = (struct ip6_hdr *)bp2;
59456893Sfenner		/* we do not attempt to decrypt jumbograms */
595127668Sbms		if (!EXTRACT_16BITS(&ip6->ip6_plen))
59656893Sfenner			goto fail;
59756893Sfenner		/* if we can't get nexthdr, we do not need to decrypt it */
598127668Sbms		len = sizeof(struct ip6_hdr) + EXTRACT_16BITS(&ip6->ip6_plen);
599127668Sbms
600127668Sbms		/* see if we can find the SA, and if so, decode it */
601146773Ssam		for (sa = ndo->ndo_sa_list_head; sa != NULL; sa = sa->next) {
602127668Sbms			struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&sa->daddr;
603214478Srpaulo			if (sa->spi == EXTRACT_32BITS(&esp->esp_spi) &&
604127668Sbms			    sin6->sin6_family == AF_INET6 &&
605127668Sbms			    memcmp(&sin6->sin6_addr, &ip6->ip6_dst,
606127668Sbms				   sizeof(struct in6_addr)) == 0) {
607127668Sbms				break;
608127668Sbms			}
609127668Sbms		}
61056893Sfenner		break;
61156893Sfenner#endif /*INET6*/
61256893Sfenner	case 4:
61398524Sfenner		/* nexthdr & padding are in the last fragment */
614127668Sbms		if (EXTRACT_16BITS(&ip->ip_off) & IP_MF)
61598524Sfenner			goto fail;
616127668Sbms		len = EXTRACT_16BITS(&ip->ip_len);
617127668Sbms
618127668Sbms		/* see if we can find the SA, and if so, decode it */
619146773Ssam		for (sa = ndo->ndo_sa_list_head; sa != NULL; sa = sa->next) {
620127668Sbms			struct sockaddr_in *sin = (struct sockaddr_in *)&sa->daddr;
621214478Srpaulo			if (sa->spi == EXTRACT_32BITS(&esp->esp_spi) &&
622127668Sbms			    sin->sin_family == AF_INET &&
623127668Sbms			    sin->sin_addr.s_addr == ip->ip_dst.s_addr) {
624127668Sbms				break;
625127668Sbms			}
626127668Sbms		}
62756893Sfenner		break;
62856893Sfenner	default:
62956893Sfenner		goto fail;
63056893Sfenner	}
63156893Sfenner
632127668Sbms	/* if we didn't find the specific one, then look for
633127668Sbms	 * an unspecified one.
634127668Sbms	 */
635127668Sbms	if (sa == NULL)
636146773Ssam		sa = ndo->ndo_sa_default;
637127668Sbms
638127668Sbms	/* if not found fail */
639127668Sbms	if (sa == NULL)
640127668Sbms		goto fail;
641127668Sbms
64256893Sfenner	/* if we can't get nexthdr, we do not need to decrypt it */
64356893Sfenner	if (ep - bp2 < len)
64456893Sfenner		goto fail;
645127668Sbms	if (ep - bp2 > len) {
646127668Sbms		/* FCS included at end of frame (NetBSD 1.6 or later) */
647127668Sbms		ep = bp2 + len;
648127668Sbms	}
64956893Sfenner
650127668Sbms	ivoff = (u_char *)(esp + 1) + 0;
651127668Sbms	ivlen = sa->ivlen;
652127668Sbms	secret = sa->secret;
653127668Sbms	espsecret_keylen = sa->secretlen;
654146773Ssam	ep = ep - sa->authlen;
65556893Sfenner
656127668Sbms	if (sa->evp) {
657127668Sbms		memset(&ctx, 0, sizeof(ctx));
658127668Sbms		if (EVP_CipherInit(&ctx, sa->evp, secret, NULL, 0) < 0)
659146773Ssam			(*ndo->ndo_warning)(ndo, "espkey init failed");
66056893Sfenner
661127668Sbms		blocksz = EVP_CIPHER_CTX_block_size(&ctx);
66256893Sfenner
663127668Sbms		p = ivoff;
664127668Sbms		EVP_CipherInit(&ctx, NULL, NULL, p, 0);
665127668Sbms		EVP_Cipher(&ctx, p + ivlen, p + ivlen, ep - (p + ivlen));
666214478Srpaulo		EVP_CIPHER_CTX_cleanup(&ctx);
66756893Sfenner		advance = ivoff - (u_char *)esp + ivlen;
668127668Sbms	} else
669127668Sbms		advance = sizeof(struct newesp);
67056893Sfenner
67156893Sfenner	/* sanity check for pad length */
67256893Sfenner	if (ep - bp < *(ep - 2))
67356893Sfenner		goto fail;
67456893Sfenner
67598524Sfenner	if (padlen)
67698524Sfenner		*padlen = *(ep - 2) + 2;
67798524Sfenner
67856893Sfenner	if (nhdr)
67956893Sfenner		*nhdr = *(ep - 1);
68056893Sfenner
681146773Ssam	(ndo->ndo_printf)(ndo, ": ");
68256893Sfenner	return advance;
683127668Sbms#endif
68456893Sfenner
68556893Sfennerfail:
686127668Sbms	return -1;
68756893Sfenner}
688146773Ssam
689146773Ssam/*
690146773Ssam * Local Variables:
691146773Ssam * c-style: whitesmith
692146773Ssam * c-basic-offset: 8
693146773Ssam * End:
694146773Ssam */
695