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