Sync usage with man page.
[netbsd-mini2440.git] / crypto / external / bsd / netpgp / dist / src / lib / validate.c
blob9f85c2127effae8fade3019fc51518aea2e3817e
1 /*-
2 * Copyright (c) 2009 The NetBSD Foundation, Inc.
3 * All rights reserved.
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
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.
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.
49 #include "config.h"
51 #ifdef HAVE_SYS_CDEFS_H
52 #include <sys/cdefs.h>
53 #endif
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 $");
58 #endif
60 #include <sys/types.h>
61 #include <sys/param.h>
62 #include <sys/stat.h>
64 #include <string.h>
65 #include <stdio.h>
67 #ifdef HAVE_UNISTD_H
68 #include <unistd.h>
69 #endif
71 #ifdef HAVE_FCNTL_H
72 #include <fcntl.h>
73 #endif
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"
87 #ifdef HAVE_FCNTL_H
88 #include <fcntl.h>
89 #endif
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)
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;
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;
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;
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;
134 default:
135 (void) fprintf(stderr, "Invalid signature version %d\n",
136 sig->info.version);
137 return 0;
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);
145 return __ops_check_sig(hashout, n, sig, signer);
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)
153 validate_reader_t *reader = __ops_reader_get_arg(readinfo);
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;
161 if (reader->packet == reader->key->packetc) {
162 return 0;
166 * we should never be asked to cross a packet boundary in a single
167 * read
169 if (reader->key->packets[reader->packet].length <
170 reader->offset + length) {
171 (void) fprintf(stderr, "keydata_reader: weird length\n");
172 return 0;
175 (void) memcpy(dest,
176 &reader->key->packets[reader->packet].raw[reader->offset],
177 length);
178 reader->offset += length;
180 return length;
183 static void
184 free_sig_info(__ops_sig_info_t *sig)
186 free(sig->v4_hashed);
187 free(sig);
190 static void
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");
196 } else {
197 (void) memcpy(dst->v4_hashed, src->v4_hashed, src->v4_hashlen);
201 static int
202 add_sig_to_list(const __ops_sig_info_t *sig, __ops_sig_info_t **sigs,
203 unsigned *count)
205 __ops_sig_info_t *newsigs;
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));
213 if (newsigs != NULL) {
214 *sigs = newsigs;
215 copy_sig_info(&(*sigs)[*count], sig);
216 *count += 1;
217 return 1;
219 return 0;
223 __ops_cb_ret_t
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;
230 __ops_io_t *io;
231 unsigned from;
232 unsigned valid = 0;
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));
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;
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;
268 key->last_seen = ID;
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");
275 return OPS_FINISHED;
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 */
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;
300 break;
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;
323 case OPS_SIG_SUBKEY:
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,
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;
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;
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;
356 default:
357 OPS_ERROR_1(errors, OPS_E_UNIMPLEMENTED,
358 "Unexpected signature type 0x%02x\n",
359 content->sig.info.type);
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");
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");
378 break;
380 /* ignore these */
381 case OPS_PARSER_PTAG:
382 case OPS_PTAG_CT_SIGNATURE_HEADER:
383 case OPS_PARSER_PACKET_END:
384 break;
386 case OPS_GET_PASSPHRASE:
387 if (key->getpassphrase) {
388 return key->getpassphrase(pkt, cbinfo);
390 break;
392 default:
393 (void) fprintf(stderr, "unexpected tag=0x%x\n", pkt->tag);
394 return OPS_FINISHED;
396 return OPS_RELEASE_MEMORY;
399 __ops_cb_ret_t
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;
406 __ops_io_t *io;
407 unsigned from;
408 unsigned valid = 0;
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));
415 data = __ops_callback_arg(cbinfo);
416 errors = __ops_callback_errors(cbinfo);
417 switch (pkt->tag) {
418 case OPS_PTAG_CT_SIGNED_CLEARTEXT_HEADER:
420 * ignore - this gives us the "Armor Header" line "Hash:
421 * SHA1" or similar
423 break;
425 case OPS_PTAG_CT_LITDATA_HEADER:
426 /* ignore */
427 break;
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 */
445 break;
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");
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");
472 break;
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);
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;
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;
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");
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");
518 break;
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;
528 case OPS_PARSER_PACKET_END:
529 break;
531 default:
532 OPS_ERROR(errors, OPS_E_V_NO_SIGNATURE, "No signature");
533 break;
535 return OPS_RELEASE_MEMORY;
538 static void
539 keydata_destroyer(__ops_reader_t *readinfo)
541 free(__ops_reader_get_arg(readinfo));
544 void
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");
551 } else {
552 data->key = key;
553 data->packet = 0;
554 data->offset = 0;
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
566 static unsigned
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()
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 *))
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 */
608 /* is never used. */
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()
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 *))
639 unsigned n;
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);
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
655 void
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);
668 free(result);
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.
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)
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;
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);
713 return 0;
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);
725 if (strcmp(&origfile[cc - 4], ".asc") == 0) {
726 realarmour = 1;
729 (void) memset(&validation, 0x0, sizeof(validation));
731 infd = __ops_setup_file_read(io, &parse, infile, &validation,
732 validate_data_cb, 1);
733 if (infd < 0) {
734 return 0;
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 */
745 /* is never used. */
746 validation.reader = parse->readinfo.arg;
748 if (realarmour) {
749 __ops_reader_push_dearmour(parse);
752 /* Do the verification */
753 __ops_parse(parse, !printerrors);
755 /* Tidy up */
756 if (realarmour) {
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 */
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);
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;
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;
792 if (strcmp(outfile, "-") != 0) {
793 (void) close(outfd);
797 __ops_memory_free(validation.mem);
798 return ret;
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.
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)
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 */
835 /* is never used. */
836 validation.reader = stream->readinfo.arg;
838 if (armoured) {
839 __ops_reader_push_dearmour(stream);
842 /* Do the verification */
843 __ops_parse(stream, !printerrors);
845 /* Tidy up */
846 if (armoured) {
847 __ops_reader_pop_dearmour(stream);
849 __ops_teardown_memory_read(stream, mem);
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);
859 return validate_result_status(result);