xref: /netbsd-src/crypto/external/bsd/netpgp/dist/src/lib/keyring.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 /*
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.23 2009/12/05 07:08:18 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 	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 	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 	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 		if ((decrypt->seckey = calloc(1, sizeof(*decrypt->seckey))) == NULL) {
271 			(void) fprintf(stderr, "decrypt_cb: bad alloc\n");
272 			return OPS_FINISHED;
273 		}
274 		decrypt->seckey->checkhash = calloc(1, OPS_CHECKHASH_SIZE);
275 		*decrypt->seckey = content->seckey;
276 		return OPS_KEEP_MEMORY;
277 
278 	case OPS_PARSER_PACKET_END:
279 		/* nothing to do */
280 		break;
281 
282 	default:
283 		fprintf(stderr, "Unexpected tag %d (0x%x)\n", pkt->tag,
284 			pkt->tag);
285 		return OPS_FINISHED;
286 	}
287 
288 	return OPS_RELEASE_MEMORY;
289 }
290 
291 /**
292 \ingroup Core_Keys
293 \brief Decrypts secret key from given keydata with given passphrase
294 \param key Key from which to get secret key
295 \param passphrase Passphrase to use to decrypt secret key
296 \return secret key
297 */
298 __ops_seckey_t *
299 __ops_decrypt_seckey(const __ops_key_t *key)
300 {
301 	__ops_stream_t	*stream;
302 	const int	 printerrors = 1;
303 	decrypt_t	 decrypt;
304 
305 	(void) memset(&decrypt, 0x0, sizeof(decrypt));
306 	decrypt.key = key;
307 	stream = __ops_new(sizeof(*stream));
308 	__ops_keydata_reader_set(stream, key);
309 	__ops_set_callback(stream, decrypt_cb, &decrypt);
310 	stream->readinfo.accumulate = 1;
311 	__ops_parse(stream, !printerrors);
312 	return decrypt.seckey;
313 }
314 
315 /**
316 \ingroup Core_Keys
317 \brief Set secret key in content
318 \param content Content to be set
319 \param key Keydata to get secret key from
320 */
321 void
322 __ops_set_seckey(__ops_contents_t *cont, const __ops_key_t *key)
323 {
324 	*cont->get_seckey.seckey = &key->key.seckey;
325 }
326 
327 /**
328 \ingroup Core_Keys
329 \brief Get Key ID from keydata
330 \param key Keydata to get Key ID from
331 \return Pointer to Key ID inside keydata
332 */
333 const unsigned char *
334 __ops_get_key_id(const __ops_key_t *key)
335 {
336 	return key->key_id;
337 }
338 
339 /**
340 \ingroup Core_Keys
341 \brief How many User IDs in this key?
342 \param key Keydata to check
343 \return Num of user ids
344 */
345 unsigned
346 __ops_get_userid_count(const __ops_key_t *key)
347 {
348 	return key->uidc;
349 }
350 
351 /**
352 \ingroup Core_Keys
353 \brief Get indexed user id from key
354 \param key Key to get user id from
355 \param index Which key to get
356 \return Pointer to requested user id
357 */
358 const unsigned char *
359 __ops_get_userid(const __ops_key_t *key, unsigned subscript)
360 {
361 	return key->uids[subscript].userid;
362 }
363 
364 /**
365    \ingroup HighLevel_Supported
366    \brief Checks whether key's algorithm and type are supported by OpenPGP::SDK
367    \param keydata Key to be checked
368    \return 1 if key algorithm and type are supported by OpenPGP::SDK; 0 if not
369 */
370 
371 unsigned
372 __ops_is_key_supported(const __ops_key_t *key)
373 {
374 	if (key->type == OPS_PTAG_CT_PUBLIC_KEY) {
375 		if (key->key.pubkey.alg == OPS_PKA_RSA) {
376 			return 1;
377 		}
378 	} else if (key->type == OPS_PTAG_CT_PUBLIC_KEY) {
379 		if (key->key.pubkey.alg == OPS_PKA_DSA) {
380 			return 1;
381 		}
382 	}
383 	return 0;
384 }
385 
386 /* \todo check where userid pointers are copied */
387 /**
388 \ingroup Core_Keys
389 \brief Copy user id, including contents
390 \param dst Destination User ID
391 \param src Source User ID
392 \note If dst already has a userid, it will be freed.
393 */
394 static __ops_userid_t *
395 __ops_copy_userid(__ops_userid_t *dst, const __ops_userid_t *src)
396 {
397 	size_t          len = strlen((char *) src->userid);
398 
399 	if (dst->userid) {
400 		free(dst->userid);
401 	}
402 	if ((dst->userid = calloc(1, len + 1)) == NULL) {
403 		(void) fprintf(stderr, "__ops_copy_userid: bad alloc\n");
404 	} else {
405 		(void) memcpy(dst->userid, src->userid, len);
406 	}
407 	return dst;
408 }
409 
410 /* \todo check where pkt pointers are copied */
411 /**
412 \ingroup Core_Keys
413 \brief Copy packet, including contents
414 \param dst Destination packet
415 \param src Source packet
416 \note If dst already has a packet, it will be freed.
417 */
418 static __ops_subpacket_t *
419 __ops_copy_packet(__ops_subpacket_t *dst, const __ops_subpacket_t *src)
420 {
421 	if (dst->raw) {
422 		free(dst->raw);
423 	}
424 	if ((dst->raw = calloc(1, src->length)) == NULL) {
425 		(void) fprintf(stderr, "__ops_copy_packet: bad alloc\n");
426 	} else {
427 		dst->length = src->length;
428 		(void) memcpy(dst->raw, src->raw, src->length);
429 	}
430 	return dst;
431 }
432 
433 /**
434 \ingroup Core_Keys
435 \brief Add User ID to key
436 \param key Key to which to add User ID
437 \param userid User ID to add
438 \return Pointer to new User ID
439 */
440 __ops_userid_t  *
441 __ops_add_userid(__ops_key_t *key, const __ops_userid_t *userid)
442 {
443 	__ops_userid_t  *uidp;
444 
445 	EXPAND_ARRAY(key, uid);
446 	/* initialise new entry in array */
447 	uidp = &key->uids[key->uidc++];
448 	uidp->userid = NULL;
449 	/* now copy it */
450 	return __ops_copy_userid(uidp, userid);
451 }
452 
453 /**
454 \ingroup Core_Keys
455 \brief Add packet to key
456 \param keydata Key to which to add packet
457 \param packet Packet to add
458 \return Pointer to new packet
459 */
460 __ops_subpacket_t   *
461 __ops_add_subpacket(__ops_key_t *keydata, const __ops_subpacket_t *packet)
462 {
463 	__ops_subpacket_t   *subpktp;
464 
465 	EXPAND_ARRAY(keydata, packet);
466 
467 	/* initialise new entry in array */
468 	subpktp = &keydata->packets[keydata->packetc++];
469 	subpktp->length = 0;
470 	subpktp->raw = NULL;
471 	/* now copy it */
472 	return __ops_copy_packet(subpktp, packet);
473 }
474 
475 /**
476 \ingroup Core_Keys
477 \brief Add signed User ID to key
478 \param keydata Key to which to add signed User ID
479 \param userid User ID to add
480 \param sigpacket Packet to add
481 */
482 void
483 __ops_add_signed_userid(__ops_key_t *keydata,
484 		const __ops_userid_t *userid,
485 		const __ops_subpacket_t *sigpacket)
486 {
487 	__ops_subpacket_t	*pkt;
488 	__ops_userid_t		*uid;
489 
490 	uid = __ops_add_userid(keydata, userid);
491 	pkt = __ops_add_subpacket(keydata, sigpacket);
492 
493 	/*
494          * add entry in sigs array to link the userid and sigpacket
495 	 * and add ptr to it from the sigs array */
496 	EXPAND_ARRAY(keydata, sig);
497 
498 	/**setup new entry in array */
499 	keydata->sigs[keydata->sigc].userid = uid;
500 	keydata->sigs[keydata->sigc].packet = pkt;
501 
502 	keydata->sigc++;
503 }
504 
505 /**
506 \ingroup Core_Keys
507 \brief Add selfsigned User ID to key
508 \param keydata Key to which to add user ID
509 \param userid Self-signed User ID to add
510 \return 1 if OK; else 0
511 */
512 unsigned
513 __ops_add_selfsigned_userid(__ops_key_t *keydata, __ops_userid_t *userid)
514 {
515 	__ops_create_sig_t	*sig;
516 	__ops_subpacket_t	 sigpacket;
517 	__ops_memory_t		*mem_userid = NULL;
518 	__ops_output_t		*useridoutput = NULL;
519 	__ops_memory_t		*mem_sig = NULL;
520 	__ops_output_t		*sigoutput = NULL;
521 
522 	/*
523          * create signature packet for this userid
524          */
525 
526 	/* create userid pkt */
527 	__ops_setup_memory_write(&useridoutput, &mem_userid, 128);
528 	__ops_write_struct_userid(useridoutput, userid);
529 
530 	/* create sig for this pkt */
531 	sig = __ops_create_sig_new();
532 	__ops_sig_start_key_sig(sig, &keydata->key.seckey.pubkey, userid,
533 					OPS_CERT_POSITIVE);
534 	__ops_add_birthtime(sig, time(NULL));
535 	__ops_add_issuer_keyid(sig, keydata->key_id);
536 	__ops_add_primary_userid(sig, 1);
537 	__ops_end_hashed_subpkts(sig);
538 
539 	__ops_setup_memory_write(&sigoutput, &mem_sig, 128);
540 	__ops_write_sig(sigoutput, sig, &keydata->key.seckey.pubkey,
541 				&keydata->key.seckey);
542 
543 	/* add this packet to keydata */
544 	sigpacket.length = __ops_mem_len(mem_sig);
545 	sigpacket.raw = __ops_mem_data(mem_sig);
546 
547 	/* add userid to keydata */
548 	__ops_add_signed_userid(keydata, userid, &sigpacket);
549 
550 	/* cleanup */
551 	__ops_create_sig_delete(sig);
552 	__ops_output_delete(useridoutput);
553 	__ops_output_delete(sigoutput);
554 	__ops_memory_free(mem_userid);
555 	__ops_memory_free(mem_sig);
556 
557 	return 1;
558 }
559 
560 /**
561 \ingroup Core_Keys
562 \brief Initialise __ops_key_t
563 \param keydata Keydata to initialise
564 \param type OPS_PTAG_CT_PUBLIC_KEY or OPS_PTAG_CT_SECRET_KEY
565 */
566 void
567 __ops_keydata_init(__ops_key_t *keydata, const __ops_content_tag_t type)
568 {
569 	if (keydata->type != OPS_PTAG_CT_RESERVED) {
570 		(void) fprintf(stderr,
571 			"__ops_keydata_init: wrong keydata type\n");
572 	} else if (type != OPS_PTAG_CT_PUBLIC_KEY &&
573 		   type != OPS_PTAG_CT_SECRET_KEY) {
574 		(void) fprintf(stderr, "__ops_keydata_init: wrong type\n");
575 	} else {
576 		keydata->type = type;
577 	}
578 }
579 
580 
581 static __ops_cb_ret_t
582 cb_keyring_read(const __ops_packet_t *pkt, __ops_cbdata_t *cbinfo)
583 {
584 	__OPS_USED(cbinfo);
585 
586 	switch (pkt->tag) {
587 	case OPS_PARSER_PTAG:
588 	case OPS_PTAG_CT_ENCRYPTED_SECRET_KEY:	/* we get these because we
589 						 * didn't prompt */
590 	case OPS_PTAG_CT_SIGNATURE_HEADER:
591 	case OPS_PTAG_CT_SIGNATURE_FOOTER:
592 	case OPS_PTAG_CT_SIGNATURE:
593 	case OPS_PTAG_CT_TRUST:
594 	case OPS_PARSER_ERRCODE:
595 		break;
596 
597 	default:
598 		break;
599 	}
600 
601 	return OPS_RELEASE_MEMORY;
602 }
603 
604 /**
605    \ingroup HighLevel_KeyringRead
606 
607    \brief Reads a keyring from a file
608 
609    \param keyring Pointer to an existing __ops_keyring_t struct
610    \param armour 1 if file is armoured; else 0
611    \param filename Filename of keyring to be read
612 
613    \return __ops 1 if OK; 0 on error
614 
615    \note Keyring struct must already exist.
616 
617    \note Can be used with either a public or secret keyring.
618 
619    \note You must call __ops_keyring_free() after usage to free alloc-ed memory.
620 
621    \note If you call this twice on the same keyring struct, without calling
622    __ops_keyring_free() between these calls, you will introduce a memory leak.
623 
624    \sa __ops_keyring_read_from_mem()
625    \sa __ops_keyring_free()
626 
627 */
628 
629 unsigned
630 __ops_keyring_fileread(__ops_keyring_t *keyring,
631 			const unsigned armour,
632 			const char *filename)
633 {
634 	__ops_stream_t	*stream;
635 	unsigned		 res = 1;
636 	int			 fd;
637 
638 	stream = __ops_new(sizeof(*stream));
639 
640 	/* add this for the moment, */
641 	/*
642 	 * \todo need to fix the problems with reading signature subpackets
643 	 * later
644 	 */
645 
646 	/* __ops_parse_options(parse,OPS_PTAG_SS_ALL,OPS_PARSE_RAW); */
647 	__ops_parse_options(stream, OPS_PTAG_SS_ALL, OPS_PARSE_PARSED);
648 
649 #ifdef O_BINARY
650 	fd = open(filename, O_RDONLY | O_BINARY);
651 #else
652 	fd = open(filename, O_RDONLY);
653 #endif
654 	if (fd < 0) {
655 		__ops_stream_delete(stream);
656 		perror(filename);
657 		return 0;
658 	}
659 #ifdef USE_MMAP_FOR_FILES
660 	__ops_reader_set_mmap(stream, fd);
661 #else
662 	__ops_reader_set_fd(stream, fd);
663 #endif
664 
665 	__ops_set_callback(stream, cb_keyring_read, NULL);
666 
667 	if (armour) {
668 		__ops_reader_push_dearmour(stream);
669 	}
670 	res = __ops_parse_and_accumulate(keyring, stream);
671 	__ops_print_errors(__ops_stream_get_errors(stream));
672 
673 	if (armour) {
674 		__ops_reader_pop_dearmour(stream);
675 	}
676 
677 	(void)close(fd);
678 
679 	__ops_stream_delete(stream);
680 
681 	return res;
682 }
683 
684 /**
685    \ingroup HighLevel_KeyringRead
686 
687    \brief Reads a keyring from memory
688 
689    \param keyring Pointer to existing __ops_keyring_t struct
690    \param armour 1 if file is armoured; else 0
691    \param mem Pointer to a __ops_memory_t struct containing keyring to be read
692 
693    \return __ops 1 if OK; 0 on error
694 
695    \note Keyring struct must already exist.
696 
697    \note Can be used with either a public or secret keyring.
698 
699    \note You must call __ops_keyring_free() after usage to free alloc-ed memory.
700 
701    \note If you call this twice on the same keyring struct, without calling
702    __ops_keyring_free() between these calls, you will introduce a memory leak.
703 
704    \sa __ops_keyring_fileread
705    \sa __ops_keyring_free
706 */
707 unsigned
708 __ops_keyring_read_from_mem(__ops_io_t *io,
709 				__ops_keyring_t *keyring,
710 				const unsigned armour,
711 				__ops_memory_t *mem)
712 {
713 	__ops_stream_t	*stream;
714 	const unsigned	 noaccum = 0;
715 	unsigned	 res;
716 
717 	stream = __ops_new(sizeof(*stream));
718 	__ops_parse_options(stream, OPS_PTAG_SS_ALL, OPS_PARSE_PARSED);
719 	__ops_setup_memory_read(io, &stream, mem, NULL, cb_keyring_read,
720 					noaccum);
721 	if (armour) {
722 		__ops_reader_push_dearmour(stream);
723 	}
724 	res = (unsigned)__ops_parse_and_accumulate(keyring, stream);
725 	__ops_print_errors(__ops_stream_get_errors(stream));
726 	if (armour) {
727 		__ops_reader_pop_dearmour(stream);
728 	}
729 	/* don't call teardown_memory_read because memory was passed in */
730 	__ops_stream_delete(stream);
731 	return res;
732 }
733 
734 /**
735    \ingroup HighLevel_KeyringRead
736 
737    \brief Frees keyring's contents (but not keyring itself)
738 
739    \param keyring Keyring whose data is to be freed
740 
741    \note This does not free keyring itself, just the memory alloc-ed in it.
742  */
743 void
744 __ops_keyring_free(__ops_keyring_t *keyring)
745 {
746 	(void)free(keyring->keys);
747 	keyring->keys = NULL;
748 	keyring->keyc = keyring->keyvsize = 0;
749 }
750 
751 /**
752    \ingroup HighLevel_KeyringFind
753 
754    \brief Finds key in keyring from its Key ID
755 
756    \param keyring Keyring to be searched
757    \param keyid ID of required key
758 
759    \return Pointer to key, if found; NULL, if not found
760 
761    \note This returns a pointer to the key inside the given keyring,
762    not a copy.  Do not free it after use.
763 
764 */
765 const __ops_key_t *
766 __ops_getkeybyid(__ops_io_t *io, const __ops_keyring_t *keyring,
767 			   const unsigned char keyid[OPS_KEY_ID_SIZE])
768 {
769 	unsigned	 n;
770 
771 	for (n = 0; keyring && n < keyring->keyc; n++) {
772 		if (__ops_get_debug_level(__FILE__)) {
773 			int	i;
774 
775 			(void) fprintf(io->errs,
776 				"__ops_getkeybyid: keyring keyid ");
777 			for (i = 0 ; i < OPS_KEY_ID_SIZE ; i++) {
778 				(void) fprintf(io->errs, "%02x",
779 					keyring->keys[n].key_id[i]);
780 			}
781 			(void) fprintf(io->errs, ", keyid ");
782 			for (i = 0 ; i < OPS_KEY_ID_SIZE ; i++) {
783 				(void) fprintf(io->errs, "%02x", keyid[i]);
784 			}
785 			(void) fprintf(io->errs, "\n");
786 		}
787 		if (memcmp(keyring->keys[n].key_id, keyid,
788 				OPS_KEY_ID_SIZE) == 0) {
789 			return &keyring->keys[n];
790 		}
791 		if (memcmp(&keyring->keys[n].key_id[OPS_KEY_ID_SIZE / 2],
792 				keyid, OPS_KEY_ID_SIZE / 2) == 0) {
793 			return &keyring->keys[n];
794 		}
795 	}
796 	return NULL;
797 }
798 
799 /* convert a string keyid into a binary keyid */
800 static void
801 str2keyid(const char *userid, unsigned char *keyid, size_t len)
802 {
803 	static const char	*uppers = "0123456789ABCDEF";
804 	static const char	*lowers = "0123456789abcdef";
805 	unsigned char		 hichar;
806 	unsigned char		 lochar;
807 	size_t			 j;
808 	const char		*hi;
809 	const char		*lo;
810 	int			 i;
811 
812 	for (i = j = 0 ; j < len && userid[i] && userid[i + 1] ; i += 2, j++) {
813 		if ((hi = strchr(uppers, userid[i])) == NULL) {
814 			if ((hi = strchr(lowers, userid[i])) == NULL) {
815 				break;
816 			}
817 			hichar = (hi - lowers);
818 		} else {
819 			hichar = (hi - uppers);
820 		}
821 		if ((lo = strchr(uppers, userid[i + 1])) == NULL) {
822 			if ((lo = strchr(lowers, userid[i + 1])) == NULL) {
823 				break;
824 			}
825 			lochar = (lo - lowers);
826 		} else {
827 			lochar = (lo - uppers);
828 		}
829 		keyid[j] = (hichar << 4) | (lochar);
830 	}
831 	keyid[j] = 0x0;
832 }
833 
834 /**
835    \ingroup HighLevel_KeyringFind
836 
837    \brief Finds key from its User ID
838 
839    \param keyring Keyring to be searched
840    \param userid User ID of required key
841 
842    \return Pointer to Key, if found; NULL, if not found
843 
844    \note This returns a pointer to the key inside the keyring, not a
845    copy.  Do not free it.
846 
847 */
848 const __ops_key_t *
849 __ops_getkeybyname(__ops_io_t *io,
850 			const __ops_keyring_t *keyring,
851 			const char *name)
852 {
853 	const __ops_key_t	*kp;
854 	__ops_key_t		*keyp;
855 	__ops_userid_t		*uidp;
856 	unsigned char		 keyid[OPS_KEY_ID_SIZE + 1];
857 	unsigned int    	 i = 0;
858 	size_t          	 len;
859 	char	                *cp;
860 	unsigned             	 n;
861 
862 	if (!keyring) {
863 		return NULL;
864 	}
865 	len = strlen(name);
866 	n = 0;
867 	for (keyp = &keyring->keys[n]; n < keyring->keyc; ++n, keyp++) {
868 		for (i = 0, uidp = keyp->uids; i < keyp->uidc; i++, uidp++) {
869 			if (__ops_get_debug_level(__FILE__)) {
870 				(void) fprintf(io->outs,
871 					"[%u][%u] name %s, last '%d'\n",
872 					n, i, uidp->userid,
873 					uidp->userid[len]);
874 			}
875 			if (strncmp((char *) uidp->userid, name, len) == 0 &&
876 			    uidp->userid[len] == ' ') {
877 				return keyp;
878 			}
879 		}
880 	}
881 
882 	if (strchr(name, '@') == NULL) {
883 		/* no '@' sign */
884 		/* first try name as a keyid */
885 		(void) memset(keyid, 0x0, sizeof(keyid));
886 		str2keyid(name, keyid, sizeof(keyid));
887 		if (__ops_get_debug_level(__FILE__)) {
888 			(void) fprintf(io->outs,
889 				"name \"%s\", keyid %02x%02x%02x%02x\n",
890 				name,
891 				keyid[0], keyid[1], keyid[2], keyid[3]);
892 		}
893 		if ((kp = __ops_getkeybyid(io, keyring, keyid)) != NULL) {
894 			return kp;
895 		}
896 		/* match on full name */
897 		keyp = keyring->keys;
898 		for (n = 0; n < keyring->keyc; ++n, keyp++) {
899 			uidp = keyp->uids;
900 			for (i = 0 ; i < keyp->uidc; i++, uidp++) {
901 				if (__ops_get_debug_level(__FILE__)) {
902 					(void) fprintf(io->outs,
903 						"keyid \"%s\" len %"
904 						PRIsize "u, keyid[len] '%c'\n",
905 					       (char *) uidp->userid,
906 					       len, uidp->userid[len]);
907 				}
908 				if (strncasecmp((char *) uidp->userid, name,
909 					len) == 0 && uidp->userid[len] == ' ') {
910 					return keyp;
911 				}
912 			}
913 		}
914 	}
915 	/* match on <email@address> */
916 	keyp = keyring->keys;
917 	for (n = 0; n < keyring->keyc; ++n, keyp++) {
918 		for (i = 0, uidp = keyp->uids; i < keyp->uidc; i++, uidp++) {
919 			/*
920 			 * look for the rightmost '<', in case there is one
921 			 * in the comment field
922 			 */
923 			cp = strrchr((char *) uidp->userid, '<');
924 			if (cp != NULL) {
925 				if (__ops_get_debug_level(__FILE__)) {
926 					(void) fprintf(io->errs,
927 						"cp ,%s, name ,%s, len %"
928 						PRIsize "u ,%c,\n",
929 						cp + 1,
930 						name,
931 						len,
932 						*(cp + len + 1));
933 				}
934 				if (strncasecmp(cp + 1, name, len) == 0 &&
935 				    *(cp + len + 1) == '>') {
936 					return keyp;
937 				}
938 			}
939 		}
940 	}
941 	return NULL;
942 }
943 
944 /**
945    \ingroup HighLevel_KeyringList
946 
947    \brief Prints all keys in keyring to stdout.
948 
949    \param keyring Keyring to use
950 
951    \return none
952 */
953 int
954 __ops_keyring_list(__ops_io_t *io, const __ops_keyring_t *keyring)
955 {
956 	__ops_key_t		*key;
957 	unsigned		 n;
958 
959 	(void) fprintf(io->res, "%u key%s\n", keyring->keyc,
960 		(keyring->keyc == 1) ? "" : "s");
961 	for (n = 0, key = keyring->keys; n < keyring->keyc; ++n, ++key) {
962 		if (__ops_is_key_secret(key)) {
963 			__ops_print_keydata(io, key, "sec",
964 				&key->key.seckey.pubkey);
965 		} else {
966 			__ops_print_keydata(io, key, "pub", &key->key.pubkey);
967 		}
968 		(void) fputc('\n', io->res);
969 	}
970 	return 1;
971 }
972 
973 static unsigned
974 get_contents_type(const __ops_key_t *keydata)
975 {
976 	return keydata->type;
977 }
978 
979 /* this interface isn't right - hook into callback for getting passphrase */
980 int
981 __ops_export_key(const __ops_key_t *keydata, unsigned char *passphrase)
982 {
983 	__ops_output_t	*output;
984 	__ops_memory_t		*mem;
985 
986 	__ops_setup_memory_write(&output, &mem, 128);
987 	if (get_contents_type(keydata) == OPS_PTAG_CT_PUBLIC_KEY) {
988 		__ops_write_xfer_pubkey(output, keydata, 1);
989 	} else {
990 		__ops_write_xfer_seckey(output, keydata, passphrase,
991 					strlen((char *)passphrase), 1);
992 	}
993 	printf("%s", (char *) __ops_mem_data(mem));
994 	__ops_teardown_memory_write(output, mem);
995 	return 1;
996 }
997 
998 /* add a key to a public keyring */
999 int
1000 __ops_add_to_pubring(__ops_keyring_t *keyring, const __ops_pubkey_t *pubkey)
1001 {
1002 	__ops_key_t	*key;
1003 
1004 	EXPAND_ARRAY(keyring, key);
1005 	key = &keyring->keys[keyring->keyc++];
1006 	(void) memset(key, 0x0, sizeof(*key));
1007 	__ops_keyid(key->key_id, OPS_KEY_ID_SIZE, pubkey);
1008 	__ops_fingerprint(&key->fingerprint, pubkey);
1009 	key->type = OPS_PTAG_CT_PUBLIC_KEY;
1010 	key->key.pubkey = *pubkey;
1011 	return 1;
1012 }
1013 
1014 /* add a key to a secret keyring */
1015 int
1016 __ops_add_to_secring(__ops_keyring_t *keyring, const __ops_seckey_t *seckey)
1017 {
1018 	const __ops_pubkey_t	*pubkey;
1019 	__ops_key_t		*key;
1020 
1021 	EXPAND_ARRAY(keyring, key);
1022 	key = &keyring->keys[keyring->keyc++];
1023 	(void) memset(key, 0x0, sizeof(*key));
1024 	pubkey = &seckey->pubkey;
1025 	__ops_keyid(key->key_id, OPS_KEY_ID_SIZE, pubkey);
1026 	__ops_fingerprint(&key->fingerprint, pubkey);
1027 	key->type = OPS_PTAG_CT_SECRET_KEY;
1028 	key->key.seckey = *seckey;
1029 	return 1;
1030 }
1031