2 * Copyright (c) 2009 The NetBSD Foundation, Inc.
5 * This code is derived from software contributed to The NetBSD Foundation
6 * by Alistair Crooks (agc@NetBSD.org)
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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.
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.
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.
36 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
37 * use this file except in compliance with the License.
39 * You may obtain a copy of the License at
40 * http://www.apache.org/licenses/LICENSE-2.0
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.
46 * See the License for the specific language governing permissions and
47 * limitations under the License.
51 #ifdef HAVE_SYS_CDEFS_H
52 #include <sys/cdefs.h>
55 #if defined(__NetBSD__)
56 __COPYRIGHT("@(#) Copyright (c) 2009 The NetBSD Foundation, Inc. All rights reserved.");
57 __RCSID("$NetBSD: validate.c,v 1.24 2009/12/07 16:17:17 agc Exp $");
60 #include <sys/types.h>
61 #include <sys/param.h>
75 #include "packet-parse.h"
76 #include "packet-show.h"
78 #include "signature.h"
79 #include "netpgpsdk.h"
80 #include "readerwriter.h"
81 #include "netpgpdefs.h"
92 /* Does the signed hash match the given hash? */
94 check_binary_sig(const unsigned char *data
,
96 const __ops_sig_t
*sig
,
97 const __ops_pubkey_t
*signer
)
99 unsigned char hashout
[OPS_MAX_HASH_SIZE
];
100 unsigned char trailer
[6];
101 unsigned int hashedlen
;
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");
111 hash
.add(&hash
, data
, len
);
112 switch (sig
->info
.version
) {
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);
123 hash
.add(&hash
, sig
->info
.v4_hashed
, sig
->info
.v4_hashlen
);
124 trailer
[0] = 0x04; /* version */
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);
135 (void) fprintf(stderr
, "Invalid signature version %d\n",
140 n
= hash
.finish(&hash
, hashout
);
141 if (__ops_get_debug_level(__FILE__
)) {
142 printf("check_binary_sig: hash length %" PRIsize
"u\n",
145 return __ops_check_sig(hashout
, n
, sig
, signer
);
149 keydata_reader(void *dest
, size_t length
, __ops_error_t
**errors
,
150 __ops_reader_t
*readinfo
,
151 __ops_cbdata_t
*cbinfo
)
153 validate_reader_t
*reader
= __ops_reader_get_arg(readinfo
);
157 if (reader
->offset
== reader
->key
->packets
[reader
->packet
].length
) {
161 if (reader
->packet
== reader
->key
->packetc
) {
166 * we should never be asked to cross a packet boundary in a single
169 if (reader
->key
->packets
[reader
->packet
].length
<
170 reader
->offset
+ length
) {
171 (void) fprintf(stderr
, "keydata_reader: weird length\n");
176 &reader
->key
->packets
[reader
->packet
].raw
[reader
->offset
],
178 reader
->offset
+= length
;
184 free_sig_info(__ops_sig_info_t
*sig
)
186 free(sig
->v4_hashed
);
191 copy_sig_info(__ops_sig_info_t
*dst
, const __ops_sig_info_t
*src
)
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");
197 (void) memcpy(dst
->v4_hashed
, src
->v4_hashed
, src
->v4_hashlen
);
202 add_sig_to_list(const __ops_sig_info_t
*sig
, __ops_sig_info_t
**sigs
,
205 __ops_sig_info_t
*newsigs
;
208 newsigs
= calloc(*count
+ 1, sizeof(__ops_sig_info_t
));
210 newsigs
= realloc(*sigs
,
211 (*count
+ 1) * sizeof(__ops_sig_info_t
));
213 if (newsigs
!= NULL
) {
215 copy_sig_info(&(*sigs
)[*count
], sig
);
224 __ops_validate_key_cb(const __ops_packet_t
*pkt
, __ops_cbdata_t
*cbinfo
)
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
;
235 if (__ops_get_debug_level(__FILE__
)) {
236 (void) fprintf(io
->errs
, "%s\n",
237 __ops_show_packet_tag(pkt
->tag
));
239 key
= __ops_callback_arg(cbinfo
);
240 errors
= __ops_callback_errors(cbinfo
);
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");
248 key
->pubkey
= content
->pubkey
;
249 return OPS_KEEP_MEMORY
;
251 case OPS_PTAG_CT_PUBLIC_SUBKEY
:
252 if (key
->subkey
.version
) {
253 __ops_pubkey_free(&key
->subkey
);
255 key
->subkey
= content
->pubkey
;
256 return OPS_KEEP_MEMORY
;
258 case OPS_PTAG_CT_SECRET_KEY
:
259 key
->seckey
= content
->seckey
;
260 key
->pubkey
= key
->seckey
.pubkey
;
261 return OPS_KEEP_MEMORY
;
263 case OPS_PTAG_CT_USER_ID
:
264 if (key
->userid
.userid
) {
265 __ops_userid_free(&key
->userid
);
267 key
->userid
= content
->userid
;
269 return OPS_KEEP_MEMORY
;
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");
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
);
282 key
->userattr
= content
->userattr
;
283 key
->last_seen
= ATTRIBUTE
;
284 return OPS_KEEP_MEMORY
;
286 case OPS_PTAG_CT_SIGNATURE
: /* V3 sigs */
287 case OPS_PTAG_CT_SIGNATURE_FOOTER
: /* V4 sigs */
289 signer
= __ops_getkeybyid(io
, key
->keyring
,
290 content
->sig
.info
.signer_id
,
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");
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
,
312 __ops_get_pubkey(signer
),
313 key
->reader
->key
->packets
[
314 key
->reader
->packet
].raw
) :
315 __ops_check_userattrcert_sig(&key
->pubkey
,
318 __ops_get_pubkey(signer
),
319 key
->reader
->key
->packets
[
320 key
->reader
->packet
].raw
);
325 * XXX: we should also check that the signer is the
326 * key we are validating, I think.
328 valid
= __ops_check_subkey_sig(&key
->pubkey
,
331 __ops_get_pubkey(signer
),
332 key
->reader
->key
->packets
[
333 key
->reader
->packet
].raw
);
334 /* XXX - agc - put subkey logic here? */
338 valid
= __ops_check_direct_sig(&key
->pubkey
,
340 __ops_get_pubkey(signer
),
341 key
->reader
->key
->packets
[
342 key
->reader
->packet
].raw
);
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
);
357 OPS_ERROR_1(errors
, OPS_E_UNIMPLEMENTED
,
358 "Unexpected signature type 0x%02x\n",
359 content
->sig
.info
.type
);
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");
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");
381 case OPS_PARSER_PTAG
:
382 case OPS_PTAG_CT_SIGNATURE_HEADER
:
383 case OPS_PARSER_PACKET_END
:
386 case OPS_GET_PASSPHRASE
:
387 if (key
->getpassphrase
) {
388 return key
->getpassphrase(pkt
, cbinfo
);
393 (void) fprintf(stderr
, "unexpected tag=0x%x\n", pkt
->tag
);
396 return OPS_RELEASE_MEMORY
;
400 validate_data_cb(const __ops_packet_t
*pkt
, __ops_cbdata_t
*cbinfo
)
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
;
411 if (__ops_get_debug_level(__FILE__
)) {
412 (void) fprintf(io
->errs
, "validate_data_cb: %s\n",
413 __ops_show_packet_tag(pkt
->tag
));
415 data
= __ops_callback_arg(cbinfo
);
416 errors
= __ops_callback_errors(cbinfo
);
418 case OPS_PTAG_CT_SIGNED_CLEARTEXT_HEADER
:
420 * ignore - this gives us the "Armor Header" line "Hash:
425 case OPS_PTAG_CT_LITDATA_HEADER
:
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
;
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
;
443 case OPS_PTAG_CT_SIGNED_CLEARTEXT_TRAILER
:
444 /* this gives us an __ops_hash_t struct */
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");
461 signer
= __ops_getkeybyid(io
, data
->keyring
,
462 content
->sig
.info
.signer_id
, &from
);
464 OPS_ERROR(errors
, OPS_E_V_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");
474 switch (content
->sig
.info
.type
) {
477 if (__ops_mem_len(data
->mem
) == 0 &&
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",
484 data
->mem
= __ops_memory_new();
485 __ops_mem_readfile(data
->mem
, data
->detachname
);
487 valid
= check_binary_sig(__ops_mem_data(data
->mem
),
488 __ops_mem_len(data
->mem
),
490 __ops_get_pubkey(signer
));
494 OPS_ERROR_1(errors
, OPS_E_UNIMPLEMENTED
,
495 "No Sig Verification type 0x%02x yet\n",
496 content
->sig
.info
.type
);
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");
509 OPS_ERROR(errors
, OPS_E_V_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");
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
:
528 case OPS_PARSER_PACKET_END
:
532 OPS_ERROR(errors
, OPS_E_V_NO_SIGNATURE
, "No signature");
535 return OPS_RELEASE_MEMORY
;
539 keydata_destroyer(__ops_reader_t
*readinfo
)
541 free(__ops_reader_get_arg(readinfo
));
545 __ops_keydata_reader_set(__ops_stream_t
*stream
, const __ops_key_t
*key
)
547 validate_reader_t
*data
;
549 if ((data
= calloc(1, sizeof(*data
))) == NULL
) {
550 (void) fprintf(stderr
, "__ops_keydata_reader_set: bad alloc\n");
555 __ops_reader_set(stream
, keydata_reader
, keydata_destroyer
, data
);
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
567 validate_result_status(__ops_validation_t
*val
)
569 return val
->validc
&& !val
->invalidc
&& !val
->unknownc
;
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()
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
*,
590 __ops_stream_t
*stream
;
591 validate_key_cb_t keysigs
;
592 const int printerrors
= 1;
594 (void) memset(&keysigs
, 0x0, sizeof(keysigs
));
595 keysigs
.result
= result
;
596 keysigs
.getpassphrase
= cb_get_passphrase
;
598 stream
= __ops_new(sizeof(*stream
));
599 /* __ops_parse_options(&opt,OPS_PTAG_CT_SIGNATURE,OPS_PARSE_PARSED); */
601 keysigs
.keyring
= keyring
;
603 __ops_set_callback(stream
, __ops_validate_key_cb
, &keysigs
);
604 stream
->readinfo
.accumulate
= 1;
605 __ops_keydata_reader_set(stream
, key
);
607 /* Note: Coverity incorrectly reports an error that keysigs.reader */
609 keysigs
.reader
= stream
->readinfo
.arg
;
611 __ops_parse(stream
, !printerrors
);
613 __ops_pubkey_free(&keysigs
.pubkey
);
614 if (keysigs
.subkey
.version
) {
615 __ops_pubkey_free(&keysigs
.subkey
);
617 __ops_userid_free(&keysigs
.userid
);
618 __ops_userattr_free(&keysigs
.userattr
);
620 __ops_stream_delete(stream
);
622 return (!result
->invalidc
&& !result
->unknownc
&& result
->validc
);
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()
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
*,
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
,
646 return validate_result_status(result
);
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
656 __ops_validate_result_free(__ops_validation_t
*result
)
658 if (result
!= NULL
) {
659 if (result
->valid_sigs
) {
660 free_sig_info(result
->valid_sigs
);
662 if (result
->invalid_sigs
) {
663 free_sig_info(result
->invalid_sigs
);
665 if (result
->unknown_sigs
) {
666 free_sig_info(result
->unknown_sigs
);
669 /* result = NULL; - XXX unnecessary */
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.
688 __ops_validate_file(__ops_io_t
*io
,
689 __ops_validation_t
*result
,
693 const __ops_keyring_t
*keyring
)
695 validate_data_cb_t validation
;
696 __ops_stream_t
*parse
= NULL
;
698 const int printerrors
= 1;
701 char origfile
[MAXPATHLEN
];
708 #define SIG_OVERHEAD 284 /* XXX - depends on sig size? */
710 realarmour
= armoured
;
711 if (stat(infile
, &st
) < 0) {
712 (void) fprintf(io
->errs
, "can't validate \"%s\"\n", infile
);
715 sigsize
= st
.st_size
;
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
);
725 if (strcmp(&origfile
[cc
- 4], ".asc") == 0) {
729 (void) memset(&validation
, 0x0, sizeof(validation
));
731 infd
= __ops_setup_file_read(io
, &parse
, infile
, &validation
,
732 validate_data_cb
, 1);
737 validation
.detachname
= detachname
;
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 */
746 validation
.reader
= parse
->readinfo
.arg
;
749 __ops_reader_push_dearmour(parse
);
752 /* Do the verification */
753 __ops_parse(parse
, !printerrors
);
757 __ops_reader_pop_dearmour(parse
);
759 __ops_teardown_file_read(parse
, infd
);
761 ret
= validate_result_status(result
);
763 /* this is triggered only for --cat output */
765 /* need to send validated output somewhere */
766 if (strcmp(outfile
, "-") == 0) {
767 outfd
= STDOUT_FILENO
;
769 outfd
= open(outfile
, O_WRONLY
| O_CREAT
, 0666);
772 /* even if the signature was good, we can't
773 * write the file, so send back a bad return
776 } else if (validate_result_status(result
)) {
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
);
786 (void) fprintf(io
->errs
,
787 "netpgp: short write\n");
792 if (strcmp(outfile
, "-") != 0) {
797 __ops_memory_free(validation
.mem
);
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.
816 __ops_validate_mem(__ops_io_t
*io
,
817 __ops_validation_t
*result
,
819 __ops_memory_t
**cat
,
821 const __ops_keyring_t
*keyring
)
823 validate_data_cb_t validation
;
824 __ops_stream_t
*stream
= NULL
;
825 const int printerrors
= 1;
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 */
836 validation
.reader
= stream
->readinfo
.arg
;
839 __ops_reader_push_dearmour(stream
);
842 /* Do the verification */
843 __ops_parse(stream
, !printerrors
);
847 __ops_reader_pop_dearmour(stream
);
849 __ops_teardown_memory_read(stream
, mem
);
851 /* this is triggered only for --cat output */
853 /* need to send validated output somewhere */
854 *cat
= validation
.mem
;
856 __ops_memory_free(validation
.mem
);
859 return validate_result_status(result
);