xref: /minix3/crypto/external/bsd/netpgp/dist/src/lib/netpgp.c (revision ebfedea0ce5bbe81e252ddf32d732e40fb633fae)
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 #include "config.h"
30*ebfedea0SLionel Sambuc 
31*ebfedea0SLionel Sambuc #ifdef HAVE_SYS_CDEFS_H
32*ebfedea0SLionel Sambuc #include <sys/cdefs.h>
33*ebfedea0SLionel Sambuc #endif
34*ebfedea0SLionel Sambuc 
35*ebfedea0SLionel Sambuc #if defined(__NetBSD__)
36*ebfedea0SLionel Sambuc __COPYRIGHT("@(#) Copyright (c) 2009 The NetBSD Foundation, Inc. All rights reserved.");
37*ebfedea0SLionel Sambuc __RCSID("$NetBSD: netpgp.c,v 1.96 2012/02/22 06:58:54 agc Exp $");
38*ebfedea0SLionel Sambuc #endif
39*ebfedea0SLionel Sambuc 
40*ebfedea0SLionel Sambuc #include <sys/types.h>
41*ebfedea0SLionel Sambuc #include <sys/stat.h>
42*ebfedea0SLionel Sambuc #include <sys/param.h>
43*ebfedea0SLionel Sambuc #include <sys/mman.h>
44*ebfedea0SLionel Sambuc 
45*ebfedea0SLionel Sambuc #ifdef HAVE_SYS_RESOURCE_H
46*ebfedea0SLionel Sambuc #include <sys/resource.h>
47*ebfedea0SLionel Sambuc #endif
48*ebfedea0SLionel Sambuc 
49*ebfedea0SLionel Sambuc #ifdef HAVE_FCNTL_H
50*ebfedea0SLionel Sambuc #include <fcntl.h>
51*ebfedea0SLionel Sambuc #endif
52*ebfedea0SLionel Sambuc 
53*ebfedea0SLionel Sambuc #include <errno.h>
54*ebfedea0SLionel Sambuc #include <regex.h>
55*ebfedea0SLionel Sambuc #include <stdarg.h>
56*ebfedea0SLionel Sambuc #include <stdlib.h>
57*ebfedea0SLionel Sambuc #include <string.h>
58*ebfedea0SLionel Sambuc #include <time.h>
59*ebfedea0SLionel Sambuc 
60*ebfedea0SLionel Sambuc #ifdef HAVE_UNISTD_H
61*ebfedea0SLionel Sambuc #include <unistd.h>
62*ebfedea0SLionel Sambuc #endif
63*ebfedea0SLionel Sambuc 
64*ebfedea0SLionel Sambuc #include <errno.h>
65*ebfedea0SLionel Sambuc 
66*ebfedea0SLionel Sambuc #ifdef HAVE_LIMITS_H
67*ebfedea0SLionel Sambuc #include <limits.h>
68*ebfedea0SLionel Sambuc #endif
69*ebfedea0SLionel Sambuc 
70*ebfedea0SLionel Sambuc #include <netpgp.h>
71*ebfedea0SLionel Sambuc 
72*ebfedea0SLionel Sambuc #include "packet.h"
73*ebfedea0SLionel Sambuc #include "packet-parse.h"
74*ebfedea0SLionel Sambuc #include "keyring.h"
75*ebfedea0SLionel Sambuc #include "errors.h"
76*ebfedea0SLionel Sambuc #include "packet-show.h"
77*ebfedea0SLionel Sambuc #include "create.h"
78*ebfedea0SLionel Sambuc #include "netpgpsdk.h"
79*ebfedea0SLionel Sambuc #include "memory.h"
80*ebfedea0SLionel Sambuc #include "validate.h"
81*ebfedea0SLionel Sambuc #include "readerwriter.h"
82*ebfedea0SLionel Sambuc #include "netpgpdefs.h"
83*ebfedea0SLionel Sambuc #include "crypto.h"
84*ebfedea0SLionel Sambuc #include "ssh2pgp.h"
85*ebfedea0SLionel Sambuc #include "defs.h"
86*ebfedea0SLionel Sambuc 
87*ebfedea0SLionel Sambuc /* read any gpg config file */
88*ebfedea0SLionel Sambuc static int
conffile(netpgp_t * netpgp,char * homedir,char * userid,size_t length)89*ebfedea0SLionel Sambuc conffile(netpgp_t *netpgp, char *homedir, char *userid, size_t length)
90*ebfedea0SLionel Sambuc {
91*ebfedea0SLionel Sambuc 	regmatch_t	 matchv[10];
92*ebfedea0SLionel Sambuc 	regex_t		 keyre;
93*ebfedea0SLionel Sambuc 	char		 buf[BUFSIZ];
94*ebfedea0SLionel Sambuc 	FILE		*fp;
95*ebfedea0SLionel Sambuc 
96*ebfedea0SLionel Sambuc 	__PGP_USED(netpgp);
97*ebfedea0SLionel Sambuc 	(void) snprintf(buf, sizeof(buf), "%s/gpg.conf", homedir);
98*ebfedea0SLionel Sambuc 	if ((fp = fopen(buf, "r")) == NULL) {
99*ebfedea0SLionel Sambuc 		return 0;
100*ebfedea0SLionel Sambuc 	}
101*ebfedea0SLionel Sambuc 	(void) memset(&keyre, 0x0, sizeof(keyre));
102*ebfedea0SLionel Sambuc 	(void) regcomp(&keyre, "^[ \t]*default-key[ \t]+([0-9a-zA-F]+)",
103*ebfedea0SLionel Sambuc 		REG_EXTENDED);
104*ebfedea0SLionel Sambuc 	while (fgets(buf, (int)sizeof(buf), fp) != NULL) {
105*ebfedea0SLionel Sambuc 		if (regexec(&keyre, buf, 10, matchv, 0) == 0) {
106*ebfedea0SLionel Sambuc 			(void) memcpy(userid, &buf[(int)matchv[1].rm_so],
107*ebfedea0SLionel Sambuc 				MIN((unsigned)(matchv[1].rm_eo -
108*ebfedea0SLionel Sambuc 						matchv[1].rm_so), length));
109*ebfedea0SLionel Sambuc 			if (netpgp->passfp == NULL) {
110*ebfedea0SLionel Sambuc 				(void) fprintf(stderr,
111*ebfedea0SLionel Sambuc 				"netpgp: default key set to \"%.*s\"\n",
112*ebfedea0SLionel Sambuc 				(int)(matchv[1].rm_eo - matchv[1].rm_so),
113*ebfedea0SLionel Sambuc 				&buf[(int)matchv[1].rm_so]);
114*ebfedea0SLionel Sambuc 			}
115*ebfedea0SLionel Sambuc 		}
116*ebfedea0SLionel Sambuc 	}
117*ebfedea0SLionel Sambuc 	(void) fclose(fp);
118*ebfedea0SLionel Sambuc 	regfree(&keyre);
119*ebfedea0SLionel Sambuc 	return 1;
120*ebfedea0SLionel Sambuc }
121*ebfedea0SLionel Sambuc 
122*ebfedea0SLionel Sambuc /* small function to pretty print an 8-character raw userid */
123*ebfedea0SLionel Sambuc static char    *
userid_to_id(const uint8_t * userid,char * id)124*ebfedea0SLionel Sambuc userid_to_id(const uint8_t *userid, char *id)
125*ebfedea0SLionel Sambuc {
126*ebfedea0SLionel Sambuc 	static const char *hexes = "0123456789abcdef";
127*ebfedea0SLionel Sambuc 	int		   i;
128*ebfedea0SLionel Sambuc 
129*ebfedea0SLionel Sambuc 	for (i = 0; i < 8 ; i++) {
130*ebfedea0SLionel Sambuc 		id[i * 2] = hexes[(unsigned)(userid[i] & 0xf0) >> 4];
131*ebfedea0SLionel Sambuc 		id[(i * 2) + 1] = hexes[userid[i] & 0xf];
132*ebfedea0SLionel Sambuc 	}
133*ebfedea0SLionel Sambuc 	id[8 * 2] = 0x0;
134*ebfedea0SLionel Sambuc 	return id;
135*ebfedea0SLionel Sambuc }
136*ebfedea0SLionel Sambuc 
137*ebfedea0SLionel Sambuc /* print out the successful signature information */
138*ebfedea0SLionel Sambuc static void
resultp(pgp_io_t * io,const char * f,pgp_validation_t * res,pgp_keyring_t * ring)139*ebfedea0SLionel Sambuc resultp(pgp_io_t *io,
140*ebfedea0SLionel Sambuc 	const char *f,
141*ebfedea0SLionel Sambuc 	pgp_validation_t *res,
142*ebfedea0SLionel Sambuc 	pgp_keyring_t *ring)
143*ebfedea0SLionel Sambuc {
144*ebfedea0SLionel Sambuc 	const pgp_key_t	*key;
145*ebfedea0SLionel Sambuc 	pgp_pubkey_t		*sigkey;
146*ebfedea0SLionel Sambuc 	unsigned		 from;
147*ebfedea0SLionel Sambuc 	unsigned		 i;
148*ebfedea0SLionel Sambuc 	time_t			 t;
149*ebfedea0SLionel Sambuc 	char			 id[MAX_ID_LENGTH + 1];
150*ebfedea0SLionel Sambuc 
151*ebfedea0SLionel Sambuc 	for (i = 0; i < res->validc; i++) {
152*ebfedea0SLionel Sambuc 		(void) fprintf(io->res,
153*ebfedea0SLionel Sambuc 			"Good signature for %s made %s",
154*ebfedea0SLionel Sambuc 			(f) ? f : "<stdin>",
155*ebfedea0SLionel Sambuc 			ctime(&res->valid_sigs[i].birthtime));
156*ebfedea0SLionel Sambuc 		if (res->duration > 0) {
157*ebfedea0SLionel Sambuc 			t = res->birthtime + res->duration;
158*ebfedea0SLionel Sambuc 			(void) fprintf(io->res, "Valid until %s", ctime(&t));
159*ebfedea0SLionel Sambuc 		}
160*ebfedea0SLionel Sambuc 		(void) fprintf(io->res,
161*ebfedea0SLionel Sambuc 			"using %s key %s\n",
162*ebfedea0SLionel Sambuc 			pgp_show_pka(res->valid_sigs[i].key_alg),
163*ebfedea0SLionel Sambuc 			userid_to_id(res->valid_sigs[i].signer_id, id));
164*ebfedea0SLionel Sambuc 		from = 0;
165*ebfedea0SLionel Sambuc 		key = pgp_getkeybyid(io, ring,
166*ebfedea0SLionel Sambuc 			(const uint8_t *) res->valid_sigs[i].signer_id,
167*ebfedea0SLionel Sambuc 			&from, &sigkey);
168*ebfedea0SLionel Sambuc 		if (sigkey == &key->enckey) {
169*ebfedea0SLionel Sambuc 			(void) fprintf(io->res,
170*ebfedea0SLionel Sambuc 				"WARNING: signature for %s made with encryption key\n",
171*ebfedea0SLionel Sambuc 				(f) ? f : "<stdin>");
172*ebfedea0SLionel Sambuc 		}
173*ebfedea0SLionel Sambuc 		pgp_print_keydata(io, ring, key, "signature ", &key->key.pubkey, 0);
174*ebfedea0SLionel Sambuc 	}
175*ebfedea0SLionel Sambuc }
176*ebfedea0SLionel Sambuc 
177*ebfedea0SLionel Sambuc /* check there's enough space in the arrays */
178*ebfedea0SLionel Sambuc static int
size_arrays(netpgp_t * netpgp,unsigned needed)179*ebfedea0SLionel Sambuc size_arrays(netpgp_t *netpgp, unsigned needed)
180*ebfedea0SLionel Sambuc {
181*ebfedea0SLionel Sambuc 	char	**temp;
182*ebfedea0SLionel Sambuc 
183*ebfedea0SLionel Sambuc 	if (netpgp->size == 0) {
184*ebfedea0SLionel Sambuc 		/* only get here first time around */
185*ebfedea0SLionel Sambuc 		netpgp->size = needed;
186*ebfedea0SLionel Sambuc 		if ((netpgp->name = calloc(sizeof(char *), needed)) == NULL) {
187*ebfedea0SLionel Sambuc 			(void) fprintf(stderr, "size_arrays: bad alloc\n");
188*ebfedea0SLionel Sambuc 			return 0;
189*ebfedea0SLionel Sambuc 		}
190*ebfedea0SLionel Sambuc 		if ((netpgp->value = calloc(sizeof(char *), needed)) == NULL) {
191*ebfedea0SLionel Sambuc 			free(netpgp->name);
192*ebfedea0SLionel Sambuc 			(void) fprintf(stderr, "size_arrays: bad alloc\n");
193*ebfedea0SLionel Sambuc 			return 0;
194*ebfedea0SLionel Sambuc 		}
195*ebfedea0SLionel Sambuc 	} else if (netpgp->c == netpgp->size) {
196*ebfedea0SLionel Sambuc 		/* only uses 'needed' when filled array */
197*ebfedea0SLionel Sambuc 		netpgp->size += needed;
198*ebfedea0SLionel Sambuc 		temp = realloc(netpgp->name, sizeof(char *) * needed);
199*ebfedea0SLionel Sambuc 		if (temp == NULL) {
200*ebfedea0SLionel Sambuc 			(void) fprintf(stderr, "size_arrays: bad alloc\n");
201*ebfedea0SLionel Sambuc 			return 0;
202*ebfedea0SLionel Sambuc 		}
203*ebfedea0SLionel Sambuc 		netpgp->name = temp;
204*ebfedea0SLionel Sambuc 		temp = realloc(netpgp->value, sizeof(char *) * needed);
205*ebfedea0SLionel Sambuc 		if (temp == NULL) {
206*ebfedea0SLionel Sambuc 			(void) fprintf(stderr, "size_arrays: bad alloc\n");
207*ebfedea0SLionel Sambuc 			return 0;
208*ebfedea0SLionel Sambuc 		}
209*ebfedea0SLionel Sambuc 		netpgp->value = temp;
210*ebfedea0SLionel Sambuc 	}
211*ebfedea0SLionel Sambuc 	return 1;
212*ebfedea0SLionel Sambuc }
213*ebfedea0SLionel Sambuc 
214*ebfedea0SLionel Sambuc /* find the name in the array */
215*ebfedea0SLionel Sambuc static int
findvar(netpgp_t * netpgp,const char * name)216*ebfedea0SLionel Sambuc findvar(netpgp_t *netpgp, const char *name)
217*ebfedea0SLionel Sambuc {
218*ebfedea0SLionel Sambuc 	unsigned	i;
219*ebfedea0SLionel Sambuc 
220*ebfedea0SLionel Sambuc 	for (i = 0 ; i < netpgp->c && strcmp(netpgp->name[i], name) != 0; i++) {
221*ebfedea0SLionel Sambuc 	}
222*ebfedea0SLionel Sambuc 	return (i == netpgp->c) ? -1 : (int)i;
223*ebfedea0SLionel Sambuc }
224*ebfedea0SLionel Sambuc 
225*ebfedea0SLionel Sambuc /* read a keyring and return it */
226*ebfedea0SLionel Sambuc static void *
readkeyring(netpgp_t * netpgp,const char * name)227*ebfedea0SLionel Sambuc readkeyring(netpgp_t *netpgp, const char *name)
228*ebfedea0SLionel Sambuc {
229*ebfedea0SLionel Sambuc 	pgp_keyring_t	*keyring;
230*ebfedea0SLionel Sambuc 	const unsigned	 noarmor = 0;
231*ebfedea0SLionel Sambuc 	char		 f[MAXPATHLEN];
232*ebfedea0SLionel Sambuc 	char		*filename;
233*ebfedea0SLionel Sambuc 	char		*homedir;
234*ebfedea0SLionel Sambuc 
235*ebfedea0SLionel Sambuc 	homedir = netpgp_getvar(netpgp, "homedir");
236*ebfedea0SLionel Sambuc 	if ((filename = netpgp_getvar(netpgp, name)) == NULL) {
237*ebfedea0SLionel Sambuc 		(void) snprintf(f, sizeof(f), "%s/%s.gpg", homedir, name);
238*ebfedea0SLionel Sambuc 		filename = f;
239*ebfedea0SLionel Sambuc 	}
240*ebfedea0SLionel Sambuc 	if ((keyring = calloc(1, sizeof(*keyring))) == NULL) {
241*ebfedea0SLionel Sambuc 		(void) fprintf(stderr, "readkeyring: bad alloc\n");
242*ebfedea0SLionel Sambuc 		return NULL;
243*ebfedea0SLionel Sambuc 	}
244*ebfedea0SLionel Sambuc 	if (!pgp_keyring_fileread(keyring, noarmor, filename)) {
245*ebfedea0SLionel Sambuc 		free(keyring);
246*ebfedea0SLionel Sambuc 		(void) fprintf(stderr, "Can't read %s %s\n", name, filename);
247*ebfedea0SLionel Sambuc 		return NULL;
248*ebfedea0SLionel Sambuc 	}
249*ebfedea0SLionel Sambuc 	netpgp_setvar(netpgp, name, filename);
250*ebfedea0SLionel Sambuc 	return keyring;
251*ebfedea0SLionel Sambuc }
252*ebfedea0SLionel Sambuc 
253*ebfedea0SLionel Sambuc /* read keys from ssh key files */
254*ebfedea0SLionel Sambuc static int
readsshkeys(netpgp_t * netpgp,char * homedir,const char * needseckey)255*ebfedea0SLionel Sambuc readsshkeys(netpgp_t *netpgp, char *homedir, const char *needseckey)
256*ebfedea0SLionel Sambuc {
257*ebfedea0SLionel Sambuc 	pgp_keyring_t	*pubring;
258*ebfedea0SLionel Sambuc 	pgp_keyring_t	*secring;
259*ebfedea0SLionel Sambuc 	struct stat	 st;
260*ebfedea0SLionel Sambuc 	unsigned	 hashtype;
261*ebfedea0SLionel Sambuc 	char		*hash;
262*ebfedea0SLionel Sambuc 	char		 f[MAXPATHLEN];
263*ebfedea0SLionel Sambuc 	char		*filename;
264*ebfedea0SLionel Sambuc 
265*ebfedea0SLionel Sambuc 	if ((filename = netpgp_getvar(netpgp, "sshkeyfile")) == NULL) {
266*ebfedea0SLionel Sambuc 		/* set reasonable default for RSA key */
267*ebfedea0SLionel Sambuc 		(void) snprintf(f, sizeof(f), "%s/id_rsa.pub", homedir);
268*ebfedea0SLionel Sambuc 		filename = f;
269*ebfedea0SLionel Sambuc 	} else if (strcmp(&filename[strlen(filename) - 4], ".pub") != 0) {
270*ebfedea0SLionel Sambuc 		/* got ssh keys, check for pub file name */
271*ebfedea0SLionel Sambuc 		(void) snprintf(f, sizeof(f), "%s.pub", filename);
272*ebfedea0SLionel Sambuc 		filename = f;
273*ebfedea0SLionel Sambuc 	}
274*ebfedea0SLionel Sambuc 	/* check the pub file exists */
275*ebfedea0SLionel Sambuc 	if (stat(filename, &st) != 0) {
276*ebfedea0SLionel Sambuc 		(void) fprintf(stderr, "readsshkeys: bad pubkey filename '%s'\n", filename);
277*ebfedea0SLionel Sambuc 		return 0;
278*ebfedea0SLionel Sambuc 	}
279*ebfedea0SLionel Sambuc 	if ((pubring = calloc(1, sizeof(*pubring))) == NULL) {
280*ebfedea0SLionel Sambuc 		(void) fprintf(stderr, "readsshkeys: bad alloc\n");
281*ebfedea0SLionel Sambuc 		return 0;
282*ebfedea0SLionel Sambuc 	}
283*ebfedea0SLionel Sambuc 	/* openssh2 keys use md5 by default */
284*ebfedea0SLionel Sambuc 	hashtype = PGP_HASH_MD5;
285*ebfedea0SLionel Sambuc 	if ((hash = netpgp_getvar(netpgp, "hash")) != NULL) {
286*ebfedea0SLionel Sambuc 		/* openssh 2 hasn't really caught up to anything else yet */
287*ebfedea0SLionel Sambuc 		if (netpgp_strcasecmp(hash, "md5") == 0) {
288*ebfedea0SLionel Sambuc 			hashtype = PGP_HASH_MD5;
289*ebfedea0SLionel Sambuc 		} else if (netpgp_strcasecmp(hash, "sha1") == 0) {
290*ebfedea0SLionel Sambuc 			hashtype = PGP_HASH_SHA1;
291*ebfedea0SLionel Sambuc 		} else if (netpgp_strcasecmp(hash, "sha256") == 0) {
292*ebfedea0SLionel Sambuc 			hashtype = PGP_HASH_SHA256;
293*ebfedea0SLionel Sambuc 		}
294*ebfedea0SLionel Sambuc 	}
295*ebfedea0SLionel Sambuc 	if (!pgp_ssh2_readkeys(netpgp->io, pubring, NULL, filename, NULL, hashtype)) {
296*ebfedea0SLionel Sambuc 		free(pubring);
297*ebfedea0SLionel Sambuc 		(void) fprintf(stderr, "readsshkeys: can't read %s\n",
298*ebfedea0SLionel Sambuc 				filename);
299*ebfedea0SLionel Sambuc 		return 0;
300*ebfedea0SLionel Sambuc 	}
301*ebfedea0SLionel Sambuc 	if (netpgp->pubring == NULL) {
302*ebfedea0SLionel Sambuc 		netpgp->pubring = pubring;
303*ebfedea0SLionel Sambuc 	} else {
304*ebfedea0SLionel Sambuc 		pgp_append_keyring(netpgp->pubring, pubring);
305*ebfedea0SLionel Sambuc 	}
306*ebfedea0SLionel Sambuc 	if (needseckey) {
307*ebfedea0SLionel Sambuc 		netpgp_setvar(netpgp, "sshpubfile", filename);
308*ebfedea0SLionel Sambuc 		/* try to take the ".pub" off the end */
309*ebfedea0SLionel Sambuc 		if (filename == f) {
310*ebfedea0SLionel Sambuc 			f[strlen(f) - 4] = 0x0;
311*ebfedea0SLionel Sambuc 		} else {
312*ebfedea0SLionel Sambuc 			(void) snprintf(f, sizeof(f), "%.*s",
313*ebfedea0SLionel Sambuc 					(int)strlen(filename) - 4, filename);
314*ebfedea0SLionel Sambuc 			filename = f;
315*ebfedea0SLionel Sambuc 		}
316*ebfedea0SLionel Sambuc 		if ((secring = calloc(1, sizeof(*secring))) == NULL) {
317*ebfedea0SLionel Sambuc 			free(pubring);
318*ebfedea0SLionel Sambuc 			(void) fprintf(stderr, "readsshkeys: bad alloc\n");
319*ebfedea0SLionel Sambuc 			return 0;
320*ebfedea0SLionel Sambuc 		}
321*ebfedea0SLionel Sambuc 		if (!pgp_ssh2_readkeys(netpgp->io, pubring, secring, NULL, filename, hashtype)) {
322*ebfedea0SLionel Sambuc 			free(pubring);
323*ebfedea0SLionel Sambuc 			free(secring);
324*ebfedea0SLionel Sambuc 			(void) fprintf(stderr, "readsshkeys: can't read sec %s\n", filename);
325*ebfedea0SLionel Sambuc 			return 0;
326*ebfedea0SLionel Sambuc 		}
327*ebfedea0SLionel Sambuc 		netpgp->secring = secring;
328*ebfedea0SLionel Sambuc 		netpgp_setvar(netpgp, "sshsecfile", filename);
329*ebfedea0SLionel Sambuc 	}
330*ebfedea0SLionel Sambuc 	return 1;
331*ebfedea0SLionel Sambuc }
332*ebfedea0SLionel Sambuc 
333*ebfedea0SLionel Sambuc /* get the uid of the first key in the keyring */
334*ebfedea0SLionel Sambuc static int
get_first_ring(pgp_keyring_t * ring,char * id,size_t len,int last)335*ebfedea0SLionel Sambuc get_first_ring(pgp_keyring_t *ring, char *id, size_t len, int last)
336*ebfedea0SLionel Sambuc {
337*ebfedea0SLionel Sambuc 	uint8_t	*src;
338*ebfedea0SLionel Sambuc 	int	 i;
339*ebfedea0SLionel Sambuc 	int	 n;
340*ebfedea0SLionel Sambuc 
341*ebfedea0SLionel Sambuc 	if (ring == NULL) {
342*ebfedea0SLionel Sambuc 		return 0;
343*ebfedea0SLionel Sambuc 	}
344*ebfedea0SLionel Sambuc 	(void) memset(id, 0x0, len);
345*ebfedea0SLionel Sambuc 	src = ring->keys[(last) ? ring->keyc - 1 : 0].sigid;
346*ebfedea0SLionel Sambuc 	for (i = 0, n = 0 ; i < PGP_KEY_ID_SIZE ; i += 2) {
347*ebfedea0SLionel Sambuc 		n += snprintf(&id[n], len - n, "%02x%02x", src[i], src[i + 1]);
348*ebfedea0SLionel Sambuc 	}
349*ebfedea0SLionel Sambuc 	id[n] = 0x0;
350*ebfedea0SLionel Sambuc 	return 1;
351*ebfedea0SLionel Sambuc }
352*ebfedea0SLionel Sambuc 
353*ebfedea0SLionel Sambuc /* find the time - in a specific %Y-%m-%d format - using a regexp */
354*ebfedea0SLionel Sambuc static int
grabdate(char * s,int64_t * t)355*ebfedea0SLionel Sambuc grabdate(char *s, int64_t *t)
356*ebfedea0SLionel Sambuc {
357*ebfedea0SLionel Sambuc 	static regex_t	r;
358*ebfedea0SLionel Sambuc 	static int	compiled;
359*ebfedea0SLionel Sambuc 	regmatch_t	matches[10];
360*ebfedea0SLionel Sambuc 	struct tm	tm;
361*ebfedea0SLionel Sambuc 
362*ebfedea0SLionel Sambuc 	if (!compiled) {
363*ebfedea0SLionel Sambuc 		compiled = 1;
364*ebfedea0SLionel Sambuc 		(void) regcomp(&r, "([0-9][0-9][0-9][0-9])[-/]([0-9][0-9])[-/]([0-9][0-9])", REG_EXTENDED);
365*ebfedea0SLionel Sambuc 	}
366*ebfedea0SLionel Sambuc 	if (regexec(&r, s, 10, matches, 0) == 0) {
367*ebfedea0SLionel Sambuc 		(void) memset(&tm, 0x0, sizeof(tm));
368*ebfedea0SLionel Sambuc 		tm.tm_year = (int)strtol(&s[(int)matches[1].rm_so], NULL, 10);
369*ebfedea0SLionel Sambuc 		tm.tm_mon = (int)strtol(&s[(int)matches[2].rm_so], NULL, 10) - 1;
370*ebfedea0SLionel Sambuc 		tm.tm_mday = (int)strtol(&s[(int)matches[3].rm_so], NULL, 10);
371*ebfedea0SLionel Sambuc 		*t = mktime(&tm);
372*ebfedea0SLionel Sambuc 		return 1;
373*ebfedea0SLionel Sambuc 	}
374*ebfedea0SLionel Sambuc 	return 0;
375*ebfedea0SLionel Sambuc }
376*ebfedea0SLionel Sambuc 
377*ebfedea0SLionel Sambuc /* get expiration in seconds */
378*ebfedea0SLionel Sambuc static uint64_t
get_duration(char * s)379*ebfedea0SLionel Sambuc get_duration(char *s)
380*ebfedea0SLionel Sambuc {
381*ebfedea0SLionel Sambuc 	uint64_t	 now;
382*ebfedea0SLionel Sambuc 	int64_t	 	 t;
383*ebfedea0SLionel Sambuc 	char		*mult;
384*ebfedea0SLionel Sambuc 
385*ebfedea0SLionel Sambuc 	if (s == NULL) {
386*ebfedea0SLionel Sambuc 		return 0;
387*ebfedea0SLionel Sambuc 	}
388*ebfedea0SLionel Sambuc 	now = (uint64_t)strtoull(s, NULL, 10);
389*ebfedea0SLionel Sambuc 	if ((mult = strchr("hdwmy", s[strlen(s) - 1])) != NULL) {
390*ebfedea0SLionel Sambuc 		switch(*mult) {
391*ebfedea0SLionel Sambuc 		case 'h':
392*ebfedea0SLionel Sambuc 			return now * 60 * 60;
393*ebfedea0SLionel Sambuc 		case 'd':
394*ebfedea0SLionel Sambuc 			return now * 60 * 60 * 24;
395*ebfedea0SLionel Sambuc 		case 'w':
396*ebfedea0SLionel Sambuc 			return now * 60 * 60 * 24 * 7;
397*ebfedea0SLionel Sambuc 		case 'm':
398*ebfedea0SLionel Sambuc 			return now * 60 * 60 * 24 * 31;
399*ebfedea0SLionel Sambuc 		case 'y':
400*ebfedea0SLionel Sambuc 			return now * 60 * 60 * 24 * 365;
401*ebfedea0SLionel Sambuc 		}
402*ebfedea0SLionel Sambuc 	}
403*ebfedea0SLionel Sambuc 	if (grabdate(s, &t)) {
404*ebfedea0SLionel Sambuc 		return t;
405*ebfedea0SLionel Sambuc 	}
406*ebfedea0SLionel Sambuc 	return (uint64_t)strtoll(s, NULL, 10);
407*ebfedea0SLionel Sambuc }
408*ebfedea0SLionel Sambuc 
409*ebfedea0SLionel Sambuc /* get birthtime in seconds */
410*ebfedea0SLionel Sambuc static int64_t
get_birthtime(char * s)411*ebfedea0SLionel Sambuc get_birthtime(char *s)
412*ebfedea0SLionel Sambuc {
413*ebfedea0SLionel Sambuc 	int64_t	t;
414*ebfedea0SLionel Sambuc 
415*ebfedea0SLionel Sambuc 	if (s == NULL) {
416*ebfedea0SLionel Sambuc 		return time(NULL);
417*ebfedea0SLionel Sambuc 	}
418*ebfedea0SLionel Sambuc 	if (grabdate(s, &t)) {
419*ebfedea0SLionel Sambuc 		return t;
420*ebfedea0SLionel Sambuc 	}
421*ebfedea0SLionel Sambuc 	return (uint64_t)strtoll(s, NULL, 10);
422*ebfedea0SLionel Sambuc }
423*ebfedea0SLionel Sambuc 
424*ebfedea0SLionel Sambuc /* resolve the userid */
425*ebfedea0SLionel Sambuc static const pgp_key_t *
resolve_userid(netpgp_t * netpgp,const pgp_keyring_t * keyring,const char * userid)426*ebfedea0SLionel Sambuc resolve_userid(netpgp_t *netpgp, const pgp_keyring_t *keyring, const char *userid)
427*ebfedea0SLionel Sambuc {
428*ebfedea0SLionel Sambuc 	const pgp_key_t	*key;
429*ebfedea0SLionel Sambuc 	pgp_io_t		*io;
430*ebfedea0SLionel Sambuc 
431*ebfedea0SLionel Sambuc 	if (userid == NULL) {
432*ebfedea0SLionel Sambuc 		userid = netpgp_getvar(netpgp, "userid");
433*ebfedea0SLionel Sambuc 		if (userid == NULL)
434*ebfedea0SLionel Sambuc 			return NULL;
435*ebfedea0SLionel Sambuc 	} else if (userid[0] == '0' && userid[1] == 'x') {
436*ebfedea0SLionel Sambuc 		userid += 2;
437*ebfedea0SLionel Sambuc 	}
438*ebfedea0SLionel Sambuc 	io = netpgp->io;
439*ebfedea0SLionel Sambuc 	if ((key = pgp_getkeybyname(io, keyring, userid)) == NULL) {
440*ebfedea0SLionel Sambuc 		(void) fprintf(io->errs, "Can't find key '%s'\n", userid);
441*ebfedea0SLionel Sambuc 	}
442*ebfedea0SLionel Sambuc 	return key;
443*ebfedea0SLionel Sambuc }
444*ebfedea0SLionel Sambuc 
445*ebfedea0SLionel Sambuc /* append a key to a keyring */
446*ebfedea0SLionel Sambuc static int
appendkey(pgp_io_t * io,pgp_key_t * key,char * ringfile)447*ebfedea0SLionel Sambuc appendkey(pgp_io_t *io, pgp_key_t *key, char *ringfile)
448*ebfedea0SLionel Sambuc {
449*ebfedea0SLionel Sambuc 	pgp_output_t	*create;
450*ebfedea0SLionel Sambuc 	const unsigned	 noarmor = 0;
451*ebfedea0SLionel Sambuc 	int		 fd;
452*ebfedea0SLionel Sambuc 
453*ebfedea0SLionel Sambuc 	if ((fd = pgp_setup_file_append(&create, ringfile)) < 0) {
454*ebfedea0SLionel Sambuc 		fd = pgp_setup_file_write(&create, ringfile, 0);
455*ebfedea0SLionel Sambuc 	}
456*ebfedea0SLionel Sambuc 	if (fd < 0) {
457*ebfedea0SLionel Sambuc 		(void) fprintf(io->errs, "can't open pubring '%s'\n", ringfile);
458*ebfedea0SLionel Sambuc 		return 0;
459*ebfedea0SLionel Sambuc 	}
460*ebfedea0SLionel Sambuc 	if (!pgp_write_xfer_pubkey(create, key, noarmor)) {
461*ebfedea0SLionel Sambuc 		(void) fprintf(io->errs, "Cannot write pubkey\n");
462*ebfedea0SLionel Sambuc 		return 0;
463*ebfedea0SLionel Sambuc 	}
464*ebfedea0SLionel Sambuc 	pgp_teardown_file_write(create, fd);
465*ebfedea0SLionel Sambuc 	return 1;
466*ebfedea0SLionel Sambuc }
467*ebfedea0SLionel Sambuc 
468*ebfedea0SLionel Sambuc /* return 1 if the file contains ascii-armoured text */
469*ebfedea0SLionel Sambuc static unsigned
isarmoured(pgp_io_t * io,const char * f,const void * memory,const char * text)470*ebfedea0SLionel Sambuc isarmoured(pgp_io_t *io, const char *f, const void *memory, const char *text)
471*ebfedea0SLionel Sambuc {
472*ebfedea0SLionel Sambuc 	regmatch_t	 matches[10];
473*ebfedea0SLionel Sambuc 	unsigned	 armoured;
474*ebfedea0SLionel Sambuc 	regex_t		 r;
475*ebfedea0SLionel Sambuc 	FILE		*fp;
476*ebfedea0SLionel Sambuc 	char	 	 buf[BUFSIZ];
477*ebfedea0SLionel Sambuc 
478*ebfedea0SLionel Sambuc 	armoured = 0;
479*ebfedea0SLionel Sambuc 	(void) regcomp(&r, text, REG_EXTENDED);
480*ebfedea0SLionel Sambuc 	if (f) {
481*ebfedea0SLionel Sambuc 		if ((fp = fopen(f, "r")) == NULL) {
482*ebfedea0SLionel Sambuc 			(void) fprintf(io->errs, "isarmoured: can't open '%s'\n", f);
483*ebfedea0SLionel Sambuc 			regfree(&r);
484*ebfedea0SLionel Sambuc 			return 0;
485*ebfedea0SLionel Sambuc 		}
486*ebfedea0SLionel Sambuc 		if (fgets(buf, (int)sizeof(buf), fp) != NULL) {
487*ebfedea0SLionel Sambuc 			if (regexec(&r, buf, 10, matches, 0) == 0) {
488*ebfedea0SLionel Sambuc 				armoured = 1;
489*ebfedea0SLionel Sambuc 			}
490*ebfedea0SLionel Sambuc 		}
491*ebfedea0SLionel Sambuc 		(void) fclose(fp);
492*ebfedea0SLionel Sambuc 	} else {
493*ebfedea0SLionel Sambuc 		if (regexec(&r, memory, 10, matches, 0) == 0) {
494*ebfedea0SLionel Sambuc 			armoured = 1;
495*ebfedea0SLionel Sambuc 		}
496*ebfedea0SLionel Sambuc 	}
497*ebfedea0SLionel Sambuc 	regfree(&r);
498*ebfedea0SLionel Sambuc 	return armoured;
499*ebfedea0SLionel Sambuc }
500*ebfedea0SLionel Sambuc 
501*ebfedea0SLionel Sambuc /* vararg print function */
502*ebfedea0SLionel Sambuc static void
p(FILE * fp,const char * s,...)503*ebfedea0SLionel Sambuc p(FILE *fp, const char *s, ...)
504*ebfedea0SLionel Sambuc {
505*ebfedea0SLionel Sambuc 	va_list	args;
506*ebfedea0SLionel Sambuc 
507*ebfedea0SLionel Sambuc 	va_start(args, s);
508*ebfedea0SLionel Sambuc 	while (s != NULL) {
509*ebfedea0SLionel Sambuc 		(void) fprintf(fp, "%s", s);
510*ebfedea0SLionel Sambuc 		s = va_arg(args, char *);
511*ebfedea0SLionel Sambuc 	}
512*ebfedea0SLionel Sambuc 	va_end(args);
513*ebfedea0SLionel Sambuc }
514*ebfedea0SLionel Sambuc 
515*ebfedea0SLionel Sambuc /* print a JSON object to the FILE stream */
516*ebfedea0SLionel Sambuc static void
pobj(FILE * fp,mj_t * obj,int depth)517*ebfedea0SLionel Sambuc pobj(FILE *fp, mj_t *obj, int depth)
518*ebfedea0SLionel Sambuc {
519*ebfedea0SLionel Sambuc 	unsigned	 i;
520*ebfedea0SLionel Sambuc 	char		*s;
521*ebfedea0SLionel Sambuc 
522*ebfedea0SLionel Sambuc 	if (obj == NULL) {
523*ebfedea0SLionel Sambuc 		(void) fprintf(stderr, "No object found\n");
524*ebfedea0SLionel Sambuc 		return;
525*ebfedea0SLionel Sambuc 	}
526*ebfedea0SLionel Sambuc 	for (i = 0 ; i < (unsigned)depth ; i++) {
527*ebfedea0SLionel Sambuc 		p(fp, " ", NULL);
528*ebfedea0SLionel Sambuc 	}
529*ebfedea0SLionel Sambuc 	switch(obj->type) {
530*ebfedea0SLionel Sambuc 	case MJ_NULL:
531*ebfedea0SLionel Sambuc 	case MJ_FALSE:
532*ebfedea0SLionel Sambuc 	case MJ_TRUE:
533*ebfedea0SLionel Sambuc 		p(fp, (obj->type == MJ_NULL) ? "null" : (obj->type == MJ_FALSE) ? "false" : "true", NULL);
534*ebfedea0SLionel Sambuc 		break;
535*ebfedea0SLionel Sambuc 	case MJ_NUMBER:
536*ebfedea0SLionel Sambuc 		p(fp, obj->value.s, NULL);
537*ebfedea0SLionel Sambuc 		break;
538*ebfedea0SLionel Sambuc 	case MJ_STRING:
539*ebfedea0SLionel Sambuc 		if ((i = mj_asprint(&s, obj, MJ_HUMAN)) > 2) {
540*ebfedea0SLionel Sambuc 			(void) fprintf(fp, "%.*s", (int)i - 2, &s[1]);
541*ebfedea0SLionel Sambuc 			free(s);
542*ebfedea0SLionel Sambuc 		}
543*ebfedea0SLionel Sambuc 		break;
544*ebfedea0SLionel Sambuc 	case MJ_ARRAY:
545*ebfedea0SLionel Sambuc 		for (i = 0 ; i < obj->c ; i++) {
546*ebfedea0SLionel Sambuc 			pobj(fp, &obj->value.v[i], depth + 1);
547*ebfedea0SLionel Sambuc 			if (i < obj->c - 1) {
548*ebfedea0SLionel Sambuc 				(void) fprintf(fp, ", ");
549*ebfedea0SLionel Sambuc 			}
550*ebfedea0SLionel Sambuc 		}
551*ebfedea0SLionel Sambuc 		(void) fprintf(fp, "\n");
552*ebfedea0SLionel Sambuc 		break;
553*ebfedea0SLionel Sambuc 	case MJ_OBJECT:
554*ebfedea0SLionel Sambuc 		for (i = 0 ; i < obj->c ; i += 2) {
555*ebfedea0SLionel Sambuc 			pobj(fp, &obj->value.v[i], depth + 1);
556*ebfedea0SLionel Sambuc 			p(fp, ": ", NULL);
557*ebfedea0SLionel Sambuc 			pobj(fp, &obj->value.v[i + 1], 0);
558*ebfedea0SLionel Sambuc 			if (i < obj->c - 1) {
559*ebfedea0SLionel Sambuc 				p(fp, ", ", NULL);
560*ebfedea0SLionel Sambuc 			}
561*ebfedea0SLionel Sambuc 		}
562*ebfedea0SLionel Sambuc 		p(fp, "\n", NULL);
563*ebfedea0SLionel Sambuc 		break;
564*ebfedea0SLionel Sambuc 	default:
565*ebfedea0SLionel Sambuc 		break;
566*ebfedea0SLionel Sambuc 	}
567*ebfedea0SLionel Sambuc }
568*ebfedea0SLionel Sambuc 
569*ebfedea0SLionel Sambuc /* return the time as a string */
570*ebfedea0SLionel Sambuc static char *
ptimestr(char * dest,size_t size,time_t t)571*ebfedea0SLionel Sambuc ptimestr(char *dest, size_t size, time_t t)
572*ebfedea0SLionel Sambuc {
573*ebfedea0SLionel Sambuc 	struct tm      *tm;
574*ebfedea0SLionel Sambuc 
575*ebfedea0SLionel Sambuc 	tm = gmtime(&t);
576*ebfedea0SLionel Sambuc 	(void) snprintf(dest, size, "%04d-%02d-%02d",
577*ebfedea0SLionel Sambuc 		tm->tm_year + 1900,
578*ebfedea0SLionel Sambuc 		tm->tm_mon + 1,
579*ebfedea0SLionel Sambuc 		tm->tm_mday);
580*ebfedea0SLionel Sambuc 	return dest;
581*ebfedea0SLionel Sambuc }
582*ebfedea0SLionel Sambuc 
583*ebfedea0SLionel Sambuc /* format a JSON object */
584*ebfedea0SLionel Sambuc static void
format_json_key(FILE * fp,mj_t * obj,const int psigs)585*ebfedea0SLionel Sambuc format_json_key(FILE *fp, mj_t *obj, const int psigs)
586*ebfedea0SLionel Sambuc {
587*ebfedea0SLionel Sambuc 	int64_t	 birthtime;
588*ebfedea0SLionel Sambuc 	int64_t	 duration;
589*ebfedea0SLionel Sambuc 	time_t	 now;
590*ebfedea0SLionel Sambuc 	char	 tbuf[32];
591*ebfedea0SLionel Sambuc 	char	*s;
592*ebfedea0SLionel Sambuc 	mj_t	*sub;
593*ebfedea0SLionel Sambuc 	int	 i;
594*ebfedea0SLionel Sambuc 
595*ebfedea0SLionel Sambuc 	if (pgp_get_debug_level(__FILE__)) {
596*ebfedea0SLionel Sambuc 		mj_asprint(&s, obj, MJ_HUMAN);
597*ebfedea0SLionel Sambuc 		(void) fprintf(stderr, "formatobj: json is '%s'\n", s);
598*ebfedea0SLionel Sambuc 		free(s);
599*ebfedea0SLionel Sambuc 	}
600*ebfedea0SLionel Sambuc 	if (obj->c == 2 && obj->value.v[1].type == MJ_STRING &&
601*ebfedea0SLionel Sambuc 	    strcmp(obj->value.v[1].value.s, "[REVOKED]") == 0) {
602*ebfedea0SLionel Sambuc 		/* whole key has been rovoked - just return */
603*ebfedea0SLionel Sambuc 		return;
604*ebfedea0SLionel Sambuc 	}
605*ebfedea0SLionel Sambuc 	pobj(fp, &obj->value.v[mj_object_find(obj, "header", 0, 2) + 1], 0);
606*ebfedea0SLionel Sambuc 	p(fp, " ", NULL);
607*ebfedea0SLionel Sambuc 	pobj(fp, &obj->value.v[mj_object_find(obj, "key bits", 0, 2) + 1], 0);
608*ebfedea0SLionel Sambuc 	p(fp, "/", NULL);
609*ebfedea0SLionel Sambuc 	pobj(fp, &obj->value.v[mj_object_find(obj, "pka", 0, 2) + 1], 0);
610*ebfedea0SLionel Sambuc 	p(fp, " ", NULL);
611*ebfedea0SLionel Sambuc 	pobj(fp, &obj->value.v[mj_object_find(obj, "key id", 0, 2) + 1], 0);
612*ebfedea0SLionel Sambuc 	birthtime = (int64_t)strtoll(obj->value.v[mj_object_find(obj, "birthtime", 0, 2) + 1].value.s, NULL, 10);
613*ebfedea0SLionel Sambuc 	p(fp, " ", ptimestr(tbuf, sizeof(tbuf), birthtime), NULL);
614*ebfedea0SLionel Sambuc 	duration = (int64_t)strtoll(obj->value.v[mj_object_find(obj, "duration", 0, 2) + 1].value.s, NULL, 10);
615*ebfedea0SLionel Sambuc 	if (duration > 0) {
616*ebfedea0SLionel Sambuc 		now = time(NULL);
617*ebfedea0SLionel Sambuc 		p(fp, " ", (birthtime + duration < now) ? "[EXPIRED " : "[EXPIRES ",
618*ebfedea0SLionel Sambuc 			ptimestr(tbuf, sizeof(tbuf), birthtime + duration), "]", NULL);
619*ebfedea0SLionel Sambuc 	}
620*ebfedea0SLionel Sambuc 	p(fp, "\n", "Key fingerprint: ", NULL);
621*ebfedea0SLionel Sambuc 	pobj(fp, &obj->value.v[mj_object_find(obj, "fingerprint", 0, 2) + 1], 0);
622*ebfedea0SLionel Sambuc 	p(fp, "\n", NULL);
623*ebfedea0SLionel Sambuc 	/* go to field after \"duration\" */
624*ebfedea0SLionel Sambuc 	for (i = mj_object_find(obj, "duration", 0, 2) + 2; i < mj_arraycount(obj) ; i += 2) {
625*ebfedea0SLionel Sambuc 		if (strcmp(obj->value.v[i].value.s, "uid") == 0) {
626*ebfedea0SLionel Sambuc 			sub = &obj->value.v[i + 1];
627*ebfedea0SLionel Sambuc 			p(fp, "uid", NULL);
628*ebfedea0SLionel Sambuc 			pobj(fp, &sub->value.v[0], (psigs) ? 4 : 14); /* human name */
629*ebfedea0SLionel Sambuc 			pobj(fp, &sub->value.v[1], 1); /* any revocation */
630*ebfedea0SLionel Sambuc 			p(fp, "\n", NULL);
631*ebfedea0SLionel Sambuc 		} else if (strcmp(obj->value.v[i].value.s, "encryption") == 0) {
632*ebfedea0SLionel Sambuc 			sub = &obj->value.v[i + 1];
633*ebfedea0SLionel Sambuc 			p(fp, "encryption", NULL);
634*ebfedea0SLionel Sambuc 			pobj(fp, &sub->value.v[0], 1);	/* size */
635*ebfedea0SLionel Sambuc 			p(fp, "/", NULL);
636*ebfedea0SLionel Sambuc 			pobj(fp, &sub->value.v[1], 0); /* alg */
637*ebfedea0SLionel Sambuc 			p(fp, " ", NULL);
638*ebfedea0SLionel Sambuc 			pobj(fp, &sub->value.v[2], 0); /* id */
639*ebfedea0SLionel Sambuc 			p(fp, " ", ptimestr(tbuf, sizeof(tbuf),
640*ebfedea0SLionel Sambuc 					(time_t)strtoll(sub->value.v[3].value.s, NULL, 10)),
641*ebfedea0SLionel Sambuc 				"\n", NULL);
642*ebfedea0SLionel Sambuc 		} else if (strcmp(obj->value.v[i].value.s, "sig") == 0) {
643*ebfedea0SLionel Sambuc 			sub = &obj->value.v[i + 1];
644*ebfedea0SLionel Sambuc 			p(fp, "sig", NULL);
645*ebfedea0SLionel Sambuc 			pobj(fp, &sub->value.v[0], 8);	/* size */
646*ebfedea0SLionel Sambuc 			p(fp, "  ", ptimestr(tbuf, sizeof(tbuf),
647*ebfedea0SLionel Sambuc 					(time_t)strtoll(sub->value.v[1].value.s, NULL, 10)),
648*ebfedea0SLionel Sambuc 				" ", NULL); /* time */
649*ebfedea0SLionel Sambuc 			pobj(fp, &sub->value.v[2], 0); /* human name */
650*ebfedea0SLionel Sambuc 			p(fp, "\n", NULL);
651*ebfedea0SLionel Sambuc 		} else {
652*ebfedea0SLionel Sambuc 			fprintf(stderr, "weird '%s'\n", obj->value.v[i].value.s);
653*ebfedea0SLionel Sambuc 			pobj(fp, &obj->value.v[i], 0); /* human name */
654*ebfedea0SLionel Sambuc 		}
655*ebfedea0SLionel Sambuc 	}
656*ebfedea0SLionel Sambuc 	p(fp, "\n", NULL);
657*ebfedea0SLionel Sambuc }
658*ebfedea0SLionel Sambuc 
659*ebfedea0SLionel Sambuc /* save a pgp pubkey to a temp file */
660*ebfedea0SLionel Sambuc static int
savepubkey(char * res,char * f,size_t size)661*ebfedea0SLionel Sambuc savepubkey(char *res, char *f, size_t size)
662*ebfedea0SLionel Sambuc {
663*ebfedea0SLionel Sambuc 	size_t	len;
664*ebfedea0SLionel Sambuc 	int	cc;
665*ebfedea0SLionel Sambuc 	int	wc;
666*ebfedea0SLionel Sambuc 	int	fd;
667*ebfedea0SLionel Sambuc 
668*ebfedea0SLionel Sambuc 	(void) snprintf(f, size, "/tmp/pgp2ssh.XXXXXXX");
669*ebfedea0SLionel Sambuc 	if ((fd = mkstemp(f)) < 0) {
670*ebfedea0SLionel Sambuc 		(void) fprintf(stderr, "can't create temp file '%s'\n", f);
671*ebfedea0SLionel Sambuc 		return 0;
672*ebfedea0SLionel Sambuc 	}
673*ebfedea0SLionel Sambuc 	len = strlen(res);
674*ebfedea0SLionel Sambuc 	for (cc = 0 ; (wc = (int)write(fd, &res[cc], len - (size_t)cc)) > 0 ; cc += wc) {
675*ebfedea0SLionel Sambuc 	}
676*ebfedea0SLionel Sambuc 	(void) close(fd);
677*ebfedea0SLionel Sambuc 	return 1;
678*ebfedea0SLionel Sambuc }
679*ebfedea0SLionel Sambuc 
680*ebfedea0SLionel Sambuc /* format a uint32_t */
681*ebfedea0SLionel Sambuc static int
formatu32(uint8_t * buffer,uint32_t value)682*ebfedea0SLionel Sambuc formatu32(uint8_t *buffer, uint32_t value)
683*ebfedea0SLionel Sambuc {
684*ebfedea0SLionel Sambuc 	buffer[0] = (uint8_t)(value >> 24) & 0xff;
685*ebfedea0SLionel Sambuc 	buffer[1] = (uint8_t)(value >> 16) & 0xff;
686*ebfedea0SLionel Sambuc 	buffer[2] = (uint8_t)(value >> 8) & 0xff;
687*ebfedea0SLionel Sambuc 	buffer[3] = (uint8_t)value & 0xff;
688*ebfedea0SLionel Sambuc 	return sizeof(uint32_t);
689*ebfedea0SLionel Sambuc }
690*ebfedea0SLionel Sambuc 
691*ebfedea0SLionel Sambuc /* format a string as (len, string) */
692*ebfedea0SLionel Sambuc static int
formatstring(char * buffer,const uint8_t * s,size_t len)693*ebfedea0SLionel Sambuc formatstring(char *buffer, const uint8_t *s, size_t len)
694*ebfedea0SLionel Sambuc {
695*ebfedea0SLionel Sambuc 	int	cc;
696*ebfedea0SLionel Sambuc 
697*ebfedea0SLionel Sambuc 	cc = formatu32((uint8_t *)buffer, (uint32_t)len);
698*ebfedea0SLionel Sambuc 	(void) memcpy(&buffer[cc], s, len);
699*ebfedea0SLionel Sambuc 	return cc + (int)len;
700*ebfedea0SLionel Sambuc }
701*ebfedea0SLionel Sambuc 
702*ebfedea0SLionel Sambuc /* format a bignum, checking for "interesting" high bit values */
703*ebfedea0SLionel Sambuc static int
formatbignum(char * buffer,BIGNUM * bn)704*ebfedea0SLionel Sambuc formatbignum(char *buffer, BIGNUM *bn)
705*ebfedea0SLionel Sambuc {
706*ebfedea0SLionel Sambuc 	size_t	 len;
707*ebfedea0SLionel Sambuc 	uint8_t	*cp;
708*ebfedea0SLionel Sambuc 	int	 cc;
709*ebfedea0SLionel Sambuc 
710*ebfedea0SLionel Sambuc 	len = (size_t) BN_num_bytes(bn);
711*ebfedea0SLionel Sambuc 	if ((cp = calloc(1, len + 1)) == NULL) {
712*ebfedea0SLionel Sambuc 		(void) fprintf(stderr, "calloc failure in formatbignum\n");
713*ebfedea0SLionel Sambuc 		return 0;
714*ebfedea0SLionel Sambuc 	}
715*ebfedea0SLionel Sambuc 	(void) BN_bn2bin(bn, cp + 1);
716*ebfedea0SLionel Sambuc 	cp[0] = 0x0;
717*ebfedea0SLionel Sambuc 	cc = (cp[1] & 0x80) ? formatstring(buffer, cp, len + 1) : formatstring(buffer, &cp[1], len);
718*ebfedea0SLionel Sambuc 	free(cp);
719*ebfedea0SLionel Sambuc 	return cc;
720*ebfedea0SLionel Sambuc }
721*ebfedea0SLionel Sambuc 
722*ebfedea0SLionel Sambuc #define MAX_PASSPHRASE_ATTEMPTS	3
723*ebfedea0SLionel Sambuc #define INFINITE_ATTEMPTS	-1
724*ebfedea0SLionel Sambuc 
725*ebfedea0SLionel Sambuc /* get the passphrase from the user */
726*ebfedea0SLionel Sambuc static int
find_passphrase(FILE * passfp,const char * id,char * passphrase,size_t size,int attempts)727*ebfedea0SLionel Sambuc find_passphrase(FILE *passfp, const char *id, char *passphrase, size_t size, int attempts)
728*ebfedea0SLionel Sambuc {
729*ebfedea0SLionel Sambuc 	char	 prompt[BUFSIZ];
730*ebfedea0SLionel Sambuc 	char	 buf[128];
731*ebfedea0SLionel Sambuc 	char	*cp;
732*ebfedea0SLionel Sambuc 	int	 cc;
733*ebfedea0SLionel Sambuc 	int	 i;
734*ebfedea0SLionel Sambuc 
735*ebfedea0SLionel Sambuc 	if (passfp) {
736*ebfedea0SLionel Sambuc 		if (fgets(passphrase, (int)size, passfp) == NULL) {
737*ebfedea0SLionel Sambuc 			return 0;
738*ebfedea0SLionel Sambuc 		}
739*ebfedea0SLionel Sambuc 		return (int)strlen(passphrase);
740*ebfedea0SLionel Sambuc 	}
741*ebfedea0SLionel Sambuc 	for (i = 0 ; i < attempts ; i++) {
742*ebfedea0SLionel Sambuc 		(void) snprintf(prompt, sizeof(prompt), "Enter passphrase for %.16s: ", id);
743*ebfedea0SLionel Sambuc 		if ((cp = getpass(prompt)) == NULL) {
744*ebfedea0SLionel Sambuc 			break;
745*ebfedea0SLionel Sambuc 		}
746*ebfedea0SLionel Sambuc 		cc = snprintf(buf, sizeof(buf), "%s", cp);
747*ebfedea0SLionel Sambuc 		(void) snprintf(prompt, sizeof(prompt), "Repeat passphrase for %.16s: ", id);
748*ebfedea0SLionel Sambuc 		if ((cp = getpass(prompt)) == NULL) {
749*ebfedea0SLionel Sambuc 			break;
750*ebfedea0SLionel Sambuc 		}
751*ebfedea0SLionel Sambuc 		cc = snprintf(passphrase, size, "%s", cp);
752*ebfedea0SLionel Sambuc 		if (strcmp(buf, passphrase) == 0) {
753*ebfedea0SLionel Sambuc 			(void) memset(buf, 0x0, sizeof(buf));
754*ebfedea0SLionel Sambuc 			return cc;
755*ebfedea0SLionel Sambuc 		}
756*ebfedea0SLionel Sambuc 	}
757*ebfedea0SLionel Sambuc 	(void) memset(buf, 0x0, sizeof(buf));
758*ebfedea0SLionel Sambuc 	(void) memset(passphrase, 0x0, size);
759*ebfedea0SLionel Sambuc 	return 0;
760*ebfedea0SLionel Sambuc }
761*ebfedea0SLionel Sambuc 
762*ebfedea0SLionel Sambuc /***************************************************************************/
763*ebfedea0SLionel Sambuc /* exported functions start here */
764*ebfedea0SLionel Sambuc /***************************************************************************/
765*ebfedea0SLionel Sambuc 
766*ebfedea0SLionel Sambuc /* initialise a netpgp_t structure */
767*ebfedea0SLionel Sambuc int
netpgp_init(netpgp_t * netpgp)768*ebfedea0SLionel Sambuc netpgp_init(netpgp_t *netpgp)
769*ebfedea0SLionel Sambuc {
770*ebfedea0SLionel Sambuc 	pgp_io_t	*io;
771*ebfedea0SLionel Sambuc 	time_t		 t;
772*ebfedea0SLionel Sambuc 	char		 id[MAX_ID_LENGTH];
773*ebfedea0SLionel Sambuc 	char		*homedir;
774*ebfedea0SLionel Sambuc 	char		*userid;
775*ebfedea0SLionel Sambuc 	char		*stream;
776*ebfedea0SLionel Sambuc 	char		*passfd;
777*ebfedea0SLionel Sambuc 	char		*results;
778*ebfedea0SLionel Sambuc 	int		 coredumps;
779*ebfedea0SLionel Sambuc 	int		 last;
780*ebfedea0SLionel Sambuc 
781*ebfedea0SLionel Sambuc #ifdef HAVE_SYS_RESOURCE_H
782*ebfedea0SLionel Sambuc 	struct rlimit	limit;
783*ebfedea0SLionel Sambuc 
784*ebfedea0SLionel Sambuc 	coredumps = netpgp_getvar(netpgp, "coredumps") != NULL;
785*ebfedea0SLionel Sambuc 	if (!coredumps) {
786*ebfedea0SLionel Sambuc 		(void) memset(&limit, 0x0, sizeof(limit));
787*ebfedea0SLionel Sambuc 		if (setrlimit(RLIMIT_CORE, &limit) != 0) {
788*ebfedea0SLionel Sambuc 			(void) fprintf(stderr,
789*ebfedea0SLionel Sambuc 			"netpgp: warning - can't turn off core dumps\n");
790*ebfedea0SLionel Sambuc 			coredumps = 1;
791*ebfedea0SLionel Sambuc 		}
792*ebfedea0SLionel Sambuc 	}
793*ebfedea0SLionel Sambuc #else
794*ebfedea0SLionel Sambuc 	coredumps = 1;
795*ebfedea0SLionel Sambuc #endif
796*ebfedea0SLionel Sambuc 	if ((io = calloc(1, sizeof(*io))) == NULL) {
797*ebfedea0SLionel Sambuc 		(void) fprintf(stderr, "netpgp_init: bad alloc\n");
798*ebfedea0SLionel Sambuc 		return 0;
799*ebfedea0SLionel Sambuc 	}
800*ebfedea0SLionel Sambuc 	io->outs = stdout;
801*ebfedea0SLionel Sambuc 	if ((stream = netpgp_getvar(netpgp, "outs")) != NULL &&
802*ebfedea0SLionel Sambuc 	    strcmp(stream, "<stderr>") == 0) {
803*ebfedea0SLionel Sambuc 		io->outs = stderr;
804*ebfedea0SLionel Sambuc 	}
805*ebfedea0SLionel Sambuc 	io->errs = stderr;
806*ebfedea0SLionel Sambuc 	if ((stream = netpgp_getvar(netpgp, "errs")) != NULL &&
807*ebfedea0SLionel Sambuc 	    strcmp(stream, "<stdout>") == 0) {
808*ebfedea0SLionel Sambuc 		io->errs = stdout;
809*ebfedea0SLionel Sambuc 	}
810*ebfedea0SLionel Sambuc 	if ((results = netpgp_getvar(netpgp, "res")) == NULL) {
811*ebfedea0SLionel Sambuc 		io->res = io->errs;
812*ebfedea0SLionel Sambuc 	} else if (strcmp(results, "<stdout>") == 0) {
813*ebfedea0SLionel Sambuc 		io->res = stdout;
814*ebfedea0SLionel Sambuc 	} else if (strcmp(results, "<stderr>") == 0) {
815*ebfedea0SLionel Sambuc 		io->res = stderr;
816*ebfedea0SLionel Sambuc 	} else {
817*ebfedea0SLionel Sambuc 		if ((io->res = fopen(results, "w")) == NULL) {
818*ebfedea0SLionel Sambuc 			(void) fprintf(io->errs, "Can't open results %s for writing\n",
819*ebfedea0SLionel Sambuc 				results);
820*ebfedea0SLionel Sambuc 			free(io);
821*ebfedea0SLionel Sambuc 			return 0;
822*ebfedea0SLionel Sambuc 		}
823*ebfedea0SLionel Sambuc 	}
824*ebfedea0SLionel Sambuc 	netpgp->io = io;
825*ebfedea0SLionel Sambuc 	/* get passphrase from an fd */
826*ebfedea0SLionel Sambuc 	if ((passfd = netpgp_getvar(netpgp, "pass-fd")) != NULL &&
827*ebfedea0SLionel Sambuc 	    (netpgp->passfp = fdopen(atoi(passfd), "r")) == NULL) {
828*ebfedea0SLionel Sambuc 		(void) fprintf(io->errs, "Can't open fd %s for reading\n",
829*ebfedea0SLionel Sambuc 			passfd);
830*ebfedea0SLionel Sambuc 		return 0;
831*ebfedea0SLionel Sambuc 	}
832*ebfedea0SLionel Sambuc 	/* warn if core dumps are enabled */
833*ebfedea0SLionel Sambuc 	if (coredumps) {
834*ebfedea0SLionel Sambuc 		(void) fprintf(io->errs,
835*ebfedea0SLionel Sambuc 			"netpgp: warning: core dumps enabled\n");
836*ebfedea0SLionel Sambuc 	}
837*ebfedea0SLionel Sambuc 	/* get home directory - where keyrings are in a subdir */
838*ebfedea0SLionel Sambuc 	if ((homedir = netpgp_getvar(netpgp, "homedir")) == NULL) {
839*ebfedea0SLionel Sambuc 		(void) fprintf(io->errs, "netpgp: bad homedir\n");
840*ebfedea0SLionel Sambuc 		return 0;
841*ebfedea0SLionel Sambuc 	}
842*ebfedea0SLionel Sambuc 	if (netpgp_getvar(netpgp, "ssh keys") == NULL) {
843*ebfedea0SLionel Sambuc 		/* read from ordinary pgp keyrings */
844*ebfedea0SLionel Sambuc 		netpgp->pubring = readkeyring(netpgp, "pubring");
845*ebfedea0SLionel Sambuc 		if (netpgp->pubring == NULL) {
846*ebfedea0SLionel Sambuc 			(void) fprintf(io->errs, "Can't read pub keyring\n");
847*ebfedea0SLionel Sambuc 			return 0;
848*ebfedea0SLionel Sambuc 		}
849*ebfedea0SLionel Sambuc 		/* if a userid has been given, we'll use it */
850*ebfedea0SLionel Sambuc 		if ((userid = netpgp_getvar(netpgp, "userid")) == NULL) {
851*ebfedea0SLionel Sambuc 			/* also search in config file for default id */
852*ebfedea0SLionel Sambuc 			(void) memset(id, 0x0, sizeof(id));
853*ebfedea0SLionel Sambuc 			(void) conffile(netpgp, homedir, id, sizeof(id));
854*ebfedea0SLionel Sambuc 			if (id[0] != 0x0) {
855*ebfedea0SLionel Sambuc 				netpgp_setvar(netpgp, "userid", userid = id);
856*ebfedea0SLionel Sambuc 			}
857*ebfedea0SLionel Sambuc 		}
858*ebfedea0SLionel Sambuc 		/* only read secret keys if we need to */
859*ebfedea0SLionel Sambuc 		if (netpgp_getvar(netpgp, "need seckey")) {
860*ebfedea0SLionel Sambuc 			/* read the secret ring */
861*ebfedea0SLionel Sambuc 			netpgp->secring = readkeyring(netpgp, "secring");
862*ebfedea0SLionel Sambuc 			if (netpgp->secring == NULL) {
863*ebfedea0SLionel Sambuc 				(void) fprintf(io->errs, "Can't read sec keyring\n");
864*ebfedea0SLionel Sambuc 				return 0;
865*ebfedea0SLionel Sambuc 			}
866*ebfedea0SLionel Sambuc 			/* now, if we don't have a valid user, use the first in secring */
867*ebfedea0SLionel Sambuc 			if (!userid && netpgp_getvar(netpgp, "need userid") != NULL) {
868*ebfedea0SLionel Sambuc 				/* signing - need userid and sec key */
869*ebfedea0SLionel Sambuc 				(void) memset(id, 0x0, sizeof(id));
870*ebfedea0SLionel Sambuc 				if (get_first_ring(netpgp->secring, id, sizeof(id), 0)) {
871*ebfedea0SLionel Sambuc 					netpgp_setvar(netpgp, "userid", userid = id);
872*ebfedea0SLionel Sambuc 				}
873*ebfedea0SLionel Sambuc 			}
874*ebfedea0SLionel Sambuc 		} else if (netpgp_getvar(netpgp, "need userid") != NULL) {
875*ebfedea0SLionel Sambuc 			/* encrypting - get first in pubring */
876*ebfedea0SLionel Sambuc 			if (!userid && get_first_ring(netpgp->pubring, id, sizeof(id), 0)) {
877*ebfedea0SLionel Sambuc 				(void) netpgp_setvar(netpgp, "userid", userid = id);
878*ebfedea0SLionel Sambuc 			}
879*ebfedea0SLionel Sambuc 		}
880*ebfedea0SLionel Sambuc 		if (!userid && netpgp_getvar(netpgp, "need userid")) {
881*ebfedea0SLionel Sambuc 			/* if we don't have a user id, and we need one, fail */
882*ebfedea0SLionel Sambuc 			(void) fprintf(io->errs, "Cannot find user id\n");
883*ebfedea0SLionel Sambuc 			return 0;
884*ebfedea0SLionel Sambuc 		}
885*ebfedea0SLionel Sambuc 	} else {
886*ebfedea0SLionel Sambuc 		/* read from ssh keys */
887*ebfedea0SLionel Sambuc 		last = (netpgp->pubring != NULL);
888*ebfedea0SLionel Sambuc 		if (!readsshkeys(netpgp, homedir, netpgp_getvar(netpgp, "need seckey"))) {
889*ebfedea0SLionel Sambuc 			(void) fprintf(io->errs, "Can't read ssh keys\n");
890*ebfedea0SLionel Sambuc 			return 0;
891*ebfedea0SLionel Sambuc 		}
892*ebfedea0SLionel Sambuc 		if ((userid = netpgp_getvar(netpgp, "userid")) == NULL) {
893*ebfedea0SLionel Sambuc 			get_first_ring(netpgp->pubring, id, sizeof(id), last);
894*ebfedea0SLionel Sambuc 			netpgp_setvar(netpgp, "userid", userid = id);
895*ebfedea0SLionel Sambuc 		}
896*ebfedea0SLionel Sambuc 		if (userid == NULL) {
897*ebfedea0SLionel Sambuc 			if (netpgp_getvar(netpgp, "need userid") != NULL) {
898*ebfedea0SLionel Sambuc 				(void) fprintf(io->errs,
899*ebfedea0SLionel Sambuc 						"Cannot find user id\n");
900*ebfedea0SLionel Sambuc 				return 0;
901*ebfedea0SLionel Sambuc 			}
902*ebfedea0SLionel Sambuc 		} else {
903*ebfedea0SLionel Sambuc 			(void) netpgp_setvar(netpgp, "userid", userid);
904*ebfedea0SLionel Sambuc 		}
905*ebfedea0SLionel Sambuc 	}
906*ebfedea0SLionel Sambuc 	t = time(NULL);
907*ebfedea0SLionel Sambuc 	netpgp_setvar(netpgp, "initialised", ctime(&t));
908*ebfedea0SLionel Sambuc 	return 1;
909*ebfedea0SLionel Sambuc }
910*ebfedea0SLionel Sambuc 
911*ebfedea0SLionel Sambuc /* finish off with the netpgp_t struct */
912*ebfedea0SLionel Sambuc int
netpgp_end(netpgp_t * netpgp)913*ebfedea0SLionel Sambuc netpgp_end(netpgp_t *netpgp)
914*ebfedea0SLionel Sambuc {
915*ebfedea0SLionel Sambuc 	unsigned	i;
916*ebfedea0SLionel Sambuc 
917*ebfedea0SLionel Sambuc 	for (i = 0 ; i < netpgp->c ; i++) {
918*ebfedea0SLionel Sambuc 		if (netpgp->name[i] != NULL) {
919*ebfedea0SLionel Sambuc 			free(netpgp->name[i]);
920*ebfedea0SLionel Sambuc 		}
921*ebfedea0SLionel Sambuc 		if (netpgp->value[i] != NULL) {
922*ebfedea0SLionel Sambuc 			free(netpgp->value[i]);
923*ebfedea0SLionel Sambuc 		}
924*ebfedea0SLionel Sambuc 	}
925*ebfedea0SLionel Sambuc 	if (netpgp->name != NULL) {
926*ebfedea0SLionel Sambuc 		free(netpgp->name);
927*ebfedea0SLionel Sambuc 	}
928*ebfedea0SLionel Sambuc 	if (netpgp->value != NULL) {
929*ebfedea0SLionel Sambuc 		free(netpgp->value);
930*ebfedea0SLionel Sambuc 	}
931*ebfedea0SLionel Sambuc 	if (netpgp->pubring != NULL) {
932*ebfedea0SLionel Sambuc 		pgp_keyring_free(netpgp->pubring);
933*ebfedea0SLionel Sambuc 	}
934*ebfedea0SLionel Sambuc 	if (netpgp->secring != NULL) {
935*ebfedea0SLionel Sambuc 		pgp_keyring_free(netpgp->secring);
936*ebfedea0SLionel Sambuc 	}
937*ebfedea0SLionel Sambuc 	free(netpgp->io);
938*ebfedea0SLionel Sambuc 	return 1;
939*ebfedea0SLionel Sambuc }
940*ebfedea0SLionel Sambuc 
941*ebfedea0SLionel Sambuc /* list the keys in a keyring */
942*ebfedea0SLionel Sambuc int
netpgp_list_keys(netpgp_t * netpgp,const int psigs)943*ebfedea0SLionel Sambuc netpgp_list_keys(netpgp_t *netpgp, const int psigs)
944*ebfedea0SLionel Sambuc {
945*ebfedea0SLionel Sambuc 	if (netpgp->pubring == NULL) {
946*ebfedea0SLionel Sambuc 		(void) fprintf(stderr, "No keyring\n");
947*ebfedea0SLionel Sambuc 		return 0;
948*ebfedea0SLionel Sambuc 	}
949*ebfedea0SLionel Sambuc 	return pgp_keyring_list(netpgp->io, netpgp->pubring, psigs);
950*ebfedea0SLionel Sambuc }
951*ebfedea0SLionel Sambuc 
952*ebfedea0SLionel Sambuc /* list the keys in a keyring, returning a JSON encoded string */
953*ebfedea0SLionel Sambuc int
netpgp_list_keys_json(netpgp_t * netpgp,char ** json,const int psigs)954*ebfedea0SLionel Sambuc netpgp_list_keys_json(netpgp_t *netpgp, char **json, const int psigs)
955*ebfedea0SLionel Sambuc {
956*ebfedea0SLionel Sambuc 	mj_t	obj;
957*ebfedea0SLionel Sambuc 	int	ret;
958*ebfedea0SLionel Sambuc 
959*ebfedea0SLionel Sambuc 	if (netpgp->pubring == NULL) {
960*ebfedea0SLionel Sambuc 		(void) fprintf(stderr, "No keyring\n");
961*ebfedea0SLionel Sambuc 		return 0;
962*ebfedea0SLionel Sambuc 	}
963*ebfedea0SLionel Sambuc 	(void) memset(&obj, 0x0, sizeof(obj));
964*ebfedea0SLionel Sambuc 	if (!pgp_keyring_json(netpgp->io, netpgp->pubring, &obj, psigs)) {
965*ebfedea0SLionel Sambuc 		(void) fprintf(stderr, "No keys in keyring\n");
966*ebfedea0SLionel Sambuc 		return 0;
967*ebfedea0SLionel Sambuc 	}
968*ebfedea0SLionel Sambuc 	ret = mj_asprint(json, &obj, MJ_JSON_ENCODE);
969*ebfedea0SLionel Sambuc 	mj_delete(&obj);
970*ebfedea0SLionel Sambuc 	return ret;
971*ebfedea0SLionel Sambuc }
972*ebfedea0SLionel Sambuc 
973*ebfedea0SLionel Sambuc DEFINE_ARRAY(strings_t, char *);
974*ebfedea0SLionel Sambuc 
975*ebfedea0SLionel Sambuc #ifndef HKP_VERSION
976*ebfedea0SLionel Sambuc #define HKP_VERSION	1
977*ebfedea0SLionel Sambuc #endif
978*ebfedea0SLionel Sambuc 
979*ebfedea0SLionel Sambuc /* find and list some keys in a keyring */
980*ebfedea0SLionel Sambuc int
netpgp_match_keys(netpgp_t * netpgp,char * name,const char * fmt,void * vp,const int psigs)981*ebfedea0SLionel Sambuc netpgp_match_keys(netpgp_t *netpgp, char *name, const char *fmt, void *vp, const int psigs)
982*ebfedea0SLionel Sambuc {
983*ebfedea0SLionel Sambuc 	const pgp_key_t	*key;
984*ebfedea0SLionel Sambuc 	unsigned		 k;
985*ebfedea0SLionel Sambuc 	strings_t		 pubs;
986*ebfedea0SLionel Sambuc 	FILE			*fp = (FILE *)vp;
987*ebfedea0SLionel Sambuc 
988*ebfedea0SLionel Sambuc 	if (name[0] == '0' && name[1] == 'x') {
989*ebfedea0SLionel Sambuc 		name += 2;
990*ebfedea0SLionel Sambuc 	}
991*ebfedea0SLionel Sambuc 	(void) memset(&pubs, 0x0, sizeof(pubs));
992*ebfedea0SLionel Sambuc 	k = 0;
993*ebfedea0SLionel Sambuc 	do {
994*ebfedea0SLionel Sambuc 		key = pgp_getnextkeybyname(netpgp->io, netpgp->pubring,
995*ebfedea0SLionel Sambuc 						name, &k);
996*ebfedea0SLionel Sambuc 		if (key != NULL) {
997*ebfedea0SLionel Sambuc 			ALLOC(char *, pubs.v, pubs.size, pubs.c, 10, 10,
998*ebfedea0SLionel Sambuc 					"netpgp_match_keys", return 0);
999*ebfedea0SLionel Sambuc 			if (strcmp(fmt, "mr") == 0) {
1000*ebfedea0SLionel Sambuc 				pgp_hkp_sprint_keydata(netpgp->io, netpgp->pubring,
1001*ebfedea0SLionel Sambuc 						key, &pubs.v[pubs.c],
1002*ebfedea0SLionel Sambuc 						&key->key.pubkey, psigs);
1003*ebfedea0SLionel Sambuc 			} else {
1004*ebfedea0SLionel Sambuc 				pgp_sprint_keydata(netpgp->io, netpgp->pubring,
1005*ebfedea0SLionel Sambuc 						key, &pubs.v[pubs.c],
1006*ebfedea0SLionel Sambuc 						"signature ",
1007*ebfedea0SLionel Sambuc 						&key->key.pubkey, psigs);
1008*ebfedea0SLionel Sambuc 			}
1009*ebfedea0SLionel Sambuc 			if (pubs.v[pubs.c] != NULL) {
1010*ebfedea0SLionel Sambuc 				pubs.c += 1;
1011*ebfedea0SLionel Sambuc 			}
1012*ebfedea0SLionel Sambuc 			k += 1;
1013*ebfedea0SLionel Sambuc 		}
1014*ebfedea0SLionel Sambuc 	} while (key != NULL);
1015*ebfedea0SLionel Sambuc 	if (strcmp(fmt, "mr") == 0) {
1016*ebfedea0SLionel Sambuc 		(void) fprintf(fp, "info:%d:%d\n", HKP_VERSION, pubs.c);
1017*ebfedea0SLionel Sambuc 	} else {
1018*ebfedea0SLionel Sambuc 		(void) fprintf(fp, "%d key%s found\n", pubs.c,
1019*ebfedea0SLionel Sambuc 			(pubs.c == 1) ? "" : "s");
1020*ebfedea0SLionel Sambuc 	}
1021*ebfedea0SLionel Sambuc 	for (k = 0 ; k < pubs.c ; k++) {
1022*ebfedea0SLionel Sambuc 		(void) fprintf(fp, "%s%s", pubs.v[k], (k < pubs.c - 1) ? "\n" : "");
1023*ebfedea0SLionel Sambuc 		free(pubs.v[k]);
1024*ebfedea0SLionel Sambuc 	}
1025*ebfedea0SLionel Sambuc 	free(pubs.v);
1026*ebfedea0SLionel Sambuc 	return pubs.c;
1027*ebfedea0SLionel Sambuc }
1028*ebfedea0SLionel Sambuc 
1029*ebfedea0SLionel Sambuc /* find and list some keys in a keyring - return JSON string */
1030*ebfedea0SLionel Sambuc int
netpgp_match_keys_json(netpgp_t * netpgp,char ** json,char * name,const char * fmt,const int psigs)1031*ebfedea0SLionel Sambuc netpgp_match_keys_json(netpgp_t *netpgp, char **json, char *name, const char *fmt, const int psigs)
1032*ebfedea0SLionel Sambuc {
1033*ebfedea0SLionel Sambuc 	const pgp_key_t	*key;
1034*ebfedea0SLionel Sambuc 	unsigned	 k;
1035*ebfedea0SLionel Sambuc 	mj_t		 id_array;
1036*ebfedea0SLionel Sambuc 	char		*newkey;
1037*ebfedea0SLionel Sambuc 	int		 ret;
1038*ebfedea0SLionel Sambuc 
1039*ebfedea0SLionel Sambuc 	if (name[0] == '0' && name[1] == 'x') {
1040*ebfedea0SLionel Sambuc 		name += 2;
1041*ebfedea0SLionel Sambuc 	}
1042*ebfedea0SLionel Sambuc 	(void) memset(&id_array, 0x0, sizeof(id_array));
1043*ebfedea0SLionel Sambuc 	k = 0;
1044*ebfedea0SLionel Sambuc 	*json = NULL;
1045*ebfedea0SLionel Sambuc 	mj_create(&id_array, "array");
1046*ebfedea0SLionel Sambuc 	do {
1047*ebfedea0SLionel Sambuc 		key = pgp_getnextkeybyname(netpgp->io, netpgp->pubring,
1048*ebfedea0SLionel Sambuc 						name, &k);
1049*ebfedea0SLionel Sambuc 		if (key != NULL) {
1050*ebfedea0SLionel Sambuc 			if (strcmp(fmt, "mr") == 0) {
1051*ebfedea0SLionel Sambuc 				pgp_hkp_sprint_keydata(netpgp->io, netpgp->pubring,
1052*ebfedea0SLionel Sambuc 						key, &newkey,
1053*ebfedea0SLionel Sambuc 						&key->key.pubkey, 0);
1054*ebfedea0SLionel Sambuc 				if (newkey) {
1055*ebfedea0SLionel Sambuc 					printf("%s\n", newkey);
1056*ebfedea0SLionel Sambuc 					free(newkey);
1057*ebfedea0SLionel Sambuc 				}
1058*ebfedea0SLionel Sambuc 			} else {
1059*ebfedea0SLionel Sambuc 				ALLOC(mj_t, id_array.value.v, id_array.size,
1060*ebfedea0SLionel Sambuc 					id_array.c, 10, 10, "netpgp_match_keys_json", return 0);
1061*ebfedea0SLionel Sambuc 				pgp_sprint_mj(netpgp->io, netpgp->pubring,
1062*ebfedea0SLionel Sambuc 						key, &id_array.value.v[id_array.c++],
1063*ebfedea0SLionel Sambuc 						"signature ",
1064*ebfedea0SLionel Sambuc 						&key->key.pubkey, psigs);
1065*ebfedea0SLionel Sambuc 			}
1066*ebfedea0SLionel Sambuc 			k += 1;
1067*ebfedea0SLionel Sambuc 		}
1068*ebfedea0SLionel Sambuc 	} while (key != NULL);
1069*ebfedea0SLionel Sambuc 	ret = mj_asprint(json, &id_array, MJ_JSON_ENCODE);
1070*ebfedea0SLionel Sambuc 	mj_delete(&id_array);
1071*ebfedea0SLionel Sambuc 	return ret;
1072*ebfedea0SLionel Sambuc }
1073*ebfedea0SLionel Sambuc 
1074*ebfedea0SLionel Sambuc /* find and list some public keys in a keyring */
1075*ebfedea0SLionel Sambuc int
netpgp_match_pubkeys(netpgp_t * netpgp,char * name,void * vp)1076*ebfedea0SLionel Sambuc netpgp_match_pubkeys(netpgp_t *netpgp, char *name, void *vp)
1077*ebfedea0SLionel Sambuc {
1078*ebfedea0SLionel Sambuc 	const pgp_key_t	*key;
1079*ebfedea0SLionel Sambuc 	unsigned	 k;
1080*ebfedea0SLionel Sambuc 	ssize_t		 cc;
1081*ebfedea0SLionel Sambuc 	char		 out[1024 * 64];
1082*ebfedea0SLionel Sambuc 	FILE		*fp = (FILE *)vp;
1083*ebfedea0SLionel Sambuc 
1084*ebfedea0SLionel Sambuc 	k = 0;
1085*ebfedea0SLionel Sambuc 	do {
1086*ebfedea0SLionel Sambuc 		key = pgp_getnextkeybyname(netpgp->io, netpgp->pubring,
1087*ebfedea0SLionel Sambuc 						name, &k);
1088*ebfedea0SLionel Sambuc 		if (key != NULL) {
1089*ebfedea0SLionel Sambuc 			cc = pgp_sprint_pubkey(key, out, sizeof(out));
1090*ebfedea0SLionel Sambuc 			(void) fprintf(fp, "%.*s", (int)cc, out);
1091*ebfedea0SLionel Sambuc 			k += 1;
1092*ebfedea0SLionel Sambuc 		}
1093*ebfedea0SLionel Sambuc 	} while (key != NULL);
1094*ebfedea0SLionel Sambuc 	return k;
1095*ebfedea0SLionel Sambuc }
1096*ebfedea0SLionel Sambuc 
1097*ebfedea0SLionel Sambuc /* find a key in a keyring */
1098*ebfedea0SLionel Sambuc int
netpgp_find_key(netpgp_t * netpgp,char * id)1099*ebfedea0SLionel Sambuc netpgp_find_key(netpgp_t *netpgp, char *id)
1100*ebfedea0SLionel Sambuc {
1101*ebfedea0SLionel Sambuc 	pgp_io_t	*io;
1102*ebfedea0SLionel Sambuc 
1103*ebfedea0SLionel Sambuc 	io = netpgp->io;
1104*ebfedea0SLionel Sambuc 	if (id == NULL) {
1105*ebfedea0SLionel Sambuc 		(void) fprintf(io->errs, "NULL id to search for\n");
1106*ebfedea0SLionel Sambuc 		return 0;
1107*ebfedea0SLionel Sambuc 	}
1108*ebfedea0SLionel Sambuc 	return pgp_getkeybyname(netpgp->io, netpgp->pubring, id) != NULL;
1109*ebfedea0SLionel Sambuc }
1110*ebfedea0SLionel Sambuc 
1111*ebfedea0SLionel Sambuc /* get a key in a keyring */
1112*ebfedea0SLionel Sambuc char *
netpgp_get_key(netpgp_t * netpgp,const char * name,const char * fmt)1113*ebfedea0SLionel Sambuc netpgp_get_key(netpgp_t *netpgp, const char *name, const char *fmt)
1114*ebfedea0SLionel Sambuc {
1115*ebfedea0SLionel Sambuc 	const pgp_key_t	*key;
1116*ebfedea0SLionel Sambuc 	char		*newkey;
1117*ebfedea0SLionel Sambuc 
1118*ebfedea0SLionel Sambuc 	if ((key = resolve_userid(netpgp, netpgp->pubring, name)) == NULL) {
1119*ebfedea0SLionel Sambuc 		return NULL;
1120*ebfedea0SLionel Sambuc 	}
1121*ebfedea0SLionel Sambuc 	if (strcmp(fmt, "mr") == 0) {
1122*ebfedea0SLionel Sambuc 		return (pgp_hkp_sprint_keydata(netpgp->io, netpgp->pubring,
1123*ebfedea0SLionel Sambuc 				key, &newkey,
1124*ebfedea0SLionel Sambuc 				&key->key.pubkey,
1125*ebfedea0SLionel Sambuc 				netpgp_getvar(netpgp, "subkey sigs") != NULL) > 0) ? newkey : NULL;
1126*ebfedea0SLionel Sambuc 	}
1127*ebfedea0SLionel Sambuc 	return (pgp_sprint_keydata(netpgp->io, netpgp->pubring,
1128*ebfedea0SLionel Sambuc 				key, &newkey, "signature",
1129*ebfedea0SLionel Sambuc 				&key->key.pubkey,
1130*ebfedea0SLionel Sambuc 				netpgp_getvar(netpgp, "subkey sigs") != NULL) > 0) ? newkey : NULL;
1131*ebfedea0SLionel Sambuc }
1132*ebfedea0SLionel Sambuc 
1133*ebfedea0SLionel Sambuc /* export a given key */
1134*ebfedea0SLionel Sambuc char *
netpgp_export_key(netpgp_t * netpgp,char * name)1135*ebfedea0SLionel Sambuc netpgp_export_key(netpgp_t *netpgp, char *name)
1136*ebfedea0SLionel Sambuc {
1137*ebfedea0SLionel Sambuc 	const pgp_key_t	*key;
1138*ebfedea0SLionel Sambuc 	pgp_io_t		*io;
1139*ebfedea0SLionel Sambuc 
1140*ebfedea0SLionel Sambuc 	io = netpgp->io;
1141*ebfedea0SLionel Sambuc 	if ((key = resolve_userid(netpgp, netpgp->pubring, name)) == NULL) {
1142*ebfedea0SLionel Sambuc 		return NULL;
1143*ebfedea0SLionel Sambuc 	}
1144*ebfedea0SLionel Sambuc 	return pgp_export_key(io, key, NULL);
1145*ebfedea0SLionel Sambuc }
1146*ebfedea0SLionel Sambuc 
1147*ebfedea0SLionel Sambuc #define IMPORT_ARMOR_HEAD	"-----BEGIN PGP PUBLIC KEY BLOCK-----"
1148*ebfedea0SLionel Sambuc 
1149*ebfedea0SLionel Sambuc /* import a key into our keyring */
1150*ebfedea0SLionel Sambuc int
netpgp_import_key(netpgp_t * netpgp,char * f)1151*ebfedea0SLionel Sambuc netpgp_import_key(netpgp_t *netpgp, char *f)
1152*ebfedea0SLionel Sambuc {
1153*ebfedea0SLionel Sambuc 	pgp_io_t	*io;
1154*ebfedea0SLionel Sambuc 	unsigned	 realarmor;
1155*ebfedea0SLionel Sambuc 	int		 done;
1156*ebfedea0SLionel Sambuc 
1157*ebfedea0SLionel Sambuc 	io = netpgp->io;
1158*ebfedea0SLionel Sambuc 	realarmor = isarmoured(io, f, NULL, IMPORT_ARMOR_HEAD);
1159*ebfedea0SLionel Sambuc 	done = pgp_keyring_fileread(netpgp->pubring, realarmor, f);
1160*ebfedea0SLionel Sambuc 	if (!done) {
1161*ebfedea0SLionel Sambuc 		(void) fprintf(io->errs, "Cannot import key from file %s\n", f);
1162*ebfedea0SLionel Sambuc 		return 0;
1163*ebfedea0SLionel Sambuc 	}
1164*ebfedea0SLionel Sambuc 	return pgp_keyring_list(io, netpgp->pubring, 0);
1165*ebfedea0SLionel Sambuc }
1166*ebfedea0SLionel Sambuc 
1167*ebfedea0SLionel Sambuc #define ID_OFFSET	38
1168*ebfedea0SLionel Sambuc 
1169*ebfedea0SLionel Sambuc /* generate a new key */
1170*ebfedea0SLionel Sambuc int
netpgp_generate_key(netpgp_t * netpgp,char * id,int numbits)1171*ebfedea0SLionel Sambuc netpgp_generate_key(netpgp_t *netpgp, char *id, int numbits)
1172*ebfedea0SLionel Sambuc {
1173*ebfedea0SLionel Sambuc 	pgp_output_t		*create;
1174*ebfedea0SLionel Sambuc 	const unsigned		 noarmor = 0;
1175*ebfedea0SLionel Sambuc 	pgp_key_t		*key;
1176*ebfedea0SLionel Sambuc 	pgp_io_t		*io;
1177*ebfedea0SLionel Sambuc 	uint8_t			*uid;
1178*ebfedea0SLionel Sambuc 	char			 passphrase[128];
1179*ebfedea0SLionel Sambuc 	char			 newid[1024];
1180*ebfedea0SLionel Sambuc 	char			 filename[MAXPATHLEN];
1181*ebfedea0SLionel Sambuc 	char			 dir[MAXPATHLEN];
1182*ebfedea0SLionel Sambuc 	char			*cp;
1183*ebfedea0SLionel Sambuc 	char			*ringfile;
1184*ebfedea0SLionel Sambuc 	char			*numtries;
1185*ebfedea0SLionel Sambuc 	int             	 attempts;
1186*ebfedea0SLionel Sambuc 	int             	 passc;
1187*ebfedea0SLionel Sambuc 	int             	 fd;
1188*ebfedea0SLionel Sambuc 	int             	 cc;
1189*ebfedea0SLionel Sambuc 
1190*ebfedea0SLionel Sambuc 	uid = NULL;
1191*ebfedea0SLionel Sambuc 	io = netpgp->io;
1192*ebfedea0SLionel Sambuc 	/* generate a new key */
1193*ebfedea0SLionel Sambuc 	if (id) {
1194*ebfedea0SLionel Sambuc 		(void) snprintf(newid, sizeof(newid), "%s", id);
1195*ebfedea0SLionel Sambuc 	} else {
1196*ebfedea0SLionel Sambuc 		(void) snprintf(newid, sizeof(newid),
1197*ebfedea0SLionel Sambuc 			"RSA %d-bit key <%s@localhost>", numbits, getenv("LOGNAME"));
1198*ebfedea0SLionel Sambuc 	}
1199*ebfedea0SLionel Sambuc 	uid = (uint8_t *)newid;
1200*ebfedea0SLionel Sambuc 	key = pgp_rsa_new_selfsign_key(numbits, 65537UL, uid,
1201*ebfedea0SLionel Sambuc 			netpgp_getvar(netpgp, "hash"),
1202*ebfedea0SLionel Sambuc 			netpgp_getvar(netpgp, "cipher"));
1203*ebfedea0SLionel Sambuc 	if (key == NULL) {
1204*ebfedea0SLionel Sambuc 		(void) fprintf(io->errs, "Cannot generate key\n");
1205*ebfedea0SLionel Sambuc 		return 0;
1206*ebfedea0SLionel Sambuc 	}
1207*ebfedea0SLionel Sambuc 	cp = NULL;
1208*ebfedea0SLionel Sambuc 	pgp_sprint_keydata(netpgp->io, NULL, key, &cp, "signature ", &key->key.seckey.pubkey, 0);
1209*ebfedea0SLionel Sambuc 	(void) fprintf(stdout, "%s", cp);
1210*ebfedea0SLionel Sambuc 	/* write public key */
1211*ebfedea0SLionel Sambuc 	cc = snprintf(dir, sizeof(dir), "%s/%.16s", netpgp_getvar(netpgp, "homedir"), &cp[ID_OFFSET]);
1212*ebfedea0SLionel Sambuc 	netpgp_setvar(netpgp, "generated userid", &dir[cc - 16]);
1213*ebfedea0SLionel Sambuc 	if (mkdir(dir, 0700) < 0) {
1214*ebfedea0SLionel Sambuc 		(void) fprintf(io->errs, "can't mkdir '%s'\n", dir);
1215*ebfedea0SLionel Sambuc 		return 0;
1216*ebfedea0SLionel Sambuc 	}
1217*ebfedea0SLionel Sambuc 	(void) fprintf(io->errs, "netpgp: generated keys in directory %s\n", dir);
1218*ebfedea0SLionel Sambuc 	(void) snprintf(ringfile = filename, sizeof(filename), "%s/pubring.gpg", dir);
1219*ebfedea0SLionel Sambuc 	if (!appendkey(io, key, ringfile)) {
1220*ebfedea0SLionel Sambuc 		(void) fprintf(io->errs, "Cannot write pubkey to '%s'\n", ringfile);
1221*ebfedea0SLionel Sambuc 		return 0;
1222*ebfedea0SLionel Sambuc 	}
1223*ebfedea0SLionel Sambuc 	if (netpgp->pubring != NULL) {
1224*ebfedea0SLionel Sambuc 		pgp_keyring_free(netpgp->pubring);
1225*ebfedea0SLionel Sambuc 	}
1226*ebfedea0SLionel Sambuc 	/* write secret key */
1227*ebfedea0SLionel Sambuc 	(void) snprintf(ringfile = filename, sizeof(filename), "%s/secring.gpg", dir);
1228*ebfedea0SLionel Sambuc 	if ((fd = pgp_setup_file_append(&create, ringfile)) < 0) {
1229*ebfedea0SLionel Sambuc 		fd = pgp_setup_file_write(&create, ringfile, 0);
1230*ebfedea0SLionel Sambuc 	}
1231*ebfedea0SLionel Sambuc 	if (fd < 0) {
1232*ebfedea0SLionel Sambuc 		(void) fprintf(io->errs, "can't append secring '%s'\n", ringfile);
1233*ebfedea0SLionel Sambuc 		return 0;
1234*ebfedea0SLionel Sambuc 	}
1235*ebfedea0SLionel Sambuc 	/* get the passphrase */
1236*ebfedea0SLionel Sambuc 	if ((numtries = netpgp_getvar(netpgp, "numtries")) == NULL ||
1237*ebfedea0SLionel Sambuc 	    (attempts = atoi(numtries)) <= 0) {
1238*ebfedea0SLionel Sambuc 		attempts = MAX_PASSPHRASE_ATTEMPTS;
1239*ebfedea0SLionel Sambuc 	} else if (strcmp(numtries, "unlimited") == 0) {
1240*ebfedea0SLionel Sambuc 		attempts = INFINITE_ATTEMPTS;
1241*ebfedea0SLionel Sambuc 	}
1242*ebfedea0SLionel Sambuc 	passc = find_passphrase(netpgp->passfp, &cp[ID_OFFSET], passphrase, sizeof(passphrase), attempts);
1243*ebfedea0SLionel Sambuc 	if (!pgp_write_xfer_seckey(create, key, (uint8_t *)passphrase, (const unsigned)passc, noarmor)) {
1244*ebfedea0SLionel Sambuc 		(void) fprintf(io->errs, "Cannot write seckey\n");
1245*ebfedea0SLionel Sambuc 		return 0;
1246*ebfedea0SLionel Sambuc 	}
1247*ebfedea0SLionel Sambuc 	pgp_teardown_file_write(create, fd);
1248*ebfedea0SLionel Sambuc 	if (netpgp->secring != NULL) {
1249*ebfedea0SLionel Sambuc 		pgp_keyring_free(netpgp->secring);
1250*ebfedea0SLionel Sambuc 	}
1251*ebfedea0SLionel Sambuc 	pgp_keydata_free(key);
1252*ebfedea0SLionel Sambuc 	free(cp);
1253*ebfedea0SLionel Sambuc 	return 1;
1254*ebfedea0SLionel Sambuc }
1255*ebfedea0SLionel Sambuc 
1256*ebfedea0SLionel Sambuc /* encrypt a file */
1257*ebfedea0SLionel Sambuc int
netpgp_encrypt_file(netpgp_t * netpgp,const char * userid,const char * f,char * out,int armored)1258*ebfedea0SLionel Sambuc netpgp_encrypt_file(netpgp_t *netpgp,
1259*ebfedea0SLionel Sambuc 			const char *userid,
1260*ebfedea0SLionel Sambuc 			const char *f,
1261*ebfedea0SLionel Sambuc 			char *out,
1262*ebfedea0SLionel Sambuc 			int armored)
1263*ebfedea0SLionel Sambuc {
1264*ebfedea0SLionel Sambuc 	const pgp_key_t	*key;
1265*ebfedea0SLionel Sambuc 	const unsigned		 overwrite = 1;
1266*ebfedea0SLionel Sambuc 	const char		*suffix;
1267*ebfedea0SLionel Sambuc 	pgp_io_t		*io;
1268*ebfedea0SLionel Sambuc 	char			 outname[MAXPATHLEN];
1269*ebfedea0SLionel Sambuc 
1270*ebfedea0SLionel Sambuc 	io = netpgp->io;
1271*ebfedea0SLionel Sambuc 	if (f == NULL) {
1272*ebfedea0SLionel Sambuc 		(void) fprintf(io->errs,
1273*ebfedea0SLionel Sambuc 			"netpgp_encrypt_file: no filename specified\n");
1274*ebfedea0SLionel Sambuc 		return 0;
1275*ebfedea0SLionel Sambuc 	}
1276*ebfedea0SLionel Sambuc 	suffix = (armored) ? ".asc" : ".gpg";
1277*ebfedea0SLionel Sambuc 	/* get key with which to sign */
1278*ebfedea0SLionel Sambuc 	if ((key = resolve_userid(netpgp, netpgp->pubring, userid)) == NULL) {
1279*ebfedea0SLionel Sambuc 		return 0;
1280*ebfedea0SLionel Sambuc 	}
1281*ebfedea0SLionel Sambuc 	if (out == NULL) {
1282*ebfedea0SLionel Sambuc 		(void) snprintf(outname, sizeof(outname), "%s%s", f, suffix);
1283*ebfedea0SLionel Sambuc 		out = outname;
1284*ebfedea0SLionel Sambuc 	}
1285*ebfedea0SLionel Sambuc 	return (int)pgp_encrypt_file(io, f, out, key, (unsigned)armored,
1286*ebfedea0SLionel Sambuc 				overwrite, netpgp_getvar(netpgp, "cipher"));
1287*ebfedea0SLionel Sambuc }
1288*ebfedea0SLionel Sambuc 
1289*ebfedea0SLionel Sambuc #define ARMOR_HEAD	"-----BEGIN PGP MESSAGE-----"
1290*ebfedea0SLionel Sambuc 
1291*ebfedea0SLionel Sambuc /* decrypt a file */
1292*ebfedea0SLionel Sambuc int
netpgp_decrypt_file(netpgp_t * netpgp,const char * f,char * out,int armored)1293*ebfedea0SLionel Sambuc netpgp_decrypt_file(netpgp_t *netpgp, const char *f, char *out, int armored)
1294*ebfedea0SLionel Sambuc {
1295*ebfedea0SLionel Sambuc 	const unsigned	 overwrite = 1;
1296*ebfedea0SLionel Sambuc 	pgp_io_t	*io;
1297*ebfedea0SLionel Sambuc 	unsigned	 realarmor;
1298*ebfedea0SLionel Sambuc 	unsigned	 sshkeys;
1299*ebfedea0SLionel Sambuc 	char		*numtries;
1300*ebfedea0SLionel Sambuc 	int            	 attempts;
1301*ebfedea0SLionel Sambuc 
1302*ebfedea0SLionel Sambuc 	__PGP_USED(armored);
1303*ebfedea0SLionel Sambuc 	io = netpgp->io;
1304*ebfedea0SLionel Sambuc 	if (f == NULL) {
1305*ebfedea0SLionel Sambuc 		(void) fprintf(io->errs,
1306*ebfedea0SLionel Sambuc 			"netpgp_decrypt_file: no filename specified\n");
1307*ebfedea0SLionel Sambuc 		return 0;
1308*ebfedea0SLionel Sambuc 	}
1309*ebfedea0SLionel Sambuc 	realarmor = isarmoured(io, f, NULL, ARMOR_HEAD);
1310*ebfedea0SLionel Sambuc 	sshkeys = (unsigned)(netpgp_getvar(netpgp, "ssh keys") != NULL);
1311*ebfedea0SLionel Sambuc 	if ((numtries = netpgp_getvar(netpgp, "numtries")) == NULL ||
1312*ebfedea0SLionel Sambuc 	    (attempts = atoi(numtries)) <= 0) {
1313*ebfedea0SLionel Sambuc 		attempts = MAX_PASSPHRASE_ATTEMPTS;
1314*ebfedea0SLionel Sambuc 	} else if (strcmp(numtries, "unlimited") == 0) {
1315*ebfedea0SLionel Sambuc 		attempts = INFINITE_ATTEMPTS;
1316*ebfedea0SLionel Sambuc 	}
1317*ebfedea0SLionel Sambuc 	return pgp_decrypt_file(netpgp->io, f, out, netpgp->secring,
1318*ebfedea0SLionel Sambuc 				netpgp->pubring,
1319*ebfedea0SLionel Sambuc 				realarmor, overwrite, sshkeys,
1320*ebfedea0SLionel Sambuc 				netpgp->passfp, attempts, get_passphrase_cb);
1321*ebfedea0SLionel Sambuc }
1322*ebfedea0SLionel Sambuc 
1323*ebfedea0SLionel Sambuc /* sign a file */
1324*ebfedea0SLionel Sambuc int
netpgp_sign_file(netpgp_t * netpgp,const char * userid,const char * f,char * out,int armored,int cleartext,int detached)1325*ebfedea0SLionel Sambuc netpgp_sign_file(netpgp_t *netpgp,
1326*ebfedea0SLionel Sambuc 		const char *userid,
1327*ebfedea0SLionel Sambuc 		const char *f,
1328*ebfedea0SLionel Sambuc 		char *out,
1329*ebfedea0SLionel Sambuc 		int armored,
1330*ebfedea0SLionel Sambuc 		int cleartext,
1331*ebfedea0SLionel Sambuc 		int detached)
1332*ebfedea0SLionel Sambuc {
1333*ebfedea0SLionel Sambuc 	const pgp_key_t		*keypair;
1334*ebfedea0SLionel Sambuc 	const pgp_key_t		*pubkey;
1335*ebfedea0SLionel Sambuc 	const unsigned		 overwrite = 1;
1336*ebfedea0SLionel Sambuc 	pgp_seckey_t		*seckey;
1337*ebfedea0SLionel Sambuc 	const char		*hashalg;
1338*ebfedea0SLionel Sambuc 	pgp_io_t		*io;
1339*ebfedea0SLionel Sambuc 	char			*numtries;
1340*ebfedea0SLionel Sambuc 	int			 attempts;
1341*ebfedea0SLionel Sambuc 	int			 ret;
1342*ebfedea0SLionel Sambuc 	int			 i;
1343*ebfedea0SLionel Sambuc 
1344*ebfedea0SLionel Sambuc 	io = netpgp->io;
1345*ebfedea0SLionel Sambuc 	if (f == NULL) {
1346*ebfedea0SLionel Sambuc 		(void) fprintf(io->errs,
1347*ebfedea0SLionel Sambuc 			"netpgp_sign_file: no filename specified\n");
1348*ebfedea0SLionel Sambuc 		return 0;
1349*ebfedea0SLionel Sambuc 	}
1350*ebfedea0SLionel Sambuc 	/* get key with which to sign */
1351*ebfedea0SLionel Sambuc 	if ((keypair = resolve_userid(netpgp, netpgp->secring, userid)) == NULL) {
1352*ebfedea0SLionel Sambuc 		return 0;
1353*ebfedea0SLionel Sambuc 	}
1354*ebfedea0SLionel Sambuc 	ret = 1;
1355*ebfedea0SLionel Sambuc 	if ((numtries = netpgp_getvar(netpgp, "numtries")) == NULL ||
1356*ebfedea0SLionel Sambuc 	    (attempts = atoi(numtries)) <= 0) {
1357*ebfedea0SLionel Sambuc 		attempts = MAX_PASSPHRASE_ATTEMPTS;
1358*ebfedea0SLionel Sambuc 	} else if (strcmp(numtries, "unlimited") == 0) {
1359*ebfedea0SLionel Sambuc 		attempts = INFINITE_ATTEMPTS;
1360*ebfedea0SLionel Sambuc 	}
1361*ebfedea0SLionel Sambuc 	for (i = 0, seckey = NULL ; !seckey && (i < attempts || attempts == INFINITE_ATTEMPTS) ; i++) {
1362*ebfedea0SLionel Sambuc 		if (netpgp->passfp == NULL) {
1363*ebfedea0SLionel Sambuc 			/* print out the user id */
1364*ebfedea0SLionel Sambuc 			pubkey = pgp_getkeybyname(io, netpgp->pubring, userid);
1365*ebfedea0SLionel Sambuc 			if (pubkey == NULL) {
1366*ebfedea0SLionel Sambuc 				(void) fprintf(io->errs,
1367*ebfedea0SLionel Sambuc 					"netpgp: warning - using pubkey from secring\n");
1368*ebfedea0SLionel Sambuc 				pgp_print_keydata(io, netpgp->pubring, keypair, "signature ",
1369*ebfedea0SLionel Sambuc 					&keypair->key.seckey.pubkey, 0);
1370*ebfedea0SLionel Sambuc 			} else {
1371*ebfedea0SLionel Sambuc 				pgp_print_keydata(io, netpgp->pubring, pubkey, "signature ",
1372*ebfedea0SLionel Sambuc 					&pubkey->key.pubkey, 0);
1373*ebfedea0SLionel Sambuc 			}
1374*ebfedea0SLionel Sambuc 		}
1375*ebfedea0SLionel Sambuc 		if (netpgp_getvar(netpgp, "ssh keys") == NULL) {
1376*ebfedea0SLionel Sambuc 			/* now decrypt key */
1377*ebfedea0SLionel Sambuc 			seckey = pgp_decrypt_seckey(keypair, netpgp->passfp);
1378*ebfedea0SLionel Sambuc 			if (seckey == NULL) {
1379*ebfedea0SLionel Sambuc 				(void) fprintf(io->errs, "Bad passphrase\n");
1380*ebfedea0SLionel Sambuc 			}
1381*ebfedea0SLionel Sambuc 		} else {
1382*ebfedea0SLionel Sambuc 			pgp_keyring_t	*secring;
1383*ebfedea0SLionel Sambuc 
1384*ebfedea0SLionel Sambuc 			secring = netpgp->secring;
1385*ebfedea0SLionel Sambuc 			seckey = &secring->keys[0].key.seckey;
1386*ebfedea0SLionel Sambuc 		}
1387*ebfedea0SLionel Sambuc 	}
1388*ebfedea0SLionel Sambuc 	if (seckey == NULL) {
1389*ebfedea0SLionel Sambuc 		(void) fprintf(io->errs, "Bad passphrase\n");
1390*ebfedea0SLionel Sambuc 		return 0;
1391*ebfedea0SLionel Sambuc 	}
1392*ebfedea0SLionel Sambuc 	/* sign file */
1393*ebfedea0SLionel Sambuc 	hashalg = netpgp_getvar(netpgp, "hash");
1394*ebfedea0SLionel Sambuc 	if (seckey->pubkey.alg == PGP_PKA_DSA) {
1395*ebfedea0SLionel Sambuc 		hashalg = "sha1";
1396*ebfedea0SLionel Sambuc 	}
1397*ebfedea0SLionel Sambuc 	if (detached) {
1398*ebfedea0SLionel Sambuc 		ret = pgp_sign_detached(io, f, out, seckey, hashalg,
1399*ebfedea0SLionel Sambuc 				get_birthtime(netpgp_getvar(netpgp, "birthtime")),
1400*ebfedea0SLionel Sambuc 				get_duration(netpgp_getvar(netpgp, "duration")),
1401*ebfedea0SLionel Sambuc 				(unsigned)armored,
1402*ebfedea0SLionel Sambuc 				overwrite);
1403*ebfedea0SLionel Sambuc 	} else {
1404*ebfedea0SLionel Sambuc 		ret = pgp_sign_file(io, f, out, seckey, hashalg,
1405*ebfedea0SLionel Sambuc 				get_birthtime(netpgp_getvar(netpgp, "birthtime")),
1406*ebfedea0SLionel Sambuc 				get_duration(netpgp_getvar(netpgp, "duration")),
1407*ebfedea0SLionel Sambuc 				(unsigned)armored, (unsigned)cleartext,
1408*ebfedea0SLionel Sambuc 				overwrite);
1409*ebfedea0SLionel Sambuc 	}
1410*ebfedea0SLionel Sambuc 	pgp_forget(seckey, (unsigned)sizeof(*seckey));
1411*ebfedea0SLionel Sambuc 	return ret;
1412*ebfedea0SLionel Sambuc }
1413*ebfedea0SLionel Sambuc 
1414*ebfedea0SLionel Sambuc #define ARMOR_SIG_HEAD	"-----BEGIN PGP (SIGNATURE|SIGNED MESSAGE)-----"
1415*ebfedea0SLionel Sambuc 
1416*ebfedea0SLionel Sambuc /* verify a file */
1417*ebfedea0SLionel Sambuc int
netpgp_verify_file(netpgp_t * netpgp,const char * in,const char * out,int armored)1418*ebfedea0SLionel Sambuc netpgp_verify_file(netpgp_t *netpgp, const char *in, const char *out, int armored)
1419*ebfedea0SLionel Sambuc {
1420*ebfedea0SLionel Sambuc 	pgp_validation_t	 result;
1421*ebfedea0SLionel Sambuc 	pgp_io_t		*io;
1422*ebfedea0SLionel Sambuc 	unsigned		 realarmor;
1423*ebfedea0SLionel Sambuc 
1424*ebfedea0SLionel Sambuc 	__PGP_USED(armored);
1425*ebfedea0SLionel Sambuc 	(void) memset(&result, 0x0, sizeof(result));
1426*ebfedea0SLionel Sambuc 	io = netpgp->io;
1427*ebfedea0SLionel Sambuc 	if (in == NULL) {
1428*ebfedea0SLionel Sambuc 		(void) fprintf(io->errs,
1429*ebfedea0SLionel Sambuc 			"netpgp_verify_file: no filename specified\n");
1430*ebfedea0SLionel Sambuc 		return 0;
1431*ebfedea0SLionel Sambuc 	}
1432*ebfedea0SLionel Sambuc 	realarmor = isarmoured(io, in, NULL, ARMOR_SIG_HEAD);
1433*ebfedea0SLionel Sambuc 	if (pgp_validate_file(io, &result, in, out, (const int)realarmor, netpgp->pubring)) {
1434*ebfedea0SLionel Sambuc 		resultp(io, in, &result, netpgp->pubring);
1435*ebfedea0SLionel Sambuc 		return 1;
1436*ebfedea0SLionel Sambuc 	}
1437*ebfedea0SLionel Sambuc 	if (result.validc + result.invalidc + result.unknownc == 0) {
1438*ebfedea0SLionel Sambuc 		(void) fprintf(io->errs,
1439*ebfedea0SLionel Sambuc 		"\"%s\": No signatures found - is this a signed file?\n",
1440*ebfedea0SLionel Sambuc 			in);
1441*ebfedea0SLionel Sambuc 	} else if (result.invalidc == 0 && result.unknownc == 0) {
1442*ebfedea0SLionel Sambuc 		(void) fprintf(io->errs,
1443*ebfedea0SLionel Sambuc 			"\"%s\": file verification failure: invalid signature time\n", in);
1444*ebfedea0SLionel Sambuc 	} else {
1445*ebfedea0SLionel Sambuc 		(void) fprintf(io->errs,
1446*ebfedea0SLionel Sambuc "\"%s\": verification failure: %u invalid signatures, %u unknown signatures\n",
1447*ebfedea0SLionel Sambuc 			in, result.invalidc, result.unknownc);
1448*ebfedea0SLionel Sambuc 	}
1449*ebfedea0SLionel Sambuc 	return 0;
1450*ebfedea0SLionel Sambuc }
1451*ebfedea0SLionel Sambuc 
1452*ebfedea0SLionel Sambuc /* sign some memory */
1453*ebfedea0SLionel Sambuc int
netpgp_sign_memory(netpgp_t * netpgp,const char * userid,char * mem,size_t size,char * out,size_t outsize,const unsigned armored,const unsigned cleartext)1454*ebfedea0SLionel Sambuc netpgp_sign_memory(netpgp_t *netpgp,
1455*ebfedea0SLionel Sambuc 		const char *userid,
1456*ebfedea0SLionel Sambuc 		char *mem,
1457*ebfedea0SLionel Sambuc 		size_t size,
1458*ebfedea0SLionel Sambuc 		char *out,
1459*ebfedea0SLionel Sambuc 		size_t outsize,
1460*ebfedea0SLionel Sambuc 		const unsigned armored,
1461*ebfedea0SLionel Sambuc 		const unsigned cleartext)
1462*ebfedea0SLionel Sambuc {
1463*ebfedea0SLionel Sambuc 	const pgp_key_t		*keypair;
1464*ebfedea0SLionel Sambuc 	const pgp_key_t		*pubkey;
1465*ebfedea0SLionel Sambuc 	pgp_seckey_t		*seckey;
1466*ebfedea0SLionel Sambuc 	pgp_memory_t		*signedmem;
1467*ebfedea0SLionel Sambuc 	const char		*hashalg;
1468*ebfedea0SLionel Sambuc 	pgp_io_t		*io;
1469*ebfedea0SLionel Sambuc 	char 			*numtries;
1470*ebfedea0SLionel Sambuc 	int			 attempts;
1471*ebfedea0SLionel Sambuc 	int			 ret;
1472*ebfedea0SLionel Sambuc 	int			 i;
1473*ebfedea0SLionel Sambuc 
1474*ebfedea0SLionel Sambuc 	io = netpgp->io;
1475*ebfedea0SLionel Sambuc 	if (mem == NULL) {
1476*ebfedea0SLionel Sambuc 		(void) fprintf(io->errs,
1477*ebfedea0SLionel Sambuc 			"netpgp_sign_memory: no memory to sign\n");
1478*ebfedea0SLionel Sambuc 		return 0;
1479*ebfedea0SLionel Sambuc 	}
1480*ebfedea0SLionel Sambuc 	if ((keypair = resolve_userid(netpgp, netpgp->secring, userid)) == NULL) {
1481*ebfedea0SLionel Sambuc 		return 0;
1482*ebfedea0SLionel Sambuc 	}
1483*ebfedea0SLionel Sambuc 	ret = 1;
1484*ebfedea0SLionel Sambuc 	if ((numtries = netpgp_getvar(netpgp, "numtries")) == NULL ||
1485*ebfedea0SLionel Sambuc 	    (attempts = atoi(numtries)) <= 0) {
1486*ebfedea0SLionel Sambuc 		attempts = MAX_PASSPHRASE_ATTEMPTS;
1487*ebfedea0SLionel Sambuc 	} else if (strcmp(numtries, "unlimited") == 0) {
1488*ebfedea0SLionel Sambuc 		attempts = INFINITE_ATTEMPTS;
1489*ebfedea0SLionel Sambuc 	}
1490*ebfedea0SLionel Sambuc 	for (i = 0, seckey = NULL ; !seckey && (i < attempts || attempts == INFINITE_ATTEMPTS) ; i++) {
1491*ebfedea0SLionel Sambuc 		if (netpgp->passfp == NULL) {
1492*ebfedea0SLionel Sambuc 			/* print out the user id */
1493*ebfedea0SLionel Sambuc 			pubkey = pgp_getkeybyname(io, netpgp->pubring, userid);
1494*ebfedea0SLionel Sambuc 			if (pubkey == NULL) {
1495*ebfedea0SLionel Sambuc 				(void) fprintf(io->errs,
1496*ebfedea0SLionel Sambuc 					"netpgp: warning - using pubkey from secring\n");
1497*ebfedea0SLionel Sambuc 				pgp_print_keydata(io, netpgp->pubring, keypair, "signature ",
1498*ebfedea0SLionel Sambuc 					&keypair->key.seckey.pubkey, 0);
1499*ebfedea0SLionel Sambuc 			} else {
1500*ebfedea0SLionel Sambuc 				pgp_print_keydata(io, netpgp->pubring, pubkey, "signature ",
1501*ebfedea0SLionel Sambuc 					&pubkey->key.pubkey, 0);
1502*ebfedea0SLionel Sambuc 			}
1503*ebfedea0SLionel Sambuc 		}
1504*ebfedea0SLionel Sambuc 		/* now decrypt key */
1505*ebfedea0SLionel Sambuc 		seckey = pgp_decrypt_seckey(keypair, netpgp->passfp);
1506*ebfedea0SLionel Sambuc 		if (seckey == NULL) {
1507*ebfedea0SLionel Sambuc 			(void) fprintf(io->errs, "Bad passphrase\n");
1508*ebfedea0SLionel Sambuc 		}
1509*ebfedea0SLionel Sambuc 	}
1510*ebfedea0SLionel Sambuc 	if (seckey == NULL) {
1511*ebfedea0SLionel Sambuc 		(void) fprintf(io->errs, "Bad passphrase\n");
1512*ebfedea0SLionel Sambuc 		return 0;
1513*ebfedea0SLionel Sambuc 	}
1514*ebfedea0SLionel Sambuc 	/* sign file */
1515*ebfedea0SLionel Sambuc 	(void) memset(out, 0x0, outsize);
1516*ebfedea0SLionel Sambuc 	hashalg = netpgp_getvar(netpgp, "hash");
1517*ebfedea0SLionel Sambuc 	if (seckey->pubkey.alg == PGP_PKA_DSA) {
1518*ebfedea0SLionel Sambuc 		hashalg = "sha1";
1519*ebfedea0SLionel Sambuc 	}
1520*ebfedea0SLionel Sambuc 	signedmem = pgp_sign_buf(io, mem, size, seckey,
1521*ebfedea0SLionel Sambuc 				get_birthtime(netpgp_getvar(netpgp, "birthtime")),
1522*ebfedea0SLionel Sambuc 				get_duration(netpgp_getvar(netpgp, "duration")),
1523*ebfedea0SLionel Sambuc 				hashalg, armored, cleartext);
1524*ebfedea0SLionel Sambuc 	if (signedmem) {
1525*ebfedea0SLionel Sambuc 		size_t	m;
1526*ebfedea0SLionel Sambuc 
1527*ebfedea0SLionel Sambuc 		m = MIN(pgp_mem_len(signedmem), outsize);
1528*ebfedea0SLionel Sambuc 		(void) memcpy(out, pgp_mem_data(signedmem), m);
1529*ebfedea0SLionel Sambuc 		pgp_memory_free(signedmem);
1530*ebfedea0SLionel Sambuc 		ret = (int)m;
1531*ebfedea0SLionel Sambuc 	} else {
1532*ebfedea0SLionel Sambuc 		ret = 0;
1533*ebfedea0SLionel Sambuc 	}
1534*ebfedea0SLionel Sambuc 	pgp_forget(seckey, (unsigned)sizeof(*seckey));
1535*ebfedea0SLionel Sambuc 	return ret;
1536*ebfedea0SLionel Sambuc }
1537*ebfedea0SLionel Sambuc 
1538*ebfedea0SLionel Sambuc /* verify memory */
1539*ebfedea0SLionel Sambuc int
netpgp_verify_memory(netpgp_t * netpgp,const void * in,const size_t size,void * out,size_t outsize,const int armored)1540*ebfedea0SLionel Sambuc netpgp_verify_memory(netpgp_t *netpgp, const void *in, const size_t size,
1541*ebfedea0SLionel Sambuc 			void *out, size_t outsize, const int armored)
1542*ebfedea0SLionel Sambuc {
1543*ebfedea0SLionel Sambuc 	pgp_validation_t	 result;
1544*ebfedea0SLionel Sambuc 	pgp_memory_t		*signedmem;
1545*ebfedea0SLionel Sambuc 	pgp_memory_t		*cat;
1546*ebfedea0SLionel Sambuc 	pgp_io_t		*io;
1547*ebfedea0SLionel Sambuc 	size_t			 m;
1548*ebfedea0SLionel Sambuc 	int			 ret;
1549*ebfedea0SLionel Sambuc 
1550*ebfedea0SLionel Sambuc 	(void) memset(&result, 0x0, sizeof(result));
1551*ebfedea0SLionel Sambuc 	io = netpgp->io;
1552*ebfedea0SLionel Sambuc 	if (in == NULL) {
1553*ebfedea0SLionel Sambuc 		(void) fprintf(io->errs,
1554*ebfedea0SLionel Sambuc 			"netpgp_verify_memory: no memory to verify\n");
1555*ebfedea0SLionel Sambuc 		return 0;
1556*ebfedea0SLionel Sambuc 	}
1557*ebfedea0SLionel Sambuc 	signedmem = pgp_memory_new();
1558*ebfedea0SLionel Sambuc 	pgp_memory_add(signedmem, in, size);
1559*ebfedea0SLionel Sambuc 	if (out) {
1560*ebfedea0SLionel Sambuc 		cat = pgp_memory_new();
1561*ebfedea0SLionel Sambuc 	}
1562*ebfedea0SLionel Sambuc 	ret = pgp_validate_mem(io, &result, signedmem,
1563*ebfedea0SLionel Sambuc 				(out) ? &cat : NULL,
1564*ebfedea0SLionel Sambuc 				armored, netpgp->pubring);
1565*ebfedea0SLionel Sambuc 	/* signedmem is freed from pgp_validate_mem */
1566*ebfedea0SLionel Sambuc 	if (ret) {
1567*ebfedea0SLionel Sambuc 		resultp(io, "<stdin>", &result, netpgp->pubring);
1568*ebfedea0SLionel Sambuc 		if (out) {
1569*ebfedea0SLionel Sambuc 			m = MIN(pgp_mem_len(cat), outsize);
1570*ebfedea0SLionel Sambuc 			(void) memcpy(out, pgp_mem_data(cat), m);
1571*ebfedea0SLionel Sambuc 			pgp_memory_free(cat);
1572*ebfedea0SLionel Sambuc 		} else {
1573*ebfedea0SLionel Sambuc 			m = 1;
1574*ebfedea0SLionel Sambuc 		}
1575*ebfedea0SLionel Sambuc 		return (int)m;
1576*ebfedea0SLionel Sambuc 	}
1577*ebfedea0SLionel Sambuc 	if (result.validc + result.invalidc + result.unknownc == 0) {
1578*ebfedea0SLionel Sambuc 		(void) fprintf(io->errs,
1579*ebfedea0SLionel Sambuc 		"No signatures found - is this memory signed?\n");
1580*ebfedea0SLionel Sambuc 	} else if (result.invalidc == 0 && result.unknownc == 0) {
1581*ebfedea0SLionel Sambuc 		(void) fprintf(io->errs,
1582*ebfedea0SLionel Sambuc 			"memory verification failure: invalid signature time\n");
1583*ebfedea0SLionel Sambuc 	} else {
1584*ebfedea0SLionel Sambuc 		(void) fprintf(io->errs,
1585*ebfedea0SLionel Sambuc "memory verification failure: %u invalid signatures, %u unknown signatures\n",
1586*ebfedea0SLionel Sambuc 			result.invalidc, result.unknownc);
1587*ebfedea0SLionel Sambuc 	}
1588*ebfedea0SLionel Sambuc 	return 0;
1589*ebfedea0SLionel Sambuc }
1590*ebfedea0SLionel Sambuc 
1591*ebfedea0SLionel Sambuc /* encrypt some memory */
1592*ebfedea0SLionel Sambuc int
netpgp_encrypt_memory(netpgp_t * netpgp,const char * userid,void * in,const size_t insize,char * out,size_t outsize,int armored)1593*ebfedea0SLionel Sambuc netpgp_encrypt_memory(netpgp_t *netpgp,
1594*ebfedea0SLionel Sambuc 			const char *userid,
1595*ebfedea0SLionel Sambuc 			void *in,
1596*ebfedea0SLionel Sambuc 			const size_t insize,
1597*ebfedea0SLionel Sambuc 			char *out,
1598*ebfedea0SLionel Sambuc 			size_t outsize,
1599*ebfedea0SLionel Sambuc 			int armored)
1600*ebfedea0SLionel Sambuc {
1601*ebfedea0SLionel Sambuc 	const pgp_key_t	*keypair;
1602*ebfedea0SLionel Sambuc 	pgp_memory_t	*enc;
1603*ebfedea0SLionel Sambuc 	pgp_io_t	*io;
1604*ebfedea0SLionel Sambuc 	size_t		 m;
1605*ebfedea0SLionel Sambuc 
1606*ebfedea0SLionel Sambuc 	io = netpgp->io;
1607*ebfedea0SLionel Sambuc 	if (in == NULL) {
1608*ebfedea0SLionel Sambuc 		(void) fprintf(io->errs,
1609*ebfedea0SLionel Sambuc 			"netpgp_encrypt_buf: no memory to encrypt\n");
1610*ebfedea0SLionel Sambuc 		return 0;
1611*ebfedea0SLionel Sambuc 	}
1612*ebfedea0SLionel Sambuc 	if ((keypair = resolve_userid(netpgp, netpgp->pubring, userid)) == NULL) {
1613*ebfedea0SLionel Sambuc 		return 0;
1614*ebfedea0SLionel Sambuc 	}
1615*ebfedea0SLionel Sambuc 	if (in == out) {
1616*ebfedea0SLionel Sambuc 		(void) fprintf(io->errs,
1617*ebfedea0SLionel Sambuc 			"netpgp_encrypt_buf: input and output bufs need to be different\n");
1618*ebfedea0SLionel Sambuc 		return 0;
1619*ebfedea0SLionel Sambuc 	}
1620*ebfedea0SLionel Sambuc 	if (outsize < insize) {
1621*ebfedea0SLionel Sambuc 		(void) fprintf(io->errs,
1622*ebfedea0SLionel Sambuc 			"netpgp_encrypt_buf: input size is larger than output size\n");
1623*ebfedea0SLionel Sambuc 		return 0;
1624*ebfedea0SLionel Sambuc 	}
1625*ebfedea0SLionel Sambuc 	enc = pgp_encrypt_buf(io, in, insize, keypair, (unsigned)armored,
1626*ebfedea0SLionel Sambuc 				netpgp_getvar(netpgp, "cipher"));
1627*ebfedea0SLionel Sambuc 	m = MIN(pgp_mem_len(enc), outsize);
1628*ebfedea0SLionel Sambuc 	(void) memcpy(out, pgp_mem_data(enc), m);
1629*ebfedea0SLionel Sambuc 	pgp_memory_free(enc);
1630*ebfedea0SLionel Sambuc 	return (int)m;
1631*ebfedea0SLionel Sambuc }
1632*ebfedea0SLionel Sambuc 
1633*ebfedea0SLionel Sambuc /* decrypt a chunk of memory */
1634*ebfedea0SLionel Sambuc int
netpgp_decrypt_memory(netpgp_t * netpgp,const void * input,const size_t insize,char * out,size_t outsize,const int armored)1635*ebfedea0SLionel Sambuc netpgp_decrypt_memory(netpgp_t *netpgp, const void *input, const size_t insize,
1636*ebfedea0SLionel Sambuc 			char *out, size_t outsize, const int armored)
1637*ebfedea0SLionel Sambuc {
1638*ebfedea0SLionel Sambuc 	pgp_memory_t	*mem;
1639*ebfedea0SLionel Sambuc 	pgp_io_t	*io;
1640*ebfedea0SLionel Sambuc 	unsigned	 realarmour;
1641*ebfedea0SLionel Sambuc 	unsigned	 sshkeys;
1642*ebfedea0SLionel Sambuc 	size_t		 m;
1643*ebfedea0SLionel Sambuc 	char		*numtries;
1644*ebfedea0SLionel Sambuc 	int            	 attempts;
1645*ebfedea0SLionel Sambuc 
1646*ebfedea0SLionel Sambuc 	__PGP_USED(armored);
1647*ebfedea0SLionel Sambuc 	io = netpgp->io;
1648*ebfedea0SLionel Sambuc 	if (input == NULL) {
1649*ebfedea0SLionel Sambuc 		(void) fprintf(io->errs,
1650*ebfedea0SLionel Sambuc 			"netpgp_decrypt_memory: no memory\n");
1651*ebfedea0SLionel Sambuc 		return 0;
1652*ebfedea0SLionel Sambuc 	}
1653*ebfedea0SLionel Sambuc 	realarmour = isarmoured(io, NULL, input, ARMOR_HEAD);
1654*ebfedea0SLionel Sambuc 	sshkeys = (unsigned)(netpgp_getvar(netpgp, "ssh keys") != NULL);
1655*ebfedea0SLionel Sambuc 	if ((numtries = netpgp_getvar(netpgp, "numtries")) == NULL ||
1656*ebfedea0SLionel Sambuc 	    (attempts = atoi(numtries)) <= 0) {
1657*ebfedea0SLionel Sambuc 		attempts = MAX_PASSPHRASE_ATTEMPTS;
1658*ebfedea0SLionel Sambuc 	} else if (strcmp(numtries, "unlimited") == 0) {
1659*ebfedea0SLionel Sambuc 		attempts = INFINITE_ATTEMPTS;
1660*ebfedea0SLionel Sambuc 	}
1661*ebfedea0SLionel Sambuc 	mem = pgp_decrypt_buf(netpgp->io, input, insize, netpgp->secring,
1662*ebfedea0SLionel Sambuc 				netpgp->pubring,
1663*ebfedea0SLionel Sambuc 				realarmour, sshkeys,
1664*ebfedea0SLionel Sambuc 				netpgp->passfp,
1665*ebfedea0SLionel Sambuc 				attempts,
1666*ebfedea0SLionel Sambuc 				get_passphrase_cb);
1667*ebfedea0SLionel Sambuc 	if (mem == NULL) {
1668*ebfedea0SLionel Sambuc 		return -1;
1669*ebfedea0SLionel Sambuc 	}
1670*ebfedea0SLionel Sambuc 	m = MIN(pgp_mem_len(mem), outsize);
1671*ebfedea0SLionel Sambuc 	(void) memcpy(out, pgp_mem_data(mem), m);
1672*ebfedea0SLionel Sambuc 	pgp_memory_free(mem);
1673*ebfedea0SLionel Sambuc 	return (int)m;
1674*ebfedea0SLionel Sambuc }
1675*ebfedea0SLionel Sambuc 
1676*ebfedea0SLionel Sambuc /* wrappers for the ops_debug_level functions we added to openpgpsdk */
1677*ebfedea0SLionel Sambuc 
1678*ebfedea0SLionel Sambuc /* set the debugging level per filename */
1679*ebfedea0SLionel Sambuc int
netpgp_set_debug(const char * f)1680*ebfedea0SLionel Sambuc netpgp_set_debug(const char *f)
1681*ebfedea0SLionel Sambuc {
1682*ebfedea0SLionel Sambuc 	return pgp_set_debug_level(f);
1683*ebfedea0SLionel Sambuc }
1684*ebfedea0SLionel Sambuc 
1685*ebfedea0SLionel Sambuc /* get the debugging level per filename */
1686*ebfedea0SLionel Sambuc int
netpgp_get_debug(const char * f)1687*ebfedea0SLionel Sambuc netpgp_get_debug(const char *f)
1688*ebfedea0SLionel Sambuc {
1689*ebfedea0SLionel Sambuc 	return pgp_get_debug_level(f);
1690*ebfedea0SLionel Sambuc }
1691*ebfedea0SLionel Sambuc 
1692*ebfedea0SLionel Sambuc /* return the version for the library */
1693*ebfedea0SLionel Sambuc const char *
netpgp_get_info(const char * type)1694*ebfedea0SLionel Sambuc netpgp_get_info(const char *type)
1695*ebfedea0SLionel Sambuc {
1696*ebfedea0SLionel Sambuc 	return pgp_get_info(type);
1697*ebfedea0SLionel Sambuc }
1698*ebfedea0SLionel Sambuc 
1699*ebfedea0SLionel Sambuc /* list all the packets in a file */
1700*ebfedea0SLionel Sambuc int
netpgp_list_packets(netpgp_t * netpgp,char * f,int armor,char * pubringname)1701*ebfedea0SLionel Sambuc netpgp_list_packets(netpgp_t *netpgp, char *f, int armor, char *pubringname)
1702*ebfedea0SLionel Sambuc {
1703*ebfedea0SLionel Sambuc 	pgp_keyring_t	*keyring;
1704*ebfedea0SLionel Sambuc 	const unsigned	 noarmor = 0;
1705*ebfedea0SLionel Sambuc 	struct stat	 st;
1706*ebfedea0SLionel Sambuc 	pgp_io_t	*io;
1707*ebfedea0SLionel Sambuc 	char		 ringname[MAXPATHLEN];
1708*ebfedea0SLionel Sambuc 	char		*homedir;
1709*ebfedea0SLionel Sambuc 	int		 ret;
1710*ebfedea0SLionel Sambuc 
1711*ebfedea0SLionel Sambuc 	io = netpgp->io;
1712*ebfedea0SLionel Sambuc 	if (f == NULL) {
1713*ebfedea0SLionel Sambuc 		(void) fprintf(io->errs, "No file containing packets\n");
1714*ebfedea0SLionel Sambuc 		return 0;
1715*ebfedea0SLionel Sambuc 	}
1716*ebfedea0SLionel Sambuc 	if (stat(f, &st) < 0) {
1717*ebfedea0SLionel Sambuc 		(void) fprintf(io->errs, "No such file '%s'\n", f);
1718*ebfedea0SLionel Sambuc 		return 0;
1719*ebfedea0SLionel Sambuc 	}
1720*ebfedea0SLionel Sambuc 	homedir = netpgp_getvar(netpgp, "homedir");
1721*ebfedea0SLionel Sambuc 	if (pubringname == NULL) {
1722*ebfedea0SLionel Sambuc 		(void) snprintf(ringname, sizeof(ringname),
1723*ebfedea0SLionel Sambuc 				"%s/pubring.gpg", homedir);
1724*ebfedea0SLionel Sambuc 		pubringname = ringname;
1725*ebfedea0SLionel Sambuc 	}
1726*ebfedea0SLionel Sambuc 	if ((keyring = calloc(1, sizeof(*keyring))) == NULL) {
1727*ebfedea0SLionel Sambuc 		(void) fprintf(io->errs, "netpgp_list_packets: bad alloc\n");
1728*ebfedea0SLionel Sambuc 		return 0;
1729*ebfedea0SLionel Sambuc 	}
1730*ebfedea0SLionel Sambuc 	if (!pgp_keyring_fileread(keyring, noarmor, pubringname)) {
1731*ebfedea0SLionel Sambuc 		free(keyring);
1732*ebfedea0SLionel Sambuc 		(void) fprintf(io->errs, "Cannot read pub keyring %s\n",
1733*ebfedea0SLionel Sambuc 			pubringname);
1734*ebfedea0SLionel Sambuc 		return 0;
1735*ebfedea0SLionel Sambuc 	}
1736*ebfedea0SLionel Sambuc 	netpgp->pubring = keyring;
1737*ebfedea0SLionel Sambuc 	netpgp_setvar(netpgp, "pubring", pubringname);
1738*ebfedea0SLionel Sambuc 	ret = pgp_list_packets(io, f, (unsigned)armor,
1739*ebfedea0SLionel Sambuc 					netpgp->secring,
1740*ebfedea0SLionel Sambuc 					netpgp->pubring,
1741*ebfedea0SLionel Sambuc 					netpgp->passfp,
1742*ebfedea0SLionel Sambuc 					get_passphrase_cb);
1743*ebfedea0SLionel Sambuc 	free(keyring);
1744*ebfedea0SLionel Sambuc 	return ret;
1745*ebfedea0SLionel Sambuc }
1746*ebfedea0SLionel Sambuc 
1747*ebfedea0SLionel Sambuc /* set a variable */
1748*ebfedea0SLionel Sambuc int
netpgp_setvar(netpgp_t * netpgp,const char * name,const char * value)1749*ebfedea0SLionel Sambuc netpgp_setvar(netpgp_t *netpgp, const char *name, const char *value)
1750*ebfedea0SLionel Sambuc {
1751*ebfedea0SLionel Sambuc 	char	*newval;
1752*ebfedea0SLionel Sambuc 	int	 i;
1753*ebfedea0SLionel Sambuc 
1754*ebfedea0SLionel Sambuc 	/* protect against the case where 'value' is netpgp->value[i] */
1755*ebfedea0SLionel Sambuc 	newval = netpgp_strdup(value);
1756*ebfedea0SLionel Sambuc 	if ((i = findvar(netpgp, name)) < 0) {
1757*ebfedea0SLionel Sambuc 		/* add the element to the array */
1758*ebfedea0SLionel Sambuc 		if (size_arrays(netpgp, netpgp->size + 15)) {
1759*ebfedea0SLionel Sambuc 			netpgp->name[i = netpgp->c++] = netpgp_strdup(name);
1760*ebfedea0SLionel Sambuc 		}
1761*ebfedea0SLionel Sambuc 	} else {
1762*ebfedea0SLionel Sambuc 		/* replace the element in the array */
1763*ebfedea0SLionel Sambuc 		if (netpgp->value[i]) {
1764*ebfedea0SLionel Sambuc 			free(netpgp->value[i]);
1765*ebfedea0SLionel Sambuc 			netpgp->value[i] = NULL;
1766*ebfedea0SLionel Sambuc 		}
1767*ebfedea0SLionel Sambuc 	}
1768*ebfedea0SLionel Sambuc 	/* sanity checks for range of values */
1769*ebfedea0SLionel Sambuc 	if (strcmp(name, "hash") == 0 || strcmp(name, "algorithm") == 0) {
1770*ebfedea0SLionel Sambuc 		if (pgp_str_to_hash_alg(newval) == PGP_HASH_UNKNOWN) {
1771*ebfedea0SLionel Sambuc 			free(newval);
1772*ebfedea0SLionel Sambuc 			return 0;
1773*ebfedea0SLionel Sambuc 		}
1774*ebfedea0SLionel Sambuc 	}
1775*ebfedea0SLionel Sambuc 	netpgp->value[i] = newval;
1776*ebfedea0SLionel Sambuc 	return 1;
1777*ebfedea0SLionel Sambuc }
1778*ebfedea0SLionel Sambuc 
1779*ebfedea0SLionel Sambuc /* unset a variable */
1780*ebfedea0SLionel Sambuc int
netpgp_unsetvar(netpgp_t * netpgp,const char * name)1781*ebfedea0SLionel Sambuc netpgp_unsetvar(netpgp_t *netpgp, const char *name)
1782*ebfedea0SLionel Sambuc {
1783*ebfedea0SLionel Sambuc 	int	i;
1784*ebfedea0SLionel Sambuc 
1785*ebfedea0SLionel Sambuc 	if ((i = findvar(netpgp, name)) >= 0) {
1786*ebfedea0SLionel Sambuc 		if (netpgp->value[i]) {
1787*ebfedea0SLionel Sambuc 			free(netpgp->value[i]);
1788*ebfedea0SLionel Sambuc 			netpgp->value[i] = NULL;
1789*ebfedea0SLionel Sambuc 		}
1790*ebfedea0SLionel Sambuc 		netpgp->value[i] = NULL;
1791*ebfedea0SLionel Sambuc 		return 1;
1792*ebfedea0SLionel Sambuc 	}
1793*ebfedea0SLionel Sambuc 	return 0;
1794*ebfedea0SLionel Sambuc }
1795*ebfedea0SLionel Sambuc 
1796*ebfedea0SLionel Sambuc /* get a variable's value (NULL if not set) */
1797*ebfedea0SLionel Sambuc char *
netpgp_getvar(netpgp_t * netpgp,const char * name)1798*ebfedea0SLionel Sambuc netpgp_getvar(netpgp_t *netpgp, const char *name)
1799*ebfedea0SLionel Sambuc {
1800*ebfedea0SLionel Sambuc 	int	i;
1801*ebfedea0SLionel Sambuc 
1802*ebfedea0SLionel Sambuc 	return ((i = findvar(netpgp, name)) < 0) ? NULL : netpgp->value[i];
1803*ebfedea0SLionel Sambuc }
1804*ebfedea0SLionel Sambuc 
1805*ebfedea0SLionel Sambuc /* increment a value */
1806*ebfedea0SLionel Sambuc int
netpgp_incvar(netpgp_t * netpgp,const char * name,const int delta)1807*ebfedea0SLionel Sambuc netpgp_incvar(netpgp_t *netpgp, const char *name, const int delta)
1808*ebfedea0SLionel Sambuc {
1809*ebfedea0SLionel Sambuc 	char	*cp;
1810*ebfedea0SLionel Sambuc 	char	 num[16];
1811*ebfedea0SLionel Sambuc 	int	 val;
1812*ebfedea0SLionel Sambuc 
1813*ebfedea0SLionel Sambuc 	val = 0;
1814*ebfedea0SLionel Sambuc 	if ((cp = netpgp_getvar(netpgp, name)) != NULL) {
1815*ebfedea0SLionel Sambuc 		val = atoi(cp);
1816*ebfedea0SLionel Sambuc 	}
1817*ebfedea0SLionel Sambuc 	(void) snprintf(num, sizeof(num), "%d", val + delta);
1818*ebfedea0SLionel Sambuc 	netpgp_setvar(netpgp, name, num);
1819*ebfedea0SLionel Sambuc 	return 1;
1820*ebfedea0SLionel Sambuc }
1821*ebfedea0SLionel Sambuc 
1822*ebfedea0SLionel Sambuc /* set the home directory value to "home/subdir" */
1823*ebfedea0SLionel Sambuc int
netpgp_set_homedir(netpgp_t * netpgp,char * home,const char * subdir,const int quiet)1824*ebfedea0SLionel Sambuc netpgp_set_homedir(netpgp_t *netpgp, char *home, const char *subdir, const int quiet)
1825*ebfedea0SLionel Sambuc {
1826*ebfedea0SLionel Sambuc 	struct stat	st;
1827*ebfedea0SLionel Sambuc 	char		d[MAXPATHLEN];
1828*ebfedea0SLionel Sambuc 
1829*ebfedea0SLionel Sambuc 	if (home == NULL) {
1830*ebfedea0SLionel Sambuc 		if (!quiet) {
1831*ebfedea0SLionel Sambuc 			(void) fprintf(stderr, "NULL HOME directory\n");
1832*ebfedea0SLionel Sambuc 		}
1833*ebfedea0SLionel Sambuc 		return 0;
1834*ebfedea0SLionel Sambuc 	}
1835*ebfedea0SLionel Sambuc 	(void) snprintf(d, sizeof(d), "%s%s", home, (subdir) ? subdir : "");
1836*ebfedea0SLionel Sambuc 	if (stat(d, &st) == 0) {
1837*ebfedea0SLionel Sambuc 		if ((st.st_mode & S_IFMT) == S_IFDIR) {
1838*ebfedea0SLionel Sambuc 			netpgp_setvar(netpgp, "homedir", d);
1839*ebfedea0SLionel Sambuc 			return 1;
1840*ebfedea0SLionel Sambuc 		}
1841*ebfedea0SLionel Sambuc 		(void) fprintf(stderr, "netpgp: homedir \"%s\" is not a dir\n",
1842*ebfedea0SLionel Sambuc 					d);
1843*ebfedea0SLionel Sambuc 		return 0;
1844*ebfedea0SLionel Sambuc 	}
1845*ebfedea0SLionel Sambuc 	if (!quiet) {
1846*ebfedea0SLionel Sambuc 		(void) fprintf(stderr,
1847*ebfedea0SLionel Sambuc 			"netpgp: warning homedir \"%s\" not found\n", d);
1848*ebfedea0SLionel Sambuc 	}
1849*ebfedea0SLionel Sambuc 	netpgp_setvar(netpgp, "homedir", d);
1850*ebfedea0SLionel Sambuc 	return 1;
1851*ebfedea0SLionel Sambuc }
1852*ebfedea0SLionel Sambuc 
1853*ebfedea0SLionel Sambuc /* validate all sigs in the pub keyring */
1854*ebfedea0SLionel Sambuc int
netpgp_validate_sigs(netpgp_t * netpgp)1855*ebfedea0SLionel Sambuc netpgp_validate_sigs(netpgp_t *netpgp)
1856*ebfedea0SLionel Sambuc {
1857*ebfedea0SLionel Sambuc 	pgp_validation_t	result;
1858*ebfedea0SLionel Sambuc 
1859*ebfedea0SLionel Sambuc 	return (int)pgp_validate_all_sigs(&result, netpgp->pubring, NULL);
1860*ebfedea0SLionel Sambuc }
1861*ebfedea0SLionel Sambuc 
1862*ebfedea0SLionel Sambuc /* print the json out on 'fp' */
1863*ebfedea0SLionel Sambuc int
netpgp_format_json(void * vp,const char * json,const int psigs)1864*ebfedea0SLionel Sambuc netpgp_format_json(void *vp, const char *json, const int psigs)
1865*ebfedea0SLionel Sambuc {
1866*ebfedea0SLionel Sambuc 	mj_t	 ids;
1867*ebfedea0SLionel Sambuc 	FILE	*fp;
1868*ebfedea0SLionel Sambuc 	int	 from;
1869*ebfedea0SLionel Sambuc 	int	 idc;
1870*ebfedea0SLionel Sambuc 	int	 tok;
1871*ebfedea0SLionel Sambuc 	int	 to;
1872*ebfedea0SLionel Sambuc 	int	 i;
1873*ebfedea0SLionel Sambuc 
1874*ebfedea0SLionel Sambuc 	if ((fp = (FILE *)vp) == NULL || json == NULL) {
1875*ebfedea0SLionel Sambuc 		return 0;
1876*ebfedea0SLionel Sambuc 	}
1877*ebfedea0SLionel Sambuc 	/* ids is an array of strings, each containing 1 entry */
1878*ebfedea0SLionel Sambuc 	(void) memset(&ids, 0x0, sizeof(ids));
1879*ebfedea0SLionel Sambuc 	from = to = tok = 0;
1880*ebfedea0SLionel Sambuc 	/* convert from string into an mj structure */
1881*ebfedea0SLionel Sambuc 	(void) mj_parse(&ids, json, &from, &to, &tok);
1882*ebfedea0SLionel Sambuc 	if ((idc = mj_arraycount(&ids)) == 1 && strchr(json, '{') == NULL) {
1883*ebfedea0SLionel Sambuc 		idc = 0;
1884*ebfedea0SLionel Sambuc 	}
1885*ebfedea0SLionel Sambuc 	(void) fprintf(fp, "%d key%s found\n", idc, (idc == 1) ? "" : "s");
1886*ebfedea0SLionel Sambuc 	for (i = 0 ; i < idc ; i++) {
1887*ebfedea0SLionel Sambuc 		format_json_key(fp, &ids.value.v[i], psigs);
1888*ebfedea0SLionel Sambuc 	}
1889*ebfedea0SLionel Sambuc 	/* clean up */
1890*ebfedea0SLionel Sambuc 	mj_delete(&ids);
1891*ebfedea0SLionel Sambuc 	return idc;
1892*ebfedea0SLionel Sambuc }
1893*ebfedea0SLionel Sambuc 
1894*ebfedea0SLionel Sambuc /* find a key in keyring, and write it in ssh format */
1895*ebfedea0SLionel Sambuc int
netpgp_write_sshkey(netpgp_t * netpgp,char * s,const char * userid,char * out,size_t size)1896*ebfedea0SLionel Sambuc netpgp_write_sshkey(netpgp_t *netpgp, char *s, const char *userid, char *out, size_t size)
1897*ebfedea0SLionel Sambuc {
1898*ebfedea0SLionel Sambuc 	const pgp_key_t	*key;
1899*ebfedea0SLionel Sambuc 	pgp_keyring_t	*keyring;
1900*ebfedea0SLionel Sambuc 	pgp_io_t	*io;
1901*ebfedea0SLionel Sambuc 	unsigned	 k;
1902*ebfedea0SLionel Sambuc 	size_t		 cc;
1903*ebfedea0SLionel Sambuc 	char		 f[MAXPATHLEN];
1904*ebfedea0SLionel Sambuc 
1905*ebfedea0SLionel Sambuc 	keyring = NULL;
1906*ebfedea0SLionel Sambuc 	io = NULL;
1907*ebfedea0SLionel Sambuc 	cc = 0;
1908*ebfedea0SLionel Sambuc 	if ((io = calloc(1, sizeof(pgp_io_t))) == NULL) {
1909*ebfedea0SLionel Sambuc 		(void) fprintf(stderr, "netpgp_save_sshpub: bad alloc 1\n");
1910*ebfedea0SLionel Sambuc 		goto done;
1911*ebfedea0SLionel Sambuc 	}
1912*ebfedea0SLionel Sambuc 	io->outs = stdout;
1913*ebfedea0SLionel Sambuc 	io->errs = stderr;
1914*ebfedea0SLionel Sambuc 	io->res = stderr;
1915*ebfedea0SLionel Sambuc 	netpgp->io = io;
1916*ebfedea0SLionel Sambuc 	/* write new to temp file */
1917*ebfedea0SLionel Sambuc 	savepubkey(s, f, sizeof(f));
1918*ebfedea0SLionel Sambuc 	if ((keyring = calloc(1, sizeof(*keyring))) == NULL) {
1919*ebfedea0SLionel Sambuc 		(void) fprintf(stderr, "netpgp_save_sshpub: bad alloc 2\n");
1920*ebfedea0SLionel Sambuc 		goto done;
1921*ebfedea0SLionel Sambuc 	}
1922*ebfedea0SLionel Sambuc 	if (!pgp_keyring_fileread(netpgp->pubring = keyring, 1, f)) {
1923*ebfedea0SLionel Sambuc 		(void) fprintf(stderr, "can't import key\n");
1924*ebfedea0SLionel Sambuc 		goto done;
1925*ebfedea0SLionel Sambuc 	}
1926*ebfedea0SLionel Sambuc 	/* get rsa key */
1927*ebfedea0SLionel Sambuc 	k = 0;
1928*ebfedea0SLionel Sambuc 	key = pgp_getnextkeybyname(netpgp->io, netpgp->pubring, userid, &k);
1929*ebfedea0SLionel Sambuc 	if (key == NULL) {
1930*ebfedea0SLionel Sambuc 		(void) fprintf(stderr, "no key found for '%s'\n", userid);
1931*ebfedea0SLionel Sambuc 		goto done;
1932*ebfedea0SLionel Sambuc 	}
1933*ebfedea0SLionel Sambuc 	if (key->key.pubkey.alg != PGP_PKA_RSA) {
1934*ebfedea0SLionel Sambuc 		/* we're not interested in supporting DSA either :-) */
1935*ebfedea0SLionel Sambuc 		(void) fprintf(stderr, "key not RSA '%s'\n", userid);
1936*ebfedea0SLionel Sambuc 		goto done;
1937*ebfedea0SLionel Sambuc 	}
1938*ebfedea0SLionel Sambuc 	/* XXX - check trust sigs */
1939*ebfedea0SLionel Sambuc 	/* XXX - check expiry */
1940*ebfedea0SLionel Sambuc 	/* XXX - check start */
1941*ebfedea0SLionel Sambuc 	/* XXX - check not weak key */
1942*ebfedea0SLionel Sambuc 	/* get rsa e and n */
1943*ebfedea0SLionel Sambuc 	(void) memset(out, 0x0, size);
1944*ebfedea0SLionel Sambuc 	cc = formatstring((char *)out, (const uint8_t *)"ssh-rsa", 7);
1945*ebfedea0SLionel Sambuc 	cc += formatbignum((char *)&out[cc], key->key.pubkey.key.rsa.e);
1946*ebfedea0SLionel Sambuc 	cc += formatbignum((char *)&out[cc], key->key.pubkey.key.rsa.n);
1947*ebfedea0SLionel Sambuc done:
1948*ebfedea0SLionel Sambuc 	if (io) {
1949*ebfedea0SLionel Sambuc 		free(io);
1950*ebfedea0SLionel Sambuc 	}
1951*ebfedea0SLionel Sambuc 	if (keyring) {
1952*ebfedea0SLionel Sambuc 		free(keyring);
1953*ebfedea0SLionel Sambuc 	}
1954*ebfedea0SLionel Sambuc 	return (int)cc;
1955*ebfedea0SLionel Sambuc }
1956