]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/tcpdump/print-esp.c
Merge ^/vendor/NetBSD/tests/dist@r311868
[FreeBSD/FreeBSD.git] / contrib / tcpdump / 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 #define NETDISSECT_REWORKED
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28
29 #include <tcpdump-stdinc.h>
30
31 #include <string.h>
32 #include <stdlib.h>
33
34 /* Any code in this file that depends on HAVE_LIBCRYPTO depends on
35  * HAVE_OPENSSL_EVP_H too. Undefining the former when the latter isn't defined
36  * is the simplest way of handling the dependency.
37  */
38 #ifdef HAVE_LIBCRYPTO
39 #ifdef HAVE_OPENSSL_EVP_H
40 #include <openssl/evp.h>
41 #else
42 #undef HAVE_LIBCRYPTO
43 #endif
44 #endif
45
46 #include "ip.h"
47 #ifdef INET6
48 #include "ip6.h"
49 #endif
50
51 #include "interface.h"
52 #include "extract.h"
53
54 /*
55  * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
56  * All rights reserved.
57  *
58  * Redistribution and use in source and binary forms, with or without
59  * modification, are permitted provided that the following conditions
60  * are met:
61  * 1. Redistributions of source code must retain the above copyright
62  *    notice, this list of conditions and the following disclaimer.
63  * 2. Redistributions in binary form must reproduce the above copyright
64  *    notice, this list of conditions and the following disclaimer in the
65  *    documentation and/or other materials provided with the distribution.
66  * 3. Neither the name of the project nor the names of its contributors
67  *    may be used to endorse or promote products derived from this software
68  *    without specific prior written permission.
69  *
70  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
71  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
72  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
73  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
74  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
75  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
76  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
77  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
78  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
79  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
80  * SUCH DAMAGE.
81  */
82
83 /*
84  * RFC1827/2406 Encapsulated Security Payload.
85  */
86
87 struct newesp {
88         uint32_t        esp_spi;        /* ESP */
89         uint32_t        esp_seq;        /* Sequence number */
90         /*variable size*/               /* (IV and) Payload data */
91         /*variable size*/               /* padding */
92         /*8bit*/                        /* pad size */
93         /*8bit*/                        /* next header */
94         /*8bit*/                        /* next header */
95         /*variable size, 32bit bound*/  /* Authentication data */
96 };
97
98 #ifdef HAVE_LIBCRYPTO
99 union inaddr_u {
100         struct in_addr in4;
101 #ifdef INET6
102         struct in6_addr in6;
103 #endif
104 };
105 struct sa_list {
106         struct sa_list  *next;
107         u_int           daddr_version;
108         union inaddr_u  daddr;
109         uint32_t        spi;          /* if == 0, then IKEv2 */
110         int             initiator;
111         u_char          spii[8];      /* for IKEv2 */
112         u_char          spir[8];
113         const EVP_CIPHER *evp;
114         int             ivlen;
115         int             authlen;
116         u_char          authsecret[256];
117         int             authsecret_len;
118         u_char          secret[256];  /* is that big enough for all secrets? */
119         int             secretlen;
120 };
121
122 /*
123  * this will adjust ndo_packetp and ndo_snapend to new buffer!
124  */
125 USES_APPLE_DEPRECATED_API
126 int esp_print_decrypt_buffer_by_ikev2(netdissect_options *ndo,
127                                       int initiator,
128                                       u_char spii[8], u_char spir[8],
129                                       u_char *buf, u_char *end)
130 {
131         struct sa_list *sa;
132         u_char *iv;
133         int len;
134         EVP_CIPHER_CTX ctx;
135
136         /* initiator arg is any non-zero value */
137         if(initiator) initiator=1;
138
139         /* see if we can find the SA, and if so, decode it */
140         for (sa = ndo->ndo_sa_list_head; sa != NULL; sa = sa->next) {
141                 if (sa->spi == 0
142                     && initiator == sa->initiator
143                     && memcmp(spii, sa->spii, 8) == 0
144                     && memcmp(spir, sa->spir, 8) == 0)
145                         break;
146         }
147
148         if(sa == NULL) return 0;
149         if(sa->evp == NULL) return 0;
150
151         /*
152          * remove authenticator, and see if we still have something to
153          * work with
154          */
155         end = end - sa->authlen;
156         iv  = buf;
157         buf = buf + sa->ivlen;
158         len = end-buf;
159
160         if(end <= buf) return 0;
161
162         memset(&ctx, 0, sizeof(ctx));
163         if (EVP_CipherInit(&ctx, sa->evp, sa->secret, NULL, 0) < 0)
164                 (*ndo->ndo_warning)(ndo, "espkey init failed");
165         EVP_CipherInit(&ctx, NULL, NULL, iv, 0);
166         EVP_Cipher(&ctx, buf, buf, len);
167         EVP_CIPHER_CTX_cleanup(&ctx);
168
169         ndo->ndo_packetp = buf;
170         ndo->ndo_snapend = end;
171
172         return 1;
173
174 }
175 USES_APPLE_RST
176
177 static void esp_print_addsa(netdissect_options *ndo,
178                             struct sa_list *sa, int sa_def)
179 {
180         /* copy the "sa" */
181
182         struct sa_list *nsa;
183
184         nsa = (struct sa_list *)malloc(sizeof(struct sa_list));
185         if (nsa == NULL)
186                 (*ndo->ndo_error)(ndo, "ran out of memory to allocate sa structure");
187
188         *nsa = *sa;
189
190         if (sa_def)
191                 ndo->ndo_sa_default = nsa;
192
193         nsa->next = ndo->ndo_sa_list_head;
194         ndo->ndo_sa_list_head = nsa;
195 }
196
197
198 static u_int hexdigit(netdissect_options *ndo, char hex)
199 {
200         if (hex >= '0' && hex <= '9')
201                 return (hex - '0');
202         else if (hex >= 'A' && hex <= 'F')
203                 return (hex - 'A' + 10);
204         else if (hex >= 'a' && hex <= 'f')
205                 return (hex - 'a' + 10);
206         else {
207                 (*ndo->ndo_error)(ndo, "invalid hex digit %c in espsecret\n", hex);
208                 return 0;
209         }
210 }
211
212 static u_int hex2byte(netdissect_options *ndo, char *hexstring)
213 {
214         u_int byte;
215
216         byte = (hexdigit(ndo, hexstring[0]) << 4) + hexdigit(ndo, hexstring[1]);
217         return byte;
218 }
219
220 /*
221  * returns size of binary, 0 on failure.
222  */
223 static
224 int espprint_decode_hex(netdissect_options *ndo,
225                         u_char *binbuf, unsigned int binbuf_len,
226                         char *hex)
227 {
228         unsigned int len;
229         int i;
230
231         len = strlen(hex) / 2;
232
233         if (len > binbuf_len) {
234                 (*ndo->ndo_warning)(ndo, "secret is too big: %d\n", len);
235                 return 0;
236         }
237
238         i = 0;
239         while (hex[0] != '\0' && hex[1]!='\0') {
240                 binbuf[i] = hex2byte(ndo, hex);
241                 hex += 2;
242                 i++;
243         }
244
245         return i;
246 }
247
248 /*
249  * decode the form:    SPINUM@IP <tab> ALGONAME:0xsecret
250  */
251
252 USES_APPLE_DEPRECATED_API
253 static int
254 espprint_decode_encalgo(netdissect_options *ndo,
255                         char *decode, struct sa_list *sa)
256 {
257         size_t i;
258         const EVP_CIPHER *evp;
259         int authlen = 0;
260         char *colon, *p;
261
262         colon = strchr(decode, ':');
263         if (colon == NULL) {
264                 (*ndo->ndo_warning)(ndo, "failed to decode espsecret: %s\n", decode);
265                 return 0;
266         }
267         *colon = '\0';
268
269         if (strlen(decode) > strlen("-hmac96") &&
270             !strcmp(decode + strlen(decode) - strlen("-hmac96"),
271                     "-hmac96")) {
272                 p = strstr(decode, "-hmac96");
273                 *p = '\0';
274                 authlen = 12;
275         }
276         if (strlen(decode) > strlen("-cbc") &&
277             !strcmp(decode + strlen(decode) - strlen("-cbc"), "-cbc")) {
278                 p = strstr(decode, "-cbc");
279                 *p = '\0';
280         }
281         evp = EVP_get_cipherbyname(decode);
282
283         if (!evp) {
284                 (*ndo->ndo_warning)(ndo, "failed to find cipher algo %s\n", decode);
285                 sa->evp = NULL;
286                 sa->authlen = 0;
287                 sa->ivlen = 0;
288                 return 0;
289         }
290
291         sa->evp = evp;
292         sa->authlen = authlen;
293         sa->ivlen = EVP_CIPHER_iv_length(evp);
294
295         colon++;
296         if (colon[0] == '0' && colon[1] == 'x') {
297                 /* decode some hex! */
298
299                 colon += 2;
300                 sa->secretlen = espprint_decode_hex(ndo, sa->secret, sizeof(sa->secret), colon);
301                 if(sa->secretlen == 0) return 0;
302         } else {
303                 i = strlen(colon);
304
305                 if (i < sizeof(sa->secret)) {
306                         memcpy(sa->secret, colon, i);
307                         sa->secretlen = i;
308                 } else {
309                         memcpy(sa->secret, colon, sizeof(sa->secret));
310                         sa->secretlen = sizeof(sa->secret);
311                 }
312         }
313
314         return 1;
315 }
316 USES_APPLE_RST
317
318 /*
319  * for the moment, ignore the auth algorith, just hard code the authenticator
320  * length. Need to research how openssl looks up HMAC stuff.
321  */
322 static int
323 espprint_decode_authalgo(netdissect_options *ndo,
324                          char *decode, struct sa_list *sa)
325 {
326         char *colon;
327
328         colon = strchr(decode, ':');
329         if (colon == NULL) {
330                 (*ndo->ndo_warning)(ndo, "failed to decode espsecret: %s\n", decode);
331                 return 0;
332         }
333         *colon = '\0';
334
335         if(strcasecmp(colon,"sha1") == 0 ||
336            strcasecmp(colon,"md5") == 0) {
337                 sa->authlen = 12;
338         }
339         return 1;
340 }
341
342 static void esp_print_decode_ikeline(netdissect_options *ndo, char *line,
343                                      const char *file, int lineno)
344 {
345         /* it's an IKEv2 secret, store it instead */
346         struct sa_list sa1;
347
348         char *init;
349         char *icookie, *rcookie;
350         int   ilen, rlen;
351         char *authkey;
352         char *enckey;
353
354         init = strsep(&line, " \t");
355         icookie = strsep(&line, " \t");
356         rcookie = strsep(&line, " \t");
357         authkey = strsep(&line, " \t");
358         enckey  = strsep(&line, " \t");
359
360         /* if any fields are missing */
361         if(!init || !icookie || !rcookie || !authkey || !enckey) {
362                 (*ndo->ndo_warning)(ndo, "print_esp: failed to find all fields for ikev2 at %s:%u",
363                                     file, lineno);
364
365                 return;
366         }
367
368         ilen = strlen(icookie);
369         rlen = strlen(rcookie);
370
371         if((init[0]!='I' && init[0]!='R')
372            || icookie[0]!='0' || icookie[1]!='x'
373            || rcookie[0]!='0' || rcookie[1]!='x'
374            || ilen!=18
375            || rlen!=18) {
376                 (*ndo->ndo_warning)(ndo, "print_esp: line %s:%u improperly formatted.",
377                                     file, lineno);
378
379                 (*ndo->ndo_warning)(ndo, "init=%s icookie=%s(%u) rcookie=%s(%u)",
380                                     init, icookie, ilen, rcookie, rlen);
381
382                 return;
383         }
384
385         sa1.spi = 0;
386         sa1.initiator = (init[0] == 'I');
387         if(espprint_decode_hex(ndo, sa1.spii, sizeof(sa1.spii), icookie+2)!=8)
388                 return;
389
390         if(espprint_decode_hex(ndo, sa1.spir, sizeof(sa1.spir), rcookie+2)!=8)
391                 return;
392
393         if(!espprint_decode_encalgo(ndo, enckey, &sa1)) return;
394
395         if(!espprint_decode_authalgo(ndo, authkey, &sa1)) return;
396
397         esp_print_addsa(ndo, &sa1, FALSE);
398 }
399
400 /*
401  *
402  * special form: file /name
403  * causes us to go read from this file instead.
404  *
405  */
406 static void esp_print_decode_onesecret(netdissect_options *ndo, char *line,
407                                        const char *file, int lineno)
408 {
409         struct sa_list sa1;
410         int sa_def;
411
412         char *spikey;
413         char *decode;
414
415         spikey = strsep(&line, " \t");
416         sa_def = 0;
417         memset(&sa1, 0, sizeof(struct sa_list));
418
419         /* if there is only one token, then it is an algo:key token */
420         if (line == NULL) {
421                 decode = spikey;
422                 spikey = NULL;
423                 /* sa1.daddr.version = 0; */
424                 /* memset(&sa1.daddr, 0, sizeof(sa1.daddr)); */
425                 /* sa1.spi = 0; */
426                 sa_def    = 1;
427         } else
428                 decode = line;
429
430         if (spikey && strcasecmp(spikey, "file") == 0) {
431                 /* open file and read it */
432                 FILE *secretfile;
433                 char  fileline[1024];
434                 int   lineno=0;
435                 char  *nl;
436                 char *filename = line;
437
438                 secretfile = fopen(filename, FOPEN_READ_TXT);
439                 if (secretfile == NULL) {
440                         perror(filename);
441                         exit(3);
442                 }
443
444                 while (fgets(fileline, sizeof(fileline)-1, secretfile) != NULL) {
445                         lineno++;
446                         /* remove newline from the line */
447                         nl = strchr(fileline, '\n');
448                         if (nl)
449                                 *nl = '\0';
450                         if (fileline[0] == '#') continue;
451                         if (fileline[0] == '\0') continue;
452
453                         esp_print_decode_onesecret(ndo, fileline, filename, lineno);
454                 }
455                 fclose(secretfile);
456
457                 return;
458         }
459
460         if (spikey && strcasecmp(spikey, "ikev2") == 0) {
461                 esp_print_decode_ikeline(ndo, line, file, lineno);
462                 return;
463         }
464
465         if (spikey) {
466
467                 char *spistr, *foo;
468                 uint32_t spino;
469
470                 spistr = strsep(&spikey, "@");
471
472                 spino = strtoul(spistr, &foo, 0);
473                 if (spistr == foo || !spikey) {
474                         (*ndo->ndo_warning)(ndo, "print_esp: failed to decode spi# %s\n", foo);
475                         return;
476                 }
477
478                 sa1.spi = spino;
479
480 #ifdef INET6
481                 if (inet_pton(AF_INET6, spikey, &sa1.daddr.in6) == 1) {
482                         sa1.daddr_version = 6;
483                 } else
484 #endif
485                         if (inet_pton(AF_INET, spikey, &sa1.daddr.in4) == 1) {
486                                 sa1.daddr_version = 4;
487                         } else {
488                                 (*ndo->ndo_warning)(ndo, "print_esp: can not decode IP# %s\n", spikey);
489                                 return;
490                         }
491         }
492
493         if (decode) {
494                 /* skip any blank spaces */
495                 while (isspace((unsigned char)*decode))
496                         decode++;
497
498                 if(!espprint_decode_encalgo(ndo, decode, &sa1)) {
499                         return;
500                 }
501         }
502
503         esp_print_addsa(ndo, &sa1, sa_def);
504 }
505
506 USES_APPLE_DEPRECATED_API
507 static void esp_init(netdissect_options *ndo _U_)
508 {
509
510         OpenSSL_add_all_algorithms();
511         EVP_add_cipher_alias(SN_des_ede3_cbc, "3des");
512 }
513 USES_APPLE_RST
514
515 void esp_print_decodesecret(netdissect_options *ndo)
516 {
517         char *line;
518         char *p;
519         static int initialized = 0;
520
521         if (!initialized) {
522                 esp_init(ndo);
523                 initialized = 1;
524         }
525
526         p = ndo->ndo_espsecret;
527
528         while (p && p[0] != '\0') {
529                 /* pick out the first line or first thing until a comma */
530                 if ((line = strsep(&p, "\n,")) == NULL) {
531                         line = p;
532                         p = NULL;
533                 }
534
535                 esp_print_decode_onesecret(ndo, line, "cmdline", 0);
536         }
537
538         ndo->ndo_espsecret = NULL;
539 }
540
541 #endif
542
543 #ifdef HAVE_LIBCRYPTO
544 USES_APPLE_DEPRECATED_API
545 #endif
546 int
547 esp_print(netdissect_options *ndo,
548           const u_char *bp, const int length, const u_char *bp2
549 #ifndef HAVE_LIBCRYPTO
550         _U_
551 #endif
552         ,
553         int *nhdr
554 #ifndef HAVE_LIBCRYPTO
555         _U_
556 #endif
557         ,
558         int *padlen
559 #ifndef HAVE_LIBCRYPTO
560         _U_
561 #endif
562         )
563 {
564         register const struct newesp *esp;
565         register const u_char *ep;
566 #ifdef HAVE_LIBCRYPTO
567         struct ip *ip;
568         struct sa_list *sa = NULL;
569 #ifdef INET6
570         struct ip6_hdr *ip6 = NULL;
571 #endif
572         int advance;
573         int len;
574         u_char *secret;
575         int ivlen = 0;
576         u_char *ivoff;
577         u_char *p;
578         EVP_CIPHER_CTX ctx;
579 #endif
580
581         esp = (struct newesp *)bp;
582
583 #ifdef HAVE_LIBCRYPTO
584         secret = NULL;
585         advance = 0;
586 #endif
587
588 #if 0
589         /* keep secret out of a register */
590         p = (u_char *)&secret;
591 #endif
592
593         /* 'ep' points to the end of available data. */
594         ep = ndo->ndo_snapend;
595
596         if ((u_char *)(esp + 1) >= ep) {
597                 ND_PRINT((ndo, "[|ESP]"));
598                 goto fail;
599         }
600         ND_PRINT((ndo, "ESP(spi=0x%08x", EXTRACT_32BITS(&esp->esp_spi)));
601         ND_PRINT((ndo, ",seq=0x%x)", EXTRACT_32BITS(&esp->esp_seq)));
602         ND_PRINT((ndo, ", length %u", length));
603
604 #ifndef HAVE_LIBCRYPTO
605         goto fail;
606 #else
607         /* initiailize SAs */
608         if (ndo->ndo_sa_list_head == NULL) {
609                 if (!ndo->ndo_espsecret)
610                         goto fail;
611
612                 esp_print_decodesecret(ndo);
613         }
614
615         if (ndo->ndo_sa_list_head == NULL)
616                 goto fail;
617
618         ip = (struct ip *)bp2;
619         switch (IP_V(ip)) {
620 #ifdef INET6
621         case 6:
622                 ip6 = (struct ip6_hdr *)bp2;
623                 /* we do not attempt to decrypt jumbograms */
624                 if (!EXTRACT_16BITS(&ip6->ip6_plen))
625                         goto fail;
626                 /* if we can't get nexthdr, we do not need to decrypt it */
627                 len = sizeof(struct ip6_hdr) + EXTRACT_16BITS(&ip6->ip6_plen);
628
629                 /* see if we can find the SA, and if so, decode it */
630                 for (sa = ndo->ndo_sa_list_head; sa != NULL; sa = sa->next) {
631                         if (sa->spi == EXTRACT_32BITS(&esp->esp_spi) &&
632                             sa->daddr_version == 6 &&
633                             UNALIGNED_MEMCMP(&sa->daddr.in6, &ip6->ip6_dst,
634                                    sizeof(struct in6_addr)) == 0) {
635                                 break;
636                         }
637                 }
638                 break;
639 #endif /*INET6*/
640         case 4:
641                 /* nexthdr & padding are in the last fragment */
642                 if (EXTRACT_16BITS(&ip->ip_off) & IP_MF)
643                         goto fail;
644                 len = EXTRACT_16BITS(&ip->ip_len);
645
646                 /* see if we can find the SA, and if so, decode it */
647                 for (sa = ndo->ndo_sa_list_head; sa != NULL; sa = sa->next) {
648                         if (sa->spi == EXTRACT_32BITS(&esp->esp_spi) &&
649                             sa->daddr_version == 4 &&
650                             UNALIGNED_MEMCMP(&sa->daddr.in4, &ip->ip_dst,
651                                    sizeof(struct in_addr)) == 0) {
652                                 break;
653                         }
654                 }
655                 break;
656         default:
657                 goto fail;
658         }
659
660         /* if we didn't find the specific one, then look for
661          * an unspecified one.
662          */
663         if (sa == NULL)
664                 sa = ndo->ndo_sa_default;
665
666         /* if not found fail */
667         if (sa == NULL)
668                 goto fail;
669
670         /* if we can't get nexthdr, we do not need to decrypt it */
671         if (ep - bp2 < len)
672                 goto fail;
673         if (ep - bp2 > len) {
674                 /* FCS included at end of frame (NetBSD 1.6 or later) */
675                 ep = bp2 + len;
676         }
677
678         ivoff = (u_char *)(esp + 1) + 0;
679         ivlen = sa->ivlen;
680         secret = sa->secret;
681         ep = ep - sa->authlen;
682
683         if (sa->evp) {
684                 memset(&ctx, 0, sizeof(ctx));
685                 if (EVP_CipherInit(&ctx, sa->evp, secret, NULL, 0) < 0)
686                         (*ndo->ndo_warning)(ndo, "espkey init failed");
687
688                 p = ivoff;
689                 EVP_CipherInit(&ctx, NULL, NULL, p, 0);
690                 EVP_Cipher(&ctx, p + ivlen, p + ivlen, ep - (p + ivlen));
691                 EVP_CIPHER_CTX_cleanup(&ctx);
692                 advance = ivoff - (u_char *)esp + ivlen;
693         } else
694                 advance = sizeof(struct newesp);
695
696         /* sanity check for pad length */
697         if (ep - bp < *(ep - 2))
698                 goto fail;
699
700         if (padlen)
701                 *padlen = *(ep - 2) + 2;
702
703         if (nhdr)
704                 *nhdr = *(ep - 1);
705
706         ND_PRINT((ndo, ": "));
707         return advance;
708 #endif
709
710 fail:
711         return -1;
712 }
713 #ifdef HAVE_LIBCRYPTO
714 USES_APPLE_RST
715 #endif
716
717 /*
718  * Local Variables:
719  * c-style: whitesmith
720  * c-basic-offset: 8
721  * End:
722  */