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