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.36 2009/12/22 06:55:03 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 */ 87 static int 88 conffile(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 */ 119 static char * 120 userid_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 */ 134 static void 135 resultp(__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) ? f : "<stdin>", 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 */ 161 static int 162 size_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 */ 198 static int 199 findvar(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 */ 209 static void * 210 readkeyring(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 */ 237 static int 238 readsshkeys(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 */ 284 static void 285 set_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 */ 304 int 305 netpgp_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 */ 418 int 419 netpgp_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 */ 448 int 449 netpgp_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 */ 455 int 456 netpgp_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 */ 481 int 482 netpgp_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 */ 495 char * 496 netpgp_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 */ 517 int 518 netpgp_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 */ 537 int 538 netpgp_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 */ 558 int 559 netpgp_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 */ 609 int 610 netpgp_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 #define ARMOR_HEAD "-----BEGIN PGP MESSAGE-----\r\n" 647 648 /* decrypt a file */ 649 int 650 netpgp_decrypt_file(netpgp_t *netpgp, const char *f, char *out, int armored) 651 { 652 const unsigned overwrite = 1; 653 __ops_io_t *io; 654 unsigned realarmour; 655 FILE *fp; 656 char buf[BUFSIZ]; 657 658 io = netpgp->io; 659 if (f == NULL) { 660 (void) fprintf(io->errs, 661 "netpgp_decrypt_file: no filename specified\n"); 662 return 0; 663 } 664 realarmour = (unsigned)armored; 665 if ((fp = fopen(f, "r")) == NULL) { 666 (void) fprintf(io->errs, 667 "netpgp_decrypt_file: can't open '%s'\n", f); 668 return 0; 669 } 670 if (fgets(buf, sizeof(buf), fp) == NULL) { 671 realarmour = 0; 672 } else { 673 realarmour = (strcmp(buf, ARMOR_HEAD) == 0); 674 } 675 (void) fclose(fp); 676 return __ops_decrypt_file(netpgp->io, f, out, netpgp->secring, 677 (unsigned)realarmour, overwrite, 678 netpgp->passfp, get_passphrase_cb); 679 } 680 681 /* sign a file */ 682 int 683 netpgp_sign_file(netpgp_t *netpgp, 684 const char *userid, 685 const char *f, 686 char *out, 687 int armored, 688 int cleartext, 689 int detached) 690 { 691 const __ops_key_t *keypair; 692 __ops_seckey_t *seckey; 693 const unsigned overwrite = 1; 694 __ops_io_t *io; 695 char *hashalg; 696 int ret; 697 698 io = netpgp->io; 699 if (f == NULL) { 700 (void) fprintf(io->errs, 701 "netpgp_sign_file: no filename specified\n"); 702 return 0; 703 } 704 if (userid == NULL) { 705 userid = netpgp_getvar(netpgp, "userid"); 706 } 707 /* get key with which to sign */ 708 keypair = __ops_getkeybyname(io, netpgp->secring, userid); 709 if (keypair == NULL) { 710 (void) fprintf(io->errs, "Userid '%s' not found in keyring\n", 711 userid); 712 return 0; 713 } 714 ret = 1; 715 do { 716 /* print out the user id */ 717 __ops_print_keydata(io, keypair, "pub", &keypair->key.pubkey); 718 if (netpgp_getvar(netpgp, "ssh keys") == NULL) { 719 /* now decrypt key */ 720 seckey = __ops_decrypt_seckey(keypair); 721 if (seckey == NULL) { 722 (void) fprintf(io->errs, "Bad passphrase\n"); 723 } 724 } else { 725 __ops_keyring_t *secring; 726 727 secring = netpgp->secring; 728 seckey = &secring->keys[0].key.seckey; 729 } 730 } while (seckey == NULL); 731 /* sign file */ 732 hashalg = netpgp_getvar(netpgp, "hash"); 733 if (detached) { 734 ret = __ops_sign_detached(io, f, out, seckey, hashalg); 735 } else { 736 ret = __ops_sign_file(io, f, out, seckey, hashalg, 737 (unsigned)armored, (unsigned)cleartext, 738 overwrite); 739 } 740 __ops_forget(seckey, sizeof(*seckey)); 741 return ret; 742 } 743 744 /* verify a file */ 745 int 746 netpgp_verify_file(netpgp_t *netpgp, const char *in, const char *out, int armored) 747 { 748 __ops_validation_t result; 749 __ops_io_t *io; 750 751 (void) memset(&result, 0x0, sizeof(result)); 752 io = netpgp->io; 753 if (in == NULL) { 754 (void) fprintf(io->errs, 755 "netpgp_verify_file: no filename specified\n"); 756 return 0; 757 } 758 if (__ops_validate_file(io, &result, in, out, armored, 759 netpgp->pubring)) { 760 resultp(io, in, &result, netpgp->pubring); 761 return 1; 762 } 763 if (result.validc + result.invalidc + result.unknownc == 0) { 764 (void) fprintf(io->errs, 765 "\"%s\": No signatures found - is this a signed file?\n", 766 in); 767 } else { 768 (void) fprintf(io->errs, 769 "\"%s\": verification failure: %u invalid signatures, %u unknown signatures\n", 770 in, result.invalidc, result.unknownc); 771 } 772 return 0; 773 } 774 775 /* sign some memory */ 776 int 777 netpgp_sign_memory(netpgp_t *netpgp, 778 const char *userid, 779 char *mem, 780 size_t size, 781 char *out, 782 size_t outsize, 783 const unsigned armored, 784 const unsigned cleartext) 785 { 786 const __ops_key_t *keypair; 787 __ops_seckey_t *seckey; 788 __ops_memory_t *signedmem; 789 __ops_io_t *io; 790 char *hashalg; 791 int ret; 792 793 io = netpgp->io; 794 if (mem == NULL) { 795 (void) fprintf(io->errs, 796 "netpgp_sign_memory: no memory to sign\n"); 797 return 0; 798 } 799 if (userid == NULL) { 800 userid = netpgp_getvar(netpgp, "userid"); 801 } 802 /* get key with which to sign */ 803 keypair = __ops_getkeybyname(io, netpgp->secring, userid); 804 if (keypair == NULL) { 805 (void) fprintf(io->errs, "Userid '%s' not found in keyring\n", 806 userid); 807 return 0; 808 } 809 ret = 1; 810 do { 811 /* print out the user id */ 812 __ops_print_keydata(io, keypair, "pub", &keypair->key.pubkey); 813 /* now decrypt key */ 814 seckey = __ops_decrypt_seckey(keypair); 815 if (seckey == NULL) { 816 (void) fprintf(io->errs, "Bad passphrase\n"); 817 } 818 } while (seckey == NULL); 819 /* sign file */ 820 hashalg = netpgp_getvar(netpgp, "hash"); 821 signedmem = __ops_sign_buf(io, mem, size, seckey, hashalg, 822 armored, cleartext); 823 if (signedmem) { 824 size_t m; 825 826 m = MIN(__ops_mem_len(signedmem), outsize); 827 (void) memcpy(out, __ops_mem_data(signedmem), m); 828 __ops_memory_free(signedmem); 829 ret = (int)m; 830 } else { 831 ret = 0; 832 } 833 __ops_forget(seckey, sizeof(*seckey)); 834 return ret; 835 } 836 837 /* verify memory */ 838 int 839 netpgp_verify_memory(netpgp_t *netpgp, const void *in, const size_t size, 840 void *out, size_t outsize, const int armored) 841 { 842 __ops_validation_t result; 843 __ops_memory_t *signedmem; 844 __ops_memory_t *cat; 845 __ops_io_t *io; 846 size_t m; 847 int ret; 848 849 (void) memset(&result, 0x0, sizeof(result)); 850 io = netpgp->io; 851 if (in == NULL) { 852 (void) fprintf(io->errs, 853 "netpgp_verify_memory: no memory to verify\n"); 854 return 0; 855 } 856 signedmem = __ops_memory_new(); 857 __ops_memory_add(signedmem, in, size); 858 ret = __ops_validate_mem(io, &result, signedmem, 859 (out) ? &cat : NULL, 860 armored, netpgp->pubring); 861 __ops_memory_free(signedmem); 862 if (ret) { 863 resultp(io, "<stdin>", &result, netpgp->pubring); 864 if (out) { 865 m = MIN(__ops_mem_len(cat), outsize); 866 (void) memcpy(out, __ops_mem_data(cat), m); 867 __ops_memory_free(cat); 868 } else { 869 m = 1; 870 } 871 return (int)m; 872 } 873 if (result.validc + result.invalidc + result.unknownc == 0) { 874 (void) fprintf(io->errs, 875 "No signatures found - is this memory signed?\n"); 876 } else { 877 (void) fprintf(io->errs, 878 "memory verification failure: %u invalid signatures, %u unknown signatures\n", 879 result.invalidc, result.unknownc); 880 } 881 return 0; 882 } 883 884 /* encrypt some memory */ 885 int 886 netpgp_encrypt_memory(netpgp_t *netpgp, 887 const char *userid, 888 void *in, 889 const size_t insize, 890 char *out, 891 size_t outsize, 892 int armored) 893 { 894 const __ops_key_t *keypair; 895 __ops_memory_t *enc; 896 __ops_io_t *io; 897 size_t m; 898 899 io = netpgp->io; 900 if (in == NULL) { 901 (void) fprintf(io->errs, 902 "netpgp_encrypt_buf: no memory to encrypt\n"); 903 return 0; 904 } 905 if (userid == NULL) { 906 userid = netpgp_getvar(netpgp, "userid"); 907 } 908 keypair = __ops_getkeybyname(io, netpgp->pubring, userid); 909 if (keypair == NULL) { 910 (void) fprintf(io->errs, "Userid '%s' not found in keyring\n", 911 userid); 912 return 0; 913 } 914 if (in == out) { 915 (void) fprintf(io->errs, 916 "netpgp_encrypt_buf: input and output bufs need to be different\n"); 917 return 0; 918 } 919 if (outsize < insize) { 920 (void) fprintf(io->errs, 921 "netpgp_encrypt_buf: input size is larger than output size\n"); 922 return 0; 923 } 924 enc = __ops_encrypt_buf(io, in, insize, keypair, (unsigned)armored); 925 m = MIN(__ops_mem_len(enc), outsize); 926 (void) memcpy(out, __ops_mem_data(enc), m); 927 __ops_memory_free(enc); 928 return (int)m; 929 } 930 931 /* decrypt a chunk of memory */ 932 int 933 netpgp_decrypt_memory(netpgp_t *netpgp, const void *input, const size_t insize, 934 char *out, size_t outsize, const int armored) 935 { 936 __ops_memory_t *mem; 937 __ops_io_t *io; 938 unsigned realarmour; 939 size_t m; 940 941 io = netpgp->io; 942 realarmour = (unsigned) armored; 943 if (input == NULL) { 944 (void) fprintf(io->errs, 945 "netpgp_decrypt_memory: no memory\n"); 946 return 0; 947 } 948 realarmour = (strncmp(input, ARMOR_HEAD, sizeof(ARMOR_HEAD) - 1) == 0); 949 mem = __ops_decrypt_buf(netpgp->io, input, insize, netpgp->secring, 950 realarmour, netpgp->passfp, 951 get_passphrase_cb); 952 m = MIN(__ops_mem_len(mem), outsize); 953 (void) memcpy(out, __ops_mem_data(mem), m); 954 __ops_memory_free(mem); 955 return (int)m; 956 } 957 958 /* wrappers for the ops_debug_level functions we added to openpgpsdk */ 959 960 /* set the debugging level per filename */ 961 int 962 netpgp_set_debug(const char *f) 963 { 964 return __ops_set_debug_level(f); 965 } 966 967 /* get the debugging level per filename */ 968 int 969 netpgp_get_debug(const char *f) 970 { 971 return __ops_get_debug_level(f); 972 } 973 974 /* return the version for the library */ 975 const char * 976 netpgp_get_info(const char *type) 977 { 978 return __ops_get_info(type); 979 } 980 981 /* list all the packets in a file */ 982 int 983 netpgp_list_packets(netpgp_t *netpgp, char *f, int armour, char *pubringname) 984 { 985 __ops_keyring_t *keyring; 986 const unsigned noarmor = 0; 987 __ops_io_t *io; 988 char ringname[MAXPATHLEN]; 989 char *homedir; 990 int ret; 991 992 io = netpgp->io; 993 if (f == NULL) { 994 (void) fprintf(io->errs, "No file containing packets\n"); 995 return 0; 996 } 997 homedir = netpgp_getvar(netpgp, "homedir"); 998 if (pubringname == NULL) { 999 (void) snprintf(ringname, sizeof(ringname), 1000 "%s/pubring.gpg", homedir); 1001 pubringname = ringname; 1002 } 1003 if ((keyring = calloc(1, sizeof(*keyring))) == NULL) { 1004 (void) fprintf(io->errs, "netpgp_list_packets: bad alloc\n"); 1005 return 0; 1006 } 1007 if (!__ops_keyring_fileread(keyring, noarmor, pubringname)) { 1008 free(keyring); 1009 (void) fprintf(io->errs, "Cannot read pub keyring %s\n", 1010 pubringname); 1011 return 0; 1012 } 1013 netpgp->pubring = keyring; 1014 netpgp_setvar(netpgp, "pubring", pubringname); 1015 ret = __ops_list_packets(io, f, (unsigned)armour, keyring, 1016 netpgp->passfp, 1017 get_passphrase_cb); 1018 free(keyring); 1019 return ret; 1020 } 1021 1022 /* set a variable */ 1023 int 1024 netpgp_setvar(netpgp_t *netpgp, const char *name, const char *value) 1025 { 1026 int i; 1027 1028 if ((i = findvar(netpgp, name)) < 0) { 1029 /* add the element to the array */ 1030 if (size_arrays(netpgp, netpgp->size + 15)) { 1031 netpgp->name[i = netpgp->c++] = strdup(name); 1032 } 1033 } else { 1034 /* replace the element in the array */ 1035 if (netpgp->value[i]) { 1036 free(netpgp->value[i]); 1037 netpgp->value[i] = NULL; 1038 } 1039 } 1040 /* sanity checks for range of values */ 1041 if (strcmp(name, "hash") == 0 || strcmp(name, "algorithm") == 0) { 1042 if (__ops_str_to_hash_alg(value) == OPS_HASH_UNKNOWN) { 1043 return 0; 1044 } 1045 } 1046 netpgp->value[i] = strdup(value); 1047 return 1; 1048 } 1049 1050 /* get a variable's value (NULL if not set) */ 1051 char * 1052 netpgp_getvar(netpgp_t *netpgp, const char *name) 1053 { 1054 int i; 1055 1056 return ((i = findvar(netpgp, name)) < 0) ? NULL : netpgp->value[i]; 1057 } 1058 1059 /* increment a value */ 1060 int 1061 netpgp_incvar(netpgp_t *netpgp, const char *name, const int delta) 1062 { 1063 char *cp; 1064 char num[16]; 1065 int val; 1066 1067 val = 0; 1068 if ((cp = netpgp_getvar(netpgp, name)) != NULL) { 1069 val = atoi(cp); 1070 } 1071 (void) snprintf(num, sizeof(num), "%d", val + delta); 1072 netpgp_setvar(netpgp, name, num); 1073 return 1; 1074 } 1075 1076 /* set the home directory value to "home/subdir" */ 1077 int 1078 netpgp_set_homedir(netpgp_t *netpgp, char *home, const char *subdir, const int quiet) 1079 { 1080 struct stat st; 1081 char d[MAXPATHLEN]; 1082 1083 if (home == NULL) { 1084 if (!quiet) { 1085 (void) fprintf(stderr, "NULL HOME directory\n"); 1086 } 1087 return 0; 1088 } 1089 (void) snprintf(d, sizeof(d), "%s%s", home, (subdir) ? subdir : ""); 1090 if (stat(d, &st) == 0) { 1091 if ((st.st_mode & S_IFMT) == S_IFDIR) { 1092 netpgp_setvar(netpgp, "homedir", d); 1093 return 1; 1094 } 1095 (void) fprintf(stderr, "netpgp: homedir \"%s\" is not a dir\n", 1096 d); 1097 return 0; 1098 } 1099 if (!quiet) { 1100 (void) fprintf(stderr, 1101 "netpgp: warning homedir \"%s\" not found\n", d); 1102 } 1103 return 1; 1104 } 1105 1106