netpgp.c revision 1.88
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.88 2011/01/01 23:00:24 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 = (int64_t)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 = (int64_t)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),
629					(time_t)strtoll(sub->value.v[3].value.s, NULL, 10)),
630				"\n", NULL);
631		} else if (strcmp(obj->value.v[i].value.s, "sig") == 0) {
632			sub = &obj->value.v[i + 1];
633			p(fp, "sig", NULL);
634			pobj(fp, &sub->value.v[0], 8);	/* size */
635			p(fp, "  ", ptimestr(tbuf, sizeof(tbuf),
636					(time_t)strtoll(sub->value.v[1].value.s, NULL, 10)),
637				" ", NULL); /* time */
638			pobj(fp, &sub->value.v[2], 0); /* human name */
639			p(fp, "\n", NULL);
640		} else {
641			fprintf(stderr, "weird '%s'\n", obj->value.v[i].value.s);
642			pobj(fp, &obj->value.v[i], 0); /* human name */
643		}
644	}
645	p(fp, "\n", NULL);
646}
647
648/* save a pgp pubkey to a temp file */
649static int
650savepubkey(char *res, char *f, size_t size)
651{
652	size_t	len;
653	int	cc;
654	int	wc;
655	int	fd;
656
657	(void) snprintf(f, size, "/tmp/pgp2ssh.XXXXXXX");
658	if ((fd = mkstemp(f)) < 0) {
659		(void) fprintf(stderr, "can't create temp file '%s'\n", f);
660		return 0;
661	}
662	len = strlen(res);
663	for (cc = 0 ; (wc = (int)write(fd, &res[cc], len - (size_t)cc)) > 0 ; cc += wc) {
664	}
665	(void) close(fd);
666	return 1;
667}
668
669/* format a uint32_t */
670static int
671formatu32(uint8_t *buffer, uint32_t value)
672{
673	buffer[0] = (uint8_t)(value >> 24) & 0xff;
674	buffer[1] = (uint8_t)(value >> 16) & 0xff;
675	buffer[2] = (uint8_t)(value >> 8) & 0xff;
676	buffer[3] = (uint8_t)value & 0xff;
677	return sizeof(uint32_t);
678}
679
680/* format a string as (len, string) */
681static int
682formatstring(char *buffer, const uint8_t *s, size_t len)
683{
684	int	cc;
685
686	cc = formatu32((uint8_t *)buffer, (uint32_t)len);
687	(void) memcpy(&buffer[cc], s, len);
688	return cc + (int)len;
689}
690
691/* format a bignum, checking for "interesting" high bit values */
692static int
693formatbignum(char *buffer, BIGNUM *bn)
694{
695	size_t	 len;
696	uint8_t	*cp;
697	int	 cc;
698
699	len = (size_t) BN_num_bytes(bn);
700	if ((cp = calloc(1, len + 1)) == NULL) {
701		(void) fprintf(stderr, "calloc failure in formatbignum\n");
702		return 0;
703	}
704	(void) BN_bn2bin(bn, cp + 1);
705	cp[0] = 0x0;
706	cc = (cp[1] & 0x80) ? formatstring(buffer, cp, len + 1) : formatstring(buffer, &cp[1], len);
707	free(cp);
708	return cc;
709}
710
711#define MAX_PASSPHRASE_ATTEMPTS	3
712#define INFINITE_ATTEMPTS	-1
713
714/* get the passphrase from the user */
715static int
716find_passphrase(FILE *passfp, const char *id, char *passphrase, size_t size, int attempts)
717{
718	char	 prompt[BUFSIZ];
719	char	 buf[128];
720	char	*cp;
721	int	 cc;
722	int	 i;
723
724	if (passfp) {
725		if (fgets(passphrase, (int)size, passfp) == NULL) {
726			return 0;
727		}
728		return (int)strlen(passphrase);
729	}
730	for (i = 0 ; i < attempts ; i++) {
731		(void) snprintf(prompt, sizeof(prompt), "Enter passphrase for %.16s: ", id);
732		if ((cp = getpass(prompt)) == NULL) {
733			break;
734		}
735		cc = snprintf(buf, sizeof(buf), "%s", cp);
736		(void) snprintf(prompt, sizeof(prompt), "Repeat passphrase for %.16s: ", id);
737		if ((cp = getpass(prompt)) == NULL) {
738			break;
739		}
740		cc = snprintf(passphrase, size, "%s", cp);
741		if (strcmp(buf, passphrase) == 0) {
742			(void) memset(buf, 0x0, sizeof(buf));
743			return cc;
744		}
745	}
746	(void) memset(buf, 0x0, sizeof(buf));
747	(void) memset(passphrase, 0x0, size);
748	return 0;
749}
750
751/***************************************************************************/
752/* exported functions start here */
753/***************************************************************************/
754
755/* initialise a netpgp_t structure */
756int
757netpgp_init(netpgp_t *netpgp)
758{
759	pgp_io_t	*io;
760	time_t		 t;
761	char		 id[MAX_ID_LENGTH];
762	char		*homedir;
763	char		*userid;
764	char		*stream;
765	char		*passfd;
766	char		*results;
767	int		 coredumps;
768	int		 last;
769
770#ifdef HAVE_SYS_RESOURCE_H
771	struct rlimit	limit;
772
773	coredumps = netpgp_getvar(netpgp, "coredumps") != NULL;
774	if (!coredumps) {
775		(void) memset(&limit, 0x0, sizeof(limit));
776		if (setrlimit(RLIMIT_CORE, &limit) != 0) {
777			(void) fprintf(stderr,
778			"netpgp: warning - can't turn off core dumps\n");
779			coredumps = 1;
780		}
781	}
782#else
783	coredumps = 1;
784#endif
785	if ((io = calloc(1, sizeof(*io))) == NULL) {
786		(void) fprintf(stderr, "netpgp_init: bad alloc\n");
787		return 0;
788	}
789	io->outs = stdout;
790	if ((stream = netpgp_getvar(netpgp, "outs")) != NULL &&
791	    strcmp(stream, "<stderr>") == 0) {
792		io->outs = stderr;
793	}
794	io->errs = stderr;
795	if ((stream = netpgp_getvar(netpgp, "errs")) != NULL &&
796	    strcmp(stream, "<stdout>") == 0) {
797		io->errs = stdout;
798	}
799	if ((results = netpgp_getvar(netpgp, "res")) == NULL) {
800		io->res = io->errs;
801	} else if (strcmp(results, "<stdout>") == 0) {
802		io->res = stdout;
803	} else if (strcmp(results, "<stderr>") == 0) {
804		io->res = stderr;
805	} else {
806		if ((io->res = fopen(results, "w")) == NULL) {
807			(void) fprintf(io->errs, "Can't open results %s for writing\n",
808				results);
809			free(io);
810			return 0;
811		}
812	}
813	netpgp->io = io;
814	if ((passfd = netpgp_getvar(netpgp, "pass-fd")) != NULL &&
815	    (netpgp->passfp = fdopen(atoi(passfd), "r")) == NULL) {
816		(void) fprintf(io->errs, "Can't open fd %s for reading\n",
817			passfd);
818		return 0;
819	}
820	if (coredumps) {
821		(void) fprintf(io->errs,
822			"netpgp: warning: core dumps enabled\n");
823	}
824	if ((homedir = netpgp_getvar(netpgp, "homedir")) == NULL) {
825		(void) fprintf(io->errs, "netpgp: bad homedir\n");
826		return 0;
827	}
828	/* read from either gpg files or ssh keys */
829	if (netpgp_getvar(netpgp, "ssh keys") == NULL) {
830		if ((userid = netpgp_getvar(netpgp, "userid")) == NULL) {
831			(void) memset(id, 0x0, sizeof(id));
832			(void) conffile(netpgp, homedir, id, sizeof(id));
833			if (id[0] != 0x0) {
834				netpgp_setvar(netpgp, "userid", userid = id);
835			}
836		}
837		if (userid == NULL) {
838			if (netpgp_getvar(netpgp, "need userid") != NULL) {
839				(void) fprintf(io->errs,
840						"Cannot find user id\n");
841				return 0;
842			}
843		} else {
844			(void) netpgp_setvar(netpgp, "userid", userid);
845		}
846		netpgp->pubring = readkeyring(netpgp, "pubring");
847		if (netpgp->pubring == NULL) {
848			(void) fprintf(io->errs, "Can't read pub keyring\n");
849			return 0;
850		}
851		netpgp->secring = readkeyring(netpgp, "secring");
852		if (netpgp->secring == NULL) {
853			(void) fprintf(io->errs, "Can't read sec keyring\n");
854			return 0;
855		}
856	} else {
857		last = (netpgp->pubring != NULL);
858		if (!readsshkeys(netpgp, homedir, netpgp_getvar(netpgp, "need seckey"))) {
859			(void) fprintf(io->errs, "Can't read ssh keys\n");
860			return 0;
861		}
862		if ((userid = netpgp_getvar(netpgp, "userid")) == NULL) {
863			set_first_pubring(netpgp->pubring, id, sizeof(id), last);
864			netpgp_setvar(netpgp, "userid", userid = id);
865		}
866		if (userid == NULL) {
867			if (netpgp_getvar(netpgp, "need userid") != NULL) {
868				(void) fprintf(io->errs,
869						"Cannot find user id\n");
870				return 0;
871			}
872		} else {
873			(void) netpgp_setvar(netpgp, "userid", userid);
874		}
875	}
876	t = time(NULL);
877	netpgp_setvar(netpgp, "initialised", ctime(&t));
878	return 1;
879}
880
881/* finish off with the netpgp_t struct */
882int
883netpgp_end(netpgp_t *netpgp)
884{
885	unsigned	i;
886
887	for (i = 0 ; i < netpgp->c ; i++) {
888		if (netpgp->name[i] != NULL) {
889			free(netpgp->name[i]);
890		}
891		if (netpgp->value[i] != NULL) {
892			free(netpgp->value[i]);
893		}
894	}
895	if (netpgp->name != NULL) {
896		free(netpgp->name);
897	}
898	if (netpgp->value != NULL) {
899		free(netpgp->value);
900	}
901	if (netpgp->pubring != NULL) {
902		pgp_keyring_free(netpgp->pubring);
903	}
904	if (netpgp->secring != NULL) {
905		pgp_keyring_free(netpgp->secring);
906	}
907	free(netpgp->io);
908	return 1;
909}
910
911/* list the keys in a keyring */
912int
913netpgp_list_keys(netpgp_t *netpgp, const int psigs)
914{
915	if (netpgp->pubring == NULL) {
916		(void) fprintf(stderr, "No keyring\n");
917		return 0;
918	}
919	return pgp_keyring_list(netpgp->io, netpgp->pubring, psigs);
920}
921
922/* list the keys in a keyring, returning a JSON string */
923int
924netpgp_list_keys_json(netpgp_t *netpgp, char **json, const int psigs)
925{
926	mj_t	obj;
927	int	ret;
928
929	if (netpgp->pubring == NULL) {
930		(void) fprintf(stderr, "No keyring\n");
931		return 0;
932	}
933	(void) memset(&obj, 0x0, sizeof(obj));
934	if (!pgp_keyring_json(netpgp->io, netpgp->pubring, &obj, psigs)) {
935		(void) fprintf(stderr, "No keys in keyring\n");
936		return 0;
937	}
938	ret = mj_asprint(json, &obj);
939	mj_delete(&obj);
940	return ret;
941}
942
943DEFINE_ARRAY(strings_t, char *);
944
945#ifndef HKP_VERSION
946#define HKP_VERSION	1
947#endif
948
949/* find and list some keys in a keyring */
950int
951netpgp_match_keys(netpgp_t *netpgp, char *name, const char *fmt, void *vp, const int psigs)
952{
953	const pgp_key_t	*key;
954	unsigned		 k;
955	strings_t		 pubs;
956	FILE			*fp = (FILE *)vp;
957
958	if (name[0] == '0' && name[1] == 'x') {
959		name += 2;
960	}
961	(void) memset(&pubs, 0x0, sizeof(pubs));
962	k = 0;
963	do {
964		key = pgp_getnextkeybyname(netpgp->io, netpgp->pubring,
965						name, &k);
966		if (key != NULL) {
967			ALLOC(char *, pubs.v, pubs.size, pubs.c, 10, 10,
968					"netpgp_match_keys", return 0);
969			if (strcmp(fmt, "mr") == 0) {
970				pgp_hkp_sprint_keydata(netpgp->io, netpgp->pubring,
971						key, &pubs.v[pubs.c],
972						&key->key.pubkey, psigs);
973			} else {
974				pgp_sprint_keydata(netpgp->io, netpgp->pubring,
975						key, &pubs.v[pubs.c],
976						"signature ",
977						&key->key.pubkey, psigs);
978			}
979			if (pubs.v[pubs.c] != NULL) {
980				pubs.c += 1;
981			}
982			k += 1;
983		}
984	} while (key != NULL);
985	if (strcmp(fmt, "mr") == 0) {
986		(void) fprintf(fp, "info:%d:%d\n", HKP_VERSION, pubs.c);
987	} else {
988		(void) fprintf(fp, "%d key%s found\n", pubs.c,
989			(pubs.c == 1) ? "" : "s");
990	}
991	for (k = 0 ; k < pubs.c ; k++) {
992		(void) fprintf(fp, "%s%s", pubs.v[k], (k < pubs.c - 1) ? "\n" : "");
993		free(pubs.v[k]);
994	}
995	free(pubs.v);
996	return pubs.c;
997}
998
999/* find and list some keys in a keyring - return JSON string */
1000int
1001netpgp_match_keys_json(netpgp_t *netpgp, char **json, char *name, const char *fmt, const int psigs)
1002{
1003	const pgp_key_t	*key;
1004	unsigned		 k;
1005	mj_t			 id_array;
1006	int			 ret;
1007
1008	if (name[0] == '0' && name[1] == 'x') {
1009		name += 2;
1010	}
1011	(void) memset(&id_array, 0x0, sizeof(id_array));
1012	k = 0;
1013	*json = NULL;
1014	mj_create(&id_array, "array");
1015	do {
1016		key = pgp_getnextkeybyname(netpgp->io, netpgp->pubring,
1017						name, &k);
1018		if (key != NULL) {
1019			if (strcmp(fmt, "mr") == 0) {
1020#if 0
1021				pgp_hkp_sprint_keydata(netpgp->io, netpgp->pubring,
1022						key, &pubs.v[pubs.c],
1023						&key->key.pubkey, psigs);
1024#endif
1025			} else {
1026				ALLOC(mj_t, id_array.value.v, id_array.size,
1027					id_array.c, 10, 10, "netpgp_match_keys_json", return 0);
1028				pgp_sprint_mj(netpgp->io, netpgp->pubring,
1029						key, &id_array.value.v[id_array.c++],
1030						"signature ",
1031						&key->key.pubkey, psigs);
1032			}
1033			k += 1;
1034		}
1035	} while (key != NULL);
1036	ret = mj_asprint(json, &id_array);
1037	mj_delete(&id_array);
1038	return ret;
1039}
1040
1041/* find and list some public keys in a keyring */
1042int
1043netpgp_match_pubkeys(netpgp_t *netpgp, char *name, void *vp)
1044{
1045	const pgp_key_t	*key;
1046	unsigned		 k;
1047	strings_t		 pubs;
1048	FILE			*fp = (FILE *)vp;
1049
1050	(void) memset(&pubs, 0x0, sizeof(pubs));
1051	do {
1052		key = pgp_getnextkeybyname(netpgp->io, netpgp->pubring,
1053						name, &k);
1054		if (key != NULL) {
1055			char	out[1024 * 64];
1056
1057			ALLOC(char *, pubs.v, pubs.size, pubs.c, 10, 10,
1058					"netpgp_match_pubkeys", return 0);
1059			(void) pgp_sprint_pubkey(key, out, sizeof(out));
1060			pubs.v[pubs.c++] = netpgp_strdup(out);
1061			k += 1;
1062		}
1063	} while (key != NULL);
1064	(void) fprintf(fp, "info:%d:%d\n", HKP_VERSION, pubs.c);
1065	for (k = 0 ; k < pubs.c ; k++) {
1066		(void) fprintf(fp, "%s", pubs.v[k]);
1067		free(pubs.v[k]);
1068	}
1069	free(pubs.v);
1070	return pubs.c;
1071}
1072
1073/* find a key in a keyring */
1074int
1075netpgp_find_key(netpgp_t *netpgp, char *id)
1076{
1077	pgp_io_t	*io;
1078
1079	io = netpgp->io;
1080	if (id == NULL) {
1081		(void) fprintf(io->errs, "NULL id to search for\n");
1082		return 0;
1083	}
1084	return pgp_getkeybyname(netpgp->io, netpgp->pubring, id) != NULL;
1085}
1086
1087/* get a key in a keyring */
1088char *
1089netpgp_get_key(netpgp_t *netpgp, const char *name, const char *fmt)
1090{
1091	const pgp_key_t	*key;
1092	char			*newkey;
1093
1094	if ((key = resolve_userid(netpgp, netpgp->pubring, name)) == NULL) {
1095		return NULL;
1096	}
1097	if (strcmp(fmt, "mr") == 0) {
1098		return (pgp_hkp_sprint_keydata(netpgp->io, netpgp->pubring,
1099				key, &newkey,
1100				&key->key.pubkey,
1101				netpgp_getvar(netpgp, "subkey sigs") != NULL) > 0) ? newkey : NULL;
1102	}
1103	return (pgp_sprint_keydata(netpgp->io, netpgp->pubring,
1104				key, &newkey, "signature",
1105				&key->key.pubkey,
1106				netpgp_getvar(netpgp, "subkey sigs") != NULL) > 0) ? newkey : NULL;
1107}
1108
1109/* export a given key */
1110char *
1111netpgp_export_key(netpgp_t *netpgp, char *name)
1112{
1113	const pgp_key_t	*key;
1114	pgp_io_t		*io;
1115
1116	io = netpgp->io;
1117	if ((key = resolve_userid(netpgp, netpgp->pubring, name)) == NULL) {
1118		return NULL;
1119	}
1120	return pgp_export_key(io, key, NULL);
1121}
1122
1123#define IMPORT_ARMOR_HEAD	"-----BEGIN PGP PUBLIC KEY BLOCK-----"
1124
1125/* import a key into our keyring */
1126int
1127netpgp_import_key(netpgp_t *netpgp, char *f)
1128{
1129	pgp_io_t	*io;
1130	unsigned	 realarmor;
1131	int		 done;
1132
1133	io = netpgp->io;
1134	realarmor = isarmoured(io, f, NULL, IMPORT_ARMOR_HEAD);
1135	done = pgp_keyring_fileread(netpgp->pubring, realarmor, f);
1136	if (!done) {
1137		(void) fprintf(io->errs, "Cannot import key from file %s\n", f);
1138		return 0;
1139	}
1140	return pgp_keyring_list(io, netpgp->pubring, 0);
1141}
1142
1143#define ID_OFFSET	38
1144
1145/* generate a new key */
1146int
1147netpgp_generate_key(netpgp_t *netpgp, char *id, int numbits)
1148{
1149	pgp_output_t		*create;
1150	const unsigned		 noarmor = 0;
1151	pgp_key_t		*key;
1152	pgp_io_t		*io;
1153	uint8_t			*uid;
1154	char			 passphrase[128];
1155	char			 newid[1024];
1156	char			 filename[MAXPATHLEN];
1157	char			 dir[MAXPATHLEN];
1158	char			*cp;
1159	char			*ringfile;
1160	char			*numtries;
1161	int             	 attempts;
1162	int             	 passc;
1163	int             	 fd;
1164	int             	 cc;
1165
1166	uid = NULL;
1167	io = netpgp->io;
1168	/* generate a new key */
1169	if (id) {
1170		(void) snprintf(newid, sizeof(newid), "%s", id);
1171	} else {
1172		(void) snprintf(newid, sizeof(newid),
1173			"RSA %d-bit key <%s@localhost>", numbits, getenv("LOGNAME"));
1174	}
1175	uid = (uint8_t *)newid;
1176	key = pgp_rsa_new_selfsign_key(numbits, 65537UL, uid,
1177			netpgp_getvar(netpgp, "hash"),
1178			netpgp_getvar(netpgp, "cipher"));
1179	if (key == NULL) {
1180		(void) fprintf(io->errs, "Cannot generate key\n");
1181		return 0;
1182	}
1183	cp = NULL;
1184	pgp_sprint_keydata(netpgp->io, NULL, key, &cp, "signature ", &key->key.seckey.pubkey, 0);
1185	(void) fprintf(stdout, "%s", cp);
1186	/* write public key */
1187	cc = snprintf(dir, sizeof(dir), "%s/%.16s", netpgp_getvar(netpgp, "homedir"), &cp[ID_OFFSET]);
1188	netpgp_setvar(netpgp, "generated userid", &dir[cc - 16]);
1189	if (mkdir(dir, 0700) < 0) {
1190		(void) fprintf(io->errs, "can't mkdir '%s'\n", dir);
1191		return 0;
1192	}
1193	(void) fprintf(io->errs, "netpgp: generated keys in directory %s\n", dir);
1194	(void) snprintf(ringfile = filename, sizeof(filename), "%s/pubring.gpg", dir);
1195	if (!appendkey(io, key, ringfile)) {
1196		(void) fprintf(io->errs, "Cannot write pubkey to '%s'\n", ringfile);
1197		return 0;
1198	}
1199	if (netpgp->pubring != NULL) {
1200		pgp_keyring_free(netpgp->pubring);
1201	}
1202	/* write secret key */
1203	(void) snprintf(ringfile = filename, sizeof(filename), "%s/secring.gpg", dir);
1204	if ((fd = pgp_setup_file_append(&create, ringfile)) < 0) {
1205		fd = pgp_setup_file_write(&create, ringfile, 0);
1206	}
1207	if (fd < 0) {
1208		(void) fprintf(io->errs, "can't append secring '%s'\n", ringfile);
1209		return 0;
1210	}
1211	/* get the passphrase */
1212	if ((numtries = netpgp_getvar(netpgp, "numtries")) == NULL ||
1213	    (attempts = atoi(numtries)) <= 0) {
1214		attempts = MAX_PASSPHRASE_ATTEMPTS;
1215	} else if (strcmp(numtries, "unlimited") == 0) {
1216		attempts = INFINITE_ATTEMPTS;
1217	}
1218	passc = find_passphrase(netpgp->passfp, &cp[ID_OFFSET], passphrase, sizeof(passphrase), attempts);
1219	if (!pgp_write_xfer_seckey(create, key, (uint8_t *)passphrase, (const unsigned)passc, noarmor)) {
1220		(void) fprintf(io->errs, "Cannot write seckey\n");
1221		return 0;
1222	}
1223	pgp_teardown_file_write(create, fd);
1224	if (netpgp->secring != NULL) {
1225		pgp_keyring_free(netpgp->secring);
1226	}
1227	pgp_keydata_free(key);
1228	free(cp);
1229	return 1;
1230}
1231
1232/* encrypt a file */
1233int
1234netpgp_encrypt_file(netpgp_t *netpgp,
1235			const char *userid,
1236			const char *f,
1237			char *out,
1238			int armored)
1239{
1240	const pgp_key_t	*key;
1241	const unsigned		 overwrite = 1;
1242	const char		*suffix;
1243	pgp_io_t		*io;
1244	char			 outname[MAXPATHLEN];
1245
1246	io = netpgp->io;
1247	if (f == NULL) {
1248		(void) fprintf(io->errs,
1249			"netpgp_encrypt_file: no filename specified\n");
1250		return 0;
1251	}
1252	suffix = (armored) ? ".asc" : ".gpg";
1253	/* get key with which to sign */
1254	if ((key = resolve_userid(netpgp, netpgp->pubring, userid)) == NULL) {
1255		return 0;
1256	}
1257	if (out == NULL) {
1258		(void) snprintf(outname, sizeof(outname), "%s%s", f, suffix);
1259		out = outname;
1260	}
1261	return (int)pgp_encrypt_file(io, f, out, key, (unsigned)armored,
1262				overwrite, netpgp_getvar(netpgp, "cipher"));
1263}
1264
1265#define ARMOR_HEAD	"-----BEGIN PGP MESSAGE-----"
1266
1267/* decrypt a file */
1268int
1269netpgp_decrypt_file(netpgp_t *netpgp, const char *f, char *out, int armored)
1270{
1271	const unsigned	 overwrite = 1;
1272	pgp_io_t	*io;
1273	unsigned	 realarmor;
1274	unsigned	 sshkeys;
1275	char		*numtries;
1276	int            	 attempts;
1277
1278	__PGP_USED(armored);
1279	io = netpgp->io;
1280	if (f == NULL) {
1281		(void) fprintf(io->errs,
1282			"netpgp_decrypt_file: no filename specified\n");
1283		return 0;
1284	}
1285	realarmor = isarmoured(io, f, NULL, ARMOR_HEAD);
1286	sshkeys = (unsigned)(netpgp_getvar(netpgp, "ssh keys") != NULL);
1287	if ((numtries = netpgp_getvar(netpgp, "numtries")) == NULL ||
1288	    (attempts = atoi(numtries)) <= 0) {
1289		attempts = MAX_PASSPHRASE_ATTEMPTS;
1290	} else if (strcmp(numtries, "unlimited") == 0) {
1291		attempts = INFINITE_ATTEMPTS;
1292	}
1293	return pgp_decrypt_file(netpgp->io, f, out, netpgp->secring,
1294				netpgp->pubring,
1295				realarmor, overwrite, sshkeys,
1296				netpgp->passfp, attempts, get_passphrase_cb);
1297}
1298
1299/* sign a file */
1300int
1301netpgp_sign_file(netpgp_t *netpgp,
1302		const char *userid,
1303		const char *f,
1304		char *out,
1305		int armored,
1306		int cleartext,
1307		int detached)
1308{
1309	const pgp_key_t		*keypair;
1310	const pgp_key_t		*pubkey;
1311	const unsigned		 overwrite = 1;
1312	pgp_seckey_t		*seckey;
1313	const char		*hashalg;
1314	pgp_io_t		*io;
1315	char			*numtries;
1316	int			 attempts;
1317	int			 ret;
1318	int			 i;
1319
1320	io = netpgp->io;
1321	if (f == NULL) {
1322		(void) fprintf(io->errs,
1323			"netpgp_sign_file: no filename specified\n");
1324		return 0;
1325	}
1326	/* get key with which to sign */
1327	if ((keypair = resolve_userid(netpgp, netpgp->secring, userid)) == NULL) {
1328		return 0;
1329	}
1330	ret = 1;
1331	if ((numtries = netpgp_getvar(netpgp, "numtries")) == NULL ||
1332	    (attempts = atoi(numtries)) <= 0) {
1333		attempts = MAX_PASSPHRASE_ATTEMPTS;
1334	} else if (strcmp(numtries, "unlimited") == 0) {
1335		attempts = INFINITE_ATTEMPTS;
1336	}
1337	for (i = 0, seckey = NULL ; !seckey && (i < attempts || attempts == INFINITE_ATTEMPTS) ; i++) {
1338		if (netpgp->passfp == NULL) {
1339			/* print out the user id */
1340			pubkey = pgp_getkeybyname(io, netpgp->pubring, userid);
1341			if (pubkey == NULL) {
1342				(void) fprintf(io->errs,
1343					"netpgp: warning - using pubkey from secring\n");
1344				pgp_print_keydata(io, netpgp->pubring, keypair, "signature ",
1345					&keypair->key.seckey.pubkey, 0);
1346			} else {
1347				pgp_print_keydata(io, netpgp->pubring, pubkey, "signature ",
1348					&pubkey->key.pubkey, 0);
1349			}
1350		}
1351		if (netpgp_getvar(netpgp, "ssh keys") == NULL) {
1352			/* now decrypt key */
1353			seckey = pgp_decrypt_seckey(keypair, netpgp->passfp);
1354			if (seckey == NULL) {
1355				(void) fprintf(io->errs, "Bad passphrase\n");
1356			}
1357		} else {
1358			pgp_keyring_t	*secring;
1359
1360			secring = netpgp->secring;
1361			seckey = &secring->keys[0].key.seckey;
1362		}
1363	}
1364	if (seckey == NULL) {
1365		(void) fprintf(io->errs, "Bad passphrase\n");
1366		return 0;
1367	}
1368	/* sign file */
1369	hashalg = netpgp_getvar(netpgp, "hash");
1370	if (seckey->pubkey.alg == PGP_PKA_DSA) {
1371		hashalg = "sha1";
1372	}
1373	if (detached) {
1374		ret = pgp_sign_detached(io, f, out, seckey, hashalg,
1375				get_birthtime(netpgp_getvar(netpgp, "birthtime")),
1376				get_duration(netpgp_getvar(netpgp, "duration")),
1377				(unsigned)armored,
1378				overwrite);
1379	} else {
1380		ret = pgp_sign_file(io, f, out, seckey, hashalg,
1381				get_birthtime(netpgp_getvar(netpgp, "birthtime")),
1382				get_duration(netpgp_getvar(netpgp, "duration")),
1383				(unsigned)armored, (unsigned)cleartext,
1384				overwrite);
1385	}
1386	pgp_forget(seckey, (unsigned)sizeof(*seckey));
1387	return ret;
1388}
1389
1390#define ARMOR_SIG_HEAD	"-----BEGIN PGP (SIGNATURE|SIGNED MESSAGE)-----"
1391
1392/* verify a file */
1393int
1394netpgp_verify_file(netpgp_t *netpgp, const char *in, const char *out, int armored)
1395{
1396	pgp_validation_t	 result;
1397	pgp_io_t		*io;
1398	unsigned		 realarmor;
1399
1400	__PGP_USED(armored);
1401	(void) memset(&result, 0x0, sizeof(result));
1402	io = netpgp->io;
1403	if (in == NULL) {
1404		(void) fprintf(io->errs,
1405			"netpgp_verify_file: no filename specified\n");
1406		return 0;
1407	}
1408	realarmor = isarmoured(io, in, NULL, ARMOR_SIG_HEAD);
1409	if (pgp_validate_file(io, &result, in, out, (const int)realarmor, netpgp->pubring)) {
1410		resultp(io, in, &result, netpgp->pubring);
1411		return 1;
1412	}
1413	if (result.validc + result.invalidc + result.unknownc == 0) {
1414		(void) fprintf(io->errs,
1415		"\"%s\": No signatures found - is this a signed file?\n",
1416			in);
1417	} else if (result.invalidc == 0 && result.unknownc == 0) {
1418		(void) fprintf(io->errs,
1419			"\"%s\": file verification failure: invalid signature time\n", in);
1420	} else {
1421		(void) fprintf(io->errs,
1422"\"%s\": verification failure: %u invalid signatures, %u unknown signatures\n",
1423			in, result.invalidc, result.unknownc);
1424	}
1425	return 0;
1426}
1427
1428/* sign some memory */
1429int
1430netpgp_sign_memory(netpgp_t *netpgp,
1431		const char *userid,
1432		char *mem,
1433		size_t size,
1434		char *out,
1435		size_t outsize,
1436		const unsigned armored,
1437		const unsigned cleartext)
1438{
1439	const pgp_key_t		*keypair;
1440	const pgp_key_t		*pubkey;
1441	pgp_seckey_t		*seckey;
1442	pgp_memory_t		*signedmem;
1443	const char		*hashalg;
1444	pgp_io_t		*io;
1445	char 			*numtries;
1446	int			 attempts;
1447	int			 ret;
1448	int			 i;
1449
1450	io = netpgp->io;
1451	if (mem == NULL) {
1452		(void) fprintf(io->errs,
1453			"netpgp_sign_memory: no memory to sign\n");
1454		return 0;
1455	}
1456	if ((keypair = resolve_userid(netpgp, netpgp->secring, userid)) == NULL) {
1457		return 0;
1458	}
1459	ret = 1;
1460	if ((numtries = netpgp_getvar(netpgp, "numtries")) == NULL ||
1461	    (attempts = atoi(numtries)) <= 0) {
1462		attempts = MAX_PASSPHRASE_ATTEMPTS;
1463	} else if (strcmp(numtries, "unlimited") == 0) {
1464		attempts = INFINITE_ATTEMPTS;
1465	}
1466	for (i = 0, seckey = NULL ; !seckey && (i < attempts || attempts == INFINITE_ATTEMPTS) ; i++) {
1467		if (netpgp->passfp == NULL) {
1468			/* print out the user id */
1469			pubkey = pgp_getkeybyname(io, netpgp->pubring, userid);
1470			if (pubkey == NULL) {
1471				(void) fprintf(io->errs,
1472					"netpgp: warning - using pubkey from secring\n");
1473				pgp_print_keydata(io, netpgp->pubring, keypair, "signature ",
1474					&keypair->key.seckey.pubkey, 0);
1475			} else {
1476				pgp_print_keydata(io, netpgp->pubring, pubkey, "signature ",
1477					&pubkey->key.pubkey, 0);
1478			}
1479		}
1480		/* now decrypt key */
1481		seckey = pgp_decrypt_seckey(keypair, netpgp->passfp);
1482		if (seckey == NULL) {
1483			(void) fprintf(io->errs, "Bad passphrase\n");
1484		}
1485	}
1486	if (seckey == NULL) {
1487		(void) fprintf(io->errs, "Bad passphrase\n");
1488		return 0;
1489	}
1490	/* sign file */
1491	(void) memset(out, 0x0, outsize);
1492	hashalg = netpgp_getvar(netpgp, "hash");
1493	if (seckey->pubkey.alg == PGP_PKA_DSA) {
1494		hashalg = "sha1";
1495	}
1496	signedmem = pgp_sign_buf(io, mem, size, seckey,
1497				get_birthtime(netpgp_getvar(netpgp, "birthtime")),
1498				get_duration(netpgp_getvar(netpgp, "duration")),
1499				hashalg, armored, cleartext);
1500	if (signedmem) {
1501		size_t	m;
1502
1503		m = MIN(pgp_mem_len(signedmem), outsize);
1504		(void) memcpy(out, pgp_mem_data(signedmem), m);
1505		pgp_memory_free(signedmem);
1506		ret = (int)m;
1507	} else {
1508		ret = 0;
1509	}
1510	pgp_forget(seckey, (unsigned)sizeof(*seckey));
1511	return ret;
1512}
1513
1514/* verify memory */
1515int
1516netpgp_verify_memory(netpgp_t *netpgp, const void *in, const size_t size,
1517			void *out, size_t outsize, const int armored)
1518{
1519	pgp_validation_t	 result;
1520	pgp_memory_t		*signedmem;
1521	pgp_memory_t		*cat;
1522	pgp_io_t		*io;
1523	size_t			 m;
1524	int			 ret;
1525
1526	(void) memset(&result, 0x0, sizeof(result));
1527	io = netpgp->io;
1528	if (in == NULL) {
1529		(void) fprintf(io->errs,
1530			"netpgp_verify_memory: no memory to verify\n");
1531		return 0;
1532	}
1533	signedmem = pgp_memory_new();
1534	pgp_memory_add(signedmem, in, size);
1535	if (out) {
1536		cat = pgp_memory_new();
1537	}
1538	ret = pgp_validate_mem(io, &result, signedmem,
1539				(out) ? &cat : NULL,
1540				armored, netpgp->pubring);
1541	pgp_memory_free(signedmem);
1542	if (ret) {
1543		resultp(io, "<stdin>", &result, netpgp->pubring);
1544		if (out) {
1545			m = MIN(pgp_mem_len(cat), outsize);
1546			(void) memcpy(out, pgp_mem_data(cat), m);
1547			pgp_memory_free(cat);
1548		} else {
1549			m = 1;
1550		}
1551		return (int)m;
1552	}
1553	if (result.validc + result.invalidc + result.unknownc == 0) {
1554		(void) fprintf(io->errs,
1555		"No signatures found - is this memory signed?\n");
1556	} else if (result.invalidc == 0 && result.unknownc == 0) {
1557		(void) fprintf(io->errs,
1558			"memory verification failure: invalid signature time\n");
1559	} else {
1560		(void) fprintf(io->errs,
1561"memory verification failure: %u invalid signatures, %u unknown signatures\n",
1562			result.invalidc, result.unknownc);
1563	}
1564	return 0;
1565}
1566
1567/* encrypt some memory */
1568int
1569netpgp_encrypt_memory(netpgp_t *netpgp,
1570			const char *userid,
1571			void *in,
1572			const size_t insize,
1573			char *out,
1574			size_t outsize,
1575			int armored)
1576{
1577	const pgp_key_t	*keypair;
1578	pgp_memory_t		*enc;
1579	pgp_io_t		*io;
1580	size_t			 m;
1581
1582	io = netpgp->io;
1583	if (in == NULL) {
1584		(void) fprintf(io->errs,
1585			"netpgp_encrypt_buf: no memory to encrypt\n");
1586		return 0;
1587	}
1588	if ((keypair = resolve_userid(netpgp, netpgp->pubring, userid)) == NULL) {
1589		return 0;
1590	}
1591	if (in == out) {
1592		(void) fprintf(io->errs,
1593			"netpgp_encrypt_buf: input and output bufs need to be different\n");
1594		return 0;
1595	}
1596	if (outsize < insize) {
1597		(void) fprintf(io->errs,
1598			"netpgp_encrypt_buf: input size is larger than output size\n");
1599		return 0;
1600	}
1601	enc = pgp_encrypt_buf(io, in, insize, keypair, (unsigned)armored,
1602				netpgp_getvar(netpgp, "cipher"));
1603	m = MIN(pgp_mem_len(enc), outsize);
1604	(void) memcpy(out, pgp_mem_data(enc), m);
1605	pgp_memory_free(enc);
1606	return (int)m;
1607}
1608
1609/* decrypt a chunk of memory */
1610int
1611netpgp_decrypt_memory(netpgp_t *netpgp, const void *input, const size_t insize,
1612			char *out, size_t outsize, const int armored)
1613{
1614	pgp_memory_t	*mem;
1615	pgp_io_t	*io;
1616	unsigned	 realarmour;
1617	unsigned	 sshkeys;
1618	size_t		 m;
1619	char		*numtries;
1620	int            	 attempts;
1621
1622	__PGP_USED(armored);
1623	io = netpgp->io;
1624	if (input == NULL) {
1625		(void) fprintf(io->errs,
1626			"netpgp_decrypt_memory: no memory\n");
1627		return 0;
1628	}
1629	realarmour = isarmoured(io, NULL, input, ARMOR_HEAD);
1630	sshkeys = (unsigned)(netpgp_getvar(netpgp, "ssh keys") != NULL);
1631	if ((numtries = netpgp_getvar(netpgp, "numtries")) == NULL ||
1632	    (attempts = atoi(numtries)) <= 0) {
1633		attempts = MAX_PASSPHRASE_ATTEMPTS;
1634	} else if (strcmp(numtries, "unlimited") == 0) {
1635		attempts = INFINITE_ATTEMPTS;
1636	}
1637	mem = pgp_decrypt_buf(netpgp->io, input, insize, netpgp->secring,
1638				netpgp->pubring,
1639				realarmour, sshkeys,
1640				netpgp->passfp,
1641				attempts,
1642				get_passphrase_cb);
1643	if (mem == NULL) {
1644		return -1;
1645	}
1646	m = MIN(pgp_mem_len(mem), outsize);
1647	(void) memcpy(out, pgp_mem_data(mem), m);
1648	pgp_memory_free(mem);
1649	return (int)m;
1650}
1651
1652/* wrappers for the ops_debug_level functions we added to openpgpsdk */
1653
1654/* set the debugging level per filename */
1655int
1656netpgp_set_debug(const char *f)
1657{
1658	return pgp_set_debug_level(f);
1659}
1660
1661/* get the debugging level per filename */
1662int
1663netpgp_get_debug(const char *f)
1664{
1665	return pgp_get_debug_level(f);
1666}
1667
1668/* return the version for the library */
1669const char *
1670netpgp_get_info(const char *type)
1671{
1672	return pgp_get_info(type);
1673}
1674
1675/* list all the packets in a file */
1676int
1677netpgp_list_packets(netpgp_t *netpgp, char *f, int armor, char *pubringname)
1678{
1679	pgp_keyring_t	*keyring;
1680	const unsigned	 noarmor = 0;
1681	struct stat	 st;
1682	pgp_io_t	*io;
1683	char		 ringname[MAXPATHLEN];
1684	char		*homedir;
1685	int		 ret;
1686
1687	io = netpgp->io;
1688	if (f == NULL) {
1689		(void) fprintf(io->errs, "No file containing packets\n");
1690		return 0;
1691	}
1692	if (stat(f, &st) < 0) {
1693		(void) fprintf(io->errs, "No such file '%s'\n", f);
1694		return 0;
1695	}
1696	homedir = netpgp_getvar(netpgp, "homedir");
1697	if (pubringname == NULL) {
1698		(void) snprintf(ringname, sizeof(ringname),
1699				"%s/pubring.gpg", homedir);
1700		pubringname = ringname;
1701	}
1702	if ((keyring = calloc(1, sizeof(*keyring))) == NULL) {
1703		(void) fprintf(io->errs, "netpgp_list_packets: bad alloc\n");
1704		return 0;
1705	}
1706	if (!pgp_keyring_fileread(keyring, noarmor, pubringname)) {
1707		free(keyring);
1708		(void) fprintf(io->errs, "Cannot read pub keyring %s\n",
1709			pubringname);
1710		return 0;
1711	}
1712	netpgp->pubring = keyring;
1713	netpgp_setvar(netpgp, "pubring", pubringname);
1714	ret = pgp_list_packets(io, f, (unsigned)armor,
1715					netpgp->secring,
1716					netpgp->pubring,
1717					netpgp->passfp,
1718					get_passphrase_cb);
1719	free(keyring);
1720	return ret;
1721}
1722
1723/* set a variable */
1724int
1725netpgp_setvar(netpgp_t *netpgp, const char *name, const char *value)
1726{
1727	char	*newval;
1728	int	 i;
1729
1730	/* protect against the case where 'value' is netpgp->value[i] */
1731	newval = netpgp_strdup(value);
1732	if ((i = findvar(netpgp, name)) < 0) {
1733		/* add the element to the array */
1734		if (size_arrays(netpgp, netpgp->size + 15)) {
1735			netpgp->name[i = netpgp->c++] = netpgp_strdup(name);
1736		}
1737	} else {
1738		/* replace the element in the array */
1739		if (netpgp->value[i]) {
1740			free(netpgp->value[i]);
1741			netpgp->value[i] = NULL;
1742		}
1743	}
1744	/* sanity checks for range of values */
1745	if (strcmp(name, "hash") == 0 || strcmp(name, "algorithm") == 0) {
1746		if (pgp_str_to_hash_alg(newval) == PGP_HASH_UNKNOWN) {
1747			free(newval);
1748			return 0;
1749		}
1750	}
1751	netpgp->value[i] = newval;
1752	return 1;
1753}
1754
1755/* unset a variable */
1756int
1757netpgp_unsetvar(netpgp_t *netpgp, const char *name)
1758{
1759	int	i;
1760
1761	if ((i = findvar(netpgp, name)) >= 0) {
1762		if (netpgp->value[i]) {
1763			free(netpgp->value[i]);
1764			netpgp->value[i] = NULL;
1765		}
1766		netpgp->value[i] = NULL;
1767		return 1;
1768	}
1769	return 0;
1770}
1771
1772/* get a variable's value (NULL if not set) */
1773char *
1774netpgp_getvar(netpgp_t *netpgp, const char *name)
1775{
1776	int	i;
1777
1778	return ((i = findvar(netpgp, name)) < 0) ? NULL : netpgp->value[i];
1779}
1780
1781/* increment a value */
1782int
1783netpgp_incvar(netpgp_t *netpgp, const char *name, const int delta)
1784{
1785	char	*cp;
1786	char	 num[16];
1787	int	 val;
1788
1789	val = 0;
1790	if ((cp = netpgp_getvar(netpgp, name)) != NULL) {
1791		val = atoi(cp);
1792	}
1793	(void) snprintf(num, sizeof(num), "%d", val + delta);
1794	netpgp_setvar(netpgp, name, num);
1795	return 1;
1796}
1797
1798/* set the home directory value to "home/subdir" */
1799int
1800netpgp_set_homedir(netpgp_t *netpgp, char *home, const char *subdir, const int quiet)
1801{
1802	struct stat	st;
1803	char		d[MAXPATHLEN];
1804
1805	if (home == NULL) {
1806		if (!quiet) {
1807			(void) fprintf(stderr, "NULL HOME directory\n");
1808		}
1809		return 0;
1810	}
1811	(void) snprintf(d, sizeof(d), "%s%s", home, (subdir) ? subdir : "");
1812	if (stat(d, &st) == 0) {
1813		if ((st.st_mode & S_IFMT) == S_IFDIR) {
1814			netpgp_setvar(netpgp, "homedir", d);
1815			return 1;
1816		}
1817		(void) fprintf(stderr, "netpgp: homedir \"%s\" is not a dir\n",
1818					d);
1819		return 0;
1820	}
1821	if (!quiet) {
1822		(void) fprintf(stderr,
1823			"netpgp: warning homedir \"%s\" not found\n", d);
1824	}
1825	netpgp_setvar(netpgp, "homedir", d);
1826	return 1;
1827}
1828
1829/* validate all sigs in the pub keyring */
1830int
1831netpgp_validate_sigs(netpgp_t *netpgp)
1832{
1833	pgp_validation_t	result;
1834
1835	return (int)pgp_validate_all_sigs(&result, netpgp->pubring, NULL);
1836}
1837
1838/* print the json out on 'fp' */
1839int
1840netpgp_format_json(void *vp, const char *json, const int psigs)
1841{
1842	mj_t	 ids;
1843	FILE	*fp;
1844	int	 from;
1845	int	 idc;
1846	int	 tok;
1847	int	 to;
1848	int	 i;
1849
1850	if ((fp = (FILE *)vp) == NULL || json == NULL) {
1851		return 0;
1852	}
1853	/* ids is an array of strings, each containing 1 entry */
1854	(void) memset(&ids, 0x0, sizeof(ids));
1855	from = to = tok = 0;
1856	/* convert from string into an mj structure */
1857	(void) mj_parse(&ids, json, &from, &to, &tok);
1858	if ((idc = mj_arraycount(&ids)) == 1 && strchr(json, '{') == NULL) {
1859		idc = 0;
1860	}
1861	(void) fprintf(fp, "%d key%s found\n", idc, (idc == 1) ? "" : "s");
1862	for (i = 0 ; i < idc ; i++) {
1863		format_json_key(fp, &ids.value.v[i], psigs);
1864	}
1865	/* clean up */
1866	mj_delete(&ids);
1867	return idc;
1868}
1869
1870/* find a key in keyring, and write it in ssh format */
1871int
1872netpgp_write_sshkey(netpgp_t *netpgp, char *s, const char *userid, char *out, size_t size)
1873{
1874	const pgp_key_t	*key;
1875	pgp_keyring_t	*keyring;
1876	pgp_io_t	*io;
1877	unsigned	 k;
1878	size_t		 cc;
1879	char		 f[MAXPATHLEN];
1880
1881	if ((io = calloc(1, sizeof(pgp_io_t))) == NULL) {
1882		(void) fprintf(stderr, "netpgp_save_sshpub: bad alloc 1\n");
1883		return 0;
1884	}
1885	io->outs = stdout;
1886	io->errs = stderr;
1887	io->res = stderr;
1888	netpgp->io = io;
1889	/* write new to temp file */
1890	savepubkey(s, f, sizeof(f));
1891	if ((keyring = calloc(1, sizeof(*keyring))) == NULL) {
1892		(void) fprintf(stderr, "netpgp_save_sshpub: bad alloc 2\n");
1893		return 0;
1894	}
1895	if (!pgp_keyring_fileread(netpgp->pubring = keyring, 1, f)) {
1896		(void) fprintf(stderr, "can't import key\n");
1897		return 0;
1898	}
1899	/* get rsa key */
1900	k = 0;
1901	key = pgp_getnextkeybyname(netpgp->io, netpgp->pubring, userid, &k);
1902	if (key == NULL) {
1903		(void) fprintf(stderr, "no key found for '%s'\n", userid);
1904		return 0;
1905	}
1906	if (key->key.pubkey.alg != PGP_PKA_RSA) {
1907		/* we're not interested in supporting DSA either :-) */
1908		(void) fprintf(stderr, "key not RSA '%s'\n", userid);
1909		return 0;
1910	}
1911	/* XXX - check trust sigs */
1912	/* XXX - check expiry */
1913	/* XXX - check start */
1914	/* XXX - check not weak key */
1915	/* get rsa e and n */
1916	(void) memset(out, 0x0, size);
1917	cc = formatstring((char *)out, (const uint8_t *)"ssh-rsa", 7);
1918	cc += formatbignum((char *)&out[cc], key->key.pubkey.key.rsa.e);
1919	cc += formatbignum((char *)&out[cc], key->key.pubkey.key.rsa.n);
1920	free(io);
1921	free(keyring);
1922	return (int)cc;
1923}
1924