12232f800Sagc /*-
22232f800Sagc  * Copyright (c) 2009 The NetBSD Foundation, Inc.
32232f800Sagc  * All rights reserved.
42232f800Sagc  *
52232f800Sagc  * This code is derived from software contributed to The NetBSD Foundation
62232f800Sagc  * by Alistair Crooks (agc@NetBSD.org)
72232f800Sagc  *
82232f800Sagc  * Redistribution and use in source and binary forms, with or without
92232f800Sagc  * modification, are permitted provided that the following conditions
102232f800Sagc  * are met:
112232f800Sagc  * 1. Redistributions of source code must retain the above copyright
122232f800Sagc  *    notice, this list of conditions and the following disclaimer.
132232f800Sagc  * 2. Redistributions in binary form must reproduce the above copyright
142232f800Sagc  *    notice, this list of conditions and the following disclaimer in the
152232f800Sagc  *    documentation and/or other materials provided with the distribution.
162232f800Sagc  *
172232f800Sagc  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
182232f800Sagc  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
192232f800Sagc  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
202232f800Sagc  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
212232f800Sagc  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
222232f800Sagc  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
232232f800Sagc  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
242232f800Sagc  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
252232f800Sagc  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
262232f800Sagc  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
272232f800Sagc  * POSSIBILITY OF SUCH DAMAGE.
282232f800Sagc  */
2993bf6008Sagc /*
3093bf6008Sagc  * Copyright (c) 2005-2008 Nominet UK (www.nic.uk)
3193bf6008Sagc  * All rights reserved.
3293bf6008Sagc  * Contributors: Ben Laurie, Rachel Willmer. The Contributors have asserted
3393bf6008Sagc  * their moral rights under the UK Copyright Design and Patents Act 1988 to
3493bf6008Sagc  * be recorded as the authors of this copyright work.
3593bf6008Sagc  *
3693bf6008Sagc  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
3793bf6008Sagc  * use this file except in compliance with the License.
3893bf6008Sagc  *
3993bf6008Sagc  * You may obtain a copy of the License at
4093bf6008Sagc  *     http://www.apache.org/licenses/LICENSE-2.0
4193bf6008Sagc  *
4293bf6008Sagc  * Unless required by applicable law or agreed to in writing, software
4393bf6008Sagc  * distributed under the License is distributed on an "AS IS" BASIS,
4493bf6008Sagc  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
4593bf6008Sagc  *
4693bf6008Sagc  * See the License for the specific language governing permissions and
4793bf6008Sagc  * limitations under the License.
4893bf6008Sagc  */
4993bf6008Sagc #include "config.h"
5093bf6008Sagc 
5157324b9fSagc #ifdef HAVE_SYS_CDEFS_H
5257324b9fSagc #include <sys/cdefs.h>
5357324b9fSagc #endif
5457324b9fSagc 
5557324b9fSagc #if defined(__NetBSD__)
5657324b9fSagc __COPYRIGHT("@(#) Copyright (c) 2009 The NetBSD Foundation, Inc. All rights reserved.");
57*3dae3613Schristos __RCSID("$NetBSD: validate.c,v 1.44 2012/03/05 02:20:18 christos Exp $");
5857324b9fSagc #endif
5957324b9fSagc 
60bcfd8565Sagc #include <sys/types.h>
61bcfd8565Sagc #include <sys/param.h>
62bcfd8565Sagc #include <sys/stat.h>
63bcfd8565Sagc 
6493bf6008Sagc #include <string.h>
65bcfd8565Sagc #include <stdio.h>
6693bf6008Sagc 
6757324b9fSagc #ifdef HAVE_UNISTD_H
6857324b9fSagc #include <unistd.h>
6957324b9fSagc #endif
7057324b9fSagc 
71648b5a99Sagc #ifdef HAVE_FCNTL_H
72648b5a99Sagc #include <fcntl.h>
73648b5a99Sagc #endif
74648b5a99Sagc 
750c310959Sagc #include "packet-parse.h"
760c310959Sagc #include "packet-show.h"
770c310959Sagc #include "keyring.h"
780c310959Sagc #include "signature.h"
790c310959Sagc #include "netpgpsdk.h"
800c310959Sagc #include "readerwriter.h"
810c310959Sagc #include "netpgpdefs.h"
820c310959Sagc #include "memory.h"
834b3a3e18Sagc #include "packet.h"
844b3a3e18Sagc #include "crypto.h"
850c310959Sagc #include "validate.h"
860c310959Sagc 
87648b5a99Sagc #ifdef HAVE_FCNTL_H
88648b5a99Sagc #include <fcntl.h>
89648b5a99Sagc #endif
90648b5a99Sagc 
9193bf6008Sagc 
9293bf6008Sagc static int
keydata_reader(pgp_stream_t * stream,void * dest,size_t length,pgp_error_t ** errors,pgp_reader_t * readinfo,pgp_cbdata_t * cbinfo)93b0df0a22Sagc keydata_reader(pgp_stream_t *stream, void *dest, size_t length, pgp_error_t **errors,
94fc1f8641Sagc 	       pgp_reader_t *readinfo,
95fc1f8641Sagc 	       pgp_cbdata_t *cbinfo)
9693bf6008Sagc {
97fc1f8641Sagc 	validate_reader_t *reader = pgp_reader_get_arg(readinfo);
9893bf6008Sagc 
99b0df0a22Sagc 	__PGP_USED(stream);
100fc1f8641Sagc 	__PGP_USED(errors);
101fc1f8641Sagc 	__PGP_USED(cbinfo);
10293bf6008Sagc 	if (reader->offset == reader->key->packets[reader->packet].length) {
103bcfd8565Sagc 		reader->packet += 1;
10493bf6008Sagc 		reader->offset = 0;
10593bf6008Sagc 	}
10641335e2dSagc 	if (reader->packet == reader->key->packetc) {
10793bf6008Sagc 		return 0;
108bcfd8565Sagc 	}
10993bf6008Sagc 
11093bf6008Sagc 	/*
11193bf6008Sagc 	 * we should never be asked to cross a packet boundary in a single
11293bf6008Sagc 	 * read
11393bf6008Sagc 	 */
114bcfd8565Sagc 	if (reader->key->packets[reader->packet].length <
115bcfd8565Sagc 			reader->offset + length) {
116bcfd8565Sagc 		(void) fprintf(stderr, "keydata_reader: weird length\n");
117bcfd8565Sagc 		return 0;
118bcfd8565Sagc 	}
11993bf6008Sagc 
120de704779Sagc 	(void) memcpy(dest,
121de704779Sagc 		&reader->key->packets[reader->packet].raw[reader->offset],
122de704779Sagc 		length);
12369d4f30fSagc 	reader->offset += (unsigned)length;
12493bf6008Sagc 
12569d4f30fSagc 	return (int)length;
12693bf6008Sagc }
12793bf6008Sagc 
12893bf6008Sagc static void
free_sig_info(pgp_sig_info_t * sig)129fc1f8641Sagc free_sig_info(pgp_sig_info_t *sig)
13093bf6008Sagc {
13183cfb9deSagc 	free(sig->v4_hashed);
13283cfb9deSagc 	free(sig);
13393bf6008Sagc }
13493bf6008Sagc 
13593bf6008Sagc static void
copy_sig_info(pgp_sig_info_t * dst,const pgp_sig_info_t * src)136fc1f8641Sagc copy_sig_info(pgp_sig_info_t *dst, const pgp_sig_info_t *src)
13793bf6008Sagc {
13893bf6008Sagc 	(void) memcpy(dst, src, sizeof(*src));
13983cfb9deSagc 	if ((dst->v4_hashed = calloc(1, src->v4_hashlen)) == NULL) {
14083cfb9deSagc 		(void) fprintf(stderr, "copy_sig_info: bad alloc\n");
14183cfb9deSagc 	} else {
1426715e11aSagc 		(void) memcpy(dst->v4_hashed, src->v4_hashed, src->v4_hashlen);
14393bf6008Sagc 	}
14483cfb9deSagc }
14593bf6008Sagc 
14683cfb9deSagc static int
add_sig_to_list(const pgp_sig_info_t * sig,pgp_sig_info_t ** sigs,unsigned * count)147fc1f8641Sagc add_sig_to_list(const pgp_sig_info_t *sig, pgp_sig_info_t **sigs,
14893bf6008Sagc 			unsigned *count)
14993bf6008Sagc {
150fc1f8641Sagc 	pgp_sig_info_t	*newsigs;
15183cfb9deSagc 
15293bf6008Sagc 	if (*count == 0) {
153fc1f8641Sagc 		newsigs = calloc(*count + 1, sizeof(pgp_sig_info_t));
15493bf6008Sagc 	} else {
15583cfb9deSagc 		newsigs = realloc(*sigs,
156fc1f8641Sagc 				(*count + 1) * sizeof(pgp_sig_info_t));
15793bf6008Sagc 	}
158600b302bSagc 	if (newsigs == NULL) {
159600b302bSagc 		(void) fprintf(stderr, "add_sig_to_list: alloc failure\n");
160600b302bSagc 		return 0;
161600b302bSagc 	}
16283cfb9deSagc 	*sigs = newsigs;
1633326c4c5Sagc 	copy_sig_info(&(*sigs)[*count], sig);
16493bf6008Sagc 	*count += 1;
16583cfb9deSagc 	return 1;
16683cfb9deSagc }
167600b302bSagc 
168600b302bSagc /*
169600b302bSagc The hash value is calculated by the following method:
170600b302bSagc + hash the data using the given digest algorithm
171600b302bSagc + hash the hash value onto the end
172600b302bSagc + hash the trailer - 6 bytes
173fc1f8641Sagc   [PGP_V4][0xff][len >> 24][len >> 16][len >> 8][len & 0xff]
174600b302bSagc to give the final hash value that is checked against the one in the signature
175600b302bSagc */
176600b302bSagc 
177600b302bSagc /* Does the signed hash match the given hash? */
178600b302bSagc unsigned
check_binary_sig(const uint8_t * data,const unsigned len,const pgp_sig_t * sig,const pgp_pubkey_t * signer)179b15ec256Sagc check_binary_sig(const uint8_t *data,
180600b302bSagc 		const unsigned len,
181fc1f8641Sagc 		const pgp_sig_t *sig,
182fc1f8641Sagc 		const pgp_pubkey_t *signer)
183600b302bSagc {
184b15ec256Sagc 	unsigned    hashedlen;
185fc1f8641Sagc 	pgp_hash_t	hash;
186600b302bSagc 	unsigned	n;
187fc1f8641Sagc 	uint8_t		hashout[PGP_MAX_HASH_SIZE];
188b15ec256Sagc 	uint8_t		trailer[6];
189600b302bSagc 
190fc1f8641Sagc 	pgp_hash_any(&hash, sig->info.hash_alg);
191600b302bSagc 	if (!hash.init(&hash)) {
192600b302bSagc 		(void) fprintf(stderr, "check_binary_sig: bad hash init\n");
193600b302bSagc 		return 0;
194600b302bSagc 	}
195600b302bSagc 	hash.add(&hash, data, len);
196600b302bSagc 	switch (sig->info.version) {
197fc1f8641Sagc 	case PGP_V3:
198600b302bSagc 		trailer[0] = sig->info.type;
199600b302bSagc 		trailer[1] = (unsigned)(sig->info.birthtime) >> 24;
200600b302bSagc 		trailer[2] = (unsigned)(sig->info.birthtime) >> 16;
201600b302bSagc 		trailer[3] = (unsigned)(sig->info.birthtime) >> 8;
202b15ec256Sagc 		trailer[4] = (uint8_t)(sig->info.birthtime);
203600b302bSagc 		hash.add(&hash, trailer, 5);
204600b302bSagc 		break;
205600b302bSagc 
206fc1f8641Sagc 	case PGP_V4:
207fc1f8641Sagc 		if (pgp_get_debug_level(__FILE__)) {
20847561e26Sagc 			hexdump(stderr, "v4 hash", sig->info.v4_hashed,
209600b302bSagc 					sig->info.v4_hashlen);
210600b302bSagc 		}
21169d4f30fSagc 		hash.add(&hash, sig->info.v4_hashed, (unsigned)sig->info.v4_hashlen);
212600b302bSagc 		trailer[0] = 0x04;	/* version */
213600b302bSagc 		trailer[1] = 0xFF;
21469d4f30fSagc 		hashedlen = (unsigned)sig->info.v4_hashlen;
21569d4f30fSagc 		trailer[2] = (uint8_t)(hashedlen >> 24);
21669d4f30fSagc 		trailer[3] = (uint8_t)(hashedlen >> 16);
21769d4f30fSagc 		trailer[4] = (uint8_t)(hashedlen >> 8);
21869d4f30fSagc 		trailer[5] = (uint8_t)(hashedlen);
219600b302bSagc 		hash.add(&hash, trailer, 6);
220600b302bSagc 		break;
221600b302bSagc 
222600b302bSagc 	default:
223600b302bSagc 		(void) fprintf(stderr, "Invalid signature version %d\n",
224600b302bSagc 				sig->info.version);
22583cfb9deSagc 		return 0;
22693bf6008Sagc 	}
22793bf6008Sagc 
228600b302bSagc 	n = hash.finish(&hash, hashout);
229fc1f8641Sagc 	if (pgp_get_debug_level(__FILE__)) {
23047561e26Sagc 		hexdump(stdout, "hash out", hashout, n);
231600b302bSagc 	}
232fc1f8641Sagc 	return pgp_check_sig(hashout, n, sig, signer);
233600b302bSagc }
23493bf6008Sagc 
235fc1f8641Sagc pgp_cb_ret_t
pgp_validate_key_cb(const pgp_packet_t * pkt,pgp_cbdata_t * cbinfo)236fc1f8641Sagc pgp_validate_key_cb(const pgp_packet_t *pkt, pgp_cbdata_t *cbinfo)
23793bf6008Sagc {
238fc1f8641Sagc 	const pgp_contents_t	 *content = &pkt->u;
239fc1f8641Sagc 	const pgp_key_t	 *signer;
24057324b9fSagc 	validate_key_cb_t	 *key;
241fc1f8641Sagc 	pgp_pubkey_t		 *sigkey;
242fc1f8641Sagc 	pgp_error_t		**errors;
243fc1f8641Sagc 	pgp_io_t		 *io;
244183e04ebSagc 	unsigned		  from;
2454b3a3e18Sagc 	unsigned		  valid = 0;
24693bf6008Sagc 
247d21b929eSagc 	io = cbinfo->io;
248fc1f8641Sagc 	if (pgp_get_debug_level(__FILE__)) {
249d21b929eSagc 		(void) fprintf(io->errs, "%s\n",
250fc1f8641Sagc 				pgp_show_packet_tag(pkt->tag));
251de704779Sagc 	}
252fc1f8641Sagc 	key = pgp_callback_arg(cbinfo);
253fc1f8641Sagc 	errors = pgp_callback_errors(cbinfo);
2543326c4c5Sagc 	switch (pkt->tag) {
255fc1f8641Sagc 	case PGP_PTAG_CT_PUBLIC_KEY:
2560c310959Sagc 		if (key->pubkey.version != 0) {
257d21b929eSagc 			(void) fprintf(io->errs,
258fc1f8641Sagc 				"pgp_validate_key_cb: version bad\n");
259fc1f8641Sagc 			return PGP_FINISHED;
260bcfd8565Sagc 		}
2610c310959Sagc 		key->pubkey = content->pubkey;
262fc1f8641Sagc 		return PGP_KEEP_MEMORY;
26393bf6008Sagc 
264fc1f8641Sagc 	case PGP_PTAG_CT_PUBLIC_SUBKEY:
26557324b9fSagc 		if (key->subkey.version) {
266fc1f8641Sagc 			pgp_pubkey_free(&key->subkey);
26757324b9fSagc 		}
268bcfd8565Sagc 		key->subkey = content->pubkey;
269fc1f8641Sagc 		return PGP_KEEP_MEMORY;
27093bf6008Sagc 
271fc1f8641Sagc 	case PGP_PTAG_CT_SECRET_KEY:
2720c310959Sagc 		key->seckey = content->seckey;
2730c310959Sagc 		key->pubkey = key->seckey.pubkey;
274fc1f8641Sagc 		return PGP_KEEP_MEMORY;
27593bf6008Sagc 
276fc1f8641Sagc 	case PGP_PTAG_CT_USER_ID:
277d427c17dSagc 		if (key->userid) {
278fc1f8641Sagc 			pgp_userid_free(&key->userid);
279d21b929eSagc 		}
28057324b9fSagc 		key->userid = content->userid;
28193bf6008Sagc 		key->last_seen = ID;
282fc1f8641Sagc 		return PGP_KEEP_MEMORY;
28393bf6008Sagc 
284fc1f8641Sagc 	case PGP_PTAG_CT_USER_ATTR:
285d427c17dSagc 		if (content->userattr.len == 0) {
286d21b929eSagc 			(void) fprintf(io->errs,
287fc1f8641Sagc 			"pgp_validate_key_cb: user attribute length 0");
288fc1f8641Sagc 			return PGP_FINISHED;
289bcfd8565Sagc 		}
290d21b929eSagc 		(void) fprintf(io->outs, "user attribute, length=%d\n",
291d427c17dSagc 			(int) content->userattr.len);
292d427c17dSagc 		if (key->userattr.len) {
293fc1f8641Sagc 			pgp_data_free(&key->userattr);
294d21b929eSagc 		}
29557324b9fSagc 		key->userattr = content->userattr;
29693bf6008Sagc 		key->last_seen = ATTRIBUTE;
297fc1f8641Sagc 		return PGP_KEEP_MEMORY;
29893bf6008Sagc 
299fc1f8641Sagc 	case PGP_PTAG_CT_SIGNATURE:	/* V3 sigs */
300fc1f8641Sagc 	case PGP_PTAG_CT_SIGNATURE_FOOTER:	/* V4 sigs */
301183e04ebSagc 		from = 0;
302fc1f8641Sagc 		signer = pgp_getkeybyid(io, key->keyring,
303183e04ebSagc 					 content->sig.info.signer_id,
30469d4f30fSagc 					 &from, &sigkey);
30593bf6008Sagc 		if (!signer) {
30683cfb9deSagc 			if (!add_sig_to_list(&content->sig.info,
30793bf6008Sagc 				&key->result->unknown_sigs,
30883cfb9deSagc 				&key->result->unknownc)) {
30983cfb9deSagc 					(void) fprintf(io->errs,
310fc1f8641Sagc 					"pgp_validate_key_cb: user attribute length 0");
311fc1f8641Sagc 					return PGP_FINISHED;
31283cfb9deSagc 			}
31393bf6008Sagc 			break;
31493bf6008Sagc 		}
31569d4f30fSagc 		if (sigkey == &signer->enckey) {
31669d4f30fSagc 			(void) fprintf(io->errs,
31769d4f30fSagc 				"WARNING: signature made with encryption key\n");
31869d4f30fSagc 		}
3193326c4c5Sagc 		switch (content->sig.info.type) {
320fc1f8641Sagc 		case PGP_CERT_GENERIC:
321fc1f8641Sagc 		case PGP_CERT_PERSONA:
322fc1f8641Sagc 		case PGP_CERT_CASUAL:
323fc1f8641Sagc 		case PGP_CERT_POSITIVE:
324fc1f8641Sagc 		case PGP_SIG_REV_CERT:
3250c310959Sagc 			valid = (key->last_seen == ID) ?
326fc1f8641Sagc 			    pgp_check_useridcert_sig(&key->pubkey,
327d427c17dSagc 					key->userid,
3283326c4c5Sagc 					&content->sig,
329fc1f8641Sagc 					pgp_get_pubkey(signer),
33057324b9fSagc 					key->reader->key->packets[
33157324b9fSagc 						key->reader->packet].raw) :
332fc1f8641Sagc 			    pgp_check_userattrcert_sig(&key->pubkey,
33357324b9fSagc 					&key->userattr,
3343326c4c5Sagc 					&content->sig,
335fc1f8641Sagc 				       pgp_get_pubkey(signer),
33657324b9fSagc 					key->reader->key->packets[
33757324b9fSagc 						key->reader->packet].raw);
33893bf6008Sagc 			break;
33993bf6008Sagc 
340fc1f8641Sagc 		case PGP_SIG_SUBKEY:
34193bf6008Sagc 			/*
34293bf6008Sagc 			 * XXX: we should also check that the signer is the
34393bf6008Sagc 			 * key we are validating, I think.
34493bf6008Sagc 			 */
345fc1f8641Sagc 			valid = pgp_check_subkey_sig(&key->pubkey,
34657324b9fSagc 				&key->subkey,
3473326c4c5Sagc 				&content->sig,
348fc1f8641Sagc 				pgp_get_pubkey(signer),
34957324b9fSagc 				key->reader->key->packets[
35057324b9fSagc 					key->reader->packet].raw);
35193bf6008Sagc 			break;
35293bf6008Sagc 
353fc1f8641Sagc 		case PGP_SIG_DIRECT:
354fc1f8641Sagc 			valid = pgp_check_direct_sig(&key->pubkey,
3550c310959Sagc 				&content->sig,
356fc1f8641Sagc 				pgp_get_pubkey(signer),
35757324b9fSagc 				key->reader->key->packets[
35857324b9fSagc 					key->reader->packet].raw);
35993bf6008Sagc 			break;
36093bf6008Sagc 
361fc1f8641Sagc 		case PGP_SIG_STANDALONE:
362fc1f8641Sagc 		case PGP_SIG_PRIMARY:
363fc1f8641Sagc 		case PGP_SIG_REV_KEY:
364fc1f8641Sagc 		case PGP_SIG_REV_SUBKEY:
365fc1f8641Sagc 		case PGP_SIG_TIMESTAMP:
366fc1f8641Sagc 		case PGP_SIG_3RD_PARTY:
367fc1f8641Sagc 			PGP_ERROR_1(errors, PGP_E_UNIMPLEMENTED,
368bcfd8565Sagc 				"Sig Verification type 0x%02x not done yet\n",
3693326c4c5Sagc 				content->sig.info.type);
37093bf6008Sagc 			break;
37193bf6008Sagc 
37293bf6008Sagc 		default:
373fc1f8641Sagc 			PGP_ERROR_1(errors, PGP_E_UNIMPLEMENTED,
374de704779Sagc 				    "Unexpected signature type 0x%02x\n",
3753326c4c5Sagc 				    	content->sig.info.type);
37693bf6008Sagc 		}
37793bf6008Sagc 
37893bf6008Sagc 		if (valid) {
37983cfb9deSagc 			if (!add_sig_to_list(&content->sig.info,
38093bf6008Sagc 				&key->result->valid_sigs,
38183cfb9deSagc 				&key->result->validc)) {
382*3dae3613Schristos 				PGP_ERROR_1(errors, PGP_E_UNIMPLEMENTED, "%s",
38383cfb9deSagc 				    "Can't add good sig to list\n");
38483cfb9deSagc 			}
38593bf6008Sagc 		} else {
386*3dae3613Schristos 			PGP_ERROR_1(errors, PGP_E_V_BAD_SIGNATURE, "%s",
387*3dae3613Schristos 			    "Bad Sig");
38883cfb9deSagc 			if (!add_sig_to_list(&content->sig.info,
38993bf6008Sagc 				&key->result->invalid_sigs,
39083cfb9deSagc 				&key->result->invalidc)) {
391*3dae3613Schristos 				PGP_ERROR_1(errors, PGP_E_UNIMPLEMENTED, "%s",
39283cfb9deSagc 				    "Can't add good sig to list\n");
39383cfb9deSagc 			}
39493bf6008Sagc 		}
39593bf6008Sagc 		break;
39693bf6008Sagc 
39793bf6008Sagc 		/* ignore these */
398fc1f8641Sagc 	case PGP_PARSER_PTAG:
399fc1f8641Sagc 	case PGP_PTAG_CT_SIGNATURE_HEADER:
400fc1f8641Sagc 	case PGP_PARSER_PACKET_END:
40193bf6008Sagc 		break;
40293bf6008Sagc 
403fc1f8641Sagc 	case PGP_GET_PASSPHRASE:
404f4badd9bSagc 		if (key->getpassphrase) {
405f4badd9bSagc 			return key->getpassphrase(pkt, cbinfo);
40693bf6008Sagc 		}
40793bf6008Sagc 		break;
40893bf6008Sagc 
409fc1f8641Sagc 	case PGP_PTAG_CT_TRUST:
410600b302bSagc 		/* 1 byte for level (depth), 1 byte for trust amount */
411600b302bSagc 		printf("trust dump\n");
412600b302bSagc 		printf("Got trust\n");
413b15ec256Sagc 		//hexdump(stdout, (const uint8_t *)content->trust.data, 10, " ");
414b15ec256Sagc 		//hexdump(stdout, (const uint8_t *)&content->ss_trust, 2, " ");
415600b302bSagc 		//printf("Trust level %d, amount %d\n", key->trust.level, key->trust.amount);
416600b302bSagc 		break;
417600b302bSagc 
41893bf6008Sagc 	default:
4193326c4c5Sagc 		(void) fprintf(stderr, "unexpected tag=0x%x\n", pkt->tag);
420fc1f8641Sagc 		return PGP_FINISHED;
42193bf6008Sagc 	}
422fc1f8641Sagc 	return PGP_RELEASE_MEMORY;
42393bf6008Sagc }
42493bf6008Sagc 
425fc1f8641Sagc pgp_cb_ret_t
validate_data_cb(const pgp_packet_t * pkt,pgp_cbdata_t * cbinfo)426fc1f8641Sagc validate_data_cb(const pgp_packet_t *pkt, pgp_cbdata_t *cbinfo)
42793bf6008Sagc {
428fc1f8641Sagc 	const pgp_contents_t	 *content = &pkt->u;
429fc1f8641Sagc 	const pgp_key_t	 *signer;
43057324b9fSagc 	validate_data_cb_t	 *data;
431fc1f8641Sagc 	pgp_pubkey_t		 *sigkey;
432fc1f8641Sagc 	pgp_error_t		**errors;
433fc1f8641Sagc 	pgp_io_t		 *io;
434183e04ebSagc 	unsigned		  from;
4354b3a3e18Sagc 	unsigned		  valid = 0;
43693bf6008Sagc 
437d21b929eSagc 	io = cbinfo->io;
438fc1f8641Sagc 	if (pgp_get_debug_level(__FILE__)) {
439d21b929eSagc 		(void) fprintf(io->errs, "validate_data_cb: %s\n",
440fc1f8641Sagc 				pgp_show_packet_tag(pkt->tag));
44193bf6008Sagc 	}
442fc1f8641Sagc 	data = pgp_callback_arg(cbinfo);
443fc1f8641Sagc 	errors = pgp_callback_errors(cbinfo);
4443326c4c5Sagc 	switch (pkt->tag) {
445fc1f8641Sagc 	case PGP_PTAG_CT_SIGNED_CLEARTEXT_HEADER:
44693bf6008Sagc 		/*
44793bf6008Sagc 		 * ignore - this gives us the "Armor Header" line "Hash:
44893bf6008Sagc 		 * SHA1" or similar
44993bf6008Sagc 		 */
45093bf6008Sagc 		break;
45193bf6008Sagc 
452fc1f8641Sagc 	case PGP_PTAG_CT_LITDATA_HEADER:
45393bf6008Sagc 		/* ignore */
45493bf6008Sagc 		break;
45593bf6008Sagc 
456fc1f8641Sagc 	case PGP_PTAG_CT_LITDATA_BODY:
4573326c4c5Sagc 		data->data.litdata_body = content->litdata_body;
45841335e2dSagc 		data->type = LITDATA;
459fc1f8641Sagc 		pgp_memory_add(data->mem, data->data.litdata_body.data,
4603326c4c5Sagc 				       data->data.litdata_body.length);
461fc1f8641Sagc 		return PGP_KEEP_MEMORY;
46293bf6008Sagc 
463fc1f8641Sagc 	case PGP_PTAG_CT_SIGNED_CLEARTEXT_BODY:
46457324b9fSagc 		data->data.cleartext_body = content->cleartext_body;
465d21b929eSagc 		data->type = SIGNED_CLEARTEXT;
466fc1f8641Sagc 		pgp_memory_add(data->mem, data->data.cleartext_body.data,
467d22b8667Sagc 			       data->data.cleartext_body.length);
468fc1f8641Sagc 		return PGP_KEEP_MEMORY;
46993bf6008Sagc 
470fc1f8641Sagc 	case PGP_PTAG_CT_SIGNED_CLEARTEXT_TRAILER:
471fc1f8641Sagc 		/* this gives us an pgp_hash_t struct */
47293bf6008Sagc 		break;
47393bf6008Sagc 
474fc1f8641Sagc 	case PGP_PTAG_CT_SIGNATURE:	/* V3 sigs */
475fc1f8641Sagc 	case PGP_PTAG_CT_SIGNATURE_FOOTER:	/* V4 sigs */
476fc1f8641Sagc 		if (pgp_get_debug_level(__FILE__)) {
47747561e26Sagc 			hexdump(io->outs, "hashed data", content->sig.info.v4_hashed,
47847561e26Sagc 					content->sig.info.v4_hashlen);
47947561e26Sagc 			hexdump(io->outs, "signer id", content->sig.info.signer_id,
48047561e26Sagc 				sizeof(content->sig.info.signer_id));
48193bf6008Sagc 		}
482183e04ebSagc 		from = 0;
483fc1f8641Sagc 		signer = pgp_getkeybyid(io, data->keyring,
48469d4f30fSagc 					 content->sig.info.signer_id, &from, &sigkey);
48593bf6008Sagc 		if (!signer) {
486*3dae3613Schristos 			PGP_ERROR_1(errors, PGP_E_V_UNKNOWN_SIGNER,
487*3dae3613Schristos 			    "%s", "Unknown Signer");
48883cfb9deSagc 			if (!add_sig_to_list(&content->sig.info,
48993bf6008Sagc 					&data->result->unknown_sigs,
49083cfb9deSagc 					&data->result->unknownc)) {
491*3dae3613Schristos 				PGP_ERROR_1(errors, PGP_E_V_UNKNOWN_SIGNER,
492*3dae3613Schristos 				    "%s", "Can't add unknown sig to list");
49383cfb9deSagc 			}
49493bf6008Sagc 			break;
49593bf6008Sagc 		}
49669d4f30fSagc 		if (sigkey == &signer->enckey) {
49769d4f30fSagc 			(void) fprintf(io->errs,
49869d4f30fSagc 				"WARNING: signature made with encryption key\n");
49969d4f30fSagc 		}
500600b302bSagc 		if (content->sig.info.birthtime_set) {
501600b302bSagc 			data->result->birthtime = content->sig.info.birthtime;
502600b302bSagc 		}
503600b302bSagc 		if (content->sig.info.duration_set) {
504600b302bSagc 			data->result->duration = content->sig.info.duration;
505600b302bSagc 		}
5063326c4c5Sagc 		switch (content->sig.info.type) {
507fc1f8641Sagc 		case PGP_SIG_BINARY:
508fc1f8641Sagc 		case PGP_SIG_TEXT:
509fc1f8641Sagc 			if (pgp_mem_len(data->mem) == 0 &&
510f4badd9bSagc 			    data->detachname) {
511f4badd9bSagc 				/* check we have seen some data */
512f4badd9bSagc 				/* if not, need to read from detached name */
5139b9aeb8dSagc 				(void) fprintf(io->errs,
514f4badd9bSagc 				"netpgp: assuming signed data in \"%s\"\n",
515f4badd9bSagc 					data->detachname);
516fc1f8641Sagc 				data->mem = pgp_memory_new();
517fc1f8641Sagc 				pgp_mem_readfile(data->mem, data->detachname);
518f4badd9bSagc 			}
519fc1f8641Sagc 			if (pgp_get_debug_level(__FILE__)) {
52047561e26Sagc 				hexdump(stderr, "sig dump", (const uint8_t *)(const void *)&content->sig,
52147561e26Sagc 					sizeof(content->sig));
522600b302bSagc 			}
523fc1f8641Sagc 			valid = check_binary_sig(pgp_mem_data(data->mem),
524fc1f8641Sagc 					(const unsigned)pgp_mem_len(data->mem),
5253326c4c5Sagc 					&content->sig,
526fc1f8641Sagc 					pgp_get_pubkey(signer));
52793bf6008Sagc 			break;
52893bf6008Sagc 
52993bf6008Sagc 		default:
530fc1f8641Sagc 			PGP_ERROR_1(errors, PGP_E_UNIMPLEMENTED,
531de704779Sagc 				    "No Sig Verification type 0x%02x yet\n",
5323326c4c5Sagc 				    content->sig.info.type);
53393bf6008Sagc 			break;
53493bf6008Sagc 
53593bf6008Sagc 		}
53693bf6008Sagc 
53793bf6008Sagc 		if (valid) {
53883cfb9deSagc 			if (!add_sig_to_list(&content->sig.info,
53993bf6008Sagc 					&data->result->valid_sigs,
54083cfb9deSagc 					&data->result->validc)) {
541*3dae3613Schristos 				PGP_ERROR_1(errors, PGP_E_V_BAD_SIGNATURE,
542*3dae3613Schristos 				    "%s", "Can't add good sig to list");
54383cfb9deSagc 			}
54493bf6008Sagc 		} else {
545*3dae3613Schristos 			PGP_ERROR_1(errors, PGP_E_V_BAD_SIGNATURE,
546*3dae3613Schristos 			    "%s", "Bad Signature");
54783cfb9deSagc 			if (!add_sig_to_list(&content->sig.info,
54893bf6008Sagc 					&data->result->invalid_sigs,
54983cfb9deSagc 					&data->result->invalidc)) {
550*3dae3613Schristos 				PGP_ERROR_1(errors, PGP_E_V_BAD_SIGNATURE, "%s",
55183cfb9deSagc 					"Can't add good sig to list");
55283cfb9deSagc 			}
55393bf6008Sagc 		}
55493bf6008Sagc 		break;
55593bf6008Sagc 
55693bf6008Sagc 		/* ignore these */
557fc1f8641Sagc 	case PGP_PARSER_PTAG:
558fc1f8641Sagc 	case PGP_PTAG_CT_SIGNATURE_HEADER:
559fc1f8641Sagc 	case PGP_PTAG_CT_ARMOUR_HEADER:
560fc1f8641Sagc 	case PGP_PTAG_CT_ARMOUR_TRAILER:
561fc1f8641Sagc 	case PGP_PTAG_CT_1_PASS_SIG:
56257324b9fSagc 		break;
56357324b9fSagc 
564fc1f8641Sagc 	case PGP_PARSER_PACKET_END:
56593bf6008Sagc 		break;
56693bf6008Sagc 
56793bf6008Sagc 	default:
568*3dae3613Schristos 		PGP_ERROR_1(errors, PGP_E_V_NO_SIGNATURE, "%s", "No signature");
56993bf6008Sagc 		break;
57093bf6008Sagc 	}
571fc1f8641Sagc 	return PGP_RELEASE_MEMORY;
57293bf6008Sagc }
57393bf6008Sagc 
57493bf6008Sagc static void
keydata_destroyer(pgp_reader_t * readinfo)575fc1f8641Sagc keydata_destroyer(pgp_reader_t *readinfo)
57693bf6008Sagc {
577fc1f8641Sagc 	free(pgp_reader_get_arg(readinfo));
57893bf6008Sagc }
57993bf6008Sagc 
58093bf6008Sagc void
pgp_keydata_reader_set(pgp_stream_t * stream,const pgp_key_t * key)581fc1f8641Sagc pgp_keydata_reader_set(pgp_stream_t *stream, const pgp_key_t *key)
58293bf6008Sagc {
58383cfb9deSagc 	validate_reader_t *data;
58493bf6008Sagc 
58583cfb9deSagc 	if ((data = calloc(1, sizeof(*data))) == NULL) {
586fc1f8641Sagc 		(void) fprintf(stderr, "pgp_keydata_reader_set: bad alloc\n");
58783cfb9deSagc 	} else {
58893bf6008Sagc 		data->key = key;
58993bf6008Sagc 		data->packet = 0;
59093bf6008Sagc 		data->offset = 0;
591fc1f8641Sagc 		pgp_reader_set(stream, keydata_reader, keydata_destroyer, data);
59293bf6008Sagc 	}
59383cfb9deSagc }
59493bf6008Sagc 
595600b302bSagc static char *
fmtsecs(int64_t n,char * buf,size_t size)596600b302bSagc fmtsecs(int64_t n, char *buf, size_t size)
597600b302bSagc {
598600b302bSagc 	if (n > 365 * 24 * 60 * 60) {
5990aa60872Sagc 		n /= (365 * 24 * 60 * 60);
6000aa60872Sagc 		(void) snprintf(buf, size, "%" PRId64 " year%s", n, (n == 1) ? "" : "s");
601600b302bSagc 		return buf;
602600b302bSagc 	}
603600b302bSagc 	if (n > 30 * 24 * 60 * 60) {
6040aa60872Sagc 		n /= (30 * 24 * 60 * 60);
6050aa60872Sagc 		(void) snprintf(buf, size, "%" PRId64 " month%s", n, (n == 1) ? "" : "s");
606600b302bSagc 		return buf;
607600b302bSagc 	}
608600b302bSagc 	if (n > 24 * 60 * 60) {
6090aa60872Sagc 		n /= (24 * 60 * 60);
6100aa60872Sagc 		(void) snprintf(buf, size, "%" PRId64 " day%s", n, (n == 1) ? "" : "s");
611600b302bSagc 		return buf;
612600b302bSagc 	}
613600b302bSagc 	if (n > 60 * 60) {
6140aa60872Sagc 		n /= (60 * 60);
6150aa60872Sagc 		(void) snprintf(buf, size, "%" PRId64 " hour%s", n, (n == 1) ? "" : "s");
616600b302bSagc 		return buf;
617600b302bSagc 	}
618600b302bSagc 	if (n > 60) {
6190aa60872Sagc 		n /= 60;
6200aa60872Sagc 		(void) snprintf(buf, size, "%" PRId64 " minute%s", n, (n == 1) ? "" : "s");
621600b302bSagc 		return buf;
622600b302bSagc 	}
6230aa60872Sagc 	(void) snprintf(buf, size, "%" PRId64 " second%s", n, (n == 1) ? "" : "s");
624600b302bSagc 	return buf;
625600b302bSagc }
626600b302bSagc 
62793bf6008Sagc /**
62893bf6008Sagc  * \ingroup HighLevel_Verify
62993bf6008Sagc  * \brief Indicicates whether any errors were found
63093bf6008Sagc  * \param result Validation result to check
6314b3a3e18Sagc  * \return 0 if any invalid signatures or unknown signers
6324b3a3e18Sagc  	or no valid signatures; else 1
63393bf6008Sagc  */
6344b3a3e18Sagc static unsigned
validate_result_status(FILE * errs,const char * f,pgp_validation_t * val)635fc1f8641Sagc validate_result_status(FILE *errs, const char *f, pgp_validation_t *val)
63693bf6008Sagc {
637600b302bSagc 	time_t	now;
638600b302bSagc 	time_t	t;
639600b302bSagc 	char	buf[128];
640600b302bSagc 
641600b302bSagc 	now = time(NULL);
642600b302bSagc 	if (now < val->birthtime) {
643600b302bSagc 		/* signature is not valid yet! */
6442b48e3a6Sagc 		if (f) {
6452b48e3a6Sagc 			(void) fprintf(errs, "\"%s\": ", f);
6462b48e3a6Sagc 		} else {
6472b48e3a6Sagc 			(void) fprintf(errs, "memory ");
6482b48e3a6Sagc 		}
649600b302bSagc 		(void) fprintf(errs,
650600b302bSagc 			"signature not valid until %.24s (%s)\n",
651600b302bSagc 			ctime(&val->birthtime),
652600b302bSagc 			fmtsecs((int64_t)(val->birthtime - now), buf, sizeof(buf)));
653600b302bSagc 		return 0;
654600b302bSagc 	}
655600b302bSagc 	if (val->duration != 0 && now > val->birthtime + val->duration) {
656600b302bSagc 		/* signature has expired */
657600b302bSagc 		t = val->duration + val->birthtime;
6582b48e3a6Sagc 		if (f) {
6592b48e3a6Sagc 			(void) fprintf(errs, "\"%s\": ", f);
6602b48e3a6Sagc 		} else {
6612b48e3a6Sagc 			(void) fprintf(errs, "memory ");
6622b48e3a6Sagc 		}
663600b302bSagc 		(void) fprintf(errs,
664600b302bSagc 			"signature not valid after %.24s (%s ago)\n",
665600b302bSagc 			ctime(&t),
666600b302bSagc 			fmtsecs((int64_t)(now - t), buf, sizeof(buf)));
667600b302bSagc 		return 0;
668600b302bSagc 	}
66993bf6008Sagc 	return val->validc && !val->invalidc && !val->unknownc;
67093bf6008Sagc }
67193bf6008Sagc 
67293bf6008Sagc /**
67393bf6008Sagc  * \ingroup HighLevel_Verify
67493bf6008Sagc  * \brief Validate all signatures on a single key against the given keyring
67593bf6008Sagc  * \param result Where to put the result
67693bf6008Sagc  * \param key Key to validate
67793bf6008Sagc  * \param keyring Keyring to use for validation
67893bf6008Sagc  * \param cb_get_passphrase Callback to use to get passphrase
6794b3a3e18Sagc  * \return 1 if all signatures OK; else 0
68093bf6008Sagc  * \note It is the caller's responsiblity to free result after use.
681fc1f8641Sagc  * \sa pgp_validate_result_free()
68293bf6008Sagc  */
6834b3a3e18Sagc unsigned
pgp_validate_key_sigs(pgp_validation_t * result,const pgp_key_t * key,const pgp_keyring_t * keyring,pgp_cb_ret_t cb_get_passphrase (const pgp_packet_t *,pgp_cbdata_t *))684fc1f8641Sagc pgp_validate_key_sigs(pgp_validation_t *result,
685fc1f8641Sagc 	const pgp_key_t *key,
686fc1f8641Sagc 	const pgp_keyring_t *keyring,
687fc1f8641Sagc 	pgp_cb_ret_t cb_get_passphrase(const pgp_packet_t *,
688fc1f8641Sagc 						pgp_cbdata_t *))
68993bf6008Sagc {
690fc1f8641Sagc 	pgp_stream_t	*stream;
69157324b9fSagc 	validate_key_cb_t	 keysigs;
692393ecd92Sagc 	const int		 printerrors = 1;
69393bf6008Sagc 
69457324b9fSagc 	(void) memset(&keysigs, 0x0, sizeof(keysigs));
69557324b9fSagc 	keysigs.result = result;
696f4badd9bSagc 	keysigs.getpassphrase = cb_get_passphrase;
69793bf6008Sagc 
698fc1f8641Sagc 	stream = pgp_new(sizeof(*stream));
699fc1f8641Sagc 	/* pgp_parse_options(&opt,PGP_PTAG_CT_SIGNATURE,PGP_PARSE_PARSED); */
70093bf6008Sagc 
70157324b9fSagc 	keysigs.keyring = keyring;
70293bf6008Sagc 
703fc1f8641Sagc 	pgp_set_callback(stream, pgp_validate_key_cb, &keysigs);
70441335e2dSagc 	stream->readinfo.accumulate = 1;
705fc1f8641Sagc 	pgp_keydata_reader_set(stream, key);
70693bf6008Sagc 
70757324b9fSagc 	/* Note: Coverity incorrectly reports an error that keysigs.reader */
70893bf6008Sagc 	/* is never used. */
70941335e2dSagc 	keysigs.reader = stream->readinfo.arg;
71093bf6008Sagc 
711fc1f8641Sagc 	pgp_parse(stream, !printerrors);
71293bf6008Sagc 
713fc1f8641Sagc 	pgp_pubkey_free(&keysigs.pubkey);
71457324b9fSagc 	if (keysigs.subkey.version) {
715fc1f8641Sagc 		pgp_pubkey_free(&keysigs.subkey);
7160c310959Sagc 	}
717fc1f8641Sagc 	pgp_userid_free(&keysigs.userid);
718fc1f8641Sagc 	pgp_data_free(&keysigs.userattr);
71993bf6008Sagc 
720fc1f8641Sagc 	pgp_stream_delete(stream);
72193bf6008Sagc 
7220c310959Sagc 	return (!result->invalidc && !result->unknownc && result->validc);
72393bf6008Sagc }
72493bf6008Sagc 
72593bf6008Sagc /**
72693bf6008Sagc    \ingroup HighLevel_Verify
72793bf6008Sagc    \param result Where to put the result
72893bf6008Sagc    \param ring Keyring to use
72993bf6008Sagc    \param cb_get_passphrase Callback to use to get passphrase
73093bf6008Sagc    \note It is the caller's responsibility to free result after use.
731fc1f8641Sagc    \sa pgp_validate_result_free()
73293bf6008Sagc */
7334b3a3e18Sagc unsigned
pgp_validate_all_sigs(pgp_validation_t * result,const pgp_keyring_t * ring,pgp_cb_ret_t cb_get_passphrase (const pgp_packet_t *,pgp_cbdata_t *))734fc1f8641Sagc pgp_validate_all_sigs(pgp_validation_t *result,
735fc1f8641Sagc 	    const pgp_keyring_t *ring,
736fc1f8641Sagc 	    pgp_cb_ret_t cb_get_passphrase(const pgp_packet_t *,
737fc1f8641Sagc 	    					pgp_cbdata_t *))
73893bf6008Sagc {
73941335e2dSagc 	unsigned	n;
74093bf6008Sagc 
74193bf6008Sagc 	(void) memset(result, 0x0, sizeof(*result));
74241335e2dSagc 	for (n = 0; n < ring->keyc; ++n) {
743fc1f8641Sagc 		pgp_validate_key_sigs(result, &ring->keys[n], ring,
744de704779Sagc 				cb_get_passphrase);
745de704779Sagc 	}
7462b48e3a6Sagc 	return validate_result_status(stderr, "keyring", result);
74793bf6008Sagc }
74893bf6008Sagc 
74993bf6008Sagc /**
75093bf6008Sagc    \ingroup HighLevel_Verify
75193bf6008Sagc    \brief Frees validation result and associated memory
75293bf6008Sagc    \param result Struct to be freed
75393bf6008Sagc    \note Must be called after validation functions
75493bf6008Sagc */
75593bf6008Sagc void
pgp_validate_result_free(pgp_validation_t * result)756fc1f8641Sagc pgp_validate_result_free(pgp_validation_t *result)
75793bf6008Sagc {
758de704779Sagc 	if (result != NULL) {
759de704779Sagc 		if (result->valid_sigs) {
7603326c4c5Sagc 			free_sig_info(result->valid_sigs);
761de704779Sagc 		}
762de704779Sagc 		if (result->invalid_sigs) {
7633326c4c5Sagc 			free_sig_info(result->invalid_sigs);
764de704779Sagc 		}
765de704779Sagc 		if (result->unknown_sigs) {
7663326c4c5Sagc 			free_sig_info(result->unknown_sigs);
767de704779Sagc 		}
76883cfb9deSagc 		free(result);
76983cfb9deSagc 		/* result = NULL; - XXX unnecessary */
77093bf6008Sagc 	}
771de704779Sagc }
77293bf6008Sagc 
77393bf6008Sagc /**
77493bf6008Sagc    \ingroup HighLevel_Verify
77593bf6008Sagc    \brief Verifies the signatures in a signed file
77693bf6008Sagc    \param result Where to put the result
77793bf6008Sagc    \param filename Name of file to be validated
77893bf6008Sagc    \param armoured Treat file as armoured, if set
77993bf6008Sagc    \param keyring Keyring to use
7804b3a3e18Sagc    \return 1 if signatures validate successfully;
7814b3a3e18Sagc    	0 if signatures fail or there are no signatures
78293bf6008Sagc    \note After verification, result holds the details of all keys which
78393bf6008Sagc    have passed, failed and not been recognised.
784de704779Sagc    \note It is the caller's responsiblity to call
785fc1f8641Sagc    	pgp_validate_result_free(result) after use.
78693bf6008Sagc */
7874b3a3e18Sagc unsigned
pgp_validate_file(pgp_io_t * io,pgp_validation_t * result,const char * infile,const char * outfile,const int user_says_armoured,const pgp_keyring_t * keyring)788fc1f8641Sagc pgp_validate_file(pgp_io_t *io,
789fc1f8641Sagc 			pgp_validation_t *result,
7902232f800Sagc 			const char *infile,
7912232f800Sagc 			const char *outfile,
792b15ec256Sagc 			const int user_says_armoured,
793fc1f8641Sagc 			const pgp_keyring_t *keyring)
79493bf6008Sagc {
79593bf6008Sagc 	validate_data_cb_t	 validation;
796fc1f8641Sagc 	pgp_stream_t		*parse = NULL;
797bcfd8565Sagc 	struct stat		 st;
7983644eb84Sagc 	const char		*signame;
799393ecd92Sagc 	const int		 printerrors = 1;
800648b5a99Sagc 	unsigned		 ret;
8013644eb84Sagc 	char			 f[MAXPATHLEN];
8023644eb84Sagc 	char			*dataname;
803632dc3acSagc 	int			 realarmour;
80457324b9fSagc 	int			 outfd = 0;
80557324b9fSagc 	int			 infd;
806bcfd8565Sagc 	int			 cc;
807bcfd8565Sagc 
8082232f800Sagc 	if (stat(infile, &st) < 0) {
809026af9faSagc 		(void) fprintf(io->errs,
810fc1f8641Sagc 			"pgp_validate_file: can't open '%s'\n", infile);
8114b3a3e18Sagc 		return 0;
812bcfd8565Sagc 	}
8133644eb84Sagc 	realarmour = user_says_armoured;
8143644eb84Sagc 	dataname = NULL;
8153644eb84Sagc 	signame = NULL;
8163644eb84Sagc 	cc = snprintf(f, sizeof(f), "%s", infile);
817026af9faSagc 	if (strcmp(&f[cc - 4], ".sig") == 0) {
8183644eb84Sagc 		/* we've been given a sigfile as infile */
8193644eb84Sagc 		f[cc - 4] = 0x0;
8203644eb84Sagc 		/* set dataname to name of file which was signed */
8213644eb84Sagc 		dataname = f;
8223644eb84Sagc 		signame = infile;
823026af9faSagc 	} else if (strcmp(&f[cc - 4], ".asc") == 0) {
824026af9faSagc 		/* we've been given an armored sigfile as infile */
825026af9faSagc 		f[cc - 4] = 0x0;
826026af9faSagc 		/* set dataname to name of file which was signed */
827026af9faSagc 		dataname = f;
828026af9faSagc 		signame = infile;
829632dc3acSagc 		realarmour = 1;
8303644eb84Sagc 	} else {
8313644eb84Sagc 		signame = infile;
832632dc3acSagc 	}
83357324b9fSagc 	(void) memset(&validation, 0x0, sizeof(validation));
834fc1f8641Sagc 	infd = pgp_setup_file_read(io, &parse, signame, &validation,
8354b3a3e18Sagc 				validate_data_cb, 1);
83657324b9fSagc 	if (infd < 0) {
8374b3a3e18Sagc 		return 0;
838de704779Sagc 	}
83993bf6008Sagc 
8403644eb84Sagc 	if (dataname) {
8413644eb84Sagc 		validation.detachname = netpgp_strdup(dataname);
8423644eb84Sagc 	}
84357324b9fSagc 
84493bf6008Sagc 	/* Set verification reader and handling options */
84593bf6008Sagc 	validation.result = result;
84693bf6008Sagc 	validation.keyring = keyring;
847fc1f8641Sagc 	validation.mem = pgp_memory_new();
848fc1f8641Sagc 	pgp_memory_init(validation.mem, 128);
84957324b9fSagc 	/* Note: Coverity incorrectly reports an error that validation.reader */
85093bf6008Sagc 	/* is never used. */
85157324b9fSagc 	validation.reader = parse->readinfo.arg;
85293bf6008Sagc 
853632dc3acSagc 	if (realarmour) {
854fc1f8641Sagc 		pgp_reader_push_dearmour(parse);
855de704779Sagc 	}
85693bf6008Sagc 
85793bf6008Sagc 	/* Do the verification */
858fc1f8641Sagc 	pgp_parse(parse, !printerrors);
859bcfd8565Sagc 
86093bf6008Sagc 	/* Tidy up */
861632dc3acSagc 	if (realarmour) {
862fc1f8641Sagc 		pgp_reader_pop_dearmour(parse);
863de704779Sagc 	}
864fc1f8641Sagc 	pgp_teardown_file_read(parse, infd);
86593bf6008Sagc 
8662b48e3a6Sagc 	ret = validate_result_status(io->errs, infile, result);
867648b5a99Sagc 
868648b5a99Sagc 	/* this is triggered only for --cat output */
869648b5a99Sagc 	if (outfile) {
870648b5a99Sagc 		/* need to send validated output somewhere */
871648b5a99Sagc 		if (strcmp(outfile, "-") == 0) {
872648b5a99Sagc 			outfd = STDOUT_FILENO;
873648b5a99Sagc 		} else {
874648b5a99Sagc 			outfd = open(outfile, O_WRONLY | O_CREAT, 0666);
875648b5a99Sagc 		}
876648b5a99Sagc 		if (outfd < 0) {
877648b5a99Sagc 			/* even if the signature was good, we can't
878648b5a99Sagc 			* write the file, so send back a bad return
879648b5a99Sagc 			* code */
880648b5a99Sagc 			ret = 0;
8812b48e3a6Sagc 		} else if (validate_result_status(io->errs, infile, result)) {
882648b5a99Sagc 			unsigned	 len;
883648b5a99Sagc 			char		*cp;
884648b5a99Sagc 			int		 i;
885648b5a99Sagc 
886fc1f8641Sagc 			len = (unsigned)pgp_mem_len(validation.mem);
887fc1f8641Sagc 			cp = pgp_mem_data(validation.mem);
888648b5a99Sagc 			for (i = 0 ; i < (int)len ; i += cc) {
889593d671cSagc 				cc = (int)write(outfd, &cp[i], (unsigned)(len - i));
890648b5a99Sagc 				if (cc < 0) {
891d21b929eSagc 					(void) fprintf(io->errs,
892648b5a99Sagc 						"netpgp: short write\n");
893648b5a99Sagc 					ret = 0;
894648b5a99Sagc 					break;
895648b5a99Sagc 				}
896648b5a99Sagc 			}
897648b5a99Sagc 			if (strcmp(outfile, "-") != 0) {
898648b5a99Sagc 				(void) close(outfd);
899648b5a99Sagc 			}
900648b5a99Sagc 		}
901648b5a99Sagc 	}
902fc1f8641Sagc 	pgp_memory_free(validation.mem);
903648b5a99Sagc 	return ret;
90493bf6008Sagc }
90593bf6008Sagc 
90693bf6008Sagc /**
90793bf6008Sagc    \ingroup HighLevel_Verify
908fc1f8641Sagc    \brief Verifies the signatures in a pgp_memory_t struct
90993bf6008Sagc    \param result Where to put the result
91093bf6008Sagc    \param mem Memory to be validated
911b15ec256Sagc    \param user_says_armoured Treat data as armoured, if set
91293bf6008Sagc    \param keyring Keyring to use
9134b3a3e18Sagc    \return 1 if signature validates successfully; 0 if not
91493bf6008Sagc    \note After verification, result holds the details of all keys which
91593bf6008Sagc    have passed, failed and not been recognised.
916de704779Sagc    \note It is the caller's responsiblity to call
917fc1f8641Sagc    	pgp_validate_result_free(result) after use.
91893bf6008Sagc */
91993bf6008Sagc 
9204b3a3e18Sagc unsigned
pgp_validate_mem(pgp_io_t * io,pgp_validation_t * result,pgp_memory_t * mem,pgp_memory_t ** cat,const int user_says_armoured,const pgp_keyring_t * keyring)921fc1f8641Sagc pgp_validate_mem(pgp_io_t *io,
922fc1f8641Sagc 			pgp_validation_t *result,
923fc1f8641Sagc 			pgp_memory_t *mem,
924fc1f8641Sagc 			pgp_memory_t **cat,
925b15ec256Sagc 			const int user_says_armoured,
926fc1f8641Sagc 			const pgp_keyring_t *keyring)
92793bf6008Sagc {
92893bf6008Sagc 	validate_data_cb_t	 validation;
929fc1f8641Sagc 	pgp_stream_t		*stream = NULL;
930393ecd92Sagc 	const int		 printerrors = 1;
931b15ec256Sagc 	int			 realarmour;
93293bf6008Sagc 
933fc1f8641Sagc 	pgp_setup_memory_read(io, &stream, mem, &validation, validate_data_cb, 1);
93493bf6008Sagc 	/* Set verification reader and handling options */
93593bf6008Sagc 	(void) memset(&validation, 0x0, sizeof(validation));
93693bf6008Sagc 	validation.result = result;
93793bf6008Sagc 	validation.keyring = keyring;
938fc1f8641Sagc 	validation.mem = pgp_memory_new();
939fc1f8641Sagc 	pgp_memory_init(validation.mem, 128);
94057324b9fSagc 	/* Note: Coverity incorrectly reports an error that validation.reader */
94193bf6008Sagc 	/* is never used. */
94241335e2dSagc 	validation.reader = stream->readinfo.arg;
94393bf6008Sagc 
944b15ec256Sagc 	if ((realarmour = user_says_armoured) != 0 ||
945fc1f8641Sagc 	    strncmp(pgp_mem_data(mem),
946b15ec256Sagc 	    		"-----BEGIN PGP MESSAGE-----", 27) == 0) {
947b15ec256Sagc 		realarmour = 1;
948b15ec256Sagc 	}
949b15ec256Sagc 	if (realarmour) {
950fc1f8641Sagc 		pgp_reader_push_dearmour(stream);
951de704779Sagc 	}
95293bf6008Sagc 
95393bf6008Sagc 	/* Do the verification */
954fc1f8641Sagc 	pgp_parse(stream, !printerrors);
955de704779Sagc 
95693bf6008Sagc 	/* Tidy up */
957b15ec256Sagc 	if (realarmour) {
958fc1f8641Sagc 		pgp_reader_pop_dearmour(stream);
959de704779Sagc 	}
960fc1f8641Sagc 	pgp_teardown_memory_read(stream, mem);
961d369874eSagc 
962d369874eSagc 	/* this is triggered only for --cat output */
963156f1405Sagc 	if (cat) {
964d369874eSagc 		/* need to send validated output somewhere */
965d369874eSagc 		*cat = validation.mem;
966d369874eSagc 	} else {
967fc1f8641Sagc 		pgp_memory_free(validation.mem);
968d369874eSagc 	}
96993bf6008Sagc 
9702b48e3a6Sagc 	return validate_result_status(io->errs, NULL, result);
97193bf6008Sagc }
972