netpgp.c revision 1.33
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#include "config.h" 30 31#ifdef HAVE_SYS_CDEFS_H 32#include <sys/cdefs.h> 33#endif 34 35#if defined(__NetBSD__) 36__COPYRIGHT("@(#) Copyright (c) 2009 The NetBSD Foundation, Inc. All rights reserved."); 37__RCSID("$NetBSD: netpgp.c,v 1.33 2009/12/14 23:29:56 agc Exp $"); 38#endif 39 40#include <sys/types.h> 41#include <sys/stat.h> 42#include <sys/param.h> 43#include <sys/mman.h> 44 45#ifdef HAVE_SYS_RESOURCE_H 46#include <sys/resource.h> 47#endif 48 49#ifdef HAVE_FCNTL_H 50#include <fcntl.h> 51#endif 52 53#include <errno.h> 54#include <regex.h> 55#include <stdarg.h> 56#include <stdlib.h> 57#include <string.h> 58#include <time.h> 59 60#ifdef HAVE_UNISTD_H 61#include <unistd.h> 62#endif 63 64#include <errno.h> 65 66#ifdef HAVE_LIMITS_H 67#include <limits.h> 68#endif 69 70#include <netpgp.h> 71 72#include "packet.h" 73#include "packet-parse.h" 74#include "keyring.h" 75#include "errors.h" 76#include "packet-show.h" 77#include "create.h" 78#include "netpgpsdk.h" 79#include "memory.h" 80#include "validate.h" 81#include "readerwriter.h" 82#include "netpgpdefs.h" 83#include "crypto.h" 84#include "ops-ssh.h" 85 86/* read any gpg config file */ 87static int 88conffile(netpgp_t *netpgp, char *homedir, char *userid, size_t length) 89{ 90 regmatch_t matchv[10]; 91 regex_t keyre; 92 char buf[BUFSIZ]; 93 FILE *fp; 94 95 __OPS_USED(netpgp); 96 (void) snprintf(buf, sizeof(buf), "%s/gpg.conf", homedir); 97 if ((fp = fopen(buf, "r")) == NULL) { 98 return 0; 99 } 100 (void) memset(&keyre, 0x0, sizeof(keyre)); 101 (void) regcomp(&keyre, "^[ \t]*default-key[ \t]+([0-9a-zA-F]+)", 102 REG_EXTENDED); 103 while (fgets(buf, sizeof(buf), fp) != NULL) { 104 if (regexec(&keyre, buf, 10, matchv, 0) == 0) { 105 (void) memcpy(userid, &buf[(int)matchv[1].rm_so], 106 MIN((unsigned)(matchv[1].rm_eo - 107 matchv[1].rm_so), length)); 108 (void) fprintf(stderr, 109 "netpgp: default key set to \"%.*s\"\n", 110 (int)(matchv[1].rm_eo - matchv[1].rm_so), 111 &buf[(int)matchv[1].rm_so]); 112 } 113 } 114 (void) fclose(fp); 115 return 1; 116} 117 118/* small function to pretty print an 8-character raw userid */ 119static char * 120userid_to_id(const unsigned char *userid, char *id) 121{ 122 static const char *hexes = "0123456789abcdef"; 123 int i; 124 125 for (i = 0; i < 8 ; i++) { 126 id[i * 2] = hexes[(unsigned)(userid[i] & 0xf0) >> 4]; 127 id[(i * 2) + 1] = hexes[userid[i] & 0xf]; 128 } 129 id[8 * 2] = 0x0; 130 return id; 131} 132 133/* print out the successful signature information */ 134static void 135resultp(__ops_io_t *io, 136 const char *f, 137 __ops_validation_t *res, 138 __ops_keyring_t *ring) 139{ 140 const __ops_key_t *pubkey; 141 unsigned from; 142 unsigned i; 143 char id[MAX_ID_LENGTH + 1]; 144 145 for (i = 0; i < res->validc; i++) { 146 (void) fprintf(io->res, 147 "Good signature for %s made %susing %s key %s\n", 148 f, 149 ctime(&res->valid_sigs[i].birthtime), 150 __ops_show_pka(res->valid_sigs[i].key_alg), 151 userid_to_id(res->valid_sigs[i].signer_id, id)); 152 from = 0; 153 pubkey = __ops_getkeybyid(io, ring, 154 (const unsigned char *) res->valid_sigs[i].signer_id, 155 &from); 156 __ops_print_keydata(io, pubkey, "pub", &pubkey->key.pubkey); 157 } 158} 159 160/* check there's enough space in the arrays */ 161static int 162size_arrays(netpgp_t *netpgp, unsigned needed) 163{ 164 char **temp; 165 166 if (netpgp->size == 0) { 167 /* only get here first time around */ 168 netpgp->size = needed; 169 if ((netpgp->name = calloc(sizeof(char *), needed)) == NULL) { 170 (void) fprintf(stderr, "size_arrays: bad alloc\n"); 171 return 0; 172 } 173 if ((netpgp->value = calloc(sizeof(char *), needed)) == NULL) { 174 free(netpgp->name); 175 (void) fprintf(stderr, "size_arrays: bad alloc\n"); 176 return 0; 177 } 178 } else if (netpgp->c == netpgp->size) { 179 /* only uses 'needed' when filled array */ 180 netpgp->size += needed; 181 temp = realloc(netpgp->name, sizeof(char *) * needed); 182 if (temp == NULL) { 183 (void) fprintf(stderr, "size_arrays: bad alloc\n"); 184 return 0; 185 } 186 netpgp->name = temp; 187 temp = realloc(netpgp->value, sizeof(char *) * needed); 188 if (temp == NULL) { 189 (void) fprintf(stderr, "size_arrays: bad alloc\n"); 190 return 0; 191 } 192 netpgp->value = temp; 193 } 194 return 1; 195} 196 197/* find the name in the array */ 198static int 199findvar(netpgp_t *netpgp, const char *name) 200{ 201 unsigned i; 202 203 for (i = 0 ; i < netpgp->c && strcmp(netpgp->name[i], name) != 0; i++) { 204 } 205 return (i == netpgp->c) ? -1 : (int)i; 206} 207 208/* read a keyring and return it */ 209static void * 210readkeyring(netpgp_t *netpgp, const char *name) 211{ 212 __ops_keyring_t *keyring; 213 const unsigned noarmor = 0; 214 char f[MAXPATHLEN]; 215 char *filename; 216 char *homedir; 217 218 homedir = netpgp_getvar(netpgp, "homedir"); 219 if ((filename = netpgp_getvar(netpgp, name)) == NULL) { 220 (void) snprintf(f, sizeof(f), "%s/%s.gpg", homedir, name); 221 filename = f; 222 } 223 if ((keyring = calloc(1, sizeof(*keyring))) == NULL) { 224 (void) fprintf(stderr, "readkeyring: bad alloc\n"); 225 return NULL; 226 } 227 if (!__ops_keyring_fileread(keyring, noarmor, filename)) { 228 free(keyring); 229 (void) fprintf(stderr, "Can't read %s %s\n", name, filename); 230 return NULL; 231 } 232 netpgp_setvar(netpgp, name, filename); 233 return keyring; 234} 235 236/* read keys from ssh key files */ 237static int 238readsshkeys(netpgp_t *netpgp, char *homedir) 239{ 240 __ops_keyring_t *pubring; 241 __ops_keyring_t *secring; 242 char f[MAXPATHLEN]; 243 char *filename; 244 245 if ((filename = netpgp_getvar(netpgp, "sshkeyfile")) == NULL) { 246 (void) snprintf(f, sizeof(f), "%s/.ssh/is_rsa.pub", homedir); 247 filename = f; 248 } 249 if ((pubring = calloc(1, sizeof(*pubring))) == NULL) { 250 (void) fprintf(stderr, "readsshkeys: bad alloc\n"); 251 return 0; 252 } 253 if (!__ops_ssh2_readkeys(netpgp->io, pubring, NULL, filename, NULL)) { 254 free(pubring); 255 (void) fprintf(stderr, "readsshkeys: can't read %s\n", 256 filename); 257 return 0; 258 } 259 netpgp->pubring = pubring; 260 netpgp_setvar(netpgp, "sshpubfile", filename); 261 /* try to take the ".pub" off the end */ 262 if (filename == f) { 263 f[strlen(f) - 4] = 0x0; 264 } else { 265 (void) snprintf(f, sizeof(f), "%.*s", 266 (int)strlen(filename) - 4, filename); 267 filename = f; 268 } 269 if ((secring = calloc(1, sizeof(*secring))) == NULL) { 270 (void) fprintf(stderr, "readsshkeys: bad alloc\n"); 271 return 0; 272 } 273 if (__ops_ssh2_readkeys(netpgp->io, pubring, secring, NULL, filename)) { 274 netpgp->secring = secring; 275 netpgp_setvar(netpgp, "sshsecfile", filename); 276 } else { 277 (void) fprintf(stderr, "readsshkeys: can't read sec %s (%d)\n", 278 filename, errno); 279 } 280 return 1; 281} 282 283/* set ssh uid to first one in ring */ 284static void 285set_ssh_userid(__ops_keyring_t *pubring, char *id, size_t len) 286{ 287 unsigned char *src; 288 int i; 289 int n; 290 291 (void) memset(id, 0x0, len); 292 src = pubring->keys[0].key_id; 293 for (i = 0, n = 0 ; i < OPS_KEY_ID_SIZE ; i += 2) { 294 n += snprintf(&id[n], len - n, "%02x%02x", src[i], src[i + 1]); 295 } 296 id[n] = 0x0; 297} 298 299/***************************************************************************/ 300/* exported functions start here */ 301/***************************************************************************/ 302 303/* initialise a netpgp_t structure */ 304int 305netpgp_init(netpgp_t *netpgp) 306{ 307 __ops_io_t *io; 308 char id[MAX_ID_LENGTH]; 309 char *homedir; 310 char *userid; 311 char *stream; 312 char *passfd; 313 char *results; 314 int coredumps; 315 316#ifdef HAVE_SYS_RESOURCE_H 317 struct rlimit limit; 318 319 coredumps = netpgp_getvar(netpgp, "coredumps") != NULL; 320 if (!coredumps) { 321 (void) memset(&limit, 0x0, sizeof(limit)); 322 if (setrlimit(RLIMIT_CORE, &limit) != 0) { 323 (void) fprintf(stderr, 324 "netpgp_init: warning - can't turn off core dumps\n"); 325 coredumps = 1; 326 } 327 } 328#else 329 coredumps = 1; 330#endif 331 if ((io = calloc(1, sizeof(*io))) == NULL) { 332 (void) fprintf(stderr, "netpgp_init: bad alloc\n"); 333 return 0; 334 } 335 io->outs = stdout; 336 if ((stream = netpgp_getvar(netpgp, "stdout")) != NULL && 337 strcmp(stream, "stderr") == 0) { 338 io->outs = stderr; 339 } 340 io->errs = stderr; 341 if ((stream = netpgp_getvar(netpgp, "stderr")) != NULL && 342 strcmp(stream, "stdout") == 0) { 343 io->errs = stdout; 344 } 345 if ((results = netpgp_getvar(netpgp, "results")) == NULL) { 346 io->res = io->errs; 347 } else if ((io->res = fopen(results, "w")) == NULL) { 348 (void) fprintf(io->errs, "Can't open results %s for writing\n", 349 results); 350 return 0; 351 } 352 netpgp->io = io; 353 if (coredumps) { 354 (void) fprintf(io->errs, 355 "netpgp: warning: core dumps enabled\n"); 356 } 357 if ((homedir = netpgp_getvar(netpgp, "homedir")) == NULL) { 358 (void) fprintf(io->errs, "netpgp: bad homedir\n"); 359 return 0; 360 } 361 /* read from either gpg files or ssh keys */ 362 if (netpgp_getvar(netpgp, "ssh keys") == NULL) { 363 if ((userid = netpgp_getvar(netpgp, "userid")) == NULL) { 364 (void) memset(id, 0x0, sizeof(id)); 365 (void) conffile(netpgp, homedir, id, sizeof(id)); 366 if (id[0] != 0x0) { 367 netpgp_setvar(netpgp, "userid", userid = id); 368 } 369 } 370 if (userid == NULL) { 371 if (netpgp_getvar(netpgp, "need userid") != NULL) { 372 (void) fprintf(io->errs, 373 "Cannot find user id\n"); 374 return 0; 375 } 376 } else { 377 (void) netpgp_setvar(netpgp, "userid", userid); 378 } 379 netpgp->pubring = readkeyring(netpgp, "pubring"); 380 if (netpgp->pubring == NULL) { 381 (void) fprintf(io->errs, "Can't read pub keyring\n"); 382 return 0; 383 } 384 netpgp->secring = readkeyring(netpgp, "secring"); 385 if (netpgp->secring == NULL) { 386 (void) fprintf(io->errs, "Can't read sec keyring\n"); 387 return 0; 388 } 389 } else { 390 if (!readsshkeys(netpgp, homedir)) { 391 (void) fprintf(io->errs, "Can't read ssh pub key\n"); 392 return 0; 393 } 394 if ((userid = netpgp_getvar(netpgp, "userid")) == NULL) { 395 set_ssh_userid(netpgp->pubring, id, sizeof(id)); 396 netpgp_setvar(netpgp, "userid", userid = id); 397 } 398 if (userid == NULL) { 399 if (netpgp_getvar(netpgp, "need userid") != NULL) { 400 (void) fprintf(io->errs, 401 "Cannot find user id\n"); 402 return 0; 403 } 404 } else { 405 (void) netpgp_setvar(netpgp, "userid", userid); 406 } 407 } 408 if ((passfd = netpgp_getvar(netpgp, "pass-fd")) != NULL && 409 (netpgp->passfp = fdopen(atoi(passfd), "r")) == NULL) { 410 (void) fprintf(io->errs, "Can't open fd %s for reading\n", 411 passfd); 412 return 0; 413 } 414 return 1; 415} 416 417/* finish off with the netpgp_t struct */ 418int 419netpgp_end(netpgp_t *netpgp) 420{ 421 unsigned i; 422 423 for (i = 0 ; i < netpgp->c ; i++) { 424 if (netpgp->name[i] != NULL) { 425 free(netpgp->name[i]); 426 } 427 if (netpgp->value[i] != NULL) { 428 free(netpgp->value[i]); 429 } 430 } 431 if (netpgp->name != NULL) { 432 free(netpgp->name); 433 } 434 if (netpgp->value != NULL) { 435 free(netpgp->value); 436 } 437 if (netpgp->pubring != NULL) { 438 __ops_keyring_free(netpgp->pubring); 439 } 440 if (netpgp->secring != NULL) { 441 __ops_keyring_free(netpgp->secring); 442 } 443 free(netpgp->io); 444 return 1; 445} 446 447/* list the keys in a keyring */ 448int 449netpgp_list_keys(netpgp_t *netpgp) 450{ 451 return __ops_keyring_list(netpgp->io, netpgp->pubring); 452} 453 454/* find and list some keys in a keyring */ 455int 456netpgp_match_list_keys(netpgp_t *netpgp, char *name) 457{ 458 const __ops_key_t *key; 459 unsigned found; 460 unsigned k; 461 char *data; 462 463 found = k = 0; 464 do { 465 key = __ops_getnextkeybyname(netpgp->io, netpgp->pubring, 466 name, &k); 467 if (key != NULL) { 468 __ops_sprint_keydata(key, &data, "pub", 469 &key->key.pubkey); 470 printf("%s\n", data); 471 free(data); 472 found += 1; 473 k += 1; 474 } 475 } while (key != NULL); 476 printf("Found %u key%s\n", found, (found == 1) ? "" : "s"); 477 return (found > 0); 478} 479 480/* find a key in a keyring */ 481int 482netpgp_find_key(netpgp_t *netpgp, char *id) 483{ 484 __ops_io_t *io; 485 486 io = netpgp->io; 487 if (id == NULL) { 488 (void) fprintf(io->errs, "NULL id to search for\n"); 489 return 0; 490 } 491 return __ops_getkeybyname(netpgp->io, netpgp->pubring, id) != NULL; 492} 493 494/* get a key in a keyring */ 495char * 496netpgp_get_key(netpgp_t *netpgp, const char *id) 497{ 498 const __ops_key_t *key; 499 __ops_io_t *io; 500 char *newkey; 501 502 io = netpgp->io; 503 if (id == NULL) { 504 (void) fprintf(io->errs, "NULL id to search for\n"); 505 return NULL; 506 } 507 key = __ops_getkeybyname(netpgp->io, netpgp->pubring, id); 508 if (key == NULL) { 509 (void) fprintf(io->errs, "Can't find key '%s'\n", id); 510 return NULL; 511 } 512 return (__ops_sprint_keydata(key, &newkey, "pub", 513 &key->key.pubkey) > 0) ? newkey : NULL; 514} 515 516/* export a given key */ 517int 518netpgp_export_key(netpgp_t *netpgp, char *userid) 519{ 520 const __ops_key_t *keypair; 521 __ops_io_t *io; 522 523 io = netpgp->io; 524 if (userid == NULL) { 525 userid = netpgp_getvar(netpgp, "userid"); 526 } 527 keypair = __ops_getkeybyname(io, netpgp->pubring, userid); 528 if (keypair == NULL) { 529 (void) fprintf(io->errs, 530 "Cannot find own key \"%s\" in keyring\n", userid); 531 return 0; 532 } 533 return __ops_export_key(keypair, NULL); 534} 535 536/* import a key into our keyring */ 537int 538netpgp_import_key(netpgp_t *netpgp, char *f) 539{ 540 const unsigned noarmor = 0; 541 const unsigned armor = 1; 542 __ops_io_t *io; 543 int done; 544 545 io = netpgp->io; 546 if ((done = __ops_keyring_fileread(netpgp->pubring, noarmor, f)) == 0) { 547 done = __ops_keyring_fileread(netpgp->pubring, armor, f); 548 } 549 if (!done) { 550 (void) fprintf(io->errs, "Cannot import key from file %s\n", 551 f); 552 return 0; 553 } 554 return __ops_keyring_list(io, netpgp->pubring); 555} 556 557/* generate a new key */ 558int 559netpgp_generate_key(netpgp_t *netpgp, char *id, int numbits) 560{ 561 __ops_key_t *keypair; 562 __ops_userid_t uid; 563 __ops_output_t *create; 564 const unsigned noarmor = 0; 565 __ops_io_t *io; 566 char *ringfile; 567 int fd; 568 569 (void) memset(&uid, 0x0, sizeof(uid)); 570 io = netpgp->io; 571 /* generate a new key for 'id' */ 572 uid.userid = (unsigned char *) id; 573 keypair = __ops_rsa_new_selfsign_key(numbits, 65537UL, &uid); 574 if (keypair == NULL) { 575 (void) fprintf(io->errs, "Cannot generate key\n"); 576 return 0; 577 } 578 /* write public key, and try to re-read it */ 579 ringfile = netpgp_getvar(netpgp, "pubring"); 580 fd = __ops_setup_file_append(&create, ringfile); 581 if (!__ops_write_xfer_pubkey(create, keypair, noarmor)) { 582 (void) fprintf(io->errs, "Cannot write pubkey\n"); 583 return 0; 584 } 585 __ops_teardown_file_write(create, fd); 586 __ops_keyring_free(netpgp->pubring); 587 if (!__ops_keyring_fileread(netpgp->pubring, noarmor, ringfile)) { 588 (void) fprintf(io->errs, "Cannot read pubring %s\n", ringfile); 589 return 0; 590 } 591 /* write secret key, and try to re-read it */ 592 ringfile = netpgp_getvar(netpgp, "sec ring file"); 593 fd = __ops_setup_file_append(&create, ringfile); 594 if (!__ops_write_xfer_seckey(create, keypair, NULL, 0, noarmor)) { 595 (void) fprintf(io->errs, "Cannot write seckey\n"); 596 return 0; 597 } 598 __ops_teardown_file_write(create, fd); 599 __ops_keyring_free(netpgp->secring); 600 if (!__ops_keyring_fileread(netpgp->secring, noarmor, ringfile)) { 601 (void) fprintf(io->errs, "Can't read secring %s\n", ringfile); 602 return 0; 603 } 604 __ops_keydata_free(keypair); 605 return 1; 606} 607 608/* encrypt a file */ 609int 610netpgp_encrypt_file(netpgp_t *netpgp, 611 const char *userid, 612 const char *f, 613 char *out, 614 int armored) 615{ 616 const __ops_key_t *keypair; 617 const unsigned overwrite = 1; 618 const char *suffix; 619 __ops_io_t *io; 620 char outname[MAXPATHLEN]; 621 622 io = netpgp->io; 623 if (f == NULL) { 624 (void) fprintf(io->errs, 625 "netpgp_encrypt_file: no filename specified\n"); 626 return 0; 627 } 628 if (userid == NULL) { 629 userid = netpgp_getvar(netpgp, "userid"); 630 } 631 suffix = (armored) ? ".asc" : ".gpg"; 632 keypair = __ops_getkeybyname(io, netpgp->pubring, userid); 633 if (keypair == NULL) { 634 (void) fprintf(io->errs, "Userid '%s' not found in keyring\n", 635 userid); 636 return 0; 637 } 638 if (out == NULL) { 639 (void) snprintf(outname, sizeof(outname), "%s%s", f, suffix); 640 out = outname; 641 } 642 return (int)__ops_encrypt_file(io, f, out, keypair, (unsigned)armored, 643 overwrite); 644} 645 646/* decrypt a file */ 647int 648netpgp_decrypt_file(netpgp_t *netpgp, const char *f, char *out, int armored) 649{ 650 const unsigned overwrite = 1; 651 __ops_io_t *io; 652 653 io = netpgp->io; 654 if (f == NULL) { 655 (void) fprintf(io->errs, 656 "netpgp_decrypt_file: no filename specified\n"); 657 return 0; 658 } 659 return __ops_decrypt_file(netpgp->io, f, out, netpgp->secring, 660 (unsigned)armored, overwrite, netpgp->passfp, 661 get_passphrase_cb); 662} 663 664/* sign a file */ 665int 666netpgp_sign_file(netpgp_t *netpgp, 667 const char *userid, 668 const char *f, 669 char *out, 670 int armored, 671 int cleartext, 672 int detached) 673{ 674 const __ops_key_t *keypair; 675 __ops_seckey_t *seckey; 676 const unsigned overwrite = 1; 677 __ops_io_t *io; 678 char *hashalg; 679 int ret; 680 681 io = netpgp->io; 682 if (f == NULL) { 683 (void) fprintf(io->errs, 684 "netpgp_sign_file: no filename specified\n"); 685 return 0; 686 } 687 if (userid == NULL) { 688 userid = netpgp_getvar(netpgp, "userid"); 689 } 690 /* get key with which to sign */ 691 keypair = __ops_getkeybyname(io, netpgp->secring, userid); 692 if (keypair == NULL) { 693 (void) fprintf(io->errs, "Userid '%s' not found in keyring\n", 694 userid); 695 return 0; 696 } 697 ret = 1; 698 do { 699 /* print out the user id */ 700 __ops_print_keydata(io, keypair, "pub", &keypair->key.pubkey); 701 if (netpgp_getvar(netpgp, "ssh keys") == NULL) { 702 /* now decrypt key */ 703 seckey = __ops_decrypt_seckey(keypair); 704 if (seckey == NULL) { 705 (void) fprintf(io->errs, "Bad passphrase\n"); 706 } 707 } else { 708 __ops_keyring_t *secring; 709 710 secring = netpgp->secring; 711 seckey = &secring->keys[0].key.seckey; 712 } 713 } while (seckey == NULL); 714 /* sign file */ 715 hashalg = netpgp_getvar(netpgp, "hash"); 716 if (detached) { 717 ret = __ops_sign_detached(io, f, out, seckey, hashalg); 718 } else { 719 ret = __ops_sign_file(io, f, out, seckey, hashalg, 720 (unsigned)armored, (unsigned)cleartext, 721 overwrite); 722 } 723 __ops_forget(seckey, sizeof(*seckey)); 724 return ret; 725} 726 727/* verify a file */ 728int 729netpgp_verify_file(netpgp_t *netpgp, const char *in, const char *out, int armored) 730{ 731 __ops_validation_t result; 732 __ops_io_t *io; 733 734 (void) memset(&result, 0x0, sizeof(result)); 735 io = netpgp->io; 736 if (in == NULL) { 737 (void) fprintf(io->errs, 738 "netpgp_verify_file: no filename specified\n"); 739 return 0; 740 } 741 if (__ops_validate_file(io, &result, in, out, armored, 742 netpgp->pubring)) { 743 resultp(io, in, &result, netpgp->pubring); 744 return 1; 745 } 746 if (result.validc + result.invalidc + result.unknownc == 0) { 747 (void) fprintf(io->errs, 748 "\"%s\": No signatures found - is this a signed file?\n", 749 in); 750 } else { 751 (void) fprintf(io->errs, 752"\"%s\": verification failure: %u invalid signatures, %u unknown signatures\n", 753 in, result.invalidc, result.unknownc); 754 } 755 return 0; 756} 757 758/* sign some memory */ 759int 760netpgp_sign_memory(netpgp_t *netpgp, 761 const char *userid, 762 char *mem, 763 size_t size, 764 char *out, 765 size_t outsize, 766 const unsigned armored, 767 const unsigned cleartext) 768{ 769 const __ops_key_t *keypair; 770 __ops_seckey_t *seckey; 771 __ops_memory_t *signedmem; 772 __ops_io_t *io; 773 char *hashalg; 774 int ret; 775 776 io = netpgp->io; 777 if (mem == NULL) { 778 (void) fprintf(io->errs, 779 "netpgp_sign_memory: no memory to sign\n"); 780 return 0; 781 } 782 if (userid == NULL) { 783 userid = netpgp_getvar(netpgp, "userid"); 784 } 785 /* get key with which to sign */ 786 keypair = __ops_getkeybyname(io, netpgp->secring, userid); 787 if (keypair == NULL) { 788 (void) fprintf(io->errs, "Userid '%s' not found in keyring\n", 789 userid); 790 return 0; 791 } 792 ret = 1; 793 do { 794 /* print out the user id */ 795 __ops_print_keydata(io, keypair, "pub", &keypair->key.pubkey); 796 /* now decrypt key */ 797 seckey = __ops_decrypt_seckey(keypair); 798 if (seckey == NULL) { 799 (void) fprintf(io->errs, "Bad passphrase\n"); 800 } 801 } while (seckey == NULL); 802 /* sign file */ 803 hashalg = netpgp_getvar(netpgp, "hash"); 804 signedmem = __ops_sign_buf(io, mem, size, seckey, hashalg, 805 armored, cleartext); 806 if (signedmem) { 807 size_t m; 808 809 m = MIN(__ops_mem_len(signedmem), outsize); 810 (void) memcpy(out, __ops_mem_data(signedmem), m); 811 __ops_memory_free(signedmem); 812 } 813 __ops_forget(seckey, sizeof(*seckey)); 814 return ret; 815} 816 817/* verify memory */ 818int 819netpgp_verify_memory(netpgp_t *netpgp, const void *in, const size_t size, 820 const int armored) 821{ 822 __ops_validation_t result; 823 __ops_memory_t *signedmem; 824 __ops_io_t *io; 825 int ret; 826 827 (void) memset(&result, 0x0, sizeof(result)); 828 io = netpgp->io; 829 if (in == NULL) { 830 (void) fprintf(io->errs, 831 "netpgp_verify_memory: no memory to verify\n"); 832 return 0; 833 } 834 signedmem = __ops_memory_new(); 835 __ops_memory_add(signedmem, in, size); 836 ret = __ops_validate_mem(io, &result, signedmem, armored, 837 netpgp->pubring); 838 __ops_memory_free(signedmem); 839 if (ret) { 840 resultp(io, in, &result, netpgp->pubring); 841 return 1; 842 } 843 if (result.validc + result.invalidc + result.unknownc == 0) { 844 (void) fprintf(io->errs, 845 "No signatures found - is this memory signed?\n"); 846 } else { 847 (void) fprintf(io->errs, 848"memory verification failure: %u invalid signatures, %u unknown signatures\n", 849 result.invalidc, result.unknownc); 850 } 851 return 0; 852} 853 854/* wrappers for the ops_debug_level functions we added to openpgpsdk */ 855 856/* set the debugging level per filename */ 857int 858netpgp_set_debug(const char *f) 859{ 860 return __ops_set_debug_level(f); 861} 862 863/* get the debugging level per filename */ 864int 865netpgp_get_debug(const char *f) 866{ 867 return __ops_get_debug_level(f); 868} 869 870/* return the version for the library */ 871const char * 872netpgp_get_info(const char *type) 873{ 874 return __ops_get_info(type); 875} 876 877/* list all the packets in a file */ 878int 879netpgp_list_packets(netpgp_t *netpgp, char *f, int armour, char *pubringname) 880{ 881 __ops_keyring_t *keyring; 882 const unsigned noarmor = 0; 883 __ops_io_t *io; 884 char ringname[MAXPATHLEN]; 885 char *homedir; 886 int ret; 887 888 io = netpgp->io; 889 if (f == NULL) { 890 (void) fprintf(io->errs, "No file containing packets\n"); 891 return 0; 892 } 893 homedir = netpgp_getvar(netpgp, "homedir"); 894 if (pubringname == NULL) { 895 (void) snprintf(ringname, sizeof(ringname), 896 "%s/pubring.gpg", homedir); 897 pubringname = ringname; 898 } 899 if ((keyring = calloc(1, sizeof(*keyring))) == NULL) { 900 (void) fprintf(io->errs, "netpgp_list_packets: bad alloc\n"); 901 return 0; 902 } 903 if (!__ops_keyring_fileread(keyring, noarmor, pubringname)) { 904 free(keyring); 905 (void) fprintf(io->errs, "Cannot read pub keyring %s\n", 906 pubringname); 907 return 0; 908 } 909 netpgp->pubring = keyring; 910 netpgp_setvar(netpgp, "pubring", pubringname); 911 ret = __ops_list_packets(io, f, (unsigned)armour, keyring, 912 netpgp->passfp, 913 get_passphrase_cb); 914 free(keyring); 915 return ret; 916} 917 918/* set a variable */ 919int 920netpgp_setvar(netpgp_t *netpgp, const char *name, const char *value) 921{ 922 int i; 923 924 if ((i = findvar(netpgp, name)) < 0) { 925 /* add the element to the array */ 926 if (size_arrays(netpgp, netpgp->size + 15)) { 927 netpgp->name[i = netpgp->c++] = strdup(name); 928 } 929 } else { 930 /* replace the element in the array */ 931 if (netpgp->value[i]) { 932 free(netpgp->value[i]); 933 netpgp->value[i] = NULL; 934 } 935 } 936 /* sanity checks for range of values */ 937 if (strcmp(name, "hash") == 0 || strcmp(name, "algorithm") == 0) { 938 if (__ops_str_to_hash_alg(value) == OPS_HASH_UNKNOWN) { 939 return 0; 940 } 941 } 942 netpgp->value[i] = strdup(value); 943 return 1; 944} 945 946/* get a variable's value (NULL if not set) */ 947char * 948netpgp_getvar(netpgp_t *netpgp, const char *name) 949{ 950 int i; 951 952 return ((i = findvar(netpgp, name)) < 0) ? NULL : netpgp->value[i]; 953} 954 955/* increment a value */ 956int 957netpgp_incvar(netpgp_t *netpgp, const char *name, const int delta) 958{ 959 char *cp; 960 char num[16]; 961 int val; 962 963 val = 0; 964 if ((cp = netpgp_getvar(netpgp, name)) != NULL) { 965 val = atoi(cp); 966 } 967 (void) snprintf(num, sizeof(num), "%d", val + delta); 968 netpgp_setvar(netpgp, name, num); 969 return 1; 970} 971 972/* set the home directory value to "home/subdir" */ 973int 974netpgp_set_homedir(netpgp_t *netpgp, char *home, const char *subdir, const int quiet) 975{ 976 struct stat st; 977 char d[MAXPATHLEN]; 978 979 if (home == NULL) { 980 if (!quiet) { 981 (void) fprintf(stderr, "NULL HOME directory\n"); 982 } 983 return 0; 984 } 985 (void) snprintf(d, sizeof(d), "%s%s", home, (subdir) ? subdir : ""); 986 if (stat(d, &st) == 0) { 987 if ((st.st_mode & S_IFMT) == S_IFDIR) { 988 netpgp_setvar(netpgp, "homedir", d); 989 return 1; 990 } 991 (void) fprintf(stderr, "netpgp: homedir \"%s\" is not a dir\n", 992 d); 993 return 0; 994 } 995 if (!quiet) { 996 (void) fprintf(stderr, 997 "netpgp: warning homedir \"%s\" not found\n", d); 998 } 999 return 1; 1000} 1001