xref: /netbsd-src/crypto/external/bsd/netpgp/dist/src/lib/reader.c (revision 4e6df137e8e14049b5a701d249962c480449c141)
1 /*-
2  * Copyright (c) 2009 The NetBSD Foundation, Inc.
3  * All rights reserved.
4  *
5  * This code is derived from software contributed to The NetBSD Foundation
6  * by Alistair Crooks (agc@NetBSD.org)
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
18  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
21  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  */
29 /*
30  * Copyright (c) 2005-2008 Nominet UK (www.nic.uk)
31  * All rights reserved.
32  * Contributors: Ben Laurie, Rachel Willmer. The Contributors have asserted
33  * their moral rights under the UK Copyright Design and Patents Act 1988 to
34  * be recorded as the authors of this copyright work.
35  *
36  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
37  * use this file except in compliance with the License.
38  *
39  * You may obtain a copy of the License at
40  *     http://www.apache.org/licenses/LICENSE-2.0
41  *
42  * Unless required by applicable law or agreed to in writing, software
43  * distributed under the License is distributed on an "AS IS" BASIS,
44  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
45  *
46  * See the License for the specific language governing permissions and
47  * limitations under the License.
48  */
49 #include "config.h"
50 
51 #ifdef HAVE_SYS_CDEFS_H
52 #include <sys/cdefs.h>
53 #endif
54 
55 #if defined(__NetBSD__)
56 __COPYRIGHT("@(#) Copyright (c) 2009 The NetBSD Foundation, Inc. All rights reserved.");
57 __RCSID("$NetBSD: reader.c,v 1.31 2010/03/05 16:01:10 agc Exp $");
58 #endif
59 
60 #include <sys/types.h>
61 #include <sys/stat.h>
62 
63 #ifdef HAVE_SYS_MMAN_H
64 #include <sys/mman.h>
65 #endif
66 
67 #ifdef HAVE_SYS_PARAM_H
68 #include <sys/param.h>
69 #endif
70 
71 #ifdef HAVE_FCNTL_H
72 #include <fcntl.h>
73 #endif
74 
75 #ifdef HAVE_UNISTD_H
76 #include <unistd.h>
77 #endif
78 
79 #ifdef HAVE_DIRECT_H
80 #include <direct.h>
81 #endif
82 
83 #ifdef HAVE_INTTYPES_H
84 #include <inttypes.h>
85 #endif
86 
87 #ifdef HAVE_OPENSSL_IDEA_H
88 #include <openssl/cast.h>
89 #endif
90 
91 #ifdef HAVE_OPENSSL_IDEA_H
92 #include <openssl/idea.h>
93 #endif
94 
95 #ifdef HAVE_OPENSSL_AES_H
96 #include <openssl/aes.h>
97 #endif
98 
99 #ifdef HAVE_OPENSSL_DES_H
100 #include <openssl/des.h>
101 #endif
102 
103 #include <string.h>
104 #include <stdlib.h>
105 #include <stdio.h>
106 
107 #ifdef HAVE_TERMIOS_H
108 #include <termios.h>
109 #endif
110 
111 #ifdef HAVE_ERRNO_H
112 #include <errno.h>
113 #endif
114 
115 #ifdef HAVE_UNISTD_H
116 #include <unistd.h>
117 #endif
118 
119 #ifdef HAVE_LIMITS_H
120 #include <limits.h>
121 #endif
122 
123 #include "errors.h"
124 #include "crypto.h"
125 #include "create.h"
126 #include "signature.h"
127 #include "packet.h"
128 #include "packet-parse.h"
129 #include "packet-show.h"
130 #include "packet.h"
131 #include "keyring.h"
132 #include "readerwriter.h"
133 #include "netpgpsdk.h"
134 #include "netpgpdefs.h"
135 #include "netpgpdigest.h"
136 
137 
138 /* get a pass phrase from the user */
139 int
140 __ops_getpassphrase(void *in, char *phrase, size_t size)
141 {
142 	char	*p;
143 
144 	if (in == NULL) {
145 		while ((p = getpass("netpgp passphrase: ")) == NULL) {
146 		}
147 		(void) snprintf(phrase, size, "%s", p);
148 	} else {
149 		if (fgets(phrase, (int)size, in) == NULL) {
150 			return 0;
151 		}
152 		phrase[strlen(phrase) - 1] = 0x0;
153 	}
154 	return 1;
155 }
156 
157 /**
158  * \ingroup Internal_Readers_Generic
159  * \brief Starts reader stack
160  * \param stream Parse settings
161  * \param reader Reader to use
162  * \param destroyer Destroyer to use
163  * \param vp Reader-specific arg
164  */
165 void
166 __ops_reader_set(__ops_stream_t *stream,
167 		__ops_reader_func_t *reader,
168 		__ops_reader_destroyer_t *destroyer,
169 		void *vp)
170 {
171 	stream->readinfo.reader = reader;
172 	stream->readinfo.destroyer = destroyer;
173 	stream->readinfo.arg = vp;
174 }
175 
176 /**
177  * \ingroup Internal_Readers_Generic
178  * \brief Adds to reader stack
179  * \param stream Parse settings
180  * \param reader Reader to use
181  * \param destroyer Reader's destroyer
182  * \param vp Reader-specific arg
183  */
184 void
185 __ops_reader_push(__ops_stream_t *stream,
186 		__ops_reader_func_t *reader,
187 		__ops_reader_destroyer_t *destroyer,
188 		void *vp)
189 {
190 	__ops_reader_t *readinfo;
191 
192 	if ((readinfo = calloc(1, sizeof(*readinfo))) == NULL) {
193 		(void) fprintf(stderr, "__ops_reader_push: bad alloc\n");
194 	} else {
195 		*readinfo = stream->readinfo;
196 		(void) memset(&stream->readinfo, 0x0, sizeof(stream->readinfo));
197 		stream->readinfo.next = readinfo;
198 		stream->readinfo.parent = stream;
199 
200 		/* should copy accumulate flags from other reader? RW */
201 		stream->readinfo.accumulate = readinfo->accumulate;
202 
203 		__ops_reader_set(stream, reader, destroyer, vp);
204 	}
205 }
206 
207 /**
208  * \ingroup Internal_Readers_Generic
209  * \brief Removes from reader stack
210  * \param stream Parse settings
211  */
212 void
213 __ops_reader_pop(__ops_stream_t *stream)
214 {
215 	__ops_reader_t *next = stream->readinfo.next;
216 
217 	stream->readinfo = *next;
218 	free(next);
219 }
220 
221 /**
222  * \ingroup Internal_Readers_Generic
223  * \brief Gets arg from reader
224  * \param readinfo Reader info
225  * \return Pointer to reader info's arg
226  */
227 void           *
228 __ops_reader_get_arg(__ops_reader_t *readinfo)
229 {
230 	return readinfo->arg;
231 }
232 
233 /**************************************************************************/
234 
235 #define CRC24_POLY 0x1864cfbL
236 
237 enum {
238 	NONE = 0,
239 	BEGIN_PGP_MESSAGE,
240 	BEGIN_PGP_PUBLIC_KEY_BLOCK,
241 	BEGIN_PGP_PRIVATE_KEY_BLOCK,
242 	BEGIN_PGP_MULTI,
243 	BEGIN_PGP_SIGNATURE,
244 
245 	END_PGP_MESSAGE,
246 	END_PGP_PUBLIC_KEY_BLOCK,
247 	END_PGP_PRIVATE_KEY_BLOCK,
248 	END_PGP_MULTI,
249 	END_PGP_SIGNATURE,
250 
251 	BEGIN_PGP_SIGNED_MESSAGE
252 };
253 
254 /**
255  * \struct dearmour_t
256  */
257 typedef struct {
258 	enum {
259 		OUTSIDE_BLOCK = 0,
260 		BASE64,
261 		AT_TRAILER_NAME
262 	} state;
263 	int		lastseen;
264 	__ops_stream_t *parse_info;
265 	unsigned	seen_nl:1;
266 	unsigned	prev_nl:1;
267 	unsigned	allow_headers_without_gap:1;
268 			/* !< allow headers in armoured data that are
269 			* not separated from the data by a blank line
270 			* */
271 	unsigned	allow_no_gap:1;
272 			/* !< allow no blank line at the start of
273 			* armoured data */
274 	unsigned	allow_trailing_whitespace:1;
275 			/* !< allow armoured stuff to have trailing
276 			* whitespace where we wouldn't strictly expect
277 			* it */
278 	/* it is an error to get a cleartext message without a sig */
279 	unsigned   	expect_sig:1;
280 	unsigned   	got_sig:1;
281 	/* base64 stuff */
282 	unsigned        buffered;
283 	uint8_t		buffer[3];
284 	unsigned	eof64;
285 	uint32_t   checksum;
286 	uint32_t   read_checksum;
287 	/* unarmoured text blocks */
288 	uint8_t   unarmoured[NETPGP_BUFSIZ];
289 	size_t          unarmoredc;
290 	/* pushed back data (stored backwards) */
291 	uint8_t  *pushback;
292 	unsigned        pushbackc;
293 	/* armoured block headers */
294 	__ops_headers_t	headers;
295 } dearmour_t;
296 
297 static void
298 push_back(dearmour_t *dearmour, const uint8_t *buf,
299 	  unsigned length)
300 {
301 	unsigned        n;
302 
303 	if (dearmour->pushback) {
304 		(void) fprintf(stderr, "push_back: already pushed back\n");
305 	} else if ((dearmour->pushback = calloc(1, length)) == NULL) {
306 		(void) fprintf(stderr, "push_back: bad alloc\n");
307 	} else {
308 		for (n = 0; n < length; ++n) {
309 			dearmour->pushback[n] = buf[(length - n) - 1];
310 		}
311 		dearmour->pushbackc = length;
312 	}
313 }
314 
315 /* this struct holds a textual header line */
316 typedef struct headerline_t {
317 	const char	*s;		/* the header line */
318 	size_t		 len;		/* its length */
319 	int		 type;		/* the defined type */
320 } headerline_t;
321 
322 static headerline_t	headerlines[] = {
323 	{ "BEGIN PGP MESSAGE",		17, BEGIN_PGP_MESSAGE },
324 	{ "BEGIN PGP PUBLIC KEY BLOCK",	26, BEGIN_PGP_PUBLIC_KEY_BLOCK },
325 	{ "BEGIN PGP PRIVATE KEY BLOCK",27, BEGIN_PGP_PRIVATE_KEY_BLOCK },
326 	{ "BEGIN PGP MESSAGE, PART ",	25, BEGIN_PGP_MULTI },
327 	{ "BEGIN PGP SIGNATURE",	19, BEGIN_PGP_SIGNATURE },
328 
329 	{ "END PGP MESSAGE",		15, END_PGP_MESSAGE },
330 	{ "END PGP PUBLIC KEY BLOCK",	24, END_PGP_PUBLIC_KEY_BLOCK },
331 	{ "END PGP PRIVATE KEY BLOCK",	25, END_PGP_PRIVATE_KEY_BLOCK },
332 	{ "END PGP MESSAGE, PART ",	22, END_PGP_MULTI },
333 	{ "END PGP SIGNATURE",		17, END_PGP_SIGNATURE },
334 
335 	{ "BEGIN PGP SIGNED MESSAGE",	24, BEGIN_PGP_SIGNED_MESSAGE },
336 
337 	{ NULL,				0, -1	}
338 };
339 
340 /* search through the table of header lines */
341 static int
342 findheaderline(char *headerline)
343 {
344 	headerline_t	*hp;
345 
346 	for (hp = headerlines ; hp->s ; hp++) {
347 		if (strncmp(headerline, hp->s, hp->len) == 0) {
348 			break;
349 		}
350 	}
351 	return hp->type;
352 }
353 
354 static int
355 set_lastseen_headerline(dearmour_t *dearmour, char *hdr, __ops_error_t **errors)
356 {
357 	int	lastseen;
358 	int	prev;
359 
360 	prev = dearmour->lastseen;
361 	if ((lastseen = findheaderline(hdr)) == -1) {
362 		OPS_ERROR_1(errors, OPS_E_R_BAD_FORMAT,
363 			"Unrecognised Header Line %s", hdr);
364 		return 0;
365 	}
366 	dearmour->lastseen = lastseen;
367 	if (__ops_get_debug_level(__FILE__)) {
368 		printf("set header: hdr=%s, dearmour->lastseen=%d, prev=%d\n",
369 			hdr, dearmour->lastseen, prev);
370 	}
371 	switch (dearmour->lastseen) {
372 	case NONE:
373 		OPS_ERROR_1(errors, OPS_E_R_BAD_FORMAT,
374 			"Unrecognised last seen Header Line %s", hdr);
375 		break;
376 
377 	case END_PGP_MESSAGE:
378 		if (prev != BEGIN_PGP_MESSAGE) {
379 			OPS_ERROR(errors, OPS_E_R_BAD_FORMAT,
380 				"Got END PGP MESSAGE, but not after BEGIN");
381 		}
382 		break;
383 
384 	case END_PGP_PUBLIC_KEY_BLOCK:
385 		if (prev != BEGIN_PGP_PUBLIC_KEY_BLOCK) {
386 			OPS_ERROR(errors, OPS_E_R_BAD_FORMAT,
387 			"Got END PGP PUBLIC KEY BLOCK, but not after BEGIN");
388 		}
389 		break;
390 
391 	case END_PGP_PRIVATE_KEY_BLOCK:
392 		if (prev != BEGIN_PGP_PRIVATE_KEY_BLOCK) {
393 			OPS_ERROR(errors, OPS_E_R_BAD_FORMAT,
394 			"Got END PGP PRIVATE KEY BLOCK, but not after BEGIN");
395 		}
396 		break;
397 
398 	case BEGIN_PGP_MULTI:
399 	case END_PGP_MULTI:
400 		OPS_ERROR(errors, OPS_E_R_UNSUPPORTED,
401 			"Multi-part messages are not yet supported");
402 		break;
403 
404 	case END_PGP_SIGNATURE:
405 		if (prev != BEGIN_PGP_SIGNATURE) {
406 			OPS_ERROR(errors, OPS_E_R_BAD_FORMAT,
407 			"Got END PGP SIGNATURE, but not after BEGIN");
408 		}
409 		break;
410 
411 	case BEGIN_PGP_MESSAGE:
412 	case BEGIN_PGP_PUBLIC_KEY_BLOCK:
413 	case BEGIN_PGP_PRIVATE_KEY_BLOCK:
414 	case BEGIN_PGP_SIGNATURE:
415 	case BEGIN_PGP_SIGNED_MESSAGE:
416 		break;
417 	}
418 	return 1;
419 }
420 
421 static int
422 read_char(dearmour_t *dearmour,
423 		__ops_error_t **errors,
424 		__ops_reader_t *readinfo,
425 		__ops_cbdata_t *cbinfo,
426 		unsigned skip)
427 {
428 	uint8_t   c;
429 
430 	do {
431 		if (dearmour->pushbackc) {
432 			c = dearmour->pushback[--dearmour->pushbackc];
433 			if (dearmour->pushbackc == 0) {
434 				free(dearmour->pushback);
435 				dearmour->pushback = NULL;
436 			}
437 		} else if (__ops_stacked_read(&c, 1, errors, readinfo,
438 					cbinfo) != 1) {
439 			return -1;
440 		}
441 	} while (skip && c == '\r');
442 	dearmour->prev_nl = dearmour->seen_nl;
443 	dearmour->seen_nl = c == '\n';
444 	return c;
445 }
446 
447 static int
448 eat_whitespace(int first,
449 	       dearmour_t *dearmour,
450 	       __ops_error_t **errors,
451 	       __ops_reader_t *readinfo,
452 	       __ops_cbdata_t *cbinfo,
453 	       unsigned skip)
454 {
455 	int             c = first;
456 
457 	while (c == ' ' || c == '\t') {
458 		c = read_char(dearmour, errors, readinfo, cbinfo, skip);
459 	}
460 	return c;
461 }
462 
463 static int
464 read_and_eat_whitespace(dearmour_t *dearmour,
465 			__ops_error_t **errors,
466 			__ops_reader_t *readinfo,
467 			__ops_cbdata_t *cbinfo,
468 			unsigned skip)
469 {
470 	int             c;
471 
472 	do {
473 		c = read_char(dearmour, errors, readinfo, cbinfo, skip);
474 	} while (c == ' ' || c == '\t');
475 	return c;
476 }
477 
478 static void
479 flush(dearmour_t *dearmour, __ops_cbdata_t *cbinfo)
480 {
481 	__ops_packet_t	content;
482 
483 	if (dearmour->unarmoredc > 0) {
484 		content.u.unarmoured_text.data = dearmour->unarmoured;
485 		content.u.unarmoured_text.length = dearmour->unarmoredc;
486 		CALLBACK(OPS_PTAG_CT_UNARMOURED_TEXT, cbinfo, &content);
487 		dearmour->unarmoredc = 0;
488 	}
489 }
490 
491 static int
492 unarmoured_read_char(dearmour_t *dearmour,
493 			__ops_error_t **errors,
494 			__ops_reader_t *readinfo,
495 			__ops_cbdata_t *cbinfo,
496 			unsigned skip)
497 {
498 	int             c;
499 
500 	do {
501 		c = read_char(dearmour, errors, readinfo, cbinfo, 0);
502 		if (c < 0) {
503 			return c;
504 		}
505 		dearmour->unarmoured[dearmour->unarmoredc++] = c;
506 		if (dearmour->unarmoredc == sizeof(dearmour->unarmoured)) {
507 			flush(dearmour, cbinfo);
508 		}
509 	} while (skip && c == '\r');
510 	return c;
511 }
512 
513 /**
514  * \param headers
515  * \param key
516  *
517  * \return header value if found, otherwise NULL
518  */
519 static const char *
520 __ops_find_header(__ops_headers_t *headers, const char *key)
521 {
522 	unsigned        n;
523 
524 	for (n = 0; n < headers->headerc; ++n) {
525 		if (strcmp(headers->headers[n].key, key) == 0) {
526 			return headers->headers[n].value;
527 		}
528 	}
529 	return NULL;
530 }
531 
532 /**
533  * \param dest
534  * \param src
535  */
536 static void
537 __ops_dup_headers(__ops_headers_t *dest, const __ops_headers_t *src)
538 {
539 	unsigned        n;
540 
541 	if ((dest->headers = calloc(src->headerc, sizeof(*dest->headers))) == NULL) {
542 		(void) fprintf(stderr, "__ops_dup_headers: bad alloc\n");
543 	} else {
544 		dest->headerc = src->headerc;
545 		for (n = 0; n < src->headerc; ++n) {
546 			dest->headers[n].key = netpgp_strdup(src->headers[n].key);
547 			dest->headers[n].value = netpgp_strdup(src->headers[n].value);
548 		}
549 	}
550 }
551 
552 /*
553  * Note that this skips CRs so implementations always see just straight LFs
554  * as line terminators
555  */
556 static int
557 process_dash_escaped(dearmour_t *dearmour,
558 			__ops_error_t **errors,
559 			__ops_reader_t *readinfo,
560 			__ops_cbdata_t *cbinfo)
561 {
562 	__ops_packet_t content;
563 	__ops_packet_t content2;
564 	__ops_cleartext_body_t *body = &content.u.cleartext_body;
565 	__ops_cleartext_trailer_t *trailer = &content2.u.cleartext_trailer;
566 	const char     *hashstr;
567 	__ops_hash_t     *hash;
568 	int             total;
569 
570 	if ((hash = calloc(1, sizeof(*hash))) == NULL) {
571 		OPS_ERROR(errors, OPS_E_R_BAD_FORMAT,
572 			"process_dash_escaped: bad alloc");
573 		return -1;
574 	}
575 	hashstr = __ops_find_header(&dearmour->headers, "Hash");
576 	if (hashstr) {
577 		__ops_hash_alg_t alg;
578 
579 		alg = __ops_str_to_hash_alg(hashstr);
580 		if (!__ops_is_hash_alg_supported(&alg)) {
581 			free(hash);
582 			OPS_ERROR_1(errors, OPS_E_R_BAD_FORMAT,
583 				"Unsupported hash algorithm '%s'", hashstr);
584 			return -1;
585 		}
586 		if (alg == OPS_HASH_UNKNOWN) {
587 			free(hash);
588 			OPS_ERROR_1(errors, OPS_E_R_BAD_FORMAT,
589 				"Unknown hash algorithm '%s'", hashstr);
590 			return -1;
591 		}
592 		__ops_hash_any(hash, alg);
593 	} else {
594 		__ops_hash_md5(hash);
595 	}
596 
597 	if (!hash->init(hash)) {
598 		OPS_ERROR(errors, OPS_E_R_BAD_FORMAT,
599 			"can't initialise hash");
600 		return -1;
601 	}
602 
603 	body->length = 0;
604 	total = 0;
605 	for (;;) {
606 		int             c;
607 		unsigned        count;
608 
609 		c = read_char(dearmour, errors, readinfo, cbinfo, 1);
610 		if (c < 0) {
611 			return -1;
612 		}
613 		if (dearmour->prev_nl && c == '-') {
614 			if ((c = read_char(dearmour, errors, readinfo, cbinfo,
615 						0)) < 0) {
616 				return -1;
617 			}
618 			if (c != ' ') {
619 				/* then this had better be a trailer! */
620 				if (c != '-') {
621 					OPS_ERROR(errors, OPS_E_R_BAD_FORMAT,
622 						"Bad dash-escaping");
623 				}
624 				for (count = 2; count < 5; ++count) {
625 					if ((c = read_char(dearmour, errors,
626 						readinfo, cbinfo, 0)) < 0) {
627 						return -1;
628 					}
629 					if (c != '-') {
630 						OPS_ERROR(errors,
631 						OPS_E_R_BAD_FORMAT,
632 						"Bad dash-escaping (2)");
633 					}
634 				}
635 				dearmour->state = AT_TRAILER_NAME;
636 				break;
637 			}
638 			/* otherwise we read the next character */
639 			if ((c = read_char(dearmour, errors, readinfo, cbinfo,
640 						0)) < 0) {
641 				return -1;
642 			}
643 		}
644 		if (c == '\n' && body->length) {
645 			if (memchr(body->data + 1, '\n', body->length - 1)
646 						!= NULL) {
647 				(void) fprintf(stderr,
648 				"process_dash_escaped: newline found\n");
649 				return -1;
650 			}
651 			if (body->data[0] == '\n') {
652 				hash->add(hash, (const uint8_t *)"\r", 1);
653 			}
654 			hash->add(hash, body->data, body->length);
655 			if (__ops_get_debug_level(__FILE__)) {
656 				fprintf(stderr, "Got body:\n%s\n", body->data);
657 			}
658 			CALLBACK(OPS_PTAG_CT_SIGNED_CLEARTEXT_BODY, cbinfo,
659 						&content);
660 			body->length = 0;
661 		}
662 		body->data[body->length++] = c;
663 		total += 1;
664 		if (body->length == sizeof(body->data)) {
665 			if (__ops_get_debug_level(__FILE__)) {
666 				(void) fprintf(stderr, "Got body (2):\n%s\n",
667 						body->data);
668 			}
669 			CALLBACK(OPS_PTAG_CT_SIGNED_CLEARTEXT_BODY, cbinfo,
670 					&content);
671 			body->length = 0;
672 		}
673 	}
674 	if (body->data[0] != '\n') {
675 		(void) fprintf(stderr,
676 			"process_dash_escaped: no newline in body data\n");
677 		return -1;
678 	}
679 	if (body->length != 1) {
680 		(void) fprintf(stderr,
681 			"process_dash_escaped: bad body length\n");
682 		return -1;
683 	}
684 
685 	/* don't send that one character, because it's part of the trailer */
686 	trailer->hash = hash;
687 	CALLBACK(OPS_PTAG_CT_SIGNED_CLEARTEXT_TRAILER, cbinfo, &content2);
688 	return total;
689 }
690 
691 static int
692 add_header(dearmour_t *dearmour, const char *key, const char *value)
693 {
694 	int	n;
695 
696 	/*
697          * Check that the header is valid
698          */
699 	if (strcmp(key, "Version") == 0 ||
700 	    strcmp(key, "Comment") == 0 ||
701 	    strcmp(key, "MessageID") == 0 ||
702 	    strcmp(key, "Hash") == 0 ||
703 	    strcmp(key, "Charset") == 0) {
704 		n = dearmour->headers.headerc;
705 		dearmour->headers.headers = realloc(dearmour->headers.headers,
706 				(n + 1) * sizeof(*dearmour->headers.headers));
707 		if (dearmour->headers.headers == NULL) {
708 			(void) fprintf(stderr, "add_header: bad alloc\n");
709 			return 0;
710 		}
711 		dearmour->headers.headers[n].key = netpgp_strdup(key);
712 		dearmour->headers.headers[n].value = netpgp_strdup(value);
713 		dearmour->headers.headerc = n + 1;
714 		return 1;
715 	}
716 	return 0;
717 }
718 
719 /* \todo what does a return value of 0 indicate? 1 is good, -1 is bad */
720 static int
721 parse_headers(dearmour_t *dearmour, __ops_error_t **errors,
722 	      __ops_reader_t * readinfo, __ops_cbdata_t * cbinfo)
723 {
724 	unsigned        nbuf;
725 	unsigned        size;
726 	unsigned	first = 1;
727 	char           *buf;
728 	int             ret = 1;
729 
730 	nbuf = 0;
731 	size = 80;
732 	if ((buf = calloc(1, size)) == NULL) {
733 		(void) fprintf(stderr, "parse_headers: bad calloc\n");
734 		return -1;
735 	}
736 	for (;;) {
737 		int             c;
738 
739 		if ((c = read_char(dearmour, errors, readinfo, cbinfo, 1)) < 0) {
740 			OPS_ERROR(errors, OPS_E_R_BAD_FORMAT, "Unexpected EOF");
741 			ret = -1;
742 			break;
743 		}
744 		if (c == '\n') {
745 			char           *s;
746 
747 			if (nbuf == 0) {
748 				break;
749 			}
750 
751 			if (nbuf >= size) {
752 				(void) fprintf(stderr,
753 					"parse_headers: bad size\n");
754 				return -1;
755 			}
756 			buf[nbuf] = '\0';
757 
758 			if ((s = strchr(buf, ':')) == NULL) {
759 				if (!first && !dearmour->allow_headers_without_gap) {
760 					/*
761 					 * then we have seriously malformed
762 					 * armour
763 					 */
764 					OPS_ERROR(errors, OPS_E_R_BAD_FORMAT, "No colon in armour header");
765 					ret = -1;
766 					break;
767 				} else {
768 					if (first &&
769 					    !(dearmour->allow_headers_without_gap || dearmour->allow_no_gap)) {
770 						OPS_ERROR(errors, OPS_E_R_BAD_FORMAT, "No colon in armour header (2)");
771 						/*
772 						 * then we have a nasty
773 						 * armoured block with no
774 						 * headers, not even a blank
775 						 * line.
776 						 */
777 						buf[nbuf] = '\n';
778 						push_back(dearmour, (uint8_t *) buf, nbuf + 1);
779 						ret = -1;
780 						break;
781 					}
782 				}
783 			} else {
784 				*s = '\0';
785 				if (s[1] != ' ') {
786 					OPS_ERROR(errors, OPS_E_R_BAD_FORMAT, "No space in armour header");
787 					ret = -1;
788 					goto end;
789 				}
790 				if (!add_header(dearmour, buf, s + 2)) {
791 					OPS_ERROR_1(errors, OPS_E_R_BAD_FORMAT, "Invalid header %s", buf);
792 					ret = -1;
793 					goto end;
794 				}
795 				nbuf = 0;
796 			}
797 			first = 0;
798 		} else {
799 			if (size <= nbuf + 1) {
800 				size += size + 80;
801 				buf = realloc(buf, size);
802 				if (buf == NULL) {
803 					(void) fprintf(stderr, "bad alloc\n");
804 					ret = -1;
805 					goto end;
806 				}
807 			}
808 			buf[nbuf++] = c;
809 		}
810 	}
811 
812 end:
813 	free(buf);
814 
815 	return ret;
816 }
817 
818 static int
819 read4(dearmour_t *dearmour, __ops_error_t **errors,
820       __ops_reader_t *readinfo, __ops_cbdata_t *cbinfo,
821       int *pc, unsigned *pn, uint32_t *pl)
822 {
823 	int             n, c;
824 	uint32_t   l = 0;
825 
826 	for (n = 0; n < 4; ++n) {
827 		c = read_char(dearmour, errors, readinfo, cbinfo, 1);
828 		if (c < 0) {
829 			dearmour->eof64 = 1;
830 			return -1;
831 		}
832 		if (c == '-' || c == '=') {
833 			break;
834 		}
835 		l <<= 6;
836 		if (c >= 'A' && c <= 'Z') {
837 			l += (uint32_t)(c - 'A');
838 		} else if (c >= 'a' && c <= 'z') {
839 			l += (uint32_t)(c - 'a') + 26;
840 		} else if (c >= '0' && c <= '9') {
841 			l += (uint32_t)(c - '0') + 52;
842 		} else if (c == '+') {
843 			l += 62;
844 		} else if (c == '/') {
845 			l += 63;
846 		} else {
847 			--n;
848 			l >>= 6;
849 		}
850 	}
851 
852 	*pc = c;
853 	*pn = n;
854 	*pl = l;
855 
856 	return 4;
857 }
858 
859 unsigned
860 __ops_crc24(unsigned checksum, uint8_t c)
861 {
862 	unsigned        i;
863 
864 	checksum ^= c << 16;
865 	for (i = 0; i < 8; i++) {
866 		checksum <<= 1;
867 		if (checksum & 0x1000000)
868 			checksum ^= CRC24_POLY;
869 	}
870 	return checksum & 0xffffffL;
871 }
872 
873 static int
874 decode64(dearmour_t *dearmour, __ops_error_t **errors,
875 	 __ops_reader_t *readinfo, __ops_cbdata_t *cbinfo)
876 {
877 	unsigned        n;
878 	int             n2;
879 	uint32_t   l;
880 	int             c;
881 	int             ret;
882 
883 	if (dearmour->buffered) {
884 		(void) fprintf(stderr, "decode64: bad dearmour->buffered\n");
885 		return 0;
886 	}
887 
888 	ret = read4(dearmour, errors, readinfo, cbinfo, &c, &n, &l);
889 	if (ret < 0) {
890 		OPS_ERROR(errors, OPS_E_R_BAD_FORMAT, "Badly formed base64");
891 		return 0;
892 	}
893 	if (n == 3) {
894 		if (c != '=') {
895 			OPS_ERROR(errors, OPS_E_R_BAD_FORMAT,
896 					"Badly terminated base64 (2)");
897 			return 0;
898 		}
899 		dearmour->buffered = 2;
900 		dearmour->eof64 = 1;
901 		l >>= 2;
902 	} else if (n == 2) {
903 		if (c != '=') {
904 			OPS_ERROR(errors, OPS_E_R_BAD_FORMAT,
905 					"Badly terminated base64 (3)");
906 			return 0;
907 		}
908 		dearmour->buffered = 1;
909 		dearmour->eof64 = 1;
910 		l >>= 4;
911 		c = read_char(dearmour, errors, readinfo, cbinfo, 0);
912 		if (c != '=') {
913 			OPS_ERROR(errors, OPS_E_R_BAD_FORMAT,
914 					"Badly terminated base64");
915 			return 0;
916 		}
917 	} else if (n == 0) {
918 		if (!dearmour->prev_nl || c != '=') {
919 			OPS_ERROR(errors, OPS_E_R_BAD_FORMAT,
920 					"Badly terminated base64 (4)");
921 			return 0;
922 		}
923 		dearmour->buffered = 0;
924 	} else {
925 		if (n != 4) {
926 			(void) fprintf(stderr,
927 				"decode64: bad n (!= 4)\n");
928 			return 0;
929 		}
930 		dearmour->buffered = 3;
931 		if (c == '-' || c == '=') {
932 			(void) fprintf(stderr, "decode64: bad c\n");
933 			return 0;
934 		}
935 	}
936 
937 	if (dearmour->buffered < 3 && dearmour->buffered > 0) {
938 		/* then we saw padding */
939 		if (c != '=') {
940 			(void) fprintf(stderr, "decode64: bad c (=)\n");
941 			return 0;
942 		}
943 		c = read_and_eat_whitespace(dearmour, errors, readinfo, cbinfo,
944 				1);
945 		if (c != '\n') {
946 			OPS_ERROR(errors, OPS_E_R_BAD_FORMAT,
947 				"No newline at base64 end");
948 			return 0;
949 		}
950 		c = read_char(dearmour, errors, readinfo, cbinfo, 0);
951 		if (c != '=') {
952 			OPS_ERROR(errors, OPS_E_R_BAD_FORMAT,
953 				"No checksum at base64 end");
954 			return 0;
955 		}
956 	}
957 	if (c == '=') {
958 		/* now we are at the checksum */
959 		ret = read4(dearmour, errors, readinfo, cbinfo, &c, &n,
960 				&dearmour->read_checksum);
961 		if (ret < 0 || n != 4) {
962 			OPS_ERROR(errors, OPS_E_R_BAD_FORMAT,
963 					"Error in checksum");
964 			return 0;
965 		}
966 		c = read_char(dearmour, errors, readinfo, cbinfo, 1);
967 		if (dearmour->allow_trailing_whitespace)
968 			c = eat_whitespace(c, dearmour, errors, readinfo, cbinfo,
969 					1);
970 		if (c != '\n') {
971 			OPS_ERROR(errors, OPS_E_R_BAD_FORMAT,
972 					"Badly terminated checksum");
973 			return 0;
974 		}
975 		c = read_char(dearmour, errors, readinfo, cbinfo, 0);
976 		if (c != '-') {
977 			OPS_ERROR(errors, OPS_E_R_BAD_FORMAT,
978 					"Bad base64 trailer (2)");
979 			return 0;
980 		}
981 	}
982 	if (c == '-') {
983 		for (n = 0; n < 4; ++n)
984 			if (read_char(dearmour, errors, readinfo, cbinfo,
985 						0) != '-') {
986 				OPS_ERROR(errors, OPS_E_R_BAD_FORMAT,
987 						"Bad base64 trailer");
988 				return 0;
989 			}
990 		dearmour->eof64 = 1;
991 	} else {
992 		if (!dearmour->buffered) {
993 			(void) fprintf(stderr, "decode64: not buffered\n");
994 			return 0;
995 		}
996 	}
997 
998 	for (n = 0; n < dearmour->buffered; ++n) {
999 		dearmour->buffer[n] = (uint8_t)l;
1000 		l >>= 8;
1001 	}
1002 
1003 	for (n2 = dearmour->buffered - 1; n2 >= 0; --n2)
1004 		dearmour->checksum = __ops_crc24((unsigned)dearmour->checksum,
1005 					dearmour->buffer[n2]);
1006 
1007 	if (dearmour->eof64 && dearmour->read_checksum != dearmour->checksum) {
1008 		OPS_ERROR(errors, OPS_E_R_BAD_FORMAT, "Checksum mismatch");
1009 		return 0;
1010 	}
1011 	return 1;
1012 }
1013 
1014 static void
1015 base64(dearmour_t *dearmour)
1016 {
1017 	dearmour->state = BASE64;
1018 	dearmour->checksum = CRC24_INIT;
1019 	dearmour->eof64 = 0;
1020 	dearmour->buffered = 0;
1021 }
1022 
1023 /* This reader is rather strange in that it can generate callbacks for */
1024 /* content - this is because plaintext is not encapsulated in PGP */
1025 /* packets... it also calls back for the text between the blocks. */
1026 
1027 static int
1028 armoured_data_reader(void *dest_, size_t length, __ops_error_t **errors,
1029 		     __ops_reader_t *readinfo,
1030 		     __ops_cbdata_t *cbinfo)
1031 {
1032 	__ops_packet_t	 content;
1033 	dearmour_t	*dearmour;
1034 	unsigned	 first;
1035 	uint8_t		*dest = dest_;
1036 	char		 buf[1024];
1037 	int		 saved;
1038 	int              ret;
1039 
1040 	dearmour = __ops_reader_get_arg(readinfo);
1041 	saved = length;
1042 	if (dearmour->eof64 && !dearmour->buffered) {
1043 		if (dearmour->state != OUTSIDE_BLOCK &&
1044 		    dearmour->state != AT_TRAILER_NAME) {
1045 			(void) fprintf(stderr,
1046 				"armoured_data_reader: bad dearmour state\n");
1047 			return 0;
1048 		}
1049 	}
1050 
1051 	while (length > 0) {
1052 		unsigned        count;
1053 		unsigned        n;
1054 		int             c;
1055 
1056 		flush(dearmour, cbinfo);
1057 		switch (dearmour->state) {
1058 		case OUTSIDE_BLOCK:
1059 			/*
1060 			 * This code returns EOF rather than EARLY_EOF
1061 			 * because if we don't see a header line at all, then
1062 			 * it is just an EOF (and not a BLOCK_END)
1063 			 */
1064 			while (!dearmour->seen_nl) {
1065 				if ((c = unarmoured_read_char(dearmour, errors,
1066 						readinfo, cbinfo, 1)) < 0) {
1067 					return 0;
1068 				}
1069 			}
1070 
1071 			/*
1072 			 * flush at this point so we definitely have room for
1073 			 * the header, and so we can easily erase it from the
1074 			 * buffer
1075 			 */
1076 			flush(dearmour, cbinfo);
1077 			/* Find and consume the 5 leading '-' */
1078 			for (count = 0; count < 5; ++count) {
1079 				if ((c = unarmoured_read_char(dearmour, errors,
1080 						readinfo, cbinfo, 0)) < 0) {
1081 					return 0;
1082 				}
1083 				if (c != '-') {
1084 					goto reloop;
1085 				}
1086 			}
1087 
1088 			/* Now find the block type */
1089 			for (n = 0; n < sizeof(buf) - 1;) {
1090 				if ((c = unarmoured_read_char(dearmour, errors,
1091 						readinfo, cbinfo, 0)) < 0) {
1092 					return 0;
1093 				}
1094 				if (c == '-') {
1095 					goto got_minus;
1096 				}
1097 				buf[n++] = c;
1098 			}
1099 			/* then I guess this wasn't a proper header */
1100 			break;
1101 
1102 got_minus:
1103 			buf[n] = '\0';
1104 
1105 			/* Consume trailing '-' */
1106 			for (count = 1; count < 5; ++count) {
1107 				if ((c = unarmoured_read_char(dearmour, errors,
1108 						readinfo, cbinfo, 0)) < 0) {
1109 					return 0;
1110 				}
1111 				if (c != '-') {
1112 					/* wasn't a header after all */
1113 					goto reloop;
1114 				}
1115 			}
1116 
1117 			/* Consume final NL */
1118 			if ((c = unarmoured_read_char(dearmour, errors, readinfo,
1119 						cbinfo, 1)) < 0) {
1120 				return 0;
1121 			}
1122 			if (dearmour->allow_trailing_whitespace) {
1123 				if ((c = eat_whitespace(c, dearmour, errors,
1124 						readinfo, cbinfo, 1)) < 0) {
1125 					return 0;
1126 				}
1127 			}
1128 			if (c != '\n') {
1129 				/* wasn't a header line after all */
1130 				break;
1131 			}
1132 
1133 			/*
1134 			 * Now we've seen the header, scrub it from the
1135 			 * buffer
1136 			 */
1137 			dearmour->unarmoredc = 0;
1138 
1139 			/*
1140 			 * But now we've seen a header line, then errors are
1141 			 * EARLY_EOF
1142 			 */
1143 			if ((ret = parse_headers(dearmour, errors, readinfo,
1144 					cbinfo)) <= 0) {
1145 				return -1;
1146 			}
1147 
1148 			if (!set_lastseen_headerline(dearmour, buf, errors)) {
1149 				return -1;
1150 			}
1151 
1152 			if (strcmp(buf, "BEGIN PGP SIGNED MESSAGE") == 0) {
1153 				__ops_dup_headers(
1154 					&content.u.cleartext_head.headers,
1155 					&dearmour->headers);
1156 				CALLBACK(OPS_PTAG_CT_SIGNED_CLEARTEXT_HEADER,
1157 					cbinfo,
1158 					&content);
1159 				ret = process_dash_escaped(dearmour, errors,
1160 						readinfo, cbinfo);
1161 				if (ret <= 0) {
1162 					return ret;
1163 				}
1164 			} else {
1165 				content.u.armour_header.type = buf;
1166 				content.u.armour_header.headers =
1167 						dearmour->headers;
1168 				(void) memset(&dearmour->headers, 0x0,
1169 						sizeof(dearmour->headers));
1170 				CALLBACK(OPS_PTAG_CT_ARMOUR_HEADER, cbinfo,
1171 						&content);
1172 				base64(dearmour);
1173 			}
1174 			break;
1175 
1176 		case BASE64:
1177 			first = 1;
1178 			while (length > 0) {
1179 				if (!dearmour->buffered) {
1180 					if (!dearmour->eof64) {
1181 						ret = decode64(dearmour,
1182 							errors, readinfo, cbinfo);
1183 						if (ret <= 0) {
1184 							return ret;
1185 						}
1186 					}
1187 					if (!dearmour->buffered) {
1188 						if (!dearmour->eof64) {
1189 							(void) fprintf(stderr,
1190 "armoured_data_reader: bad dearmour eof64\n");
1191 							return 0;
1192 						}
1193 						if (first) {
1194 							dearmour->state =
1195 								AT_TRAILER_NAME;
1196 							goto reloop;
1197 						}
1198 						return -1;
1199 					}
1200 				}
1201 				if (!dearmour->buffered) {
1202 					(void) fprintf(stderr,
1203 			"armoured_data_reader: bad dearmour buffered\n");
1204 					return 0;
1205 				}
1206 				*dest = dearmour->buffer[--dearmour->buffered];
1207 				++dest;
1208 				--length;
1209 				first = 0;
1210 			}
1211 			if (dearmour->eof64 && !dearmour->buffered) {
1212 				dearmour->state = AT_TRAILER_NAME;
1213 			}
1214 			break;
1215 
1216 		case AT_TRAILER_NAME:
1217 			for (n = 0; n < sizeof(buf) - 1;) {
1218 				if ((c = read_char(dearmour, errors, readinfo,
1219 						cbinfo, 0)) < 0) {
1220 					return -1;
1221 				}
1222 				if (c == '-') {
1223 					goto got_minus2;
1224 				}
1225 				buf[n++] = c;
1226 			}
1227 			/* then I guess this wasn't a proper trailer */
1228 			OPS_ERROR(errors, OPS_E_R_BAD_FORMAT,
1229 					"Bad ASCII armour trailer");
1230 			break;
1231 
1232 got_minus2:
1233 			buf[n] = '\0';
1234 
1235 			if (!set_lastseen_headerline(dearmour, buf, errors)) {
1236 				return -1;
1237 			}
1238 
1239 			/* Consume trailing '-' */
1240 			for (count = 1; count < 5; ++count) {
1241 				if ((c = read_char(dearmour, errors, readinfo,
1242 						cbinfo, 0)) < 0) {
1243 					return -1;
1244 				}
1245 				if (c != '-') {
1246 					/* wasn't a trailer after all */
1247 					OPS_ERROR(errors, OPS_E_R_BAD_FORMAT,
1248 						"Bad ASCII armour trailer (2)");
1249 				}
1250 			}
1251 
1252 			/* Consume final NL */
1253 			if ((c = read_char(dearmour, errors, readinfo, cbinfo,
1254 						1)) < 0) {
1255 				return -1;
1256 			}
1257 			if (dearmour->allow_trailing_whitespace) {
1258 				if ((c = eat_whitespace(c, dearmour, errors,
1259 						readinfo, cbinfo, 1)) < 0) {
1260 					return 0;
1261 				}
1262 			}
1263 			if (c != '\n') {
1264 				/* wasn't a trailer line after all */
1265 				OPS_ERROR(errors, OPS_E_R_BAD_FORMAT,
1266 					"Bad ASCII armour trailer (3)");
1267 			}
1268 
1269 			if (strncmp(buf, "BEGIN ", 6) == 0) {
1270 				if (!set_lastseen_headerline(dearmour, buf,
1271 						errors)) {
1272 					return -1;
1273 				}
1274 				if ((ret = parse_headers(dearmour, errors,
1275 						readinfo, cbinfo)) <= 0) {
1276 					return ret;
1277 				}
1278 				content.u.armour_header.type = buf;
1279 				content.u.armour_header.headers =
1280 						dearmour->headers;
1281 				(void) memset(&dearmour->headers, 0x0,
1282 						sizeof(dearmour->headers));
1283 				CALLBACK(OPS_PTAG_CT_ARMOUR_HEADER, cbinfo,
1284 						&content);
1285 				base64(dearmour);
1286 			} else {
1287 				content.u.armour_trailer.type = buf;
1288 				CALLBACK(OPS_PTAG_CT_ARMOUR_TRAILER, cbinfo,
1289 						&content);
1290 				dearmour->state = OUTSIDE_BLOCK;
1291 			}
1292 			break;
1293 		}
1294 reloop:
1295 		continue;
1296 	}
1297 
1298 	return saved;
1299 }
1300 
1301 static void
1302 armoured_data_destroyer(__ops_reader_t *readinfo)
1303 {
1304 	free(__ops_reader_get_arg(readinfo));
1305 }
1306 
1307 /**
1308  * \ingroup Core_Readers_Armour
1309  * \brief Pushes dearmouring reader onto stack
1310  * \param parse_info Usual structure containing information about to how to do the parse
1311  * \sa __ops_reader_pop_dearmour()
1312  */
1313 void
1314 __ops_reader_push_dearmour(__ops_stream_t *parse_info)
1315 /*
1316  * This function originally had these params to cater for packets which
1317  * didn't strictly match the RFC. The initial 0.5 release is only going to
1318  * support strict checking. If it becomes desirable to support loose checking
1319  * of armoured packets and these params are reinstated, parse_headers() must
1320  * be fixed so that these flags work correctly.
1321  *
1322  * // Allow headers in armoured data that are not separated from the data by a
1323  * blank line unsigned without_gap,
1324  *
1325  * // Allow no blank line at the start of armoured data unsigned no_gap,
1326  *
1327  * //Allow armoured data to have trailing whitespace where we strictly would not
1328  * expect it			      unsigned trailing_whitespace
1329  */
1330 {
1331 	dearmour_t *dearmour;
1332 
1333 	if ((dearmour = calloc(1, sizeof(*dearmour))) == NULL) {
1334 		(void) fprintf(stderr, "__ops_reader_push_dearmour: bad alloc\n");
1335 	} else {
1336 		dearmour->seen_nl = 1;
1337 		/*
1338 		    dearmour->allow_headers_without_gap=without_gap;
1339 		    dearmour->allow_no_gap=no_gap;
1340 		    dearmour->allow_trailing_whitespace=trailing_whitespace;
1341 		*/
1342 		dearmour->expect_sig = 0;
1343 		dearmour->got_sig = 0;
1344 
1345 		__ops_reader_push(parse_info, armoured_data_reader,
1346 			armoured_data_destroyer, dearmour);
1347 	}
1348 }
1349 
1350 /**
1351  * \ingroup Core_Readers_Armour
1352  * \brief Pops dearmour reader from stock
1353  * \param stream
1354  * \sa __ops_reader_push_dearmour()
1355  */
1356 void
1357 __ops_reader_pop_dearmour(__ops_stream_t *stream)
1358 {
1359 	dearmour_t *dearmour;
1360 
1361 	dearmour = __ops_reader_get_arg(__ops_readinfo(stream));
1362 	free(dearmour);
1363 	__ops_reader_pop(stream);
1364 }
1365 
1366 /**************************************************************************/
1367 
1368 /* this is actually used for *decrypting* */
1369 typedef struct {
1370 	uint8_t		 decrypted[1024 * 15];
1371 	size_t		 c;
1372 	size_t		 off;
1373 	__ops_crypt_t	*decrypt;
1374 	__ops_region_t	*region;
1375 	unsigned	 prevplain:1;
1376 } encrypted_t;
1377 
1378 static int
1379 encrypted_data_reader(void *dest,
1380 			size_t length,
1381 			__ops_error_t **errors,
1382 			__ops_reader_t *readinfo,
1383 			__ops_cbdata_t *cbinfo)
1384 {
1385 	encrypted_t	*encrypted;
1386 	char		*cdest;
1387 	int		 saved;
1388 
1389 	encrypted = __ops_reader_get_arg(readinfo);
1390 	saved = length;
1391 	/*
1392 	 * V3 MPIs have the count plain and the cipher is reset after each
1393 	 * count
1394 	 */
1395 	if (encrypted->prevplain && !readinfo->parent->reading_mpi_len) {
1396 		if (!readinfo->parent->reading_v3_secret) {
1397 			(void) fprintf(stderr,
1398 				"encrypted_data_reader: bad v3 secret\n");
1399 			return -1;
1400 		}
1401 		encrypted->decrypt->decrypt_resync(encrypted->decrypt);
1402 		encrypted->prevplain = 0;
1403 	} else if (readinfo->parent->reading_v3_secret &&
1404 		   readinfo->parent->reading_mpi_len) {
1405 		encrypted->prevplain = 1;
1406 	}
1407 	while (length > 0) {
1408 		if (encrypted->c) {
1409 			unsigned        n;
1410 
1411 			/*
1412 			 * if we are reading v3 we should never read
1413 			 * more than we're asked for */
1414 			if (length < encrypted->c &&
1415 			     (readinfo->parent->reading_v3_secret ||
1416 			      readinfo->parent->exact_read)) {
1417 				(void) fprintf(stderr,
1418 					"encrypted_data_reader: bad v3 read\n");
1419 				return 0;
1420 			}
1421 			n = MIN(length, encrypted->c);
1422 			(void) memcpy(dest,
1423 				encrypted->decrypted + encrypted->off, n);
1424 			encrypted->c -= n;
1425 			encrypted->off += n;
1426 			length -= n;
1427 			cdest = dest;
1428 			cdest += n;
1429 			dest = cdest;
1430 		} else {
1431 			unsigned	n = encrypted->region->length;
1432 			uint8_t		buffer[1024];
1433 
1434 			if (!n) {
1435 				return -1;
1436 			}
1437 			if (!encrypted->region->indeterminate) {
1438 				n -= encrypted->region->readc;
1439 				if (n == 0) {
1440 					return saved - length;
1441 				}
1442 				if (n > sizeof(buffer)) {
1443 					n = sizeof(buffer);
1444 				}
1445 			} else {
1446 				n = sizeof(buffer);
1447 			}
1448 
1449 			/*
1450 			 * we can only read as much as we're asked for
1451 			 * in v3 keys because they're partially
1452 			 * unencrypted!  */
1453 			if ((readinfo->parent->reading_v3_secret ||
1454 			     readinfo->parent->exact_read) && n > length) {
1455 				n = length;
1456 			}
1457 
1458 			if (!__ops_stacked_limited_read(buffer, n,
1459 				encrypted->region, errors, readinfo, cbinfo)) {
1460 				return -1;
1461 			}
1462 			if (!readinfo->parent->reading_v3_secret ||
1463 			    !readinfo->parent->reading_mpi_len) {
1464 				encrypted->c =
1465 					__ops_decrypt_se_ip(encrypted->decrypt,
1466 					encrypted->decrypted, buffer, n);
1467 
1468 				if (__ops_get_debug_level(__FILE__)) {
1469 					int             i;
1470 
1471 					(void) fprintf(stderr,
1472 						"READING:\nencrypted: ");
1473 					for (i = 0; i < 16; i++) {
1474 						(void) fprintf(stderr,
1475 							"%2x ", buffer[i]);
1476 					}
1477 					(void) fprintf(stderr, "\ndecrypted: ");
1478 					for (i = 0; i < 16; i++) {
1479 						(void) fprintf(stderr, "%2x ",
1480 						encrypted->decrypted[i]);
1481 					}
1482 					(void) fprintf(stderr, "\n");
1483 				}
1484 			} else {
1485 				(void) memcpy(
1486 	&encrypted->decrypted[encrypted->off], buffer, n);
1487 				encrypted->c = n;
1488 			}
1489 
1490 			if (encrypted->c == 0) {
1491 				(void) fprintf(stderr,
1492 				"encrypted_data_reader: 0 decrypted count\n");
1493 				return 0;
1494 			}
1495 
1496 			encrypted->off = 0;
1497 		}
1498 	}
1499 
1500 	return saved;
1501 }
1502 
1503 static void
1504 encrypted_data_destroyer(__ops_reader_t *readinfo)
1505 {
1506 	free(__ops_reader_get_arg(readinfo));
1507 }
1508 
1509 /**
1510  * \ingroup Core_Readers_SE
1511  * \brief Pushes decryption reader onto stack
1512  * \sa __ops_reader_pop_decrypt()
1513  */
1514 void
1515 __ops_reader_push_decrypt(__ops_stream_t *stream, __ops_crypt_t *decrypt,
1516 			__ops_region_t *region)
1517 {
1518 	encrypted_t	*encrypted;
1519 
1520 	if ((encrypted = calloc(1, sizeof(*encrypted))) == NULL) {
1521 		(void) fprintf(stderr, "__ops_reader_push_decrypted: bad alloc\n");
1522 	} else {
1523 		encrypted->decrypt = decrypt;
1524 		encrypted->region = region;
1525 		__ops_decrypt_init(encrypted->decrypt);
1526 		__ops_reader_push(stream, encrypted_data_reader,
1527 			encrypted_data_destroyer, encrypted);
1528 	}
1529 }
1530 
1531 /**
1532  * \ingroup Core_Readers_Encrypted
1533  * \brief Pops decryption reader from stack
1534  * \sa __ops_reader_push_decrypt()
1535  */
1536 void
1537 __ops_reader_pop_decrypt(__ops_stream_t *stream)
1538 {
1539 	encrypted_t	*encrypted;
1540 
1541 	encrypted = __ops_reader_get_arg(__ops_readinfo(stream));
1542 	encrypted->decrypt->decrypt_finish(encrypted->decrypt);
1543 	free(encrypted);
1544 	__ops_reader_pop(stream);
1545 }
1546 
1547 /**************************************************************************/
1548 
1549 typedef struct {
1550 	/* boolean: 0 once we've done the preamble/MDC checks */
1551 	/* and are reading from the plaintext */
1552 	int              passed_checks;
1553 	uint8_t		*plaintext;
1554 	size_t           plaintext_available;
1555 	size_t           plaintext_offset;
1556 	__ops_region_t	*region;
1557 	__ops_crypt_t	*decrypt;
1558 } decrypt_se_ip_t;
1559 
1560 /*
1561   Gets entire SE_IP data packet.
1562   Verifies leading preamble
1563   Verifies trailing MDC packet
1564   Then passes up plaintext as requested
1565 */
1566 static int
1567 se_ip_data_reader(void *dest_,
1568 			size_t len,
1569 			__ops_error_t **errors,
1570 			__ops_reader_t *readinfo,
1571 			__ops_cbdata_t *cbinfo)
1572 {
1573 	decrypt_se_ip_t	*se_ip;
1574 	__ops_region_t	 decrypted_region;
1575 	unsigned	 n = 0;
1576 
1577 	se_ip = __ops_reader_get_arg(readinfo);
1578 	if (!se_ip->passed_checks) {
1579 		uint8_t		*buf = NULL;
1580 		uint8_t		hashed[OPS_SHA1_HASH_SIZE];
1581 		uint8_t		*preamble;
1582 		uint8_t		*plaintext;
1583 		uint8_t		*mdc;
1584 		uint8_t		*mdc_hash;
1585 		__ops_hash_t	hash;
1586 		size_t		b;
1587 		size_t          sz_preamble;
1588 		size_t          sz_mdc_hash;
1589 		size_t          sz_mdc;
1590 		size_t          sz_plaintext;
1591 
1592 		__ops_hash_any(&hash, OPS_HASH_SHA1);
1593 		if (!hash.init(&hash)) {
1594 			(void) fprintf(stderr,
1595 				"se_ip_data_reader: can't init hash\n");
1596 			return -1;
1597 		}
1598 
1599 		__ops_init_subregion(&decrypted_region, NULL);
1600 		decrypted_region.length =
1601 			se_ip->region->length - se_ip->region->readc;
1602 		if ((buf = calloc(1, decrypted_region.length)) == NULL) {
1603 			(void) fprintf(stderr, "se_ip_data_reader: bad alloc\n");
1604 			return -1;
1605 		}
1606 
1607 		/* read entire SE IP packet */
1608 		if (!__ops_stacked_limited_read(buf, decrypted_region.length,
1609 				&decrypted_region, errors, readinfo, cbinfo)) {
1610 			free(buf);
1611 			return -1;
1612 		}
1613 		if (__ops_get_debug_level(__FILE__)) {
1614 			unsigned	i;
1615 
1616 			fprintf(stderr, "\n\nentire SE IP packet (len=%d):\n",
1617 					decrypted_region.length);
1618 			for (i = 0; i < decrypted_region.length; i++) {
1619 				fprintf(stderr, "0x%02x ", buf[i]);
1620 				if (!((i + 1) % 8))
1621 					fprintf(stderr, "\n");
1622 			}
1623 			fprintf(stderr, "\n\n");
1624 		}
1625 		/* verify leading preamble */
1626 
1627 		if (__ops_get_debug_level(__FILE__)) {
1628 			unsigned	i;
1629 
1630 			fprintf(stderr, "\npreamble: ");
1631 			for (i = 0; i < se_ip->decrypt->blocksize + 2; i++)
1632 				fprintf(stderr, " 0x%02x", buf[i]);
1633 			fprintf(stderr, "\n");
1634 		}
1635 		b = se_ip->decrypt->blocksize;
1636 		if (buf[b - 2] != buf[b] || buf[b - 1] != buf[b + 1]) {
1637 			fprintf(stderr,
1638 			"Bad symmetric decrypt (%02x%02x vs %02x%02x)\n",
1639 				buf[b - 2], buf[b - 1], buf[b], buf[b + 1]);
1640 			OPS_ERROR(errors, OPS_E_PROTO_BAD_SYMMETRIC_DECRYPT,
1641 			"Bad symmetric decrypt when parsing SE IP packet");
1642 			free(buf);
1643 			return -1;
1644 		}
1645 		/* Verify trailing MDC hash */
1646 
1647 		sz_preamble = se_ip->decrypt->blocksize + 2;
1648 		sz_mdc_hash = OPS_SHA1_HASH_SIZE;
1649 		sz_mdc = 1 + 1 + sz_mdc_hash;
1650 		sz_plaintext = (decrypted_region.length - sz_preamble) - sz_mdc;
1651 
1652 		preamble = buf;
1653 		plaintext = buf + sz_preamble;
1654 		mdc = plaintext + sz_plaintext;
1655 		mdc_hash = mdc + 2;
1656 
1657 		if (__ops_get_debug_level(__FILE__)) {
1658 			unsigned	i;
1659 
1660 			fprintf(stderr, "\nplaintext (len=%" PRIsize "u): ",
1661 				sz_plaintext);
1662 			for (i = 0; i < sz_plaintext; i++)
1663 				fprintf(stderr, " 0x%02x", plaintext[i]);
1664 			fprintf(stderr, "\n");
1665 
1666 			fprintf(stderr, "\nmdc (len=%" PRIsize "u): ", sz_mdc);
1667 			for (i = 0; i < sz_mdc; i++)
1668 				fprintf(stderr, " 0x%02x", mdc[i]);
1669 			fprintf(stderr, "\n");
1670 		}
1671 		__ops_calc_mdc_hash(preamble, sz_preamble, plaintext,
1672 				sz_plaintext, hashed);
1673 
1674 		if (memcmp(mdc_hash, hashed, OPS_SHA1_HASH_SIZE) != 0) {
1675 			OPS_ERROR(errors, OPS_E_V_BAD_HASH,
1676 					"Bad hash in MDC packet");
1677 			free(buf);
1678 			return 0;
1679 		}
1680 		/* all done with the checks */
1681 		/* now can start reading from the plaintext */
1682 		if (se_ip->plaintext) {
1683 			(void) fprintf(stderr,
1684 				"se_ip_data_reader: bad plaintext\n");
1685 			return 0;
1686 		}
1687 		if ((se_ip->plaintext = calloc(1, sz_plaintext)) == NULL) {
1688 			(void) fprintf(stderr,
1689 				"se_ip_data_reader: bad alloc\n");
1690 			return 0;
1691 		}
1692 		memcpy(se_ip->plaintext, plaintext, sz_plaintext);
1693 		se_ip->plaintext_available = sz_plaintext;
1694 
1695 		se_ip->passed_checks = 1;
1696 
1697 		free(buf);
1698 	}
1699 	n = len;
1700 	if (n > se_ip->plaintext_available) {
1701 		n = se_ip->plaintext_available;
1702 	}
1703 
1704 	memcpy(dest_, se_ip->plaintext + se_ip->plaintext_offset, n);
1705 	se_ip->plaintext_available -= n;
1706 	se_ip->plaintext_offset += n;
1707 	/* len -= n; - not used at all, for info only */
1708 
1709 	return n;
1710 }
1711 
1712 static void
1713 se_ip_data_destroyer(__ops_reader_t *readinfo)
1714 {
1715 	decrypt_se_ip_t	*se_ip;
1716 
1717 	se_ip = __ops_reader_get_arg(readinfo);
1718 	free(se_ip->plaintext);
1719 	free(se_ip);
1720 }
1721 
1722 /**
1723    \ingroup Internal_Readers_SEIP
1724 */
1725 void
1726 __ops_reader_push_se_ip_data(__ops_stream_t *stream, __ops_crypt_t *decrypt,
1727 			   __ops_region_t * region)
1728 {
1729 	decrypt_se_ip_t *se_ip;
1730 
1731 	if ((se_ip = calloc(1, sizeof(*se_ip))) == NULL) {
1732 		(void) fprintf(stderr, "__ops_reader_push_se_ip_data: bad alloc\n");
1733 	} else {
1734 		se_ip->region = region;
1735 		se_ip->decrypt = decrypt;
1736 		__ops_reader_push(stream, se_ip_data_reader, se_ip_data_destroyer,
1737 				se_ip);
1738 	}
1739 }
1740 
1741 /**
1742    \ingroup Internal_Readers_SEIP
1743  */
1744 void
1745 __ops_reader_pop_se_ip_data(__ops_stream_t *stream)
1746 {
1747 	/*
1748 	 * decrypt_se_ip_t
1749 	 * *se_ip=__ops_reader_get_arg(__ops_readinfo(stream));
1750 	 */
1751 	/* free(se_ip); */
1752 	__ops_reader_pop(stream);
1753 }
1754 
1755 /**************************************************************************/
1756 
1757 /** Arguments for reader_fd
1758  */
1759 typedef struct mmap_reader_t {
1760 	void		*mem;		/* memory mapped file */
1761 	uint64_t	 size;		/* size of file */
1762 	uint64_t	 offset;	/* current offset in file */
1763 	int		 fd;		/* file descriptor */
1764 } mmap_reader_t;
1765 
1766 
1767 /**
1768  * \ingroup Core_Readers
1769  *
1770  * __ops_reader_fd() attempts to read up to "plength" bytes from the file
1771  * descriptor in "parse_info" into the buffer starting at "dest" using the
1772  * rules contained in "flags"
1773  *
1774  * \param	dest	Pointer to previously allocated buffer
1775  * \param	plength Number of bytes to try to read
1776  * \param	flags	Rules about reading to use
1777  * \param	readinfo	Reader info
1778  * \param	cbinfo	Callback info
1779  *
1780  * \return	n	Number of bytes read
1781  *
1782  * OPS_R_EARLY_EOF and OPS_R_ERROR push errors on the stack
1783  */
1784 static int
1785 fd_reader(void *dest, size_t length, __ops_error_t **errors,
1786 	  __ops_reader_t *readinfo, __ops_cbdata_t *cbinfo)
1787 {
1788 	mmap_reader_t *reader = __ops_reader_get_arg(readinfo);
1789 	int             n = read(reader->fd, dest, length);
1790 
1791 	__OPS_USED(cbinfo);
1792 	if (n == 0)
1793 		return 0;
1794 	if (n < 0) {
1795 		OPS_SYSTEM_ERROR_1(errors, OPS_E_R_READ_FAILED, "read",
1796 				   "file descriptor %d", reader->fd);
1797 		return -1;
1798 	}
1799 	return n;
1800 }
1801 
1802 static void
1803 reader_fd_destroyer(__ops_reader_t *readinfo)
1804 {
1805 	free(__ops_reader_get_arg(readinfo));
1806 }
1807 
1808 /**
1809    \ingroup Core_Readers_First
1810    \brief Starts stack with file reader
1811 */
1812 
1813 void
1814 __ops_reader_set_fd(__ops_stream_t *stream, int fd)
1815 {
1816 	mmap_reader_t *reader;
1817 
1818 	if ((reader = calloc(1, sizeof(*reader))) == NULL) {
1819 		(void) fprintf(stderr, "__ops_reader_set_fd: bad alloc\n");
1820 	} else {
1821 		reader->fd = fd;
1822 		__ops_reader_set(stream, fd_reader, reader_fd_destroyer, reader);
1823 	}
1824 }
1825 
1826 /**************************************************************************/
1827 
1828 typedef struct {
1829 	const uint8_t *buffer;
1830 	size_t          length;
1831 	size_t          offset;
1832 } reader_mem_t;
1833 
1834 static int
1835 mem_reader(void *dest, size_t length, __ops_error_t **errors,
1836 	   __ops_reader_t *readinfo, __ops_cbdata_t *cbinfo)
1837 {
1838 	reader_mem_t *reader = __ops_reader_get_arg(readinfo);
1839 	unsigned        n;
1840 
1841 	__OPS_USED(cbinfo);
1842 	__OPS_USED(errors);
1843 
1844 	if (reader->offset + length > reader->length)
1845 		n = reader->length - reader->offset;
1846 	else
1847 		n = length;
1848 
1849 	if (n == 0)
1850 		return 0;
1851 
1852 	memcpy(dest, reader->buffer + reader->offset, n);
1853 	reader->offset += n;
1854 
1855 	return n;
1856 }
1857 
1858 static void
1859 mem_destroyer(__ops_reader_t *readinfo)
1860 {
1861 	free(__ops_reader_get_arg(readinfo));
1862 }
1863 
1864 /**
1865    \ingroup Core_Readers_First
1866    \brief Starts stack with memory reader
1867 */
1868 
1869 void
1870 __ops_reader_set_memory(__ops_stream_t *stream, const void *buffer,
1871 		      size_t length)
1872 {
1873 	reader_mem_t *mem;
1874 
1875 	if ((mem = calloc(1, sizeof(*mem))) == NULL) {
1876 		(void) fprintf(stderr, "__ops_reader_set_memory: bad alloc\n");
1877 	} else {
1878 		mem->buffer = buffer;
1879 		mem->length = length;
1880 		mem->offset = 0;
1881 		__ops_reader_set(stream, mem_reader, mem_destroyer, mem);
1882 	}
1883 }
1884 
1885 /**************************************************************************/
1886 
1887 /**
1888  \ingroup Core_Writers
1889  \brief Create and initialise output and mem; Set for writing to mem
1890  \param output Address where new output pointer will be set
1891  \param mem Address when new mem pointer will be set
1892  \param bufsz Initial buffer size (will automatically be increased when necessary)
1893  \note It is the caller's responsiblity to free output and mem.
1894  \sa __ops_teardown_memory_write()
1895 */
1896 void
1897 __ops_setup_memory_write(__ops_output_t **output, __ops_memory_t **mem, size_t bufsz)
1898 {
1899 	/*
1900          * initialise needed structures for writing to memory
1901          */
1902 
1903 	*output = __ops_output_new();
1904 	*mem = __ops_memory_new();
1905 
1906 	__ops_memory_init(*mem, bufsz);
1907 
1908 	__ops_writer_set_memory(*output, *mem);
1909 }
1910 
1911 /**
1912    \ingroup Core_Writers
1913    \brief Closes writer and frees output and mem
1914    \param output
1915    \param mem
1916    \sa __ops_setup_memory_write()
1917 */
1918 void
1919 __ops_teardown_memory_write(__ops_output_t *output, __ops_memory_t *mem)
1920 {
1921 	__ops_writer_close(output);/* new */
1922 	__ops_output_delete(output);
1923 	__ops_memory_free(mem);
1924 }
1925 
1926 /**
1927    \ingroup Core_Readers
1928    \brief Create parse_info and sets to read from memory
1929    \param stream Address where new parse_info will be set
1930    \param mem Memory to read from
1931    \param arg Reader-specific arg
1932    \param callback Callback to use with reader
1933    \param accumulate Set if we need to accumulate as we read. (Usually 0 unless doing signature verification)
1934    \note It is the caller's responsiblity to free parse_info
1935    \sa __ops_teardown_memory_read()
1936 */
1937 void
1938 __ops_setup_memory_read(__ops_io_t *io,
1939 			__ops_stream_t **stream,
1940 			__ops_memory_t *mem,
1941 			void *vp,
1942 			__ops_cb_ret_t callback(const __ops_packet_t *,
1943 						__ops_cbdata_t *),
1944 			unsigned accumulate)
1945 {
1946 	*stream = __ops_new(sizeof(**stream));
1947 	(*stream)->io = (*stream)->cbinfo.io = io;
1948 	__ops_set_callback(*stream, callback, vp);
1949 	__ops_reader_set_memory(*stream,
1950 			      __ops_mem_data(mem),
1951 			      __ops_mem_len(mem));
1952 	if (accumulate) {
1953 		(*stream)->readinfo.accumulate = 1;
1954 	}
1955 }
1956 
1957 /**
1958    \ingroup Core_Readers
1959    \brief Frees stream and mem
1960    \param stream
1961    \param mem
1962    \sa __ops_setup_memory_read()
1963 */
1964 void
1965 __ops_teardown_memory_read(__ops_stream_t *stream, __ops_memory_t *mem)
1966 {
1967 	__ops_stream_delete(stream);
1968 	__ops_memory_free(mem);
1969 }
1970 
1971 /**
1972  \ingroup Core_Writers
1973  \brief Create and initialise output and mem; Set for writing to file
1974  \param output Address where new output pointer will be set
1975  \param filename File to write to
1976  \param allow_overwrite Allows file to be overwritten, if set.
1977  \return Newly-opened file descriptor
1978  \note It is the caller's responsiblity to free output and to close fd.
1979  \sa __ops_teardown_file_write()
1980 */
1981 int
1982 __ops_setup_file_write(__ops_output_t **output, const char *filename,
1983 			unsigned allow_overwrite)
1984 {
1985 	int             fd = 0;
1986 	int             flags = 0;
1987 
1988 	/*
1989          * initialise needed structures for writing to file
1990          */
1991 	if (filename == NULL) {
1992 		/* write to stdout */
1993 		fd = STDOUT_FILENO;
1994 	} else {
1995 		flags = O_WRONLY | O_CREAT;
1996 		if (allow_overwrite)
1997 			flags |= O_TRUNC;
1998 		else
1999 			flags |= O_EXCL;
2000 #ifdef O_BINARY
2001 		flags |= O_BINARY;
2002 #endif
2003 		fd = open(filename, flags, 0600);
2004 		if (fd < 0) {
2005 			perror(filename);
2006 			return fd;
2007 		}
2008 	}
2009 	*output = __ops_output_new();
2010 	__ops_writer_set_fd(*output, fd);
2011 	return fd;
2012 }
2013 
2014 /**
2015    \ingroup Core_Writers
2016    \brief Closes writer, frees info, closes fd
2017    \param output
2018    \param fd
2019 */
2020 void
2021 __ops_teardown_file_write(__ops_output_t *output, int fd)
2022 {
2023 	__ops_writer_close(output);
2024 	close(fd);
2025 	__ops_output_delete(output);
2026 }
2027 
2028 /**
2029    \ingroup Core_Writers
2030    \brief As __ops_setup_file_write, but appends to file
2031 */
2032 int
2033 __ops_setup_file_append(__ops_output_t **output, const char *filename)
2034 {
2035 	int             fd;
2036 	/*
2037          * initialise needed structures for writing to file
2038          */
2039 
2040 #ifdef O_BINARY
2041 	fd = open(filename, O_WRONLY | O_APPEND | O_BINARY, 0600);
2042 #else
2043 	fd = open(filename, O_WRONLY | O_APPEND, 0600);
2044 #endif
2045 	if (fd < 0) {
2046 		perror(filename);
2047 		return fd;
2048 	}
2049 	*output = __ops_output_new();
2050 
2051 	__ops_writer_set_fd(*output, fd);
2052 
2053 	return fd;
2054 }
2055 
2056 /**
2057    \ingroup Core_Writers
2058    \brief As __ops_teardown_file_write()
2059 */
2060 void
2061 __ops_teardown_file_append(__ops_output_t *output, int fd)
2062 {
2063 	__ops_teardown_file_write(output, fd);
2064 }
2065 
2066 /**
2067    \ingroup Core_Readers
2068    \brief Creates parse_info, opens file, and sets to read from file
2069    \param stream Address where new parse_info will be set
2070    \param filename Name of file to read
2071    \param vp Reader-specific arg
2072    \param callback Callback to use when reading
2073    \param accumulate Set if we need to accumulate as we read. (Usually 0 unless doing signature verification)
2074    \note It is the caller's responsiblity to free parse_info and to close fd
2075    \sa __ops_teardown_file_read()
2076 */
2077 int
2078 __ops_setup_file_read(__ops_io_t *io,
2079 			__ops_stream_t **stream,
2080 			const char *filename,
2081 			void *vp,
2082 			__ops_cb_ret_t callback(const __ops_packet_t *,
2083 						__ops_cbdata_t *),
2084 			unsigned accumulate)
2085 {
2086 	int	fd;
2087 
2088 #ifdef O_BINARY
2089 	fd = open(filename, O_RDONLY | O_BINARY);
2090 #else
2091 	fd = open(filename, O_RDONLY);
2092 #endif
2093 	if (fd < 0) {
2094 		(void) fprintf(io->errs, "can't open \"%s\"\n", filename);
2095 		return fd;
2096 	}
2097 	*stream = __ops_new(sizeof(**stream));
2098 	(*stream)->io = (*stream)->cbinfo.io = io;
2099 	__ops_set_callback(*stream, callback, vp);
2100 #ifdef USE_MMAP_FOR_FILES
2101 	__ops_reader_set_mmap(*stream, fd);
2102 #else
2103 	__ops_reader_set_fd(*stream, fd);
2104 #endif
2105 	if (accumulate) {
2106 		(*stream)->readinfo.accumulate = 1;
2107 	}
2108 	return fd;
2109 }
2110 
2111 /**
2112    \ingroup Core_Readers
2113    \brief Frees stream and closes fd
2114    \param stream
2115    \param fd
2116    \sa __ops_setup_file_read()
2117 */
2118 void
2119 __ops_teardown_file_read(__ops_stream_t *stream, int fd)
2120 {
2121 	close(fd);
2122 	__ops_stream_delete(stream);
2123 }
2124 
2125 __ops_cb_ret_t
2126 litdata_cb(const __ops_packet_t *pkt, __ops_cbdata_t *cbinfo)
2127 {
2128 	const __ops_contents_t	*content = &pkt->u;
2129 
2130 	if (__ops_get_debug_level(__FILE__)) {
2131 		printf("litdata_cb: ");
2132 		__ops_print_packet(&cbinfo->printstate, pkt);
2133 	}
2134 	/* Read data from packet into static buffer */
2135 	switch (pkt->tag) {
2136 	case OPS_PTAG_CT_LITDATA_BODY:
2137 		/* if writer enabled, use it */
2138 		if (cbinfo->output) {
2139 			if (__ops_get_debug_level(__FILE__)) {
2140 				printf("litdata_cb: length is %u\n",
2141 					content->litdata_body.length);
2142 			}
2143 			__ops_write(cbinfo->output,
2144 					content->litdata_body.data,
2145 					content->litdata_body.length);
2146 		}
2147 		break;
2148 
2149 	case OPS_PTAG_CT_LITDATA_HEADER:
2150 		/* ignore */
2151 		break;
2152 
2153 	default:
2154 		break;
2155 	}
2156 
2157 	return OPS_RELEASE_MEMORY;
2158 }
2159 
2160 __ops_cb_ret_t
2161 pk_sesskey_cb(const __ops_packet_t *pkt, __ops_cbdata_t *cbinfo)
2162 {
2163 	const __ops_contents_t	*content = &pkt->u;
2164 	unsigned		 from;
2165 	__ops_io_t		*io;
2166 
2167 	io = cbinfo->io;
2168 	if (__ops_get_debug_level(__FILE__)) {
2169 		__ops_print_packet(&cbinfo->printstate, pkt);
2170 	}
2171 	/* Read data from packet into static buffer */
2172 	switch (pkt->tag) {
2173 	case OPS_PTAG_CT_PK_SESSION_KEY:
2174 		if (__ops_get_debug_level(__FILE__)) {
2175 			printf("OPS_PTAG_CT_PK_SESSION_KEY\n");
2176 		}
2177 		if (!cbinfo->cryptinfo.secring) {
2178 			(void) fprintf(io->errs,
2179 				"pk_sesskey_cb: bad keyring\n");
2180 			return (__ops_cb_ret_t)0;
2181 		}
2182 		from = 0;
2183 		cbinfo->cryptinfo.keydata =
2184 			__ops_getkeybyid(io, cbinfo->cryptinfo.secring,
2185 				content->pk_sesskey.key_id, &from);
2186 		if (!cbinfo->cryptinfo.keydata) {
2187 			break;
2188 		}
2189 		break;
2190 
2191 	default:
2192 		break;
2193 	}
2194 
2195 	return OPS_RELEASE_MEMORY;
2196 }
2197 
2198 /**
2199  \ingroup Core_Callbacks
2200 
2201 \brief Callback to get secret key, decrypting if necessary.
2202 
2203 @verbatim
2204  This callback does the following:
2205  * finds the session key in the keyring
2206  * gets a passphrase if required
2207  * decrypts the secret key, if necessary
2208  * sets the seckey in the content struct
2209 @endverbatim
2210 */
2211 
2212 __ops_cb_ret_t
2213 get_seckey_cb(const __ops_packet_t *pkt, __ops_cbdata_t *cbinfo)
2214 {
2215 	const __ops_contents_t	*content = &pkt->u;
2216 	const __ops_seckey_t	*secret;
2217 	const __ops_key_t	*pubkey;
2218 	const __ops_key_t	*keypair;
2219 	unsigned		 from;
2220 	__ops_io_t		*io;
2221 
2222 	io = cbinfo->io;
2223 	if (__ops_get_debug_level(__FILE__)) {
2224 		__ops_print_packet(&cbinfo->printstate, pkt);
2225 	}
2226 	switch (pkt->tag) {
2227 	case OPS_GET_SECKEY:
2228 		/* print key from pubring */
2229 		from = 0;
2230 		pubkey = __ops_getkeybyid(io, cbinfo->cryptinfo.pubring,
2231 				content->get_seckey.pk_sesskey->key_id,
2232 				&from);
2233 		/* validate key from secring */
2234 		from = 0;
2235 		cbinfo->cryptinfo.keydata =
2236 			__ops_getkeybyid(io, cbinfo->cryptinfo.secring,
2237 				content->get_seckey.pk_sesskey->key_id,
2238 				&from);
2239 		if (!cbinfo->cryptinfo.keydata ||
2240 		    !__ops_is_key_secret(cbinfo->cryptinfo.keydata)) {
2241 			return (__ops_cb_ret_t)0;
2242 		}
2243 		keypair = cbinfo->cryptinfo.keydata;
2244 		do {
2245 			/* print out the user id */
2246 			__ops_print_keydata(io, pubkey, "pub", &pubkey->key.pubkey);
2247 			/* now decrypt key */
2248 			secret = __ops_decrypt_seckey(keypair, cbinfo->passfp);
2249 			if (secret == NULL) {
2250 				(void) fprintf(io->errs, "Bad passphrase\n");
2251 			}
2252 		} while (secret == NULL);
2253 		*content->get_seckey.seckey = secret;
2254 		break;
2255 
2256 	default:
2257 		break;
2258 	}
2259 
2260 	return OPS_RELEASE_MEMORY;
2261 }
2262 
2263 /**
2264  \ingroup HighLevel_Callbacks
2265  \brief Callback to use when you need to prompt user for passphrase
2266  \param contents
2267  \param cbinfo
2268 */
2269 __ops_cb_ret_t
2270 get_passphrase_cb(const __ops_packet_t *pkt, __ops_cbdata_t *cbinfo)
2271 {
2272 	const __ops_contents_t	*content = &pkt->u;
2273 	__ops_io_t		*io;
2274 
2275 	io = cbinfo->io;
2276 	if (__ops_get_debug_level(__FILE__)) {
2277 		__ops_print_packet(&cbinfo->printstate, pkt);
2278 	}
2279 	if (cbinfo->cryptinfo.keydata == NULL) {
2280 		(void) fprintf(io->errs, "get_passphrase_cb: NULL keydata\n");
2281 	} else {
2282 		__ops_print_keydata(io, cbinfo->cryptinfo.keydata, "pub",
2283 			&cbinfo->cryptinfo.keydata->key.pubkey);
2284 	}
2285 	switch (pkt->tag) {
2286 	case OPS_GET_PASSPHRASE:
2287 		*(content->skey_passphrase.passphrase) =
2288 				netpgp_strdup(getpass("netpgp passphrase: "));
2289 		return OPS_KEEP_MEMORY;
2290 	default:
2291 		break;
2292 	}
2293 	return OPS_RELEASE_MEMORY;
2294 }
2295 
2296 unsigned
2297 __ops_reader_set_accumulate(__ops_stream_t *stream, unsigned state)
2298 {
2299 	return stream->readinfo.accumulate = state;
2300 }
2301 
2302 /**************************************************************************/
2303 
2304 static int
2305 hash_reader(void *dest,
2306 		size_t length,
2307 		__ops_error_t **errors,
2308 		__ops_reader_t *readinfo,
2309 		__ops_cbdata_t *cbinfo)
2310 {
2311 	__ops_hash_t	*hash = __ops_reader_get_arg(readinfo);
2312 	int		 r;
2313 
2314 	r = __ops_stacked_read(dest, length, errors, readinfo, cbinfo);
2315 	if (r <= 0) {
2316 		return r;
2317 	}
2318 	hash->add(hash, dest, (unsigned)r);
2319 	return r;
2320 }
2321 
2322 /**
2323    \ingroup Internal_Readers_Hash
2324    \brief Push hashed data reader on stack
2325 */
2326 void
2327 __ops_reader_push_hash(__ops_stream_t *stream, __ops_hash_t *hash)
2328 {
2329 	if (!hash->init(hash)) {
2330 		(void) fprintf(stderr, "__ops_reader_push_hash: can't init hash\n");
2331 		/* just continue and die */
2332 		/* XXX - agc - no way to return failure */
2333 	}
2334 	__ops_reader_push(stream, hash_reader, NULL, hash);
2335 }
2336 
2337 /**
2338    \ingroup Internal_Readers_Hash
2339    \brief Pop hashed data reader from stack
2340 */
2341 void
2342 __ops_reader_pop_hash(__ops_stream_t *stream)
2343 {
2344 	__ops_reader_pop(stream);
2345 }
2346 
2347 /* read memory from the previously mmap-ed file */
2348 static int
2349 mmap_reader(void *dest, size_t length, __ops_error_t **errors,
2350 	  __ops_reader_t *readinfo, __ops_cbdata_t *cbinfo)
2351 {
2352 	mmap_reader_t	*mem = __ops_reader_get_arg(readinfo);
2353 	unsigned	 n;
2354 	char		*cmem = mem->mem;
2355 
2356 	__OPS_USED(errors);
2357 	__OPS_USED(cbinfo);
2358 	n = MIN(length, (unsigned)(mem->size - mem->offset));
2359 	if (n > 0) {
2360 		(void) memcpy(dest, &cmem[(int)mem->offset], (unsigned)n);
2361 		mem->offset += n;
2362 	}
2363 	return n;
2364 }
2365 
2366 /* tear down the mmap, close the fd */
2367 static void
2368 mmap_destroyer(__ops_reader_t *readinfo)
2369 {
2370 	mmap_reader_t *mem = __ops_reader_get_arg(readinfo);
2371 
2372 	(void) munmap(mem->mem, (unsigned)mem->size);
2373 	(void) close(mem->fd);
2374 	free(__ops_reader_get_arg(readinfo));
2375 }
2376 
2377 /* set up the file to use mmap-ed memory if available, file IO otherwise */
2378 void
2379 __ops_reader_set_mmap(__ops_stream_t *stream, int fd)
2380 {
2381 	mmap_reader_t	*mem;
2382 	struct stat	 st;
2383 
2384 	if (fstat(fd, &st) != 0) {
2385 		(void) fprintf(stderr, "__ops_reader_set_mmap: can't fstat\n");
2386 	} else if ((mem = calloc(1, sizeof(*mem))) == NULL) {
2387 		(void) fprintf(stderr, "__ops_reader_set_mmap: bad alloc\n");
2388 	} else {
2389 		mem->size = (uint64_t)st.st_size;
2390 		mem->offset = 0;
2391 		mem->fd = fd;
2392 		mem->mem = mmap(NULL, (size_t)st.st_size, PROT_READ,
2393 				MAP_PRIVATE | MAP_FILE, fd, 0);
2394 		if (mem->mem == MAP_FAILED) {
2395 			__ops_reader_set(stream, fd_reader, reader_fd_destroyer,
2396 					mem);
2397 		} else {
2398 			__ops_reader_set(stream, mmap_reader, mmap_destroyer,
2399 					mem);
2400 		}
2401 	}
2402 }
2403