xref: /netbsd-src/crypto/external/bsd/netpgp/dist/src/lib/keyring.c (revision da9817918ec7e88db2912a2882967c7570a83f47)
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 /*
30  * Copyright (c) 2005-2008 Nominet UK (www.nic.uk)
31  * All rights reserved.
32  * Contributors: Ben Laurie, Rachel Willmer. The Contributors have asserted
33  * their moral rights under the UK Copyright Design and Patents Act 1988 to
34  * be recorded as the authors of this copyright work.
35  *
36  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
37  * use this file except in compliance with the License.
38  *
39  * You may obtain a copy of the License at
40  *     http://www.apache.org/licenses/LICENSE-2.0
41  *
42  * Unless required by applicable law or agreed to in writing, software
43  * distributed under the License is distributed on an "AS IS" BASIS,
44  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
45  *
46  * See the License for the specific language governing permissions and
47  * limitations under the License.
48  */
49 
50 /** \file
51  */
52 #include "config.h"
53 
54 #ifdef HAVE_SYS_CDEFS_H
55 #include <sys/cdefs.h>
56 #endif
57 
58 #if defined(__NetBSD__)
59 __COPYRIGHT("@(#) Copyright (c) 2009 The NetBSD Foundation, Inc. All rights reserved.");
60 __RCSID("$NetBSD: keyring.c,v 1.20 2009/06/11 04:57:52 agc Exp $");
61 #endif
62 
63 #ifdef HAVE_FCNTL_H
64 #include <fcntl.h>
65 #endif
66 
67 #include <stdlib.h>
68 #include <string.h>
69 
70 #ifdef HAVE_TERMIOS_H
71 #include <termios.h>
72 #endif
73 
74 #ifdef HAVE_UNISTD_H
75 #include <unistd.h>
76 #endif
77 
78 #include "types.h"
79 #include "keyring.h"
80 #include "packet-parse.h"
81 #include "signature.h"
82 #include "netpgpsdk.h"
83 #include "readerwriter.h"
84 #include "netpgpdefs.h"
85 #include "packet.h"
86 #include "crypto.h"
87 #include "validate.h"
88 #include "netpgpdigest.h"
89 
90 
91 
92 /**
93    \ingroup HighLevel_Keyring
94 
95    \brief Creates a new __ops_key_t struct
96 
97    \return A new __ops_key_t struct, initialised to zero.
98 
99    \note The returned __ops_key_t struct must be freed after use with __ops_keydata_free.
100 */
101 
102 __ops_key_t  *
103 __ops_keydata_new(void)
104 {
105 	return calloc(1, sizeof(__ops_key_t));
106 }
107 
108 
109 /**
110  \ingroup HighLevel_Keyring
111 
112  \brief Frees keydata and its memory
113 
114  \param keydata Key to be freed.
115 
116  \note This frees the keydata itself, as well as any other memory alloc-ed by it.
117 */
118 void
119 __ops_keydata_free(__ops_key_t *keydata)
120 {
121 	unsigned        n;
122 
123 	for (n = 0; n < keydata->uidc; ++n) {
124 		__ops_userid_free(&keydata->uids[n]);
125 	}
126 	(void) free(keydata->uids);
127 	keydata->uids = NULL;
128 	keydata->uidc = 0;
129 
130 	for (n = 0; n < keydata->packetc; ++n) {
131 		__ops_subpacket_free(&keydata->packets[n]);
132 	}
133 	(void) free(keydata->packets);
134 	keydata->packets = NULL;
135 	keydata->packetc = 0;
136 
137 	if (keydata->type == OPS_PTAG_CT_PUBLIC_KEY) {
138 		__ops_pubkey_free(&keydata->key.pubkey);
139 	} else {
140 		__ops_seckey_free(&keydata->key.seckey);
141 	}
142 
143 	(void) free(keydata);
144 }
145 
146 /**
147  \ingroup HighLevel_KeyGeneral
148 
149  \brief Returns the public key in the given keydata.
150  \param keydata
151 
152   \return Pointer to public key
153 
154   \note This is not a copy, do not free it after use.
155 */
156 
157 const __ops_pubkey_t *
158 __ops_get_pubkey(const __ops_key_t *keydata)
159 {
160 	return (keydata->type == OPS_PTAG_CT_PUBLIC_KEY) ?
161 				&keydata->key.pubkey :
162 				&keydata->key.seckey.pubkey;
163 }
164 
165 /**
166 \ingroup HighLevel_KeyGeneral
167 
168 \brief Check whether this is a secret key or not.
169 */
170 
171 unsigned
172 __ops_is_key_secret(const __ops_key_t *data)
173 {
174 	return data->type != OPS_PTAG_CT_PUBLIC_KEY;
175 }
176 
177 /**
178  \ingroup HighLevel_KeyGeneral
179 
180  \brief Returns the secret key in the given keydata.
181 
182  \note This is not a copy, do not free it after use.
183 
184  \note This returns a const.  If you need to be able to write to this
185  pointer, use __ops_get_writable_seckey
186 */
187 
188 const __ops_seckey_t *
189 __ops_get_seckey(const __ops_key_t *data)
190 {
191 	return (data->type == OPS_PTAG_CT_SECRET_KEY) ?
192 				&data->key.seckey : NULL;
193 }
194 
195 /**
196  \ingroup HighLevel_KeyGeneral
197 
198   \brief Returns the secret key in the given keydata.
199 
200   \note This is not a copy, do not free it after use.
201 
202   \note If you do not need to be able to modify this key, there is an
203   equivalent read-only function __ops_get_seckey.
204 */
205 
206 __ops_seckey_t *
207 __ops_get_writable_seckey(__ops_key_t *data)
208 {
209 	return (data->type == OPS_PTAG_CT_SECRET_KEY) ?
210 				&data->key.seckey : NULL;
211 }
212 
213 /* utility function to zero out memory */
214 void
215 __ops_forget(void *vp, unsigned size)
216 {
217 	(void) memset(vp, 0x0, size);
218 }
219 
220 typedef struct {
221 	const __ops_key_t	*key;
222 	char			*passphrase;
223 	__ops_seckey_t		*seckey;
224 } decrypt_t;
225 
226 static __ops_cb_ret_t
227 decrypt_cb(const __ops_packet_t *pkt, __ops_cbdata_t *cbinfo)
228 {
229 	const __ops_contents_t	*content = &pkt->u;
230 	decrypt_t		*decrypt;
231 	char			 pass[MAX_PASSPHRASE_LENGTH];
232 
233 	decrypt = __ops_callback_arg(cbinfo);
234 	switch (pkt->tag) {
235 	case OPS_PARSER_PTAG:
236 	case OPS_PTAG_CT_USER_ID:
237 	case OPS_PTAG_CT_SIGNATURE:
238 	case OPS_PTAG_CT_SIGNATURE_HEADER:
239 	case OPS_PTAG_CT_SIGNATURE_FOOTER:
240 	case OPS_PTAG_CT_TRUST:
241 		break;
242 
243 	case OPS_GET_PASSPHRASE:
244 		(void) __ops_getpassphrase(NULL, pass, sizeof(pass));
245 		*content->skey_passphrase.passphrase = strdup(pass);
246 		return OPS_KEEP_MEMORY;
247 
248 	case OPS_PARSER_ERRCODE:
249 		switch (content->errcode.errcode) {
250 		case OPS_E_P_MPI_FORMAT_ERROR:
251 			/* Generally this means a bad passphrase */
252 			fprintf(stderr, "Bad passphrase!\n");
253 			return OPS_RELEASE_MEMORY;
254 
255 		case OPS_E_P_PACKET_CONSUMED:
256 			/* And this is because of an error we've accepted */
257 			return OPS_RELEASE_MEMORY;
258 		default:
259 			break;
260 		}
261 		(void) fprintf(stderr, "parse error: %s\n",
262 				__ops_errcode(content->errcode.errcode));
263 		return OPS_FINISHED;
264 
265 	case OPS_PARSER_ERROR:
266 		fprintf(stderr, "parse error: %s\n", content->error.error);
267 		return OPS_FINISHED;
268 
269 	case OPS_PTAG_CT_SECRET_KEY:
270 		decrypt->seckey = calloc(1, sizeof(*decrypt->seckey));
271 		decrypt->seckey->checkhash = calloc(1, OPS_CHECKHASH_SIZE);
272 		*decrypt->seckey = content->seckey;
273 		return OPS_KEEP_MEMORY;
274 
275 	case OPS_PARSER_PACKET_END:
276 		/* nothing to do */
277 		break;
278 
279 	default:
280 		fprintf(stderr, "Unexpected tag %d (0x%x)\n", pkt->tag,
281 			pkt->tag);
282 		return OPS_FINISHED;
283 	}
284 
285 	return OPS_RELEASE_MEMORY;
286 }
287 
288 /**
289 \ingroup Core_Keys
290 \brief Decrypts secret key from given keydata with given passphrase
291 \param key Key from which to get secret key
292 \param passphrase Passphrase to use to decrypt secret key
293 \return secret key
294 */
295 __ops_seckey_t *
296 __ops_decrypt_seckey(const __ops_key_t *key)
297 {
298 	__ops_stream_t	*stream;
299 	const int	 printerrors = 1;
300 	decrypt_t	 decrypt;
301 
302 	(void) memset(&decrypt, 0x0, sizeof(decrypt));
303 	decrypt.key = key;
304 	stream = __ops_new(sizeof(*stream));
305 	__ops_keydata_reader_set(stream, key);
306 	__ops_set_callback(stream, decrypt_cb, &decrypt);
307 	stream->readinfo.accumulate = 1;
308 	__ops_parse(stream, !printerrors);
309 	return decrypt.seckey;
310 }
311 
312 /**
313 \ingroup Core_Keys
314 \brief Set secret key in content
315 \param content Content to be set
316 \param key Keydata to get secret key from
317 */
318 void
319 __ops_set_seckey(__ops_contents_t *cont, const __ops_key_t *key)
320 {
321 	*cont->get_seckey.seckey = &key->key.seckey;
322 }
323 
324 /**
325 \ingroup Core_Keys
326 \brief Get Key ID from keydata
327 \param key Keydata to get Key ID from
328 \return Pointer to Key ID inside keydata
329 */
330 const unsigned char *
331 __ops_get_key_id(const __ops_key_t *key)
332 {
333 	return key->key_id;
334 }
335 
336 /**
337 \ingroup Core_Keys
338 \brief How many User IDs in this key?
339 \param key Keydata to check
340 \return Num of user ids
341 */
342 unsigned
343 __ops_get_userid_count(const __ops_key_t *key)
344 {
345 	return key->uidc;
346 }
347 
348 /**
349 \ingroup Core_Keys
350 \brief Get indexed user id from key
351 \param key Key to get user id from
352 \param index Which key to get
353 \return Pointer to requested user id
354 */
355 const unsigned char *
356 __ops_get_userid(const __ops_key_t *key, unsigned subscript)
357 {
358 	return key->uids[subscript].userid;
359 }
360 
361 /**
362    \ingroup HighLevel_Supported
363    \brief Checks whether key's algorithm and type are supported by OpenPGP::SDK
364    \param keydata Key to be checked
365    \return 1 if key algorithm and type are supported by OpenPGP::SDK; 0 if not
366 */
367 
368 unsigned
369 __ops_is_key_supported(const __ops_key_t *key)
370 {
371 	if (key->type == OPS_PTAG_CT_PUBLIC_KEY) {
372 		if (key->key.pubkey.alg == OPS_PKA_RSA) {
373 			return 1;
374 		}
375 	} else if (key->type == OPS_PTAG_CT_PUBLIC_KEY) {
376 		if (key->key.pubkey.alg == OPS_PKA_DSA) {
377 			return 1;
378 		}
379 	}
380 	return 0;
381 }
382 
383 /* \todo check where userid pointers are copied */
384 /**
385 \ingroup Core_Keys
386 \brief Copy user id, including contents
387 \param dst Destination User ID
388 \param src Source User ID
389 \note If dst already has a userid, it will be freed.
390 */
391 static __ops_userid_t *
392 __ops_copy_userid(__ops_userid_t *dst, const __ops_userid_t *src)
393 {
394 	size_t          len = strlen((char *) src->userid);
395 
396 	if (dst->userid) {
397 		(void) free(dst->userid);
398 	}
399 	dst->userid = calloc(1, len + 1);
400 	(void) memcpy(dst->userid, src->userid, len);
401 	return dst;
402 }
403 
404 /* \todo check where pkt pointers are copied */
405 /**
406 \ingroup Core_Keys
407 \brief Copy packet, including contents
408 \param dst Destination packet
409 \param src Source packet
410 \note If dst already has a packet, it will be freed.
411 */
412 static __ops_subpacket_t *
413 __ops_copy_packet(__ops_subpacket_t *dst, const __ops_subpacket_t *src)
414 {
415 	if (dst->raw) {
416 		(void) free(dst->raw);
417 	}
418 	dst->raw = calloc(1, src->length);
419 	dst->length = src->length;
420 	(void) memcpy(dst->raw, src->raw, src->length);
421 	return dst;
422 }
423 
424 /**
425 \ingroup Core_Keys
426 \brief Add User ID to key
427 \param key Key to which to add User ID
428 \param userid User ID to add
429 \return Pointer to new User ID
430 */
431 __ops_userid_t  *
432 __ops_add_userid(__ops_key_t *key, const __ops_userid_t *userid)
433 {
434 	__ops_userid_t  *uidp = NULL;
435 
436 	EXPAND_ARRAY(key, uid);
437 	/* initialise new entry in array */
438 	uidp = &key->uids[key->uidc++];
439 	uidp->userid = NULL;
440 	/* now copy it */
441 	return __ops_copy_userid(uidp, userid);
442 }
443 
444 /**
445 \ingroup Core_Keys
446 \brief Add packet to key
447 \param keydata Key to which to add packet
448 \param packet Packet to add
449 \return Pointer to new packet
450 */
451 __ops_subpacket_t   *
452 __ops_add_subpacket(__ops_key_t *keydata, const __ops_subpacket_t *packet)
453 {
454 	__ops_subpacket_t   *subpktp = NULL;
455 
456 	EXPAND_ARRAY(keydata, packet);
457 
458 	/* initialise new entry in array */
459 	subpktp = &keydata->packets[keydata->packetc++];
460 	subpktp->length = 0;
461 	subpktp->raw = NULL;
462 	/* now copy it */
463 	return __ops_copy_packet(subpktp, packet);
464 }
465 
466 /**
467 \ingroup Core_Keys
468 \brief Add signed User ID to key
469 \param keydata Key to which to add signed User ID
470 \param userid User ID to add
471 \param sigpacket Packet to add
472 */
473 void
474 __ops_add_signed_userid(__ops_key_t *keydata,
475 		const __ops_userid_t *userid,
476 		const __ops_subpacket_t *sigpacket)
477 {
478 	__ops_subpacket_t	*pkt = NULL;
479 	__ops_userid_t		*uid = NULL;
480 
481 	uid = __ops_add_userid(keydata, userid);
482 	pkt = __ops_add_subpacket(keydata, sigpacket);
483 
484 	/*
485          * add entry in sigs array to link the userid and sigpacket
486 	 * and add ptr to it from the sigs array */
487 	EXPAND_ARRAY(keydata, sig);
488 
489 	/**setup new entry in array */
490 	keydata->sigs[keydata->sigc].userid = uid;
491 	keydata->sigs[keydata->sigc].packet = pkt;
492 
493 	keydata->sigc++;
494 }
495 
496 /**
497 \ingroup Core_Keys
498 \brief Add selfsigned User ID to key
499 \param keydata Key to which to add user ID
500 \param userid Self-signed User ID to add
501 \return 1 if OK; else 0
502 */
503 unsigned
504 __ops_add_selfsigned_userid(__ops_key_t *keydata, __ops_userid_t *userid)
505 {
506 	__ops_create_sig_t	*sig = NULL;
507 	__ops_subpacket_t	 sigpacket;
508 	__ops_memory_t		*mem_userid = NULL;
509 	__ops_output_t		*useridoutput = NULL;
510 	__ops_memory_t		*mem_sig = NULL;
511 	__ops_output_t		*sigoutput = NULL;
512 
513 	/*
514          * create signature packet for this userid
515          */
516 
517 	/* create userid pkt */
518 	__ops_setup_memory_write(&useridoutput, &mem_userid, 128);
519 	__ops_write_struct_userid(useridoutput, userid);
520 
521 	/* create sig for this pkt */
522 	sig = __ops_create_sig_new();
523 	__ops_sig_start_key_sig(sig, &keydata->key.seckey.pubkey, userid,
524 					OPS_CERT_POSITIVE);
525 	__ops_add_birthtime(sig, time(NULL));
526 	__ops_add_issuer_keyid(sig, keydata->key_id);
527 	__ops_add_primary_userid(sig, 1);
528 	__ops_end_hashed_subpkts(sig);
529 
530 	__ops_setup_memory_write(&sigoutput, &mem_sig, 128);
531 	__ops_write_sig(sigoutput, sig, &keydata->key.seckey.pubkey,
532 				&keydata->key.seckey);
533 
534 	/* add this packet to keydata */
535 	sigpacket.length = __ops_mem_len(mem_sig);
536 	sigpacket.raw = __ops_mem_data(mem_sig);
537 
538 	/* add userid to keydata */
539 	__ops_add_signed_userid(keydata, userid, &sigpacket);
540 
541 	/* cleanup */
542 	__ops_create_sig_delete(sig);
543 	__ops_output_delete(useridoutput);
544 	__ops_output_delete(sigoutput);
545 	__ops_memory_free(mem_userid);
546 	__ops_memory_free(mem_sig);
547 
548 	return 1;
549 }
550 
551 /**
552 \ingroup Core_Keys
553 \brief Initialise __ops_key_t
554 \param keydata Keydata to initialise
555 \param type OPS_PTAG_CT_PUBLIC_KEY or OPS_PTAG_CT_SECRET_KEY
556 */
557 void
558 __ops_keydata_init(__ops_key_t *keydata, const __ops_content_tag_t type)
559 {
560 	if (keydata->type != OPS_PTAG_CT_RESERVED) {
561 		(void) fprintf(stderr,
562 			"__ops_keydata_init: wrong keydata type\n");
563 	} else if (type != OPS_PTAG_CT_PUBLIC_KEY &&
564 		   type != OPS_PTAG_CT_SECRET_KEY) {
565 		(void) fprintf(stderr, "__ops_keydata_init: wrong type\n");
566 	} else {
567 		keydata->type = type;
568 	}
569 }
570 
571 
572 static __ops_cb_ret_t
573 cb_keyring_read(const __ops_packet_t *pkt, __ops_cbdata_t *cbinfo)
574 {
575 	__OPS_USED(cbinfo);
576 
577 	switch (pkt->tag) {
578 	case OPS_PARSER_PTAG:
579 	case OPS_PTAG_CT_ENCRYPTED_SECRET_KEY:	/* we get these because we
580 						 * didn't prompt */
581 	case OPS_PTAG_CT_SIGNATURE_HEADER:
582 	case OPS_PTAG_CT_SIGNATURE_FOOTER:
583 	case OPS_PTAG_CT_SIGNATURE:
584 	case OPS_PTAG_CT_TRUST:
585 	case OPS_PARSER_ERRCODE:
586 		break;
587 
588 	default:
589 		;
590 	}
591 
592 	return OPS_RELEASE_MEMORY;
593 }
594 
595 /**
596    \ingroup HighLevel_KeyringRead
597 
598    \brief Reads a keyring from a file
599 
600    \param keyring Pointer to an existing __ops_keyring_t struct
601    \param armour 1 if file is armoured; else 0
602    \param filename Filename of keyring to be read
603 
604    \return __ops 1 if OK; 0 on error
605 
606    \note Keyring struct must already exist.
607 
608    \note Can be used with either a public or secret keyring.
609 
610    \note You must call __ops_keyring_free() after usage to free alloc-ed memory.
611 
612    \note If you call this twice on the same keyring struct, without calling
613    __ops_keyring_free() between these calls, you will introduce a memory leak.
614 
615    \sa __ops_keyring_read_from_mem()
616    \sa __ops_keyring_free()
617 
618 */
619 
620 unsigned
621 __ops_keyring_fileread(__ops_keyring_t *keyring,
622 			const unsigned armour,
623 			const char *filename)
624 {
625 	__ops_stream_t	*stream;
626 	unsigned		 res = 1;
627 	int			 fd;
628 
629 	stream = __ops_new(sizeof(*stream));
630 
631 	/* add this for the moment, */
632 	/*
633 	 * \todo need to fix the problems with reading signature subpackets
634 	 * later
635 	 */
636 
637 	/* __ops_parse_options(parse,OPS_PTAG_SS_ALL,OPS_PARSE_RAW); */
638 	__ops_parse_options(stream, OPS_PTAG_SS_ALL, OPS_PARSE_PARSED);
639 
640 #ifdef O_BINARY
641 	fd = open(filename, O_RDONLY | O_BINARY);
642 #else
643 	fd = open(filename, O_RDONLY);
644 #endif
645 	if (fd < 0) {
646 		__ops_stream_delete(stream);
647 		perror(filename);
648 		return 0;
649 	}
650 #ifdef USE_MMAP_FOR_FILES
651 	__ops_reader_set_mmap(stream, fd);
652 #else
653 	__ops_reader_set_fd(stream, fd);
654 #endif
655 
656 	__ops_set_callback(stream, cb_keyring_read, NULL);
657 
658 	if (armour) {
659 		__ops_reader_push_dearmour(stream);
660 	}
661 	if (__ops_parse_and_accumulate(keyring, stream) == 0) {
662 		res = 0;
663 	} else {
664 		res = 1;
665 	}
666 	__ops_print_errors(__ops_stream_get_errors(stream));
667 
668 	if (armour)
669 		__ops_reader_pop_dearmour(stream);
670 
671 	close(fd);
672 
673 	__ops_stream_delete(stream);
674 
675 	return res;
676 }
677 
678 /**
679    \ingroup HighLevel_KeyringRead
680 
681    \brief Reads a keyring from memory
682 
683    \param keyring Pointer to existing __ops_keyring_t struct
684    \param armour 1 if file is armoured; else 0
685    \param mem Pointer to a __ops_memory_t struct containing keyring to be read
686 
687    \return __ops 1 if OK; 0 on error
688 
689    \note Keyring struct must already exist.
690 
691    \note Can be used with either a public or secret keyring.
692 
693    \note You must call __ops_keyring_free() after usage to free alloc-ed memory.
694 
695    \note If you call this twice on the same keyring struct, without calling
696    __ops_keyring_free() between these calls, you will introduce a memory leak.
697 
698    \sa __ops_keyring_fileread
699    \sa __ops_keyring_free
700 */
701 unsigned
702 __ops_keyring_read_from_mem(__ops_io_t *io,
703 				__ops_keyring_t *keyring,
704 				const unsigned armour,
705 				__ops_memory_t *mem)
706 {
707 	__ops_stream_t	*stream = NULL;
708 	const unsigned		 noaccum = 0;
709 	unsigned		 res = 1;
710 
711 	stream = __ops_new(sizeof(*stream));
712 	__ops_parse_options(stream, OPS_PTAG_SS_ALL, OPS_PARSE_PARSED);
713 	__ops_setup_memory_read(io, &stream, mem, NULL, cb_keyring_read,
714 					noaccum);
715 	if (armour) {
716 		__ops_reader_push_dearmour(stream);
717 	}
718 	res = __ops_parse_and_accumulate(keyring, stream);
719 	__ops_print_errors(__ops_stream_get_errors(stream));
720 	if (armour) {
721 		__ops_reader_pop_dearmour(stream);
722 	}
723 	/* don't call teardown_memory_read because memory was passed in */
724 	__ops_stream_delete(stream);
725 	return res;
726 }
727 
728 /**
729    \ingroup HighLevel_KeyringRead
730 
731    \brief Frees keyring's contents (but not keyring itself)
732 
733    \param keyring Keyring whose data is to be freed
734 
735    \note This does not free keyring itself, just the memory alloc-ed in it.
736  */
737 void
738 __ops_keyring_free(__ops_keyring_t *keyring)
739 {
740 	(void)free(keyring->keys);
741 	keyring->keys = NULL;
742 	keyring->keyc = keyring->keyvsize = 0;
743 }
744 
745 /**
746    \ingroup HighLevel_KeyringFind
747 
748    \brief Finds key in keyring from its Key ID
749 
750    \param keyring Keyring to be searched
751    \param keyid ID of required key
752 
753    \return Pointer to key, if found; NULL, if not found
754 
755    \note This returns a pointer to the key inside the given keyring,
756    not a copy.  Do not free it after use.
757 
758 */
759 const __ops_key_t *
760 __ops_getkeybyid(__ops_io_t *io, const __ops_keyring_t *keyring,
761 			   const unsigned char keyid[OPS_KEY_ID_SIZE])
762 {
763 	unsigned	 n;
764 
765 	for (n = 0; keyring && n < keyring->keyc; n++) {
766 		if (__ops_get_debug_level(__FILE__)) {
767 			int	i;
768 
769 			(void) fprintf(io->errs,
770 				"__ops_getkeybyid: keyring keyid ");
771 			for (i = 0 ; i < OPS_KEY_ID_SIZE ; i++) {
772 				(void) fprintf(io->errs, "%02x",
773 					keyring->keys[n].key_id[i]);
774 			}
775 			(void) fprintf(io->errs, ", keyid ");
776 			for (i = 0 ; i < OPS_KEY_ID_SIZE ; i++) {
777 				(void) fprintf(io->errs, "%02x", keyid[i]);
778 			}
779 			(void) fprintf(io->errs, "\n");
780 		}
781 		if (memcmp(keyring->keys[n].key_id, keyid,
782 				OPS_KEY_ID_SIZE) == 0) {
783 			return &keyring->keys[n];
784 		}
785 		if (memcmp(&keyring->keys[n].key_id[OPS_KEY_ID_SIZE / 2],
786 				keyid, OPS_KEY_ID_SIZE / 2) == 0) {
787 			return &keyring->keys[n];
788 		}
789 	}
790 	return NULL;
791 }
792 
793 /* convert a string keyid into a binary keyid */
794 static void
795 str2keyid(const char *userid, unsigned char *keyid, size_t len)
796 {
797 	static const char	*uppers = "0123456789ABCDEF";
798 	static const char	*lowers = "0123456789abcdef";
799 	unsigned char		 hichar;
800 	unsigned char		 lochar;
801 	size_t			 j;
802 	const char		*hi;
803 	const char		*lo;
804 	int			 i;
805 
806 	for (i = j = 0 ; j < len && userid[i] && userid[i + 1] ; i += 2, j++) {
807 		if ((hi = strchr(uppers, userid[i])) == NULL) {
808 			if ((hi = strchr(lowers, userid[i])) == NULL) {
809 				break;
810 			}
811 			hichar = (hi - lowers);
812 		} else {
813 			hichar = (hi - uppers);
814 		}
815 		if ((lo = strchr(uppers, userid[i + 1])) == NULL) {
816 			if ((lo = strchr(lowers, userid[i + 1])) == NULL) {
817 				break;
818 			}
819 			lochar = (lo - lowers);
820 		} else {
821 			lochar = (lo - uppers);
822 		}
823 		keyid[j] = (hichar << 4) | (lochar);
824 	}
825 	keyid[j] = 0x0;
826 }
827 
828 /**
829    \ingroup HighLevel_KeyringFind
830 
831    \brief Finds key from its User ID
832 
833    \param keyring Keyring to be searched
834    \param userid User ID of required key
835 
836    \return Pointer to Key, if found; NULL, if not found
837 
838    \note This returns a pointer to the key inside the keyring, not a
839    copy.  Do not free it.
840 
841 */
842 const __ops_key_t *
843 __ops_getkeybyname(__ops_io_t *io,
844 			const __ops_keyring_t *keyring,
845 			const char *name)
846 {
847 	const __ops_key_t	*kp;
848 	__ops_key_t		*keyp;
849 	__ops_userid_t		*uidp;
850 	unsigned char		 keyid[OPS_KEY_ID_SIZE + 1];
851 	unsigned int    	 i = 0;
852 	size_t          	 len;
853 	char	                *cp;
854 	unsigned             	 n = 0;
855 
856 	if (!keyring) {
857 		return NULL;
858 	}
859 	len = strlen(name);
860 	n = 0;
861 	for (keyp = &keyring->keys[n]; n < keyring->keyc; ++n, keyp++) {
862 		for (i = 0, uidp = keyp->uids; i < keyp->uidc; i++, uidp++) {
863 			if (__ops_get_debug_level(__FILE__)) {
864 				(void) fprintf(io->outs,
865 					"[%d][%d] name %s, last '%d'\n",
866 					n, i, uidp->userid,
867 					uidp->userid[len]);
868 			}
869 			if (strncmp((char *) uidp->userid, name, len) == 0 &&
870 			    uidp->userid[len] == ' ') {
871 				return keyp;
872 			}
873 		}
874 	}
875 
876 	if (strchr(name, '@') == NULL) {
877 		/* no '@' sign */
878 		/* first try name as a keyid */
879 		(void) memset(keyid, 0x0, sizeof(keyid));
880 		str2keyid(name, keyid, sizeof(keyid));
881 		if (__ops_get_debug_level(__FILE__)) {
882 			(void) fprintf(io->outs,
883 				"name \"%s\", keyid %02x%02x%02x%02x\n",
884 				name,
885 				keyid[0], keyid[1], keyid[2], keyid[3]);
886 		}
887 		if ((kp = __ops_getkeybyid(io, keyring, keyid)) != NULL) {
888 			return kp;
889 		}
890 		/* match on full name */
891 		keyp = keyring->keys;
892 		for (n = 0; n < keyring->keyc; ++n, keyp++) {
893 			uidp = keyp->uids;
894 			for (i = 0 ; i < keyp->uidc; i++, uidp++) {
895 				if (__ops_get_debug_level(__FILE__)) {
896 					(void) fprintf(io->outs,
897 						"keyid \"%s\" len %"
898 						PRIsize "u, keyid[len] '%c'\n",
899 					       (char *) uidp->userid,
900 					       len, uidp->userid[len]);
901 				}
902 				if (strncasecmp((char *) uidp->userid, name,
903 					len) == 0 && uidp->userid[len] == ' ') {
904 					return keyp;
905 				}
906 			}
907 		}
908 	}
909 	/* match on <email@address> */
910 	keyp = keyring->keys;
911 	for (n = 0; n < keyring->keyc; ++n, keyp++) {
912 		for (i = 0, uidp = keyp->uids; i < keyp->uidc; i++, uidp++) {
913 			/*
914 			 * look for the rightmost '<', in case there is one
915 			 * in the comment field
916 			 */
917 			cp = strrchr((char *) uidp->userid, '<');
918 			if (cp != NULL) {
919 				if (__ops_get_debug_level(__FILE__)) {
920 					(void) fprintf(io->errs,
921 						"cp ,%s, name ,%s, len %"
922 						PRIsize "u ,%c,\n",
923 						cp + 1,
924 						name,
925 						len,
926 						*(cp + len + 1));
927 				}
928 				if (strncasecmp(cp + 1, name, len) == 0 &&
929 				    *(cp + len + 1) == '>') {
930 					return keyp;
931 				}
932 			}
933 		}
934 	}
935 	return NULL;
936 }
937 
938 /**
939    \ingroup HighLevel_KeyringList
940 
941    \brief Prints all keys in keyring to stdout.
942 
943    \param keyring Keyring to use
944 
945    \return none
946 */
947 int
948 __ops_keyring_list(__ops_io_t *io, const __ops_keyring_t *keyring)
949 {
950 	__ops_key_t		*key;
951 	unsigned		 n;
952 
953 	(void) fprintf(io->res, "%d keys\n", keyring->keyc);
954 	for (n = 0, key = keyring->keys; n < keyring->keyc; ++n, ++key) {
955 		if (__ops_is_key_secret(key)) {
956 			__ops_print_seckeydata(io, key);
957 		} else {
958 			__ops_print_pubkeydata(io, key);
959 		}
960 		(void) fputc('\n', io->res);
961 	}
962 	return 1;
963 }
964 
965 static unsigned
966 get_contents_type(const __ops_key_t *keydata)
967 {
968 	return keydata->type;
969 }
970 
971 /* this interface isn't right - hook into callback for getting passphrase */
972 int
973 __ops_export_key(const __ops_key_t *keydata, unsigned char *passphrase)
974 {
975 	__ops_output_t	*output;
976 	__ops_memory_t		*mem;
977 
978 	__ops_setup_memory_write(&output, &mem, 128);
979 	if (get_contents_type(keydata) == OPS_PTAG_CT_PUBLIC_KEY) {
980 		__ops_write_xfer_pubkey(output, keydata, 1);
981 	} else {
982 		__ops_write_xfer_seckey(output, keydata, passphrase,
983 					strlen((char *)passphrase), 1);
984 	}
985 	printf("%s", (char *) __ops_mem_data(mem));
986 	__ops_teardown_memory_write(output, mem);
987 	return 1;
988 }
989