1 /* $OpenBSD: print-ipsec.c,v 1.19 2014/08/14 12:44:44 mpi 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/ip.h> 35 #include <netinet/ip_var.h> 36 #include <netinet/udp.h> 37 #include <netinet/udp_var.h> 38 #include <netinet/tcp.h> 39 40 #include <stdio.h> 41 #include <stdlib.h> 42 #include <string.h> 43 #include <unistd.h> 44 45 #ifdef INET6 46 #include <netinet/ip6.h> 47 #endif 48 49 #include "addrtoname.h" 50 #include "interface.h" 51 #include "extract.h" /* must come after interface.h */ 52 53 #include <openssl/evp.h> 54 #include <ctype.h> 55 56 /* 57 * IPsec/ESP header 58 */ 59 struct esp_hdr { 60 u_int esp_spi; 61 u_int esp_seq; 62 }; 63 64 static int espinit = 0; 65 static int espauthlen = 12; 66 static EVP_CIPHER_CTX ctx; 67 68 int 69 esp_init (char *espspec) 70 { 71 const EVP_CIPHER *evp; 72 char *p, *espkey, s[3], name[1024]; 73 u_char *key; 74 int i, klen, len; 75 76 evp = EVP_aes_128_cbc(); /* default */ 77 espkey = espspec; 78 if ((p = strchr(espspec, ':')) != NULL) { 79 len = p - espspec; 80 if (len >= sizeof(name)) 81 error("espalg too long"); 82 memcpy(name, espspec, len); 83 name[len] = '\0'; 84 espkey = p + 1; 85 86 /* strip auth alg */ 87 espauthlen = 0; 88 if ((p = strstr(name, "-hmac96")) != NULL) { 89 espauthlen = 12; 90 *p = '\0'; 91 } 92 OpenSSL_add_all_algorithms(); 93 if ((evp = EVP_get_cipherbyname(name)) == NULL) 94 error("espalg `%s' not supported", name); 95 } 96 klen = EVP_CIPHER_key_length(evp); 97 if (strlen(espkey) != klen * 2) 98 error("espkey size mismatch, %d bytes needed", klen); 99 if ((key = malloc(klen)) == NULL) 100 error("malloc failed"); 101 for (i = 0; i < klen; i++) { 102 s[0] = espkey[2*i]; 103 s[1] = espkey[2*i + 1]; 104 s[2] = 0; 105 if (!isxdigit(s[0]) || !isxdigit(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 (register const u_char *bp, register u_int len, 203 register const u_char *bp2) 204 { 205 const struct ip *ip; 206 const struct esp_hdr *esp; 207 u_int plen = len; 208 #ifdef INET6 209 const struct ip6_hdr *ip6; 210 #endif 211 212 ip = (const struct ip *)bp2; 213 #ifdef INET6 214 if (ip->ip_v == 6) { 215 ip6 = (const struct ip6_hdr *)bp2; 216 printf("esp %s > %s", ip6addr_string(&ip6->ip6_src), 217 ip6addr_string(&ip6->ip6_dst)); 218 } else 219 #endif 220 { 221 printf("esp %s > %s", 222 ipaddr_string(&ip->ip_src), ipaddr_string(&ip->ip_dst)); 223 } 224 225 if (plen < sizeof(struct esp_hdr)) { 226 printf("[|esp]"); 227 return; 228 } 229 esp = (const struct esp_hdr *)bp; 230 231 printf(" spi 0x%08x seq %u len %d", 232 ntohl(esp->esp_spi), ntohl(esp->esp_seq), len); 233 234 if (espinit) 235 esp_decrypt(bp, len, bp2); 236 } 237 238 /* 239 * IPsec/AH header 240 */ 241 struct ah_hdr { 242 u_char ah_nxt_hdr; 243 u_char ah_pl_len; 244 u_short ah_reserved; 245 u_int ah_spi; 246 u_int ah_seq; 247 }; 248 249 void 250 ah_print (register const u_char *bp, register u_int len, 251 register const u_char *bp2) 252 { 253 const struct ip *ip; 254 const struct ah_hdr *ah; 255 u_int pl_len = len; 256 #ifdef INET6 257 const struct ip6_hdr *ip6; 258 #endif 259 260 ip = (const struct ip *)bp2; 261 #ifdef INET6 262 if (ip->ip_v == 6) { 263 ip6 = (const struct ip6_hdr *)bp2; 264 printf("ah %s > %s", ip6addr_string(&ip6->ip6_src), 265 ip6addr_string(&ip6->ip6_dst)); 266 } else 267 #endif 268 { 269 printf("ah %s > %s", 270 ipaddr_string(&ip->ip_src), ipaddr_string(&ip->ip_dst)); 271 } 272 273 if (pl_len < sizeof(struct ah_hdr)) { 274 printf("[|ah]"); 275 return; 276 } 277 ah = (const struct ah_hdr *)bp; 278 279 printf(" spi 0x%08x seq %u len %d", 280 ntohl(ah->ah_spi), ntohl(ah->ah_seq), len); 281 282 if (vflag) { 283 (void)printf("\n\t[ "); 284 285 pl_len = (ah->ah_pl_len + 2) << 2; /* RFC2402, sec 2.2 */ 286 287 if (len <= pl_len) { 288 (void)printf("truncated"); 289 goto out; 290 } 291 292 switch (ah->ah_nxt_hdr) { 293 294 case IPPROTO_IPIP: /* Tunnel Mode, IP-in-IP */ 295 ip_print(bp + pl_len, len - pl_len); 296 break; 297 298 case IPPROTO_ICMP: /* From here and down; Transport mode */ 299 icmp_print(bp + pl_len, len - pl_len, 300 (const u_char *) ip); 301 break; 302 303 case IPPROTO_ICMPV6: 304 icmp6_print(bp + pl_len, len - pl_len, 305 (const u_char *) ip); 306 break; 307 308 case IPPROTO_TCP: 309 tcp_print(bp + pl_len, len - pl_len, 310 (const u_char *) ip); 311 break; 312 313 case IPPROTO_UDP: 314 udp_print(bp + pl_len, len - pl_len, 315 (const u_char *) ip); 316 break; 317 318 case IPPROTO_ESP: 319 esp_print(bp + pl_len, len - pl_len, 320 (const u_char *) ip); 321 break; 322 323 case IPPROTO_AH: 324 ah_print(bp + pl_len, len - pl_len, 325 (const u_char *) ip); 326 break; 327 328 default: 329 (void)printf("ip-proto-%d len %d", ah->ah_nxt_hdr, 330 len - pl_len); 331 } 332 out: 333 (void)printf(" ]"); 334 } 335 336 } 337 338 struct ipcomp_hdr { 339 u_char ipcomp_nxt_hdr; 340 u_char ipcomp_flags; 341 u_short ipcomp_cpi; 342 }; 343 344 void 345 ipcomp_print (register const u_char *bp, register u_int len, 346 register const u_char *bp2) 347 { 348 const struct ip *ip; 349 const struct ipcomp_hdr *ipc; 350 u_int plen = len; 351 352 ip = (const struct ip *)bp2; 353 354 printf("ipcomp %s > %s", 355 ipaddr_string(&ip->ip_src), ipaddr_string(&ip->ip_dst)); 356 357 if (plen < sizeof(struct ipcomp_hdr)) { 358 printf("[|ipcomp]"); 359 return; 360 } 361 ipc = (const struct ipcomp_hdr *)bp; 362 363 printf(" cpi 0x%04X flags %x next %x", 364 ntohs(ipc->ipcomp_cpi), ipc->ipcomp_flags, ipc->ipcomp_nxt_hdr); 365 } 366