print-esp.c revision 98524
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[] =
26    "@(#) $Header: /tcpdump/master/tcpdump/print-esp.c,v 1.20 2002/01/21 11:39:59 mcr Exp $ (LBL)";
27#endif
28
29#ifdef HAVE_CONFIG_H
30#include "config.h"
31#endif
32
33#include <string.h>
34#include <sys/param.h>
35#include <sys/time.h>
36#include <sys/types.h>
37#include <sys/socket.h>
38
39#include <netinet/in.h>
40
41#ifdef HAVE_LIBCRYPTO
42#include <openssl/des.h>
43#include <openssl/blowfish.h>
44#ifdef HAVE_RC5_H
45#include <openssl/rc5.h>
46#endif
47#ifdef HAVE_CAST_H
48#include <openssl/cast.h>
49#endif
50#endif
51
52#include <stdio.h>
53
54#include "ip.h"
55#include "esp.h"
56#ifdef INET6
57#include "ip6.h"
58#endif
59
60#define AVOID_CHURN 1
61#include "interface.h"
62#include "addrtoname.h"
63
64static struct esp_algorithm *espsecret_xform=NULL;  /* cache of decoded alg. */
65static char                 *espsecret_key=NULL;
66
67
68enum cipher { NONE,
69	      DESCBC,
70	      BLOWFISH,
71	      RC5,
72	      CAST128,
73	      DES3CBC};
74
75
76
77struct esp_algorithm {
78	char        *name;
79	enum  cipher algo;
80	int          ivlen;
81	int          authlen;
82	int          replaysize;
83};
84
85struct esp_algorithm esp_xforms[]={
86	{"none",                  NONE,    0,  0, 0},
87	{"des-cbc",               DESCBC,  8,  0, 0},
88	{"des-cbc-hmac96",        DESCBC,  8, 12, 4},
89	{"blowfish-cbc",          BLOWFISH,8,  0, 0},
90	{"blowfish-cbc-hmac96",   BLOWFISH,8, 12, 4},
91	{"rc5-cbc",               RC5,     8,  0, 0},
92	{"rc5-cbc-hmac96",        RC5,     8, 12, 4},
93	{"cast128-cbc",           CAST128, 8,  0, 0},
94	{"cast128-cbc-hmac96",    CAST128, 8, 12, 4},
95	{"3des-cbc-hmac96",       DES3CBC, 8, 12, 4},
96};
97
98static int hexdigit(char hex)
99{
100	if(hex >= '0' && hex <= '9') {
101		return (hex - '0');
102	} else if(hex >= 'A' && hex <= 'F') {
103		return (hex - 'A' + 10);
104	} else if(hex >= 'a' && hex <= 'f') {
105		return (hex - 'a' + 10);
106	} else {
107		printf("invalid hex digit %c in espsecret\n", hex);
108		return 0;
109	}
110}
111
112static int hex2byte(char *hexstring)
113{
114	int byte;
115
116	byte = (hexdigit(hexstring[0]) << 4) +
117		hexdigit(hexstring[1]);
118	return byte;
119}
120
121
122void esp_print_decodesecret()
123{
124	char *colon;
125	int   len, i;
126	struct esp_algorithm *xf;
127
128	if(espsecret == NULL) {
129		/* set to NONE transform */
130		espsecret_xform = esp_xforms;
131		return;
132	}
133
134	if(espsecret_key != NULL) {
135		return;
136	}
137
138	colon = strchr(espsecret, ':');
139	if(colon == NULL) {
140		printf("failed to decode espsecret: %s\n",
141		       espsecret);
142		/* set to NONE transform */
143		espsecret_xform = esp_xforms;
144	}
145
146	len   = colon - espsecret;
147	xf = esp_xforms;
148	while(xf->name && strncasecmp(espsecret, xf->name, len)!=0) {
149		xf++;
150	}
151	if(xf->name == NULL) {
152		printf("failed to find cipher algo %s\n",
153		       espsecret);
154		espsecret_xform = esp_xforms;
155		return;
156	}
157	espsecret_xform = xf;
158
159	colon++;
160	if(colon[0]=='0' && colon[1]=='x') {
161		/* decode some hex! */
162		colon+=2;
163		len = strlen(colon) / 2;
164		espsecret_key = (char *)malloc(len);
165		if(espsecret_key == NULL) {
166		  fprintf(stderr, "%s: ran out of memory (%d) to allocate secret key\n",
167			  program_name, len);
168		  exit(2);
169		}
170		i = 0;
171		while(colon[0] != '\0' && colon[1]!='\0') {
172			espsecret_key[i]=hex2byte(colon);
173			colon+=2;
174			i++;
175		}
176	} else {
177		espsecret_key = colon;
178	}
179}
180
181int
182esp_print(register const u_char *bp, register const u_char *bp2,
183	  int *nhdr, int *padlen)
184{
185	register const struct esp *esp;
186	register const u_char *ep;
187	u_int32_t spi;
188	struct ip *ip = NULL;
189#ifdef INET6
190	struct ip6_hdr *ip6 = NULL;
191#endif
192	int advance;
193	int len;
194	char *secret;
195	int ivlen = 0;
196	u_char *ivoff;
197	u_char *p;
198
199	esp = (struct esp *)bp;
200	spi = (u_int32_t)ntohl(esp->esp_spi);
201	secret = NULL;
202
203#if 0
204	/* keep secret out of a register */
205	p = (u_char *)&secret;
206#endif
207
208	/* 'ep' points to the end of available data. */
209	ep = snapend;
210
211	if ((u_char *)(esp + 1) >= ep - sizeof(struct esp)) {
212		fputs("[|ESP]", stdout);
213		goto fail;
214	}
215	printf("ESP(spi=0x%08x", spi);
216	printf(",seq=0x%x", (u_int32_t)ntohl(*(u_int32_t *)(esp + 1)));
217	printf(")");
218
219	/* if we don't have decryption key, we can't decrypt this packet. */
220	if (!espsecret)
221		goto fail;
222
223	if(!espsecret_xform) {
224		esp_print_decodesecret();
225	}
226	if(espsecret_xform->algo == NONE) {
227		goto fail;
228	}
229
230	ip = (struct ip *)bp2;
231	switch (IP_V(ip)) {
232#ifdef INET6
233	case 6:
234		ip6 = (struct ip6_hdr *)bp2;
235		ip = NULL;
236		/* we do not attempt to decrypt jumbograms */
237		if (!ntohs(ip6->ip6_plen))
238			goto fail;
239		/* if we can't get nexthdr, we do not need to decrypt it */
240		len = sizeof(struct ip6_hdr) + ntohs(ip6->ip6_plen);
241		break;
242#endif /*INET6*/
243	case 4:
244		/* nexthdr & padding are in the last fragment */
245		if (ntohs(ip->ip_off) & IP_MF)
246			goto fail;
247#ifdef INET6
248		ip6 = NULL;
249#endif
250		len = ntohs(ip->ip_len);
251		break;
252	default:
253		goto fail;
254	}
255
256	/* if we can't get nexthdr, we do not need to decrypt it */
257	if (ep - bp2 < len)
258		goto fail;
259
260	ivoff = (u_char *)(esp + 1) + espsecret_xform->replaysize;
261	ivlen = espsecret_xform->ivlen;
262	secret = espsecret_key;
263
264	switch (espsecret_xform->algo) {
265	case DESCBC:
266#ifdef HAVE_LIBCRYPTO
267	    {
268		u_char iv[8];
269		des_key_schedule schedule;
270
271		switch (ivlen) {
272		case 4:
273			memcpy(iv, ivoff, 4);
274			memcpy(&iv[4], ivoff, 4);
275			p = &iv[4];
276			*p++ ^= 0xff;
277			*p++ ^= 0xff;
278			*p++ ^= 0xff;
279			*p++ ^= 0xff;
280			break;
281		case 8:
282			memcpy(iv, ivoff, 8);
283			break;
284		default:
285			goto fail;
286		}
287
288		des_check_key = 0;
289		des_set_key((void *)secret, schedule);
290
291		p = ivoff + ivlen;
292		des_cbc_encrypt((void *)p, (void *)p,
293			(long)(ep - p), schedule, (void *)iv,
294			DES_DECRYPT);
295		advance = ivoff - (u_char *)esp + ivlen;
296		break;
297	    }
298#else
299		goto fail;
300#endif /*HAVE_LIBCRYPTO*/
301
302	case BLOWFISH:
303#ifdef HAVE_LIBCRYPTO
304	    {
305		BF_KEY schedule;
306
307		BF_set_key(&schedule, strlen(secret), secret);
308
309		p = ivoff + ivlen;
310		BF_cbc_encrypt(p, p, (long)(ep - p), &schedule, ivoff,
311			BF_DECRYPT);
312		advance = ivoff - (u_char *)esp + ivlen;
313		break;
314	    }
315#else
316		goto fail;
317#endif /*HAVE_LIBCRYPTO*/
318
319	case RC5:
320#if defined(HAVE_LIBCRYPTO) && defined(HAVE_RC5_H)
321	    {
322		RC5_32_KEY schedule;
323
324		RC5_32_set_key(&schedule, strlen(secret), secret,
325			RC5_16_ROUNDS);
326
327		p = ivoff + ivlen;
328		RC5_32_cbc_encrypt(p, p, (long)(ep - p), &schedule, ivoff,
329			RC5_DECRYPT);
330		advance = ivoff - (u_char *)esp + ivlen;
331		break;
332	    }
333#else
334		goto fail;
335#endif /*HAVE_LIBCRYPTO*/
336
337	case CAST128:
338#if defined(HAVE_LIBCRYPTO) && defined(HAVE_CAST_H) && !defined(HAVE_BUGGY_CAST128)
339	    {
340		CAST_KEY schedule;
341
342		CAST_set_key(&schedule, strlen(secret), secret);
343
344		p = ivoff + ivlen;
345		CAST_cbc_encrypt(p, p, (long)(ep - p), &schedule, ivoff,
346			CAST_DECRYPT);
347		advance = ivoff - (u_char *)esp + ivlen;
348		break;
349	    }
350#else
351		goto fail;
352#endif /*HAVE_LIBCRYPTO*/
353
354	case DES3CBC:
355#if defined(HAVE_LIBCRYPTO)
356	    {
357		des_key_schedule s1, s2, s3;
358
359		des_check_key = 1;
360		des_set_odd_parity((void *)secret);
361		des_set_odd_parity((void *)secret+8);
362		des_set_odd_parity((void *)secret+16);
363		if(des_set_key((void *)secret, s1) != 0) {
364		  printf("failed to schedule key 1\n");
365		}
366		if(des_set_key((void *)(secret + 8), s2)!=0) {
367		  printf("failed to schedule key 2\n");
368		}
369		if(des_set_key((void *)(secret + 16), s3)!=0) {
370		  printf("failed to schedule key 3\n");
371		}
372
373		p = ivoff + ivlen;
374		des_ede3_cbc_encrypt((void *)p, (void *)p,
375				     (long)(ep - p),
376				     s1, s2, s3,
377				     (void *)ivoff, DES_DECRYPT);
378		advance = ivoff - (u_char *)esp + ivlen;
379		break;
380	    }
381#else
382		goto fail;
383#endif /*HAVE_LIBCRYPTO*/
384
385	case NONE:
386	default:
387		advance = sizeof(struct esp) + espsecret_xform->replaysize;
388		break;
389	}
390
391	ep = ep - espsecret_xform->authlen;
392	/* sanity check for pad length */
393	if (ep - bp < *(ep - 2))
394		goto fail;
395
396	if (padlen)
397		*padlen = *(ep - 2) + 2;
398
399	if (nhdr)
400		*nhdr = *(ep - 1);
401
402	printf(": ");
403	return advance;
404
405fail:
406	if (nhdr)
407		*nhdr = -1;
408	return 65536;
409}
410