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