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