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