keyring.c revision 1.27
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.27 2010/02/06 02:24:33 agc Exp $");
61#endif
62
63#ifdef HAVE_FCNTL_H
64#include <fcntl.h>
65#endif
66
67#include <regex.h>
68#include <stdlib.h>
69#include <string.h>
70
71#ifdef HAVE_TERMIOS_H
72#include <termios.h>
73#endif
74
75#ifdef HAVE_UNISTD_H
76#include <unistd.h>
77#endif
78
79#include "types.h"
80#include "keyring.h"
81#include "packet-parse.h"
82#include "signature.h"
83#include "netpgpsdk.h"
84#include "readerwriter.h"
85#include "netpgpdefs.h"
86#include "packet.h"
87#include "crypto.h"
88#include "validate.h"
89#include "netpgpdigest.h"
90
91
92
93/**
94   \ingroup HighLevel_Keyring
95
96   \brief Creates a new __ops_key_t struct
97
98   \return A new __ops_key_t struct, initialised to zero.
99
100   \note The returned __ops_key_t struct must be freed after use with __ops_keydata_free.
101*/
102
103__ops_key_t  *
104__ops_keydata_new(void)
105{
106	return calloc(1, sizeof(__ops_key_t));
107}
108
109
110/**
111 \ingroup HighLevel_Keyring
112
113 \brief Frees keydata and its memory
114
115 \param keydata Key to be freed.
116
117 \note This frees the keydata itself, as well as any other memory alloc-ed by it.
118*/
119void
120__ops_keydata_free(__ops_key_t *keydata)
121{
122	unsigned        n;
123
124	for (n = 0; n < keydata->uidc; ++n) {
125		__ops_userid_free(&keydata->uids[n]);
126	}
127	free(keydata->uids);
128	keydata->uids = NULL;
129	keydata->uidc = 0;
130
131	for (n = 0; n < keydata->packetc; ++n) {
132		__ops_subpacket_free(&keydata->packets[n]);
133	}
134	free(keydata->packets);
135	keydata->packets = NULL;
136	keydata->packetc = 0;
137
138	if (keydata->type == OPS_PTAG_CT_PUBLIC_KEY) {
139		__ops_pubkey_free(&keydata->key.pubkey);
140	} else {
141		__ops_seckey_free(&keydata->key.seckey);
142	}
143
144	free(keydata);
145}
146
147/**
148 \ingroup HighLevel_KeyGeneral
149
150 \brief Returns the public key in the given keydata.
151 \param keydata
152
153  \return Pointer to public key
154
155  \note This is not a copy, do not free it after use.
156*/
157
158const __ops_pubkey_t *
159__ops_get_pubkey(const __ops_key_t *keydata)
160{
161	return (keydata->type == OPS_PTAG_CT_PUBLIC_KEY) ?
162				&keydata->key.pubkey :
163				&keydata->key.seckey.pubkey;
164}
165
166/**
167\ingroup HighLevel_KeyGeneral
168
169\brief Check whether this is a secret key or not.
170*/
171
172unsigned
173__ops_is_key_secret(const __ops_key_t *data)
174{
175	return data->type != OPS_PTAG_CT_PUBLIC_KEY;
176}
177
178/**
179 \ingroup HighLevel_KeyGeneral
180
181 \brief Returns the secret key in the given keydata.
182
183 \note This is not a copy, do not free it after use.
184
185 \note This returns a const.  If you need to be able to write to this
186 pointer, use __ops_get_writable_seckey
187*/
188
189const __ops_seckey_t *
190__ops_get_seckey(const __ops_key_t *data)
191{
192	return (data->type == OPS_PTAG_CT_SECRET_KEY) ?
193				&data->key.seckey : NULL;
194}
195
196/**
197 \ingroup HighLevel_KeyGeneral
198
199  \brief Returns the secret key in the given keydata.
200
201  \note This is not a copy, do not free it after use.
202
203  \note If you do not need to be able to modify this key, there is an
204  equivalent read-only function __ops_get_seckey.
205*/
206
207__ops_seckey_t *
208__ops_get_writable_seckey(__ops_key_t *data)
209{
210	return (data->type == OPS_PTAG_CT_SECRET_KEY) ?
211				&data->key.seckey : NULL;
212}
213
214/* utility function to zero out memory */
215void
216__ops_forget(void *vp, unsigned size)
217{
218	(void) memset(vp, 0x0, size);
219}
220
221typedef struct {
222	FILE			*passfp;
223	const __ops_key_t	*key;
224	char			*passphrase;
225	__ops_seckey_t		*seckey;
226} decrypt_t;
227
228static __ops_cb_ret_t
229decrypt_cb(const __ops_packet_t *pkt, __ops_cbdata_t *cbinfo)
230{
231	const __ops_contents_t	*content = &pkt->u;
232	decrypt_t		*decrypt;
233	char			 pass[MAX_PASSPHRASE_LENGTH];
234
235	decrypt = __ops_callback_arg(cbinfo);
236	switch (pkt->tag) {
237	case OPS_PARSER_PTAG:
238	case OPS_PTAG_CT_USER_ID:
239	case OPS_PTAG_CT_SIGNATURE:
240	case OPS_PTAG_CT_SIGNATURE_HEADER:
241	case OPS_PTAG_CT_SIGNATURE_FOOTER:
242	case OPS_PTAG_CT_TRUST:
243		break;
244
245	case OPS_GET_PASSPHRASE:
246		(void) __ops_getpassphrase(decrypt->passfp, pass, sizeof(pass));
247		*content->skey_passphrase.passphrase = strdup(pass);
248		__ops_forget(pass, sizeof(pass));
249		return OPS_KEEP_MEMORY;
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		if ((decrypt->seckey = calloc(1, sizeof(*decrypt->seckey))) == NULL) {
274			(void) fprintf(stderr, "decrypt_cb: bad alloc\n");
275			return OPS_FINISHED;
276		}
277		decrypt->seckey->checkhash = calloc(1, OPS_CHECKHASH_SIZE);
278		*decrypt->seckey = content->seckey;
279		return OPS_KEEP_MEMORY;
280
281	case OPS_PARSER_PACKET_END:
282		/* nothing to do */
283		break;
284
285	default:
286		fprintf(stderr, "Unexpected tag %d (0x%x)\n", pkt->tag,
287			pkt->tag);
288		return OPS_FINISHED;
289	}
290
291	return OPS_RELEASE_MEMORY;
292}
293
294/**
295\ingroup Core_Keys
296\brief Decrypts secret key from given keydata with given passphrase
297\param key Key from which to get secret key
298\param passphrase Passphrase to use to decrypt secret key
299\return secret key
300*/
301__ops_seckey_t *
302__ops_decrypt_seckey(const __ops_key_t *key, void *passfp)
303{
304	__ops_stream_t	*stream;
305	const int	 printerrors = 1;
306	decrypt_t	 decrypt;
307
308	(void) memset(&decrypt, 0x0, sizeof(decrypt));
309	decrypt.key = key;
310	decrypt.passfp = passfp;
311	stream = __ops_new(sizeof(*stream));
312	__ops_keydata_reader_set(stream, key);
313	__ops_set_callback(stream, decrypt_cb, &decrypt);
314	stream->readinfo.accumulate = 1;
315	__ops_parse(stream, !printerrors);
316	return decrypt.seckey;
317}
318
319/**
320\ingroup Core_Keys
321\brief Set secret key in content
322\param content Content to be set
323\param key Keydata to get secret key from
324*/
325void
326__ops_set_seckey(__ops_contents_t *cont, const __ops_key_t *key)
327{
328	*cont->get_seckey.seckey = &key->key.seckey;
329}
330
331/**
332\ingroup Core_Keys
333\brief Get Key ID from keydata
334\param key Keydata to get Key ID from
335\return Pointer to Key ID inside keydata
336*/
337const unsigned char *
338__ops_get_key_id(const __ops_key_t *key)
339{
340	return key->key_id;
341}
342
343/**
344\ingroup Core_Keys
345\brief How many User IDs in this key?
346\param key Keydata to check
347\return Num of user ids
348*/
349unsigned
350__ops_get_userid_count(const __ops_key_t *key)
351{
352	return key->uidc;
353}
354
355/**
356\ingroup Core_Keys
357\brief Get indexed user id from key
358\param key Key to get user id from
359\param index Which key to get
360\return Pointer to requested user id
361*/
362const unsigned char *
363__ops_get_userid(const __ops_key_t *key, unsigned subscript)
364{
365	return key->uids[subscript].userid;
366}
367
368/**
369   \ingroup HighLevel_Supported
370   \brief Checks whether key's algorithm and type are supported by OpenPGP::SDK
371   \param keydata Key to be checked
372   \return 1 if key algorithm and type are supported by OpenPGP::SDK; 0 if not
373*/
374
375unsigned
376__ops_is_key_supported(const __ops_key_t *key)
377{
378	if (key->type == OPS_PTAG_CT_PUBLIC_KEY) {
379		if (key->key.pubkey.alg == OPS_PKA_RSA) {
380			return 1;
381		}
382	} else if (key->type == OPS_PTAG_CT_PUBLIC_KEY) {
383		if (key->key.pubkey.alg == OPS_PKA_DSA) {
384			return 1;
385		}
386	}
387	return 0;
388}
389
390/* \todo check where userid pointers are copied */
391/**
392\ingroup Core_Keys
393\brief Copy user id, including contents
394\param dst Destination User ID
395\param src Source User ID
396\note If dst already has a userid, it will be freed.
397*/
398static __ops_userid_t *
399__ops_copy_userid(__ops_userid_t *dst, const __ops_userid_t *src)
400{
401	size_t          len = strlen((char *) src->userid);
402
403	if (dst->userid) {
404		free(dst->userid);
405	}
406	if ((dst->userid = calloc(1, len + 1)) == NULL) {
407		(void) fprintf(stderr, "__ops_copy_userid: bad alloc\n");
408	} else {
409		(void) memcpy(dst->userid, src->userid, len);
410	}
411	return dst;
412}
413
414/* \todo check where pkt pointers are copied */
415/**
416\ingroup Core_Keys
417\brief Copy packet, including contents
418\param dst Destination packet
419\param src Source packet
420\note If dst already has a packet, it will be freed.
421*/
422static __ops_subpacket_t *
423__ops_copy_packet(__ops_subpacket_t *dst, const __ops_subpacket_t *src)
424{
425	if (dst->raw) {
426		free(dst->raw);
427	}
428	if ((dst->raw = calloc(1, src->length)) == NULL) {
429		(void) fprintf(stderr, "__ops_copy_packet: bad alloc\n");
430	} else {
431		dst->length = src->length;
432		(void) memcpy(dst->raw, src->raw, src->length);
433	}
434	return dst;
435}
436
437/**
438\ingroup Core_Keys
439\brief Add User ID to key
440\param key Key to which to add User ID
441\param userid User ID to add
442\return Pointer to new User ID
443*/
444__ops_userid_t  *
445__ops_add_userid(__ops_key_t *key, const __ops_userid_t *userid)
446{
447	__ops_userid_t  *uidp;
448
449	EXPAND_ARRAY(key, uid);
450	/* initialise new entry in array */
451	uidp = &key->uids[key->uidc++];
452	uidp->userid = NULL;
453	/* now copy it */
454	return __ops_copy_userid(uidp, userid);
455}
456
457/**
458\ingroup Core_Keys
459\brief Add packet to key
460\param keydata Key to which to add packet
461\param packet Packet to add
462\return Pointer to new packet
463*/
464__ops_subpacket_t   *
465__ops_add_subpacket(__ops_key_t *keydata, const __ops_subpacket_t *packet)
466{
467	__ops_subpacket_t   *subpktp;
468
469	EXPAND_ARRAY(keydata, packet);
470
471	/* initialise new entry in array */
472	subpktp = &keydata->packets[keydata->packetc++];
473	subpktp->length = 0;
474	subpktp->raw = NULL;
475	/* now copy it */
476	return __ops_copy_packet(subpktp, packet);
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_key_t *keydata,
488		const __ops_userid_t *userid,
489		const __ops_subpacket_t *sigpacket)
490{
491	__ops_subpacket_t	*pkt;
492	__ops_userid_t		*uid;
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, sig);
501
502	/**setup new entry in array */
503	keydata->sigs[keydata->sigc].userid = uid;
504	keydata->sigs[keydata->sigc].packet = pkt;
505
506	keydata->sigc++;
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_key_t *keydata, __ops_userid_t *userid)
518{
519	__ops_create_sig_t	*sig;
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_key_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_key_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		break;
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_stream_t	*stream;
639	unsigned		 res = 1;
640	int			 fd;
641
642	stream = __ops_new(sizeof(*stream));
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(stream, 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_stream_delete(stream);
660		perror(filename);
661		return 0;
662	}
663#ifdef USE_MMAP_FOR_FILES
664	__ops_reader_set_mmap(stream, fd);
665#else
666	__ops_reader_set_fd(stream, fd);
667#endif
668
669	__ops_set_callback(stream, cb_keyring_read, NULL);
670
671	if (armour) {
672		__ops_reader_push_dearmour(stream);
673	}
674	res = __ops_parse_and_accumulate(keyring, stream);
675	__ops_print_errors(__ops_stream_get_errors(stream));
676
677	if (armour) {
678		__ops_reader_pop_dearmour(stream);
679	}
680
681	(void)close(fd);
682
683	__ops_stream_delete(stream);
684
685	return res;
686}
687
688/**
689   \ingroup HighLevel_KeyringRead
690
691   \brief Reads a keyring from memory
692
693   \param keyring Pointer to existing __ops_keyring_t struct
694   \param armour 1 if file is armoured; else 0
695   \param mem Pointer to a __ops_memory_t struct containing keyring to be read
696
697   \return __ops 1 if OK; 0 on error
698
699   \note Keyring struct must already exist.
700
701   \note Can be used with either a public or secret keyring.
702
703   \note You must call __ops_keyring_free() after usage to free alloc-ed memory.
704
705   \note If you call this twice on the same keyring struct, without calling
706   __ops_keyring_free() between these calls, you will introduce a memory leak.
707
708   \sa __ops_keyring_fileread
709   \sa __ops_keyring_free
710*/
711unsigned
712__ops_keyring_read_from_mem(__ops_io_t *io,
713				__ops_keyring_t *keyring,
714				const unsigned armour,
715				__ops_memory_t *mem)
716{
717	__ops_stream_t	*stream;
718	const unsigned	 noaccum = 0;
719	unsigned	 res;
720
721	stream = __ops_new(sizeof(*stream));
722	__ops_parse_options(stream, OPS_PTAG_SS_ALL, OPS_PARSE_PARSED);
723	__ops_setup_memory_read(io, &stream, mem, NULL, cb_keyring_read,
724					noaccum);
725	if (armour) {
726		__ops_reader_push_dearmour(stream);
727	}
728	res = (unsigned)__ops_parse_and_accumulate(keyring, stream);
729	__ops_print_errors(__ops_stream_get_errors(stream));
730	if (armour) {
731		__ops_reader_pop_dearmour(stream);
732	}
733	/* don't call teardown_memory_read because memory was passed in */
734	__ops_stream_delete(stream);
735	return res;
736}
737
738/**
739   \ingroup HighLevel_KeyringRead
740
741   \brief Frees keyring's contents (but not keyring itself)
742
743   \param keyring Keyring whose data is to be freed
744
745   \note This does not free keyring itself, just the memory alloc-ed in it.
746 */
747void
748__ops_keyring_free(__ops_keyring_t *keyring)
749{
750	(void)free(keyring->keys);
751	keyring->keys = NULL;
752	keyring->keyc = keyring->keyvsize = 0;
753}
754
755/* simple function to print out a binary keyid */
756void
757__ops_pkeyid(FILE *fp, const unsigned char *keyid, size_t size)
758{
759	size_t	i;
760
761	for (i = 0 ; i < size ; i++) {
762		(void) fprintf(fp, "%02x", keyid[i]);
763	}
764}
765
766/**
767   \ingroup HighLevel_KeyringFind
768
769   \brief Finds key in keyring from its Key ID
770
771   \param keyring Keyring to be searched
772   \param keyid ID of required key
773
774   \return Pointer to key, if found; NULL, if not found
775
776   \note This returns a pointer to the key inside the given keyring,
777   not a copy.  Do not free it after use.
778
779*/
780const __ops_key_t *
781__ops_getkeybyid(__ops_io_t *io, const __ops_keyring_t *keyring,
782			   const unsigned char *keyid, unsigned *from)
783{
784	for ( ; keyring && *from < keyring->keyc; *from += 1) {
785		if (__ops_get_debug_level(__FILE__)) {
786			(void) fprintf(io->errs,
787				"__ops_getkeybyid: keyring keyid ");
788			__ops_pkeyid(io->errs, keyring->keys[*from].key_id,
789				OPS_KEY_ID_SIZE);
790			(void) fprintf(io->errs, ", keyid ");
791			__ops_pkeyid(io->errs, keyid, OPS_KEY_ID_SIZE);
792			(void) fprintf(io->errs, "\n");
793		}
794		if (memcmp(keyring->keys[*from].key_id, keyid,
795				OPS_KEY_ID_SIZE) == 0) {
796			return &keyring->keys[*from];
797		}
798		if (memcmp(&keyring->keys[*from].key_id[OPS_KEY_ID_SIZE / 2],
799				keyid, OPS_KEY_ID_SIZE / 2) == 0) {
800			return &keyring->keys[*from];
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/* return the next key which matches, starting searching at *from */
842static const __ops_key_t *
843getkeybyname(__ops_io_t *io,
844			const __ops_keyring_t *keyring,
845			const char *name,
846			unsigned *from)
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	unsigned		 savedstart;
854	regex_t			 r;
855	size_t          	 len;
856
857	if (!keyring) {
858		return NULL;
859	}
860	len = strlen(name);
861	if (__ops_get_debug_level(__FILE__)) {
862		(void) fprintf(io->outs, "[%u] name '%s', len %zu\n",
863			*from, name, len);
864	}
865	/* first try name as a keyid */
866	(void) memset(keyid, 0x0, sizeof(keyid));
867	str2keyid(name, keyid, sizeof(keyid));
868	if (__ops_get_debug_level(__FILE__)) {
869		(void) fprintf(io->outs,
870			"name \"%s\", keyid %02x%02x%02x%02x\n",
871			name,
872			keyid[0], keyid[1], keyid[2], keyid[3]);
873	}
874	savedstart = *from;
875	if ((kp = __ops_getkeybyid(io, keyring, keyid, from)) != NULL) {
876		return kp;
877	}
878	*from = savedstart;
879	if (__ops_get_debug_level(__FILE__)) {
880		(void) fprintf(io->outs, "regex match '%s' from %u\n",
881			name, *from);
882	}
883	/* match on full name or email address as a NOSUB, ICASE regexp */
884	(void) regcomp(&r, name, REG_EXTENDED | REG_ICASE);
885	for (keyp = &keyring->keys[*from]; *from < keyring->keyc; *from += 1, keyp++) {
886		uidp = keyp->uids;
887		for (i = 0 ; i < keyp->uidc; i++, uidp++) {
888			if (__ops_get_debug_level(__FILE__)) {
889				(void) fprintf(io->outs,
890					"keyid \"%s\" len %"
891					PRIsize "u, keyid[len] '%c'\n",
892				       (char *) uidp->userid,
893				       len, uidp->userid[len]);
894			}
895			if (regexec(&r, (char *)uidp->userid, 0, NULL, 0) == 0) {
896				regfree(&r);
897				return keyp;
898			}
899		}
900	}
901	regfree(&r);
902	return NULL;
903}
904
905/**
906   \ingroup HighLevel_KeyringFind
907
908   \brief Finds key from its User ID
909
910   \param keyring Keyring to be searched
911   \param userid User ID of required key
912
913   \return Pointer to Key, if found; NULL, if not found
914
915   \note This returns a pointer to the key inside the keyring, not a
916   copy.  Do not free it.
917
918*/
919const __ops_key_t *
920__ops_getkeybyname(__ops_io_t *io,
921			const __ops_keyring_t *keyring,
922			const char *name)
923{
924	unsigned	from;
925
926	from = 0;
927	return getkeybyname(io, keyring, name, &from);
928}
929
930const __ops_key_t *
931__ops_getnextkeybyname(__ops_io_t *io,
932			const __ops_keyring_t *keyring,
933			const char *name,
934			unsigned *n)
935{
936	return getkeybyname(io, keyring, name, n);
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, "%u key%s\n", keyring->keyc,
955		(keyring->keyc == 1) ? "" : "s");
956	for (n = 0, key = keyring->keys; n < keyring->keyc; ++n, ++key) {
957		if (__ops_is_key_secret(key)) {
958			__ops_print_keydata(io, key, "sec",
959				&key->key.seckey.pubkey);
960		} else {
961			__ops_print_keydata(io, key, "pub", &key->key.pubkey);
962		}
963		(void) fputc('\n', io->res);
964	}
965	return 1;
966}
967
968/* this interface isn't right - hook into callback for getting passphrase */
969int
970__ops_export_key(const __ops_key_t *keydata, unsigned char *passphrase)
971{
972	__ops_output_t	*output;
973	__ops_memory_t		*mem;
974
975	__ops_setup_memory_write(&output, &mem, 128);
976	if (keydata->type == OPS_PTAG_CT_PUBLIC_KEY) {
977		__ops_write_xfer_pubkey(output, keydata, 1);
978	} else {
979		__ops_write_xfer_seckey(output, keydata, passphrase,
980					strlen((char *)passphrase), 1);
981	}
982	printf("%s", (char *) __ops_mem_data(mem));
983	__ops_teardown_memory_write(output, mem);
984	return 1;
985}
986
987/* add a key to a public keyring */
988int
989__ops_add_to_pubring(__ops_keyring_t *keyring, const __ops_pubkey_t *pubkey)
990{
991	__ops_key_t	*key;
992
993	EXPAND_ARRAY(keyring, key);
994	key = &keyring->keys[keyring->keyc++];
995	(void) memset(key, 0x0, sizeof(*key));
996	__ops_keyid(key->key_id, OPS_KEY_ID_SIZE, pubkey);
997	__ops_fingerprint(&key->fingerprint, pubkey);
998	key->type = OPS_PTAG_CT_PUBLIC_KEY;
999	key->key.pubkey = *pubkey;
1000	return 1;
1001}
1002
1003/* add a key to a secret keyring */
1004int
1005__ops_add_to_secring(__ops_keyring_t *keyring, const __ops_seckey_t *seckey)
1006{
1007	const __ops_pubkey_t	*pubkey;
1008	__ops_key_t		*key;
1009
1010	EXPAND_ARRAY(keyring, key);
1011	key = &keyring->keys[keyring->keyc++];
1012	(void) memset(key, 0x0, sizeof(*key));
1013	pubkey = &seckey->pubkey;
1014	__ops_keyid(key->key_id, OPS_KEY_ID_SIZE, pubkey);
1015	__ops_fingerprint(&key->fingerprint, pubkey);
1016	key->type = OPS_PTAG_CT_SECRET_KEY;
1017	key->key.seckey = *seckey;
1018	return 1;
1019}
1020
1021/* append one keyring to another */
1022int
1023__ops_append_keyring(__ops_keyring_t *keyring, __ops_keyring_t *newring)
1024{
1025	unsigned	i;
1026
1027	for (i = 0 ; i < newring->keyc ; i++) {
1028		EXPAND_ARRAY(keyring, key);
1029		(void) memcpy(&keyring->keys[keyring->keyc], &newring->keys[i],
1030				sizeof(newring->keys[i]));
1031		keyring->keyc += 1;
1032	}
1033	return 1;
1034}
1035