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