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