keyring.c revision 1.23
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*/
118void
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
157const __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
171unsigned
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
188const __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 */
214void
215__ops_forget(void *vp, unsigned size)
216{
217	(void) memset(vp, 0x0, size);
218}
219
220typedef struct {
221	const __ops_key_t	*key;
222	char			*passphrase;
223	__ops_seckey_t		*seckey;
224} decrypt_t;
225
226static __ops_cb_ret_t
227decrypt_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*/
321void
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*/
333const 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*/
345unsigned
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*/
358const 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
371unsigned
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*/
394static __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*/
418static __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*/
482void
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*/
512unsigned
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*/
566void
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
581static __ops_cb_ret_t
582cb_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
629unsigned
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*/
707unsigned
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 */
743void
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*/
765const __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 */
800static void
801str2keyid(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*/
848const __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*/
953int
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
973static unsigned
974get_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 */
980int
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 */
999int
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 */
1015int
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