12232f800Sagc /*-
22232f800Sagc * Copyright (c) 2009 The NetBSD Foundation, Inc.
32232f800Sagc * All rights reserved.
42232f800Sagc *
52232f800Sagc * This code is derived from software contributed to The NetBSD Foundation
62232f800Sagc * by Alistair Crooks (agc@NetBSD.org)
72232f800Sagc *
82232f800Sagc * Redistribution and use in source and binary forms, with or without
92232f800Sagc * modification, are permitted provided that the following conditions
102232f800Sagc * are met:
112232f800Sagc * 1. Redistributions of source code must retain the above copyright
122232f800Sagc * notice, this list of conditions and the following disclaimer.
132232f800Sagc * 2. Redistributions in binary form must reproduce the above copyright
142232f800Sagc * notice, this list of conditions and the following disclaimer in the
152232f800Sagc * documentation and/or other materials provided with the distribution.
162232f800Sagc *
172232f800Sagc * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
182232f800Sagc * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
192232f800Sagc * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
202232f800Sagc * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
212232f800Sagc * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
222232f800Sagc * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
232232f800Sagc * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
242232f800Sagc * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
252232f800Sagc * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
262232f800Sagc * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
272232f800Sagc * POSSIBILITY OF SUCH DAMAGE.
282232f800Sagc */
2993bf6008Sagc /*
3093bf6008Sagc * Copyright (c) 2005-2008 Nominet UK (www.nic.uk)
3193bf6008Sagc * All rights reserved.
3293bf6008Sagc * Contributors: Ben Laurie, Rachel Willmer. The Contributors have asserted
3393bf6008Sagc * their moral rights under the UK Copyright Design and Patents Act 1988 to
3493bf6008Sagc * be recorded as the authors of this copyright work.
3593bf6008Sagc *
3693bf6008Sagc * Licensed under the Apache License, Version 2.0 (the "License"); you may not
3793bf6008Sagc * use this file except in compliance with the License.
3893bf6008Sagc *
3993bf6008Sagc * You may obtain a copy of the License at
4093bf6008Sagc * http://www.apache.org/licenses/LICENSE-2.0
4193bf6008Sagc *
4293bf6008Sagc * Unless required by applicable law or agreed to in writing, software
4393bf6008Sagc * distributed under the License is distributed on an "AS IS" BASIS,
4493bf6008Sagc * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
4593bf6008Sagc *
4693bf6008Sagc * See the License for the specific language governing permissions and
4793bf6008Sagc * limitations under the License.
4893bf6008Sagc */
4993bf6008Sagc #include "config.h"
5093bf6008Sagc
5157324b9fSagc #ifdef HAVE_SYS_CDEFS_H
5257324b9fSagc #include <sys/cdefs.h>
5357324b9fSagc #endif
5457324b9fSagc
5557324b9fSagc #if defined(__NetBSD__)
5657324b9fSagc __COPYRIGHT("@(#) Copyright (c) 2009 The NetBSD Foundation, Inc. All rights reserved.");
57*94fcde8eSchristos __RCSID("$NetBSD: validate.c,v 1.44 2012/03/05 02:20:18 christos Exp $");
5857324b9fSagc #endif
5957324b9fSagc
60bcfd8565Sagc #include <sys/types.h>
61bcfd8565Sagc #include <sys/param.h>
62bcfd8565Sagc #include <sys/stat.h>
63bcfd8565Sagc
6493bf6008Sagc #include <string.h>
65bcfd8565Sagc #include <stdio.h>
6693bf6008Sagc
6757324b9fSagc #ifdef HAVE_UNISTD_H
6857324b9fSagc #include <unistd.h>
6957324b9fSagc #endif
7057324b9fSagc
71648b5a99Sagc #ifdef HAVE_FCNTL_H
72648b5a99Sagc #include <fcntl.h>
73648b5a99Sagc #endif
74648b5a99Sagc
750c310959Sagc #include "packet-parse.h"
760c310959Sagc #include "packet-show.h"
770c310959Sagc #include "keyring.h"
780c310959Sagc #include "signature.h"
790c310959Sagc #include "netpgpsdk.h"
800c310959Sagc #include "readerwriter.h"
810c310959Sagc #include "netpgpdefs.h"
820c310959Sagc #include "memory.h"
834b3a3e18Sagc #include "packet.h"
844b3a3e18Sagc #include "crypto.h"
850c310959Sagc #include "validate.h"
860c310959Sagc
87648b5a99Sagc #ifdef HAVE_FCNTL_H
88648b5a99Sagc #include <fcntl.h>
89648b5a99Sagc #endif
90648b5a99Sagc
9193bf6008Sagc
9293bf6008Sagc static int
keydata_reader(pgp_stream_t * stream,void * dest,size_t length,pgp_error_t ** errors,pgp_reader_t * readinfo,pgp_cbdata_t * cbinfo)93b0df0a22Sagc keydata_reader(pgp_stream_t *stream, void *dest, size_t length, pgp_error_t **errors,
94fc1f8641Sagc pgp_reader_t *readinfo,
95fc1f8641Sagc pgp_cbdata_t *cbinfo)
9693bf6008Sagc {
97fc1f8641Sagc validate_reader_t *reader = pgp_reader_get_arg(readinfo);
9893bf6008Sagc
99b0df0a22Sagc __PGP_USED(stream);
100fc1f8641Sagc __PGP_USED(errors);
101fc1f8641Sagc __PGP_USED(cbinfo);
10293bf6008Sagc if (reader->offset == reader->key->packets[reader->packet].length) {
103bcfd8565Sagc reader->packet += 1;
10493bf6008Sagc reader->offset = 0;
10593bf6008Sagc }
10641335e2dSagc if (reader->packet == reader->key->packetc) {
10793bf6008Sagc return 0;
108bcfd8565Sagc }
10993bf6008Sagc
11093bf6008Sagc /*
11193bf6008Sagc * we should never be asked to cross a packet boundary in a single
11293bf6008Sagc * read
11393bf6008Sagc */
114bcfd8565Sagc if (reader->key->packets[reader->packet].length <
115bcfd8565Sagc reader->offset + length) {
116bcfd8565Sagc (void) fprintf(stderr, "keydata_reader: weird length\n");
117bcfd8565Sagc return 0;
118bcfd8565Sagc }
11993bf6008Sagc
120de704779Sagc (void) memcpy(dest,
121de704779Sagc &reader->key->packets[reader->packet].raw[reader->offset],
122de704779Sagc length);
12369d4f30fSagc reader->offset += (unsigned)length;
12493bf6008Sagc
12569d4f30fSagc return (int)length;
12693bf6008Sagc }
12793bf6008Sagc
12893bf6008Sagc static void
free_sig_info(pgp_sig_info_t * sig)129fc1f8641Sagc free_sig_info(pgp_sig_info_t *sig)
13093bf6008Sagc {
13183cfb9deSagc free(sig->v4_hashed);
13283cfb9deSagc free(sig);
13393bf6008Sagc }
13493bf6008Sagc
13593bf6008Sagc static void
copy_sig_info(pgp_sig_info_t * dst,const pgp_sig_info_t * src)136fc1f8641Sagc copy_sig_info(pgp_sig_info_t *dst, const pgp_sig_info_t *src)
13793bf6008Sagc {
13893bf6008Sagc (void) memcpy(dst, src, sizeof(*src));
13983cfb9deSagc if ((dst->v4_hashed = calloc(1, src->v4_hashlen)) == NULL) {
14083cfb9deSagc (void) fprintf(stderr, "copy_sig_info: bad alloc\n");
14183cfb9deSagc } else {
1426715e11aSagc (void) memcpy(dst->v4_hashed, src->v4_hashed, src->v4_hashlen);
14393bf6008Sagc }
14483cfb9deSagc }
14593bf6008Sagc
14683cfb9deSagc static int
add_sig_to_list(const pgp_sig_info_t * sig,pgp_sig_info_t ** sigs,unsigned * count)147fc1f8641Sagc add_sig_to_list(const pgp_sig_info_t *sig, pgp_sig_info_t **sigs,
14893bf6008Sagc unsigned *count)
14993bf6008Sagc {
150fc1f8641Sagc pgp_sig_info_t *newsigs;
15183cfb9deSagc
15293bf6008Sagc if (*count == 0) {
153fc1f8641Sagc newsigs = calloc(*count + 1, sizeof(pgp_sig_info_t));
15493bf6008Sagc } else {
15583cfb9deSagc newsigs = realloc(*sigs,
156fc1f8641Sagc (*count + 1) * sizeof(pgp_sig_info_t));
15793bf6008Sagc }
158600b302bSagc if (newsigs == NULL) {
159600b302bSagc (void) fprintf(stderr, "add_sig_to_list: alloc failure\n");
160600b302bSagc return 0;
161600b302bSagc }
16283cfb9deSagc *sigs = newsigs;
1633326c4c5Sagc copy_sig_info(&(*sigs)[*count], sig);
16493bf6008Sagc *count += 1;
16583cfb9deSagc return 1;
16683cfb9deSagc }
167600b302bSagc
168600b302bSagc /*
169600b302bSagc The hash value is calculated by the following method:
170600b302bSagc + hash the data using the given digest algorithm
171600b302bSagc + hash the hash value onto the end
172600b302bSagc + hash the trailer - 6 bytes
173fc1f8641Sagc [PGP_V4][0xff][len >> 24][len >> 16][len >> 8][len & 0xff]
174600b302bSagc to give the final hash value that is checked against the one in the signature
175600b302bSagc */
176600b302bSagc
177600b302bSagc /* Does the signed hash match the given hash? */
178600b302bSagc unsigned
check_binary_sig(const uint8_t * data,const unsigned len,const pgp_sig_t * sig,const pgp_pubkey_t * signer)179b15ec256Sagc check_binary_sig(const uint8_t *data,
180600b302bSagc const unsigned len,
181fc1f8641Sagc const pgp_sig_t *sig,
182fc1f8641Sagc const pgp_pubkey_t *signer)
183600b302bSagc {
184b15ec256Sagc unsigned hashedlen;
185fc1f8641Sagc pgp_hash_t hash;
186600b302bSagc unsigned n;
187fc1f8641Sagc uint8_t hashout[PGP_MAX_HASH_SIZE];
188b15ec256Sagc uint8_t trailer[6];
189600b302bSagc
190fc1f8641Sagc pgp_hash_any(&hash, sig->info.hash_alg);
191600b302bSagc if (!hash.init(&hash)) {
192600b302bSagc (void) fprintf(stderr, "check_binary_sig: bad hash init\n");
193600b302bSagc return 0;
194600b302bSagc }
195600b302bSagc hash.add(&hash, data, len);
196600b302bSagc switch (sig->info.version) {
197fc1f8641Sagc case PGP_V3:
198600b302bSagc trailer[0] = sig->info.type;
199600b302bSagc trailer[1] = (unsigned)(sig->info.birthtime) >> 24;
200600b302bSagc trailer[2] = (unsigned)(sig->info.birthtime) >> 16;
201600b302bSagc trailer[3] = (unsigned)(sig->info.birthtime) >> 8;
202b15ec256Sagc trailer[4] = (uint8_t)(sig->info.birthtime);
203600b302bSagc hash.add(&hash, trailer, 5);
204600b302bSagc break;
205600b302bSagc
206fc1f8641Sagc case PGP_V4:
207fc1f8641Sagc if (pgp_get_debug_level(__FILE__)) {
20847561e26Sagc hexdump(stderr, "v4 hash", sig->info.v4_hashed,
209600b302bSagc sig->info.v4_hashlen);
210600b302bSagc }
21169d4f30fSagc hash.add(&hash, sig->info.v4_hashed, (unsigned)sig->info.v4_hashlen);
212600b302bSagc trailer[0] = 0x04; /* version */
213600b302bSagc trailer[1] = 0xFF;
21469d4f30fSagc hashedlen = (unsigned)sig->info.v4_hashlen;
21569d4f30fSagc trailer[2] = (uint8_t)(hashedlen >> 24);
21669d4f30fSagc trailer[3] = (uint8_t)(hashedlen >> 16);
21769d4f30fSagc trailer[4] = (uint8_t)(hashedlen >> 8);
21869d4f30fSagc trailer[5] = (uint8_t)(hashedlen);
219600b302bSagc hash.add(&hash, trailer, 6);
220600b302bSagc break;
221600b302bSagc
222600b302bSagc default:
223600b302bSagc (void) fprintf(stderr, "Invalid signature version %d\n",
224600b302bSagc sig->info.version);
22583cfb9deSagc return 0;
22693bf6008Sagc }
22793bf6008Sagc
228600b302bSagc n = hash.finish(&hash, hashout);
229fc1f8641Sagc if (pgp_get_debug_level(__FILE__)) {
23047561e26Sagc hexdump(stdout, "hash out", hashout, n);
231600b302bSagc }
232fc1f8641Sagc return pgp_check_sig(hashout, n, sig, signer);
233600b302bSagc }
23493bf6008Sagc
235fc1f8641Sagc pgp_cb_ret_t
pgp_validate_key_cb(const pgp_packet_t * pkt,pgp_cbdata_t * cbinfo)236fc1f8641Sagc pgp_validate_key_cb(const pgp_packet_t *pkt, pgp_cbdata_t *cbinfo)
23793bf6008Sagc {
238fc1f8641Sagc const pgp_contents_t *content = &pkt->u;
239fc1f8641Sagc const pgp_key_t *signer;
24057324b9fSagc validate_key_cb_t *key;
241fc1f8641Sagc pgp_pubkey_t *sigkey;
242fc1f8641Sagc pgp_error_t **errors;
243fc1f8641Sagc pgp_io_t *io;
244183e04ebSagc unsigned from;
2454b3a3e18Sagc unsigned valid = 0;
24693bf6008Sagc
247d21b929eSagc io = cbinfo->io;
248fc1f8641Sagc if (pgp_get_debug_level(__FILE__)) {
249d21b929eSagc (void) fprintf(io->errs, "%s\n",
250fc1f8641Sagc pgp_show_packet_tag(pkt->tag));
251de704779Sagc }
252fc1f8641Sagc key = pgp_callback_arg(cbinfo);
253fc1f8641Sagc errors = pgp_callback_errors(cbinfo);
2543326c4c5Sagc switch (pkt->tag) {
255fc1f8641Sagc case PGP_PTAG_CT_PUBLIC_KEY:
2560c310959Sagc if (key->pubkey.version != 0) {
257d21b929eSagc (void) fprintf(io->errs,
258fc1f8641Sagc "pgp_validate_key_cb: version bad\n");
259fc1f8641Sagc return PGP_FINISHED;
260bcfd8565Sagc }
2610c310959Sagc key->pubkey = content->pubkey;
262fc1f8641Sagc return PGP_KEEP_MEMORY;
26393bf6008Sagc
264fc1f8641Sagc case PGP_PTAG_CT_PUBLIC_SUBKEY:
26557324b9fSagc if (key->subkey.version) {
266fc1f8641Sagc pgp_pubkey_free(&key->subkey);
26757324b9fSagc }
268bcfd8565Sagc key->subkey = content->pubkey;
269fc1f8641Sagc return PGP_KEEP_MEMORY;
27093bf6008Sagc
271fc1f8641Sagc case PGP_PTAG_CT_SECRET_KEY:
2720c310959Sagc key->seckey = content->seckey;
2730c310959Sagc key->pubkey = key->seckey.pubkey;
274fc1f8641Sagc return PGP_KEEP_MEMORY;
27593bf6008Sagc
276fc1f8641Sagc case PGP_PTAG_CT_USER_ID:
277d427c17dSagc if (key->userid) {
278fc1f8641Sagc pgp_userid_free(&key->userid);
279d21b929eSagc }
28057324b9fSagc key->userid = content->userid;
28193bf6008Sagc key->last_seen = ID;
282fc1f8641Sagc return PGP_KEEP_MEMORY;
28393bf6008Sagc
284fc1f8641Sagc case PGP_PTAG_CT_USER_ATTR:
285d427c17dSagc if (content->userattr.len == 0) {
286d21b929eSagc (void) fprintf(io->errs,
287fc1f8641Sagc "pgp_validate_key_cb: user attribute length 0");
288fc1f8641Sagc return PGP_FINISHED;
289bcfd8565Sagc }
290d21b929eSagc (void) fprintf(io->outs, "user attribute, length=%d\n",
291d427c17dSagc (int) content->userattr.len);
292d427c17dSagc if (key->userattr.len) {
293fc1f8641Sagc pgp_data_free(&key->userattr);
294d21b929eSagc }
29557324b9fSagc key->userattr = content->userattr;
29693bf6008Sagc key->last_seen = ATTRIBUTE;
297fc1f8641Sagc return PGP_KEEP_MEMORY;
29893bf6008Sagc
299fc1f8641Sagc case PGP_PTAG_CT_SIGNATURE: /* V3 sigs */
300fc1f8641Sagc case PGP_PTAG_CT_SIGNATURE_FOOTER: /* V4 sigs */
301183e04ebSagc from = 0;
302fc1f8641Sagc signer = pgp_getkeybyid(io, key->keyring,
303183e04ebSagc content->sig.info.signer_id,
30469d4f30fSagc &from, &sigkey);
30593bf6008Sagc if (!signer) {
30683cfb9deSagc if (!add_sig_to_list(&content->sig.info,
30793bf6008Sagc &key->result->unknown_sigs,
30883cfb9deSagc &key->result->unknownc)) {
30983cfb9deSagc (void) fprintf(io->errs,
310fc1f8641Sagc "pgp_validate_key_cb: user attribute length 0");
311fc1f8641Sagc return PGP_FINISHED;
31283cfb9deSagc }
31393bf6008Sagc break;
31493bf6008Sagc }
31569d4f30fSagc if (sigkey == &signer->enckey) {
31669d4f30fSagc (void) fprintf(io->errs,
31769d4f30fSagc "WARNING: signature made with encryption key\n");
31869d4f30fSagc }
3193326c4c5Sagc switch (content->sig.info.type) {
320fc1f8641Sagc case PGP_CERT_GENERIC:
321fc1f8641Sagc case PGP_CERT_PERSONA:
322fc1f8641Sagc case PGP_CERT_CASUAL:
323fc1f8641Sagc case PGP_CERT_POSITIVE:
324fc1f8641Sagc case PGP_SIG_REV_CERT:
3250c310959Sagc valid = (key->last_seen == ID) ?
326fc1f8641Sagc pgp_check_useridcert_sig(&key->pubkey,
327d427c17dSagc key->userid,
3283326c4c5Sagc &content->sig,
329fc1f8641Sagc pgp_get_pubkey(signer),
33057324b9fSagc key->reader->key->packets[
33157324b9fSagc key->reader->packet].raw) :
332fc1f8641Sagc pgp_check_userattrcert_sig(&key->pubkey,
33357324b9fSagc &key->userattr,
3343326c4c5Sagc &content->sig,
335fc1f8641Sagc pgp_get_pubkey(signer),
33657324b9fSagc key->reader->key->packets[
33757324b9fSagc key->reader->packet].raw);
33893bf6008Sagc break;
33993bf6008Sagc
340fc1f8641Sagc case PGP_SIG_SUBKEY:
34193bf6008Sagc /*
34293bf6008Sagc * XXX: we should also check that the signer is the
34393bf6008Sagc * key we are validating, I think.
34493bf6008Sagc */
345fc1f8641Sagc valid = pgp_check_subkey_sig(&key->pubkey,
34657324b9fSagc &key->subkey,
3473326c4c5Sagc &content->sig,
348fc1f8641Sagc pgp_get_pubkey(signer),
34957324b9fSagc key->reader->key->packets[
35057324b9fSagc key->reader->packet].raw);
35193bf6008Sagc break;
35293bf6008Sagc
353fc1f8641Sagc case PGP_SIG_DIRECT:
354fc1f8641Sagc valid = pgp_check_direct_sig(&key->pubkey,
3550c310959Sagc &content->sig,
356fc1f8641Sagc pgp_get_pubkey(signer),
35757324b9fSagc key->reader->key->packets[
35857324b9fSagc key->reader->packet].raw);
35993bf6008Sagc break;
36093bf6008Sagc
361fc1f8641Sagc case PGP_SIG_STANDALONE:
362fc1f8641Sagc case PGP_SIG_PRIMARY:
363fc1f8641Sagc case PGP_SIG_REV_KEY:
364fc1f8641Sagc case PGP_SIG_REV_SUBKEY:
365fc1f8641Sagc case PGP_SIG_TIMESTAMP:
366fc1f8641Sagc case PGP_SIG_3RD_PARTY:
367fc1f8641Sagc PGP_ERROR_1(errors, PGP_E_UNIMPLEMENTED,
368bcfd8565Sagc "Sig Verification type 0x%02x not done yet\n",
3693326c4c5Sagc content->sig.info.type);
37093bf6008Sagc break;
37193bf6008Sagc
37293bf6008Sagc default:
373fc1f8641Sagc PGP_ERROR_1(errors, PGP_E_UNIMPLEMENTED,
374de704779Sagc "Unexpected signature type 0x%02x\n",
3753326c4c5Sagc content->sig.info.type);
37693bf6008Sagc }
37793bf6008Sagc
37893bf6008Sagc if (valid) {
37983cfb9deSagc if (!add_sig_to_list(&content->sig.info,
38093bf6008Sagc &key->result->valid_sigs,
38183cfb9deSagc &key->result->validc)) {
382*94fcde8eSchristos PGP_ERROR_1(errors, PGP_E_UNIMPLEMENTED, "%s",
38383cfb9deSagc "Can't add good sig to list\n");
38483cfb9deSagc }
38593bf6008Sagc } else {
386*94fcde8eSchristos PGP_ERROR_1(errors, PGP_E_V_BAD_SIGNATURE, "%s",
387*94fcde8eSchristos "Bad Sig");
38883cfb9deSagc if (!add_sig_to_list(&content->sig.info,
38993bf6008Sagc &key->result->invalid_sigs,
39083cfb9deSagc &key->result->invalidc)) {
391*94fcde8eSchristos PGP_ERROR_1(errors, PGP_E_UNIMPLEMENTED, "%s",
39283cfb9deSagc "Can't add good sig to list\n");
39383cfb9deSagc }
39493bf6008Sagc }
39593bf6008Sagc break;
39693bf6008Sagc
39793bf6008Sagc /* ignore these */
398fc1f8641Sagc case PGP_PARSER_PTAG:
399fc1f8641Sagc case PGP_PTAG_CT_SIGNATURE_HEADER:
400fc1f8641Sagc case PGP_PARSER_PACKET_END:
40193bf6008Sagc break;
40293bf6008Sagc
403fc1f8641Sagc case PGP_GET_PASSPHRASE:
404f4badd9bSagc if (key->getpassphrase) {
405f4badd9bSagc return key->getpassphrase(pkt, cbinfo);
40693bf6008Sagc }
40793bf6008Sagc break;
40893bf6008Sagc
409fc1f8641Sagc case PGP_PTAG_CT_TRUST:
410600b302bSagc /* 1 byte for level (depth), 1 byte for trust amount */
411600b302bSagc printf("trust dump\n");
412600b302bSagc printf("Got trust\n");
413b15ec256Sagc //hexdump(stdout, (const uint8_t *)content->trust.data, 10, " ");
414b15ec256Sagc //hexdump(stdout, (const uint8_t *)&content->ss_trust, 2, " ");
415600b302bSagc //printf("Trust level %d, amount %d\n", key->trust.level, key->trust.amount);
416600b302bSagc break;
417600b302bSagc
41893bf6008Sagc default:
4193326c4c5Sagc (void) fprintf(stderr, "unexpected tag=0x%x\n", pkt->tag);
420fc1f8641Sagc return PGP_FINISHED;
42193bf6008Sagc }
422fc1f8641Sagc return PGP_RELEASE_MEMORY;
42393bf6008Sagc }
42493bf6008Sagc
425fc1f8641Sagc pgp_cb_ret_t
validate_data_cb(const pgp_packet_t * pkt,pgp_cbdata_t * cbinfo)426fc1f8641Sagc validate_data_cb(const pgp_packet_t *pkt, pgp_cbdata_t *cbinfo)
42793bf6008Sagc {
428fc1f8641Sagc const pgp_contents_t *content = &pkt->u;
429fc1f8641Sagc const pgp_key_t *signer;
43057324b9fSagc validate_data_cb_t *data;
431fc1f8641Sagc pgp_pubkey_t *sigkey;
432fc1f8641Sagc pgp_error_t **errors;
433fc1f8641Sagc pgp_io_t *io;
434183e04ebSagc unsigned from;
4354b3a3e18Sagc unsigned valid = 0;
43693bf6008Sagc
437d21b929eSagc io = cbinfo->io;
438fc1f8641Sagc if (pgp_get_debug_level(__FILE__)) {
439d21b929eSagc (void) fprintf(io->errs, "validate_data_cb: %s\n",
440fc1f8641Sagc pgp_show_packet_tag(pkt->tag));
44193bf6008Sagc }
442fc1f8641Sagc data = pgp_callback_arg(cbinfo);
443fc1f8641Sagc errors = pgp_callback_errors(cbinfo);
4443326c4c5Sagc switch (pkt->tag) {
445fc1f8641Sagc case PGP_PTAG_CT_SIGNED_CLEARTEXT_HEADER:
44693bf6008Sagc /*
44793bf6008Sagc * ignore - this gives us the "Armor Header" line "Hash:
44893bf6008Sagc * SHA1" or similar
44993bf6008Sagc */
45093bf6008Sagc break;
45193bf6008Sagc
452fc1f8641Sagc case PGP_PTAG_CT_LITDATA_HEADER:
45393bf6008Sagc /* ignore */
45493bf6008Sagc break;
45593bf6008Sagc
456fc1f8641Sagc case PGP_PTAG_CT_LITDATA_BODY:
4573326c4c5Sagc data->data.litdata_body = content->litdata_body;
45841335e2dSagc data->type = LITDATA;
459fc1f8641Sagc pgp_memory_add(data->mem, data->data.litdata_body.data,
4603326c4c5Sagc data->data.litdata_body.length);
461fc1f8641Sagc return PGP_KEEP_MEMORY;
46293bf6008Sagc
463fc1f8641Sagc case PGP_PTAG_CT_SIGNED_CLEARTEXT_BODY:
46457324b9fSagc data->data.cleartext_body = content->cleartext_body;
465d21b929eSagc data->type = SIGNED_CLEARTEXT;
466fc1f8641Sagc pgp_memory_add(data->mem, data->data.cleartext_body.data,
467d22b8667Sagc data->data.cleartext_body.length);
468fc1f8641Sagc return PGP_KEEP_MEMORY;
46993bf6008Sagc
470fc1f8641Sagc case PGP_PTAG_CT_SIGNED_CLEARTEXT_TRAILER:
471fc1f8641Sagc /* this gives us an pgp_hash_t struct */
47293bf6008Sagc break;
47393bf6008Sagc
474fc1f8641Sagc case PGP_PTAG_CT_SIGNATURE: /* V3 sigs */
475fc1f8641Sagc case PGP_PTAG_CT_SIGNATURE_FOOTER: /* V4 sigs */
476fc1f8641Sagc if (pgp_get_debug_level(__FILE__)) {
47747561e26Sagc hexdump(io->outs, "hashed data", content->sig.info.v4_hashed,
47847561e26Sagc content->sig.info.v4_hashlen);
47947561e26Sagc hexdump(io->outs, "signer id", content->sig.info.signer_id,
48047561e26Sagc sizeof(content->sig.info.signer_id));
48193bf6008Sagc }
482183e04ebSagc from = 0;
483fc1f8641Sagc signer = pgp_getkeybyid(io, data->keyring,
48469d4f30fSagc content->sig.info.signer_id, &from, &sigkey);
48593bf6008Sagc if (!signer) {
486*94fcde8eSchristos PGP_ERROR_1(errors, PGP_E_V_UNKNOWN_SIGNER,
487*94fcde8eSchristos "%s", "Unknown Signer");
48883cfb9deSagc if (!add_sig_to_list(&content->sig.info,
48993bf6008Sagc &data->result->unknown_sigs,
49083cfb9deSagc &data->result->unknownc)) {
491*94fcde8eSchristos PGP_ERROR_1(errors, PGP_E_V_UNKNOWN_SIGNER,
492*94fcde8eSchristos "%s", "Can't add unknown sig to list");
49383cfb9deSagc }
49493bf6008Sagc break;
49593bf6008Sagc }
49669d4f30fSagc if (sigkey == &signer->enckey) {
49769d4f30fSagc (void) fprintf(io->errs,
49869d4f30fSagc "WARNING: signature made with encryption key\n");
49969d4f30fSagc }
500600b302bSagc if (content->sig.info.birthtime_set) {
501600b302bSagc data->result->birthtime = content->sig.info.birthtime;
502600b302bSagc }
503600b302bSagc if (content->sig.info.duration_set) {
504600b302bSagc data->result->duration = content->sig.info.duration;
505600b302bSagc }
5063326c4c5Sagc switch (content->sig.info.type) {
507fc1f8641Sagc case PGP_SIG_BINARY:
508fc1f8641Sagc case PGP_SIG_TEXT:
509fc1f8641Sagc if (pgp_mem_len(data->mem) == 0 &&
510f4badd9bSagc data->detachname) {
511f4badd9bSagc /* check we have seen some data */
512f4badd9bSagc /* if not, need to read from detached name */
5139b9aeb8dSagc (void) fprintf(io->errs,
514f4badd9bSagc "netpgp: assuming signed data in \"%s\"\n",
515f4badd9bSagc data->detachname);
516fc1f8641Sagc data->mem = pgp_memory_new();
517fc1f8641Sagc pgp_mem_readfile(data->mem, data->detachname);
518f4badd9bSagc }
519fc1f8641Sagc if (pgp_get_debug_level(__FILE__)) {
52047561e26Sagc hexdump(stderr, "sig dump", (const uint8_t *)(const void *)&content->sig,
52147561e26Sagc sizeof(content->sig));
522600b302bSagc }
523fc1f8641Sagc valid = check_binary_sig(pgp_mem_data(data->mem),
524fc1f8641Sagc (const unsigned)pgp_mem_len(data->mem),
5253326c4c5Sagc &content->sig,
526fc1f8641Sagc pgp_get_pubkey(signer));
52793bf6008Sagc break;
52893bf6008Sagc
52993bf6008Sagc default:
530fc1f8641Sagc PGP_ERROR_1(errors, PGP_E_UNIMPLEMENTED,
531de704779Sagc "No Sig Verification type 0x%02x yet\n",
5323326c4c5Sagc content->sig.info.type);
53393bf6008Sagc break;
53493bf6008Sagc
53593bf6008Sagc }
53693bf6008Sagc
53793bf6008Sagc if (valid) {
53883cfb9deSagc if (!add_sig_to_list(&content->sig.info,
53993bf6008Sagc &data->result->valid_sigs,
54083cfb9deSagc &data->result->validc)) {
541*94fcde8eSchristos PGP_ERROR_1(errors, PGP_E_V_BAD_SIGNATURE,
542*94fcde8eSchristos "%s", "Can't add good sig to list");
54383cfb9deSagc }
54493bf6008Sagc } else {
545*94fcde8eSchristos PGP_ERROR_1(errors, PGP_E_V_BAD_SIGNATURE,
546*94fcde8eSchristos "%s", "Bad Signature");
54783cfb9deSagc if (!add_sig_to_list(&content->sig.info,
54893bf6008Sagc &data->result->invalid_sigs,
54983cfb9deSagc &data->result->invalidc)) {
550*94fcde8eSchristos PGP_ERROR_1(errors, PGP_E_V_BAD_SIGNATURE, "%s",
55183cfb9deSagc "Can't add good sig to list");
55283cfb9deSagc }
55393bf6008Sagc }
55493bf6008Sagc break;
55593bf6008Sagc
55693bf6008Sagc /* ignore these */
557fc1f8641Sagc case PGP_PARSER_PTAG:
558fc1f8641Sagc case PGP_PTAG_CT_SIGNATURE_HEADER:
559fc1f8641Sagc case PGP_PTAG_CT_ARMOUR_HEADER:
560fc1f8641Sagc case PGP_PTAG_CT_ARMOUR_TRAILER:
561fc1f8641Sagc case PGP_PTAG_CT_1_PASS_SIG:
56257324b9fSagc break;
56357324b9fSagc
564fc1f8641Sagc case PGP_PARSER_PACKET_END:
56593bf6008Sagc break;
56693bf6008Sagc
56793bf6008Sagc default:
568*94fcde8eSchristos PGP_ERROR_1(errors, PGP_E_V_NO_SIGNATURE, "%s", "No signature");
56993bf6008Sagc break;
57093bf6008Sagc }
571fc1f8641Sagc return PGP_RELEASE_MEMORY;
57293bf6008Sagc }
57393bf6008Sagc
57493bf6008Sagc static void
keydata_destroyer(pgp_reader_t * readinfo)575fc1f8641Sagc keydata_destroyer(pgp_reader_t *readinfo)
57693bf6008Sagc {
577fc1f8641Sagc free(pgp_reader_get_arg(readinfo));
57893bf6008Sagc }
57993bf6008Sagc
58093bf6008Sagc void
pgp_keydata_reader_set(pgp_stream_t * stream,const pgp_key_t * key)581fc1f8641Sagc pgp_keydata_reader_set(pgp_stream_t *stream, const pgp_key_t *key)
58293bf6008Sagc {
58383cfb9deSagc validate_reader_t *data;
58493bf6008Sagc
58583cfb9deSagc if ((data = calloc(1, sizeof(*data))) == NULL) {
586fc1f8641Sagc (void) fprintf(stderr, "pgp_keydata_reader_set: bad alloc\n");
58783cfb9deSagc } else {
58893bf6008Sagc data->key = key;
58993bf6008Sagc data->packet = 0;
59093bf6008Sagc data->offset = 0;
591fc1f8641Sagc pgp_reader_set(stream, keydata_reader, keydata_destroyer, data);
59293bf6008Sagc }
59383cfb9deSagc }
59493bf6008Sagc
595600b302bSagc static char *
fmtsecs(int64_t n,char * buf,size_t size)596600b302bSagc fmtsecs(int64_t n, char *buf, size_t size)
597600b302bSagc {
598600b302bSagc if (n > 365 * 24 * 60 * 60) {
5990aa60872Sagc n /= (365 * 24 * 60 * 60);
6000aa60872Sagc (void) snprintf(buf, size, "%" PRId64 " year%s", n, (n == 1) ? "" : "s");
601600b302bSagc return buf;
602600b302bSagc }
603600b302bSagc if (n > 30 * 24 * 60 * 60) {
6040aa60872Sagc n /= (30 * 24 * 60 * 60);
6050aa60872Sagc (void) snprintf(buf, size, "%" PRId64 " month%s", n, (n == 1) ? "" : "s");
606600b302bSagc return buf;
607600b302bSagc }
608600b302bSagc if (n > 24 * 60 * 60) {
6090aa60872Sagc n /= (24 * 60 * 60);
6100aa60872Sagc (void) snprintf(buf, size, "%" PRId64 " day%s", n, (n == 1) ? "" : "s");
611600b302bSagc return buf;
612600b302bSagc }
613600b302bSagc if (n > 60 * 60) {
6140aa60872Sagc n /= (60 * 60);
6150aa60872Sagc (void) snprintf(buf, size, "%" PRId64 " hour%s", n, (n == 1) ? "" : "s");
616600b302bSagc return buf;
617600b302bSagc }
618600b302bSagc if (n > 60) {
6190aa60872Sagc n /= 60;
6200aa60872Sagc (void) snprintf(buf, size, "%" PRId64 " minute%s", n, (n == 1) ? "" : "s");
621600b302bSagc return buf;
622600b302bSagc }
6230aa60872Sagc (void) snprintf(buf, size, "%" PRId64 " second%s", n, (n == 1) ? "" : "s");
624600b302bSagc return buf;
625600b302bSagc }
626600b302bSagc
62793bf6008Sagc /**
62893bf6008Sagc * \ingroup HighLevel_Verify
62993bf6008Sagc * \brief Indicicates whether any errors were found
63093bf6008Sagc * \param result Validation result to check
6314b3a3e18Sagc * \return 0 if any invalid signatures or unknown signers
6324b3a3e18Sagc or no valid signatures; else 1
63393bf6008Sagc */
6344b3a3e18Sagc static unsigned
validate_result_status(FILE * errs,const char * f,pgp_validation_t * val)635fc1f8641Sagc validate_result_status(FILE *errs, const char *f, pgp_validation_t *val)
63693bf6008Sagc {
637600b302bSagc time_t now;
638600b302bSagc time_t t;
639600b302bSagc char buf[128];
640600b302bSagc
641600b302bSagc now = time(NULL);
642600b302bSagc if (now < val->birthtime) {
643600b302bSagc /* signature is not valid yet! */
6442b48e3a6Sagc if (f) {
6452b48e3a6Sagc (void) fprintf(errs, "\"%s\": ", f);
6462b48e3a6Sagc } else {
6472b48e3a6Sagc (void) fprintf(errs, "memory ");
6482b48e3a6Sagc }
649600b302bSagc (void) fprintf(errs,
650600b302bSagc "signature not valid until %.24s (%s)\n",
651600b302bSagc ctime(&val->birthtime),
652600b302bSagc fmtsecs((int64_t)(val->birthtime - now), buf, sizeof(buf)));
653600b302bSagc return 0;
654600b302bSagc }
655600b302bSagc if (val->duration != 0 && now > val->birthtime + val->duration) {
656600b302bSagc /* signature has expired */
657600b302bSagc t = val->duration + val->birthtime;
6582b48e3a6Sagc if (f) {
6592b48e3a6Sagc (void) fprintf(errs, "\"%s\": ", f);
6602b48e3a6Sagc } else {
6612b48e3a6Sagc (void) fprintf(errs, "memory ");
6622b48e3a6Sagc }
663600b302bSagc (void) fprintf(errs,
664600b302bSagc "signature not valid after %.24s (%s ago)\n",
665600b302bSagc ctime(&t),
666600b302bSagc fmtsecs((int64_t)(now - t), buf, sizeof(buf)));
667600b302bSagc return 0;
668600b302bSagc }
66993bf6008Sagc return val->validc && !val->invalidc && !val->unknownc;
67093bf6008Sagc }
67193bf6008Sagc
67293bf6008Sagc /**
67393bf6008Sagc * \ingroup HighLevel_Verify
67493bf6008Sagc * \brief Validate all signatures on a single key against the given keyring
67593bf6008Sagc * \param result Where to put the result
67693bf6008Sagc * \param key Key to validate
67793bf6008Sagc * \param keyring Keyring to use for validation
67893bf6008Sagc * \param cb_get_passphrase Callback to use to get passphrase
6794b3a3e18Sagc * \return 1 if all signatures OK; else 0
68093bf6008Sagc * \note It is the caller's responsiblity to free result after use.
681fc1f8641Sagc * \sa pgp_validate_result_free()
68293bf6008Sagc */
6834b3a3e18Sagc unsigned
pgp_validate_key_sigs(pgp_validation_t * result,const pgp_key_t * key,const pgp_keyring_t * keyring,pgp_cb_ret_t cb_get_passphrase (const pgp_packet_t *,pgp_cbdata_t *))684fc1f8641Sagc pgp_validate_key_sigs(pgp_validation_t *result,
685fc1f8641Sagc const pgp_key_t *key,
686fc1f8641Sagc const pgp_keyring_t *keyring,
687fc1f8641Sagc pgp_cb_ret_t cb_get_passphrase(const pgp_packet_t *,
688fc1f8641Sagc pgp_cbdata_t *))
68993bf6008Sagc {
690fc1f8641Sagc pgp_stream_t *stream;
69157324b9fSagc validate_key_cb_t keysigs;
692393ecd92Sagc const int printerrors = 1;
69393bf6008Sagc
69457324b9fSagc (void) memset(&keysigs, 0x0, sizeof(keysigs));
69557324b9fSagc keysigs.result = result;
696f4badd9bSagc keysigs.getpassphrase = cb_get_passphrase;
69793bf6008Sagc
698fc1f8641Sagc stream = pgp_new(sizeof(*stream));
699fc1f8641Sagc /* pgp_parse_options(&opt,PGP_PTAG_CT_SIGNATURE,PGP_PARSE_PARSED); */
70093bf6008Sagc
70157324b9fSagc keysigs.keyring = keyring;
70293bf6008Sagc
703fc1f8641Sagc pgp_set_callback(stream, pgp_validate_key_cb, &keysigs);
70441335e2dSagc stream->readinfo.accumulate = 1;
705fc1f8641Sagc pgp_keydata_reader_set(stream, key);
70693bf6008Sagc
70757324b9fSagc /* Note: Coverity incorrectly reports an error that keysigs.reader */
70893bf6008Sagc /* is never used. */
70941335e2dSagc keysigs.reader = stream->readinfo.arg;
71093bf6008Sagc
711fc1f8641Sagc pgp_parse(stream, !printerrors);
71293bf6008Sagc
713fc1f8641Sagc pgp_pubkey_free(&keysigs.pubkey);
71457324b9fSagc if (keysigs.subkey.version) {
715fc1f8641Sagc pgp_pubkey_free(&keysigs.subkey);
7160c310959Sagc }
717fc1f8641Sagc pgp_userid_free(&keysigs.userid);
718fc1f8641Sagc pgp_data_free(&keysigs.userattr);
71993bf6008Sagc
720fc1f8641Sagc pgp_stream_delete(stream);
72193bf6008Sagc
7220c310959Sagc return (!result->invalidc && !result->unknownc && result->validc);
72393bf6008Sagc }
72493bf6008Sagc
72593bf6008Sagc /**
72693bf6008Sagc \ingroup HighLevel_Verify
72793bf6008Sagc \param result Where to put the result
72893bf6008Sagc \param ring Keyring to use
72993bf6008Sagc \param cb_get_passphrase Callback to use to get passphrase
73093bf6008Sagc \note It is the caller's responsibility to free result after use.
731fc1f8641Sagc \sa pgp_validate_result_free()
73293bf6008Sagc */
7334b3a3e18Sagc unsigned
pgp_validate_all_sigs(pgp_validation_t * result,const pgp_keyring_t * ring,pgp_cb_ret_t cb_get_passphrase (const pgp_packet_t *,pgp_cbdata_t *))734fc1f8641Sagc pgp_validate_all_sigs(pgp_validation_t *result,
735fc1f8641Sagc const pgp_keyring_t *ring,
736fc1f8641Sagc pgp_cb_ret_t cb_get_passphrase(const pgp_packet_t *,
737fc1f8641Sagc pgp_cbdata_t *))
73893bf6008Sagc {
73941335e2dSagc unsigned n;
74093bf6008Sagc
74193bf6008Sagc (void) memset(result, 0x0, sizeof(*result));
74241335e2dSagc for (n = 0; n < ring->keyc; ++n) {
743fc1f8641Sagc pgp_validate_key_sigs(result, &ring->keys[n], ring,
744de704779Sagc cb_get_passphrase);
745de704779Sagc }
7462b48e3a6Sagc return validate_result_status(stderr, "keyring", result);
74793bf6008Sagc }
74893bf6008Sagc
74993bf6008Sagc /**
75093bf6008Sagc \ingroup HighLevel_Verify
75193bf6008Sagc \brief Frees validation result and associated memory
75293bf6008Sagc \param result Struct to be freed
75393bf6008Sagc \note Must be called after validation functions
75493bf6008Sagc */
75593bf6008Sagc void
pgp_validate_result_free(pgp_validation_t * result)756fc1f8641Sagc pgp_validate_result_free(pgp_validation_t *result)
75793bf6008Sagc {
758de704779Sagc if (result != NULL) {
759de704779Sagc if (result->valid_sigs) {
7603326c4c5Sagc free_sig_info(result->valid_sigs);
761de704779Sagc }
762de704779Sagc if (result->invalid_sigs) {
7633326c4c5Sagc free_sig_info(result->invalid_sigs);
764de704779Sagc }
765de704779Sagc if (result->unknown_sigs) {
7663326c4c5Sagc free_sig_info(result->unknown_sigs);
767de704779Sagc }
76883cfb9deSagc free(result);
76983cfb9deSagc /* result = NULL; - XXX unnecessary */
77093bf6008Sagc }
771de704779Sagc }
77293bf6008Sagc
77393bf6008Sagc /**
77493bf6008Sagc \ingroup HighLevel_Verify
77593bf6008Sagc \brief Verifies the signatures in a signed file
77693bf6008Sagc \param result Where to put the result
77793bf6008Sagc \param filename Name of file to be validated
77893bf6008Sagc \param armoured Treat file as armoured, if set
77993bf6008Sagc \param keyring Keyring to use
7804b3a3e18Sagc \return 1 if signatures validate successfully;
7814b3a3e18Sagc 0 if signatures fail or there are no signatures
78293bf6008Sagc \note After verification, result holds the details of all keys which
78393bf6008Sagc have passed, failed and not been recognised.
784de704779Sagc \note It is the caller's responsiblity to call
785fc1f8641Sagc pgp_validate_result_free(result) after use.
78693bf6008Sagc */
7874b3a3e18Sagc unsigned
pgp_validate_file(pgp_io_t * io,pgp_validation_t * result,const char * infile,const char * outfile,const int user_says_armoured,const pgp_keyring_t * keyring)788fc1f8641Sagc pgp_validate_file(pgp_io_t *io,
789fc1f8641Sagc pgp_validation_t *result,
7902232f800Sagc const char *infile,
7912232f800Sagc const char *outfile,
792b15ec256Sagc const int user_says_armoured,
793fc1f8641Sagc const pgp_keyring_t *keyring)
79493bf6008Sagc {
79593bf6008Sagc validate_data_cb_t validation;
796fc1f8641Sagc pgp_stream_t *parse = NULL;
797bcfd8565Sagc struct stat st;
7983644eb84Sagc const char *signame;
799393ecd92Sagc const int printerrors = 1;
800648b5a99Sagc unsigned ret;
8013644eb84Sagc char f[MAXPATHLEN];
8023644eb84Sagc char *dataname;
803632dc3acSagc int realarmour;
80457324b9fSagc int outfd = 0;
80557324b9fSagc int infd;
806bcfd8565Sagc int cc;
807bcfd8565Sagc
8082232f800Sagc if (stat(infile, &st) < 0) {
809026af9faSagc (void) fprintf(io->errs,
810fc1f8641Sagc "pgp_validate_file: can't open '%s'\n", infile);
8114b3a3e18Sagc return 0;
812bcfd8565Sagc }
8133644eb84Sagc realarmour = user_says_armoured;
8143644eb84Sagc dataname = NULL;
8153644eb84Sagc signame = NULL;
8163644eb84Sagc cc = snprintf(f, sizeof(f), "%s", infile);
817026af9faSagc if (strcmp(&f[cc - 4], ".sig") == 0) {
8183644eb84Sagc /* we've been given a sigfile as infile */
8193644eb84Sagc f[cc - 4] = 0x0;
8203644eb84Sagc /* set dataname to name of file which was signed */
8213644eb84Sagc dataname = f;
8223644eb84Sagc signame = infile;
823026af9faSagc } else if (strcmp(&f[cc - 4], ".asc") == 0) {
824026af9faSagc /* we've been given an armored sigfile as infile */
825026af9faSagc f[cc - 4] = 0x0;
826026af9faSagc /* set dataname to name of file which was signed */
827026af9faSagc dataname = f;
828026af9faSagc signame = infile;
829632dc3acSagc realarmour = 1;
8303644eb84Sagc } else {
8313644eb84Sagc signame = infile;
832632dc3acSagc }
83357324b9fSagc (void) memset(&validation, 0x0, sizeof(validation));
834fc1f8641Sagc infd = pgp_setup_file_read(io, &parse, signame, &validation,
8354b3a3e18Sagc validate_data_cb, 1);
83657324b9fSagc if (infd < 0) {
8374b3a3e18Sagc return 0;
838de704779Sagc }
83993bf6008Sagc
8403644eb84Sagc if (dataname) {
8413644eb84Sagc validation.detachname = netpgp_strdup(dataname);
8423644eb84Sagc }
84357324b9fSagc
84493bf6008Sagc /* Set verification reader and handling options */
84593bf6008Sagc validation.result = result;
84693bf6008Sagc validation.keyring = keyring;
847fc1f8641Sagc validation.mem = pgp_memory_new();
848fc1f8641Sagc pgp_memory_init(validation.mem, 128);
84957324b9fSagc /* Note: Coverity incorrectly reports an error that validation.reader */
85093bf6008Sagc /* is never used. */
85157324b9fSagc validation.reader = parse->readinfo.arg;
85293bf6008Sagc
853632dc3acSagc if (realarmour) {
854fc1f8641Sagc pgp_reader_push_dearmour(parse);
855de704779Sagc }
85693bf6008Sagc
85793bf6008Sagc /* Do the verification */
858fc1f8641Sagc pgp_parse(parse, !printerrors);
859bcfd8565Sagc
86093bf6008Sagc /* Tidy up */
861632dc3acSagc if (realarmour) {
862fc1f8641Sagc pgp_reader_pop_dearmour(parse);
863de704779Sagc }
864fc1f8641Sagc pgp_teardown_file_read(parse, infd);
86593bf6008Sagc
8662b48e3a6Sagc ret = validate_result_status(io->errs, infile, result);
867648b5a99Sagc
868648b5a99Sagc /* this is triggered only for --cat output */
869648b5a99Sagc if (outfile) {
870648b5a99Sagc /* need to send validated output somewhere */
871648b5a99Sagc if (strcmp(outfile, "-") == 0) {
872648b5a99Sagc outfd = STDOUT_FILENO;
873648b5a99Sagc } else {
874648b5a99Sagc outfd = open(outfile, O_WRONLY | O_CREAT, 0666);
875648b5a99Sagc }
876648b5a99Sagc if (outfd < 0) {
877648b5a99Sagc /* even if the signature was good, we can't
878648b5a99Sagc * write the file, so send back a bad return
879648b5a99Sagc * code */
880648b5a99Sagc ret = 0;
8812b48e3a6Sagc } else if (validate_result_status(io->errs, infile, result)) {
882648b5a99Sagc unsigned len;
883648b5a99Sagc char *cp;
884648b5a99Sagc int i;
885648b5a99Sagc
886fc1f8641Sagc len = (unsigned)pgp_mem_len(validation.mem);
887fc1f8641Sagc cp = pgp_mem_data(validation.mem);
888648b5a99Sagc for (i = 0 ; i < (int)len ; i += cc) {
889593d671cSagc cc = (int)write(outfd, &cp[i], (unsigned)(len - i));
890648b5a99Sagc if (cc < 0) {
891d21b929eSagc (void) fprintf(io->errs,
892648b5a99Sagc "netpgp: short write\n");
893648b5a99Sagc ret = 0;
894648b5a99Sagc break;
895648b5a99Sagc }
896648b5a99Sagc }
897648b5a99Sagc if (strcmp(outfile, "-") != 0) {
898648b5a99Sagc (void) close(outfd);
899648b5a99Sagc }
900648b5a99Sagc }
901648b5a99Sagc }
902fc1f8641Sagc pgp_memory_free(validation.mem);
903648b5a99Sagc return ret;
90493bf6008Sagc }
90593bf6008Sagc
90693bf6008Sagc /**
90793bf6008Sagc \ingroup HighLevel_Verify
908fc1f8641Sagc \brief Verifies the signatures in a pgp_memory_t struct
90993bf6008Sagc \param result Where to put the result
91093bf6008Sagc \param mem Memory to be validated
911b15ec256Sagc \param user_says_armoured Treat data as armoured, if set
91293bf6008Sagc \param keyring Keyring to use
9134b3a3e18Sagc \return 1 if signature validates successfully; 0 if not
91493bf6008Sagc \note After verification, result holds the details of all keys which
91593bf6008Sagc have passed, failed and not been recognised.
916de704779Sagc \note It is the caller's responsiblity to call
917fc1f8641Sagc pgp_validate_result_free(result) after use.
91893bf6008Sagc */
91993bf6008Sagc
9204b3a3e18Sagc unsigned
pgp_validate_mem(pgp_io_t * io,pgp_validation_t * result,pgp_memory_t * mem,pgp_memory_t ** cat,const int user_says_armoured,const pgp_keyring_t * keyring)921fc1f8641Sagc pgp_validate_mem(pgp_io_t *io,
922fc1f8641Sagc pgp_validation_t *result,
923fc1f8641Sagc pgp_memory_t *mem,
924fc1f8641Sagc pgp_memory_t **cat,
925b15ec256Sagc const int user_says_armoured,
926fc1f8641Sagc const pgp_keyring_t *keyring)
92793bf6008Sagc {
92893bf6008Sagc validate_data_cb_t validation;
929fc1f8641Sagc pgp_stream_t *stream = NULL;
930393ecd92Sagc const int printerrors = 1;
931b15ec256Sagc int realarmour;
93293bf6008Sagc
933fc1f8641Sagc pgp_setup_memory_read(io, &stream, mem, &validation, validate_data_cb, 1);
93493bf6008Sagc /* Set verification reader and handling options */
93593bf6008Sagc (void) memset(&validation, 0x0, sizeof(validation));
93693bf6008Sagc validation.result = result;
93793bf6008Sagc validation.keyring = keyring;
938fc1f8641Sagc validation.mem = pgp_memory_new();
939fc1f8641Sagc pgp_memory_init(validation.mem, 128);
94057324b9fSagc /* Note: Coverity incorrectly reports an error that validation.reader */
94193bf6008Sagc /* is never used. */
94241335e2dSagc validation.reader = stream->readinfo.arg;
94393bf6008Sagc
944b15ec256Sagc if ((realarmour = user_says_armoured) != 0 ||
945fc1f8641Sagc strncmp(pgp_mem_data(mem),
946b15ec256Sagc "-----BEGIN PGP MESSAGE-----", 27) == 0) {
947b15ec256Sagc realarmour = 1;
948b15ec256Sagc }
949b15ec256Sagc if (realarmour) {
950fc1f8641Sagc pgp_reader_push_dearmour(stream);
951de704779Sagc }
95293bf6008Sagc
95393bf6008Sagc /* Do the verification */
954fc1f8641Sagc pgp_parse(stream, !printerrors);
955de704779Sagc
95693bf6008Sagc /* Tidy up */
957b15ec256Sagc if (realarmour) {
958fc1f8641Sagc pgp_reader_pop_dearmour(stream);
959de704779Sagc }
960fc1f8641Sagc pgp_teardown_memory_read(stream, mem);
961d369874eSagc
962d369874eSagc /* this is triggered only for --cat output */
963156f1405Sagc if (cat) {
964d369874eSagc /* need to send validated output somewhere */
965d369874eSagc *cat = validation.mem;
966d369874eSagc } else {
967fc1f8641Sagc pgp_memory_free(validation.mem);
968d369874eSagc }
96993bf6008Sagc
9702b48e3a6Sagc return validate_result_status(io->errs, NULL, result);
97193bf6008Sagc }
972