GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/tcpdump/print-ipsec.c Lines: 0 143 0.0 %
Date: 2017-11-07 Branches: 0 65 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: print-ipsec.c,v 1.23 2015/11/16 00:16:39 mmcc Exp $	*/
2
3
/*
4
 * Copyright (c) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999
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
 * Format and print IPsec (ESP/AH) packets.
24
 *      By Tero Kivinen <kivinen@ssh.fi>, Tero Mononen <tmo@ssh.fi>,
25
 *         Tatu Ylonen <ylo@ssh.fi> and Timo J. Rinne <tri@ssh.fi>
26
 *         in co-operation with SSH Communications Security, Espoo, Finland
27
 */
28
29
#include <sys/time.h>
30
#include <sys/socket.h>
31
32
#include <netinet/in.h>
33
#include <netinet/ip.h>
34
#include <netinet/ip_var.h>
35
#include <netinet/udp.h>
36
#include <netinet/udp_var.h>
37
#include <netinet/tcp.h>
38
39
#include <stdio.h>
40
#include <stdlib.h>
41
#include <string.h>
42
#include <unistd.h>
43
44
#ifdef INET6
45
#include <netinet/ip6.h>
46
#endif
47
48
#include "addrtoname.h"
49
#include "interface.h"
50
#include "extract.h"		    /* must come after interface.h */
51
52
#include <openssl/evp.h>
53
#include <ctype.h>
54
55
/*
56
 * IPsec/ESP header
57
 */
