xref: /freebsd/contrib/tcpdump/print-esp.c (revision f9218d3d4fd34f082473b3a021c6d4d109fb47cf)
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[] =
26     "@(#) $Header: /tcpdump/master/tcpdump/print-esp.c,v 1.20.4.2 2002/02/22 09:26:27 guy 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 #include <stdlib.h>
39 
40 #include <netinet/in.h>
41 
42 #ifdef HAVE_LIBCRYPTO
43 #include <openssl/des.h>
44 #include <openssl/blowfish.h>
45 #ifdef HAVE_RC5_H
46 #include <openssl/rc5.h>
47 #endif
48 #ifdef HAVE_CAST_H
49 #include <openssl/cast.h>
50 #endif
51 #endif
52 
53 #include <stdio.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 
65 static struct esp_algorithm *espsecret_xform=NULL;  /* cache of decoded alg. */
66 static char                 *espsecret_key=NULL;
67 
68 
69 enum cipher { NONE,
70 	      DESCBC,
71 	      BLOWFISH,
72 	      RC5,
73 	      CAST128,
74 	      DES3CBC};
75 
76 
77 
78 struct esp_algorithm {
79 	char        *name;
80 	enum  cipher algo;
81 	int          ivlen;
82 	int          authlen;
83 	int          replaysize;
84 };
85 
86 struct 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 
99 static 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 
113 static 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 
123 static void esp_print_decodesecret(void)
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 
182 int
183 esp_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 
406 fail:
407 	if (nhdr)
408 		*nhdr = -1;
409 	return 65536;
410 }
411