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.44 2012/03/05 02:20:18 christos 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 
92 static int
93 keydata_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 
128 static void
129 free_sig_info(pgp_sig_info_t *sig)
130 {
131 	free(sig->v4_hashed);
132 	free(sig);
133 }
134 
135 static void
136 copy_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 
146 static int
147 add_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 /*
169 The 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]
174 to 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? */
178 unsigned
179 check_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 
235 pgp_cb_ret_t
236 pgp_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_1(errors, PGP_E_UNIMPLEMENTED, "%s",
383 				    "Can't add good sig to list\n");
384 			}
385 		} else {
386 			PGP_ERROR_1(errors, PGP_E_V_BAD_SIGNATURE, "%s",
387 			    "Bad Sig");
388 			if (!add_sig_to_list(&content->sig.info,
389 				&key->result->invalid_sigs,
390 				&key->result->invalidc)) {
391 				PGP_ERROR_1(errors, PGP_E_UNIMPLEMENTED, "%s",
392 				    "Can't add good sig to list\n");
393 			}
394 		}
395 		break;
396 
397 		/* ignore these */
398 	case PGP_PARSER_PTAG:
399 	case PGP_PTAG_CT_SIGNATURE_HEADER:
400 	case PGP_PARSER_PACKET_END:
401 		break;
402 
403 	case PGP_GET_PASSPHRASE:
404 		if (key->getpassphrase) {
405 			return key->getpassphrase(pkt, cbinfo);
406 		}
407 		break;
408 
409 	case PGP_PTAG_CT_TRUST:
410 		/* 1 byte for level (depth), 1 byte for trust amount */
411 		printf("trust dump\n");
412 		printf("Got trust\n");
413 		//hexdump(stdout, (const uint8_t *)content->trust.data, 10, " ");
414 		//hexdump(stdout, (const uint8_t *)&content->ss_trust, 2, " ");
415 		//printf("Trust level %d, amount %d\n", key->trust.level, key->trust.amount);
416 		break;
417 
418 	default:
419 		(void) fprintf(stderr, "unexpected tag=0x%x\n", pkt->tag);
420 		return PGP_FINISHED;
421 	}
422 	return PGP_RELEASE_MEMORY;
423 }
424 
425 pgp_cb_ret_t
426 validate_data_cb(const pgp_packet_t *pkt, pgp_cbdata_t *cbinfo)
427 {
428 	const pgp_contents_t	 *content = &pkt->u;
429 	const pgp_key_t	 *signer;
430 	validate_data_cb_t	 *data;
431 	pgp_pubkey_t		 *sigkey;
432 	pgp_error_t		**errors;
433 	pgp_io_t		 *io;
434 	unsigned		  from;
435 	unsigned		  valid = 0;
436 
437 	io = cbinfo->io;
438 	if (pgp_get_debug_level(__FILE__)) {
439 		(void) fprintf(io->errs, "validate_data_cb: %s\n",
440 				pgp_show_packet_tag(pkt->tag));
441 	}
442 	data = pgp_callback_arg(cbinfo);
443 	errors = pgp_callback_errors(cbinfo);
444 	switch (pkt->tag) {
445 	case PGP_PTAG_CT_SIGNED_CLEARTEXT_HEADER:
446 		/*
447 		 * ignore - this gives us the "Armor Header" line "Hash:
448 		 * SHA1" or similar
449 		 */
450 		break;
451 
452 	case PGP_PTAG_CT_LITDATA_HEADER:
453 		/* ignore */
454 		break;
455 
456 	case PGP_PTAG_CT_LITDATA_BODY:
457 		data->data.litdata_body = content->litdata_body;
458 		data->type = LITDATA;
459 		pgp_memory_add(data->mem, data->data.litdata_body.data,
460 				       data->data.litdata_body.length);
461 		return PGP_KEEP_MEMORY;
462 
463 	case PGP_PTAG_CT_SIGNED_CLEARTEXT_BODY:
464 		data->data.cleartext_body = content->cleartext_body;
465 		data->type = SIGNED_CLEARTEXT;
466 		pgp_memory_add(data->mem, data->data.cleartext_body.data,
467 			       data->data.cleartext_body.length);
468 		return PGP_KEEP_MEMORY;
469 
470 	case PGP_PTAG_CT_SIGNED_CLEARTEXT_TRAILER:
471 		/* this gives us an pgp_hash_t struct */
472 		break;
473 
474 	case PGP_PTAG_CT_SIGNATURE:	/* V3 sigs */
475 	case PGP_PTAG_CT_SIGNATURE_FOOTER:	/* V4 sigs */
476 		if (pgp_get_debug_level(__FILE__)) {
477 			hexdump(io->outs, "hashed data", content->sig.info.v4_hashed,
478 					content->sig.info.v4_hashlen);
479 			hexdump(io->outs, "signer id", content->sig.info.signer_id,
480 				sizeof(content->sig.info.signer_id));
481 		}
482 		from = 0;
483 		signer = pgp_getkeybyid(io, data->keyring,
484 					 content->sig.info.signer_id, &from, &sigkey);
485 		if (!signer) {
486 			PGP_ERROR_1(errors, PGP_E_V_UNKNOWN_SIGNER,
487 			    "%s", "Unknown Signer");
488 			if (!add_sig_to_list(&content->sig.info,
489 					&data->result->unknown_sigs,
490 					&data->result->unknownc)) {
491 				PGP_ERROR_1(errors, PGP_E_V_UNKNOWN_SIGNER,
492 				    "%s", "Can't add unknown sig to list");
493 			}
494 			break;
495 		}
496 		if (sigkey == &signer->enckey) {
497 			(void) fprintf(io->errs,
498 				"WARNING: signature made with encryption key\n");
499 		}
500 		if (content->sig.info.birthtime_set) {
501 			data->result->birthtime = content->sig.info.birthtime;
502 		}
503 		if (content->sig.info.duration_set) {
504 			data->result->duration = content->sig.info.duration;
505 		}
506 		switch (content->sig.info.type) {
507 		case PGP_SIG_BINARY:
508 		case PGP_SIG_TEXT:
509 			if (pgp_mem_len(data->mem) == 0 &&
510 			    data->detachname) {
511 				/* check we have seen some data */
512 				/* if not, need to read from detached name */
513 				(void) fprintf(io->errs,
514 				"netpgp: assuming signed data in \"%s\"\n",
515 					data->detachname);
516 				data->mem = pgp_memory_new();
517 				pgp_mem_readfile(data->mem, data->detachname);
518 			}
519 			if (pgp_get_debug_level(__FILE__)) {
520 				hexdump(stderr, "sig dump", (const uint8_t *)(const void *)&content->sig,
521 					sizeof(content->sig));
522 			}
523 			valid = check_binary_sig(pgp_mem_data(data->mem),
524 					(const unsigned)pgp_mem_len(data->mem),
525 					&content->sig,
526 					pgp_get_pubkey(signer));
527 			break;
528 
529 		default:
530 			PGP_ERROR_1(errors, PGP_E_UNIMPLEMENTED,
531 				    "No Sig Verification type 0x%02x yet\n",
532 				    content->sig.info.type);
533 			break;
534 
535 		}
536 
537 		if (valid) {
538 			if (!add_sig_to_list(&content->sig.info,
539 					&data->result->valid_sigs,
540 					&data->result->validc)) {
541 				PGP_ERROR_1(errors, PGP_E_V_BAD_SIGNATURE,
542 				    "%s", "Can't add good sig to list");
543 			}
544 		} else {
545 			PGP_ERROR_1(errors, PGP_E_V_BAD_SIGNATURE,
546 			    "%s", "Bad Signature");
547 			if (!add_sig_to_list(&content->sig.info,
548 					&data->result->invalid_sigs,
549 					&data->result->invalidc)) {
550 				PGP_ERROR_1(errors, PGP_E_V_BAD_SIGNATURE, "%s",
551 					"Can't add good sig to list");
552 			}
553 		}
554 		break;
555 
556 		/* ignore these */
557 	case PGP_PARSER_PTAG:
558 	case PGP_PTAG_CT_SIGNATURE_HEADER:
559 	case PGP_PTAG_CT_ARMOUR_HEADER:
560 	case PGP_PTAG_CT_ARMOUR_TRAILER:
561 	case PGP_PTAG_CT_1_PASS_SIG:
562 		break;
563 
564 	case PGP_PARSER_PACKET_END:
565 		break;
566 
567 	default:
568 		PGP_ERROR_1(errors, PGP_E_V_NO_SIGNATURE, "%s", "No signature");
569 		break;
570 	}
571 	return PGP_RELEASE_MEMORY;
572 }
573 
574 static void
575 keydata_destroyer(pgp_reader_t *readinfo)
576 {
577 	free(pgp_reader_get_arg(readinfo));
578 }
579 
580 void
581 pgp_keydata_reader_set(pgp_stream_t *stream, const pgp_key_t *key)
582 {
583 	validate_reader_t *data;
584 
585 	if ((data = calloc(1, sizeof(*data))) == NULL) {
586 		(void) fprintf(stderr, "pgp_keydata_reader_set: bad alloc\n");
587 	} else {
588 		data->key = key;
589 		data->packet = 0;
590 		data->offset = 0;
591 		pgp_reader_set(stream, keydata_reader, keydata_destroyer, data);
592 	}
593 }
594 
595 static char *
596 fmtsecs(int64_t n, char *buf, size_t size)
597 {
598 	if (n > 365 * 24 * 60 * 60) {
599 		n /= (365 * 24 * 60 * 60);
600 		(void) snprintf(buf, size, "%" PRId64 " year%s", n, (n == 1) ? "" : "s");
601 		return buf;
602 	}
603 	if (n > 30 * 24 * 60 * 60) {
604 		n /= (30 * 24 * 60 * 60);
605 		(void) snprintf(buf, size, "%" PRId64 " month%s", n, (n == 1) ? "" : "s");
606 		return buf;
607 	}
608 	if (n > 24 * 60 * 60) {
609 		n /= (24 * 60 * 60);
610 		(void) snprintf(buf, size, "%" PRId64 " day%s", n, (n == 1) ? "" : "s");
611 		return buf;
612 	}
613 	if (n > 60 * 60) {
614 		n /= (60 * 60);
615 		(void) snprintf(buf, size, "%" PRId64 " hour%s", n, (n == 1) ? "" : "s");
616 		return buf;
617 	}
618 	if (n > 60) {
619 		n /= 60;
620 		(void) snprintf(buf, size, "%" PRId64 " minute%s", n, (n == 1) ? "" : "s");
621 		return buf;
622 	}
623 	(void) snprintf(buf, size, "%" PRId64 " second%s", n, (n == 1) ? "" : "s");
624 	return buf;
625 }
626 
627 /**
628  * \ingroup HighLevel_Verify
629  * \brief Indicicates whether any errors were found
630  * \param result Validation result to check
631  * \return 0 if any invalid signatures or unknown signers
632  	or no valid signatures; else 1
633  */
634 static unsigned
635 validate_result_status(FILE *errs, const char *f, pgp_validation_t *val)
636 {
637 	time_t	now;
638 	time_t	t;
639 	char	buf[128];
640 
641 	now = time(NULL);
642 	if (now < val->birthtime) {
643 		/* signature is not valid yet! */
644 		if (f) {
645 			(void) fprintf(errs, "\"%s\": ", f);
646 		} else {
647 			(void) fprintf(errs, "memory ");
648 		}
649 		(void) fprintf(errs,
650 			"signature not valid until %.24s (%s)\n",
651 			ctime(&val->birthtime),
652 			fmtsecs((int64_t)(val->birthtime - now), buf, sizeof(buf)));
653 		return 0;
654 	}
655 	if (val->duration != 0 && now > val->birthtime + val->duration) {
656 		/* signature has expired */
657 		t = val->duration + val->birthtime;
658 		if (f) {
659 			(void) fprintf(errs, "\"%s\": ", f);
660 		} else {
661 			(void) fprintf(errs, "memory ");
662 		}
663 		(void) fprintf(errs,
664 			"signature not valid after %.24s (%s ago)\n",
665 			ctime(&t),
666 			fmtsecs((int64_t)(now - t), buf, sizeof(buf)));
667 		return 0;
668 	}
669 	return val->validc && !val->invalidc && !val->unknownc;
670 }
671 
672 /**
673  * \ingroup HighLevel_Verify
674  * \brief Validate all signatures on a single key against the given keyring
675  * \param result Where to put the result
676  * \param key Key to validate
677  * \param keyring Keyring to use for validation
678  * \param cb_get_passphrase Callback to use to get passphrase
679  * \return 1 if all signatures OK; else 0
680  * \note It is the caller's responsiblity to free result after use.
681  * \sa pgp_validate_result_free()
682  */
683 unsigned
684 pgp_validate_key_sigs(pgp_validation_t *result,
685 	const pgp_key_t *key,
686 	const pgp_keyring_t *keyring,
687 	pgp_cb_ret_t cb_get_passphrase(const pgp_packet_t *,
688 						pgp_cbdata_t *))
689 {
690 	pgp_stream_t	*stream;
691 	validate_key_cb_t	 keysigs;
692 	const int		 printerrors = 1;
693 
694 	(void) memset(&keysigs, 0x0, sizeof(keysigs));
695 	keysigs.result = result;
696 	keysigs.getpassphrase = cb_get_passphrase;
697 
698 	stream = pgp_new(sizeof(*stream));
699 	/* pgp_parse_options(&opt,PGP_PTAG_CT_SIGNATURE,PGP_PARSE_PARSED); */
700 
701 	keysigs.keyring = keyring;
702 
703 	pgp_set_callback(stream, pgp_validate_key_cb, &keysigs);
704 	stream->readinfo.accumulate = 1;
705 	pgp_keydata_reader_set(stream, key);
706 
707 	/* Note: Coverity incorrectly reports an error that keysigs.reader */
708 	/* is never used. */
709 	keysigs.reader = stream->readinfo.arg;
710 
711 	pgp_parse(stream, !printerrors);
712 
713 	pgp_pubkey_free(&keysigs.pubkey);
714 	if (keysigs.subkey.version) {
715 		pgp_pubkey_free(&keysigs.subkey);
716 	}
717 	pgp_userid_free(&keysigs.userid);
718 	pgp_data_free(&keysigs.userattr);
719 
720 	pgp_stream_delete(stream);
721 
722 	return (!result->invalidc && !result->unknownc && result->validc);
723 }
724 
725 /**
726    \ingroup HighLevel_Verify
727    \param result Where to put the result
728    \param ring Keyring to use
729    \param cb_get_passphrase Callback to use to get passphrase
730    \note It is the caller's responsibility to free result after use.
731    \sa pgp_validate_result_free()
732 */
733 unsigned
734 pgp_validate_all_sigs(pgp_validation_t *result,
735 	    const pgp_keyring_t *ring,
736 	    pgp_cb_ret_t cb_get_passphrase(const pgp_packet_t *,
737 	    					pgp_cbdata_t *))
738 {
739 	unsigned	n;
740 
741 	(void) memset(result, 0x0, sizeof(*result));
742 	for (n = 0; n < ring->keyc; ++n) {
743 		pgp_validate_key_sigs(result, &ring->keys[n], ring,
744 				cb_get_passphrase);
745 	}
746 	return validate_result_status(stderr, "keyring", result);
747 }
748 
749 /**
750    \ingroup HighLevel_Verify
751    \brief Frees validation result and associated memory
752    \param result Struct to be freed
753    \note Must be called after validation functions
754 */
755 void
756 pgp_validate_result_free(pgp_validation_t *result)
757 {
758 	if (result != NULL) {
759 		if (result->valid_sigs) {
760 			free_sig_info(result->valid_sigs);
761 		}
762 		if (result->invalid_sigs) {
763 			free_sig_info(result->invalid_sigs);
764 		}
765 		if (result->unknown_sigs) {
766 			free_sig_info(result->unknown_sigs);
767 		}
768 		free(result);
769 		/* result = NULL; - XXX unnecessary */
770 	}
771 }
772 
773 /**
774    \ingroup HighLevel_Verify
775    \brief Verifies the signatures in a signed file
776    \param result Where to put the result
777    \param filename Name of file to be validated
778    \param armoured Treat file as armoured, if set
779    \param keyring Keyring to use
780    \return 1 if signatures validate successfully;
781    	0 if signatures fail or there are no signatures
782    \note After verification, result holds the details of all keys which
783    have passed, failed and not been recognised.
784    \note It is the caller's responsiblity to call
785    	pgp_validate_result_free(result) after use.
786 */
787 unsigned
788 pgp_validate_file(pgp_io_t *io,
789 			pgp_validation_t *result,
790 			const char *infile,
791 			const char *outfile,
792 			const int user_says_armoured,
793 			const pgp_keyring_t *keyring)
794 {
795 	validate_data_cb_t	 validation;
796 	pgp_stream_t		*parse = NULL;
797 	struct stat		 st;
798 	const char		*signame;
799 	const int		 printerrors = 1;
800 	unsigned		 ret;
801 	char			 f[MAXPATHLEN];
802 	char			*dataname;
803 	int			 realarmour;
804 	int			 outfd = 0;
805 	int			 infd;
806 	int			 cc;
807 
808 	if (stat(infile, &st) < 0) {
809 		(void) fprintf(io->errs,
810 			"pgp_validate_file: can't open '%s'\n", infile);
811 		return 0;
812 	}
813 	realarmour = user_says_armoured;
814 	dataname = NULL;
815 	signame = NULL;
816 	cc = snprintf(f, sizeof(f), "%s", infile);
817 	if (strcmp(&f[cc - 4], ".sig") == 0) {
818 		/* we've been given a sigfile as infile */
819 		f[cc - 4] = 0x0;
820 		/* set dataname to name of file which was signed */
821 		dataname = f;
822 		signame = infile;
823 	} else if (strcmp(&f[cc - 4], ".asc") == 0) {
824 		/* we've been given an armored sigfile as infile */
825 		f[cc - 4] = 0x0;
826 		/* set dataname to name of file which was signed */
827 		dataname = f;
828 		signame = infile;
829 		realarmour = 1;
830 	} else {
831 		signame = infile;
832 	}
833 	(void) memset(&validation, 0x0, sizeof(validation));
834 	infd = pgp_setup_file_read(io, &parse, signame, &validation,
835 				validate_data_cb, 1);
836 	if (infd < 0) {
837 		return 0;
838 	}
839 
840 	if (dataname) {
841 		validation.detachname = netpgp_strdup(dataname);
842 	}
843 
844 	/* Set verification reader and handling options */
845 	validation.result = result;
846 	validation.keyring = keyring;
847 	validation.mem = pgp_memory_new();
848 	pgp_memory_init(validation.mem, 128);
849 	/* Note: Coverity incorrectly reports an error that validation.reader */
850 	/* is never used. */
851 	validation.reader = parse->readinfo.arg;
852 
853 	if (realarmour) {
854 		pgp_reader_push_dearmour(parse);
855 	}
856 
857 	/* Do the verification */
858 	pgp_parse(parse, !printerrors);
859 
860 	/* Tidy up */
861 	if (realarmour) {
862 		pgp_reader_pop_dearmour(parse);
863 	}
864 	pgp_teardown_file_read(parse, infd);
865 
866 	ret = validate_result_status(io->errs, infile, result);
867 
868 	/* this is triggered only for --cat output */
869 	if (outfile) {
870 		/* need to send validated output somewhere */
871 		if (strcmp(outfile, "-") == 0) {
872 			outfd = STDOUT_FILENO;
873 		} else {
874 			outfd = open(outfile, O_WRONLY | O_CREAT, 0666);
875 		}
876 		if (outfd < 0) {
877 			/* even if the signature was good, we can't
878 			* write the file, so send back a bad return
879 			* code */
880 			ret = 0;
881 		} else if (validate_result_status(io->errs, infile, result)) {
882 			unsigned	 len;
883 			char		*cp;
884 			int		 i;
885 
886 			len = (unsigned)pgp_mem_len(validation.mem);
887 			cp = pgp_mem_data(validation.mem);
888 			for (i = 0 ; i < (int)len ; i += cc) {
889 				cc = (int)write(outfd, &cp[i], (unsigned)(len - i));
890 				if (cc < 0) {
891 					(void) fprintf(io->errs,
892 						"netpgp: short write\n");
893 					ret = 0;
894 					break;
895 				}
896 			}
897 			if (strcmp(outfile, "-") != 0) {
898 				(void) close(outfd);
899 			}
900 		}
901 	}
902 	pgp_memory_free(validation.mem);
903 	return ret;
904 }
905 
906 /**
907    \ingroup HighLevel_Verify
908    \brief Verifies the signatures in a pgp_memory_t struct
909    \param result Where to put the result
910    \param mem Memory to be validated
911    \param user_says_armoured Treat data as armoured, if set
912    \param keyring Keyring to use
913    \return 1 if signature validates successfully; 0 if not
914    \note After verification, result holds the details of all keys which
915    have passed, failed and not been recognised.
916    \note It is the caller's responsiblity to call
917    	pgp_validate_result_free(result) after use.
918 */
919 
920 unsigned
921 pgp_validate_mem(pgp_io_t *io,
922 			pgp_validation_t *result,
923 			pgp_memory_t *mem,
924 			pgp_memory_t **cat,
925 			const int user_says_armoured,
926 			const pgp_keyring_t *keyring)
927 {
928 	validate_data_cb_t	 validation;
929 	pgp_stream_t		*stream = NULL;
930 	const int		 printerrors = 1;
931 	int			 realarmour;
932 
933 	pgp_setup_memory_read(io, &stream, mem, &validation, validate_data_cb, 1);
934 	/* Set verification reader and handling options */
935 	(void) memset(&validation, 0x0, sizeof(validation));
936 	validation.result = result;
937 	validation.keyring = keyring;
938 	validation.mem = pgp_memory_new();
939 	pgp_memory_init(validation.mem, 128);
940 	/* Note: Coverity incorrectly reports an error that validation.reader */
941 	/* is never used. */
942 	validation.reader = stream->readinfo.arg;
943 
944 	if ((realarmour = user_says_armoured) != 0 ||
945 	    strncmp(pgp_mem_data(mem),
946 	    		"-----BEGIN PGP MESSAGE-----", 27) == 0) {
947 		realarmour = 1;
948 	}
949 	if (realarmour) {
950 		pgp_reader_push_dearmour(stream);
951 	}
952 
953 	/* Do the verification */
954 	pgp_parse(stream, !printerrors);
955 
956 	/* Tidy up */
957 	if (realarmour) {
958 		pgp_reader_pop_dearmour(stream);
959 	}
960 	pgp_teardown_memory_read(stream, mem);
961 
962 	/* this is triggered only for --cat output */
963 	if (cat) {
964 		/* need to send validated output somewhere */
965 		*cat = validation.mem;
966 	} else {
967 		pgp_memory_free(validation.mem);
968 	}
969 
970 	return validate_result_status(io->errs, NULL, result);
971 }
972