netpgp.c revision 1.32
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.32 2009/12/07 16:17:17 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, const char *pubname, const char *secname) 239{ 240 __ops_keyring_t *pubring; 241 __ops_keyring_t *secring; 242 char f[MAXPATHLEN]; 243 char *filename; 244 char *etcdir; 245 246 __OPS_USED(secname); 247 etcdir = netpgp_getvar(netpgp, "sshkeydir"); 248 if ((filename = netpgp_getvar(netpgp, pubname)) == NULL) { 249 (void) snprintf(f, sizeof(f), "%s/ssh_host_rsa_key.pub", etcdir); 250 filename = f; 251 } 252 if ((pubring = calloc(1, sizeof(*pubring))) == NULL) { 253 (void) fprintf(stderr, "readsshkeys: bad alloc\n"); 254 return 0; 255 } 256 if (!__ops_ssh2_readkeys(netpgp->io, pubring, NULL, filename, NULL)) { 257 free(pubring); 258 (void) fprintf(stderr, "readsshkeys: can't read %s\n", filename); 259 return 0; 260 } 261 netpgp->pubring = pubring; 262 netpgp_setvar(netpgp, pubname, filename); 263 if ((filename = netpgp_getvar(netpgp, secname)) == NULL) { 264 (void) snprintf(f, sizeof(f), "%s/ssh_host_rsa_key", etcdir); 265 filename = f; 266 } 267 if ((secring = calloc(1, sizeof(*secring))) == NULL) { 268 (void) fprintf(stderr, "readsshkeys: bad alloc\n"); 269 return 0; 270 } 271 if (__ops_ssh2_readkeys(netpgp->io, pubring, secring, NULL, filename)) { 272 netpgp->secring = secring; 273 netpgp_setvar(netpgp, secname, filename); 274 } else { 275 (void) fprintf(stderr, "readsshkeys: can't read sec %s (%d)\n", filename, errno); 276 } 277 return 1; 278} 279 280/***************************************************************************/ 281/* exported functions start here */ 282/***************************************************************************/ 283 284/* initialise a netpgp_t structure */ 285int 286netpgp_init(netpgp_t *netpgp) 287{ 288 __ops_io_t *io; 289 char id[MAX_ID_LENGTH]; 290 char *homedir; 291 char *userid; 292 char *stream; 293 char *passfd; 294 char *results; 295 int coredumps; 296 297#ifdef HAVE_SYS_RESOURCE_H 298 struct rlimit limit; 299 300 coredumps = netpgp_getvar(netpgp, "coredumps") != NULL; 301 if (!coredumps) { 302 (void) memset(&limit, 0x0, sizeof(limit)); 303 if (setrlimit(RLIMIT_CORE, &limit) != 0) { 304 (void) fprintf(stderr, 305 "netpgp_init: warning - can't turn off core dumps\n"); 306 coredumps = 1; 307 } 308 } 309#else 310 coredumps = 1; 311#endif 312 if ((io = calloc(1, sizeof(*io))) == NULL) { 313 (void) fprintf(stderr, "netpgp_init: bad alloc\n"); 314 return 0; 315 } 316 io->outs = stdout; 317 if ((stream = netpgp_getvar(netpgp, "stdout")) != NULL && 318 strcmp(stream, "stderr") == 0) { 319 io->outs = stderr; 320 } 321 io->errs = stderr; 322 if ((stream = netpgp_getvar(netpgp, "stderr")) != NULL && 323 strcmp(stream, "stdout") == 0) { 324 io->errs = stdout; 325 } 326 if ((results = netpgp_getvar(netpgp, "results")) == NULL) { 327 io->res = io->errs; 328 } else if ((io->res = fopen(results, "w")) == NULL) { 329 (void) fprintf(io->errs, "Can't open results %s for writing\n", 330 results); 331 return 0; 332 } 333 netpgp->io = io; 334 if (coredumps) { 335 (void) fprintf(io->errs, 336 "netpgp: warning: core dumps enabled\n"); 337 } 338 if ((homedir = netpgp_getvar(netpgp, "homedir")) == NULL) { 339 (void) fprintf(io->errs, "netpgp: bad homedir\n"); 340 return 0; 341 } 342 /* read from either gpg files or ssh keys */ 343 if (netpgp_getvar(netpgp, "ssh keys") == NULL) { 344 if ((userid = netpgp_getvar(netpgp, "userid")) == NULL) { 345 (void) memset(id, 0x0, sizeof(id)); 346 (void) conffile(netpgp, homedir, id, sizeof(id)); 347 if (id[0] != 0x0) { 348 netpgp_setvar(netpgp, "userid", userid = id); 349 } 350 } 351 if (userid == NULL) { 352 if (netpgp_getvar(netpgp, "need userid") != NULL) { 353 (void) fprintf(io->errs, "Cannot find user id\n"); 354 return 0; 355 } 356 } else { 357 (void) netpgp_setvar(netpgp, "userid", userid); 358 } 359 if ((netpgp->pubring = readkeyring(netpgp, "pubring")) == NULL) { 360 (void) fprintf(io->errs, "Can't read pub keyring\n"); 361 return 0; 362 } 363 if ((netpgp->secring = readkeyring(netpgp, "secring")) == NULL) { 364 (void) fprintf(io->errs, "Can't read sec keyring\n"); 365 return 0; 366 } 367 } else { 368 if (!readsshkeys(netpgp, "ssh pub key", "ssh sec file")) { 369 (void) fprintf(io->errs, "Can't read ssh pub key\n"); 370 return 0; 371 } 372 if ((userid = netpgp_getvar(netpgp, "userid")) == NULL) { 373 /* set ssh uid to first one in ring */ 374 __ops_keyring_t *pubring; 375 unsigned char *src; 376 int i; 377 int n; 378 379 pubring = netpgp->pubring; 380 (void) memset(id, 0x0, sizeof(id)); 381 src = pubring->keys[0].key_id; 382 for (i = 0, n = 0 ; i < OPS_KEY_ID_SIZE ; i += 2) { 383 n += snprintf(&id[n], sizeof(id) - n, "%02x%02x", src[i], src[i + 1]); 384 } 385 id[n] = 0x0; 386 netpgp_setvar(netpgp, "userid", userid = id); 387 } 388 if (userid == NULL) { 389 if (netpgp_getvar(netpgp, "need userid") != NULL) { 390 (void) fprintf(io->errs, "Cannot find user id\n"); 391 return 0; 392 } 393 } else { 394 (void) netpgp_setvar(netpgp, "userid", userid); 395 } 396 } 397 if ((passfd = netpgp_getvar(netpgp, "pass-fd")) != NULL && 398 (netpgp->passfp = fdopen(atoi(passfd), "r")) == NULL) { 399 (void) fprintf(io->errs, "Can't open fd %s for reading\n", 400 passfd); 401 return 0; 402 } 403 return 1; 404} 405 406/* finish off with the netpgp_t struct */ 407int 408netpgp_end(netpgp_t *netpgp) 409{ 410 unsigned i; 411 412 for (i = 0 ; i < netpgp->c ; i++) { 413 if (netpgp->name[i] != NULL) { 414 free(netpgp->name[i]); 415 } 416 if (netpgp->value[i] != NULL) { 417 free(netpgp->value[i]); 418 } 419 } 420 if (netpgp->name != NULL) { 421 free(netpgp->name); 422 } 423 if (netpgp->value != NULL) { 424 free(netpgp->value); 425 } 426 if (netpgp->pubring != NULL) { 427 __ops_keyring_free(netpgp->pubring); 428 } 429 if (netpgp->secring != NULL) { 430 __ops_keyring_free(netpgp->secring); 431 } 432 free(netpgp->io); 433 return 1; 434} 435 436/* list the keys in a keyring */ 437int 438netpgp_list_keys(netpgp_t *netpgp) 439{ 440 return __ops_keyring_list(netpgp->io, netpgp->pubring); 441} 442 443/* find and list some keys in a keyring */ 444int 445netpgp_match_list_keys(netpgp_t *netpgp, char *name) 446{ 447 const __ops_key_t *key; 448 unsigned found; 449 unsigned k; 450 char *data; 451 452 found = k = 0; 453 do { 454 if ((key = __ops_getnextkeybyname(netpgp->io, netpgp->pubring, name, &k)) != NULL) { 455 __ops_sprint_keydata(key, &data, "pub", &key->key.pubkey); 456 printf("%s\n", data); 457 free(data); 458 found += 1; 459 k += 1; 460 } 461 } while (key != NULL); 462 printf("Found %u key%s\n", found, (found == 1) ? "" : "s"); 463 return (found > 0); 464} 465 466/* find a key in a keyring */ 467int 468netpgp_find_key(netpgp_t *netpgp, char *id) 469{ 470 __ops_io_t *io; 471 472 io = netpgp->io; 473 if (id == NULL) { 474 (void) fprintf(io->errs, "NULL id to search for\n"); 475 return 0; 476 } 477 return __ops_getkeybyname(netpgp->io, netpgp->pubring, id) != NULL; 478} 479 480/* get a key in a keyring */ 481char * 482netpgp_get_key(netpgp_t *netpgp, const char *id) 483{ 484 const __ops_key_t *key; 485 __ops_io_t *io; 486 char *newkey; 487 488 io = netpgp->io; 489 if (id == NULL) { 490 (void) fprintf(io->errs, "NULL id to search for\n"); 491 return NULL; 492 } 493 if ((key = __ops_getkeybyname(netpgp->io, netpgp->pubring, id)) == NULL) { 494 (void) fprintf(io->errs, "Can't find key '%s'\n", id); 495 return NULL; 496 } 497 return (__ops_sprint_keydata(key, &newkey, "pub", &key->key.pubkey) > 0) ? newkey : NULL; 498} 499 500/* export a given key */ 501int 502netpgp_export_key(netpgp_t *netpgp, char *userid) 503{ 504 const __ops_key_t *keypair; 505 __ops_io_t *io; 506 507 io = netpgp->io; 508 if (userid == NULL) { 509 userid = netpgp_getvar(netpgp, "userid"); 510 } 511 keypair = __ops_getkeybyname(io, netpgp->pubring, userid); 512 if (keypair == NULL) { 513 (void) fprintf(io->errs, 514 "Cannot find own key \"%s\" in keyring\n", userid); 515 return 0; 516 } 517 return __ops_export_key(keypair, NULL); 518} 519 520/* import a key into our keyring */ 521int 522netpgp_import_key(netpgp_t *netpgp, char *f) 523{ 524 const unsigned noarmor = 0; 525 const unsigned armor = 1; 526 __ops_io_t *io; 527 int done; 528 529 io = netpgp->io; 530 if ((done = __ops_keyring_fileread(netpgp->pubring, noarmor, f)) == 0) { 531 done = __ops_keyring_fileread(netpgp->pubring, armor, f); 532 } 533 if (!done) { 534 (void) fprintf(io->errs, "Cannot import key from file %s\n", 535 f); 536 return 0; 537 } 538 return __ops_keyring_list(io, netpgp->pubring); 539} 540 541/* generate a new key */ 542int 543netpgp_generate_key(netpgp_t *netpgp, char *id, int numbits) 544{ 545 __ops_key_t *keypair; 546 __ops_userid_t uid; 547 __ops_output_t *create; 548 const unsigned noarmor = 0; 549 __ops_io_t *io; 550 char *ringfile; 551 int fd; 552 553 (void) memset(&uid, 0x0, sizeof(uid)); 554 io = netpgp->io; 555 /* generate a new key for 'id' */ 556 uid.userid = (unsigned char *) id; 557 keypair = __ops_rsa_new_selfsign_key(numbits, 65537UL, &uid); 558 if (keypair == NULL) { 559 (void) fprintf(io->errs, "Cannot generate key\n"); 560 return 0; 561 } 562 /* write public key, and try to re-read it */ 563 ringfile = netpgp_getvar(netpgp, "pubring"); 564 fd = __ops_setup_file_append(&create, ringfile); 565 if (!__ops_write_xfer_pubkey(create, keypair, noarmor)) { 566 (void) fprintf(io->errs, "Cannot write pubkey\n"); 567 return 0; 568 } 569 __ops_teardown_file_write(create, fd); 570 __ops_keyring_free(netpgp->pubring); 571 if (!__ops_keyring_fileread(netpgp->pubring, noarmor, ringfile)) { 572 (void) fprintf(io->errs, "Cannot read pubring %s\n", ringfile); 573 return 0; 574 } 575 /* write secret key, and try to re-read it */ 576 ringfile = netpgp_getvar(netpgp, "sec ring file"); 577 fd = __ops_setup_file_append(&create, ringfile); 578 if (!__ops_write_xfer_seckey(create, keypair, NULL, 0, noarmor)) { 579 (void) fprintf(io->errs, "Cannot write seckey\n"); 580 return 0; 581 } 582 __ops_teardown_file_write(create, fd); 583 __ops_keyring_free(netpgp->secring); 584 if (!__ops_keyring_fileread(netpgp->secring, noarmor, ringfile)) { 585 (void) fprintf(io->errs, "Can't read secring %s\n", ringfile); 586 return 0; 587 } 588 __ops_keydata_free(keypair); 589 return 1; 590} 591 592/* encrypt a file */ 593int 594netpgp_encrypt_file(netpgp_t *netpgp, 595 const char *userid, 596 const char *f, 597 char *out, 598 int armored) 599{ 600 const __ops_key_t *keypair; 601 const unsigned overwrite = 1; 602 const char *suffix; 603 __ops_io_t *io; 604 char outname[MAXPATHLEN]; 605 606 io = netpgp->io; 607 if (f == NULL) { 608 (void) fprintf(io->errs, 609 "netpgp_encrypt_file: no filename specified\n"); 610 return 0; 611 } 612 if (userid == NULL) { 613 userid = netpgp_getvar(netpgp, "userid"); 614 } 615 suffix = (armored) ? ".asc" : ".gpg"; 616 keypair = __ops_getkeybyname(io, netpgp->pubring, userid); 617 if (keypair == NULL) { 618 (void) fprintf(io->errs, "Userid '%s' not found in keyring\n", 619 userid); 620 return 0; 621 } 622 if (out == NULL) { 623 (void) snprintf(outname, sizeof(outname), "%s%s", f, suffix); 624 out = outname; 625 } 626 return (int)__ops_encrypt_file(io, f, out, keypair, (unsigned)armored, 627 overwrite); 628} 629 630/* decrypt a file */ 631int 632netpgp_decrypt_file(netpgp_t *netpgp, const char *f, char *out, int armored) 633{ 634 const unsigned overwrite = 1; 635 __ops_io_t *io; 636 637 io = netpgp->io; 638 if (f == NULL) { 639 (void) fprintf(io->errs, 640 "netpgp_decrypt_file: no filename specified\n"); 641 return 0; 642 } 643 return __ops_decrypt_file(netpgp->io, f, out, netpgp->secring, 644 (unsigned)armored, overwrite, netpgp->passfp, 645 get_passphrase_cb); 646} 647 648/* sign a file */ 649int 650netpgp_sign_file(netpgp_t *netpgp, 651 const char *userid, 652 const char *f, 653 char *out, 654 int armored, 655 int cleartext, 656 int detached) 657{ 658 const __ops_key_t *keypair; 659 __ops_seckey_t *seckey; 660 const unsigned overwrite = 1; 661 __ops_io_t *io; 662 char *hashalg; 663 int ret; 664 665 io = netpgp->io; 666 if (f == NULL) { 667 (void) fprintf(io->errs, 668 "netpgp_sign_file: no filename specified\n"); 669 return 0; 670 } 671 if (userid == NULL) { 672 userid = netpgp_getvar(netpgp, "userid"); 673 } 674 /* get key with which to sign */ 675 keypair = __ops_getkeybyname(io, netpgp->secring, userid); 676 if (keypair == NULL) { 677 (void) fprintf(io->errs, "Userid '%s' not found in keyring\n", 678 userid); 679 return 0; 680 } 681 ret = 1; 682 do { 683 /* print out the user id */ 684 __ops_print_keydata(io, keypair, "pub", &keypair->key.pubkey); 685 if (netpgp_getvar(netpgp, "ssh keys") == NULL) { 686 /* now decrypt key */ 687 seckey = __ops_decrypt_seckey(keypair); 688 if (seckey == NULL) { 689 (void) fprintf(io->errs, "Bad passphrase\n"); 690 } 691 } else { 692 __ops_keyring_t *secring; 693 694 secring = netpgp->secring; 695 seckey = &secring->keys[0].key.seckey; 696 } 697 } while (seckey == NULL); 698 /* sign file */ 699 hashalg = netpgp_getvar(netpgp, "hash"); 700 if (detached) { 701 ret = __ops_sign_detached(io, f, out, seckey, hashalg); 702 } else { 703 ret = __ops_sign_file(io, f, out, seckey, hashalg, 704 (unsigned)armored, (unsigned)cleartext, overwrite); 705 } 706 __ops_forget(seckey, sizeof(*seckey)); 707 return ret; 708} 709 710/* verify a file */ 711int 712netpgp_verify_file(netpgp_t *netpgp, const char *in, const char *out, int armored) 713{ 714 __ops_validation_t result; 715 __ops_io_t *io; 716 717 (void) memset(&result, 0x0, sizeof(result)); 718 io = netpgp->io; 719 if (in == NULL) { 720 (void) fprintf(io->errs, 721 "netpgp_verify_file: no filename specified\n"); 722 return 0; 723 } 724 if (__ops_validate_file(io, &result, in, out, armored, 725 netpgp->pubring)) { 726 resultp(io, in, &result, netpgp->pubring); 727 return 1; 728 } 729 if (result.validc + result.invalidc + result.unknownc == 0) { 730 (void) fprintf(io->errs, 731 "\"%s\": No signatures found - is this a signed file?\n", 732 in); 733 } else { 734 (void) fprintf(io->errs, 735"\"%s\": verification failure: %u invalid signatures, %u unknown signatures\n", 736 in, result.invalidc, result.unknownc); 737 } 738 return 0; 739} 740 741/* sign some memory */ 742int 743netpgp_sign_memory(netpgp_t *netpgp, 744 const char *userid, 745 char *mem, 746 size_t size, 747 char *out, 748 size_t outsize, 749 const unsigned armored, 750 const unsigned cleartext) 751{ 752 const __ops_key_t *keypair; 753 __ops_seckey_t *seckey; 754 __ops_memory_t *signedmem; 755 __ops_io_t *io; 756 char *hashalg; 757 int ret; 758 759 io = netpgp->io; 760 if (mem == NULL) { 761 (void) fprintf(io->errs, 762 "netpgp_sign_memory: no memory to sign\n"); 763 return 0; 764 } 765 if (userid == NULL) { 766 userid = netpgp_getvar(netpgp, "userid"); 767 } 768 /* get key with which to sign */ 769 keypair = __ops_getkeybyname(io, netpgp->secring, userid); 770 if (keypair == NULL) { 771 (void) fprintf(io->errs, "Userid '%s' not found in keyring\n", 772 userid); 773 return 0; 774 } 775 ret = 1; 776 do { 777 /* print out the user id */ 778 __ops_print_keydata(io, keypair, "pub", &keypair->key.pubkey); 779 /* now decrypt key */ 780 seckey = __ops_decrypt_seckey(keypair); 781 if (seckey == NULL) { 782 (void) fprintf(io->errs, "Bad passphrase\n"); 783 } 784 } while (seckey == NULL); 785 /* sign file */ 786 hashalg = netpgp_getvar(netpgp, "hash"); 787 signedmem = __ops_sign_buf(io, mem, size, seckey, hashalg, 788 armored, cleartext); 789 if (signedmem) { 790 size_t m; 791 792 m = MIN(__ops_mem_len(signedmem), outsize); 793 (void) memcpy(out, __ops_mem_data(signedmem), m); 794 __ops_memory_free(signedmem); 795 } 796 __ops_forget(seckey, sizeof(*seckey)); 797 return ret; 798} 799 800/* verify memory */ 801int 802netpgp_verify_memory(netpgp_t *netpgp, const void *in, const size_t size, const int armored) 803{ 804 __ops_validation_t result; 805 __ops_memory_t *signedmem; 806 __ops_io_t *io; 807 int ret; 808 809 (void) memset(&result, 0x0, sizeof(result)); 810 io = netpgp->io; 811 if (in == NULL) { 812 (void) fprintf(io->errs, 813 "netpgp_verify_memory: no memory to verify\n"); 814 return 0; 815 } 816 signedmem = __ops_memory_new(); 817 __ops_memory_add(signedmem, in, size); 818 ret = __ops_validate_mem(io, &result, signedmem, armored, 819 netpgp->pubring); 820 __ops_memory_free(signedmem); 821 if (ret) { 822 resultp(io, in, &result, netpgp->pubring); 823 return 1; 824 } 825 if (result.validc + result.invalidc + result.unknownc == 0) { 826 (void) fprintf(io->errs, 827 "No signatures found - is this memory signed?\n"); 828 } else { 829 (void) fprintf(io->errs, 830"memory verification failure: %u invalid signatures, %u unknown signatures\n", 831 result.invalidc, result.unknownc); 832 } 833 return 0; 834} 835 836/* wrappers for the ops_debug_level functions we added to openpgpsdk */ 837 838/* set the debugging level per filename */ 839int 840netpgp_set_debug(const char *f) 841{ 842 return __ops_set_debug_level(f); 843} 844 845/* get the debugging level per filename */ 846int 847netpgp_get_debug(const char *f) 848{ 849 return __ops_get_debug_level(f); 850} 851 852/* return the version for the library */ 853const char * 854netpgp_get_info(const char *type) 855{ 856 return __ops_get_info(type); 857} 858 859/* list all the packets in a file */ 860int 861netpgp_list_packets(netpgp_t *netpgp, char *f, int armour, char *pubringname) 862{ 863 __ops_keyring_t *keyring; 864 const unsigned noarmor = 0; 865 __ops_io_t *io; 866 char ringname[MAXPATHLEN]; 867 char *homedir; 868 int ret; 869 870 io = netpgp->io; 871 if (f == NULL) { 872 (void) fprintf(io->errs, "No file containing packets\n"); 873 return 0; 874 } 875 homedir = netpgp_getvar(netpgp, "homedir"); 876 if (pubringname == NULL) { 877 (void) snprintf(ringname, sizeof(ringname), 878 "%s/pubring.gpg", homedir); 879 pubringname = ringname; 880 } 881 if ((keyring = calloc(1, sizeof(*keyring))) == NULL) { 882 (void) fprintf(io->errs, "netpgp_list_packets: bad alloc\n"); 883 return 0; 884 } 885 if (!__ops_keyring_fileread(keyring, noarmor, pubringname)) { 886 free(keyring); 887 (void) fprintf(io->errs, "Cannot read pub keyring %s\n", 888 pubringname); 889 return 0; 890 } 891 netpgp->pubring = keyring; 892 netpgp_setvar(netpgp, "pubring", pubringname); 893 ret = __ops_list_packets(io, f, (unsigned)armour, keyring, 894 netpgp->passfp, 895 get_passphrase_cb); 896 free(keyring); 897 return ret; 898} 899 900/* set a variable */ 901int 902netpgp_setvar(netpgp_t *netpgp, const char *name, const char *value) 903{ 904 int i; 905 906 if ((i = findvar(netpgp, name)) < 0) { 907 /* add the element to the array */ 908 if (size_arrays(netpgp, netpgp->size + 15)) { 909 netpgp->name[i = netpgp->c++] = strdup(name); 910 } 911 } else { 912 /* replace the element in the array */ 913 if (netpgp->value[i]) { 914 free(netpgp->value[i]); 915 netpgp->value[i] = NULL; 916 } 917 } 918 /* sanity checks for range of values */ 919 if (strcmp(name, "hash") == 0 || strcmp(name, "algorithm") == 0) { 920 if (__ops_str_to_hash_alg(value) == OPS_HASH_UNKNOWN) { 921 return 0; 922 } 923 } 924 netpgp->value[i] = strdup(value); 925 return 1; 926} 927 928/* get a variable's value (NULL if not set) */ 929char * 930netpgp_getvar(netpgp_t *netpgp, const char *name) 931{ 932 int i; 933 934 return ((i = findvar(netpgp, name)) < 0) ? NULL : netpgp->value[i]; 935} 936