1 /* $OpenBSD: print-ipsec.c,v 1.27 2021/11/29 18:50:16 tb 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/ip6.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 #include "addrtoname.h" 46 #include "interface.h" 47 #include "extract.h" /* must come after interface.h */ 48 49 #include <openssl/evp.h> 50 #include <ctype.h> 51 52 /* 53 * IPsec/ESP header 54 */ 55 struct esp_hdr { 56 u_int esp_spi; 57 u_int esp_seq; 58 }; 59 60 static int espinit = 0; 61 static int espauthlen = 12; 62 static EVP_CIPHER_CTX *ctx; 63 64 int 65 esp_init (char *espspec) 66 { 67 const EVP_CIPHER *evp; 68 char *p, *espkey, s[3], name[1024]; 69 u_char *key; 70 int i, klen, len; 71 72 evp = EVP_aes_128_cbc(); /* default */ 73 espkey = espspec; 74 if ((p = strchr(espspec, ':')) != NULL) { 75 len = p - espspec; 76 if (len >= sizeof(name)) 77 error("espalg too long"); 78 memcpy(name, espspec, len); 79 name[len] = '\0'; 80 espkey = p + 1; 81 82 /* strip auth alg */ 83 espauthlen = 0; 84 if ((p = strstr(name, "-hmac96")) != NULL) { 85 espauthlen = 12; 86 *p = '\0'; 87 } 88 OpenSSL_add_all_algorithms(); 89 if ((evp = EVP_get_cipherbyname(name)) == NULL) 90 error("espalg `%s' not supported", name); 91 } 92 klen = EVP_CIPHER_key_length(evp); 93 if (strlen(espkey) != klen * 2) 94 error("espkey size mismatch, %d bytes needed", klen); 95 if ((key = malloc(klen)) == NULL) 96 error("malloc failed"); 97 for (i = 0; i < klen; i++) { 98 s[0] = espkey[2*i]; 99 s[1] = espkey[2*i + 1]; 100 s[2] = 0; 101 if (!isxdigit((unsigned char)s[0]) || 102 !isxdigit((unsigned char)s[1])) { 103 free(key); 104 error("espkey must be specified in hex"); 105 } 106 key[i] = strtoul(s, NULL, 16); 107 } 108 if ((ctx = EVP_CIPHER_CTX_new()) == NULL) { 109 free(key); 110 error("espkey init failed"); 111 } 112 if (!EVP_CipherInit(ctx, evp, key, NULL, 0)) { 113 EVP_CIPHER_CTX_free(ctx); 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 if (!EVP_CipherInit(ctx, NULL, NULL, data, 0)) 157 return; 158 159 len -= blocksz; 160 data += blocksz; 161 162 /* decrypt remaining payload */ 163 if (!EVP_Cipher(ctx, data, data, len)) 164 return; 165 166 nh = data[len - 1]; 167 pad = data[len - 2]; 168 169 /* verify padding */ 170 if (pad + 2 > len) 171 return; 172 if (data[len - 3] != pad) 173 return; 174 if (vflag > 1) 175 printf(" pad %d", pad); 176 len -= (pad + 2); 177 printf(": "); 178 switch (nh) { 179 case IPPROTO_TCP: 180 tcp_print(data, len, bp2); 181 break; 182 case IPPROTO_UDP: 183 udp_print(data, len, bp2); 184 break; 185 case IPPROTO_IPV6: 186 ip6_print(data, len); 187 break; 188 case IPPROTO_IPV4: 189 ip_print(data, len); 190 break; 191 case IPPROTO_ICMP: 192 icmp_print(data, len, bp2); 193 break; 194 case IPPROTO_ICMPV6: 195 icmp6_print(data, len, bp2); 196 break; 197 default: 198 printf("ip-proto-%d %d", nh, len); 199 break; 200 } 201 if (vflag) 202 printf(" (esp)"); 203 } 204 205 void 206 esp_print (const u_char *bp, u_int len, const u_char *bp2) 207 { 208 const struct esp_hdr *esp; 209 210 if (len < sizeof(struct esp_hdr)) { 211 printf("[|esp]"); 212 return; 213 } 214 esp = (const struct esp_hdr *)bp; 215 216 printf("esp spi 0x%08x seq %u len %d", 217 ntohl(esp->esp_spi), ntohl(esp->esp_seq), len); 218 219 if (espinit) 220 esp_decrypt(bp, len, bp2); 221 } 222 223 /* 224 * IPsec/AH header 225 */ 226 struct ah_hdr { 227 u_char ah_nxt_hdr; 228 u_char ah_pl_len; 229 u_short ah_reserved; 230 u_int ah_spi; 231 u_int ah_seq; 232 }; 233 234 void 235 ah_print (const u_char *bp, u_int len, const u_char *bp2) 236 { 237 const struct ip *ip; 238 const struct ah_hdr *ah; 239 u_int pl_len = len; 240 const struct ip6_hdr *ip6; 241 242 ip = (const struct ip *)bp2; 243 if (ip->ip_v == 6) { 244 ip6 = (const struct ip6_hdr *)bp2; 245 printf("ah %s > %s", ip6addr_string(&ip6->ip6_src), 246 ip6addr_string(&ip6->ip6_dst)); 247 } else 248 printf("ah %s > %s", 249 ipaddr_string(&ip->ip_src), ipaddr_string(&ip->ip_dst)); 250 251 if (pl_len < sizeof(struct ah_hdr)) { 252 printf("[|ah]"); 253 return; 254 } 255 ah = (const struct ah_hdr *)bp; 256 257 printf(" spi 0x%08x seq %u len %d", 258 ntohl(ah->ah_spi), ntohl(ah->ah_seq), len); 259 260 if (vflag) { 261 printf(" [ "); 262 263 pl_len = (ah->ah_pl_len + 2) << 2; /* RFC2402, sec 2.2 */ 264 265 if (len <= pl_len) { 266 printf("truncated"); 267 goto out; 268 } 269 270 switch (ah->ah_nxt_hdr) { 271 272 case IPPROTO_IPIP: /* Tunnel Mode, IP-in-IP */ 273 ip_print(bp + pl_len, len - pl_len); 274 break; 275 276 case IPPROTO_ICMP: /* From here and down; Transport mode */ 277 icmp_print(bp + pl_len, len - pl_len, 278 (const u_char *) ip); 279 break; 280 281 case IPPROTO_ICMPV6: 282 icmp6_print(bp + pl_len, len - pl_len, 283 (const u_char *) ip); 284 break; 285 286 case IPPROTO_TCP: 287 tcp_print(bp + pl_len, len - pl_len, 288 (const u_char *) ip); 289 break; 290 291 case IPPROTO_UDP: 292 udp_print(bp + pl_len, len - pl_len, 293 (const u_char *) ip); 294 break; 295 296 case IPPROTO_ESP: 297 esp_print(bp + pl_len, len - pl_len, 298 (const u_char *) ip); 299 break; 300 301 case IPPROTO_AH: 302 ah_print(bp + pl_len, len - pl_len, 303 (const u_char *) ip); 304 break; 305 306 default: 307 printf("ip-proto-%d len %d", 308 ah->ah_nxt_hdr, len - pl_len); 309 } 310 out: 311 printf(" ]"); 312 } 313 314 } 315 316 struct ipcomp_hdr { 317 u_char ipcomp_nxt_hdr; 318 u_char ipcomp_flags; 319 u_short ipcomp_cpi; 320 }; 321 322 void 323 ipcomp_print (const u_char *bp, u_int len, const u_char *bp2) 324 { 325 const struct ip *ip; 326 const struct ipcomp_hdr *ipc; 327 u_int plen = len; 328 329 ip = (const struct ip *)bp2; 330 331 printf("ipcomp %s > %s", 332 ipaddr_string(&ip->ip_src), 333 ipaddr_string(&ip->ip_dst)); 334 335 if (plen < sizeof(struct ipcomp_hdr)) { 336 printf("[|ipcomp]"); 337 return; 338 } 339 ipc = (const struct ipcomp_hdr *)bp; 340 341 printf(" cpi 0x%04X flags %x next %x", 342 ntohs(ipc->ipcomp_cpi), ipc->ipcomp_flags, ipc->ipcomp_nxt_hdr); 343 } 344