xref: /freebsd/contrib/tcpdump/print-esp.c (revision b52b9d56d4e96089873a75f9e29062eec19fabba)
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 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 
64 static struct esp_algorithm *espsecret_xform=NULL;  /* cache of decoded alg. */
65 static char                 *espsecret_key=NULL;
66 
67 
68 enum cipher { NONE,
69 	      DESCBC,
70 	      BLOWFISH,
71 	      RC5,
72 	      CAST128,
73 	      DES3CBC};
74 
75 
76 
77 struct esp_algorithm {
78 	char        *name;
79 	enum  cipher algo;
80 	int          ivlen;
81 	int          authlen;
82 	int          replaysize;
83 };
84 
85 struct 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 
98 static 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 
112 static 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 
122 void 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 
181 int
182 esp_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 
405 fail:
406 	if (nhdr)
407 		*nhdr = -1;
408 	return 65536;
409 }
410