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