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