xref: /netbsd-src/crypto/external/bsd/netpgp/dist/src/lib/validate.c (revision 3816d47b2c42fcd6e549e3407f842a5b1a1d23ad)
1 /*-
2  * Copyright (c) 2009 The NetBSD Foundation, Inc.
3  * All rights reserved.
4  *
5  * This code is derived from software contributed to The NetBSD Foundation
6  * by Alistair Crooks (agc@NetBSD.org)
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
18  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
21  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  */
29 /*
30  * Copyright (c) 2005-2008 Nominet UK (www.nic.uk)
31  * All rights reserved.
32  * Contributors: Ben Laurie, Rachel Willmer. The Contributors have asserted
33  * their moral rights under the UK Copyright Design and Patents Act 1988 to
34  * be recorded as the authors of this copyright work.
35  *
36  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
37  * use this file except in compliance with the License.
38  *
39  * You may obtain a copy of the License at
40  *     http://www.apache.org/licenses/LICENSE-2.0
41  *
42  * Unless required by applicable law or agreed to in writing, software
43  * distributed under the License is distributed on an "AS IS" BASIS,
44  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
45  *
46  * See the License for the specific language governing permissions and
47  * limitations under the License.
48  */
49 #include "config.h"
50 
51 #ifdef HAVE_SYS_CDEFS_H
52 #include <sys/cdefs.h>
53 #endif
54 
55 #if defined(__NetBSD__)
56 __COPYRIGHT("@(#) Copyright (c) 2009 The NetBSD Foundation, Inc. All rights reserved.");
57 __RCSID("$NetBSD: validate.c,v 1.25 2009/12/22 06:03:25 agc Exp $");
58 #endif
59 
60 #include <sys/types.h>
61 #include <sys/param.h>
62 #include <sys/stat.h>
63 
64 #include <string.h>
65 #include <stdio.h>
66 
67 #ifdef HAVE_UNISTD_H
68 #include <unistd.h>
69 #endif
70 
71 #ifdef HAVE_FCNTL_H
72 #include <fcntl.h>
73 #endif
74 
75 #include "packet-parse.h"
76 #include "packet-show.h"
77 #include "keyring.h"
78 #include "signature.h"
79 #include "netpgpsdk.h"
80 #include "readerwriter.h"
81 #include "netpgpdefs.h"
82 #include "memory.h"
83 #include "packet.h"
84 #include "crypto.h"
85 #include "validate.h"
86 
87 #ifdef HAVE_FCNTL_H
88 #include <fcntl.h>
89 #endif
90 
91 
92 /* Does the signed hash match the given hash? */
93 static unsigned
94 check_binary_sig(const unsigned char *data,
95 		const unsigned len,
96 		const __ops_sig_t *sig,
97 		const __ops_pubkey_t *signer)
98 {
99 	unsigned char   hashout[OPS_MAX_HASH_SIZE];
100 	unsigned char   trailer[6];
101 	unsigned int    hashedlen;
102 	__ops_hash_t	hash;
103 	unsigned	n;
104 
105 	__OPS_USED(signer);
106 	__ops_hash_any(&hash, sig->info.hash_alg);
107 	if (!hash.init(&hash)) {
108 		(void) fprintf(stderr, "check_binary_sig: bad hash init\n");
109 		return 0;
110 	}
111 	hash.add(&hash, data, len);
112 	switch (sig->info.version) {
113 	case OPS_V3:
114 		trailer[0] = sig->info.type;
115 		trailer[1] = (unsigned)(sig->info.birthtime) >> 24;
116 		trailer[2] = (unsigned)(sig->info.birthtime) >> 16;
117 		trailer[3] = (unsigned)(sig->info.birthtime) >> 8;
118 		trailer[4] = (unsigned char)(sig->info.birthtime);
119 		hash.add(&hash, trailer, 5);
120 		break;
121 
122 	case OPS_V4:
123 		hash.add(&hash, sig->info.v4_hashed, sig->info.v4_hashlen);
124 		trailer[0] = 0x04;	/* version */
125 		trailer[1] = 0xFF;
126 		hashedlen = sig->info.v4_hashlen;
127 		trailer[2] = hashedlen >> 24;
128 		trailer[3] = hashedlen >> 16;
129 		trailer[4] = hashedlen >> 8;
130 		trailer[5] = hashedlen;
131 		hash.add(&hash, trailer, 6);
132 		break;
133 
134 	default:
135 		(void) fprintf(stderr, "Invalid signature version %d\n",
136 				sig->info.version);
137 		return 0;
138 	}
139 
140 	n = hash.finish(&hash, hashout);
141 	if (__ops_get_debug_level(__FILE__)) {
142 		printf("check_binary_sig: hash length %" PRIsize "u\n",
143 			hash.size);
144 	}
145 	return __ops_check_sig(hashout, n, sig, signer);
146 }
147 
148 static int
149 keydata_reader(void *dest, size_t length, __ops_error_t **errors,
150 	       __ops_reader_t *readinfo,
151 	       __ops_cbdata_t *cbinfo)
152 {
153 	validate_reader_t *reader = __ops_reader_get_arg(readinfo);
154 
155 	__OPS_USED(errors);
156 	__OPS_USED(cbinfo);
157 	if (reader->offset == reader->key->packets[reader->packet].length) {
158 		reader->packet += 1;
159 		reader->offset = 0;
160 	}
161 	if (reader->packet == reader->key->packetc) {
162 		return 0;
163 	}
164 
165 	/*
166 	 * we should never be asked to cross a packet boundary in a single
167 	 * read
168 	 */
169 	if (reader->key->packets[reader->packet].length <
170 			reader->offset + length) {
171 		(void) fprintf(stderr, "keydata_reader: weird length\n");
172 		return 0;
173 	}
174 
175 	(void) memcpy(dest,
176 		&reader->key->packets[reader->packet].raw[reader->offset],
177 		length);
178 	reader->offset += length;
179 
180 	return length;
181 }
182 
183 static void
184 free_sig_info(__ops_sig_info_t *sig)
185 {
186 	free(sig->v4_hashed);
187 	free(sig);
188 }
189 
190 static void
191 copy_sig_info(__ops_sig_info_t *dst, const __ops_sig_info_t *src)
192 {
193 	(void) memcpy(dst, src, sizeof(*src));
194 	if ((dst->v4_hashed = calloc(1, src->v4_hashlen)) == NULL) {
195 		(void) fprintf(stderr, "copy_sig_info: bad alloc\n");
196 	} else {
197 		(void) memcpy(dst->v4_hashed, src->v4_hashed, src->v4_hashlen);
198 	}
199 }
200 
201 static int
202 add_sig_to_list(const __ops_sig_info_t *sig, __ops_sig_info_t **sigs,
203 			unsigned *count)
204 {
205 	__ops_sig_info_t	*newsigs;
206 
207 	if (*count == 0) {
208 		newsigs = calloc(*count + 1, sizeof(__ops_sig_info_t));
209 	} else {
210 		newsigs = realloc(*sigs,
211 				(*count + 1) * sizeof(__ops_sig_info_t));
212 	}
213 	if (newsigs != NULL) {
214 		*sigs = newsigs;
215 		copy_sig_info(&(*sigs)[*count], sig);
216 		*count += 1;
217 		return 1;
218 	}
219 	return 0;
220 }
221 
222 
223 __ops_cb_ret_t
224 __ops_validate_key_cb(const __ops_packet_t *pkt, __ops_cbdata_t *cbinfo)
225 {
226 	const __ops_contents_t	 *content = &pkt->u;
227 	const __ops_key_t	 *signer;
228 	validate_key_cb_t	 *key;
229 	__ops_error_t		**errors;
230 	__ops_io_t		 *io;
231 	unsigned		  from;
232 	unsigned		  valid = 0;
233 
234 	io = cbinfo->io;
235 	if (__ops_get_debug_level(__FILE__)) {
236 		(void) fprintf(io->errs, "%s\n",
237 				__ops_show_packet_tag(pkt->tag));
238 	}
239 	key = __ops_callback_arg(cbinfo);
240 	errors = __ops_callback_errors(cbinfo);
241 	switch (pkt->tag) {
242 	case OPS_PTAG_CT_PUBLIC_KEY:
243 		if (key->pubkey.version != 0) {
244 			(void) fprintf(io->errs,
245 				"__ops_validate_key_cb: version bad\n");
246 			return OPS_FINISHED;
247 		}
248 		key->pubkey = content->pubkey;
249 		return OPS_KEEP_MEMORY;
250 
251 	case OPS_PTAG_CT_PUBLIC_SUBKEY:
252 		if (key->subkey.version) {
253 			__ops_pubkey_free(&key->subkey);
254 		}
255 		key->subkey = content->pubkey;
256 		return OPS_KEEP_MEMORY;
257 
258 	case OPS_PTAG_CT_SECRET_KEY:
259 		key->seckey = content->seckey;
260 		key->pubkey = key->seckey.pubkey;
261 		return OPS_KEEP_MEMORY;
262 
263 	case OPS_PTAG_CT_USER_ID:
264 		if (key->userid.userid) {
265 			__ops_userid_free(&key->userid);
266 		}
267 		key->userid = content->userid;
268 		key->last_seen = ID;
269 		return OPS_KEEP_MEMORY;
270 
271 	case OPS_PTAG_CT_USER_ATTR:
272 		if (content->userattr.data.len == 0) {
273 			(void) fprintf(io->errs,
274 			"__ops_validate_key_cb: user attribute length 0");
275 			return OPS_FINISHED;
276 		}
277 		(void) fprintf(io->outs, "user attribute, length=%d\n",
278 			(int) content->userattr.data.len);
279 		if (key->userattr.data.len) {
280 			__ops_userattr_free(&key->userattr);
281 		}
282 		key->userattr = content->userattr;
283 		key->last_seen = ATTRIBUTE;
284 		return OPS_KEEP_MEMORY;
285 
286 	case OPS_PTAG_CT_SIGNATURE:	/* V3 sigs */
287 	case OPS_PTAG_CT_SIGNATURE_FOOTER:	/* V4 sigs */
288 		from = 0;
289 		signer = __ops_getkeybyid(io, key->keyring,
290 					 content->sig.info.signer_id,
291 					 &from);
292 		if (!signer) {
293 			if (!add_sig_to_list(&content->sig.info,
294 				&key->result->unknown_sigs,
295 				&key->result->unknownc)) {
296 					(void) fprintf(io->errs,
297 					"__ops_validate_key_cb: user attribute length 0");
298 					return OPS_FINISHED;
299 			}
300 			break;
301 		}
302 		switch (content->sig.info.type) {
303 		case OPS_CERT_GENERIC:
304 		case OPS_CERT_PERSONA:
305 		case OPS_CERT_CASUAL:
306 		case OPS_CERT_POSITIVE:
307 		case OPS_SIG_REV_CERT:
308 			valid = (key->last_seen == ID) ?
309 			    __ops_check_useridcert_sig(&key->pubkey,
310 					&key->userid,
311 					&content->sig,
312 					__ops_get_pubkey(signer),
313 					key->reader->key->packets[
314 						key->reader->packet].raw) :
315 			    __ops_check_userattrcert_sig(&key->pubkey,
316 					&key->userattr,
317 					&content->sig,
318 				       __ops_get_pubkey(signer),
319 					key->reader->key->packets[
320 						key->reader->packet].raw);
321 			break;
322 
323 		case OPS_SIG_SUBKEY:
324 			/*
325 			 * XXX: we should also check that the signer is the
326 			 * key we are validating, I think.
327 			 */
328 			valid = __ops_check_subkey_sig(&key->pubkey,
329 				&key->subkey,
330 				&content->sig,
331 				__ops_get_pubkey(signer),
332 				key->reader->key->packets[
333 					key->reader->packet].raw);
334 			/* XXX - agc - put subkey logic here? */
335 			break;
336 
337 		case OPS_SIG_DIRECT:
338 			valid = __ops_check_direct_sig(&key->pubkey,
339 				&content->sig,
340 				__ops_get_pubkey(signer),
341 				key->reader->key->packets[
342 					key->reader->packet].raw);
343 			break;
344 
345 		case OPS_SIG_STANDALONE:
346 		case OPS_SIG_PRIMARY:
347 		case OPS_SIG_REV_KEY:
348 		case OPS_SIG_REV_SUBKEY:
349 		case OPS_SIG_TIMESTAMP:
350 		case OPS_SIG_3RD_PARTY:
351 			OPS_ERROR_1(errors, OPS_E_UNIMPLEMENTED,
352 				"Sig Verification type 0x%02x not done yet\n",
353 				content->sig.info.type);
354 			break;
355 
356 		default:
357 			OPS_ERROR_1(errors, OPS_E_UNIMPLEMENTED,
358 				    "Unexpected signature type 0x%02x\n",
359 				    	content->sig.info.type);
360 		}
361 
362 		if (valid) {
363 			if (!add_sig_to_list(&content->sig.info,
364 				&key->result->valid_sigs,
365 				&key->result->validc)) {
366 				OPS_ERROR(errors, OPS_E_UNIMPLEMENTED,
367 				    "Can't add good sig to list\n");
368 			}
369 		} else {
370 			OPS_ERROR(errors, OPS_E_V_BAD_SIGNATURE, "Bad Sig");
371 			if (!add_sig_to_list(&content->sig.info,
372 				&key->result->invalid_sigs,
373 				&key->result->invalidc)) {
374 				OPS_ERROR(errors, OPS_E_UNIMPLEMENTED,
375 				    "Can't add good sig to list\n");
376 			}
377 		}
378 		break;
379 
380 		/* ignore these */
381 	case OPS_PARSER_PTAG:
382 	case OPS_PTAG_CT_SIGNATURE_HEADER:
383 	case OPS_PARSER_PACKET_END:
384 		break;
385 
386 	case OPS_GET_PASSPHRASE:
387 		if (key->getpassphrase) {
388 			return key->getpassphrase(pkt, cbinfo);
389 		}
390 		break;
391 
392 	default:
393 		(void) fprintf(stderr, "unexpected tag=0x%x\n", pkt->tag);
394 		return OPS_FINISHED;
395 	}
396 	return OPS_RELEASE_MEMORY;
397 }
398 
399 __ops_cb_ret_t
400 validate_data_cb(const __ops_packet_t *pkt, __ops_cbdata_t *cbinfo)
401 {
402 	const __ops_contents_t	 *content = &pkt->u;
403 	const __ops_key_t	 *signer;
404 	validate_data_cb_t	 *data;
405 	__ops_error_t		**errors;
406 	__ops_io_t		 *io;
407 	unsigned		  from;
408 	unsigned		  valid = 0;
409 
410 	io = cbinfo->io;
411 	if (__ops_get_debug_level(__FILE__)) {
412 		(void) fprintf(io->errs, "validate_data_cb: %s\n",
413 				__ops_show_packet_tag(pkt->tag));
414 	}
415 	data = __ops_callback_arg(cbinfo);
416 	errors = __ops_callback_errors(cbinfo);
417 	switch (pkt->tag) {
418 	case OPS_PTAG_CT_SIGNED_CLEARTEXT_HEADER:
419 		/*
420 		 * ignore - this gives us the "Armor Header" line "Hash:
421 		 * SHA1" or similar
422 		 */
423 		break;
424 
425 	case OPS_PTAG_CT_LITDATA_HEADER:
426 		/* ignore */
427 		break;
428 
429 	case OPS_PTAG_CT_LITDATA_BODY:
430 		data->data.litdata_body = content->litdata_body;
431 		data->type = LITDATA;
432 		__ops_memory_add(data->mem, data->data.litdata_body.data,
433 				       data->data.litdata_body.length);
434 		return OPS_KEEP_MEMORY;
435 
436 	case OPS_PTAG_CT_SIGNED_CLEARTEXT_BODY:
437 		data->data.cleartext_body = content->cleartext_body;
438 		data->type = SIGNED_CLEARTEXT;
439 		__ops_memory_add(data->mem, data->data.litdata_body.data,
440 			       data->data.litdata_body.length);
441 		return OPS_KEEP_MEMORY;
442 
443 	case OPS_PTAG_CT_SIGNED_CLEARTEXT_TRAILER:
444 		/* this gives us an __ops_hash_t struct */
445 		break;
446 
447 	case OPS_PTAG_CT_SIGNATURE:	/* V3 sigs */
448 	case OPS_PTAG_CT_SIGNATURE_FOOTER:	/* V4 sigs */
449 		if (__ops_get_debug_level(__FILE__)) {
450 			(void) fprintf(io->outs, "\n*** hashed data:\n");
451 			hexdump(io->outs, content->sig.info.v4_hashed,
452 					content->sig.info.v4_hashlen, " ");
453 			(void) fprintf(io->outs, "\n");
454 			(void) fprintf(io->outs, "type=%02x signer_id=",
455 					content->sig.info.type);
456 			hexdump(io->outs, content->sig.info.signer_id,
457 				sizeof(content->sig.info.signer_id), "");
458 			(void) fprintf(io->outs, "\n");
459 		}
460 		from = 0;
461 		signer = __ops_getkeybyid(io, data->keyring,
462 					 content->sig.info.signer_id, &from);
463 		if (!signer) {
464 			OPS_ERROR(errors, OPS_E_V_UNKNOWN_SIGNER,
465 					"Unknown Signer");
466 			if (!add_sig_to_list(&content->sig.info,
467 					&data->result->unknown_sigs,
468 					&data->result->unknownc)) {
469 				OPS_ERROR(errors, OPS_E_V_UNKNOWN_SIGNER,
470 					"Can't add unknown sig to list");
471 			}
472 			break;
473 		}
474 		switch (content->sig.info.type) {
475 		case OPS_SIG_BINARY:
476 		case OPS_SIG_TEXT:
477 			if (__ops_mem_len(data->mem) == 0 &&
478 			    data->detachname) {
479 				/* check we have seen some data */
480 				/* if not, need to read from detached name */
481 				(void) fprintf(io->outs,
482 				"netpgp: assuming signed data in \"%s\"\n",
483 					data->detachname);
484 				data->mem = __ops_memory_new();
485 				__ops_mem_readfile(data->mem, data->detachname);
486 			}
487 			valid = check_binary_sig(__ops_mem_data(data->mem),
488 					__ops_mem_len(data->mem),
489 					&content->sig,
490 					__ops_get_pubkey(signer));
491 			break;
492 
493 		default:
494 			OPS_ERROR_1(errors, OPS_E_UNIMPLEMENTED,
495 				    "No Sig Verification type 0x%02x yet\n",
496 				    content->sig.info.type);
497 			break;
498 
499 		}
500 
501 		if (valid) {
502 			if (!add_sig_to_list(&content->sig.info,
503 					&data->result->valid_sigs,
504 					&data->result->validc)) {
505 				OPS_ERROR(errors, OPS_E_V_BAD_SIGNATURE,
506 					"Can't add good sig to list");
507 			}
508 		} else {
509 			OPS_ERROR(errors, OPS_E_V_BAD_SIGNATURE,
510 					"Bad Signature");
511 			if (!add_sig_to_list(&content->sig.info,
512 					&data->result->invalid_sigs,
513 					&data->result->invalidc)) {
514 				OPS_ERROR(errors, OPS_E_V_BAD_SIGNATURE,
515 					"Can't add good sig to list");
516 			}
517 		}
518 		break;
519 
520 		/* ignore these */
521 	case OPS_PARSER_PTAG:
522 	case OPS_PTAG_CT_SIGNATURE_HEADER:
523 	case OPS_PTAG_CT_ARMOUR_HEADER:
524 	case OPS_PTAG_CT_ARMOUR_TRAILER:
525 	case OPS_PTAG_CT_1_PASS_SIG:
526 		break;
527 
528 	case OPS_PARSER_PACKET_END:
529 		break;
530 
531 	default:
532 		OPS_ERROR(errors, OPS_E_V_NO_SIGNATURE, "No signature");
533 		break;
534 	}
535 	return OPS_RELEASE_MEMORY;
536 }
537 
538 static void
539 keydata_destroyer(__ops_reader_t *readinfo)
540 {
541 	free(__ops_reader_get_arg(readinfo));
542 }
543 
544 void
545 __ops_keydata_reader_set(__ops_stream_t *stream, const __ops_key_t *key)
546 {
547 	validate_reader_t *data;
548 
549 	if ((data = calloc(1, sizeof(*data))) == NULL) {
550 		(void) fprintf(stderr, "__ops_keydata_reader_set: bad alloc\n");
551 	} else {
552 		data->key = key;
553 		data->packet = 0;
554 		data->offset = 0;
555 		__ops_reader_set(stream, keydata_reader, keydata_destroyer, data);
556 	}
557 }
558 
559 /**
560  * \ingroup HighLevel_Verify
561  * \brief Indicicates whether any errors were found
562  * \param result Validation result to check
563  * \return 0 if any invalid signatures or unknown signers
564  	or no valid signatures; else 1
565  */
566 static unsigned
567 validate_result_status(__ops_validation_t *val)
568 {
569 	return val->validc && !val->invalidc && !val->unknownc;
570 }
571 
572 /**
573  * \ingroup HighLevel_Verify
574  * \brief Validate all signatures on a single key against the given keyring
575  * \param result Where to put the result
576  * \param key Key to validate
577  * \param keyring Keyring to use for validation
578  * \param cb_get_passphrase Callback to use to get passphrase
579  * \return 1 if all signatures OK; else 0
580  * \note It is the caller's responsiblity to free result after use.
581  * \sa __ops_validate_result_free()
582  */
583 unsigned
584 __ops_validate_key_sigs(__ops_validation_t *result,
585 	const __ops_key_t *key,
586 	const __ops_keyring_t *keyring,
587 	__ops_cb_ret_t cb_get_passphrase(const __ops_packet_t *,
588 						__ops_cbdata_t *))
589 {
590 	__ops_stream_t	*stream;
591 	validate_key_cb_t	 keysigs;
592 	const int		 printerrors = 1;
593 
594 	(void) memset(&keysigs, 0x0, sizeof(keysigs));
595 	keysigs.result = result;
596 	keysigs.getpassphrase = cb_get_passphrase;
597 
598 	stream = __ops_new(sizeof(*stream));
599 	/* __ops_parse_options(&opt,OPS_PTAG_CT_SIGNATURE,OPS_PARSE_PARSED); */
600 
601 	keysigs.keyring = keyring;
602 
603 	__ops_set_callback(stream, __ops_validate_key_cb, &keysigs);
604 	stream->readinfo.accumulate = 1;
605 	__ops_keydata_reader_set(stream, key);
606 
607 	/* Note: Coverity incorrectly reports an error that keysigs.reader */
608 	/* is never used. */
609 	keysigs.reader = stream->readinfo.arg;
610 
611 	__ops_parse(stream, !printerrors);
612 
613 	__ops_pubkey_free(&keysigs.pubkey);
614 	if (keysigs.subkey.version) {
615 		__ops_pubkey_free(&keysigs.subkey);
616 	}
617 	__ops_userid_free(&keysigs.userid);
618 	__ops_userattr_free(&keysigs.userattr);
619 
620 	__ops_stream_delete(stream);
621 
622 	return (!result->invalidc && !result->unknownc && result->validc);
623 }
624 
625 /**
626    \ingroup HighLevel_Verify
627    \param result Where to put the result
628    \param ring Keyring to use
629    \param cb_get_passphrase Callback to use to get passphrase
630    \note It is the caller's responsibility to free result after use.
631    \sa __ops_validate_result_free()
632 */
633 unsigned
634 __ops_validate_all_sigs(__ops_validation_t *result,
635 	    const __ops_keyring_t *ring,
636 	    __ops_cb_ret_t cb_get_passphrase(const __ops_packet_t *,
637 	    					__ops_cbdata_t *))
638 {
639 	unsigned	n;
640 
641 	(void) memset(result, 0x0, sizeof(*result));
642 	for (n = 0; n < ring->keyc; ++n) {
643 		__ops_validate_key_sigs(result, &ring->keys[n], ring,
644 				cb_get_passphrase);
645 	}
646 	return validate_result_status(result);
647 }
648 
649 /**
650    \ingroup HighLevel_Verify
651    \brief Frees validation result and associated memory
652    \param result Struct to be freed
653    \note Must be called after validation functions
654 */
655 void
656 __ops_validate_result_free(__ops_validation_t *result)
657 {
658 	if (result != NULL) {
659 		if (result->valid_sigs) {
660 			free_sig_info(result->valid_sigs);
661 		}
662 		if (result->invalid_sigs) {
663 			free_sig_info(result->invalid_sigs);
664 		}
665 		if (result->unknown_sigs) {
666 			free_sig_info(result->unknown_sigs);
667 		}
668 		free(result);
669 		/* result = NULL; - XXX unnecessary */
670 	}
671 }
672 
673 /**
674    \ingroup HighLevel_Verify
675    \brief Verifies the signatures in a signed file
676    \param result Where to put the result
677    \param filename Name of file to be validated
678    \param armoured Treat file as armoured, if set
679    \param keyring Keyring to use
680    \return 1 if signatures validate successfully;
681    	0 if signatures fail or there are no signatures
682    \note After verification, result holds the details of all keys which
683    have passed, failed and not been recognised.
684    \note It is the caller's responsiblity to call
685    	__ops_validate_result_free(result) after use.
686 */
687 unsigned
688 __ops_validate_file(__ops_io_t *io,
689 			__ops_validation_t *result,
690 			const char *infile,
691 			const char *outfile,
692 			const int armoured,
693 			const __ops_keyring_t *keyring)
694 {
695 	validate_data_cb_t	 validation;
696 	__ops_stream_t		*parse = NULL;
697 	struct stat		 st;
698 	const int		 printerrors = 1;
699 	unsigned		 ret;
700 	int64_t		 	 sigsize;
701 	char			 origfile[MAXPATHLEN];
702 	char			*detachname;
703 	int			 realarmour;
704 	int			 outfd = 0;
705 	int			 infd;
706 	int			 cc;
707 
708 #define SIG_OVERHEAD	284 /* XXX - depends on sig size? */
709 
710 	realarmour = armoured;
711 	if (stat(infile, &st) < 0) {
712 		(void) fprintf(io->errs, "can't validate \"%s\"\n", infile);
713 		return 0;
714 	}
715 	sigsize = st.st_size;
716 	detachname = NULL;
717 	cc = snprintf(origfile, sizeof(origfile), "%s", infile);
718 	if (strcmp(&origfile[cc - 4], ".sig") == 0) {
719 		origfile[cc - 4] = 0x0;
720 		if (stat(origfile, &st) == 0 &&
721 		    st.st_size > sigsize - SIG_OVERHEAD) {
722 			detachname = strdup(origfile);
723 		}
724 	}
725 	if (strcmp(&origfile[cc - 4], ".asc") == 0) {
726 		realarmour = 1;
727 	}
728 
729 	(void) memset(&validation, 0x0, sizeof(validation));
730 
731 	infd = __ops_setup_file_read(io, &parse, infile, &validation,
732 				validate_data_cb, 1);
733 	if (infd < 0) {
734 		return 0;
735 	}
736 
737 	validation.detachname = detachname;
738 
739 	/* Set verification reader and handling options */
740 	validation.result = result;
741 	validation.keyring = keyring;
742 	validation.mem = __ops_memory_new();
743 	__ops_memory_init(validation.mem, 128);
744 	/* Note: Coverity incorrectly reports an error that validation.reader */
745 	/* is never used. */
746 	validation.reader = parse->readinfo.arg;
747 
748 	if (realarmour) {
749 		__ops_reader_push_dearmour(parse);
750 	}
751 
752 	/* Do the verification */
753 	__ops_parse(parse, !printerrors);
754 
755 	/* Tidy up */
756 	if (realarmour) {
757 		__ops_reader_pop_dearmour(parse);
758 	}
759 	__ops_teardown_file_read(parse, infd);
760 
761 	ret = validate_result_status(result);
762 
763 	/* this is triggered only for --cat output */
764 	if (outfile) {
765 		/* need to send validated output somewhere */
766 		if (strcmp(outfile, "-") == 0) {
767 			outfd = STDOUT_FILENO;
768 		} else {
769 			outfd = open(outfile, O_WRONLY | O_CREAT, 0666);
770 		}
771 		if (outfd < 0) {
772 			/* even if the signature was good, we can't
773 			* write the file, so send back a bad return
774 			* code */
775 			ret = 0;
776 		} else if (validate_result_status(result)) {
777 			unsigned	 len;
778 			char		*cp;
779 			int		 i;
780 
781 			len = __ops_mem_len(validation.mem);
782 			cp = __ops_mem_data(validation.mem);
783 			for (i = 0 ; i < (int)len ; i += cc) {
784 				cc = write(outfd, &cp[i], len - i);
785 				if (cc < 0) {
786 					(void) fprintf(io->errs,
787 						"netpgp: short write\n");
788 					ret = 0;
789 					break;
790 				}
791 			}
792 			if (strcmp(outfile, "-") != 0) {
793 				(void) close(outfd);
794 			}
795 		}
796 	}
797 	__ops_memory_free(validation.mem);
798 	return ret;
799 }
800 
801 /**
802    \ingroup HighLevel_Verify
803    \brief Verifies the signatures in a __ops_memory_t struct
804    \param result Where to put the result
805    \param mem Memory to be validated
806    \param armoured Treat data as armoured, if set
807    \param keyring Keyring to use
808    \return 1 if signature validates successfully; 0 if not
809    \note After verification, result holds the details of all keys which
810    have passed, failed and not been recognised.
811    \note It is the caller's responsiblity to call
812    	__ops_validate_result_free(result) after use.
813 */
814 
815 unsigned
816 __ops_validate_mem(__ops_io_t *io,
817 			__ops_validation_t *result,
818 			__ops_memory_t *mem,
819 			__ops_memory_t **cat,
820 			const int armoured,
821 			const __ops_keyring_t *keyring)
822 {
823 	validate_data_cb_t	 validation;
824 	__ops_stream_t		*stream = NULL;
825 	const int		 printerrors = 1;
826 
827 	__ops_setup_memory_read(io, &stream, mem, &validation, validate_data_cb, 1);
828 	/* Set verification reader and handling options */
829 	(void) memset(&validation, 0x0, sizeof(validation));
830 	validation.result = result;
831 	validation.keyring = keyring;
832 	validation.mem = __ops_memory_new();
833 	__ops_memory_init(validation.mem, 128);
834 	/* Note: Coverity incorrectly reports an error that validation.reader */
835 	/* is never used. */
836 	validation.reader = stream->readinfo.arg;
837 
838 	if (armoured) {
839 		__ops_reader_push_dearmour(stream);
840 	}
841 
842 	/* Do the verification */
843 	__ops_parse(stream, !printerrors);
844 
845 	/* Tidy up */
846 	if (armoured) {
847 		__ops_reader_pop_dearmour(stream);
848 	}
849 	__ops_teardown_memory_read(stream, mem);
850 
851 	/* this is triggered only for --cat output */
852 	if (*cat) {
853 		/* need to send validated output somewhere */
854 		*cat = validation.mem;
855 	} else {
856 		__ops_memory_free(validation.mem);
857 	}
858 
859 	return validate_result_status(result);
860 }
861