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: validate.c,v 1.42 2010/11/07 08:39:59 agc Exp $");
58#endif
59
60#include <sys/types.h>
61#include <sys/param.h>
62#include <sys/stat.h>
63
64#include <string.h>
65#include <stdio.h>
66
67#ifdef HAVE_UNISTD_H
68#include <unistd.h>
69#endif
70
71#ifdef HAVE_FCNTL_H
72#include <fcntl.h>
73#endif
74
75#include "packet-parse.h"
76#include "packet-show.h"
77#include "keyring.h"
78#include "signature.h"
79#include "netpgpsdk.h"
80#include "readerwriter.h"
81#include "netpgpdefs.h"
82#include "memory.h"
83#include "packet.h"
84#include "crypto.h"
85#include "validate.h"
86
87#ifdef HAVE_FCNTL_H
88#include <fcntl.h>
89#endif
90
91
92static int
93keydata_reader(pgp_stream_t *stream, void *dest, size_t length, pgp_error_t **errors,
94	       pgp_reader_t *readinfo,
95	       pgp_cbdata_t *cbinfo)
96{
97	validate_reader_t *reader = pgp_reader_get_arg(readinfo);
98
99	__PGP_USED(stream);
100	__PGP_USED(errors);
101	__PGP_USED(cbinfo);
102	if (reader->offset == reader->key->packets[reader->packet].length) {
103		reader->packet += 1;
104		reader->offset = 0;
105	}
106	if (reader->packet == reader->key->packetc) {
107		return 0;
108	}
109
110	/*
111	 * we should never be asked to cross a packet boundary in a single
112	 * read
113	 */
114	if (reader->key->packets[reader->packet].length <
115			reader->offset + length) {
116		(void) fprintf(stderr, "keydata_reader: weird length\n");
117		return 0;
118	}
119
120	(void) memcpy(dest,
121		&reader->key->packets[reader->packet].raw[reader->offset],
122		length);
123	reader->offset += (unsigned)length;
124
125	return (int)length;
126}
127
128static void
129free_sig_info(pgp_sig_info_t *sig)
130{
131	free(sig->v4_hashed);
132	free(sig);
133}
134
135static void
136copy_sig_info(pgp_sig_info_t *dst, const pgp_sig_info_t *src)
137{
138	(void) memcpy(dst, src, sizeof(*src));
139	if ((dst->v4_hashed = calloc(1, src->v4_hashlen)) == NULL) {
140		(void) fprintf(stderr, "copy_sig_info: bad alloc\n");
141	} else {
142		(void) memcpy(dst->v4_hashed, src->v4_hashed, src->v4_hashlen);
143	}
144}
145
146static int
147add_sig_to_list(const pgp_sig_info_t *sig, pgp_sig_info_t **sigs,
148			unsigned *count)
149{
150	pgp_sig_info_t	*newsigs;
151
152	if (*count == 0) {
153		newsigs = calloc(*count + 1, sizeof(pgp_sig_info_t));
154	} else {
155		newsigs = realloc(*sigs,
156				(*count + 1) * sizeof(pgp_sig_info_t));
157	}
158	if (newsigs == NULL) {
159		(void) fprintf(stderr, "add_sig_to_list: alloc failure\n");
160		return 0;
161	}
162	*sigs = newsigs;
163	copy_sig_info(&(*sigs)[*count], sig);
164	*count += 1;
165	return 1;
166}
167
168/*
169The hash value is calculated by the following method:
170+ hash the data using the given digest algorithm
171+ hash the hash value onto the end
172+ hash the trailer - 6 bytes
173  [PGP_V4][0xff][len >> 24][len >> 16][len >> 8][len & 0xff]
174to give the final hash value that is checked against the one in the signature
175*/
176
177/* Does the signed hash match the given hash? */
178unsigned
179check_binary_sig(const uint8_t *data,
180		const unsigned len,
181		const pgp_sig_t *sig,
182		const pgp_pubkey_t *signer)
183{
184	unsigned    hashedlen;
185	pgp_hash_t	hash;
186	unsigned	n;
187	uint8_t		hashout[PGP_MAX_HASH_SIZE];
188	uint8_t		trailer[6];
189
190	pgp_hash_any(&hash, sig->info.hash_alg);
191	if (!hash.init(&hash)) {
192		(void) fprintf(stderr, "check_binary_sig: bad hash init\n");
193		return 0;
194	}
195	hash.add(&hash, data, len);
196	switch (sig->info.version) {
197	case PGP_V3:
198		trailer[0] = sig->info.type;
199		trailer[1] = (unsigned)(sig->info.birthtime) >> 24;
200		trailer[2] = (unsigned)(sig->info.birthtime) >> 16;
201		trailer[3] = (unsigned)(sig->info.birthtime) >> 8;
202		trailer[4] = (uint8_t)(sig->info.birthtime);
203		hash.add(&hash, trailer, 5);
204		break;
205
206	case PGP_V4:
207		if (pgp_get_debug_level(__FILE__)) {
208			hexdump(stderr, "v4 hash", sig->info.v4_hashed,
209					sig->info.v4_hashlen);
210		}
211		hash.add(&hash, sig->info.v4_hashed, (unsigned)sig->info.v4_hashlen);
212		trailer[0] = 0x04;	/* version */
213		trailer[1] = 0xFF;
214		hashedlen = (unsigned)sig->info.v4_hashlen;
215		trailer[2] = (uint8_t)(hashedlen >> 24);
216		trailer[3] = (uint8_t)(hashedlen >> 16);
217		trailer[4] = (uint8_t)(hashedlen >> 8);
218		trailer[5] = (uint8_t)(hashedlen);
219		hash.add(&hash, trailer, 6);
220		break;
221
222	default:
223		(void) fprintf(stderr, "Invalid signature version %d\n",
224				sig->info.version);
225		return 0;
226	}
227
228	n = hash.finish(&hash, hashout);
229	if (pgp_get_debug_level(__FILE__)) {
230		hexdump(stdout, "hash out", hashout, n);
231	}
232	return pgp_check_sig(hashout, n, sig, signer);
233}
234
235pgp_cb_ret_t
236pgp_validate_key_cb(const pgp_packet_t *pkt, pgp_cbdata_t *cbinfo)
237{
238	const pgp_contents_t	 *content = &pkt->u;
239	const pgp_key_t	 *signer;
240	validate_key_cb_t	 *key;
241	pgp_pubkey_t		 *sigkey;
242	pgp_error_t		**errors;
243	pgp_io_t		 *io;
244	unsigned		  from;
245	unsigned		  valid = 0;
246
247	io = cbinfo->io;
248	if (pgp_get_debug_level(__FILE__)) {
249		(void) fprintf(io->errs, "%s\n",
250				pgp_show_packet_tag(pkt->tag));
251	}
252	key = pgp_callback_arg(cbinfo);
253	errors = pgp_callback_errors(cbinfo);
254	switch (pkt->tag) {
255	case PGP_PTAG_CT_PUBLIC_KEY:
256		if (key->pubkey.version != 0) {
257			(void) fprintf(io->errs,
258				"pgp_validate_key_cb: version bad\n");
259			return PGP_FINISHED;
260		}
261		key->pubkey = content->pubkey;
262		return PGP_KEEP_MEMORY;
263
264	case PGP_PTAG_CT_PUBLIC_SUBKEY:
265		if (key->subkey.version) {
266			pgp_pubkey_free(&key->subkey);
267		}
268		key->subkey = content->pubkey;
269		return PGP_KEEP_MEMORY;
270
271	case PGP_PTAG_CT_SECRET_KEY:
272		key->seckey = content->seckey;
273		key->pubkey = key->seckey.pubkey;
274		return PGP_KEEP_MEMORY;
275
276	case PGP_PTAG_CT_USER_ID:
277		if (key->userid) {
278			pgp_userid_free(&key->userid);
279		}
280		key->userid = content->userid;
281		key->last_seen = ID;
282		return PGP_KEEP_MEMORY;
283
284	case PGP_PTAG_CT_USER_ATTR:
285		if (content->userattr.len == 0) {
286			(void) fprintf(io->errs,
287			"pgp_validate_key_cb: user attribute length 0");
288			return PGP_FINISHED;
289		}
290		(void) fprintf(io->outs, "user attribute, length=%d\n",
291			(int) content->userattr.len);
292		if (key->userattr.len) {
293			pgp_data_free(&key->userattr);
294		}
295		key->userattr = content->userattr;
296		key->last_seen = ATTRIBUTE;
297		return PGP_KEEP_MEMORY;
298
299	case PGP_PTAG_CT_SIGNATURE:	/* V3 sigs */
300	case PGP_PTAG_CT_SIGNATURE_FOOTER:	/* V4 sigs */
301		from = 0;
302		signer = pgp_getkeybyid(io, key->keyring,
303					 content->sig.info.signer_id,
304					 &from, &sigkey);
305		if (!signer) {
306			if (!add_sig_to_list(&content->sig.info,
307				&key->result->unknown_sigs,
308				&key->result->unknownc)) {
309					(void) fprintf(io->errs,
310					"pgp_validate_key_cb: user attribute length 0");
311					return PGP_FINISHED;
312			}
313			break;
314		}
315		if (sigkey == &signer->enckey) {
316			(void) fprintf(io->errs,
317				"WARNING: signature made with encryption key\n");
318		}
319		switch (content->sig.info.type) {
320		case PGP_CERT_GENERIC:
321		case PGP_CERT_PERSONA:
322		case PGP_CERT_CASUAL:
323		case PGP_CERT_POSITIVE:
324		case PGP_SIG_REV_CERT:
325			valid = (key->last_seen == ID) ?
326			    pgp_check_useridcert_sig(&key->pubkey,
327					key->userid,
328					&content->sig,
329					pgp_get_pubkey(signer),
330					key->reader->key->packets[
331						key->reader->packet].raw) :
332			    pgp_check_userattrcert_sig(&key->pubkey,
333					&key->userattr,
334					&content->sig,
335				       pgp_get_pubkey(signer),
336					key->reader->key->packets[
337						key->reader->packet].raw);
338			break;
339
340		case PGP_SIG_SUBKEY:
341			/*
342			 * XXX: we should also check that the signer is the
343			 * key we are validating, I think.
344			 */
345			valid = pgp_check_subkey_sig(&key->pubkey,
346				&key->subkey,
347				&content->sig,
348				pgp_get_pubkey(signer),
349				key->reader->key->packets[
350					key->reader->packet].raw);
351			break;
352
353		case PGP_SIG_DIRECT:
354			valid = pgp_check_direct_sig(&key->pubkey,
355				&content->sig,
356				pgp_get_pubkey(signer),
357				key->reader->key->packets[
358					key->reader->packet].raw);
359			break;
360
361		case PGP_SIG_STANDALONE:
362		case PGP_SIG_PRIMARY:
363		case PGP_SIG_REV_KEY:
364		case PGP_SIG_REV_SUBKEY:
365		case PGP_SIG_TIMESTAMP:
366		case PGP_SIG_3RD_PARTY:
367			PGP_ERROR_1(errors, PGP_E_UNIMPLEMENTED,
368				"Sig Verification type 0x%02x not done yet\n",
369				content->sig.info.type);
370			break;
371
372		default:
373			PGP_ERROR_1(errors, PGP_E_UNIMPLEMENTED,
374				    "Unexpected signature type 0x%02x\n",
375				    	content->sig.info.type);
376		}
377
378		if (valid) {
379			if (!add_sig_to_list(&content->sig.info,
380				&key->result->valid_sigs,
381				&key->result->validc)) {
382				PGP_ERROR(errors, PGP_E_UNIMPLEMENTED,
383				    "Can't add good sig to list\n");
384			}
385		} else {
386			PGP_ERROR(errors, PGP_E_V_BAD_SIGNATURE, "Bad Sig");
387			if (!add_sig_to_list(&content->sig.info,
388				&key->result->invalid_sigs,
389				&key->result->invalidc)) {
390				PGP_ERROR(errors, PGP_E_UNIMPLEMENTED,
391				    "Can't add good sig to list\n");
392			}
393		}
394		break;
395
396		/* ignore these */
397	case PGP_PARSER_PTAG:
398	case PGP_PTAG_CT_SIGNATURE_HEADER:
399	case PGP_PARSER_PACKET_END:
400		break;
401
402	case PGP_GET_PASSPHRASE:
403		if (key->getpassphrase) {
404			return key->getpassphrase(pkt, cbinfo);
405		}
406		break;
407
408	case PGP_PTAG_CT_TRUST:
409		/* 1 byte for level (depth), 1 byte for trust amount */
410		printf("trust dump\n");
411		printf("Got trust\n");
412		//hexdump(stdout, (const uint8_t *)content->trust.data, 10, " ");
413		//hexdump(stdout, (const uint8_t *)&content->ss_trust, 2, " ");
414		//printf("Trust level %d, amount %d\n", key->trust.level, key->trust.amount);
415		break;
416
417	default:
418		(void) fprintf(stderr, "unexpected tag=0x%x\n", pkt->tag);
419		return PGP_FINISHED;
420	}
421	return PGP_RELEASE_MEMORY;
422}
423
424pgp_cb_ret_t
425validate_data_cb(const pgp_packet_t *pkt, pgp_cbdata_t *cbinfo)
426{
427	const pgp_contents_t	 *content = &pkt->u;
428	const pgp_key_t	 *signer;
429	validate_data_cb_t	 *data;
430	pgp_pubkey_t		 *sigkey;
431	pgp_error_t		**errors;
432	pgp_io_t		 *io;
433	unsigned		  from;
434	unsigned		  valid = 0;
435
436	io = cbinfo->io;
437	if (pgp_get_debug_level(__FILE__)) {
438		(void) fprintf(io->errs, "validate_data_cb: %s\n",
439				pgp_show_packet_tag(pkt->tag));
440	}
441	data = pgp_callback_arg(cbinfo);
442	errors = pgp_callback_errors(cbinfo);
443	switch (pkt->tag) {
444	case PGP_PTAG_CT_SIGNED_CLEARTEXT_HEADER:
445		/*
446		 * ignore - this gives us the "Armor Header" line "Hash:
447		 * SHA1" or similar
448		 */
449		break;
450
451	case PGP_PTAG_CT_LITDATA_HEADER:
452		/* ignore */
453		break;
454
455	case PGP_PTAG_CT_LITDATA_BODY:
456		data->data.litdata_body = content->litdata_body;
457		data->type = LITDATA;
458		pgp_memory_add(data->mem, data->data.litdata_body.data,
459				       data->data.litdata_body.length);
460		return PGP_KEEP_MEMORY;
461
462	case PGP_PTAG_CT_SIGNED_CLEARTEXT_BODY:
463		data->data.cleartext_body = content->cleartext_body;
464		data->type = SIGNED_CLEARTEXT;
465		pgp_memory_add(data->mem, data->data.cleartext_body.data,
466			       data->data.cleartext_body.length);
467		return PGP_KEEP_MEMORY;
468
469	case PGP_PTAG_CT_SIGNED_CLEARTEXT_TRAILER:
470		/* this gives us an pgp_hash_t struct */
471		break;
472
473	case PGP_PTAG_CT_SIGNATURE:	/* V3 sigs */
474	case PGP_PTAG_CT_SIGNATURE_FOOTER:	/* V4 sigs */
475		if (pgp_get_debug_level(__FILE__)) {
476			hexdump(io->outs, "hashed data", content->sig.info.v4_hashed,
477					content->sig.info.v4_hashlen);
478			hexdump(io->outs, "signer id", content->sig.info.signer_id,
479				sizeof(content->sig.info.signer_id));
480		}
481		from = 0;
482		signer = pgp_getkeybyid(io, data->keyring,
483					 content->sig.info.signer_id, &from, &sigkey);
484		if (!signer) {
485			PGP_ERROR(errors, PGP_E_V_UNKNOWN_SIGNER,
486					"Unknown Signer");
487			if (!add_sig_to_list(&content->sig.info,
488					&data->result->unknown_sigs,
489					&data->result->unknownc)) {
490				PGP_ERROR(errors, PGP_E_V_UNKNOWN_SIGNER,
491					"Can't add unknown sig to list");
492			}
493			break;
494		}
495		if (sigkey == &signer->enckey) {
496			(void) fprintf(io->errs,
497				"WARNING: signature made with encryption key\n");
498		}
499		if (content->sig.info.birthtime_set) {
500			data->result->birthtime = content->sig.info.birthtime;
501		}
502		if (content->sig.info.duration_set) {
503			data->result->duration = content->sig.info.duration;
504		}
505		switch (content->sig.info.type) {
506		case PGP_SIG_BINARY:
507		case PGP_SIG_TEXT:
508			if (pgp_mem_len(data->mem) == 0 &&
509			    data->detachname) {
510				/* check we have seen some data */
511				/* if not, need to read from detached name */
512				(void) fprintf(io->errs,
513				"netpgp: assuming signed data in \"%s\"\n",
514					data->detachname);
515				data->mem = pgp_memory_new();
516				pgp_mem_readfile(data->mem, data->detachname);
517			}
518			if (pgp_get_debug_level(__FILE__)) {
519				hexdump(stderr, "sig dump", (const uint8_t *)(const void *)&content->sig,
520					sizeof(content->sig));
521			}
522			valid = check_binary_sig(pgp_mem_data(data->mem),
523					(const unsigned)pgp_mem_len(data->mem),
524					&content->sig,
525					pgp_get_pubkey(signer));
526			break;
527
528		default:
529			PGP_ERROR_1(errors, PGP_E_UNIMPLEMENTED,
530				    "No Sig Verification type 0x%02x yet\n",
531				    content->sig.info.type);
532			break;
533
534		}
535
536		if (valid) {
537			if (!add_sig_to_list(&content->sig.info,
538					&data->result->valid_sigs,
539					&data->result->validc)) {
540				PGP_ERROR(errors, PGP_E_V_BAD_SIGNATURE,
541					"Can't add good sig to list");
542			}
543		} else {
544			PGP_ERROR(errors, PGP_E_V_BAD_SIGNATURE,
545					"Bad Signature");
546			if (!add_sig_to_list(&content->sig.info,
547					&data->result->invalid_sigs,
548					&data->result->invalidc)) {
549				PGP_ERROR(errors, PGP_E_V_BAD_SIGNATURE,
550					"Can't add good sig to list");
551			}
552		}
553		break;
554
555		/* ignore these */
556	case PGP_PARSER_PTAG:
557	case PGP_PTAG_CT_SIGNATURE_HEADER:
558	case PGP_PTAG_CT_ARMOUR_HEADER:
559	case PGP_PTAG_CT_ARMOUR_TRAILER:
560	case PGP_PTAG_CT_1_PASS_SIG:
561		break;
562
563	case PGP_PARSER_PACKET_END:
564		break;
565
566	default:
567		PGP_ERROR(errors, PGP_E_V_NO_SIGNATURE, "No signature");
568		break;
569	}
570	return PGP_RELEASE_MEMORY;
571}
572
573static void
574keydata_destroyer(pgp_reader_t *readinfo)
575{
576	free(pgp_reader_get_arg(readinfo));
577}
578
579void
580pgp_keydata_reader_set(pgp_stream_t *stream, const pgp_key_t *key)
581{
582	validate_reader_t *data;
583
584	if ((data = calloc(1, sizeof(*data))) == NULL) {
585		(void) fprintf(stderr, "pgp_keydata_reader_set: bad alloc\n");
586	} else {
587		data->key = key;
588		data->packet = 0;
589		data->offset = 0;
590		pgp_reader_set(stream, keydata_reader, keydata_destroyer, data);
591	}
592}
593
594static char *
595fmtsecs(int64_t n, char *buf, size_t size)
596{
597	if (n > 365 * 24 * 60 * 60) {
598		n /= (365 * 24 * 60 * 60);
599		(void) snprintf(buf, size, "%" PRId64 " year%s", n, (n == 1) ? "" : "s");
600		return buf;
601	}
602	if (n > 30 * 24 * 60 * 60) {
603		n /= (30 * 24 * 60 * 60);
604		(void) snprintf(buf, size, "%" PRId64 " month%s", n, (n == 1) ? "" : "s");
605		return buf;
606	}
607	if (n > 24 * 60 * 60) {
608		n /= (24 * 60 * 60);
609		(void) snprintf(buf, size, "%" PRId64 " day%s", n, (n == 1) ? "" : "s");
610		return buf;
611	}
612	if (n > 60 * 60) {
613		n /= (60 * 60);
614		(void) snprintf(buf, size, "%" PRId64 " hour%s", n, (n == 1) ? "" : "s");
615		return buf;
616	}
617	if (n > 60) {
618		n /= 60;
619		(void) snprintf(buf, size, "%" PRId64 " minute%s", n, (n == 1) ? "" : "s");
620		return buf;
621	}
622	(void) snprintf(buf, size, "%" PRId64 " second%s", n, (n == 1) ? "" : "s");
623	return buf;
624}
625
626/**
627 * \ingroup HighLevel_Verify
628 * \brief Indicicates whether any errors were found
629 * \param result Validation result to check
630 * \return 0 if any invalid signatures or unknown signers
631 	or no valid signatures; else 1
632 */
633static unsigned
634validate_result_status(FILE *errs, const char *f, pgp_validation_t *val)
635{
636	time_t	now;
637	time_t	t;
638	char	buf[128];
639
640	now = time(NULL);
641	if (now < val->birthtime) {
642		/* signature is not valid yet! */
643		if (f) {
644			(void) fprintf(errs, "\"%s\": ", f);
645		} else {
646			(void) fprintf(errs, "memory ");
647		}
648		(void) fprintf(errs,
649			"signature not valid until %.24s (%s)\n",
650			ctime(&val->birthtime),
651			fmtsecs((int64_t)(val->birthtime - now), buf, sizeof(buf)));
652		return 0;
653	}
654	if (val->duration != 0 && now > val->birthtime + val->duration) {
655		/* signature has expired */
656		t = val->duration + val->birthtime;
657		if (f) {
658			(void) fprintf(errs, "\"%s\": ", f);
659		} else {
660			(void) fprintf(errs, "memory ");
661		}
662		(void) fprintf(errs,
663			"signature not valid after %.24s (%s ago)\n",
664			ctime(&t),
665			fmtsecs((int64_t)(now - t), buf, sizeof(buf)));
666		return 0;
667	}
668	return val->validc && !val->invalidc && !val->unknownc;
669}
670
671/**
672 * \ingroup HighLevel_Verify
673 * \brief Validate all signatures on a single key against the given keyring
674 * \param result Where to put the result
675 * \param key Key to validate
676 * \param keyring Keyring to use for validation
677 * \param cb_get_passphrase Callback to use to get passphrase
678 * \return 1 if all signatures OK; else 0
679 * \note It is the caller's responsiblity to free result after use.
680 * \sa pgp_validate_result_free()
681 */
682unsigned
683pgp_validate_key_sigs(pgp_validation_t *result,
684	const pgp_key_t *key,
685	const pgp_keyring_t *keyring,
686	pgp_cb_ret_t cb_get_passphrase(const pgp_packet_t *,
687						pgp_cbdata_t *))
688{
689	pgp_stream_t	*stream;
690	validate_key_cb_t	 keysigs;
691	const int		 printerrors = 1;
692
693	(void) memset(&keysigs, 0x0, sizeof(keysigs));
694	keysigs.result = result;
695	keysigs.getpassphrase = cb_get_passphrase;
696
697	stream = pgp_new(sizeof(*stream));
698	/* pgp_parse_options(&opt,PGP_PTAG_CT_SIGNATURE,PGP_PARSE_PARSED); */
699
700	keysigs.keyring = keyring;
701
702	pgp_set_callback(stream, pgp_validate_key_cb, &keysigs);
703	stream->readinfo.accumulate = 1;
704	pgp_keydata_reader_set(stream, key);
705
706	/* Note: Coverity incorrectly reports an error that keysigs.reader */
707	/* is never used. */
708	keysigs.reader = stream->readinfo.arg;
709
710	pgp_parse(stream, !printerrors);
711
712	pgp_pubkey_free(&keysigs.pubkey);
713	if (keysigs.subkey.version) {
714		pgp_pubkey_free(&keysigs.subkey);
715	}
716	pgp_userid_free(&keysigs.userid);
717	pgp_data_free(&keysigs.userattr);
718
719	pgp_stream_delete(stream);
720
721	return (!result->invalidc && !result->unknownc && result->validc);
722}
723
724/**
725   \ingroup HighLevel_Verify
726   \param result Where to put the result
727   \param ring Keyring to use
728   \param cb_get_passphrase Callback to use to get passphrase
729   \note It is the caller's responsibility to free result after use.
730   \sa pgp_validate_result_free()
731*/
732unsigned
733pgp_validate_all_sigs(pgp_validation_t *result,
734	    const pgp_keyring_t *ring,
735	    pgp_cb_ret_t cb_get_passphrase(const pgp_packet_t *,
736	    					pgp_cbdata_t *))
737{
738	unsigned	n;
739
740	(void) memset(result, 0x0, sizeof(*result));
741	for (n = 0; n < ring->keyc; ++n) {
742		pgp_validate_key_sigs(result, &ring->keys[n], ring,
743				cb_get_passphrase);
744	}
745	return validate_result_status(stderr, "keyring", result);
746}
747
748/**
749   \ingroup HighLevel_Verify
750   \brief Frees validation result and associated memory
751   \param result Struct to be freed
752   \note Must be called after validation functions
753*/
754void
755pgp_validate_result_free(pgp_validation_t *result)
756{
757	if (result != NULL) {
758		if (result->valid_sigs) {
759			free_sig_info(result->valid_sigs);
760		}
761		if (result->invalid_sigs) {
762			free_sig_info(result->invalid_sigs);
763		}
764		if (result->unknown_sigs) {
765			free_sig_info(result->unknown_sigs);
766		}
767		free(result);
768		/* result = NULL; - XXX unnecessary */
769	}
770}
771
772/**
773   \ingroup HighLevel_Verify
774   \brief Verifies the signatures in a signed file
775   \param result Where to put the result
776   \param filename Name of file to be validated
777   \param armoured Treat file as armoured, if set
778   \param keyring Keyring to use
779   \return 1 if signatures validate successfully;
780   	0 if signatures fail or there are no signatures
781   \note After verification, result holds the details of all keys which
782   have passed, failed and not been recognised.
783   \note It is the caller's responsiblity to call
784   	pgp_validate_result_free(result) after use.
785*/
786unsigned
787pgp_validate_file(pgp_io_t *io,
788			pgp_validation_t *result,
789			const char *infile,
790			const char *outfile,
791			const int user_says_armoured,
792			const pgp_keyring_t *keyring)
793{
794	validate_data_cb_t	 validation;
795	pgp_stream_t		*parse = NULL;
796	struct stat		 st;
797	const char		*signame;
798	const int		 printerrors = 1;
799	unsigned		 ret;
800	char			 f[MAXPATHLEN];
801	char			*dataname;
802	int			 realarmour;
803	int			 outfd = 0;
804	int			 infd;
805	int			 cc;
806
807	if (stat(infile, &st) < 0) {
808		(void) fprintf(io->errs,
809			"pgp_validate_file: can't open '%s'\n", infile);
810		return 0;
811	}
812	realarmour = user_says_armoured;
813	dataname = NULL;
814	signame = NULL;
815	cc = snprintf(f, sizeof(f), "%s", infile);
816	if (strcmp(&f[cc - 4], ".sig") == 0) {
817		/* we've been given a sigfile as infile */
818		f[cc - 4] = 0x0;
819		/* set dataname to name of file which was signed */
820		dataname = f;
821		signame = infile;
822	} else if (strcmp(&f[cc - 4], ".asc") == 0) {
823		/* we've been given an armored sigfile as infile */
824		f[cc - 4] = 0x0;
825		/* set dataname to name of file which was signed */
826		dataname = f;
827		signame = infile;
828		realarmour = 1;
829	} else {
830		signame = infile;
831	}
832	(void) memset(&validation, 0x0, sizeof(validation));
833	infd = pgp_setup_file_read(io, &parse, signame, &validation,
834				validate_data_cb, 1);
835	if (infd < 0) {
836		return 0;
837	}
838
839	if (dataname) {
840		validation.detachname = netpgp_strdup(dataname);
841	}
842
843	/* Set verification reader and handling options */
844	validation.result = result;
845	validation.keyring = keyring;
846	validation.mem = pgp_memory_new();
847	pgp_memory_init(validation.mem, 128);
848	/* Note: Coverity incorrectly reports an error that validation.reader */
849	/* is never used. */
850	validation.reader = parse->readinfo.arg;
851
852	if (realarmour) {
853		pgp_reader_push_dearmour(parse);
854	}
855
856	/* Do the verification */
857	pgp_parse(parse, !printerrors);
858
859	/* Tidy up */
860	if (realarmour) {
861		pgp_reader_pop_dearmour(parse);
862	}
863	pgp_teardown_file_read(parse, infd);
864
865	ret = validate_result_status(io->errs, infile, result);
866
867	/* this is triggered only for --cat output */
868	if (outfile) {
869		/* need to send validated output somewhere */
870		if (strcmp(outfile, "-") == 0) {
871			outfd = STDOUT_FILENO;
872		} else {
873			outfd = open(outfile, O_WRONLY | O_CREAT, 0666);
874		}
875		if (outfd < 0) {
876			/* even if the signature was good, we can't
877			* write the file, so send back a bad return
878			* code */
879			ret = 0;
880		} else if (validate_result_status(io->errs, infile, result)) {
881			unsigned	 len;
882			char		*cp;
883			int		 i;
884
885			len = (unsigned)pgp_mem_len(validation.mem);
886			cp = pgp_mem_data(validation.mem);
887			for (i = 0 ; i < (int)len ; i += cc) {
888				cc = (int)write(outfd, &cp[i], (unsigned)(len - i));
889				if (cc < 0) {
890					(void) fprintf(io->errs,
891						"netpgp: short write\n");
892					ret = 0;
893					break;
894				}
895			}
896			if (strcmp(outfile, "-") != 0) {
897				(void) close(outfd);
898			}
899		}
900	}
901	pgp_memory_free(validation.mem);
902	return ret;
903}
904
905/**
906   \ingroup HighLevel_Verify
907   \brief Verifies the signatures in a pgp_memory_t struct
908   \param result Where to put the result
909   \param mem Memory to be validated
910   \param user_says_armoured Treat data as armoured, if set
911   \param keyring Keyring to use
912   \return 1 if signature validates successfully; 0 if not
913   \note After verification, result holds the details of all keys which
914   have passed, failed and not been recognised.
915   \note It is the caller's responsiblity to call
916   	pgp_validate_result_free(result) after use.
917*/
918
919unsigned
920pgp_validate_mem(pgp_io_t *io,
921			pgp_validation_t *result,
922			pgp_memory_t *mem,
923			pgp_memory_t **cat,
924			const int user_says_armoured,
925			const pgp_keyring_t *keyring)
926{
927	validate_data_cb_t	 validation;
928	pgp_stream_t		*stream = NULL;
929	const int		 printerrors = 1;
930	int			 realarmour;
931
932	pgp_setup_memory_read(io, &stream, mem, &validation, validate_data_cb, 1);
933	/* Set verification reader and handling options */
934	(void) memset(&validation, 0x0, sizeof(validation));
935	validation.result = result;
936	validation.keyring = keyring;
937	validation.mem = pgp_memory_new();
938	pgp_memory_init(validation.mem, 128);
939	/* Note: Coverity incorrectly reports an error that validation.reader */
940	/* is never used. */
941	validation.reader = stream->readinfo.arg;
942
943	if ((realarmour = user_says_armoured) != 0 ||
944	    strncmp(pgp_mem_data(mem),
945	    		"-----BEGIN PGP MESSAGE-----", 27) == 0) {
946		realarmour = 1;
947	}
948	if (realarmour) {
949		pgp_reader_push_dearmour(stream);
950	}
951
952	/* Do the verification */
953	pgp_parse(stream, !printerrors);
954
955	/* Tidy up */
956	if (realarmour) {
957		pgp_reader_pop_dearmour(stream);
958	}
959	pgp_teardown_memory_read(stream, mem);
960
961	/* this is triggered only for --cat output */
962	if (cat) {
963		/* need to send validated output somewhere */
964		*cat = validation.mem;
965	} else {
966		pgp_memory_free(validation.mem);
967	}
968
969	return validate_result_status(io->errs, NULL, result);
970}
971