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