58
struct esp_hdr {
59
	u_int esp_spi;
60
	u_int esp_seq;
61
};
62
63
static int espinit = 0;
64
static int espauthlen = 12;
65
static EVP_CIPHER_CTX ctx;
66
67
int
68
esp_init (char *espspec)
69
{
70
	const EVP_CIPHER *evp;
71
	char *p, *espkey, s[3], name[1024];
72
	u_char *key;
73
	int i, klen, len;
74
75
	evp = EVP_aes_128_cbc();	/* default */
76
	espkey = espspec;
77
	if ((p = strchr(espspec, ':')) != NULL) {
78
		len = p - espspec;
79
		if (len >= sizeof(name))
80
			error("espalg too long");
81
		memcpy(name, espspec, len);
82
		name[len] = '\0';
83
		espkey = p + 1;
84
85
		/* strip auth alg */
86
		espauthlen = 0;
87
		if ((p = strstr(name, "-hmac96")) != NULL) {
88
			espauthlen = 12;
89
			*p = '\0';
90
		}
91
		OpenSSL_add_all_algorithms();
92
		if ((evp = EVP_get_cipherbyname(name)) == NULL)
93
			error("espalg `%s' not supported", name);
94
	}
95
	klen = EVP_CIPHER_key_length(evp);
96
	if (strlen(espkey) != klen * 2)
97
		error("espkey size mismatch, %d bytes needed", klen);
98
	if ((key = malloc(klen)) == NULL)
99
		error("malloc failed");
100
	for (i = 0; i < klen; i++) {
101
		s[0] = espkey[2*i];
102
		s[1] = espkey[2*i + 1];
103
		s[2] = 0;
104
		if (!isxdigit((unsigned char)s[0]) ||
105
		    !isxdigit((unsigned char)s[1])) {
106
			free(key);
107
			error("espkey must be specified in hex");
108
		}
109
		key[i] = strtoul(s, NULL, 16);
110
	}
111
	EVP_CIPHER_CTX_init(&ctx);
112
	if (EVP_CipherInit(&ctx, evp, key, NULL, 0) < 0) {
113
		free(key);
114
		error("espkey init failed");
115
	}
116
	free(key);
117
	espinit = 1;
118
	return (0);
119
}
120
121
void
122
esp_decrypt (const u_char *bp, u_int len, const u_char *bp2)
123
{
124
	const struct ip *ip;
125
	u_char *data, pad, nh;
126
	int blocksz;
127
128
	ip = (const struct ip *)bp2;
129
130
	blocksz = EVP_CIPHER_CTX_block_size(&ctx);
131
132
	/* Skip fragments and short packets */
133
	if (ntohs(ip->ip_off) & 0x3fff)
134
		return;
135
	if (snapend - bp < len) {
136
		printf(" [|esp]");
137
		return;
138
	}
139
	/*
140
	 * Skip ESP header and ignore authentication trailer.
141
	 * For decryption we need at least 2 blocks: IV and
142
	 * one cipher block.
143
	 */
144
	if (len < sizeof(struct esp_hdr) + espauthlen + 2 * blocksz) {
145
		printf(" [|esp]");
146
		return;
147
	}
148
149
	data = (char *)bp;
150
	data += sizeof(struct esp_hdr);
151
	len -= sizeof(struct esp_hdr);
152
	len -= espauthlen;
153
154
	/* the first block contains the IV */
155
	EVP_CipherInit(&ctx, NULL, NULL, data, 0);
156
	len -= blocksz;
157
	data += blocksz;
158
159
	/* decrypt remaining payload */
160
	EVP_Cipher(&ctx, data, data, len);
161
162
	nh = data[len - 1];
163
	pad = data[len - 2];
164
165
	/* verify padding */
166
	if (pad + 2 > len)
167
		return;
168
	if (data[len - 3]  != pad)
169
		return;
170
	if (vflag > 1)
171
		printf(" pad %d", pad);
172
	len -= (pad + 2);
173
	printf(": ");
174
	switch (nh) {
175
	case IPPROTO_TCP:
176
		tcp_print(data, len, bp2);
177
		break;
178
	case IPPROTO_UDP:
179
		udp_print(data, len, bp2);
180
		break;
181
	case IPPROTO_IPV6:
182
		ip6_print(data, len);
183
		break;
184
	case IPPROTO_IPV4:
185
		ip_print(data, len);
186
		break;
187
	case IPPROTO_ICMP:
188
		icmp_print(data, len, bp2);
189
		break;
190
	case IPPROTO_ICMPV6:
191
		icmp6_print(data, len, bp2);
192
		break;
193
	default:
194
		printf("ip-proto-%d %d", nh, len);
195
		break;
196
	}
197
	if (vflag)
198
		printf(" (esp)");
199
}
200
201
void
202
esp_print (const u_char *bp, u_int len, const u_char *bp2)
203
{
204
	const struct ip *ip;
205
	const struct esp_hdr *esp;
206
	u_int plen = len;
207
#ifdef INET6
208
	const struct ip6_hdr *ip6;
209
#endif
210
211
	ip = (const struct ip *)bp2;
212
#ifdef INET6
213
	if (ip->ip_v == 6) {
214
		ip6 = (const struct ip6_hdr *)bp2;
215
		printf("esp %s > %s", ip6addr_string(&ip6->ip6_src),
216
		    ip6addr_string(&ip6->ip6_dst));
217
	} else
218
#endif
219
	{
220
		printf("esp %s > %s",
221
	    	    ipaddr_string(&ip->ip_src), ipaddr_string(&ip->ip_dst));
222
	}
223
224
	if (plen < sizeof(struct esp_hdr)) {
225
		printf("[|esp]");
226
		return;
227
	}
228
	esp = (const struct esp_hdr *)bp;
229
230
	printf(" spi 0x%08x seq %u len %d",
231
	    ntohl(esp->esp_spi), ntohl(esp->esp_seq), len);
232
233
	if (espinit)
234
		esp_decrypt(bp, len, bp2);
235
}
236
237
/*
238
 * IPsec/AH header
239
 */
