netpgp.c revision 1.57
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.57 2010/06/01 05:22:38 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 "ops-ssh.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	__OPS_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, 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	return 1;
119}
120
121/* small function to pretty print an 8-character raw userid */
122static char    *
123userid_to_id(const uint8_t *userid, char *id)
124{
125	static const char *hexes = "0123456789abcdef";
126	int		   i;
127
128	for (i = 0; i < 8 ; i++) {
129		id[i * 2] = hexes[(unsigned)(userid[i] & 0xf0) >> 4];
130		id[(i * 2) + 1] = hexes[userid[i] & 0xf];
131	}
132	id[8 * 2] = 0x0;
133	return id;
134}
135
136/* print out the successful signature information */
137static void
138resultp(__ops_io_t *io,
139	const char *f,
140	__ops_validation_t *res,
141	__ops_keyring_t *ring)
142{
143	const __ops_key_t	*pubkey;
144	unsigned		 from;
145	unsigned		 i;
146	time_t			 t;
147	char			 id[MAX_ID_LENGTH + 1];
148
149	for (i = 0; i < res->validc; i++) {
150		(void) fprintf(io->res,
151			"Good signature for %s made %s",
152			(f) ? f : "<stdin>",
153			ctime(&res->valid_sigs[i].birthtime));
154		if (res->duration > 0) {
155			t = res->birthtime + res->duration;
156			(void) fprintf(io->res, "Valid until %s", ctime(&t));
157		}
158		(void) fprintf(io->res,
159			"using %s key %s\n",
160			__ops_show_pka(res->valid_sigs[i].key_alg),
161			userid_to_id(res->valid_sigs[i].signer_id, id));
162		from = 0;
163		pubkey = __ops_getkeybyid(io, ring,
164			(const uint8_t *) res->valid_sigs[i].signer_id,
165			&from);
166		__ops_print_keydata(io, ring, pubkey, "pub", &pubkey->key.pubkey, 0);
167	}
168}
169
170/* check there's enough space in the arrays */
171static int
172size_arrays(netpgp_t *netpgp, unsigned needed)
173{
174	char	**temp;
175
176	if (netpgp->size == 0) {
177		/* only get here first time around */
178		netpgp->size = needed;
179		if ((netpgp->name = calloc(sizeof(char *), needed)) == NULL) {
180			(void) fprintf(stderr, "size_arrays: bad alloc\n");
181			return 0;
182		}
183		if ((netpgp->value = calloc(sizeof(char *), needed)) == NULL) {
184			free(netpgp->name);
185			(void) fprintf(stderr, "size_arrays: bad alloc\n");
186			return 0;
187		}
188	} else if (netpgp->c == netpgp->size) {
189		/* only uses 'needed' when filled array */
190		netpgp->size += needed;
191		temp = realloc(netpgp->name, sizeof(char *) * needed);
192		if (temp == NULL) {
193			(void) fprintf(stderr, "size_arrays: bad alloc\n");
194			return 0;
195		}
196		netpgp->name = temp;
197		temp = realloc(netpgp->value, sizeof(char *) * needed);
198		if (temp == NULL) {
199			(void) fprintf(stderr, "size_arrays: bad alloc\n");
200			return 0;
201		}
202		netpgp->value = temp;
203	}
204	return 1;
205}
206
207/* find the name in the array */
208static int
209findvar(netpgp_t *netpgp, const char *name)
210{
211	unsigned	i;
212
213	for (i = 0 ; i < netpgp->c && strcmp(netpgp->name[i], name) != 0; i++) {
214	}
215	return (i == netpgp->c) ? -1 : (int)i;
216}
217
218/* read a keyring and return it */
219static void *
220readkeyring(netpgp_t *netpgp, const char *name)
221{
222	__ops_keyring_t	*keyring;
223	const unsigned	 noarmor = 0;
224	char		 f[MAXPATHLEN];
225	char		*filename;
226	char		*homedir;
227
228	homedir = netpgp_getvar(netpgp, "homedir");
229	if ((filename = netpgp_getvar(netpgp, name)) == NULL) {
230		(void) snprintf(f, sizeof(f), "%s/%s.gpg", homedir, name);
231		filename = f;
232	}
233	if ((keyring = calloc(1, sizeof(*keyring))) == NULL) {
234		(void) fprintf(stderr, "readkeyring: bad alloc\n");
235		return NULL;
236	}
237	if (!__ops_keyring_fileread(keyring, noarmor, filename)) {
238		free(keyring);
239		(void) fprintf(stderr, "Can't read %s %s\n", name, filename);
240		return NULL;
241	}
242	netpgp_setvar(netpgp, name, filename);
243	return keyring;
244}
245
246/* read keys from ssh key files */
247static int
248readsshkeys(netpgp_t *netpgp, char *homedir)
249{
250	__ops_keyring_t	*pubring;
251	__ops_keyring_t	*secring;
252	char		 f[MAXPATHLEN];
253	char		*filename;
254
255	if ((filename = netpgp_getvar(netpgp, "sshkeyfile")) == NULL) {
256		(void) snprintf(f, sizeof(f), "%s/.ssh/is_rsa.pub", homedir);
257		filename = f;
258	}
259	if ((pubring = calloc(1, sizeof(*pubring))) == NULL) {
260		(void) fprintf(stderr, "readsshkeys: bad alloc\n");
261		return 0;
262	}
263	if (!__ops_ssh2_readkeys(netpgp->io, pubring, NULL, filename, NULL)) {
264		free(pubring);
265		(void) fprintf(stderr, "readsshkeys: can't read %s\n",
266				filename);
267		return 0;
268	}
269	if (netpgp->pubring == NULL) {
270		netpgp->pubring = pubring;
271	} else {
272		__ops_append_keyring(netpgp->pubring, pubring);
273	}
274	netpgp_setvar(netpgp, "sshpubfile", filename);
275	/* try to take the ".pub" off the end */
276	if (filename == f) {
277		f[strlen(f) - 4] = 0x0;
278	} else {
279		(void) snprintf(f, sizeof(f), "%.*s",
280				(int)strlen(filename) - 4, filename);
281		filename = f;
282	}
283	if ((secring = calloc(1, sizeof(*secring))) == NULL) {
284		(void) fprintf(stderr, "readsshkeys: bad alloc\n");
285		return 0;
286	}
287	if (__ops_ssh2_readkeys(netpgp->io, pubring, secring, NULL, filename)) {
288		netpgp->secring = secring;
289		netpgp_setvar(netpgp, "sshsecfile", filename);
290	} else {
291		(void) fprintf(stderr, "readsshkeys: can't read sec %s (%d)\n",
292				filename, errno);
293	}
294	return 1;
295}
296
297/* set ssh uid to first one in pubring */
298static void
299set_first_pubring(__ops_keyring_t *pubring, char *id, size_t len, int last)
300{
301	uint8_t	*src;
302	int	 i;
303	int	 n;
304
305	(void) memset(id, 0x0, len);
306	src = pubring->keys[(last) ? pubring->keyc - 1 : 0].key_id;
307	for (i = 0, n = 0 ; i < OPS_KEY_ID_SIZE ; i += 2) {
308		n += snprintf(&id[n], len - n, "%02x%02x", src[i], src[i + 1]);
309	}
310	id[n] = 0x0;
311}
312
313/* find the time - in a specific %Y-%m-%d format - using a regexp */
314static int
315grabdate(char *s, int64_t *t)
316{
317	static regex_t	r;
318	static int	compiled;
319	regmatch_t	matches[10];
320	struct tm	tm;
321
322	if (!compiled) {
323		compiled = 1;
324		(void) regcomp(&r, "([0-9][0-9][0-9][0-9])[-/]([0-9][0-9])[-/]([0-9][0-9])", REG_EXTENDED);
325	}
326	if (regexec(&r, s, 10, matches, 0) == 0) {
327		(void) memset(&tm, 0x0, sizeof(tm));
328		tm.tm_year = (int)strtol(&s[(int)matches[1].rm_so], NULL, 10);
329		tm.tm_mon = (int)strtol(&s[(int)matches[2].rm_so], NULL, 10) - 1;
330		tm.tm_mday = (int)strtol(&s[(int)matches[3].rm_so], NULL, 10);
331		*t = mktime(&tm);
332		return 1;
333	}
334	return 0;
335}
336
337/* get expiration in seconds */
338static uint64_t
339get_duration(char *s)
340{
341	uint64_t	 now;
342	int64_t	 	 t;
343	char		*mult;
344
345	if (s == NULL) {
346		return 0;
347	}
348	now = strtoull(s, NULL, 10);
349	if ((mult = strchr("hdwmy", s[strlen(s) - 1])) != NULL) {
350		switch(*mult) {
351		case 'h':
352			return now * 60 * 60;
353		case 'd':
354			return now * 60 * 60 * 24;
355		case 'w':
356			return now * 60 * 60 * 24 * 7;
357		case 'm':
358			return now * 60 * 60 * 24 * 31;
359		case 'y':
360			return now * 60 * 60 * 24 * 365;
361		}
362	}
363	if (grabdate(s, &t)) {
364		return t;
365	}
366	return (uint64_t)strtoll(s, NULL, 10);
367}
368
369/* get birthtime in seconds */
370static int64_t
371get_birthtime(char *s)
372{
373	int64_t	t;
374
375	if (s == NULL) {
376		return time(NULL);
377	}
378	if (grabdate(s, &t)) {
379		return t;
380	}
381	return (uint64_t)strtoll(s, NULL, 10);
382}
383
384/* resolve the userid */
385static const __ops_key_t *
386resolve_userid(netpgp_t *netpgp, const __ops_keyring_t *keyring, const char *userid)
387{
388	const __ops_key_t	*key;
389	__ops_io_t		*io;
390
391	if (userid == NULL) {
392		userid = netpgp_getvar(netpgp, "userid");
393	} else if (userid[0] == '0' && userid[1] == 'x') {
394		userid += 2;
395	}
396	io = netpgp->io;
397	if ((key = __ops_getkeybyname(io, keyring, userid)) == NULL) {
398		(void) fprintf(io->errs, "Can't find key '%s'\n", userid);
399	}
400	return key;
401}
402
403/***************************************************************************/
404/* exported functions start here */
405/***************************************************************************/
406
407/* initialise a netpgp_t structure */
408int
409netpgp_init(netpgp_t *netpgp)
410{
411	__ops_io_t	*io;
412	char		 id[MAX_ID_LENGTH];
413	char		*homedir;
414	char		*userid;
415	char		*stream;
416	char		*passfd;
417	char		*results;
418	int		 coredumps;
419	int		 last;
420
421#ifdef HAVE_SYS_RESOURCE_H
422	struct rlimit	limit;
423
424	coredumps = netpgp_getvar(netpgp, "coredumps") != NULL;
425	if (!coredumps) {
426		(void) memset(&limit, 0x0, sizeof(limit));
427		if (setrlimit(RLIMIT_CORE, &limit) != 0) {
428			(void) fprintf(stderr,
429			"netpgp: warning - can't turn off core dumps\n");
430			coredumps = 1;
431		}
432	}
433#else
434	coredumps = 1;
435#endif
436	if ((io = calloc(1, sizeof(*io))) == NULL) {
437		(void) fprintf(stderr, "netpgp_init: bad alloc\n");
438		return 0;
439	}
440	io->outs = stdout;
441	if ((stream = netpgp_getvar(netpgp, "outs")) != NULL &&
442	    strcmp(stream, "<stderr>") == 0) {
443		io->outs = stderr;
444	}
445	io->errs = stderr;
446	if ((stream = netpgp_getvar(netpgp, "errs")) != NULL &&
447	    strcmp(stream, "<stdout>") == 0) {
448		io->errs = stdout;
449	}
450	if ((results = netpgp_getvar(netpgp, "res")) == NULL) {
451		io->res = io->errs;
452	} else if (strcmp(results, "<stdout>") == 0) {
453		io->res = stdout;
454	} else if (strcmp(results, "<stderr>") == 0) {
455		io->res = stderr;
456	} else {
457		if ((io->res = fopen(results, "w")) == NULL) {
458			(void) fprintf(io->errs, "Can't open results %s for writing\n",
459				results);
460			free(io);
461			return 0;
462		}
463	}
464	netpgp->io = io;
465	if ((passfd = netpgp_getvar(netpgp, "pass-fd")) != NULL &&
466	    (netpgp->passfp = fdopen(atoi(passfd), "r")) == NULL) {
467		(void) fprintf(io->errs, "Can't open fd %s for reading\n",
468			passfd);
469		return 0;
470	}
471	if (coredumps) {
472		(void) fprintf(io->errs,
473			"netpgp: warning: core dumps enabled\n");
474	}
475	if ((homedir = netpgp_getvar(netpgp, "homedir")) == NULL) {
476		(void) fprintf(io->errs, "netpgp: bad homedir\n");
477		return 0;
478	}
479	/* read from either gpg files or ssh keys */
480	if (netpgp_getvar(netpgp, "ssh keys") == NULL) {
481		if ((userid = netpgp_getvar(netpgp, "userid")) == NULL) {
482			(void) memset(id, 0x0, sizeof(id));
483			(void) conffile(netpgp, homedir, id, sizeof(id));
484			if (id[0] != 0x0) {
485				netpgp_setvar(netpgp, "userid", userid = id);
486			}
487		}
488		if (userid == NULL) {
489			if (netpgp_getvar(netpgp, "need userid") != NULL) {
490				(void) fprintf(io->errs,
491						"Cannot find user id\n");
492				return 0;
493			}
494		} else {
495			(void) netpgp_setvar(netpgp, "userid", userid);
496		}
497		netpgp->pubring = readkeyring(netpgp, "pubring");
498		if (netpgp->pubring == NULL) {
499			(void) fprintf(io->errs, "Can't read pub keyring\n");
500			return 0;
501		}
502		netpgp->secring = readkeyring(netpgp, "secring");
503		if (netpgp->secring == NULL) {
504			(void) fprintf(io->errs, "Can't read sec keyring\n");
505			return 0;
506		}
507	} else {
508		last = (netpgp->pubring != NULL);
509		if (!readsshkeys(netpgp, homedir)) {
510			(void) fprintf(io->errs, "Can't read ssh pub key\n");
511			return 0;
512		}
513		if ((userid = netpgp_getvar(netpgp, "userid")) == NULL) {
514			set_first_pubring(netpgp->pubring, id, sizeof(id), last);
515			netpgp_setvar(netpgp, "userid", userid = id);
516		}
517		if (userid == NULL) {
518			if (netpgp_getvar(netpgp, "need userid") != NULL) {
519				(void) fprintf(io->errs,
520						"Cannot find user id\n");
521				return 0;
522			}
523		} else {
524			(void) netpgp_setvar(netpgp, "userid", userid);
525		}
526	}
527	return 1;
528}
529
530/* finish off with the netpgp_t struct */
531int
532netpgp_end(netpgp_t *netpgp)
533{
534	unsigned	i;
535
536	for (i = 0 ; i < netpgp->c ; i++) {
537		if (netpgp->name[i] != NULL) {
538			free(netpgp->name[i]);
539		}
540		if (netpgp->value[i] != NULL) {
541			free(netpgp->value[i]);
542		}
543	}
544	if (netpgp->name != NULL) {
545		free(netpgp->name);
546	}
547	if (netpgp->value != NULL) {
548		free(netpgp->value);
549	}
550	if (netpgp->pubring != NULL) {
551		__ops_keyring_free(netpgp->pubring);
552	}
553	if (netpgp->secring != NULL) {
554		__ops_keyring_free(netpgp->secring);
555	}
556	free(netpgp->io);
557	return 1;
558}
559
560/* list the keys in a keyring */
561int
562netpgp_list_keys(netpgp_t *netpgp, const int psigs)
563{
564	return __ops_keyring_list(netpgp->io, netpgp->pubring, psigs);
565}
566
567DEFINE_ARRAY(strings_t, char *);
568
569#ifndef HKP_VERSION
570#define HKP_VERSION	1
571#endif
572
573/* find and list some keys in a keyring */
574int
575netpgp_match_keys(netpgp_t *netpgp, char *name, const char *fmt, void *vp, const int psigs)
576{
577	const __ops_key_t	*key;
578	unsigned		 k;
579	strings_t		 pubs;
580	FILE			*fp = (FILE *)vp;
581
582	if (name[0] == '0' && name[1] == 'x') {
583		name += 2;
584	}
585	(void) memset(&pubs, 0x0, sizeof(pubs));
586	k = 0;
587	do {
588		key = __ops_getnextkeybyname(netpgp->io, netpgp->pubring,
589						name, &k);
590		if (key != NULL) {
591			ALLOC(char *, pubs.v, pubs.size, pubs.c, 10, 10,
592					"netpgp_match_keys", return 0);
593			if (strcmp(fmt, "mr") == 0) {
594				__ops_hkp_sprint_keydata(netpgp->io, netpgp->pubring,
595						key, &pubs.v[pubs.c],
596						&key->key.pubkey, psigs);
597			} else {
598				__ops_sprint_keydata(netpgp->io, netpgp->pubring,
599						key, &pubs.v[pubs.c],
600						"pub",
601						&key->key.pubkey, psigs);
602			}
603			if (pubs.v[pubs.c] != NULL) {
604				pubs.c += 1;
605			}
606			k += 1;
607		}
608	} while (key != NULL);
609	if (strcmp(fmt, "mr") == 0) {
610		(void) fprintf(fp, "info:%d:%d\n", HKP_VERSION, pubs.c);
611	} else {
612		(void) fprintf(fp, "%d key%s found\n", pubs.c,
613			(pubs.c == 1) ? "" : "s");
614	}
615	for (k = 0 ; k < pubs.c ; k++) {
616		(void) fprintf(fp, "%s%s", pubs.v[k], (k < pubs.c - 1) ? "\n" : "");
617		free(pubs.v[k]);
618	}
619	free(pubs.v);
620	return pubs.c;
621}
622
623/* find and list some public keys in a keyring */
624int
625netpgp_match_pubkeys(netpgp_t *netpgp, char *name, void *vp)
626{
627	const __ops_key_t	*key;
628	unsigned		 k;
629	strings_t		 pubs;
630	FILE			*fp = (FILE *)vp;
631
632	(void) memset(&pubs, 0x0, sizeof(pubs));
633	do {
634		key = __ops_getnextkeybyname(netpgp->io, netpgp->pubring,
635						name, &k);
636		if (key != NULL) {
637			char	out[1024 * 64];
638
639			ALLOC(char *, pubs.v, pubs.size, pubs.c, 10, 10,
640					"netpgp_match_pubkeys", return 0);
641			(void) __ops_sprint_pubkey(key, out, sizeof(out));
642			pubs.v[pubs.c++] = netpgp_strdup(out);
643			k += 1;
644		}
645	} while (key != NULL);
646	(void) fprintf(fp, "info:%d:%d\n", HKP_VERSION, pubs.c);
647	for (k = 0 ; k < pubs.c ; k++) {
648		(void) fprintf(fp, "%s", pubs.v[k]);
649		free(pubs.v[k]);
650	}
651	free(pubs.v);
652	return pubs.c;
653}
654
655/* find a key in a keyring */
656int
657netpgp_find_key(netpgp_t *netpgp, char *id)
658{
659	__ops_io_t	*io;
660
661	io = netpgp->io;
662	if (id == NULL) {
663		(void) fprintf(io->errs, "NULL id to search for\n");
664		return 0;
665	}
666	return __ops_getkeybyname(netpgp->io, netpgp->pubring, id) != NULL;
667}
668
669/* get a key in a keyring */
670char *
671netpgp_get_key(netpgp_t *netpgp, const char *name, const char *fmt)
672{
673	const __ops_key_t	*key;
674	char			*newkey;
675
676	if ((key = resolve_userid(netpgp, netpgp->pubring, name)) == NULL) {
677		return NULL;
678	}
679	if (strcmp(fmt, "mr") == 0) {
680		return (__ops_hkp_sprint_keydata(netpgp->io, netpgp->pubring,
681				key, &newkey,
682				&key->key.pubkey,
683				netpgp_getvar(netpgp, "subkey sigs") != NULL) > 0) ? newkey : NULL;
684	}
685	return (__ops_sprint_keydata(netpgp->io, netpgp->pubring,
686				key, &newkey, "pub",
687				&key->key.pubkey,
688				netpgp_getvar(netpgp, "subkey sigs") != NULL) > 0) ? newkey : NULL;
689}
690
691/* export a given key */
692char *
693netpgp_export_key(netpgp_t *netpgp, char *name)
694{
695	const __ops_key_t	*key;
696	__ops_io_t		*io;
697
698	io = netpgp->io;
699	if ((key = resolve_userid(netpgp, netpgp->pubring, name)) == NULL) {
700		return NULL;
701	}
702	return __ops_export_key(io, key, NULL);
703}
704
705/* import a key into our keyring */
706int
707netpgp_import_key(netpgp_t *netpgp, char *f)
708{
709	const unsigned	noarmor = 0;
710	const unsigned	armor = 1;
711	__ops_io_t	*io;
712	int		done;
713
714	io = netpgp->io;
715	if ((done = __ops_keyring_fileread(netpgp->pubring, noarmor, f)) == 0) {
716		done = __ops_keyring_fileread(netpgp->pubring, armor, f);
717	}
718	if (!done) {
719		(void) fprintf(io->errs, "Cannot import key from file %s\n", f);
720		return 0;
721	}
722	return __ops_keyring_list(io, netpgp->pubring, 0);
723}
724
725/* generate a new key */
726int
727netpgp_generate_key(netpgp_t *netpgp, char *id, int numbits)
728{
729	__ops_output_t		*create;
730	const unsigned		 noarmor = 0;
731	__ops_key_t		*key;
732	__ops_io_t		*io;
733	uint8_t			*uid;
734	char			 newid[1024];
735	char			 filename[MAXPATHLEN];
736	char			 dir[MAXPATHLEN];
737	char			*cp;
738	char			*ringfile;
739	int             	 fd;
740
741	uid = NULL;
742	io = netpgp->io;
743	/* generate a new key */
744	if (id) {
745		(void) snprintf(newid, sizeof(newid), "%s", id);
746	} else {
747		(void) snprintf(newid, sizeof(newid), "RSA %d-bit key <%s@localhost>", numbits, getenv("LOGNAME"));
748	}
749	uid = (uint8_t *)newid;
750	key = __ops_rsa_new_selfsign_key(numbits, 65537UL, uid, netpgp_getvar(netpgp, "hash"));
751	if (key == NULL) {
752		(void) fprintf(io->errs, "Cannot generate key\n");
753		return 0;
754	}
755	cp = NULL;
756	__ops_sprint_keydata(netpgp->io, NULL, key, &cp, "pub", &key->key.seckey.pubkey, 0);
757	(void) fprintf(stdout, "%s", cp);
758	/* write public key */
759	(void) snprintf(dir, sizeof(dir), "%s/%.16s", netpgp_getvar(netpgp, "homedir"), &cp[31]);
760	if (mkdir(dir, 0700) < 0) {
761		(void) fprintf(io->errs, "can't mkdir '%s'\n", dir);
762		return 0;
763	}
764	(void) fprintf(io->errs, "netpgp: generated keys in directory %s\n", dir);
765	(void) snprintf(ringfile = filename, sizeof(filename), "%s/pubring.gpg", dir);
766	if ((fd = __ops_setup_file_append(&create, ringfile)) < 0) {
767		fd = __ops_setup_file_write(&create, ringfile, 0);
768	}
769	if (fd < 0) {
770		(void) fprintf(io->errs, "can't open pubring '%s'\n", ringfile);
771		return 0;
772	}
773	if (!__ops_write_xfer_pubkey(create, key, noarmor)) {
774		(void) fprintf(io->errs, "Cannot write pubkey\n");
775		return 0;
776	}
777	__ops_teardown_file_write(create, fd);
778	if (netpgp->pubring != NULL) {
779		__ops_keyring_free(netpgp->pubring);
780	}
781	/* write secret key */
782	(void) snprintf(ringfile = filename, sizeof(filename), "%s/secring.gpg", dir);
783	if ((fd = __ops_setup_file_append(&create, ringfile)) < 0) {
784		fd = __ops_setup_file_write(&create, ringfile, 0);
785	}
786	if (fd < 0) {
787		(void) fprintf(io->errs, "can't append secring '%s'\n", ringfile);
788		return 0;
789	}
790	if (!__ops_write_xfer_seckey(create, key, NULL, 0, noarmor)) {
791		(void) fprintf(io->errs, "Cannot write seckey\n");
792		return 0;
793	}
794	__ops_teardown_file_write(create, fd);
795	if (netpgp->secring != NULL) {
796		__ops_keyring_free(netpgp->secring);
797	}
798	__ops_keydata_free(key);
799	free(cp);
800	return 1;
801}
802
803/* encrypt a file */
804int
805netpgp_encrypt_file(netpgp_t *netpgp,
806			const char *userid,
807			const char *f,
808			char *out,
809			int armored)
810{
811	const __ops_key_t	*keypair;
812	const unsigned		 overwrite = 1;
813	const char		*suffix;
814	__ops_io_t		*io;
815	char			 outname[MAXPATHLEN];
816
817	io = netpgp->io;
818	if (f == NULL) {
819		(void) fprintf(io->errs,
820			"netpgp_encrypt_file: no filename specified\n");
821		return 0;
822	}
823	suffix = (armored) ? ".asc" : ".gpg";
824	/* get key with which to sign */
825	if ((keypair = resolve_userid(netpgp, netpgp->pubring, userid)) == NULL) {
826		return 0;
827	}
828	if (out == NULL) {
829		(void) snprintf(outname, sizeof(outname), "%s%s", f, suffix);
830		out = outname;
831	}
832	return (int)__ops_encrypt_file(io, f, out, keypair, (unsigned)armored,
833					overwrite);
834}
835
836#define ARMOR_HEAD	"-----BEGIN PGP MESSAGE-----\r\n"
837
838/* decrypt a file */
839int
840netpgp_decrypt_file(netpgp_t *netpgp, const char *f, char *out, int armored)
841{
842	const unsigned	 overwrite = 1;
843	__ops_io_t	*io;
844	unsigned	 realarmor;
845	FILE		*fp;
846	char		 buf[BUFSIZ];
847
848	io = netpgp->io;
849	if (f == NULL) {
850		(void) fprintf(io->errs,
851			"netpgp_decrypt_file: no filename specified\n");
852		return 0;
853	}
854	realarmor = (unsigned)armored;
855	if ((fp = fopen(f, "r")) == NULL) {
856		(void) fprintf(io->errs,
857			"netpgp_decrypt_file: can't open '%s'\n", f);
858		return 0;
859	}
860	if (fgets(buf, sizeof(buf), fp) == NULL) {
861		realarmor = 0;
862	} else {
863		realarmor = (strcmp(buf, ARMOR_HEAD) == 0);
864	}
865	(void) fclose(fp);
866	return __ops_decrypt_file(netpgp->io, f, out, netpgp->secring,
867				netpgp->pubring,
868				(unsigned)realarmor, overwrite,
869				netpgp->passfp, get_passphrase_cb);
870}
871
872/* sign a file */
873int
874netpgp_sign_file(netpgp_t *netpgp,
875		const char *userid,
876		const char *f,
877		char *out,
878		int armored,
879		int cleartext,
880		int detached)
881{
882	const __ops_key_t	*keypair;
883	const __ops_key_t	*pubkey;
884	__ops_seckey_t		*seckey;
885	const unsigned		 overwrite = 1;
886	__ops_io_t		*io;
887	const char		*hashalg;
888	int			 ret;
889
890	io = netpgp->io;
891	if (f == NULL) {
892		(void) fprintf(io->errs,
893			"netpgp_sign_file: no filename specified\n");
894		return 0;
895	}
896	/* get key with which to sign */
897	if ((keypair = resolve_userid(netpgp, netpgp->secring, userid)) == NULL) {
898		return 0;
899	}
900	ret = 1;
901	do {
902		if (netpgp->passfp == NULL) {
903			/* print out the user id */
904			pubkey = __ops_getkeybyname(io, netpgp->pubring, userid);
905			if (pubkey == NULL) {
906				(void) fprintf(io->errs,
907					"netpgp: warning - using pubkey from secring\n");
908				__ops_print_keydata(io, netpgp->pubring, keypair, "pub",
909					&keypair->key.seckey.pubkey, 0);
910			} else {
911				__ops_print_keydata(io, netpgp->pubring, pubkey, "pub", &pubkey->key.pubkey, 0);
912			}
913		}
914		if (netpgp_getvar(netpgp, "ssh keys") == NULL) {
915			/* now decrypt key */
916			seckey = __ops_decrypt_seckey(keypair, netpgp->passfp);
917			if (seckey == NULL) {
918				(void) fprintf(io->errs, "Bad passphrase\n");
919			}
920		} else {
921			__ops_keyring_t	*secring;
922
923			secring = netpgp->secring;
924			seckey = &secring->keys[0].key.seckey;
925		}
926	} while (seckey == NULL);
927	/* sign file */
928	hashalg = netpgp_getvar(netpgp, "hash");
929	if (seckey->pubkey.alg == OPS_PKA_DSA) {
930		hashalg = "sha1";
931	}
932	if (detached) {
933		ret = __ops_sign_detached(io, f, out, seckey, hashalg,
934				get_birthtime(netpgp_getvar(netpgp, "birthtime")),
935				get_duration(netpgp_getvar(netpgp, "duration")),
936				(unsigned)armored,
937				overwrite);
938	} else {
939		ret = __ops_sign_file(io, f, out, seckey, hashalg,
940				get_birthtime(netpgp_getvar(netpgp, "birthtime")),
941				get_duration(netpgp_getvar(netpgp, "duration")),
942				(unsigned)armored, (unsigned)cleartext,
943				overwrite);
944	}
945	__ops_forget(seckey, sizeof(*seckey));
946	return ret;
947}
948
949#define ARMOR_SIG_HEAD	"-----BEGIN PGP SIGNATURE-----\r\n"
950
951/* verify a file */
952int
953netpgp_verify_file(netpgp_t *netpgp, const char *in, const char *out, int armored)
954{
955	__ops_validation_t	 result;
956	__ops_io_t		*io;
957	unsigned		 realarmor;
958	FILE			*fp;
959	char			 buf[BUFSIZ];
960
961	(void) memset(&result, 0x0, sizeof(result));
962	io = netpgp->io;
963	if (in == NULL) {
964		(void) fprintf(io->errs,
965			"netpgp_verify_file: no filename specified\n");
966		return 0;
967	}
968	realarmor = (unsigned)armored;
969	if ((fp = fopen(in, "r")) == NULL) {
970		(void) fprintf(io->errs,
971			"netpgp_decrypt_file: can't open '%s'\n", in);
972		return 0;
973	}
974	if (fgets(buf, sizeof(buf), fp) == NULL) {
975		realarmor = 0;
976	} else {
977		realarmor = (strcmp(buf, ARMOR_SIG_HEAD) == 0);
978	}
979	(void) fclose(fp);
980	if (__ops_validate_file(io, &result, in, out, (const int)realarmor, netpgp->pubring)) {
981		resultp(io, in, &result, netpgp->pubring);
982		return 1;
983	}
984	if (result.validc + result.invalidc + result.unknownc == 0) {
985		(void) fprintf(io->errs,
986		"\"%s\": No signatures found - is this a signed file?\n",
987			in);
988	} else if (result.invalidc == 0 && result.unknownc == 0) {
989		(void) fprintf(io->errs,
990			"\"%s\": file verification failure: invalid signature time\n", in);
991	} else {
992		(void) fprintf(io->errs,
993"\"%s\": verification failure: %u invalid signatures, %u unknown signatures\n",
994			in, result.invalidc, result.unknownc);
995	}
996	return 0;
997}
998
999/* sign some memory */
1000int
1001netpgp_sign_memory(netpgp_t *netpgp,
1002		const char *userid,
1003		char *mem,
1004		size_t size,
1005		char *out,
1006		size_t outsize,
1007		const unsigned armored,
1008		const unsigned cleartext)
1009{
1010	const __ops_key_t	*keypair;
1011	const __ops_key_t	*pubkey;
1012	__ops_seckey_t		*seckey;
1013	__ops_memory_t		*signedmem;
1014	__ops_io_t		*io;
1015	const char		*hashalg;
1016	int			 ret;
1017
1018	io = netpgp->io;
1019	if (mem == NULL) {
1020		(void) fprintf(io->errs,
1021			"netpgp_sign_memory: no memory to sign\n");
1022		return 0;
1023	}
1024	if ((keypair = resolve_userid(netpgp, netpgp->secring, userid)) == NULL) {
1025		return 0;
1026	}
1027	ret = 1;
1028	do {
1029		if (netpgp->passfp == NULL) {
1030			/* print out the user id */
1031			pubkey = __ops_getkeybyname(io, netpgp->pubring, userid);
1032			if (pubkey == NULL) {
1033				(void) fprintf(io->errs,
1034					"netpgp: warning - using pubkey from secring\n");
1035				__ops_print_keydata(io, netpgp->pubring, keypair, "pub",
1036					&keypair->key.seckey.pubkey, 0);
1037			} else {
1038				__ops_print_keydata(io, netpgp->pubring, pubkey, "pub", &pubkey->key.pubkey, 0);
1039			}
1040		}
1041		/* now decrypt key */
1042		seckey = __ops_decrypt_seckey(keypair, netpgp->passfp);
1043		if (seckey == NULL) {
1044			(void) fprintf(io->errs, "Bad passphrase\n");
1045		}
1046	} while (seckey == NULL);
1047	/* sign file */
1048	(void) memset(out, 0x0, outsize);
1049	hashalg = netpgp_getvar(netpgp, "hash");
1050	if (seckey->pubkey.alg == OPS_PKA_DSA) {
1051		hashalg = "sha1";
1052	}
1053	signedmem = __ops_sign_buf(io, mem, size, seckey,
1054				get_birthtime(netpgp_getvar(netpgp, "birthtime")),
1055				get_duration(netpgp_getvar(netpgp, "duration")),
1056				hashalg, armored, cleartext);
1057	if (signedmem) {
1058		size_t	m;
1059
1060		m = MIN(__ops_mem_len(signedmem), outsize);
1061		(void) memcpy(out, __ops_mem_data(signedmem), m);
1062		__ops_memory_free(signedmem);
1063		ret = (int)m;
1064	} else {
1065		ret = 0;
1066	}
1067	__ops_forget(seckey, sizeof(*seckey));
1068	return ret;
1069}
1070
1071/* verify memory */
1072int
1073netpgp_verify_memory(netpgp_t *netpgp, const void *in, const size_t size,
1074			void *out, size_t outsize, const int armored)
1075{
1076	__ops_validation_t	 result;
1077	__ops_memory_t		*signedmem;
1078	__ops_memory_t		*cat;
1079	__ops_io_t		*io;
1080	size_t			 m;
1081	int			 ret;
1082
1083	(void) memset(&result, 0x0, sizeof(result));
1084	io = netpgp->io;
1085	if (in == NULL) {
1086		(void) fprintf(io->errs,
1087			"netpgp_verify_memory: no memory to verify\n");
1088		return 0;
1089	}
1090	signedmem = __ops_memory_new();
1091	__ops_memory_add(signedmem, in, size);
1092	if (out) {
1093		cat = __ops_memory_new();
1094	}
1095	ret = __ops_validate_mem(io, &result, signedmem,
1096				(out) ? &cat : NULL,
1097				armored, netpgp->pubring);
1098	__ops_memory_free(signedmem);
1099	if (ret) {
1100		resultp(io, "<stdin>", &result, netpgp->pubring);
1101		if (out) {
1102			m = MIN(__ops_mem_len(cat), outsize);
1103			(void) memcpy(out, __ops_mem_data(cat), m);
1104			__ops_memory_free(cat);
1105		} else {
1106			m = 1;
1107		}
1108		return (int)m;
1109	}
1110	if (result.validc + result.invalidc + result.unknownc == 0) {
1111		(void) fprintf(io->errs,
1112		"No signatures found - is this memory signed?\n");
1113	} else if (result.invalidc == 0 && result.unknownc == 0) {
1114		(void) fprintf(io->errs,
1115			"memory verification failure: invalid signature time\n");
1116	} else {
1117		(void) fprintf(io->errs,
1118"memory verification failure: %u invalid signatures, %u unknown signatures\n",
1119			result.invalidc, result.unknownc);
1120	}
1121	return 0;
1122}
1123
1124/* encrypt some memory */
1125int
1126netpgp_encrypt_memory(netpgp_t *netpgp,
1127			const char *userid,
1128			void *in,
1129			const size_t insize,
1130			char *out,
1131			size_t outsize,
1132			int armored)
1133{
1134	const __ops_key_t	*keypair;
1135	__ops_memory_t		*enc;
1136	__ops_io_t		*io;
1137	size_t			 m;
1138
1139	io = netpgp->io;
1140	if (in == NULL) {
1141		(void) fprintf(io->errs,
1142			"netpgp_encrypt_buf: no memory to encrypt\n");
1143		return 0;
1144	}
1145	if ((keypair = resolve_userid(netpgp, netpgp->pubring, userid)) == NULL) {
1146		return 0;
1147	}
1148	if (in == out) {
1149		(void) fprintf(io->errs,
1150			"netpgp_encrypt_buf: input and output bufs need to be different\n");
1151		return 0;
1152	}
1153	if (outsize < insize) {
1154		(void) fprintf(io->errs,
1155			"netpgp_encrypt_buf: input size is larger than output size\n");
1156		return 0;
1157	}
1158	enc = __ops_encrypt_buf(io, in, insize, keypair, (unsigned)armored);
1159	m = MIN(__ops_mem_len(enc), outsize);
1160	(void) memcpy(out, __ops_mem_data(enc), m);
1161	__ops_memory_free(enc);
1162	return (int)m;
1163}
1164
1165/* decrypt a chunk of memory */
1166int
1167netpgp_decrypt_memory(netpgp_t *netpgp, const void *input, const size_t insize,
1168			char *out, size_t outsize, const int armored)
1169{
1170	__ops_memory_t	*mem;
1171	__ops_io_t	*io;
1172	unsigned	 realarmor;
1173	size_t		 m;
1174
1175	io = netpgp->io;
1176	realarmor = (unsigned) armored;
1177	if (input == NULL) {
1178		(void) fprintf(io->errs,
1179			"netpgp_decrypt_memory: no memory\n");
1180		return 0;
1181	}
1182	realarmor = (strncmp(input, ARMOR_HEAD, sizeof(ARMOR_HEAD) - 1) == 0);
1183	mem = __ops_decrypt_buf(netpgp->io, input, insize, netpgp->secring,
1184				netpgp->pubring,
1185				realarmor, netpgp->passfp,
1186				get_passphrase_cb);
1187	m = MIN(__ops_mem_len(mem), outsize);
1188	(void) memcpy(out, __ops_mem_data(mem), m);
1189	__ops_memory_free(mem);
1190	return (int)m;
1191}
1192
1193/* wrappers for the ops_debug_level functions we added to openpgpsdk */
1194
1195/* set the debugging level per filename */
1196int
1197netpgp_set_debug(const char *f)
1198{
1199	return __ops_set_debug_level(f);
1200}
1201
1202/* get the debugging level per filename */
1203int
1204netpgp_get_debug(const char *f)
1205{
1206	return __ops_get_debug_level(f);
1207}
1208
1209/* return the version for the library */
1210const char *
1211netpgp_get_info(const char *type)
1212{
1213	return __ops_get_info(type);
1214}
1215
1216/* list all the packets in a file */
1217int
1218netpgp_list_packets(netpgp_t *netpgp, char *f, int armor, char *pubringname)
1219{
1220	__ops_keyring_t	*keyring;
1221	const unsigned	 noarmor = 0;
1222	struct stat	 st;
1223	__ops_io_t	*io;
1224	char		 ringname[MAXPATHLEN];
1225	char		*homedir;
1226	int		 ret;
1227
1228	io = netpgp->io;
1229	if (f == NULL) {
1230		(void) fprintf(io->errs, "No file containing packets\n");
1231		return 0;
1232	}
1233	if (stat(f, &st) < 0) {
1234		(void) fprintf(io->errs, "No such file '%s'\n", f);
1235		return 0;
1236	}
1237	homedir = netpgp_getvar(netpgp, "homedir");
1238	if (pubringname == NULL) {
1239		(void) snprintf(ringname, sizeof(ringname),
1240				"%s/pubring.gpg", homedir);
1241		pubringname = ringname;
1242	}
1243	if ((keyring = calloc(1, sizeof(*keyring))) == NULL) {
1244		(void) fprintf(io->errs, "netpgp_list_packets: bad alloc\n");
1245		return 0;
1246	}
1247	if (!__ops_keyring_fileread(keyring, noarmor, pubringname)) {
1248		free(keyring);
1249		(void) fprintf(io->errs, "Cannot read pub keyring %s\n",
1250			pubringname);
1251		return 0;
1252	}
1253	netpgp->pubring = keyring;
1254	netpgp_setvar(netpgp, "pubring", pubringname);
1255	ret = __ops_list_packets(io, f, (unsigned)armor,
1256					netpgp->secring,
1257					netpgp->pubring,
1258					netpgp->passfp,
1259					get_passphrase_cb);
1260	free(keyring);
1261	return ret;
1262}
1263
1264/* set a variable */
1265int
1266netpgp_setvar(netpgp_t *netpgp, const char *name, const char *value)
1267{
1268	char	*newval;
1269	int	 i;
1270
1271	/* protect against the case where 'value' is netpgp->value[i] */
1272	newval = netpgp_strdup(value);
1273	if ((i = findvar(netpgp, name)) < 0) {
1274		/* add the element to the array */
1275		if (size_arrays(netpgp, netpgp->size + 15)) {
1276			netpgp->name[i = netpgp->c++] = netpgp_strdup(name);
1277		}
1278	} else {
1279		/* replace the element in the array */
1280		if (netpgp->value[i]) {
1281			free(netpgp->value[i]);
1282			netpgp->value[i] = NULL;
1283		}
1284	}
1285	/* sanity checks for range of values */
1286	if (strcmp(name, "hash") == 0 || strcmp(name, "algorithm") == 0) {
1287		if (__ops_str_to_hash_alg(newval) == OPS_HASH_UNKNOWN) {
1288			free(newval);
1289			return 0;
1290		}
1291	}
1292	netpgp->value[i] = newval;
1293	return 1;
1294}
1295
1296/* unset a variable */
1297int
1298netpgp_unsetvar(netpgp_t *netpgp, const char *name)
1299{
1300	int	i;
1301
1302	if ((i = findvar(netpgp, name)) >= 0) {
1303		if (netpgp->value[i]) {
1304			free(netpgp->value[i]);
1305			netpgp->value[i] = NULL;
1306		}
1307		netpgp->value[i] = NULL;
1308		return 1;
1309	}
1310	return 0;
1311}
1312
1313/* get a variable's value (NULL if not set) */
1314char *
1315netpgp_getvar(netpgp_t *netpgp, const char *name)
1316{
1317	int	i;
1318
1319	return ((i = findvar(netpgp, name)) < 0) ? NULL : netpgp->value[i];
1320}
1321
1322/* increment a value */
1323int
1324netpgp_incvar(netpgp_t *netpgp, const char *name, const int delta)
1325{
1326	char	*cp;
1327	char	 num[16];
1328	int	 val;
1329
1330	val = 0;
1331	if ((cp = netpgp_getvar(netpgp, name)) != NULL) {
1332		val = atoi(cp);
1333	}
1334	(void) snprintf(num, sizeof(num), "%d", val + delta);
1335	netpgp_setvar(netpgp, name, num);
1336	return 1;
1337}
1338
1339/* set the home directory value to "home/subdir" */
1340int
1341netpgp_set_homedir(netpgp_t *netpgp, char *home, const char *subdir, const int quiet)
1342{
1343	struct stat	st;
1344	char		d[MAXPATHLEN];
1345
1346	if (home == NULL) {
1347		if (!quiet) {
1348			(void) fprintf(stderr, "NULL HOME directory\n");
1349		}
1350		return 0;
1351	}
1352	(void) snprintf(d, sizeof(d), "%s%s", home, (subdir) ? subdir : "");
1353	if (stat(d, &st) == 0) {
1354		if ((st.st_mode & S_IFMT) == S_IFDIR) {
1355			netpgp_setvar(netpgp, "homedir", d);
1356			return 1;
1357		}
1358		(void) fprintf(stderr, "netpgp: homedir \"%s\" is not a dir\n",
1359					d);
1360		return 0;
1361	}
1362	if (!quiet) {
1363		(void) fprintf(stderr,
1364			"netpgp: warning homedir \"%s\" not found\n", d);
1365	}
1366	netpgp_setvar(netpgp, "homedir", d);
1367	return 1;
1368}
1369
1370/* validate all sigs in the pub keyring */
1371int
1372netpgp_validate_sigs(netpgp_t *netpgp)
1373{
1374	__ops_validation_t	result;
1375
1376	return (int)__ops_validate_all_sigs(&result, netpgp->pubring, NULL);
1377}
1378
1379#if 0
1380#include "sshkey.h"
1381
1382int
1383netpgp_pgpkey_to_sshkey(netpgp_t *netpgp, char *name, SSHKey *sshkey)
1384{
1385	const __ops_key_t	*pgpkey;
1386	unsigned		 k;
1387
1388	k = 0;
1389	pgpkey = __ops_getnextkeybyname(netpgp->io, netpgp->pubring, name, &k);
1390	if (pgpkey == NULL) {
1391		pgpkey = __ops_getkeybyname(io, netpgp->pubring, userid);
1392	}
1393	if (pgpkey == NULL) {
1394		(void) fprintf(stderr, "No key matching '%s'\n", name);
1395		return 0;
1396	}
1397	switch(pgpkey->key.pubkey.alg) {
1398	case OPS_PKA_RSA:
1399		sshkey->type = KEY_RSA;
1400		sshkey->rsa = calloc(1, sizeof(*sshkey->rsa);
1401		if (sshkey->rsa == NULL) {
1402			(void) fprintf(stderr, "RSA memory problems\n");
1403			return 0;
1404		}
1405		sshkey->rsa->n = pgpkey->key.pubkey.key.rsa.n;
1406		sshkey->rsa->e = pgpkey->key.pubkey.key.rsa.e;
1407		sshkey->rsa->d = pgpkey->key.seckey.key.rsa.d;
1408		sshkey->rsa->p = pgpkey->key.seckey.key.rsa.p;
1409		sshkey->rsa->q = pgpkey->key.seckey.key.rsa.q;
1410		sshkey->rsa->iqmp = pgpkey->key.seckey.key.rsa.u;
1411		break;
1412	case OPS_PKA_DSA:
1413		sshkey->type = KEY_DSA;
1414		sshkey->dsa = calloc(1, sizeof(*sshkey->dsa);
1415		if (sshkey->dsa == NULL) {
1416			(void) fprintf(stderr, "DSA memory problems\n");
1417			return 0;
1418		}
1419		sshkey->rsa->n = pgpkey->key.pubkey.key.rsa.n;
1420		key->dsa->p = pgpkey->key.pubkey.key.dsa.p;
1421		key->dsa->q = pgpkey->key.pubkey.key.dsa.q;
1422		key->dsa->g = pgpkey->key.pubkey.key.dsa.g;
1423		key->dsa->pub_key = pgpkey->key.pubkey.key.dsa.y;
1424		key->dsa->priv_key = pgpkey->key.seckey.key.dsa.x;
1425		break;
1426	default:
1427		(void) fprintf(stderr, "weird type\n");
1428		return 0;
1429	}
1430	return 1;
1431}
1432#endif
1433