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