xref: /netbsd-src/crypto/external/bsd/netpgp/dist/src/lib/validate.c (revision 93bf6008f8b7982c1d1a9486e4a4a0e687fe36eb)
1 /*
2  * Copyright (c) 2005-2008 Nominet UK (www.nic.uk)
3  * All rights reserved.
4  * Contributors: Ben Laurie, Rachel Willmer. The Contributors have asserted
5  * their moral rights under the UK Copyright Design and Patents Act 1988 to
6  * be recorded as the authors of this copyright work.
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
9  * use this file except in compliance with the License.
10  *
11  * You may obtain a copy of the License at
12  *     http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  *
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  */
21 #include "config.h"
22 
23 #include "packet-parse.h"
24 #include "packet-show.h"
25 #include "keyring.h"
26 #include "signature.h"
27 #include "netpgpsdk.h"
28 
29 #include "readerwriter.h"
30 #include "netpgpdefs.h"
31 #include "memory.h"
32 #include "keyring_local.h"
33 #include "parse_local.h"
34 #include "validate.h"
35 
36 #ifdef HAVE_ASSERT_H
37 #include <assert.h>
38 #endif
39 
40 #include <string.h>
41 
42 
43 static          bool
44 check_binary_signature(const unsigned len,
45 		       const unsigned char *data,
46 		       const __ops_signature_t * sig,
47 		    const __ops_public_key_t * signer __attribute__((unused)))
48 {
49 	/* Does the signed hash match the given hash? */
50 
51 	int             n = 0;
52 	__ops_hash_t      hash;
53 	unsigned char   hashout[OPS_MAX_HASH_SIZE];
54 	unsigned char   trailer[6];
55 	unsigned int    hashedlen;
56 
57 	/* common_init_signature(&hash,sig); */
58 	__ops_hash_any(&hash, sig->info.hash_algorithm);
59 	hash.init(&hash);
60 	hash.add(&hash, data, len);
61 	switch (sig->info.version) {
62 	case OPS_V3:
63 		trailer[0] = sig->info.type;
64 		trailer[1] = sig->info.creation_time >> 24;
65 		trailer[2] = sig->info.creation_time >> 16;
66 		trailer[3] = sig->info.creation_time >> 8;
67 		trailer[4] = sig->info.creation_time;
68 		hash.add(&hash, &trailer[0], 5);
69 		break;
70 
71 	case OPS_V4:
72 		hash.add(&hash, sig->info.v4_hashed_data, sig->info.v4_hashed_data_length);
73 
74 		trailer[0] = 0x04;	/* version */
75 		trailer[1] = 0xFF;
76 		hashedlen = sig->info.v4_hashed_data_length;
77 		trailer[2] = hashedlen >> 24;
78 		trailer[3] = hashedlen >> 16;
79 		trailer[4] = hashedlen >> 8;
80 		trailer[5] = hashedlen;
81 		hash.add(&hash, &trailer[0], 6);
82 
83 		break;
84 
85 	default:
86 		fprintf(stderr, "Invalid signature version %d\n", sig->info.version);
87 		return false;
88 	}
89 
90 	n = hash.finish(&hash, hashout);
91 
92 	if (__ops_get_debug_level(__FILE__)) {
93 		printf("check_binary_signature: hash length %" PRIsize "u\n", hash.size);
94 	}
95 	/* return false; */
96 	return __ops_check_signature(hashout, n, sig, signer);
97 }
98 
99 static int
100 keydata_reader(void *dest, size_t length, __ops_error_t ** errors,
101 	       __ops_reader_info_t * rinfo,
102 	       __ops_parse_cb_info_t * cbinfo)
103 {
104 	validate_reader_t *reader = __ops_reader_get_arg(rinfo);
105 
106 	OPS_USED(errors);
107 	OPS_USED(cbinfo);
108 	if (reader->offset == reader->key->packets[reader->packet].length) {
109 		++reader->packet;
110 		reader->offset = 0;
111 	}
112 	if (reader->packet == reader->key->npackets)
113 		return 0;
114 
115 	/*
116 	 * we should never be asked to cross a packet boundary in a single
117 	 * read
118 	 */
119 	assert(reader->key->packets[reader->packet].length >= reader->offset + length);
120 
121 	(void) memcpy(dest, &reader->key->packets[reader->packet].raw[reader->offset], length);
122 	reader->offset += length;
123 
124 	return length;
125 }
126 
127 static void
128 free_signature_info(__ops_signature_info_t * sig)
129 {
130 	free(sig->v4_hashed_data);
131 	free(sig);
132 }
133 
134 static void
135 copy_signature_info(__ops_signature_info_t * dst, const __ops_signature_info_t * src)
136 {
137 	(void) memcpy(dst, src, sizeof(*src));
138 	dst->v4_hashed_data = calloc(1, src->v4_hashed_data_length);
139 	(void) memcpy(dst->v4_hashed_data, src->v4_hashed_data, src->v4_hashed_data_length);
140 }
141 
142 static void
143 add_sig_to_list(const __ops_signature_info_t *sig, __ops_signature_info_t **sigs,
144 		unsigned *count)
145 {
146 	if (*count == 0) {
147 		*sigs = calloc(*count + 1, sizeof(__ops_signature_info_t));
148 	} else {
149 		*sigs = realloc(*sigs, (*count + 1) * sizeof(__ops_signature_info_t));
150 	}
151 	copy_signature_info(&(*sigs)[*count], sig);
152 	*count += 1;
153 }
154 
155 
156 __ops_parse_cb_return_t
157 __ops_validate_key_cb(const __ops_parser_content_t * contents, __ops_parse_cb_info_t * cbinfo)
158 {
159 	const __ops_parser_content_union_t *content = &contents->u;
160 	validate_key_cb_t *key = __ops_parse_cb_get_arg(cbinfo);
161 	__ops_error_t   **errors = __ops_parse_cb_get_errors(cbinfo);
162 	const __ops_keydata_t *signer;
163 	bool   valid = false;
164 
165 	if (__ops_get_debug_level(__FILE__))
166 		printf("%s\n", __ops_show_packet_tag(contents->tag));
167 
168 	switch (contents->tag) {
169 	case OPS_PTAG_CT_PUBLIC_KEY:
170 		assert(key->pkey.version == 0);
171 		key->pkey = content->public_key;
172 		return OPS_KEEP_MEMORY;
173 
174 	case OPS_PTAG_CT_PUBLIC_SUBKEY:
175 		if (key->subkey.version)
176 			__ops_public_key_free(&key->subkey);
177 		key->subkey = content->public_key;
178 		return OPS_KEEP_MEMORY;
179 
180 	case OPS_PTAG_CT_SECRET_KEY:
181 		key->skey = content->secret_key;
182 		key->pkey = key->skey.public_key;
183 		return OPS_KEEP_MEMORY;
184 
185 	case OPS_PTAG_CT_USER_ID:
186 		if (key->user_id.user_id)
187 			__ops_user_id_free(&key->user_id);
188 		key->user_id = content->user_id;
189 		key->last_seen = ID;
190 		return OPS_KEEP_MEMORY;
191 
192 	case OPS_PTAG_CT_USER_ATTRIBUTE:
193 		assert(content->user_attribute.data.len);
194 		printf("user attribute, length=%d\n", (int) content->user_attribute.data.len);
195 		if (key->user_attribute.data.len)
196 			__ops_user_attribute_free(&key->user_attribute);
197 		key->user_attribute = content->user_attribute;
198 		key->last_seen = ATTRIBUTE;
199 		return OPS_KEEP_MEMORY;
200 
201 	case OPS_PTAG_CT_SIGNATURE:	/* V3 sigs */
202 	case OPS_PTAG_CT_SIGNATURE_FOOTER:	/* V4 sigs */
203 
204 		signer = __ops_keyring_find_key_by_id(key->keyring,
205 					 content->signature.info.signer_id);
206 		if (!signer) {
207 			add_sig_to_list(&content->signature.info,
208 					&key->result->unknown_sigs,
209 					&key->result->unknownc);
210 			break;
211 		}
212 		switch (content->signature.info.type) {
213 		case OPS_CERT_GENERIC:
214 		case OPS_CERT_PERSONA:
215 		case OPS_CERT_CASUAL:
216 		case OPS_CERT_POSITIVE:
217 		case OPS_SIG_REV_CERT:
218 			if (key->last_seen == ID)
219 				valid = __ops_check_user_id_certification_signature(&key->pkey,
220 							      &key->user_id,
221 							&content->signature,
222 				       __ops_get_public_key_from_data(signer),
223 					key->rarg->key->packets[key->rarg->packet].raw);
224 			else
225 				valid = __ops_check_user_attribute_certification_signature(&key->pkey,
226 						       &key->user_attribute,
227 							&content->signature,
228 				       __ops_get_public_key_from_data(signer),
229 					key->rarg->key->packets[key->rarg->packet].raw);
230 
231 			break;
232 
233 		case OPS_SIG_SUBKEY:
234 			/*
235 			 * XXX: we should also check that the signer is the
236 			 * key we are validating, I think.
237 			 */
238 			valid = __ops_check_subkey_signature(&key->pkey, &key->subkey,
239 							&content->signature,
240 				       __ops_get_public_key_from_data(signer),
241 			    key->rarg->key->packets[key->rarg->packet].raw);
242 			break;
243 
244 		case OPS_SIG_DIRECT:
245 			valid = __ops_check_direct_signature(&key->pkey, &content->signature,
246 				       __ops_get_public_key_from_data(signer),
247 			    key->rarg->key->packets[key->rarg->packet].raw);
248 			break;
249 
250 		case OPS_SIG_STANDALONE:
251 		case OPS_SIG_PRIMARY:
252 		case OPS_SIG_REV_KEY:
253 		case OPS_SIG_REV_SUBKEY:
254 		case OPS_SIG_TIMESTAMP:
255 		case OPS_SIG_3RD_PARTY:
256 			OPS_ERROR_1(errors, OPS_E_UNIMPLEMENTED,
257 				    "Verification of signature type 0x%02x not yet implemented\n", content->signature.info.type);
258 			break;
259 
260 		default:
261 			OPS_ERROR_1(errors, OPS_E_UNIMPLEMENTED,
262 				    "Unexpected signature type 0x%02x\n", content->signature.info.type);
263 		}
264 
265 		if (valid) {
266 			add_sig_to_list(&content->signature.info,
267 				&key->result->valid_sigs,
268 				&key->result->validc);
269 		} else {
270 			OPS_ERROR(errors, OPS_E_V_BAD_SIGNATURE, "Bad Signature");
271 			add_sig_to_list(&content->signature.info,
272 					&key->result->invalid_sigs,
273 					&key->result->invalidc);
274 		}
275 		break;
276 
277 		/* ignore these */
278 	case OPS_PARSER_PTAG:
279 	case OPS_PTAG_CT_SIGNATURE_HEADER:
280 	case OPS_PARSER_PACKET_END:
281 		break;
282 
283 	case OPS_PARSER_CMD_GET_SK_PASSPHRASE:
284 		if (key->cb_get_passphrase) {
285 			return key->cb_get_passphrase(contents, cbinfo);
286 		}
287 		break;
288 
289 	default:
290 		fprintf(stderr, "unexpected tag=0x%x\n", contents->tag);
291 		assert(0);
292 		break;
293 	}
294 	return OPS_RELEASE_MEMORY;
295 }
296 
297 __ops_parse_cb_return_t
298 validate_data_cb(const __ops_parser_content_t * contents, __ops_parse_cb_info_t * cbinfo)
299 {
300 	const __ops_parser_content_union_t *content = &contents->u;
301 	validate_data_cb_t *data = __ops_parse_cb_get_arg(cbinfo);
302 	__ops_error_t   **errors = __ops_parse_cb_get_errors(cbinfo);
303 	const __ops_keydata_t *signer;
304 	bool   valid = false;
305 
306 	if (__ops_get_debug_level(__FILE__)) {
307 		printf("validate_data_cb: %s\n", __ops_show_packet_tag(contents->tag));
308 	}
309 	switch (contents->tag) {
310 	case OPS_PTAG_CT_SIGNED_CLEARTEXT_HEADER:
311 		/*
312 		 * ignore - this gives us the "Armor Header" line "Hash:
313 		 * SHA1" or similar
314 		 */
315 		break;
316 
317 	case OPS_PTAG_CT_LITERAL_DATA_HEADER:
318 		/* ignore */
319 		break;
320 
321 	case OPS_PTAG_CT_LITERAL_DATA_BODY:
322 		data->data.literal_data_body = content->literal_data_body;
323 		data->use = LITERAL_DATA;
324 		__ops_memory_add(data->mem, data->data.literal_data_body.data,
325 			       data->data.literal_data_body.length);
326 		return OPS_KEEP_MEMORY;
327 
328 	case OPS_PTAG_CT_SIGNED_CLEARTEXT_BODY:
329 		data->data.signed_cleartext_body = content->signed_cleartext_body;
330 		data->use = SIGNED_CLEARTEXT;
331 		__ops_memory_add(data->mem, data->data.literal_data_body.data,
332 			       data->data.literal_data_body.length);
333 		return OPS_KEEP_MEMORY;
334 
335 	case OPS_PTAG_CT_SIGNED_CLEARTEXT_TRAILER:
336 		/* this gives us an __ops_hash_t struct */
337 		break;
338 
339 	case OPS_PTAG_CT_SIGNATURE:	/* V3 sigs */
340 	case OPS_PTAG_CT_SIGNATURE_FOOTER:	/* V4 sigs */
341 
342 		if (__ops_get_debug_level(__FILE__)) {
343 			unsigned int    zzz = 0;
344 			printf("\n*** hashed data:\n");
345 			for (zzz = 0; zzz < content->signature.info.v4_hashed_data_length; zzz++)
346 				printf("0x%02x ", content->signature.info.v4_hashed_data[zzz]);
347 			printf("\n");
348 			printf("  type=%02x signer_id=", content->signature.info.type);
349 			hexdump(content->signature.info.signer_id,
350 				sizeof(content->signature.info.signer_id), "");
351 			printf("\n");
352 		}
353 		signer = __ops_keyring_find_key_by_id(data->keyring,
354 					 content->signature.info.signer_id);
355 		if (!signer) {
356 			OPS_ERROR(errors, OPS_E_V_UNKNOWN_SIGNER, "Unknown Signer");
357 			add_sig_to_list(&content->signature.info,
358 					&data->result->unknown_sigs,
359 					&data->result->unknownc);
360 			break;
361 		}
362 		switch (content->signature.info.type) {
363 		case OPS_SIG_BINARY:
364 		case OPS_SIG_TEXT:
365 
366 			valid = check_binary_signature(__ops_memory_get_length(data->mem),
367 					      __ops_memory_get_data(data->mem),
368 						       &content->signature,
369 				      __ops_get_public_key_from_data(signer));
370 			break;
371 
372 		default:
373 			OPS_ERROR_1(errors, OPS_E_UNIMPLEMENTED,
374 				    "Verification of signature type 0x%02x not yet implemented\n", content->signature.info.type);
375 			break;
376 
377 		}
378 
379 		__ops_memory_free(data->mem);
380 
381 		if (valid) {
382 			add_sig_to_list(&content->signature.info,
383 					&data->result->valid_sigs,
384 					&data->result->validc);
385 		} else {
386 			OPS_ERROR(errors, OPS_E_V_BAD_SIGNATURE, "Bad Signature");
387 			add_sig_to_list(&content->signature.info,
388 					&data->result->invalid_sigs,
389 					&data->result->invalidc);
390 		}
391 		break;
392 
393 		/* ignore these */
394 	case OPS_PARSER_PTAG:
395 	case OPS_PTAG_CT_SIGNATURE_HEADER:
396 	case OPS_PTAG_CT_ARMOUR_HEADER:
397 	case OPS_PTAG_CT_ARMOUR_TRAILER:
398 	case OPS_PTAG_CT_ONE_PASS_SIGNATURE:
399 	case OPS_PARSER_PACKET_END:
400 		break;
401 
402 	default:
403 		OPS_ERROR(errors, OPS_E_V_NO_SIGNATURE, "No signature");
404 		break;
405 	}
406 	return OPS_RELEASE_MEMORY;
407 }
408 
409 static void
410 keydata_destroyer(__ops_reader_info_t * rinfo)
411 {
412 	free(__ops_reader_get_arg(rinfo));
413 }
414 
415 void
416 __ops_keydata_reader_set(__ops_parse_info_t * pinfo, const __ops_keydata_t * key)
417 {
418 	validate_reader_t *data = calloc(1, sizeof(*data));
419 
420 	data->key = key;
421 	data->packet = 0;
422 	data->offset = 0;
423 
424 	__ops_reader_set(pinfo, keydata_reader, keydata_destroyer, data);
425 }
426 
427 /**
428  * \ingroup HighLevel_Verify
429  * \brief Indicicates whether any errors were found
430  * \param result Validation result to check
431  * \return false if any invalid signatures or unknown signers or no valid signatures; else true
432  */
433 static bool
434 validate_result_status(__ops_validation_t *val)
435 {
436 	return val->validc && !val->invalidc && !val->unknownc;
437 }
438 
439 /**
440  * \ingroup HighLevel_Verify
441  * \brief Validate all signatures on a single key against the given keyring
442  * \param result Where to put the result
443  * \param key Key to validate
444  * \param keyring Keyring to use for validation
445  * \param cb_get_passphrase Callback to use to get passphrase
446  * \return true if all signatures OK; else false
447  * \note It is the caller's responsiblity to free result after use.
448  * \sa __ops_validate_result_free()
449 
450  Example Code:
451 \code
452 void example(const __ops_keydata_t* key, const __ops_keyring_t *keyring)
453 {
454   __ops_validation_t *result=NULL;
455   if (__ops_validate_key_signatures(result, key, keyring, callback_cmd_get_passphrase_from_cmdline)==true)
456     printf("OK");
457   else
458     printf("ERR");
459   printf("valid=%d, invalid=%d, unknown=%d\n",
460          result->validc,
461          result->invalidc,
462          result->unknownc);
463   __ops_validate_result_free(result);
464 }
465 
466 \endcode
467  */
468 bool
469 __ops_validate_key_signatures(__ops_validation_t * result, const __ops_keydata_t * key,
470 			    const __ops_keyring_t * keyring,
471 			    __ops_parse_cb_return_t cb_get_passphrase(const __ops_parser_content_t *, __ops_parse_cb_info_t *)
472 )
473 {
474 	__ops_parse_info_t *pinfo;
475 	validate_key_cb_t carg;
476 
477 	(void) memset(&carg, 0x0, sizeof(carg));
478 	carg.result = result;
479 	carg.cb_get_passphrase = cb_get_passphrase;
480 
481 	pinfo = __ops_parse_info_new();
482 	/* __ops_parse_options(&opt,OPS_PTAG_CT_SIGNATURE,OPS_PARSE_PARSED); */
483 
484 	carg.keyring = keyring;
485 
486 	__ops_parse_cb_set(pinfo, __ops_validate_key_cb, &carg);
487 	pinfo->rinfo.accumulate = true;
488 	__ops_keydata_reader_set(pinfo, key);
489 
490 	/* Note: Coverity incorrectly reports an error that carg.rarg */
491 	/* is never used. */
492 	carg.rarg = pinfo->rinfo.arg;
493 
494 	__ops_parse(pinfo);
495 
496 	__ops_public_key_free(&carg.pkey);
497 	if (carg.subkey.version)
498 		__ops_public_key_free(&carg.subkey);
499 	__ops_user_id_free(&carg.user_id);
500 	__ops_user_attribute_free(&carg.user_attribute);
501 
502 	__ops_parse_info_delete(pinfo);
503 
504 	if (result->invalidc || result->unknownc || !result->validc)
505 		return false;
506 	else
507 		return true;
508 }
509 
510 /**
511    \ingroup HighLevel_Verify
512    \param result Where to put the result
513    \param ring Keyring to use
514    \param cb_get_passphrase Callback to use to get passphrase
515    \note It is the caller's responsibility to free result after use.
516    \sa __ops_validate_result_free()
517 */
518 bool
519 __ops_validate_all_signatures(__ops_validation_t * result,
520 			    const __ops_keyring_t * ring,
521 			    __ops_parse_cb_return_t cb_get_passphrase(const __ops_parser_content_t *, __ops_parse_cb_info_t *)
522 )
523 {
524 	int             n;
525 
526 	(void) memset(result, 0x0, sizeof(*result));
527 	for (n = 0; n < ring->nkeys; ++n)
528 		__ops_validate_key_signatures(result, &ring->keys[n], ring, cb_get_passphrase);
529 	return validate_result_status(result);
530 }
531 
532 /**
533    \ingroup HighLevel_Verify
534    \brief Frees validation result and associated memory
535    \param result Struct to be freed
536    \note Must be called after validation functions
537 */
538 void
539 __ops_validate_result_free(__ops_validation_t * result)
540 {
541 	if (!result)
542 		return;
543 
544 	if (result->valid_sigs)
545 		free_signature_info(result->valid_sigs);
546 	if (result->invalid_sigs)
547 		free_signature_info(result->invalid_sigs);
548 	if (result->unknown_sigs)
549 		free_signature_info(result->unknown_sigs);
550 
551 	free(result);
552 	result = NULL;
553 }
554 
555 /**
556    \ingroup HighLevel_Verify
557    \brief Verifies the signatures in a signed file
558    \param result Where to put the result
559    \param filename Name of file to be validated
560    \param armoured Treat file as armoured, if set
561    \param keyring Keyring to use
562    \return true if signatures validate successfully; false if signatures fail or there are no signatures
563    \note After verification, result holds the details of all keys which
564    have passed, failed and not been recognised.
565    \note It is the caller's responsiblity to call __ops_validate_result_free(result) after use.
566 
567 Example code:
568 \code
569 void example(const char* filename, const int armoured, const __ops_keyring_t* keyring)
570 {
571   __ops_validation_t* result=calloc(1, sizeof(*result));
572 
573   if (__ops_validate_file(result, filename, armoured, keyring)==true)
574   {
575     printf("OK");
576     // look at result for details of keys with good signatures
577   }
578   else
579   {
580     printf("ERR");
581     // look at result for details of failed signatures or unknown signers
582   }
583 
584   __ops_validate_result_free(result);
585 }
586 \endcode
587 */
588 bool
589 __ops_validate_file(__ops_validation_t * result, const char *filename, const int armoured, const __ops_keyring_t * keyring)
590 {
591 	__ops_parse_info_t *pinfo = NULL;
592 	validate_data_cb_t validation;
593 
594 	int             fd = 0;
595 
596 	/* */
597 	fd = __ops_setup_file_read(&pinfo, filename, &validation, validate_data_cb, true);
598 	if (fd < 0)
599 		return false;
600 
601 	/* Set verification reader and handling options */
602 
603 	(void) memset(&validation, 0x0, sizeof(validation));
604 	validation.result = result;
605 	validation.keyring = keyring;
606 	validation.mem = __ops_memory_new();
607 	__ops_memory_init(validation.mem, 128);
608 	/* Note: Coverity incorrectly reports an error that carg.rarg */
609 	/* is never used. */
610 	validation.rarg = pinfo->rinfo.arg;
611 
612 	if (armoured)
613 		__ops_reader_push_dearmour(pinfo);
614 
615 	/* Do the verification */
616 
617 	__ops_parse(pinfo);
618 
619 	if (__ops_get_debug_level(__FILE__)) {
620 		printf("valid=%d, invalid=%d, unknown=%d\n",
621 		       result->validc,
622 		       result->invalidc,
623 		       result->unknownc);
624 	}
625 	/* Tidy up */
626 	if (armoured)
627 		__ops_reader_pop_dearmour(pinfo);
628 	__ops_teardown_file_read(pinfo, fd);
629 
630 	return validate_result_status(result);
631 }
632 
633 /**
634    \ingroup HighLevel_Verify
635    \brief Verifies the signatures in a __ops_memory_t struct
636    \param result Where to put the result
637    \param mem Memory to be validated
638    \param armoured Treat data as armoured, if set
639    \param keyring Keyring to use
640    \return true if signature validates successfully; false if not
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 __ops_validate_result_free(result) after use.
644 */
645 
646 bool
647 __ops_validate_mem(__ops_validation_t *result, __ops_memory_t * mem, const int armoured, const __ops_keyring_t * keyring)
648 {
649 	__ops_parse_info_t *pinfo = NULL;
650 	validate_data_cb_t validation;
651 
652 	/* */
653 	__ops_setup_memory_read(&pinfo, mem, &validation, validate_data_cb, true);
654 
655 	/* Set verification reader and handling options */
656 
657 	(void) memset(&validation, 0x0, sizeof(validation));
658 	validation.result = result;
659 	validation.keyring = keyring;
660 	validation.mem = __ops_memory_new();
661 	__ops_memory_init(validation.mem, 128);
662 	/* Note: Coverity incorrectly reports an error that carg.rarg */
663 	/* is never used. */
664 	validation.rarg = pinfo->rinfo.arg;
665 
666 	if (armoured)
667 		__ops_reader_push_dearmour(pinfo);
668 
669 	/* Do the verification */
670 
671 	__ops_parse(pinfo);
672 
673 	if (__ops_get_debug_level(__FILE__)) {
674 		printf("valid=%d, invalid=%d, unknown=%d\n",
675 		       result->validc,
676 		       result->invalidc,
677 		       result->unknownc);
678 	}
679 	/* Tidy up */
680 	if (armoured)
681 		__ops_reader_pop_dearmour(pinfo);
682 	__ops_teardown_memory_read(pinfo, mem);
683 
684 	return validate_result_status(result);
685 }
686