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