We don't currently build ld-elf as binary for i386 and even if
[dragonfly.git] / contrib / tcpdump-3.8.3 / print-esp.c
1 /*      $NetBSD: print-ah.c,v 1.4 1996/05/20 00:41:16 fvdl Exp $        */
2
3 /*
4  * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994
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
24 #ifndef lint
25 static const char rcsid[] _U_ =
26     "@(#) $Header: /tcpdump/master/tcpdump/print-esp.c,v 1.44.2.4 2003/11/19 05:36:40 guy Exp $ (LBL)";
27 #endif
28
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
32
33 #include <string.h>
34
35 #include <tcpdump-stdinc.h>
36
37 #include <stdlib.h>
38
39 #ifdef HAVE_LIBCRYPTO
40 #ifdef HAVE_OPENSSL_EVP_H
41 #include <openssl/evp.h>
42 #endif
43 #endif
44
45 #include <stdio.h>
46
47 #include "ip.h"
48 #include "esp.h"
49 #ifdef INET6
50 #include "ip6.h"
51 #endif
52
53 #if defined(__MINGW32__) || defined(__WATCOMC__)
54 extern char *strsep(char **stringp, const char *delim); /* Missing/strsep.c */
55 #endif
56
57 #include "interface.h"
58 #include "addrtoname.h"
59 #include "extract.h"
60
61 #ifndef HAVE_SOCKADDR_STORAGE
62 #ifdef INET6
63 struct sockaddr_storage {
64         union {
65                 struct sockaddr_in sin;
66                 struct sockaddr_in6 sin6;
67         } un;
68 };
69 #else
70 #define sockaddr_storage sockaddr
71 #endif
72 #endif /* HAVE_SOCKADDR_STORAGE */
73
74 #ifdef HAVE_LIBCRYPTO
75 struct sa_list {
76         struct sa_list  *next;
77         struct sockaddr_storage daddr;
78         u_int32_t       spi;
79         const EVP_CIPHER *evp;
80         int             ivlen;
81         int             authlen;
82         char            secret[256];  /* is that big enough for all secrets? */
83         int             secretlen;
84 };
85
86 static struct sa_list *sa_list_head = NULL;
87 static struct sa_list *sa_default = NULL;
88
89 static void esp_print_addsa(struct sa_list *sa, int sa_def)
90 {
91         /* copy the "sa" */
92
93         struct sa_list *nsa;
94
95         nsa = (struct sa_list *)malloc(sizeof(struct sa_list));
96         if (nsa == NULL)
97                 error("ran out of memory to allocate sa structure");
98
99         *nsa = *sa;
100
101         if (sa_def)
102                 sa_default = nsa;
103
104         nsa->next = sa_list_head;
105         sa_list_head = nsa;
106 }
107
108
109 static int hexdigit(char hex)
110 {
111         if (hex >= '0' && hex <= '9')
112                 return (hex - '0');
113         else if (hex >= 'A' && hex <= 'F')
114                 return (hex - 'A' + 10);
115         else if (hex >= 'a' && hex <= 'f')
116                 return (hex - 'a' + 10);
117         else {
118                 printf("invalid hex digit %c in espsecret\n", hex);
119                 return 0;
120         }
121 }
122
123 static int hex2byte(char *hexstring)
124 {
125         int byte;
126
127         byte = (hexdigit(hexstring[0]) << 4) + hexdigit(hexstring[1]);
128         return byte;
129 }
130
131 /*
132  * decode the form:    SPINUM@IP <tab> ALGONAME:0xsecret
133  *
134  * special form: file /name
135  * causes us to go read from this file instead.
136  *
137  */
138 static void esp_print_decode_onesecret(char *line)
139 {
140         struct sa_list sa1;
141         int sa_def;
142
143         char *spikey;
144         char *decode;
145
146         spikey = strsep(&line, " \t");
147         sa_def = 0;
148         memset(&sa1, 0, sizeof(struct sa_list));
149
150         /* if there is only one token, then it is an algo:key token */
151         if (line == NULL) {
152                 decode = spikey;
153                 spikey = NULL;
154                 /* memset(&sa1.daddr, 0, sizeof(sa1.daddr)); */
155                 /* sa1.spi = 0; */
156                 sa_def    = 1;
157         } else
158                 decode = line;
159
160         if (spikey && strcasecmp(spikey, "file") == 0) {
161                 /* open file and read it */
162                 FILE *secretfile;
163                 char  fileline[1024];
164                 char  *nl;
165
166                 secretfile = fopen(line, FOPEN_READ_TXT);
167                 if (secretfile == NULL) {
168                         perror(line);
169                         exit(3);
170                 }
171
172                 while (fgets(fileline, sizeof(fileline)-1, secretfile) != NULL) {
173                         /* remove newline from the line */
174                         nl = strchr(fileline, '\n');
175                         if (nl)
176                                 *nl = '\0';
177                         if (fileline[0] == '#') continue;
178                         if (fileline[0] == '\0') continue;
179
180                         esp_print_decode_onesecret(fileline);
181                 }
182                 fclose(secretfile);
183
184                 return;
185         }
186
187         if (spikey) {
188                 char *spistr, *foo;
189                 u_int32_t spino;
190                 struct sockaddr_in *sin;
191 #ifdef INET6
192                 struct sockaddr_in6 *sin6;
193 #endif
194
195                 spistr = strsep(&spikey, "@");
196
197                 spino = strtoul(spistr, &foo, 0);
198                 if (spistr == foo || !spikey) {
199                         printf("print_esp: failed to decode spi# %s\n", foo);
200                         return;
201                 }
202
203                 sa1.spi = spino;
204
205                 sin = (struct sockaddr_in *)&sa1.daddr;
206 #ifdef INET6
207                 sin6 = (struct sockaddr_in6 *)&sa1.daddr;
208                 if (inet_pton(AF_INET6, spikey, &sin6->sin6_addr) == 1) {
209 #ifdef HAVE_SOCKADDR_SA_LEN
210                         sin6->sin6_len = sizeof(struct sockaddr_in6);
211 #endif
212                         sin6->sin6_family = AF_INET6;
213                 } else
214 #endif
215                 if (inet_pton(AF_INET, spikey, &sin->sin_addr) == 1) {
216 #ifdef HAVE_SOCKADDR_SA_LEN
217                         sin->sin_len = sizeof(struct sockaddr_in);
218 #endif
219                         sin->sin_family = AF_INET;
220                 } else {
221                         printf("print_esp: can not decode IP# %s\n", spikey);
222                         return;
223                 }
224         }
225
226         if (decode) {
227                 char *colon, *p;
228                 char  espsecret_key[256];
229                 int len;
230                 size_t i;
231                 const EVP_CIPHER *evp;
232                 int ivlen = 8;
233                 int authlen = 0;
234
235                 /* skip any blank spaces */
236                 while (isspace((unsigned char)*decode))
237                         decode++;
238
239                 colon = strchr(decode, ':');
240                 if (colon == NULL) {
241                         printf("failed to decode espsecret: %s\n", decode);
242                         return;
243                 }
244                 *colon = '\0';
245
246                 len = colon - decode;
247                 if (strlen(decode) > strlen("-hmac96") &&
248                     !strcmp(decode + strlen(decode) - strlen("-hmac96"),
249                     "-hmac96")) {
250                         p = strstr(decode, "-hmac96");
251                         *p = '\0';
252                         authlen = 12;
253                 }
254                 if (strlen(decode) > strlen("-cbc") &&
255                     !strcmp(decode + strlen(decode) - strlen("-cbc"), "-cbc")) {
256                         p = strstr(decode, "-cbc");
257                         *p = '\0';
258                 }
259                 evp = EVP_get_cipherbyname(decode);
260                 if (!evp) {
261                         printf("failed to find cipher algo %s\n", decode);
262                         sa1.evp = NULL;
263                         sa1.authlen = 0;
264                         sa1.ivlen = 0;
265                         return;
266                 }
267
268                 sa1.evp = evp;
269                 sa1.authlen = authlen;
270                 sa1.ivlen = ivlen;
271
272                 colon++;
273                 if (colon[0] == '0' && colon[1] == 'x') {
274                         /* decode some hex! */
275                         colon += 2;
276                         len = strlen(colon) / 2;
277
278                         if (len > 256) {
279                                 printf("secret is too big: %d\n", len);
280                                 return;
281                         }
282
283                         i = 0;
284                         while (colon[0] != '\0' && colon[1]!='\0') {
285                                 espsecret_key[i] = hex2byte(colon);
286                                 colon += 2;
287                                 i++;
288                         }
289
290                         memcpy(sa1.secret, espsecret_key, i);
291                         sa1.secretlen = i;
292                 } else {
293                         i = strlen(colon);
294
295                         if (i < sizeof(sa1.secret)) {
296                                 memcpy(sa1.secret, colon, i);
297                                 sa1.secretlen = i;
298                         } else {
299                                 memcpy(sa1.secret, colon, sizeof(sa1.secret));
300                                 sa1.secretlen = sizeof(sa1.secret);
301                         }
302                 }
303         }
304
305         esp_print_addsa(&sa1, sa_def);
306 }
307
308 static void esp_print_decodesecret(void)
309 {
310         char *line;
311         char *p;
312
313         p = espsecret;
314
315         while (espsecret && espsecret[0] != '\0') {
316                 /* pick out the first line or first thing until a comma */
317                 if ((line = strsep(&espsecret, "\n,")) == NULL) {
318                         line = espsecret;
319                         espsecret = NULL;
320                 }
321
322                 esp_print_decode_onesecret(line);
323         }
324 }
325
326 static void esp_init(void)
327 {
328
329         OpenSSL_add_all_algorithms();
330         EVP_add_cipher_alias(SN_des_ede3_cbc, "3des");
331 }
332 #endif
333
334 int
335 esp_print(const u_char *bp, const u_char *bp2
336 #ifndef HAVE_LIBCRYPTO
337         _U_
338 #endif
339         ,
340         int *nhdr
341 #ifndef HAVE_LIBCRYPTO
342         _U_
343 #endif
344         ,
345         int *padlen
346 #ifndef HAVE_LIBCRYPTO
347         _U_
348 #endif
349         )
350 {
351         register const struct newesp *esp;
352         register const u_char *ep;
353 #ifdef HAVE_LIBCRYPTO
354         struct ip *ip;
355         struct sa_list *sa = NULL;
356         int espsecret_keylen;
357 #ifdef INET6
358         struct ip6_hdr *ip6 = NULL;
359 #endif
360         int advance;
361         int len;
362         char *secret;
363         int ivlen = 0;
364         u_char *ivoff;
365         const u_char *p;
366         EVP_CIPHER_CTX ctx;
367         int blocksz;
368         static int initialized = 0;
369 #endif
370
371         esp = (struct newesp *)bp;
372
373 #ifdef HAVE_LIBCRYPTO
374         secret = NULL;
375         advance = 0;
376
377         if (!initialized) {
378                 esp_init();
379                 initialized = 1;
380         }
381 #endif
382
383 #if 0
384         /* keep secret out of a register */
385         p = (u_char *)&secret;
386 #endif
387
388         /* 'ep' points to the end of available data. */
389         ep = snapend;
390
391         if ((u_char *)(esp + 1) >= ep) {
392                 fputs("[|ESP]", stdout);
393                 goto fail;
394         }
395         printf("ESP(spi=0x%08x", EXTRACT_32BITS(&esp->esp_spi));
396         printf(",seq=0x%x", EXTRACT_32BITS(&esp->esp_seq));
397         printf(")");
398
399 #ifndef HAVE_LIBCRYPTO
400         goto fail;
401 #else
402         /* initiailize SAs */
403         if (sa_list_head == NULL) {
404                 if (!espsecret)
405                         goto fail;
406
407                 esp_print_decodesecret();
408         }
409
410         if (sa_list_head == NULL)
411                 goto fail;
412
413         ip = (struct ip *)bp2;
414         switch (IP_V(ip)) {
415 #ifdef INET6
416         case 6:
417                 ip6 = (struct ip6_hdr *)bp2;
418                 /* we do not attempt to decrypt jumbograms */
419                 if (!EXTRACT_16BITS(&ip6->ip6_plen))
420                         goto fail;
421                 /* if we can't get nexthdr, we do not need to decrypt it */
422                 len = sizeof(struct ip6_hdr) + EXTRACT_16BITS(&ip6->ip6_plen);
423
424                 /* see if we can find the SA, and if so, decode it */
425                 for (sa = sa_list_head; sa != NULL; sa = sa->next) {
426                         struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&sa->daddr;
427                         if (sa->spi == ntohl(esp->esp_spi) &&
428                             sin6->sin6_family == AF_INET6 &&
429                             memcmp(&sin6->sin6_addr, &ip6->ip6_dst,
430                                    sizeof(struct in6_addr)) == 0) {
431                                 break;
432                         }
433                 }
434                 break;
435 #endif /*INET6*/
436         case 4:
437                 /* nexthdr & padding are in the last fragment */
438                 if (EXTRACT_16BITS(&ip->ip_off) & IP_MF)
439                         goto fail;
440                 len = EXTRACT_16BITS(&ip->ip_len);
441
442                 /* see if we can find the SA, and if so, decode it */
443                 for (sa = sa_list_head; sa != NULL; sa = sa->next) {
444                         struct sockaddr_in *sin = (struct sockaddr_in *)&sa->daddr;
445                         if (sa->spi == ntohl(esp->esp_spi) &&
446                             sin->sin_family == AF_INET &&
447                             sin->sin_addr.s_addr == ip->ip_dst.s_addr) {
448                                 break;
449                         }
450                 }
451                 break;
452         default:
453                 goto fail;
454         }
455
456         /* if we didn't find the specific one, then look for
457          * an unspecified one.
458          */
459         if (sa == NULL)
460                 sa = sa_default;
461         
462         /* if not found fail */
463         if (sa == NULL)
464                 goto fail;
465
466         /* if we can't get nexthdr, we do not need to decrypt it */
467         if (ep - bp2 < len)
468                 goto fail;
469         if (ep - bp2 > len) {
470                 /* FCS included at end of frame (NetBSD 1.6 or later) */
471                 ep = bp2 + len;
472         }
473
474         ivoff = (u_char *)(esp + 1) + 0;
475         ivlen = sa->ivlen;
476         secret = sa->secret;
477         espsecret_keylen = sa->secretlen;
478
479         if (sa->evp) {
480                 memset(&ctx, 0, sizeof(ctx));
481                 if (EVP_CipherInit(&ctx, sa->evp, secret, NULL, 0) < 0)
482                         printf("espkey init failed");
483
484                 blocksz = EVP_CIPHER_CTX_block_size(&ctx);
485
486                 p = ivoff;
487                 EVP_CipherInit(&ctx, NULL, NULL, p, 0);
488                 EVP_Cipher(&ctx, p + ivlen, p + ivlen, ep - (p + ivlen));
489                 advance = ivoff - (u_char *)esp + ivlen;
490         } else
491                 advance = sizeof(struct newesp);
492
493         ep = ep - sa->authlen;
494         /* sanity check for pad length */
495         if (ep - bp < *(ep - 2))
496                 goto fail;
497
498         if (padlen)
499                 *padlen = *(ep - 2) + 2;
500
501         if (nhdr)
502                 *nhdr = *(ep - 1);
503
504         printf(": ");
505         return advance;
506 #endif
507
508 fail:
509         return -1;
510 }