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