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