xref: /netbsd-src/crypto/external/bsd/netpgp/dist/src/lib/validate.c (revision da9817918ec7e88db2912a2882967c7570a83f47)
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.19 2009/06/11 01:12:42 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 len,
95 		const unsigned char *data,
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 = 0;
104 
105 	__OPS_USED(signer);
106 	__ops_hash_any(&hash, sig->info.hash_alg);
107 	hash.init(&hash);
108 	hash.add(&hash, data, len);
109 	switch (sig->info.version) {
110 	case OPS_V3:
111 		trailer[0] = sig->info.type;
112 		trailer[1] = (unsigned)(sig->info.birthtime) >> 24;
113 		trailer[2] = (unsigned)(sig->info.birthtime) >> 16;
114 		trailer[3] = (unsigned)(sig->info.birthtime) >> 8;
115 		trailer[4] = (unsigned char)(sig->info.birthtime);
116 		hash.add(&hash, &trailer[0], 5);
117 		break;
118 
119 	case OPS_V4:
120 		hash.add(&hash, sig->info.v4_hashed, sig->info.v4_hashlen);
121 		trailer[0] = 0x04;	/* version */
122 		trailer[1] = 0xFF;
123 		hashedlen = sig->info.v4_hashlen;
124 		trailer[2] = hashedlen >> 24;
125 		trailer[3] = hashedlen >> 16;
126 		trailer[4] = hashedlen >> 8;
127 		trailer[5] = hashedlen;
128 		hash.add(&hash, trailer, 6);
129 		break;
130 
131 	default:
132 		(void) fprintf(stderr, "Invalid signature version %d\n",
133 				sig->info.version);
134 		return 0;
135 	}
136 
137 	n = hash.finish(&hash, hashout);
138 	if (__ops_get_debug_level(__FILE__)) {
139 		printf("check_binary_sig: hash length %" PRIsize "u\n",
140 			hash.size);
141 	}
142 	return __ops_check_sig(hashout, n, sig, signer);
143 }
144 
145 static int
146 keydata_reader(void *dest, size_t length, __ops_error_t **errors,
147 	       __ops_reader_t *readinfo,
148 	       __ops_cbdata_t *cbinfo)
149 {
150 	validate_reader_t *reader = __ops_reader_get_arg(readinfo);
151 
152 	__OPS_USED(errors);
153 	__OPS_USED(cbinfo);
154 	if (reader->offset == reader->key->packets[reader->packet].length) {
155 		reader->packet += 1;
156 		reader->offset = 0;
157 	}
158 	if (reader->packet == reader->key->packetc) {
159 		return 0;
160 	}
161 
162 	/*
163 	 * we should never be asked to cross a packet boundary in a single
164 	 * read
165 	 */
166 	if (reader->key->packets[reader->packet].length <
167 			reader->offset + length) {
168 		(void) fprintf(stderr, "keydata_reader: weird length\n");
169 		return 0;
170 	}
171 
172 	(void) memcpy(dest,
173 		&reader->key->packets[reader->packet].raw[reader->offset],
174 		length);
175 	reader->offset += length;
176 
177 	return length;
178 }
179 
180 static void
181 free_sig_info(__ops_sig_info_t *sig)
182 {
183 	(void) free(sig->v4_hashed);
184 	(void) free(sig);
185 }
186 
187 static void
188 copy_sig_info(__ops_sig_info_t *dst, const __ops_sig_info_t *src)
189 {
190 	(void) memcpy(dst, src, sizeof(*src));
191 	dst->v4_hashed = calloc(1, src->v4_hashlen);
192 	(void) memcpy(dst->v4_hashed, src->v4_hashed, src->v4_hashlen);
193 }
194 
195 static void
196 add_sig_to_list(const __ops_sig_info_t *sig, __ops_sig_info_t **sigs,
197 			unsigned *count)
198 {
199 	if (*count == 0) {
200 		*sigs = calloc(*count + 1, sizeof(__ops_sig_info_t));
201 	} else {
202 		*sigs = realloc(*sigs,
203 				(*count + 1) * sizeof(__ops_sig_info_t));
204 	}
205 	copy_sig_info(&(*sigs)[*count], sig);
206 	*count += 1;
207 }
208 
209 
210 __ops_cb_ret_t
211 __ops_validate_key_cb(const __ops_packet_t *pkt, __ops_cbdata_t *cbinfo)
212 {
213 	const __ops_contents_t	 *content = &pkt->u;
214 	const __ops_key_t	 *signer;
215 	validate_key_cb_t	 *key;
216 	__ops_error_t		**errors;
217 	__ops_io_t		 *io;
218 	unsigned		  valid = 0;
219 
220 	io = cbinfo->io;
221 	if (__ops_get_debug_level(__FILE__)) {
222 		(void) fprintf(io->errs, "%s\n",
223 				__ops_show_packet_tag(pkt->tag));
224 	}
225 	key = __ops_callback_arg(cbinfo);
226 	errors = __ops_callback_errors(cbinfo);
227 	switch (pkt->tag) {
228 	case OPS_PTAG_CT_PUBLIC_KEY:
229 		if (key->pubkey.version != 0) {
230 			(void) fprintf(io->errs,
231 				"__ops_validate_key_cb: version bad\n");
232 			return OPS_FINISHED;
233 		}
234 		key->pubkey = content->pubkey;
235 		return OPS_KEEP_MEMORY;
236 
237 	case OPS_PTAG_CT_PUBLIC_SUBKEY:
238 		if (key->subkey.version) {
239 			__ops_pubkey_free(&key->subkey);
240 		}
241 		key->subkey = content->pubkey;
242 		return OPS_KEEP_MEMORY;
243 
244 	case OPS_PTAG_CT_SECRET_KEY:
245 		key->seckey = content->seckey;
246 		key->pubkey = key->seckey.pubkey;
247 		return OPS_KEEP_MEMORY;
248 
249 	case OPS_PTAG_CT_USER_ID:
250 		if (key->userid.userid) {
251 			__ops_userid_free(&key->userid);
252 		}
253 		key->userid = content->userid;
254 		key->last_seen = ID;
255 		return OPS_KEEP_MEMORY;
256 
257 	case OPS_PTAG_CT_USER_ATTR:
258 		if (content->userattr.data.len == 0) {
259 			(void) fprintf(io->errs,
260 			"__ops_validate_key_cb: user attribute length 0");
261 			return OPS_FINISHED;
262 		}
263 		(void) fprintf(io->outs, "user attribute, length=%d\n",
264 			(int) content->userattr.data.len);
265 		if (key->userattr.data.len) {
266 			__ops_userattr_free(&key->userattr);
267 		}
268 		key->userattr = content->userattr;
269 		key->last_seen = ATTRIBUTE;
270 		return OPS_KEEP_MEMORY;
271 
272 	case OPS_PTAG_CT_SIGNATURE:	/* V3 sigs */
273 	case OPS_PTAG_CT_SIGNATURE_FOOTER:	/* V4 sigs */
274 
275 		signer = __ops_getkeybyid(io, key->keyring,
276 					 content->sig.info.signer_id);
277 		if (!signer) {
278 			add_sig_to_list(&content->sig.info,
279 					&key->result->unknown_sigs,
280 					&key->result->unknownc);
281 			break;
282 		}
283 		switch (content->sig.info.type) {
284 		case OPS_CERT_GENERIC:
285 		case OPS_CERT_PERSONA:
286 		case OPS_CERT_CASUAL:
287 		case OPS_CERT_POSITIVE:
288 		case OPS_SIG_REV_CERT:
289 			valid = (key->last_seen == ID) ?
290 			    __ops_check_useridcert_sig(&key->pubkey,
291 					&key->userid,
292 					&content->sig,
293 					__ops_get_pubkey(signer),
294 					key->reader->key->packets[
295 						key->reader->packet].raw) :
296 			    __ops_check_userattrcert_sig(&key->pubkey,
297 					&key->userattr,
298 					&content->sig,
299 				       __ops_get_pubkey(signer),
300 					key->reader->key->packets[
301 						key->reader->packet].raw);
302 			break;
303 
304 		case OPS_SIG_SUBKEY:
305 			/*
306 			 * XXX: we should also check that the signer is the
307 			 * key we are validating, I think.
308 			 */
309 			valid = __ops_check_subkey_sig(&key->pubkey,
310 				&key->subkey,
311 				&content->sig,
312 				__ops_get_pubkey(signer),
313 				key->reader->key->packets[
314 					key->reader->packet].raw);
315 			break;
316 
317 		case OPS_SIG_DIRECT:
318 			valid = __ops_check_direct_sig(&key->pubkey,
319 				&content->sig,
320 				__ops_get_pubkey(signer),
321 				key->reader->key->packets[
322 					key->reader->packet].raw);
323 			break;
324 
325 		case OPS_SIG_STANDALONE:
326 		case OPS_SIG_PRIMARY:
327 		case OPS_SIG_REV_KEY:
328 		case OPS_SIG_REV_SUBKEY:
329 		case OPS_SIG_TIMESTAMP:
330 		case OPS_SIG_3RD_PARTY:
331 			OPS_ERROR_1(errors, OPS_E_UNIMPLEMENTED,
332 				"Sig Verification type 0x%02x not done yet\n",
333 				content->sig.info.type);
334 			break;
335 
336 		default:
337 			OPS_ERROR_1(errors, OPS_E_UNIMPLEMENTED,
338 				    "Unexpected signature type 0x%02x\n",
339 				    	content->sig.info.type);
340 		}
341 
342 		if (valid) {
343 			add_sig_to_list(&content->sig.info,
344 				&key->result->valid_sigs,
345 				&key->result->validc);
346 		} else {
347 			OPS_ERROR(errors, OPS_E_V_BAD_SIGNATURE, "Bad Sig");
348 			add_sig_to_list(&content->sig.info,
349 					&key->result->invalid_sigs,
350 					&key->result->invalidc);
351 		}
352 		break;
353 
354 		/* ignore these */
355 	case OPS_PARSER_PTAG:
356 	case OPS_PTAG_CT_SIGNATURE_HEADER:
357 	case OPS_PARSER_PACKET_END:
358 		break;
359 
360 	case OPS_GET_PASSPHRASE:
361 		if (key->getpassphrase) {
362 			return key->getpassphrase(pkt, cbinfo);
363 		}
364 		break;
365 
366 	default:
367 		(void) fprintf(stderr, "unexpected tag=0x%x\n", pkt->tag);
368 		return OPS_FINISHED;
369 	}
370 	return OPS_RELEASE_MEMORY;
371 }
372 
373 __ops_cb_ret_t
374 validate_data_cb(const __ops_packet_t *pkt, __ops_cbdata_t *cbinfo)
375 {
376 	const __ops_contents_t	 *content = &pkt->u;
377 	const __ops_key_t	 *signer;
378 	validate_data_cb_t	 *data;
379 	__ops_error_t		**errors;
380 	__ops_io_t		 *io;
381 	unsigned		  valid = 0;
382 
383 	io = cbinfo->io;
384 	if (__ops_get_debug_level(__FILE__)) {
385 		(void) fprintf(io->errs, "validate_data_cb: %s\n",
386 				__ops_show_packet_tag(pkt->tag));
387 	}
388 	data = __ops_callback_arg(cbinfo);
389 	errors = __ops_callback_errors(cbinfo);
390 	switch (pkt->tag) {
391 	case OPS_PTAG_CT_SIGNED_CLEARTEXT_HEADER:
392 		/*
393 		 * ignore - this gives us the "Armor Header" line "Hash:
394 		 * SHA1" or similar
395 		 */
396 		break;
397 
398 	case OPS_PTAG_CT_LITDATA_HEADER:
399 		/* ignore */
400 		break;
401 
402 	case OPS_PTAG_CT_LITDATA_BODY:
403 		data->data.litdata_body = content->litdata_body;
404 		data->type = LITDATA;
405 		__ops_memory_add(data->mem, data->data.litdata_body.data,
406 				       data->data.litdata_body.length);
407 		return OPS_KEEP_MEMORY;
408 
409 	case OPS_PTAG_CT_SIGNED_CLEARTEXT_BODY:
410 		data->data.cleartext_body = content->cleartext_body;
411 		data->type = SIGNED_CLEARTEXT;
412 		__ops_memory_add(data->mem, data->data.litdata_body.data,
413 			       data->data.litdata_body.length);
414 		return OPS_KEEP_MEMORY;
415 
416 	case OPS_PTAG_CT_SIGNED_CLEARTEXT_TRAILER:
417 		/* this gives us an __ops_hash_t struct */
418 		break;
419 
420 	case OPS_PTAG_CT_SIGNATURE:	/* V3 sigs */
421 	case OPS_PTAG_CT_SIGNATURE_FOOTER:	/* V4 sigs */
422 		if (__ops_get_debug_level(__FILE__)) {
423 			(void) fprintf(io->outs, "\n*** hashed data:\n");
424 			hexdump(io->outs, content->sig.info.v4_hashed,
425 					content->sig.info.v4_hashlen, " ");
426 			(void) fprintf(io->outs, "\n");
427 			(void) fprintf(io->outs, "type=%02x signer_id=",
428 					content->sig.info.type);
429 			hexdump(io->outs, content->sig.info.signer_id,
430 				sizeof(content->sig.info.signer_id), "");
431 			(void) fprintf(io->outs, "\n");
432 		}
433 		signer = __ops_getkeybyid(io, data->keyring,
434 					 content->sig.info.signer_id);
435 		if (!signer) {
436 			OPS_ERROR(errors, OPS_E_V_UNKNOWN_SIGNER,
437 					"Unknown Signer");
438 			add_sig_to_list(&content->sig.info,
439 					&data->result->unknown_sigs,
440 					&data->result->unknownc);
441 			break;
442 		}
443 		switch (content->sig.info.type) {
444 		case OPS_SIG_BINARY:
445 		case OPS_SIG_TEXT:
446 			if (__ops_mem_len(data->mem) == 0 &&
447 			    data->detachname) {
448 				/* check we have seen some data */
449 				/* if not, need to read from detached name */
450 				(void) fprintf(io->outs,
451 				"netpgp: assuming signed data in \"%s\"\n",
452 					data->detachname);
453 				data->mem = __ops_memory_new();
454 				__ops_mem_readfile(data->mem, data->detachname);
455 			}
456 			valid = check_binary_sig(__ops_mem_len(data->mem),
457 					__ops_mem_data(data->mem),
458 					&content->sig,
459 					__ops_get_pubkey(signer));
460 			break;
461 
462 		default:
463 			OPS_ERROR_1(errors, OPS_E_UNIMPLEMENTED,
464 				    "No Sig Verification type 0x%02x yet\n",
465 				    content->sig.info.type);
466 			break;
467 
468 		}
469 
470 		if (valid) {
471 			add_sig_to_list(&content->sig.info,
472 					&data->result->valid_sigs,
473 					&data->result->validc);
474 		} else {
475 			OPS_ERROR(errors, OPS_E_V_BAD_SIGNATURE,
476 					"Bad Signature");
477 			add_sig_to_list(&content->sig.info,
478 					&data->result->invalid_sigs,
479 					&data->result->invalidc);
480 		}
481 		break;
482 
483 		/* ignore these */
484 	case OPS_PARSER_PTAG:
485 	case OPS_PTAG_CT_SIGNATURE_HEADER:
486 	case OPS_PTAG_CT_ARMOUR_HEADER:
487 	case OPS_PTAG_CT_ARMOUR_TRAILER:
488 	case OPS_PTAG_CT_1_PASS_SIG:
489 		break;
490 
491 	case OPS_PARSER_PACKET_END:
492 		break;
493 
494 	default:
495 		OPS_ERROR(errors, OPS_E_V_NO_SIGNATURE, "No signature");
496 		break;
497 	}
498 	return OPS_RELEASE_MEMORY;
499 }
500 
501 static void
502 keydata_destroyer(__ops_reader_t *readinfo)
503 {
504 	(void) free(__ops_reader_get_arg(readinfo));
505 }
506 
507 void
508 __ops_keydata_reader_set(__ops_stream_t *stream, const __ops_key_t *key)
509 {
510 	validate_reader_t *data = calloc(1, sizeof(*data));
511 
512 	data->key = key;
513 	data->packet = 0;
514 	data->offset = 0;
515 	__ops_reader_set(stream, keydata_reader, keydata_destroyer, data);
516 }
517 
518 /**
519  * \ingroup HighLevel_Verify
520  * \brief Indicicates whether any errors were found
521  * \param result Validation result to check
522  * \return 0 if any invalid signatures or unknown signers
523  	or no valid signatures; else 1
524  */
525 static unsigned
526 validate_result_status(__ops_validation_t *val)
527 {
528 	return val->validc && !val->invalidc && !val->unknownc;
529 }
530 
531 /**
532  * \ingroup HighLevel_Verify
533  * \brief Validate all signatures on a single key against the given keyring
534  * \param result Where to put the result
535  * \param key Key to validate
536  * \param keyring Keyring to use for validation
537  * \param cb_get_passphrase Callback to use to get passphrase
538  * \return 1 if all signatures OK; else 0
539  * \note It is the caller's responsiblity to free result after use.
540  * \sa __ops_validate_result_free()
541  */
542 unsigned
543 __ops_validate_key_sigs(__ops_validation_t *result,
544 	const __ops_key_t *key,
545 	const __ops_keyring_t *keyring,
546 	__ops_cb_ret_t cb_get_passphrase(const __ops_packet_t *,
547 						__ops_cbdata_t *))
548 {
549 	__ops_stream_t	*stream;
550 	validate_key_cb_t	 keysigs;
551 	const int		 printerrors = 1;
552 
553 	(void) memset(&keysigs, 0x0, sizeof(keysigs));
554 	keysigs.result = result;
555 	keysigs.getpassphrase = cb_get_passphrase;
556 
557 	stream = __ops_new(sizeof(*stream));
558 	/* __ops_parse_options(&opt,OPS_PTAG_CT_SIGNATURE,OPS_PARSE_PARSED); */
559 
560 	keysigs.keyring = keyring;
561 
562 	__ops_set_callback(stream, __ops_validate_key_cb, &keysigs);
563 	stream->readinfo.accumulate = 1;
564 	__ops_keydata_reader_set(stream, key);
565 
566 	/* Note: Coverity incorrectly reports an error that keysigs.reader */
567 	/* is never used. */
568 	keysigs.reader = stream->readinfo.arg;
569 
570 	__ops_parse(stream, !printerrors);
571 
572 	__ops_pubkey_free(&keysigs.pubkey);
573 	if (keysigs.subkey.version) {
574 		__ops_pubkey_free(&keysigs.subkey);
575 	}
576 	__ops_userid_free(&keysigs.userid);
577 	__ops_userattr_free(&keysigs.userattr);
578 
579 	__ops_stream_delete(stream);
580 
581 	return (!result->invalidc && !result->unknownc && result->validc);
582 }
583 
584 /**
585    \ingroup HighLevel_Verify
586    \param result Where to put the result
587    \param ring Keyring to use
588    \param cb_get_passphrase Callback to use to get passphrase
589    \note It is the caller's responsibility to free result after use.
590    \sa __ops_validate_result_free()
591 */
592 unsigned
593 __ops_validate_all_sigs(__ops_validation_t *result,
594 	    const __ops_keyring_t *ring,
595 	    __ops_cb_ret_t cb_get_passphrase(const __ops_packet_t *,
596 	    					__ops_cbdata_t *))
597 {
598 	unsigned	n;
599 
600 	(void) memset(result, 0x0, sizeof(*result));
601 	for (n = 0; n < ring->keyc; ++n) {
602 		__ops_validate_key_sigs(result, &ring->keys[n], ring,
603 				cb_get_passphrase);
604 	}
605 	return validate_result_status(result);
606 }
607 
608 /**
609    \ingroup HighLevel_Verify
610    \brief Frees validation result and associated memory
611    \param result Struct to be freed
612    \note Must be called after validation functions
613 */
614 void
615 __ops_validate_result_free(__ops_validation_t *result)
616 {
617 	if (result != NULL) {
618 		if (result->valid_sigs) {
619 			free_sig_info(result->valid_sigs);
620 		}
621 		if (result->invalid_sigs) {
622 			free_sig_info(result->invalid_sigs);
623 		}
624 		if (result->unknown_sigs) {
625 			free_sig_info(result->unknown_sigs);
626 		}
627 		(void) free(result);
628 		result = NULL;
629 	}
630 }
631 
632 /**
633    \ingroup HighLevel_Verify
634    \brief Verifies the signatures in a signed file
635    \param result Where to put the result
636    \param filename Name of file to be validated
637    \param armoured Treat file as armoured, if set
638    \param keyring Keyring to use
639    \return 1 if signatures validate successfully;
640    	0 if signatures fail or there are no signatures
641    \note After verification, result holds the details of all keys which
642    have passed, failed and not been recognised.
643    \note It is the caller's responsiblity to call
644    	__ops_validate_result_free(result) after use.
645 */
646 unsigned
647 __ops_validate_file(__ops_io_t *io,
648 			__ops_validation_t *result,
649 			const char *infile,
650 			const char *outfile,
651 			const int armoured,
652 			const __ops_keyring_t *keyring)
653 {
654 	validate_data_cb_t	 validation;
655 	__ops_stream_t	*parse = NULL;
656 	struct stat		 st;
657 	const int		 printerrors = 1;
658 	unsigned		 ret;
659 	int64_t		 	 sigsize;
660 	char			 origfile[MAXPATHLEN];
661 	char			*detachname;
662 	int			 outfd = 0;
663 	int			 infd;
664 	int			 cc;
665 
666 #define SIG_OVERHEAD	284 /* XXX - depends on sig size? */
667 
668 	if (stat(infile, &st) < 0) {
669 		(void) fprintf(io->errs, "can't validate \"%s\"\n", infile);
670 		return 0;
671 	}
672 	sigsize = st.st_size;
673 	detachname = NULL;
674 	cc = snprintf(origfile, sizeof(origfile), "%s", infile);
675 	if (strcmp(&origfile[cc - 4], ".sig") == 0) {
676 		origfile[cc - 4] = 0x0;
677 		if (stat(origfile, &st) == 0 &&
678 		    st.st_size > sigsize - SIG_OVERHEAD) {
679 			detachname = strdup(origfile);
680 		}
681 	}
682 
683 	(void) memset(&validation, 0x0, sizeof(validation));
684 
685 	infd = __ops_setup_file_read(io, &parse, infile, &validation,
686 				validate_data_cb, 1);
687 	if (infd < 0) {
688 		return 0;
689 	}
690 
691 	validation.detachname = detachname;
692 
693 	/* Set verification reader and handling options */
694 	validation.result = result;
695 	validation.keyring = keyring;
696 	validation.mem = __ops_memory_new();
697 	__ops_memory_init(validation.mem, 128);
698 	/* Note: Coverity incorrectly reports an error that validation.reader */
699 	/* is never used. */
700 	validation.reader = parse->readinfo.arg;
701 
702 	if (armoured) {
703 		__ops_reader_push_dearmour(parse);
704 	}
705 
706 	/* Do the verification */
707 	__ops_parse(parse, !printerrors);
708 
709 	/* Tidy up */
710 	if (armoured) {
711 		__ops_reader_pop_dearmour(parse);
712 	}
713 	__ops_teardown_file_read(parse, infd);
714 
715 	ret = validate_result_status(result);
716 
717 	/* this is triggered only for --cat output */
718 	if (outfile) {
719 		/* need to send validated output somewhere */
720 		if (strcmp(outfile, "-") == 0) {
721 			outfd = STDOUT_FILENO;
722 		} else {
723 			outfd = open(outfile, O_WRONLY | O_CREAT, 0666);
724 		}
725 		if (outfd < 0) {
726 			/* even if the signature was good, we can't
727 			* write the file, so send back a bad return
728 			* code */
729 			ret = 0;
730 		} else if (validate_result_status(result)) {
731 			unsigned	 len;
732 			char		*cp;
733 			int		 i;
734 
735 			len = __ops_mem_len(validation.mem);
736 			cp = __ops_mem_data(validation.mem);
737 			for (i = 0 ; i < (int)len ; i += cc) {
738 				cc = write(outfd, &cp[i], len - i);
739 				if (cc < 0) {
740 					(void) fprintf(io->errs,
741 						"netpgp: short write\n");
742 					ret = 0;
743 					break;
744 				}
745 			}
746 			if (strcmp(outfile, "-") != 0) {
747 				(void) close(outfd);
748 			}
749 		}
750 	}
751 	__ops_memory_free(validation.mem);
752 	return ret;
753 }
754 
755 /**
756    \ingroup HighLevel_Verify
757    \brief Verifies the signatures in a __ops_memory_t struct
758    \param result Where to put the result
759    \param mem Memory to be validated
760    \param armoured Treat data as armoured, if set
761    \param keyring Keyring to use
762    \return 1 if signature validates successfully; 0 if not
763    \note After verification, result holds the details of all keys which
764    have passed, failed and not been recognised.
765    \note It is the caller's responsiblity to call
766    	__ops_validate_result_free(result) after use.
767 */
768 
769 unsigned
770 __ops_validate_mem(__ops_io_t *io,
771 			__ops_validation_t *result,
772 			__ops_memory_t *mem,
773 			const int armoured,
774 			const __ops_keyring_t *keyring)
775 {
776 	validate_data_cb_t	 validation;
777 	__ops_stream_t	*stream = NULL;
778 	const int		 printerrors = 1;
779 
780 	__ops_setup_memory_read(io, &stream, mem, &validation, validate_data_cb,				1);
781 	/* Set verification reader and handling options */
782 	(void) memset(&validation, 0x0, sizeof(validation));
783 	validation.result = result;
784 	validation.keyring = keyring;
785 	validation.mem = __ops_memory_new();
786 	__ops_memory_init(validation.mem, 128);
787 	/* Note: Coverity incorrectly reports an error that validation.reader */
788 	/* is never used. */
789 	validation.reader = stream->readinfo.arg;
790 
791 	if (armoured) {
792 		__ops_reader_push_dearmour(stream);
793 	}
794 
795 	/* Do the verification */
796 	__ops_parse(stream, !printerrors);
797 
798 	/* Tidy up */
799 	if (armoured) {
800 		__ops_reader_pop_dearmour(stream);
801 	}
802 	__ops_teardown_memory_read(stream, mem);
803 	__ops_memory_free(validation.mem);
804 
805 	return validate_result_status(result);
806 }
807