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