1*ebfedea0SLionel Sambuc /*-
2*ebfedea0SLionel Sambuc * Copyright (c) 2009 The NetBSD Foundation, Inc.
3*ebfedea0SLionel Sambuc * All rights reserved.
4*ebfedea0SLionel Sambuc *
5*ebfedea0SLionel Sambuc * This code is derived from software contributed to The NetBSD Foundation
6*ebfedea0SLionel Sambuc * by Alistair Crooks (agc@NetBSD.org)
7*ebfedea0SLionel Sambuc *
8*ebfedea0SLionel Sambuc * Redistribution and use in source and binary forms, with or without
9*ebfedea0SLionel Sambuc * modification, are permitted provided that the following conditions
10*ebfedea0SLionel Sambuc * are met:
11*ebfedea0SLionel Sambuc * 1. Redistributions of source code must retain the above copyright
12*ebfedea0SLionel Sambuc * notice, this list of conditions and the following disclaimer.
13*ebfedea0SLionel Sambuc * 2. Redistributions in binary form must reproduce the above copyright
14*ebfedea0SLionel Sambuc * notice, this list of conditions and the following disclaimer in the
15*ebfedea0SLionel Sambuc * documentation and/or other materials provided with the distribution.
16*ebfedea0SLionel Sambuc *
17*ebfedea0SLionel Sambuc * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
18*ebfedea0SLionel Sambuc * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19*ebfedea0SLionel Sambuc * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20*ebfedea0SLionel Sambuc * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
21*ebfedea0SLionel Sambuc * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22*ebfedea0SLionel Sambuc * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23*ebfedea0SLionel Sambuc * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24*ebfedea0SLionel Sambuc * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25*ebfedea0SLionel Sambuc * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26*ebfedea0SLionel Sambuc * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27*ebfedea0SLionel Sambuc * POSSIBILITY OF SUCH DAMAGE.
28*ebfedea0SLionel Sambuc */
29*ebfedea0SLionel Sambuc /*
30*ebfedea0SLionel Sambuc * Copyright (c) 2005-2008 Nominet UK (www.nic.uk)
31*ebfedea0SLionel Sambuc * All rights reserved.
32*ebfedea0SLionel Sambuc * Contributors: Ben Laurie, Rachel Willmer. The Contributors have asserted
33*ebfedea0SLionel Sambuc * their moral rights under the UK Copyright Design and Patents Act 1988 to
34*ebfedea0SLionel Sambuc * be recorded as the authors of this copyright work.
35*ebfedea0SLionel Sambuc *
36*ebfedea0SLionel Sambuc * Licensed under the Apache License, Version 2.0 (the "License"); you may not
37*ebfedea0SLionel Sambuc * use this file except in compliance with the License.
38*ebfedea0SLionel Sambuc *
39*ebfedea0SLionel Sambuc * You may obtain a copy of the License at
40*ebfedea0SLionel Sambuc * http://www.apache.org/licenses/LICENSE-2.0
41*ebfedea0SLionel Sambuc *
42*ebfedea0SLionel Sambuc * Unless required by applicable law or agreed to in writing, software
43*ebfedea0SLionel Sambuc * distributed under the License is distributed on an "AS IS" BASIS,
44*ebfedea0SLionel Sambuc * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
45*ebfedea0SLionel Sambuc *
46*ebfedea0SLionel Sambuc * See the License for the specific language governing permissions and
47*ebfedea0SLionel Sambuc * limitations under the License.
48*ebfedea0SLionel Sambuc */
49*ebfedea0SLionel Sambuc #include "config.h"
50*ebfedea0SLionel Sambuc
51*ebfedea0SLionel Sambuc #ifdef HAVE_SYS_CDEFS_H
52*ebfedea0SLionel Sambuc #include <sys/cdefs.h>
53*ebfedea0SLionel Sambuc #endif
54*ebfedea0SLionel Sambuc
55*ebfedea0SLionel Sambuc #if defined(__NetBSD__)
56*ebfedea0SLionel Sambuc __COPYRIGHT("@(#) Copyright (c) 2009 The NetBSD Foundation, Inc. All rights reserved.");
57*ebfedea0SLionel Sambuc __RCSID("$NetBSD: validate.c,v 1.44 2012/03/05 02:20:18 christos Exp $");
58*ebfedea0SLionel Sambuc #endif
59*ebfedea0SLionel Sambuc
60*ebfedea0SLionel Sambuc #include <sys/types.h>
61*ebfedea0SLionel Sambuc #include <sys/param.h>
62*ebfedea0SLionel Sambuc #include <sys/stat.h>
63*ebfedea0SLionel Sambuc
64*ebfedea0SLionel Sambuc #include <string.h>
65*ebfedea0SLionel Sambuc #include <stdio.h>
66*ebfedea0SLionel Sambuc
67*ebfedea0SLionel Sambuc #ifdef HAVE_UNISTD_H
68*ebfedea0SLionel Sambuc #include <unistd.h>
69*ebfedea0SLionel Sambuc #endif
70*ebfedea0SLionel Sambuc
71*ebfedea0SLionel Sambuc #ifdef HAVE_FCNTL_H
72*ebfedea0SLionel Sambuc #include <fcntl.h>
73*ebfedea0SLionel Sambuc #endif
74*ebfedea0SLionel Sambuc
75*ebfedea0SLionel Sambuc #include "packet-parse.h"
76*ebfedea0SLionel Sambuc #include "packet-show.h"
77*ebfedea0SLionel Sambuc #include "keyring.h"
78*ebfedea0SLionel Sambuc #include "signature.h"
79*ebfedea0SLionel Sambuc #include "netpgpsdk.h"
80*ebfedea0SLionel Sambuc #include "readerwriter.h"
81*ebfedea0SLionel Sambuc #include "netpgpdefs.h"
82*ebfedea0SLionel Sambuc #include "memory.h"
83*ebfedea0SLionel Sambuc #include "packet.h"
84*ebfedea0SLionel Sambuc #include "crypto.h"
85*ebfedea0SLionel Sambuc #include "validate.h"
86*ebfedea0SLionel Sambuc
87*ebfedea0SLionel Sambuc #ifdef HAVE_FCNTL_H
88*ebfedea0SLionel Sambuc #include <fcntl.h>
89*ebfedea0SLionel Sambuc #endif
90*ebfedea0SLionel Sambuc
91*ebfedea0SLionel Sambuc
92*ebfedea0SLionel Sambuc 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)93*ebfedea0SLionel Sambuc keydata_reader(pgp_stream_t *stream, void *dest, size_t length, pgp_error_t **errors,
94*ebfedea0SLionel Sambuc pgp_reader_t *readinfo,
95*ebfedea0SLionel Sambuc pgp_cbdata_t *cbinfo)
96*ebfedea0SLionel Sambuc {
97*ebfedea0SLionel Sambuc validate_reader_t *reader = pgp_reader_get_arg(readinfo);
98*ebfedea0SLionel Sambuc
99*ebfedea0SLionel Sambuc __PGP_USED(stream);
100*ebfedea0SLionel Sambuc __PGP_USED(errors);
101*ebfedea0SLionel Sambuc __PGP_USED(cbinfo);
102*ebfedea0SLionel Sambuc if (reader->offset == reader->key->packets[reader->packet].length) {
103*ebfedea0SLionel Sambuc reader->packet += 1;
104*ebfedea0SLionel Sambuc reader->offset = 0;
105*ebfedea0SLionel Sambuc }
106*ebfedea0SLionel Sambuc if (reader->packet == reader->key->packetc) {
107*ebfedea0SLionel Sambuc return 0;
108*ebfedea0SLionel Sambuc }
109*ebfedea0SLionel Sambuc
110*ebfedea0SLionel Sambuc /*
111*ebfedea0SLionel Sambuc * we should never be asked to cross a packet boundary in a single
112*ebfedea0SLionel Sambuc * read
113*ebfedea0SLionel Sambuc */
114*ebfedea0SLionel Sambuc if (reader->key->packets[reader->packet].length <
115*ebfedea0SLionel Sambuc reader->offset + length) {
116*ebfedea0SLionel Sambuc (void) fprintf(stderr, "keydata_reader: weird length\n");
117*ebfedea0SLionel Sambuc return 0;
118*ebfedea0SLionel Sambuc }
119*ebfedea0SLionel Sambuc
120*ebfedea0SLionel Sambuc (void) memcpy(dest,
121*ebfedea0SLionel Sambuc &reader->key->packets[reader->packet].raw[reader->offset],
122*ebfedea0SLionel Sambuc length);
123*ebfedea0SLionel Sambuc reader->offset += (unsigned)length;
124*ebfedea0SLionel Sambuc
125*ebfedea0SLionel Sambuc return (int)length;
126*ebfedea0SLionel Sambuc }
127*ebfedea0SLionel Sambuc
128*ebfedea0SLionel Sambuc static void
free_sig_info(pgp_sig_info_t * sig)129*ebfedea0SLionel Sambuc free_sig_info(pgp_sig_info_t *sig)
130*ebfedea0SLionel Sambuc {
131*ebfedea0SLionel Sambuc free(sig->v4_hashed);
132*ebfedea0SLionel Sambuc free(sig);
133*ebfedea0SLionel Sambuc }
134*ebfedea0SLionel Sambuc
135*ebfedea0SLionel Sambuc static void
copy_sig_info(pgp_sig_info_t * dst,const pgp_sig_info_t * src)136*ebfedea0SLionel Sambuc copy_sig_info(pgp_sig_info_t *dst, const pgp_sig_info_t *src)
137*ebfedea0SLionel Sambuc {
138*ebfedea0SLionel Sambuc (void) memcpy(dst, src, sizeof(*src));
139*ebfedea0SLionel Sambuc if ((dst->v4_hashed = calloc(1, src->v4_hashlen)) == NULL) {
140*ebfedea0SLionel Sambuc (void) fprintf(stderr, "copy_sig_info: bad alloc\n");
141*ebfedea0SLionel Sambuc } else {
142*ebfedea0SLionel Sambuc (void) memcpy(dst->v4_hashed, src->v4_hashed, src->v4_hashlen);
143*ebfedea0SLionel Sambuc }
144*ebfedea0SLionel Sambuc }
145*ebfedea0SLionel Sambuc
146*ebfedea0SLionel Sambuc static int
add_sig_to_list(const pgp_sig_info_t * sig,pgp_sig_info_t ** sigs,unsigned * count)147*ebfedea0SLionel Sambuc add_sig_to_list(const pgp_sig_info_t *sig, pgp_sig_info_t **sigs,
148*ebfedea0SLionel Sambuc unsigned *count)
149*ebfedea0SLionel Sambuc {
150*ebfedea0SLionel Sambuc pgp_sig_info_t *newsigs;
151*ebfedea0SLionel Sambuc
152*ebfedea0SLionel Sambuc if (*count == 0) {
153*ebfedea0SLionel Sambuc newsigs = calloc(*count + 1, sizeof(pgp_sig_info_t));
154*ebfedea0SLionel Sambuc } else {
155*ebfedea0SLionel Sambuc newsigs = realloc(*sigs,
156*ebfedea0SLionel Sambuc (*count + 1) * sizeof(pgp_sig_info_t));
157*ebfedea0SLionel Sambuc }
158*ebfedea0SLionel Sambuc if (newsigs == NULL) {
159*ebfedea0SLionel Sambuc (void) fprintf(stderr, "add_sig_to_list: alloc failure\n");
160*ebfedea0SLionel Sambuc return 0;
161*ebfedea0SLionel Sambuc }
162*ebfedea0SLionel Sambuc *sigs = newsigs;
163*ebfedea0SLionel Sambuc copy_sig_info(&(*sigs)[*count], sig);
164*ebfedea0SLionel Sambuc *count += 1;
165*ebfedea0SLionel Sambuc return 1;
166*ebfedea0SLionel Sambuc }
167*ebfedea0SLionel Sambuc
168*ebfedea0SLionel Sambuc /*
169*ebfedea0SLionel Sambuc The hash value is calculated by the following method:
170*ebfedea0SLionel Sambuc + hash the data using the given digest algorithm
171*ebfedea0SLionel Sambuc + hash the hash value onto the end
172*ebfedea0SLionel Sambuc + hash the trailer - 6 bytes
173*ebfedea0SLionel Sambuc [PGP_V4][0xff][len >> 24][len >> 16][len >> 8][len & 0xff]
174*ebfedea0SLionel Sambuc to give the final hash value that is checked against the one in the signature
175*ebfedea0SLionel Sambuc */
176*ebfedea0SLionel Sambuc
177*ebfedea0SLionel Sambuc /* Does the signed hash match the given hash? */
178*ebfedea0SLionel Sambuc unsigned
check_binary_sig(const uint8_t * data,const unsigned len,const pgp_sig_t * sig,const pgp_pubkey_t * signer)179*ebfedea0SLionel Sambuc check_binary_sig(const uint8_t *data,
180*ebfedea0SLionel Sambuc const unsigned len,
181*ebfedea0SLionel Sambuc const pgp_sig_t *sig,
182*ebfedea0SLionel Sambuc const pgp_pubkey_t *signer)
183*ebfedea0SLionel Sambuc {
184*ebfedea0SLionel Sambuc unsigned hashedlen;
185*ebfedea0SLionel Sambuc pgp_hash_t hash;
186*ebfedea0SLionel Sambuc unsigned n;
187*ebfedea0SLionel Sambuc uint8_t hashout[PGP_MAX_HASH_SIZE];
188*ebfedea0SLionel Sambuc uint8_t trailer[6];
189*ebfedea0SLionel Sambuc
190*ebfedea0SLionel Sambuc pgp_hash_any(&hash, sig->info.hash_alg);
191*ebfedea0SLionel Sambuc if (!hash.init(&hash)) {
192*ebfedea0SLionel Sambuc (void) fprintf(stderr, "check_binary_sig: bad hash init\n");
193*ebfedea0SLionel Sambuc return 0;
194*ebfedea0SLionel Sambuc }
195*ebfedea0SLionel Sambuc hash.add(&hash, data, len);
196*ebfedea0SLionel Sambuc switch (sig->info.version) {
197*ebfedea0SLionel Sambuc case PGP_V3:
198*ebfedea0SLionel Sambuc trailer[0] = sig->info.type;
199*ebfedea0SLionel Sambuc trailer[1] = (unsigned)(sig->info.birthtime) >> 24;
200*ebfedea0SLionel Sambuc trailer[2] = (unsigned)(sig->info.birthtime) >> 16;
201*ebfedea0SLionel Sambuc trailer[3] = (unsigned)(sig->info.birthtime) >> 8;
202*ebfedea0SLionel Sambuc trailer[4] = (uint8_t)(sig->info.birthtime);
203*ebfedea0SLionel Sambuc hash.add(&hash, trailer, 5);
204*ebfedea0SLionel Sambuc break;
205*ebfedea0SLionel Sambuc
206*ebfedea0SLionel Sambuc case PGP_V4:
207*ebfedea0SLionel Sambuc if (pgp_get_debug_level(__FILE__)) {
208*ebfedea0SLionel Sambuc hexdump(stderr, "v4 hash", sig->info.v4_hashed,
209*ebfedea0SLionel Sambuc sig->info.v4_hashlen);
210*ebfedea0SLionel Sambuc }
211*ebfedea0SLionel Sambuc hash.add(&hash, sig->info.v4_hashed, (unsigned)sig->info.v4_hashlen);
212*ebfedea0SLionel Sambuc trailer[0] = 0x04; /* version */
213*ebfedea0SLionel Sambuc trailer[1] = 0xFF;
214*ebfedea0SLionel Sambuc hashedlen = (unsigned)sig->info.v4_hashlen;
215*ebfedea0SLionel Sambuc trailer[2] = (uint8_t)(hashedlen >> 24);
216*ebfedea0SLionel Sambuc trailer[3] = (uint8_t)(hashedlen >> 16);
217*ebfedea0SLionel Sambuc trailer[4] = (uint8_t)(hashedlen >> 8);
218*ebfedea0SLionel Sambuc trailer[5] = (uint8_t)(hashedlen);
219*ebfedea0SLionel Sambuc hash.add(&hash, trailer, 6);
220*ebfedea0SLionel Sambuc break;
221*ebfedea0SLionel Sambuc
222*ebfedea0SLionel Sambuc default:
223*ebfedea0SLionel Sambuc (void) fprintf(stderr, "Invalid signature version %d\n",
224*ebfedea0SLionel Sambuc sig->info.version);
225*ebfedea0SLionel Sambuc return 0;
226*ebfedea0SLionel Sambuc }
227*ebfedea0SLionel Sambuc
228*ebfedea0SLionel Sambuc n = hash.finish(&hash, hashout);
229*ebfedea0SLionel Sambuc if (pgp_get_debug_level(__FILE__)) {
230*ebfedea0SLionel Sambuc hexdump(stdout, "hash out", hashout, n);
231*ebfedea0SLionel Sambuc }
232*ebfedea0SLionel Sambuc return pgp_check_sig(hashout, n, sig, signer);
233*ebfedea0SLionel Sambuc }
234*ebfedea0SLionel Sambuc
235*ebfedea0SLionel Sambuc pgp_cb_ret_t
pgp_validate_key_cb(const pgp_packet_t * pkt,pgp_cbdata_t * cbinfo)236*ebfedea0SLionel Sambuc pgp_validate_key_cb(const pgp_packet_t *pkt, pgp_cbdata_t *cbinfo)
237*ebfedea0SLionel Sambuc {
238*ebfedea0SLionel Sambuc const pgp_contents_t *content = &pkt->u;
239*ebfedea0SLionel Sambuc const pgp_key_t *signer;
240*ebfedea0SLionel Sambuc validate_key_cb_t *key;
241*ebfedea0SLionel Sambuc pgp_pubkey_t *sigkey;
242*ebfedea0SLionel Sambuc pgp_error_t **errors;
243*ebfedea0SLionel Sambuc pgp_io_t *io;
244*ebfedea0SLionel Sambuc unsigned from;
245*ebfedea0SLionel Sambuc unsigned valid = 0;
246*ebfedea0SLionel Sambuc
247*ebfedea0SLionel Sambuc io = cbinfo->io;
248*ebfedea0SLionel Sambuc if (pgp_get_debug_level(__FILE__)) {
249*ebfedea0SLionel Sambuc (void) fprintf(io->errs, "%s\n",
250*ebfedea0SLionel Sambuc pgp_show_packet_tag(pkt->tag));
251*ebfedea0SLionel Sambuc }
252*ebfedea0SLionel Sambuc key = pgp_callback_arg(cbinfo);
253*ebfedea0SLionel Sambuc errors = pgp_callback_errors(cbinfo);
254*ebfedea0SLionel Sambuc switch (pkt->tag) {
255*ebfedea0SLionel Sambuc case PGP_PTAG_CT_PUBLIC_KEY:
256*ebfedea0SLionel Sambuc if (key->pubkey.version != 0) {
257*ebfedea0SLionel Sambuc (void) fprintf(io->errs,
258*ebfedea0SLionel Sambuc "pgp_validate_key_cb: version bad\n");
259*ebfedea0SLionel Sambuc return PGP_FINISHED;
260*ebfedea0SLionel Sambuc }
261*ebfedea0SLionel Sambuc key->pubkey = content->pubkey;
262*ebfedea0SLionel Sambuc return PGP_KEEP_MEMORY;
263*ebfedea0SLionel Sambuc
264*ebfedea0SLionel Sambuc case PGP_PTAG_CT_PUBLIC_SUBKEY:
265*ebfedea0SLionel Sambuc if (key->subkey.version) {
266*ebfedea0SLionel Sambuc pgp_pubkey_free(&key->subkey);
267*ebfedea0SLionel Sambuc }
268*ebfedea0SLionel Sambuc key->subkey = content->pubkey;
269*ebfedea0SLionel Sambuc return PGP_KEEP_MEMORY;
270*ebfedea0SLionel Sambuc
271*ebfedea0SLionel Sambuc case PGP_PTAG_CT_SECRET_KEY:
272*ebfedea0SLionel Sambuc key->seckey = content->seckey;
273*ebfedea0SLionel Sambuc key->pubkey = key->seckey.pubkey;
274*ebfedea0SLionel Sambuc return PGP_KEEP_MEMORY;
275*ebfedea0SLionel Sambuc
276*ebfedea0SLionel Sambuc case PGP_PTAG_CT_USER_ID:
277*ebfedea0SLionel Sambuc if (key->userid) {
278*ebfedea0SLionel Sambuc pgp_userid_free(&key->userid);
279*ebfedea0SLionel Sambuc }
280*ebfedea0SLionel Sambuc key->userid = content->userid;
281*ebfedea0SLionel Sambuc key->last_seen = ID;
282*ebfedea0SLionel Sambuc return PGP_KEEP_MEMORY;
283*ebfedea0SLionel Sambuc
284*ebfedea0SLionel Sambuc case PGP_PTAG_CT_USER_ATTR:
285*ebfedea0SLionel Sambuc if (content->userattr.len == 0) {
286*ebfedea0SLionel Sambuc (void) fprintf(io->errs,
287*ebfedea0SLionel Sambuc "pgp_validate_key_cb: user attribute length 0");
288*ebfedea0SLionel Sambuc return PGP_FINISHED;
289*ebfedea0SLionel Sambuc }
290*ebfedea0SLionel Sambuc (void) fprintf(io->outs, "user attribute, length=%d\n",
291*ebfedea0SLionel Sambuc (int) content->userattr.len);
292*ebfedea0SLionel Sambuc if (key->userattr.len) {
293*ebfedea0SLionel Sambuc pgp_data_free(&key->userattr);
294*ebfedea0SLionel Sambuc }
295*ebfedea0SLionel Sambuc key->userattr = content->userattr;
296*ebfedea0SLionel Sambuc key->last_seen = ATTRIBUTE;
297*ebfedea0SLionel Sambuc return PGP_KEEP_MEMORY;
298*ebfedea0SLionel Sambuc
299*ebfedea0SLionel Sambuc case PGP_PTAG_CT_SIGNATURE: /* V3 sigs */
300*ebfedea0SLionel Sambuc case PGP_PTAG_CT_SIGNATURE_FOOTER: /* V4 sigs */
301*ebfedea0SLionel Sambuc from = 0;
302*ebfedea0SLionel Sambuc signer = pgp_getkeybyid(io, key->keyring,
303*ebfedea0SLionel Sambuc content->sig.info.signer_id,
304*ebfedea0SLionel Sambuc &from, &sigkey);
305*ebfedea0SLionel Sambuc if (!signer) {
306*ebfedea0SLionel Sambuc if (!add_sig_to_list(&content->sig.info,
307*ebfedea0SLionel Sambuc &key->result->unknown_sigs,
308*ebfedea0SLionel Sambuc &key->result->unknownc)) {
309*ebfedea0SLionel Sambuc (void) fprintf(io->errs,
310*ebfedea0SLionel Sambuc "pgp_validate_key_cb: user attribute length 0");
311*ebfedea0SLionel Sambuc return PGP_FINISHED;
312*ebfedea0SLionel Sambuc }
313*ebfedea0SLionel Sambuc break;
314*ebfedea0SLionel Sambuc }
315*ebfedea0SLionel Sambuc if (sigkey == &signer->enckey) {
316*ebfedea0SLionel Sambuc (void) fprintf(io->errs,
317*ebfedea0SLionel Sambuc "WARNING: signature made with encryption key\n");
318*ebfedea0SLionel Sambuc }
319*ebfedea0SLionel Sambuc switch (content->sig.info.type) {
320*ebfedea0SLionel Sambuc case PGP_CERT_GENERIC:
321*ebfedea0SLionel Sambuc case PGP_CERT_PERSONA:
322*ebfedea0SLionel Sambuc case PGP_CERT_CASUAL:
323*ebfedea0SLionel Sambuc case PGP_CERT_POSITIVE:
324*ebfedea0SLionel Sambuc case PGP_SIG_REV_CERT:
325*ebfedea0SLionel Sambuc valid = (key->last_seen == ID) ?
326*ebfedea0SLionel Sambuc pgp_check_useridcert_sig(&key->pubkey,
327*ebfedea0SLionel Sambuc key->userid,
328*ebfedea0SLionel Sambuc &content->sig,
329*ebfedea0SLionel Sambuc pgp_get_pubkey(signer),
330*ebfedea0SLionel Sambuc key->reader->key->packets[
331*ebfedea0SLionel Sambuc key->reader->packet].raw) :
332*ebfedea0SLionel Sambuc pgp_check_userattrcert_sig(&key->pubkey,
333*ebfedea0SLionel Sambuc &key->userattr,
334*ebfedea0SLionel Sambuc &content->sig,
335*ebfedea0SLionel Sambuc pgp_get_pubkey(signer),
336*ebfedea0SLionel Sambuc key->reader->key->packets[
337*ebfedea0SLionel Sambuc key->reader->packet].raw);
338*ebfedea0SLionel Sambuc break;
339*ebfedea0SLionel Sambuc
340*ebfedea0SLionel Sambuc case PGP_SIG_SUBKEY:
341*ebfedea0SLionel Sambuc /*
342*ebfedea0SLionel Sambuc * XXX: we should also check that the signer is the
343*ebfedea0SLionel Sambuc * key we are validating, I think.
344*ebfedea0SLionel Sambuc */
345*ebfedea0SLionel Sambuc valid = pgp_check_subkey_sig(&key->pubkey,
346*ebfedea0SLionel Sambuc &key->subkey,
347*ebfedea0SLionel Sambuc &content->sig,
348*ebfedea0SLionel Sambuc pgp_get_pubkey(signer),
349*ebfedea0SLionel Sambuc key->reader->key->packets[
350*ebfedea0SLionel Sambuc key->reader->packet].raw);
351*ebfedea0SLionel Sambuc break;
352*ebfedea0SLionel Sambuc
353*ebfedea0SLionel Sambuc case PGP_SIG_DIRECT:
354*ebfedea0SLionel Sambuc valid = pgp_check_direct_sig(&key->pubkey,
355*ebfedea0SLionel Sambuc &content->sig,
356*ebfedea0SLionel Sambuc pgp_get_pubkey(signer),
357*ebfedea0SLionel Sambuc key->reader->key->packets[
358*ebfedea0SLionel Sambuc key->reader->packet].raw);
359*ebfedea0SLionel Sambuc break;
360*ebfedea0SLionel Sambuc
361*ebfedea0SLionel Sambuc case PGP_SIG_STANDALONE:
362*ebfedea0SLionel Sambuc case PGP_SIG_PRIMARY:
363*ebfedea0SLionel Sambuc case PGP_SIG_REV_KEY:
364*ebfedea0SLionel Sambuc case PGP_SIG_REV_SUBKEY:
365*ebfedea0SLionel Sambuc case PGP_SIG_TIMESTAMP:
366*ebfedea0SLionel Sambuc case PGP_SIG_3RD_PARTY:
367*ebfedea0SLionel Sambuc PGP_ERROR_1(errors, PGP_E_UNIMPLEMENTED,
368*ebfedea0SLionel Sambuc "Sig Verification type 0x%02x not done yet\n",
369*ebfedea0SLionel Sambuc content->sig.info.type);
370*ebfedea0SLionel Sambuc break;
371*ebfedea0SLionel Sambuc
372*ebfedea0SLionel Sambuc default:
373*ebfedea0SLionel Sambuc PGP_ERROR_1(errors, PGP_E_UNIMPLEMENTED,
374*ebfedea0SLionel Sambuc "Unexpected signature type 0x%02x\n",
375*ebfedea0SLionel Sambuc content->sig.info.type);
376*ebfedea0SLionel Sambuc }
377*ebfedea0SLionel Sambuc
378*ebfedea0SLionel Sambuc if (valid) {
379*ebfedea0SLionel Sambuc if (!add_sig_to_list(&content->sig.info,
380*ebfedea0SLionel Sambuc &key->result->valid_sigs,
381*ebfedea0SLionel Sambuc &key->result->validc)) {
382*ebfedea0SLionel Sambuc PGP_ERROR_1(errors, PGP_E_UNIMPLEMENTED, "%s",
383*ebfedea0SLionel Sambuc "Can't add good sig to list\n");
384*ebfedea0SLionel Sambuc }
385*ebfedea0SLionel Sambuc } else {
386*ebfedea0SLionel Sambuc PGP_ERROR_1(errors, PGP_E_V_BAD_SIGNATURE, "%s",
387*ebfedea0SLionel Sambuc "Bad Sig");
388*ebfedea0SLionel Sambuc if (!add_sig_to_list(&content->sig.info,
389*ebfedea0SLionel Sambuc &key->result->invalid_sigs,
390*ebfedea0SLionel Sambuc &key->result->invalidc)) {
391*ebfedea0SLionel Sambuc PGP_ERROR_1(errors, PGP_E_UNIMPLEMENTED, "%s",
392*ebfedea0SLionel Sambuc "Can't add good sig to list\n");
393*ebfedea0SLionel Sambuc }
394*ebfedea0SLionel Sambuc }
395*ebfedea0SLionel Sambuc break;
396*ebfedea0SLionel Sambuc
397*ebfedea0SLionel Sambuc /* ignore these */
398*ebfedea0SLionel Sambuc case PGP_PARSER_PTAG:
399*ebfedea0SLionel Sambuc case PGP_PTAG_CT_SIGNATURE_HEADER:
400*ebfedea0SLionel Sambuc case PGP_PARSER_PACKET_END:
401*ebfedea0SLionel Sambuc break;
402*ebfedea0SLionel Sambuc
403*ebfedea0SLionel Sambuc case PGP_GET_PASSPHRASE:
404*ebfedea0SLionel Sambuc if (key->getpassphrase) {
405*ebfedea0SLionel Sambuc return key->getpassphrase(pkt, cbinfo);
406*ebfedea0SLionel Sambuc }
407*ebfedea0SLionel Sambuc break;
408*ebfedea0SLionel Sambuc
409*ebfedea0SLionel Sambuc case PGP_PTAG_CT_TRUST:
410*ebfedea0SLionel Sambuc /* 1 byte for level (depth), 1 byte for trust amount */
411*ebfedea0SLionel Sambuc printf("trust dump\n");
412*ebfedea0SLionel Sambuc printf("Got trust\n");
413*ebfedea0SLionel Sambuc //hexdump(stdout, (const uint8_t *)content->trust.data, 10, " ");
414*ebfedea0SLionel Sambuc //hexdump(stdout, (const uint8_t *)&content->ss_trust, 2, " ");
415*ebfedea0SLionel Sambuc //printf("Trust level %d, amount %d\n", key->trust.level, key->trust.amount);
416*ebfedea0SLionel Sambuc break;
417*ebfedea0SLionel Sambuc
418*ebfedea0SLionel Sambuc default:
419*ebfedea0SLionel Sambuc (void) fprintf(stderr, "unexpected tag=0x%x\n", pkt->tag);
420*ebfedea0SLionel Sambuc return PGP_FINISHED;
421*ebfedea0SLionel Sambuc }
422*ebfedea0SLionel Sambuc return PGP_RELEASE_MEMORY;
423*ebfedea0SLionel Sambuc }
424*ebfedea0SLionel Sambuc
425*ebfedea0SLionel Sambuc pgp_cb_ret_t
validate_data_cb(const pgp_packet_t * pkt,pgp_cbdata_t * cbinfo)426*ebfedea0SLionel Sambuc validate_data_cb(const pgp_packet_t *pkt, pgp_cbdata_t *cbinfo)
427*ebfedea0SLionel Sambuc {
428*ebfedea0SLionel Sambuc const pgp_contents_t *content = &pkt->u;
429*ebfedea0SLionel Sambuc const pgp_key_t *signer;
430*ebfedea0SLionel Sambuc validate_data_cb_t *data;
431*ebfedea0SLionel Sambuc pgp_pubkey_t *sigkey;
432*ebfedea0SLionel Sambuc pgp_error_t **errors;
433*ebfedea0SLionel Sambuc pgp_io_t *io;
434*ebfedea0SLionel Sambuc unsigned from;
435*ebfedea0SLionel Sambuc unsigned valid = 0;
436*ebfedea0SLionel Sambuc
437*ebfedea0SLionel Sambuc io = cbinfo->io;
438*ebfedea0SLionel Sambuc if (pgp_get_debug_level(__FILE__)) {
439*ebfedea0SLionel Sambuc (void) fprintf(io->errs, "validate_data_cb: %s\n",
440*ebfedea0SLionel Sambuc pgp_show_packet_tag(pkt->tag));
441*ebfedea0SLionel Sambuc }
442*ebfedea0SLionel Sambuc data = pgp_callback_arg(cbinfo);
443*ebfedea0SLionel Sambuc errors = pgp_callback_errors(cbinfo);
444*ebfedea0SLionel Sambuc switch (pkt->tag) {
445*ebfedea0SLionel Sambuc case PGP_PTAG_CT_SIGNED_CLEARTEXT_HEADER:
446*ebfedea0SLionel Sambuc /*
447*ebfedea0SLionel Sambuc * ignore - this gives us the "Armor Header" line "Hash:
448*ebfedea0SLionel Sambuc * SHA1" or similar
449*ebfedea0SLionel Sambuc */
450*ebfedea0SLionel Sambuc break;
451*ebfedea0SLionel Sambuc
452*ebfedea0SLionel Sambuc case PGP_PTAG_CT_LITDATA_HEADER:
453*ebfedea0SLionel Sambuc /* ignore */
454*ebfedea0SLionel Sambuc break;
455*ebfedea0SLionel Sambuc
456*ebfedea0SLionel Sambuc case PGP_PTAG_CT_LITDATA_BODY:
457*ebfedea0SLionel Sambuc data->data.litdata_body = content->litdata_body;
458*ebfedea0SLionel Sambuc data->type = LITDATA;
459*ebfedea0SLionel Sambuc pgp_memory_add(data->mem, data->data.litdata_body.data,
460*ebfedea0SLionel Sambuc data->data.litdata_body.length);
461*ebfedea0SLionel Sambuc return PGP_KEEP_MEMORY;
462*ebfedea0SLionel Sambuc
463*ebfedea0SLionel Sambuc case PGP_PTAG_CT_SIGNED_CLEARTEXT_BODY:
464*ebfedea0SLionel Sambuc data->data.cleartext_body = content->cleartext_body;
465*ebfedea0SLionel Sambuc data->type = SIGNED_CLEARTEXT;
466*ebfedea0SLionel Sambuc pgp_memory_add(data->mem, data->data.cleartext_body.data,
467*ebfedea0SLionel Sambuc data->data.cleartext_body.length);
468*ebfedea0SLionel Sambuc return PGP_KEEP_MEMORY;
469*ebfedea0SLionel Sambuc
470*ebfedea0SLionel Sambuc case PGP_PTAG_CT_SIGNED_CLEARTEXT_TRAILER:
471*ebfedea0SLionel Sambuc /* this gives us an pgp_hash_t struct */
472*ebfedea0SLionel Sambuc break;
473*ebfedea0SLionel Sambuc
474*ebfedea0SLionel Sambuc case PGP_PTAG_CT_SIGNATURE: /* V3 sigs */
475*ebfedea0SLionel Sambuc case PGP_PTAG_CT_SIGNATURE_FOOTER: /* V4 sigs */
476*ebfedea0SLionel Sambuc if (pgp_get_debug_level(__FILE__)) {
477*ebfedea0SLionel Sambuc hexdump(io->outs, "hashed data", content->sig.info.v4_hashed,
478*ebfedea0SLionel Sambuc content->sig.info.v4_hashlen);
479*ebfedea0SLionel Sambuc hexdump(io->outs, "signer id", content->sig.info.signer_id,
480*ebfedea0SLionel Sambuc sizeof(content->sig.info.signer_id));
481*ebfedea0SLionel Sambuc }
482*ebfedea0SLionel Sambuc from = 0;
483*ebfedea0SLionel Sambuc signer = pgp_getkeybyid(io, data->keyring,
484*ebfedea0SLionel Sambuc content->sig.info.signer_id, &from, &sigkey);
485*ebfedea0SLionel Sambuc if (!signer) {
486*ebfedea0SLionel Sambuc PGP_ERROR_1(errors, PGP_E_V_UNKNOWN_SIGNER,
487*ebfedea0SLionel Sambuc "%s", "Unknown Signer");
488*ebfedea0SLionel Sambuc if (!add_sig_to_list(&content->sig.info,
489*ebfedea0SLionel Sambuc &data->result->unknown_sigs,
490*ebfedea0SLionel Sambuc &data->result->unknownc)) {
491*ebfedea0SLionel Sambuc PGP_ERROR_1(errors, PGP_E_V_UNKNOWN_SIGNER,
492*ebfedea0SLionel Sambuc "%s", "Can't add unknown sig to list");
493*ebfedea0SLionel Sambuc }
494*ebfedea0SLionel Sambuc break;
495*ebfedea0SLionel Sambuc }
496*ebfedea0SLionel Sambuc if (sigkey == &signer->enckey) {
497*ebfedea0SLionel Sambuc (void) fprintf(io->errs,
498*ebfedea0SLionel Sambuc "WARNING: signature made with encryption key\n");
499*ebfedea0SLionel Sambuc }
500*ebfedea0SLionel Sambuc if (content->sig.info.birthtime_set) {
501*ebfedea0SLionel Sambuc data->result->birthtime = content->sig.info.birthtime;
502*ebfedea0SLionel Sambuc }
503*ebfedea0SLionel Sambuc if (content->sig.info.duration_set) {
504*ebfedea0SLionel Sambuc data->result->duration = content->sig.info.duration;
505*ebfedea0SLionel Sambuc }
506*ebfedea0SLionel Sambuc switch (content->sig.info.type) {
507*ebfedea0SLionel Sambuc case PGP_SIG_BINARY:
508*ebfedea0SLionel Sambuc case PGP_SIG_TEXT:
509*ebfedea0SLionel Sambuc if (pgp_mem_len(data->mem) == 0 &&
510*ebfedea0SLionel Sambuc data->detachname) {
511*ebfedea0SLionel Sambuc /* check we have seen some data */
512*ebfedea0SLionel Sambuc /* if not, need to read from detached name */
513*ebfedea0SLionel Sambuc (void) fprintf(io->errs,
514*ebfedea0SLionel Sambuc "netpgp: assuming signed data in \"%s\"\n",
515*ebfedea0SLionel Sambuc data->detachname);
516*ebfedea0SLionel Sambuc data->mem = pgp_memory_new();
517*ebfedea0SLionel Sambuc pgp_mem_readfile(data->mem, data->detachname);
518*ebfedea0SLionel Sambuc }
519*ebfedea0SLionel Sambuc if (pgp_get_debug_level(__FILE__)) {
520*ebfedea0SLionel Sambuc hexdump(stderr, "sig dump", (const uint8_t *)(const void *)&content->sig,
521*ebfedea0SLionel Sambuc sizeof(content->sig));
522*ebfedea0SLionel Sambuc }
523*ebfedea0SLionel Sambuc valid = check_binary_sig(pgp_mem_data(data->mem),
524*ebfedea0SLionel Sambuc (const unsigned)pgp_mem_len(data->mem),
525*ebfedea0SLionel Sambuc &content->sig,
526*ebfedea0SLionel Sambuc pgp_get_pubkey(signer));
527*ebfedea0SLionel Sambuc break;
528*ebfedea0SLionel Sambuc
529*ebfedea0SLionel Sambuc default:
530*ebfedea0SLionel Sambuc PGP_ERROR_1(errors, PGP_E_UNIMPLEMENTED,
531*ebfedea0SLionel Sambuc "No Sig Verification type 0x%02x yet\n",
532*ebfedea0SLionel Sambuc content->sig.info.type);
533*ebfedea0SLionel Sambuc break;
534*ebfedea0SLionel Sambuc
535*ebfedea0SLionel Sambuc }
536*ebfedea0SLionel Sambuc
537*ebfedea0SLionel Sambuc if (valid) {
538*ebfedea0SLionel Sambuc if (!add_sig_to_list(&content->sig.info,
539*ebfedea0SLionel Sambuc &data->result->valid_sigs,
540*ebfedea0SLionel Sambuc &data->result->validc)) {
541*ebfedea0SLionel Sambuc PGP_ERROR_1(errors, PGP_E_V_BAD_SIGNATURE,
542*ebfedea0SLionel Sambuc "%s", "Can't add good sig to list");
543*ebfedea0SLionel Sambuc }
544*ebfedea0SLionel Sambuc } else {
545*ebfedea0SLionel Sambuc PGP_ERROR_1(errors, PGP_E_V_BAD_SIGNATURE,
546*ebfedea0SLionel Sambuc "%s", "Bad Signature");
547*ebfedea0SLionel Sambuc if (!add_sig_to_list(&content->sig.info,
548*ebfedea0SLionel Sambuc &data->result->invalid_sigs,
549*ebfedea0SLionel Sambuc &data->result->invalidc)) {
550*ebfedea0SLionel Sambuc PGP_ERROR_1(errors, PGP_E_V_BAD_SIGNATURE, "%s",
551*ebfedea0SLionel Sambuc "Can't add good sig to list");
552*ebfedea0SLionel Sambuc }
553*ebfedea0SLionel Sambuc }
554*ebfedea0SLionel Sambuc break;
555*ebfedea0SLionel Sambuc
556*ebfedea0SLionel Sambuc /* ignore these */
557*ebfedea0SLionel Sambuc case PGP_PARSER_PTAG:
558*ebfedea0SLionel Sambuc case PGP_PTAG_CT_SIGNATURE_HEADER:
559*ebfedea0SLionel Sambuc case PGP_PTAG_CT_ARMOUR_HEADER:
560*ebfedea0SLionel Sambuc case PGP_PTAG_CT_ARMOUR_TRAILER:
561*ebfedea0SLionel Sambuc case PGP_PTAG_CT_1_PASS_SIG:
562*ebfedea0SLionel Sambuc break;
563*ebfedea0SLionel Sambuc
564*ebfedea0SLionel Sambuc case PGP_PARSER_PACKET_END:
565*ebfedea0SLionel Sambuc break;
566*ebfedea0SLionel Sambuc
567*ebfedea0SLionel Sambuc default:
568*ebfedea0SLionel Sambuc PGP_ERROR_1(errors, PGP_E_V_NO_SIGNATURE, "%s", "No signature");
569*ebfedea0SLionel Sambuc break;
570*ebfedea0SLionel Sambuc }
571*ebfedea0SLionel Sambuc return PGP_RELEASE_MEMORY;
572*ebfedea0SLionel Sambuc }
573*ebfedea0SLionel Sambuc
574*ebfedea0SLionel Sambuc static void
keydata_destroyer(pgp_reader_t * readinfo)575*ebfedea0SLionel Sambuc keydata_destroyer(pgp_reader_t *readinfo)
576*ebfedea0SLionel Sambuc {
577*ebfedea0SLionel Sambuc free(pgp_reader_get_arg(readinfo));
578*ebfedea0SLionel Sambuc }
579*ebfedea0SLionel Sambuc
580*ebfedea0SLionel Sambuc void
pgp_keydata_reader_set(pgp_stream_t * stream,const pgp_key_t * key)581*ebfedea0SLionel Sambuc pgp_keydata_reader_set(pgp_stream_t *stream, const pgp_key_t *key)
582*ebfedea0SLionel Sambuc {
583*ebfedea0SLionel Sambuc validate_reader_t *data;
584*ebfedea0SLionel Sambuc
585*ebfedea0SLionel Sambuc if ((data = calloc(1, sizeof(*data))) == NULL) {
586*ebfedea0SLionel Sambuc (void) fprintf(stderr, "pgp_keydata_reader_set: bad alloc\n");
587*ebfedea0SLionel Sambuc } else {
588*ebfedea0SLionel Sambuc data->key = key;
589*ebfedea0SLionel Sambuc data->packet = 0;
590*ebfedea0SLionel Sambuc data->offset = 0;
591*ebfedea0SLionel Sambuc pgp_reader_set(stream, keydata_reader, keydata_destroyer, data);
592*ebfedea0SLionel Sambuc }
593*ebfedea0SLionel Sambuc }
594*ebfedea0SLionel Sambuc
595*ebfedea0SLionel Sambuc static char *
fmtsecs(int64_t n,char * buf,size_t size)596*ebfedea0SLionel Sambuc fmtsecs(int64_t n, char *buf, size_t size)
597*ebfedea0SLionel Sambuc {
598*ebfedea0SLionel Sambuc if (n > 365 * 24 * 60 * 60) {
599*ebfedea0SLionel Sambuc n /= (365 * 24 * 60 * 60);
600*ebfedea0SLionel Sambuc (void) snprintf(buf, size, "%" PRId64 " year%s", n, (n == 1) ? "" : "s");
601*ebfedea0SLionel Sambuc return buf;
602*ebfedea0SLionel Sambuc }
603*ebfedea0SLionel Sambuc if (n > 30 * 24 * 60 * 60) {
604*ebfedea0SLionel Sambuc n /= (30 * 24 * 60 * 60);
605*ebfedea0SLionel Sambuc (void) snprintf(buf, size, "%" PRId64 " month%s", n, (n == 1) ? "" : "s");
606*ebfedea0SLionel Sambuc return buf;
607*ebfedea0SLionel Sambuc }
608*ebfedea0SLionel Sambuc if (n > 24 * 60 * 60) {
609*ebfedea0SLionel Sambuc n /= (24 * 60 * 60);
610*ebfedea0SLionel Sambuc (void) snprintf(buf, size, "%" PRId64 " day%s", n, (n == 1) ? "" : "s");
611*ebfedea0SLionel Sambuc return buf;
612*ebfedea0SLionel Sambuc }
613*ebfedea0SLionel Sambuc if (n > 60 * 60) {
614*ebfedea0SLionel Sambuc n /= (60 * 60);
615*ebfedea0SLionel Sambuc (void) snprintf(buf, size, "%" PRId64 " hour%s", n, (n == 1) ? "" : "s");
616*ebfedea0SLionel Sambuc return buf;
617*ebfedea0SLionel Sambuc }
618*ebfedea0SLionel Sambuc if (n > 60) {
619*ebfedea0SLionel Sambuc n /= 60;
620*ebfedea0SLionel Sambuc (void) snprintf(buf, size, "%" PRId64 " minute%s", n, (n == 1) ? "" : "s");
621*ebfedea0SLionel Sambuc return buf;
622*ebfedea0SLionel Sambuc }
623*ebfedea0SLionel Sambuc (void) snprintf(buf, size, "%" PRId64 " second%s", n, (n == 1) ? "" : "s");
624*ebfedea0SLionel Sambuc return buf;
625*ebfedea0SLionel Sambuc }
626*ebfedea0SLionel Sambuc
627*ebfedea0SLionel Sambuc /**
628*ebfedea0SLionel Sambuc * \ingroup HighLevel_Verify
629*ebfedea0SLionel Sambuc * \brief Indicicates whether any errors were found
630*ebfedea0SLionel Sambuc * \param result Validation result to check
631*ebfedea0SLionel Sambuc * \return 0 if any invalid signatures or unknown signers
632*ebfedea0SLionel Sambuc or no valid signatures; else 1
633*ebfedea0SLionel Sambuc */
634*ebfedea0SLionel Sambuc static unsigned
validate_result_status(FILE * errs,const char * f,pgp_validation_t * val)635*ebfedea0SLionel Sambuc validate_result_status(FILE *errs, const char *f, pgp_validation_t *val)
636*ebfedea0SLionel Sambuc {
637*ebfedea0SLionel Sambuc time_t now;
638*ebfedea0SLionel Sambuc time_t t;
639*ebfedea0SLionel Sambuc char buf[128];
640*ebfedea0SLionel Sambuc
641*ebfedea0SLionel Sambuc now = time(NULL);
642*ebfedea0SLionel Sambuc if (now < val->birthtime) {
643*ebfedea0SLionel Sambuc /* signature is not valid yet! */
644*ebfedea0SLionel Sambuc if (f) {
645*ebfedea0SLionel Sambuc (void) fprintf(errs, "\"%s\": ", f);
646*ebfedea0SLionel Sambuc } else {
647*ebfedea0SLionel Sambuc (void) fprintf(errs, "memory ");
648*ebfedea0SLionel Sambuc }
649*ebfedea0SLionel Sambuc (void) fprintf(errs,
650*ebfedea0SLionel Sambuc "signature not valid until %.24s (%s)\n",
651*ebfedea0SLionel Sambuc ctime(&val->birthtime),
652*ebfedea0SLionel Sambuc fmtsecs((int64_t)(val->birthtime - now), buf, sizeof(buf)));
653*ebfedea0SLionel Sambuc return 0;
654*ebfedea0SLionel Sambuc }
655*ebfedea0SLionel Sambuc if (val->duration != 0 && now > val->birthtime + val->duration) {
656*ebfedea0SLionel Sambuc /* signature has expired */
657*ebfedea0SLionel Sambuc t = val->duration + val->birthtime;
658*ebfedea0SLionel Sambuc if (f) {
659*ebfedea0SLionel Sambuc (void) fprintf(errs, "\"%s\": ", f);
660*ebfedea0SLionel Sambuc } else {
661*ebfedea0SLionel Sambuc (void) fprintf(errs, "memory ");
662*ebfedea0SLionel Sambuc }
663*ebfedea0SLionel Sambuc (void) fprintf(errs,
664*ebfedea0SLionel Sambuc "signature not valid after %.24s (%s ago)\n",
665*ebfedea0SLionel Sambuc ctime(&t),
666*ebfedea0SLionel Sambuc fmtsecs((int64_t)(now - t), buf, sizeof(buf)));
667*ebfedea0SLionel Sambuc return 0;
668*ebfedea0SLionel Sambuc }
669*ebfedea0SLionel Sambuc return val->validc && !val->invalidc && !val->unknownc;
670*ebfedea0SLionel Sambuc }
671*ebfedea0SLionel Sambuc
672*ebfedea0SLionel Sambuc /**
673*ebfedea0SLionel Sambuc * \ingroup HighLevel_Verify
674*ebfedea0SLionel Sambuc * \brief Validate all signatures on a single key against the given keyring
675*ebfedea0SLionel Sambuc * \param result Where to put the result
676*ebfedea0SLionel Sambuc * \param key Key to validate
677*ebfedea0SLionel Sambuc * \param keyring Keyring to use for validation
678*ebfedea0SLionel Sambuc * \param cb_get_passphrase Callback to use to get passphrase
679*ebfedea0SLionel Sambuc * \return 1 if all signatures OK; else 0
680*ebfedea0SLionel Sambuc * \note It is the caller's responsiblity to free result after use.
681*ebfedea0SLionel Sambuc * \sa pgp_validate_result_free()
682*ebfedea0SLionel Sambuc */
683*ebfedea0SLionel Sambuc 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 *))684*ebfedea0SLionel Sambuc pgp_validate_key_sigs(pgp_validation_t *result,
685*ebfedea0SLionel Sambuc const pgp_key_t *key,
686*ebfedea0SLionel Sambuc const pgp_keyring_t *keyring,
687*ebfedea0SLionel Sambuc pgp_cb_ret_t cb_get_passphrase(const pgp_packet_t *,
688*ebfedea0SLionel Sambuc pgp_cbdata_t *))
689*ebfedea0SLionel Sambuc {
690*ebfedea0SLionel Sambuc pgp_stream_t *stream;
691*ebfedea0SLionel Sambuc validate_key_cb_t keysigs;
692*ebfedea0SLionel Sambuc const int printerrors = 1;
693*ebfedea0SLionel Sambuc
694*ebfedea0SLionel Sambuc (void) memset(&keysigs, 0x0, sizeof(keysigs));
695*ebfedea0SLionel Sambuc keysigs.result = result;
696*ebfedea0SLionel Sambuc keysigs.getpassphrase = cb_get_passphrase;
697*ebfedea0SLionel Sambuc
698*ebfedea0SLionel Sambuc stream = pgp_new(sizeof(*stream));
699*ebfedea0SLionel Sambuc /* pgp_parse_options(&opt,PGP_PTAG_CT_SIGNATURE,PGP_PARSE_PARSED); */
700*ebfedea0SLionel Sambuc
701*ebfedea0SLionel Sambuc keysigs.keyring = keyring;
702*ebfedea0SLionel Sambuc
703*ebfedea0SLionel Sambuc pgp_set_callback(stream, pgp_validate_key_cb, &keysigs);
704*ebfedea0SLionel Sambuc stream->readinfo.accumulate = 1;
705*ebfedea0SLionel Sambuc pgp_keydata_reader_set(stream, key);
706*ebfedea0SLionel Sambuc
707*ebfedea0SLionel Sambuc /* Note: Coverity incorrectly reports an error that keysigs.reader */
708*ebfedea0SLionel Sambuc /* is never used. */
709*ebfedea0SLionel Sambuc keysigs.reader = stream->readinfo.arg;
710*ebfedea0SLionel Sambuc
711*ebfedea0SLionel Sambuc pgp_parse(stream, !printerrors);
712*ebfedea0SLionel Sambuc
713*ebfedea0SLionel Sambuc pgp_pubkey_free(&keysigs.pubkey);
714*ebfedea0SLionel Sambuc if (keysigs.subkey.version) {
715*ebfedea0SLionel Sambuc pgp_pubkey_free(&keysigs.subkey);
716*ebfedea0SLionel Sambuc }
717*ebfedea0SLionel Sambuc pgp_userid_free(&keysigs.userid);
718*ebfedea0SLionel Sambuc pgp_data_free(&keysigs.userattr);
719*ebfedea0SLionel Sambuc
720*ebfedea0SLionel Sambuc pgp_stream_delete(stream);
721*ebfedea0SLionel Sambuc
722*ebfedea0SLionel Sambuc return (!result->invalidc && !result->unknownc && result->validc);
723*ebfedea0SLionel Sambuc }
724*ebfedea0SLionel Sambuc
725*ebfedea0SLionel Sambuc /**
726*ebfedea0SLionel Sambuc \ingroup HighLevel_Verify
727*ebfedea0SLionel Sambuc \param result Where to put the result
728*ebfedea0SLionel Sambuc \param ring Keyring to use
729*ebfedea0SLionel Sambuc \param cb_get_passphrase Callback to use to get passphrase
730*ebfedea0SLionel Sambuc \note It is the caller's responsibility to free result after use.
731*ebfedea0SLionel Sambuc \sa pgp_validate_result_free()
732*ebfedea0SLionel Sambuc */
733*ebfedea0SLionel Sambuc 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 *))734*ebfedea0SLionel Sambuc pgp_validate_all_sigs(pgp_validation_t *result,
735*ebfedea0SLionel Sambuc const pgp_keyring_t *ring,
736*ebfedea0SLionel Sambuc pgp_cb_ret_t cb_get_passphrase(const pgp_packet_t *,
737*ebfedea0SLionel Sambuc pgp_cbdata_t *))
738*ebfedea0SLionel Sambuc {
739*ebfedea0SLionel Sambuc unsigned n;
740*ebfedea0SLionel Sambuc
741*ebfedea0SLionel Sambuc (void) memset(result, 0x0, sizeof(*result));
742*ebfedea0SLionel Sambuc for (n = 0; n < ring->keyc; ++n) {
743*ebfedea0SLionel Sambuc pgp_validate_key_sigs(result, &ring->keys[n], ring,
744*ebfedea0SLionel Sambuc cb_get_passphrase);
745*ebfedea0SLionel Sambuc }
746*ebfedea0SLionel Sambuc return validate_result_status(stderr, "keyring", result);
747*ebfedea0SLionel Sambuc }
748*ebfedea0SLionel Sambuc
749*ebfedea0SLionel Sambuc /**
750*ebfedea0SLionel Sambuc \ingroup HighLevel_Verify
751*ebfedea0SLionel Sambuc \brief Frees validation result and associated memory
752*ebfedea0SLionel Sambuc \param result Struct to be freed
753*ebfedea0SLionel Sambuc \note Must be called after validation functions
754*ebfedea0SLionel Sambuc */
755*ebfedea0SLionel Sambuc void
pgp_validate_result_free(pgp_validation_t * result)756*ebfedea0SLionel Sambuc pgp_validate_result_free(pgp_validation_t *result)
757*ebfedea0SLionel Sambuc {
758*ebfedea0SLionel Sambuc if (result != NULL) {
759*ebfedea0SLionel Sambuc if (result->valid_sigs) {
760*ebfedea0SLionel Sambuc free_sig_info(result->valid_sigs);
761*ebfedea0SLionel Sambuc }
762*ebfedea0SLionel Sambuc if (result->invalid_sigs) {
763*ebfedea0SLionel Sambuc free_sig_info(result->invalid_sigs);
764*ebfedea0SLionel Sambuc }
765*ebfedea0SLionel Sambuc if (result->unknown_sigs) {
766*ebfedea0SLionel Sambuc free_sig_info(result->unknown_sigs);
767*ebfedea0SLionel Sambuc }
768*ebfedea0SLionel Sambuc free(result);
769*ebfedea0SLionel Sambuc /* result = NULL; - XXX unnecessary */
770*ebfedea0SLionel Sambuc }
771*ebfedea0SLionel Sambuc }
772*ebfedea0SLionel Sambuc
773*ebfedea0SLionel Sambuc /**
774*ebfedea0SLionel Sambuc \ingroup HighLevel_Verify
775*ebfedea0SLionel Sambuc \brief Verifies the signatures in a signed file
776*ebfedea0SLionel Sambuc \param result Where to put the result
777*ebfedea0SLionel Sambuc \param filename Name of file to be validated
778*ebfedea0SLionel Sambuc \param armoured Treat file as armoured, if set
779*ebfedea0SLionel Sambuc \param keyring Keyring to use
780*ebfedea0SLionel Sambuc \return 1 if signatures validate successfully;
781*ebfedea0SLionel Sambuc 0 if signatures fail or there are no signatures
782*ebfedea0SLionel Sambuc \note After verification, result holds the details of all keys which
783*ebfedea0SLionel Sambuc have passed, failed and not been recognised.
784*ebfedea0SLionel Sambuc \note It is the caller's responsiblity to call
785*ebfedea0SLionel Sambuc pgp_validate_result_free(result) after use.
786*ebfedea0SLionel Sambuc */
787*ebfedea0SLionel Sambuc 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)788*ebfedea0SLionel Sambuc pgp_validate_file(pgp_io_t *io,
789*ebfedea0SLionel Sambuc pgp_validation_t *result,
790*ebfedea0SLionel Sambuc const char *infile,
791*ebfedea0SLionel Sambuc const char *outfile,
792*ebfedea0SLionel Sambuc const int user_says_armoured,
793*ebfedea0SLionel Sambuc const pgp_keyring_t *keyring)
794*ebfedea0SLionel Sambuc {
795*ebfedea0SLionel Sambuc validate_data_cb_t validation;
796*ebfedea0SLionel Sambuc pgp_stream_t *parse = NULL;
797*ebfedea0SLionel Sambuc struct stat st;
798*ebfedea0SLionel Sambuc const char *signame;
799*ebfedea0SLionel Sambuc const int printerrors = 1;
800*ebfedea0SLionel Sambuc unsigned ret;
801*ebfedea0SLionel Sambuc char f[MAXPATHLEN];
802*ebfedea0SLionel Sambuc char *dataname;
803*ebfedea0SLionel Sambuc int realarmour;
804*ebfedea0SLionel Sambuc int outfd = 0;
805*ebfedea0SLionel Sambuc int infd;
806*ebfedea0SLionel Sambuc int cc;
807*ebfedea0SLionel Sambuc
808*ebfedea0SLionel Sambuc if (stat(infile, &st) < 0) {
809*ebfedea0SLionel Sambuc (void) fprintf(io->errs,
810*ebfedea0SLionel Sambuc "pgp_validate_file: can't open '%s'\n", infile);
811*ebfedea0SLionel Sambuc return 0;
812*ebfedea0SLionel Sambuc }
813*ebfedea0SLionel Sambuc realarmour = user_says_armoured;
814*ebfedea0SLionel Sambuc dataname = NULL;
815*ebfedea0SLionel Sambuc signame = NULL;
816*ebfedea0SLionel Sambuc cc = snprintf(f, sizeof(f), "%s", infile);
817*ebfedea0SLionel Sambuc if (strcmp(&f[cc - 4], ".sig") == 0) {
818*ebfedea0SLionel Sambuc /* we've been given a sigfile as infile */
819*ebfedea0SLionel Sambuc f[cc - 4] = 0x0;
820*ebfedea0SLionel Sambuc /* set dataname to name of file which was signed */
821*ebfedea0SLionel Sambuc dataname = f;
822*ebfedea0SLionel Sambuc signame = infile;
823*ebfedea0SLionel Sambuc } else if (strcmp(&f[cc - 4], ".asc") == 0) {
824*ebfedea0SLionel Sambuc /* we've been given an armored sigfile as infile */
825*ebfedea0SLionel Sambuc f[cc - 4] = 0x0;
826*ebfedea0SLionel Sambuc /* set dataname to name of file which was signed */
827*ebfedea0SLionel Sambuc dataname = f;
828*ebfedea0SLionel Sambuc signame = infile;
829*ebfedea0SLionel Sambuc realarmour = 1;
830*ebfedea0SLionel Sambuc } else {
831*ebfedea0SLionel Sambuc signame = infile;
832*ebfedea0SLionel Sambuc }
833*ebfedea0SLionel Sambuc (void) memset(&validation, 0x0, sizeof(validation));
834*ebfedea0SLionel Sambuc infd = pgp_setup_file_read(io, &parse, signame, &validation,
835*ebfedea0SLionel Sambuc validate_data_cb, 1);
836*ebfedea0SLionel Sambuc if (infd < 0) {
837*ebfedea0SLionel Sambuc return 0;
838*ebfedea0SLionel Sambuc }
839*ebfedea0SLionel Sambuc
840*ebfedea0SLionel Sambuc if (dataname) {
841*ebfedea0SLionel Sambuc validation.detachname = netpgp_strdup(dataname);
842*ebfedea0SLionel Sambuc }
843*ebfedea0SLionel Sambuc
844*ebfedea0SLionel Sambuc /* Set verification reader and handling options */
845*ebfedea0SLionel Sambuc validation.result = result;
846*ebfedea0SLionel Sambuc validation.keyring = keyring;
847*ebfedea0SLionel Sambuc validation.mem = pgp_memory_new();
848*ebfedea0SLionel Sambuc pgp_memory_init(validation.mem, 128);
849*ebfedea0SLionel Sambuc /* Note: Coverity incorrectly reports an error that validation.reader */
850*ebfedea0SLionel Sambuc /* is never used. */
851*ebfedea0SLionel Sambuc validation.reader = parse->readinfo.arg;
852*ebfedea0SLionel Sambuc
853*ebfedea0SLionel Sambuc if (realarmour) {
854*ebfedea0SLionel Sambuc pgp_reader_push_dearmour(parse);
855*ebfedea0SLionel Sambuc }
856*ebfedea0SLionel Sambuc
857*ebfedea0SLionel Sambuc /* Do the verification */
858*ebfedea0SLionel Sambuc pgp_parse(parse, !printerrors);
859*ebfedea0SLionel Sambuc
860*ebfedea0SLionel Sambuc /* Tidy up */
861*ebfedea0SLionel Sambuc if (realarmour) {
862*ebfedea0SLionel Sambuc pgp_reader_pop_dearmour(parse);
863*ebfedea0SLionel Sambuc }
864*ebfedea0SLionel Sambuc pgp_teardown_file_read(parse, infd);
865*ebfedea0SLionel Sambuc
866*ebfedea0SLionel Sambuc ret = validate_result_status(io->errs, infile, result);
867*ebfedea0SLionel Sambuc
868*ebfedea0SLionel Sambuc /* this is triggered only for --cat output */
869*ebfedea0SLionel Sambuc if (outfile) {
870*ebfedea0SLionel Sambuc /* need to send validated output somewhere */
871*ebfedea0SLionel Sambuc if (strcmp(outfile, "-") == 0) {
872*ebfedea0SLionel Sambuc outfd = STDOUT_FILENO;
873*ebfedea0SLionel Sambuc } else {
874*ebfedea0SLionel Sambuc outfd = open(outfile, O_WRONLY | O_CREAT, 0666);
875*ebfedea0SLionel Sambuc }
876*ebfedea0SLionel Sambuc if (outfd < 0) {
877*ebfedea0SLionel Sambuc /* even if the signature was good, we can't
878*ebfedea0SLionel Sambuc * write the file, so send back a bad return
879*ebfedea0SLionel Sambuc * code */
880*ebfedea0SLionel Sambuc ret = 0;
881*ebfedea0SLionel Sambuc } else if (validate_result_status(io->errs, infile, result)) {
882*ebfedea0SLionel Sambuc unsigned len;
883*ebfedea0SLionel Sambuc char *cp;
884*ebfedea0SLionel Sambuc int i;
885*ebfedea0SLionel Sambuc
886*ebfedea0SLionel Sambuc len = (unsigned)pgp_mem_len(validation.mem);
887*ebfedea0SLionel Sambuc cp = pgp_mem_data(validation.mem);
888*ebfedea0SLionel Sambuc for (i = 0 ; i < (int)len ; i += cc) {
889*ebfedea0SLionel Sambuc cc = (int)write(outfd, &cp[i], (unsigned)(len - i));
890*ebfedea0SLionel Sambuc if (cc < 0) {
891*ebfedea0SLionel Sambuc (void) fprintf(io->errs,
892*ebfedea0SLionel Sambuc "netpgp: short write\n");
893*ebfedea0SLionel Sambuc ret = 0;
894*ebfedea0SLionel Sambuc break;
895*ebfedea0SLionel Sambuc }
896*ebfedea0SLionel Sambuc }
897*ebfedea0SLionel Sambuc if (strcmp(outfile, "-") != 0) {
898*ebfedea0SLionel Sambuc (void) close(outfd);
899*ebfedea0SLionel Sambuc }
900*ebfedea0SLionel Sambuc }
901*ebfedea0SLionel Sambuc }
902*ebfedea0SLionel Sambuc pgp_memory_free(validation.mem);
903*ebfedea0SLionel Sambuc return ret;
904*ebfedea0SLionel Sambuc }
905*ebfedea0SLionel Sambuc
906*ebfedea0SLionel Sambuc /**
907*ebfedea0SLionel Sambuc \ingroup HighLevel_Verify
908*ebfedea0SLionel Sambuc \brief Verifies the signatures in a pgp_memory_t struct
909*ebfedea0SLionel Sambuc \param result Where to put the result
910*ebfedea0SLionel Sambuc \param mem Memory to be validated
911*ebfedea0SLionel Sambuc \param user_says_armoured Treat data as armoured, if set
912*ebfedea0SLionel Sambuc \param keyring Keyring to use
913*ebfedea0SLionel Sambuc \return 1 if signature validates successfully; 0 if not
914*ebfedea0SLionel Sambuc \note After verification, result holds the details of all keys which
915*ebfedea0SLionel Sambuc have passed, failed and not been recognised.
916*ebfedea0SLionel Sambuc \note It is the caller's responsiblity to call
917*ebfedea0SLionel Sambuc pgp_validate_result_free(result) after use.
918*ebfedea0SLionel Sambuc */
919*ebfedea0SLionel Sambuc
920*ebfedea0SLionel Sambuc 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)921*ebfedea0SLionel Sambuc pgp_validate_mem(pgp_io_t *io,
922*ebfedea0SLionel Sambuc pgp_validation_t *result,
923*ebfedea0SLionel Sambuc pgp_memory_t *mem,
924*ebfedea0SLionel Sambuc pgp_memory_t **cat,
925*ebfedea0SLionel Sambuc const int user_says_armoured,
926*ebfedea0SLionel Sambuc const pgp_keyring_t *keyring)
927*ebfedea0SLionel Sambuc {
928*ebfedea0SLionel Sambuc validate_data_cb_t validation;
929*ebfedea0SLionel Sambuc pgp_stream_t *stream = NULL;
930*ebfedea0SLionel Sambuc const int printerrors = 1;
931*ebfedea0SLionel Sambuc int realarmour;
932*ebfedea0SLionel Sambuc
933*ebfedea0SLionel Sambuc pgp_setup_memory_read(io, &stream, mem, &validation, validate_data_cb, 1);
934*ebfedea0SLionel Sambuc /* Set verification reader and handling options */
935*ebfedea0SLionel Sambuc (void) memset(&validation, 0x0, sizeof(validation));
936*ebfedea0SLionel Sambuc validation.result = result;
937*ebfedea0SLionel Sambuc validation.keyring = keyring;
938*ebfedea0SLionel Sambuc validation.mem = pgp_memory_new();
939*ebfedea0SLionel Sambuc pgp_memory_init(validation.mem, 128);
940*ebfedea0SLionel Sambuc /* Note: Coverity incorrectly reports an error that validation.reader */
941*ebfedea0SLionel Sambuc /* is never used. */
942*ebfedea0SLionel Sambuc validation.reader = stream->readinfo.arg;
943*ebfedea0SLionel Sambuc
944*ebfedea0SLionel Sambuc if ((realarmour = user_says_armoured) != 0 ||
945*ebfedea0SLionel Sambuc strncmp(pgp_mem_data(mem),
946*ebfedea0SLionel Sambuc "-----BEGIN PGP MESSAGE-----", 27) == 0) {
947*ebfedea0SLionel Sambuc realarmour = 1;
948*ebfedea0SLionel Sambuc }
949*ebfedea0SLionel Sambuc if (realarmour) {
950*ebfedea0SLionel Sambuc pgp_reader_push_dearmour(stream);
951*ebfedea0SLionel Sambuc }
952*ebfedea0SLionel Sambuc
953*ebfedea0SLionel Sambuc /* Do the verification */
954*ebfedea0SLionel Sambuc pgp_parse(stream, !printerrors);
955*ebfedea0SLionel Sambuc
956*ebfedea0SLionel Sambuc /* Tidy up */
957*ebfedea0SLionel Sambuc if (realarmour) {
958*ebfedea0SLionel Sambuc pgp_reader_pop_dearmour(stream);
959*ebfedea0SLionel Sambuc }
960*ebfedea0SLionel Sambuc pgp_teardown_memory_read(stream, mem);
961*ebfedea0SLionel Sambuc
962*ebfedea0SLionel Sambuc /* this is triggered only for --cat output */
963*ebfedea0SLionel Sambuc if (cat) {
964*ebfedea0SLionel Sambuc /* need to send validated output somewhere */
965*ebfedea0SLionel Sambuc *cat = validation.mem;
966*ebfedea0SLionel Sambuc } else {
967*ebfedea0SLionel Sambuc pgp_memory_free(validation.mem);
968*ebfedea0SLionel Sambuc }
969*ebfedea0SLionel Sambuc
970*ebfedea0SLionel Sambuc return validate_result_status(io->errs, NULL, result);
971*ebfedea0SLionel Sambuc }
972