240
struct ah_hdr {
241
	u_char  ah_nxt_hdr;
242
	u_char  ah_pl_len;
243
	u_short ah_reserved;
244
	u_int   ah_spi;
245
	u_int   ah_seq;
246
};
247
248
void
249
ah_print (const u_char *bp, u_int len, const u_char *bp2)
250
{
251
	const struct ip *ip;
252
	const struct ah_hdr *ah;
253
	u_int pl_len = len;
254
#ifdef INET6
255
	const struct ip6_hdr *ip6;
256
#endif
257
258
	ip = (const struct ip *)bp2;
259
#ifdef INET6
260
	if (ip->ip_v == 6) {
261
		ip6 = (const struct ip6_hdr *)bp2;
262
		printf("ah %s > %s", ip6addr_string(&ip6->ip6_src),
263
		    ip6addr_string(&ip6->ip6_dst));
264
	} else
265
#endif
266
	{
267
		printf("ah %s > %s",
268
	    	    ipaddr_string(&ip->ip_src), ipaddr_string(&ip->ip_dst));
269
	}
270
271
	if (pl_len < sizeof(struct ah_hdr)) {
272
		printf("[|ah]");
273
		return;
274
	}
275
	ah = (const struct ah_hdr *)bp;
276
277
	printf(" spi 0x%08x seq %u len %d",
278
	    ntohl(ah->ah_spi), ntohl(ah->ah_seq), len);
279
280
	if (vflag) {
281
	        (void)printf(" [ ");
282
283
	        pl_len = (ah->ah_pl_len + 2) << 2; /* RFC2402, sec 2.2 */
284
285
		if (len <= pl_len) {
286
		        (void)printf("truncated");
287
			goto out;
288
		}
289
290
		switch (ah->ah_nxt_hdr) {
291
292
		case IPPROTO_IPIP: /* Tunnel Mode, IP-in-IP */
293
		        ip_print(bp + pl_len, len - pl_len);
294
			break;
295
296
	        case IPPROTO_ICMP: /* From here and down; Transport mode */
297
		        icmp_print(bp + pl_len, len - pl_len,
298
				  (const u_char *) ip);
299
			break;
300
301
	        case IPPROTO_ICMPV6:
302
		        icmp6_print(bp + pl_len, len - pl_len,
303
				  (const u_char *) ip);
304
			break;
305
306
	        case IPPROTO_TCP:
307
		        tcp_print(bp + pl_len, len - pl_len,
308
				  (const u_char *) ip);
309
			break;
310
311
	        case IPPROTO_UDP:
312
		        udp_print(bp + pl_len, len - pl_len,
313
				  (const u_char *) ip);
314
			break;
315
316
		case IPPROTO_ESP:
317
		        esp_print(bp + pl_len, len - pl_len,
318
				  (const u_char *) ip);
319
			break;
320
321
		case IPPROTO_AH:
322
		        ah_print(bp + pl_len, len - pl_len,
323
				 (const u_char *) ip);
324
			break;
325
326
		default:
327
		        (void)printf("ip-proto-%d len %d", ah->ah_nxt_hdr,
328
				     len - pl_len);
329
		}
330
out:
331
		(void)printf(" ]");
332
	}
333
334
}
335
336
struct ipcomp_hdr {
337
	u_char  ipcomp_nxt_hdr;
338
	u_char	ipcomp_flags;
339
	u_short	ipcomp_cpi;
340
};
341
342
void
343
ipcomp_print (const u_char *bp, u_int len, const u_char *bp2)
344
{
345
	const struct ip *ip;
346
	const struct ipcomp_hdr *ipc;
347
	u_int plen = len;
348
349
	ip = (const struct ip *)bp2;
350
351
	printf("ipcomp %s > %s",
352
	    ipaddr_string(&ip->ip_src), ipaddr_string(&ip->ip_dst));
353
354
	if (plen < sizeof(struct ipcomp_hdr)) {
355
		printf("[|ipcomp]");
356
		return;
357
	}
358
	ipc = (const struct ipcomp_hdr *)bp;
359
360
	printf(" cpi 0x%04X flags %x next %x",
361
	    ntohs(ipc->ipcomp_cpi), ipc->ipcomp_flags, ipc->ipcomp_nxt_hdr);
362
}