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