xref: /netbsd-src/crypto/external/bsd/netpgp/dist/src/lib/netpgp.c (revision 1ca06f9c9235889e2ff6dc77279d01d151d70a9a)
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.32 2009/12/07 16:17:17 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 
86 /* read any gpg config file */
87 static int
88 conffile(netpgp_t *netpgp, char *homedir, char *userid, size_t length)
89 {
90 	regmatch_t	 matchv[10];
91 	regex_t		 keyre;
92 	char		 buf[BUFSIZ];
93 	FILE		*fp;
94 
95 	__OPS_USED(netpgp);
96 	(void) snprintf(buf, sizeof(buf), "%s/gpg.conf", homedir);
97 	if ((fp = fopen(buf, "r")) == NULL) {
98 		return 0;
99 	}
100 	(void) memset(&keyre, 0x0, sizeof(keyre));
101 	(void) regcomp(&keyre, "^[ \t]*default-key[ \t]+([0-9a-zA-F]+)",
102 		REG_EXTENDED);
103 	while (fgets(buf, sizeof(buf), fp) != NULL) {
104 		if (regexec(&keyre, buf, 10, matchv, 0) == 0) {
105 			(void) memcpy(userid, &buf[(int)matchv[1].rm_so],
106 				MIN((unsigned)(matchv[1].rm_eo -
107 						matchv[1].rm_so), length));
108 			(void) fprintf(stderr,
109 				"netpgp: default key set to \"%.*s\"\n",
110 				(int)(matchv[1].rm_eo - matchv[1].rm_so),
111 				&buf[(int)matchv[1].rm_so]);
112 		}
113 	}
114 	(void) fclose(fp);
115 	return 1;
116 }
117 
118 /* small function to pretty print an 8-character raw userid */
119 static char    *
120 userid_to_id(const unsigned char *userid, char *id)
121 {
122 	static const char *hexes = "0123456789abcdef";
123 	int		   i;
124 
125 	for (i = 0; i < 8 ; i++) {
126 		id[i * 2] = hexes[(unsigned)(userid[i] & 0xf0) >> 4];
127 		id[(i * 2) + 1] = hexes[userid[i] & 0xf];
128 	}
129 	id[8 * 2] = 0x0;
130 	return id;
131 }
132 
133 /* print out the successful signature information */
134 static void
135 resultp(__ops_io_t *io,
136 	const char *f,
137 	__ops_validation_t *res,
138 	__ops_keyring_t *ring)
139 {
140 	const __ops_key_t	*pubkey;
141 	unsigned		 from;
142 	unsigned		 i;
143 	char			 id[MAX_ID_LENGTH + 1];
144 
145 	for (i = 0; i < res->validc; i++) {
146 		(void) fprintf(io->res,
147 			"Good signature for %s made %susing %s key %s\n",
148 			f,
149 			ctime(&res->valid_sigs[i].birthtime),
150 			__ops_show_pka(res->valid_sigs[i].key_alg),
151 			userid_to_id(res->valid_sigs[i].signer_id, id));
152 		from = 0;
153 		pubkey = __ops_getkeybyid(io, ring,
154 			(const unsigned char *) res->valid_sigs[i].signer_id,
155 			&from);
156 		__ops_print_keydata(io, pubkey, "pub", &pubkey->key.pubkey);
157 	}
158 }
159 
160 /* check there's enough space in the arrays */
161 static int
162 size_arrays(netpgp_t *netpgp, unsigned needed)
163 {
164 	char	**temp;
165 
166 	if (netpgp->size == 0) {
167 		/* only get here first time around */
168 		netpgp->size = needed;
169 		if ((netpgp->name = calloc(sizeof(char *), needed)) == NULL) {
170 			(void) fprintf(stderr, "size_arrays: bad alloc\n");
171 			return 0;
172 		}
173 		if ((netpgp->value = calloc(sizeof(char *), needed)) == NULL) {
174 			free(netpgp->name);
175 			(void) fprintf(stderr, "size_arrays: bad alloc\n");
176 			return 0;
177 		}
178 	} else if (netpgp->c == netpgp->size) {
179 		/* only uses 'needed' when filled array */
180 		netpgp->size += needed;
181 		temp = realloc(netpgp->name, sizeof(char *) * needed);
182 		if (temp == NULL) {
183 			(void) fprintf(stderr, "size_arrays: bad alloc\n");
184 			return 0;
185 		}
186 		netpgp->name = temp;
187 		temp = realloc(netpgp->value, sizeof(char *) * needed);
188 		if (temp == NULL) {
189 			(void) fprintf(stderr, "size_arrays: bad alloc\n");
190 			return 0;
191 		}
192 		netpgp->value = temp;
193 	}
194 	return 1;
195 }
196 
197 /* find the name in the array */
198 static int
199 findvar(netpgp_t *netpgp, const char *name)
200 {
201 	unsigned	i;
202 
203 	for (i = 0 ; i < netpgp->c && strcmp(netpgp->name[i], name) != 0; i++) {
204 	}
205 	return (i == netpgp->c) ? -1 : (int)i;
206 }
207 
208 /* read a keyring and return it */
209 static void *
210 readkeyring(netpgp_t *netpgp, const char *name)
211 {
212 	__ops_keyring_t	*keyring;
213 	const unsigned	 noarmor = 0;
214 	char		 f[MAXPATHLEN];
215 	char		*filename;
216 	char		*homedir;
217 
218 	homedir = netpgp_getvar(netpgp, "homedir");
219 	if ((filename = netpgp_getvar(netpgp, name)) == NULL) {
220 		(void) snprintf(f, sizeof(f), "%s/%s.gpg", homedir, name);
221 		filename = f;
222 	}
223 	if ((keyring = calloc(1, sizeof(*keyring))) == NULL) {
224 		(void) fprintf(stderr, "readkeyring: bad alloc\n");
225 		return NULL;
226 	}
227 	if (!__ops_keyring_fileread(keyring, noarmor, filename)) {
228 		free(keyring);
229 		(void) fprintf(stderr, "Can't read %s %s\n", name, filename);
230 		return NULL;
231 	}
232 	netpgp_setvar(netpgp, name, filename);
233 	return keyring;
234 }
235 
236 /* read keys from ssh key files */
237 static int
238 readsshkeys(netpgp_t *netpgp, const char *pubname, const char *secname)
239 {
240 	__ops_keyring_t	*pubring;
241 	__ops_keyring_t	*secring;
242 	char		 f[MAXPATHLEN];
243 	char		*filename;
244 	char		*etcdir;
245 
246 	__OPS_USED(secname);
247 	etcdir = netpgp_getvar(netpgp, "sshkeydir");
248 	if ((filename = netpgp_getvar(netpgp, pubname)) == NULL) {
249 		(void) snprintf(f, sizeof(f), "%s/ssh_host_rsa_key.pub", etcdir);
250 		filename = f;
251 	}
252 	if ((pubring = calloc(1, sizeof(*pubring))) == NULL) {
253 		(void) fprintf(stderr, "readsshkeys: bad alloc\n");
254 		return 0;
255 	}
256 	if (!__ops_ssh2_readkeys(netpgp->io, pubring, NULL, filename, NULL)) {
257 		free(pubring);
258 		(void) fprintf(stderr, "readsshkeys: can't read %s\n", filename);
259 		return 0;
260 	}
261 	netpgp->pubring = pubring;
262 	netpgp_setvar(netpgp, pubname, filename);
263 	if ((filename = netpgp_getvar(netpgp, secname)) == NULL) {
264 		(void) snprintf(f, sizeof(f), "%s/ssh_host_rsa_key", etcdir);
265 		filename = f;
266 	}
267 	if ((secring = calloc(1, sizeof(*secring))) == NULL) {
268 		(void) fprintf(stderr, "readsshkeys: bad alloc\n");
269 		return 0;
270 	}
271 	if (__ops_ssh2_readkeys(netpgp->io, pubring, secring, NULL, filename)) {
272 		netpgp->secring = secring;
273 		netpgp_setvar(netpgp, secname, filename);
274 	} else {
275 		(void) fprintf(stderr, "readsshkeys: can't read sec %s (%d)\n", filename, errno);
276 	}
277 	return 1;
278 }
279 
280 /***************************************************************************/
281 /* exported functions start here */
282 /***************************************************************************/
283 
284 /* initialise a netpgp_t structure */
285 int
286 netpgp_init(netpgp_t *netpgp)
287 {
288 	__ops_io_t	*io;
289 	char		 id[MAX_ID_LENGTH];
290 	char		*homedir;
291 	char		*userid;
292 	char		*stream;
293 	char		*passfd;
294 	char		*results;
295 	int		 coredumps;
296 
297 #ifdef HAVE_SYS_RESOURCE_H
298 	struct rlimit	limit;
299 
300 	coredumps = netpgp_getvar(netpgp, "coredumps") != NULL;
301 	if (!coredumps) {
302 		(void) memset(&limit, 0x0, sizeof(limit));
303 		if (setrlimit(RLIMIT_CORE, &limit) != 0) {
304 			(void) fprintf(stderr,
305 			"netpgp_init: warning - can't turn off core dumps\n");
306 			coredumps = 1;
307 		}
308 	}
309 #else
310 	coredumps = 1;
311 #endif
312 	if ((io = calloc(1, sizeof(*io))) == NULL) {
313 		(void) fprintf(stderr, "netpgp_init: bad alloc\n");
314 		return 0;
315 	}
316 	io->outs = stdout;
317 	if ((stream = netpgp_getvar(netpgp, "stdout")) != NULL &&
318 	    strcmp(stream, "stderr") == 0) {
319 		io->outs = stderr;
320 	}
321 	io->errs = stderr;
322 	if ((stream = netpgp_getvar(netpgp, "stderr")) != NULL &&
323 	    strcmp(stream, "stdout") == 0) {
324 		io->errs = stdout;
325 	}
326 	if ((results = netpgp_getvar(netpgp, "results")) == NULL) {
327 		io->res = io->errs;
328 	} else if ((io->res = fopen(results, "w")) == NULL) {
329 		(void) fprintf(io->errs, "Can't open results %s for writing\n",
330 			results);
331 		return 0;
332 	}
333 	netpgp->io = io;
334 	if (coredumps) {
335 		(void) fprintf(io->errs,
336 			"netpgp: warning: core dumps enabled\n");
337 	}
338 	if ((homedir = netpgp_getvar(netpgp, "homedir")) == NULL) {
339 		(void) fprintf(io->errs, "netpgp: bad homedir\n");
340 		return 0;
341 	}
342 	/* read from either gpg files or ssh keys */
343 	if (netpgp_getvar(netpgp, "ssh keys") == NULL) {
344 		if ((userid = netpgp_getvar(netpgp, "userid")) == NULL) {
345 			(void) memset(id, 0x0, sizeof(id));
346 			(void) conffile(netpgp, homedir, id, sizeof(id));
347 			if (id[0] != 0x0) {
348 				netpgp_setvar(netpgp, "userid", userid = id);
349 			}
350 		}
351 		if (userid == NULL) {
352 			if (netpgp_getvar(netpgp, "need userid") != NULL) {
353 				(void) fprintf(io->errs, "Cannot find user id\n");
354 				return 0;
355 			}
356 		} else {
357 			(void) netpgp_setvar(netpgp, "userid", userid);
358 		}
359 		if ((netpgp->pubring = readkeyring(netpgp, "pubring")) == NULL) {
360 			(void) fprintf(io->errs, "Can't read pub keyring\n");
361 			return 0;
362 		}
363 		if ((netpgp->secring = readkeyring(netpgp, "secring")) == NULL) {
364 			(void) fprintf(io->errs, "Can't read sec keyring\n");
365 			return 0;
366 		}
367 	} else {
368 		if (!readsshkeys(netpgp, "ssh pub key", "ssh sec file")) {
369 			(void) fprintf(io->errs, "Can't read ssh pub key\n");
370 			return 0;
371 		}
372 		if ((userid = netpgp_getvar(netpgp, "userid")) == NULL) {
373 			/* set ssh uid to first one in ring */
374 			__ops_keyring_t	*pubring;
375 			unsigned char	*src;
376 			int		 i;
377 			int		 n;
378 
379 			pubring = netpgp->pubring;
380 			(void) memset(id, 0x0, sizeof(id));
381 			src = pubring->keys[0].key_id;
382 			for (i = 0, n = 0 ; i < OPS_KEY_ID_SIZE ; i += 2) {
383 				n += snprintf(&id[n], sizeof(id) - n, "%02x%02x", src[i], src[i + 1]);
384 			}
385 			id[n] = 0x0;
386 			netpgp_setvar(netpgp, "userid", userid = id);
387 		}
388 		if (userid == NULL) {
389 			if (netpgp_getvar(netpgp, "need userid") != NULL) {
390 				(void) fprintf(io->errs, "Cannot find user id\n");
391 				return 0;
392 			}
393 		} else {
394 			(void) netpgp_setvar(netpgp, "userid", userid);
395 		}
396 	}
397 	if ((passfd = netpgp_getvar(netpgp, "pass-fd")) != NULL &&
398 	    (netpgp->passfp = fdopen(atoi(passfd), "r")) == NULL) {
399 		(void) fprintf(io->errs, "Can't open fd %s for reading\n",
400 			passfd);
401 		return 0;
402 	}
403 	return 1;
404 }
405 
406 /* finish off with the netpgp_t struct */
407 int
408 netpgp_end(netpgp_t *netpgp)
409 {
410 	unsigned	i;
411 
412 	for (i = 0 ; i < netpgp->c ; i++) {
413 		if (netpgp->name[i] != NULL) {
414 			free(netpgp->name[i]);
415 		}
416 		if (netpgp->value[i] != NULL) {
417 			free(netpgp->value[i]);
418 		}
419 	}
420 	if (netpgp->name != NULL) {
421 		free(netpgp->name);
422 	}
423 	if (netpgp->value != NULL) {
424 		free(netpgp->value);
425 	}
426 	if (netpgp->pubring != NULL) {
427 		__ops_keyring_free(netpgp->pubring);
428 	}
429 	if (netpgp->secring != NULL) {
430 		__ops_keyring_free(netpgp->secring);
431 	}
432 	free(netpgp->io);
433 	return 1;
434 }
435 
436 /* list the keys in a keyring */
437 int
438 netpgp_list_keys(netpgp_t *netpgp)
439 {
440 	return __ops_keyring_list(netpgp->io, netpgp->pubring);
441 }
442 
443 /* find and list some keys in a keyring */
444 int
445 netpgp_match_list_keys(netpgp_t *netpgp, char *name)
446 {
447 	const __ops_key_t	*key;
448 	unsigned		 found;
449 	unsigned		 k;
450 	char			*data;
451 
452 	found = k = 0;
453 	do {
454 		if ((key = __ops_getnextkeybyname(netpgp->io, netpgp->pubring, name, &k)) != NULL) {
455 			__ops_sprint_keydata(key, &data, "pub", &key->key.pubkey);
456 			printf("%s\n", data);
457 			free(data);
458 			found += 1;
459 			k += 1;
460 		}
461 	} while (key != NULL);
462 	printf("Found %u key%s\n", found, (found == 1) ? "" : "s");
463 	return (found > 0);
464 }
465 
466 /* find a key in a keyring */
467 int
468 netpgp_find_key(netpgp_t *netpgp, char *id)
469 {
470 	__ops_io_t	*io;
471 
472 	io = netpgp->io;
473 	if (id == NULL) {
474 		(void) fprintf(io->errs, "NULL id to search for\n");
475 		return 0;
476 	}
477 	return __ops_getkeybyname(netpgp->io, netpgp->pubring, id) != NULL;
478 }
479 
480 /* get a key in a keyring */
481 char *
482 netpgp_get_key(netpgp_t *netpgp, const char *id)
483 {
484 	const __ops_key_t	*key;
485 	__ops_io_t		*io;
486 	char			*newkey;
487 
488 	io = netpgp->io;
489 	if (id == NULL) {
490 		(void) fprintf(io->errs, "NULL id to search for\n");
491 		return NULL;
492 	}
493 	if ((key = __ops_getkeybyname(netpgp->io, netpgp->pubring, id)) == NULL) {
494 		(void) fprintf(io->errs, "Can't find key '%s'\n", id);
495 		return NULL;
496 	}
497 	return (__ops_sprint_keydata(key, &newkey, "pub", &key->key.pubkey) > 0) ? newkey : NULL;
498 }
499 
500 /* export a given key */
501 int
502 netpgp_export_key(netpgp_t *netpgp, char *userid)
503 {
504 	const __ops_key_t	*keypair;
505 	__ops_io_t		*io;
506 
507 	io = netpgp->io;
508 	if (userid == NULL) {
509 		userid = netpgp_getvar(netpgp, "userid");
510 	}
511 	keypair = __ops_getkeybyname(io, netpgp->pubring, userid);
512 	if (keypair == NULL) {
513 		(void) fprintf(io->errs,
514 			"Cannot find own key \"%s\" in keyring\n", userid);
515 		return 0;
516 	}
517 	return __ops_export_key(keypair, NULL);
518 }
519 
520 /* import a key into our keyring */
521 int
522 netpgp_import_key(netpgp_t *netpgp, char *f)
523 {
524 	const unsigned	noarmor = 0;
525 	const unsigned	armor = 1;
526 	__ops_io_t	*io;
527 	int		done;
528 
529 	io = netpgp->io;
530 	if ((done = __ops_keyring_fileread(netpgp->pubring, noarmor, f)) == 0) {
531 		done = __ops_keyring_fileread(netpgp->pubring, armor, f);
532 	}
533 	if (!done) {
534 		(void) fprintf(io->errs, "Cannot import key from file %s\n",
535 				f);
536 		return 0;
537 	}
538 	return __ops_keyring_list(io, netpgp->pubring);
539 }
540 
541 /* generate a new key */
542 int
543 netpgp_generate_key(netpgp_t *netpgp, char *id, int numbits)
544 {
545 	__ops_key_t		*keypair;
546 	__ops_userid_t		 uid;
547 	__ops_output_t		*create;
548 	const unsigned		 noarmor = 0;
549 	__ops_io_t		*io;
550 	char			*ringfile;
551 	int             	 fd;
552 
553 	(void) memset(&uid, 0x0, sizeof(uid));
554 	io = netpgp->io;
555 	/* generate a new key for 'id' */
556 	uid.userid = (unsigned char *) id;
557 	keypair = __ops_rsa_new_selfsign_key(numbits, 65537UL, &uid);
558 	if (keypair == NULL) {
559 		(void) fprintf(io->errs, "Cannot generate key\n");
560 		return 0;
561 	}
562 	/* write public key, and try to re-read it */
563 	ringfile = netpgp_getvar(netpgp, "pubring");
564 	fd = __ops_setup_file_append(&create, ringfile);
565 	if (!__ops_write_xfer_pubkey(create, keypair, noarmor)) {
566 		(void) fprintf(io->errs, "Cannot write pubkey\n");
567 		return 0;
568 	}
569 	__ops_teardown_file_write(create, fd);
570 	__ops_keyring_free(netpgp->pubring);
571 	if (!__ops_keyring_fileread(netpgp->pubring, noarmor, ringfile)) {
572 		(void) fprintf(io->errs, "Cannot read pubring %s\n", ringfile);
573 		return 0;
574 	}
575 	/* write secret key, and try to re-read it */
576 	ringfile = netpgp_getvar(netpgp, "sec ring file");
577 	fd = __ops_setup_file_append(&create, ringfile);
578 	if (!__ops_write_xfer_seckey(create, keypair, NULL, 0, noarmor)) {
579 		(void) fprintf(io->errs, "Cannot write seckey\n");
580 		return 0;
581 	}
582 	__ops_teardown_file_write(create, fd);
583 	__ops_keyring_free(netpgp->secring);
584 	if (!__ops_keyring_fileread(netpgp->secring, noarmor, ringfile)) {
585 		(void) fprintf(io->errs, "Can't read secring %s\n", ringfile);
586 		return 0;
587 	}
588 	__ops_keydata_free(keypair);
589 	return 1;
590 }
591 
592 /* encrypt a file */
593 int
594 netpgp_encrypt_file(netpgp_t *netpgp,
595 			const char *userid,
596 			const char *f,
597 			char *out,
598 			int armored)
599 {
600 	const __ops_key_t	*keypair;
601 	const unsigned		 overwrite = 1;
602 	const char		*suffix;
603 	__ops_io_t		*io;
604 	char			 outname[MAXPATHLEN];
605 
606 	io = netpgp->io;
607 	if (f == NULL) {
608 		(void) fprintf(io->errs,
609 			"netpgp_encrypt_file: no filename specified\n");
610 		return 0;
611 	}
612 	if (userid == NULL) {
613 		userid = netpgp_getvar(netpgp, "userid");
614 	}
615 	suffix = (armored) ? ".asc" : ".gpg";
616 	keypair = __ops_getkeybyname(io, netpgp->pubring, userid);
617 	if (keypair == NULL) {
618 		(void) fprintf(io->errs, "Userid '%s' not found in keyring\n",
619 					userid);
620 		return 0;
621 	}
622 	if (out == NULL) {
623 		(void) snprintf(outname, sizeof(outname), "%s%s", f, suffix);
624 		out = outname;
625 	}
626 	return (int)__ops_encrypt_file(io, f, out, keypair, (unsigned)armored,
627 					overwrite);
628 }
629 
630 /* decrypt a file */
631 int
632 netpgp_decrypt_file(netpgp_t *netpgp, const char *f, char *out, int armored)
633 {
634 	const unsigned	overwrite = 1;
635 	__ops_io_t		*io;
636 
637 	io = netpgp->io;
638 	if (f == NULL) {
639 		(void) fprintf(io->errs,
640 			"netpgp_decrypt_file: no filename specified\n");
641 		return 0;
642 	}
643 	return __ops_decrypt_file(netpgp->io, f, out, netpgp->secring,
644 				(unsigned)armored, overwrite, netpgp->passfp,
645 				get_passphrase_cb);
646 }
647 
648 /* sign a file */
649 int
650 netpgp_sign_file(netpgp_t *netpgp,
651 		const char *userid,
652 		const char *f,
653 		char *out,
654 		int armored,
655 		int cleartext,
656 		int detached)
657 {
658 	const __ops_key_t	*keypair;
659 	__ops_seckey_t		*seckey;
660 	const unsigned		 overwrite = 1;
661 	__ops_io_t		*io;
662 	char			*hashalg;
663 	int			 ret;
664 
665 	io = netpgp->io;
666 	if (f == NULL) {
667 		(void) fprintf(io->errs,
668 			"netpgp_sign_file: no filename specified\n");
669 		return 0;
670 	}
671 	if (userid == NULL) {
672 		userid = netpgp_getvar(netpgp, "userid");
673 	}
674 	/* get key with which to sign */
675 	keypair = __ops_getkeybyname(io, netpgp->secring, userid);
676 	if (keypair == NULL) {
677 		(void) fprintf(io->errs, "Userid '%s' not found in keyring\n",
678 				userid);
679 		return 0;
680 	}
681 	ret = 1;
682 	do {
683 		/* print out the user id */
684 		__ops_print_keydata(io, keypair, "pub", &keypair->key.pubkey);
685 		if (netpgp_getvar(netpgp, "ssh keys") == NULL) {
686 			/* now decrypt key */
687 			seckey = __ops_decrypt_seckey(keypair);
688 			if (seckey == NULL) {
689 				(void) fprintf(io->errs, "Bad passphrase\n");
690 			}
691 		} else {
692 			__ops_keyring_t	*secring;
693 
694 			secring = netpgp->secring;
695 			seckey = &secring->keys[0].key.seckey;
696 		}
697 	} while (seckey == NULL);
698 	/* sign file */
699 	hashalg = netpgp_getvar(netpgp, "hash");
700 	if (detached) {
701 		ret = __ops_sign_detached(io, f, out, seckey, hashalg);
702 	} else {
703 		ret = __ops_sign_file(io, f, out, seckey, hashalg,
704 				(unsigned)armored, (unsigned)cleartext, overwrite);
705 	}
706 	__ops_forget(seckey, sizeof(*seckey));
707 	return ret;
708 }
709 
710 /* verify a file */
711 int
712 netpgp_verify_file(netpgp_t *netpgp, const char *in, const char *out, int armored)
713 {
714 	__ops_validation_t	 result;
715 	__ops_io_t		*io;
716 
717 	(void) memset(&result, 0x0, sizeof(result));
718 	io = netpgp->io;
719 	if (in == NULL) {
720 		(void) fprintf(io->errs,
721 			"netpgp_verify_file: no filename specified\n");
722 		return 0;
723 	}
724 	if (__ops_validate_file(io, &result, in, out, armored,
725 						netpgp->pubring)) {
726 		resultp(io, in, &result, netpgp->pubring);
727 		return 1;
728 	}
729 	if (result.validc + result.invalidc + result.unknownc == 0) {
730 		(void) fprintf(io->errs,
731 		"\"%s\": No signatures found - is this a signed file?\n",
732 			in);
733 	} else {
734 		(void) fprintf(io->errs,
735 "\"%s\": verification failure: %u invalid signatures, %u unknown signatures\n",
736 			in, result.invalidc, result.unknownc);
737 	}
738 	return 0;
739 }
740 
741 /* sign some memory */
742 int
743 netpgp_sign_memory(netpgp_t *netpgp,
744 		const char *userid,
745 		char *mem,
746 		size_t size,
747 		char *out,
748 		size_t outsize,
749 		const unsigned armored,
750 		const unsigned cleartext)
751 {
752 	const __ops_key_t	*keypair;
753 	__ops_seckey_t		*seckey;
754 	__ops_memory_t		*signedmem;
755 	__ops_io_t		*io;
756 	char			*hashalg;
757 	int			 ret;
758 
759 	io = netpgp->io;
760 	if (mem == NULL) {
761 		(void) fprintf(io->errs,
762 			"netpgp_sign_memory: no memory to sign\n");
763 		return 0;
764 	}
765 	if (userid == NULL) {
766 		userid = netpgp_getvar(netpgp, "userid");
767 	}
768 	/* get key with which to sign */
769 	keypair = __ops_getkeybyname(io, netpgp->secring, userid);
770 	if (keypair == NULL) {
771 		(void) fprintf(io->errs, "Userid '%s' not found in keyring\n",
772 				userid);
773 		return 0;
774 	}
775 	ret = 1;
776 	do {
777 		/* print out the user id */
778 		__ops_print_keydata(io, keypair, "pub", &keypair->key.pubkey);
779 		/* now decrypt key */
780 		seckey = __ops_decrypt_seckey(keypair);
781 		if (seckey == NULL) {
782 			(void) fprintf(io->errs, "Bad passphrase\n");
783 		}
784 	} while (seckey == NULL);
785 	/* sign file */
786 	hashalg = netpgp_getvar(netpgp, "hash");
787 	signedmem = __ops_sign_buf(io, mem, size, seckey, hashalg,
788 						armored, cleartext);
789 	if (signedmem) {
790 		size_t	m;
791 
792 		m = MIN(__ops_mem_len(signedmem), outsize);
793 		(void) memcpy(out, __ops_mem_data(signedmem), m);
794 		__ops_memory_free(signedmem);
795 	}
796 	__ops_forget(seckey, sizeof(*seckey));
797 	return ret;
798 }
799 
800 /* verify memory */
801 int
802 netpgp_verify_memory(netpgp_t *netpgp, const void *in, const size_t size, const int armored)
803 {
804 	__ops_validation_t	 result;
805 	__ops_memory_t		*signedmem;
806 	__ops_io_t		*io;
807 	int			 ret;
808 
809 	(void) memset(&result, 0x0, sizeof(result));
810 	io = netpgp->io;
811 	if (in == NULL) {
812 		(void) fprintf(io->errs,
813 			"netpgp_verify_memory: no memory to verify\n");
814 		return 0;
815 	}
816 	signedmem = __ops_memory_new();
817 	__ops_memory_add(signedmem, in, size);
818 	ret = __ops_validate_mem(io, &result, signedmem, armored,
819 						netpgp->pubring);
820 	__ops_memory_free(signedmem);
821 	if (ret) {
822 		resultp(io, in, &result, netpgp->pubring);
823 		return 1;
824 	}
825 	if (result.validc + result.invalidc + result.unknownc == 0) {
826 		(void) fprintf(io->errs,
827 		"No signatures found - is this memory signed?\n");
828 	} else {
829 		(void) fprintf(io->errs,
830 "memory verification failure: %u invalid signatures, %u unknown signatures\n",
831 			result.invalidc, result.unknownc);
832 	}
833 	return 0;
834 }
835 
836 /* wrappers for the ops_debug_level functions we added to openpgpsdk */
837 
838 /* set the debugging level per filename */
839 int
840 netpgp_set_debug(const char *f)
841 {
842 	return __ops_set_debug_level(f);
843 }
844 
845 /* get the debugging level per filename */
846 int
847 netpgp_get_debug(const char *f)
848 {
849 	return __ops_get_debug_level(f);
850 }
851 
852 /* return the version for the library */
853 const char *
854 netpgp_get_info(const char *type)
855 {
856 	return __ops_get_info(type);
857 }
858 
859 /* list all the packets in a file */
860 int
861 netpgp_list_packets(netpgp_t *netpgp, char *f, int armour, char *pubringname)
862 {
863 	__ops_keyring_t	*keyring;
864 	const unsigned	 noarmor = 0;
865 	__ops_io_t	*io;
866 	char		 ringname[MAXPATHLEN];
867 	char		*homedir;
868 	int		 ret;
869 
870 	io = netpgp->io;
871 	if (f == NULL) {
872 		(void) fprintf(io->errs, "No file containing packets\n");
873 		return 0;
874 	}
875 	homedir = netpgp_getvar(netpgp, "homedir");
876 	if (pubringname == NULL) {
877 		(void) snprintf(ringname, sizeof(ringname),
878 				"%s/pubring.gpg", homedir);
879 		pubringname = ringname;
880 	}
881 	if ((keyring = calloc(1, sizeof(*keyring))) == NULL) {
882 		(void) fprintf(io->errs, "netpgp_list_packets: bad alloc\n");
883 		return 0;
884 	}
885 	if (!__ops_keyring_fileread(keyring, noarmor, pubringname)) {
886 		free(keyring);
887 		(void) fprintf(io->errs, "Cannot read pub keyring %s\n",
888 			pubringname);
889 		return 0;
890 	}
891 	netpgp->pubring = keyring;
892 	netpgp_setvar(netpgp, "pubring", pubringname);
893 	ret = __ops_list_packets(io, f, (unsigned)armour, keyring,
894 					netpgp->passfp,
895 					get_passphrase_cb);
896 	free(keyring);
897 	return ret;
898 }
899 
900 /* set a variable */
901 int
902 netpgp_setvar(netpgp_t *netpgp, const char *name, const char *value)
903 {
904 	int	i;
905 
906 	if ((i = findvar(netpgp, name)) < 0) {
907 		/* add the element to the array */
908 		if (size_arrays(netpgp, netpgp->size + 15)) {
909 			netpgp->name[i = netpgp->c++] = strdup(name);
910 		}
911 	} else {
912 		/* replace the element in the array */
913 		if (netpgp->value[i]) {
914 			free(netpgp->value[i]);
915 			netpgp->value[i] = NULL;
916 		}
917 	}
918 	/* sanity checks for range of values */
919 	if (strcmp(name, "hash") == 0 || strcmp(name, "algorithm") == 0) {
920 		if (__ops_str_to_hash_alg(value) == OPS_HASH_UNKNOWN) {
921 			return 0;
922 		}
923 	}
924 	netpgp->value[i] = strdup(value);
925 	return 1;
926 }
927 
928 /* get a variable's value (NULL if not set) */
929 char *
930 netpgp_getvar(netpgp_t *netpgp, const char *name)
931 {
932 	int	i;
933 
934 	return ((i = findvar(netpgp, name)) < 0) ? NULL : netpgp->value[i];
935 }
936