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