netpgp.c revision 1.38
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.38 2010/02/11 17:46:09 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#include "defs.h" 86 87/* read any gpg config file */ 88static int 89conffile(netpgp_t *netpgp, char *homedir, char *userid, size_t length) 90{ 91 regmatch_t matchv[10]; 92 regex_t keyre; 93 char buf[BUFSIZ]; 94 FILE *fp; 95 96 __OPS_USED(netpgp); 97 (void) snprintf(buf, sizeof(buf), "%s/gpg.conf", homedir); 98 if ((fp = fopen(buf, "r")) == NULL) { 99 return 0; 100 } 101 (void) memset(&keyre, 0x0, sizeof(keyre)); 102 (void) regcomp(&keyre, "^[ \t]*default-key[ \t]+([0-9a-zA-F]+)", 103 REG_EXTENDED); 104 while (fgets(buf, sizeof(buf), fp) != NULL) { 105 if (regexec(&keyre, buf, 10, matchv, 0) == 0) { 106 (void) memcpy(userid, &buf[(int)matchv[1].rm_so], 107 MIN((unsigned)(matchv[1].rm_eo - 108 matchv[1].rm_so), length)); 109 if (netpgp->passfp == NULL) { 110 (void) fprintf(stderr, 111 "netpgp: default key set to \"%.*s\"\n", 112 (int)(matchv[1].rm_eo - matchv[1].rm_so), 113 &buf[(int)matchv[1].rm_so]); 114 } 115 } 116 } 117 (void) fclose(fp); 118 return 1; 119} 120 121/* small function to pretty print an 8-character raw userid */ 122static char * 123userid_to_id(const unsigned char *userid, char *id) 124{ 125 static const char *hexes = "0123456789abcdef"; 126 int i; 127 128 for (i = 0; i < 8 ; i++) { 129 id[i * 2] = hexes[(unsigned)(userid[i] & 0xf0) >> 4]; 130 id[(i * 2) + 1] = hexes[userid[i] & 0xf]; 131 } 132 id[8 * 2] = 0x0; 133 return id; 134} 135 136/* print out the successful signature information */ 137static void 138resultp(__ops_io_t *io, 139 const char *f, 140 __ops_validation_t *res, 141 __ops_keyring_t *ring) 142{ 143 const __ops_key_t *pubkey; 144 unsigned from; 145 unsigned i; 146 time_t t; 147 char id[MAX_ID_LENGTH + 1]; 148 149 for (i = 0; i < res->validc; i++) { 150 (void) fprintf(io->res, 151 "Good signature for %s made %s", 152 (f) ? f : "<stdin>", 153 ctime(&res->valid_sigs[i].birthtime)); 154 if (res->duration > 0) { 155 t = res->birthtime + res->duration; 156 (void) fprintf(io->res, "Valid until %s", ctime(&t)); 157 } 158 (void) fprintf(io->res, 159 "using %s key %s\n", 160 __ops_show_pka(res->valid_sigs[i].key_alg), 161 userid_to_id(res->valid_sigs[i].signer_id, id)); 162 from = 0; 163 pubkey = __ops_getkeybyid(io, ring, 164 (const unsigned char *) res->valid_sigs[i].signer_id, 165 &from); 166 __ops_print_keydata(io, pubkey, "pub", &pubkey->key.pubkey); 167 } 168} 169 170/* check there's enough space in the arrays */ 171static int 172size_arrays(netpgp_t *netpgp, unsigned needed) 173{ 174 char **temp; 175 176 if (netpgp->size == 0) { 177 /* only get here first time around */ 178 netpgp->size = needed; 179 if ((netpgp->name = calloc(sizeof(char *), needed)) == NULL) { 180 (void) fprintf(stderr, "size_arrays: bad alloc\n"); 181 return 0; 182 } 183 if ((netpgp->value = calloc(sizeof(char *), needed)) == NULL) { 184 free(netpgp->name); 185 (void) fprintf(stderr, "size_arrays: bad alloc\n"); 186 return 0; 187 } 188 } else if (netpgp->c == netpgp->size) { 189 /* only uses 'needed' when filled array */ 190 netpgp->size += needed; 191 temp = realloc(netpgp->name, sizeof(char *) * needed); 192 if (temp == NULL) { 193 (void) fprintf(stderr, "size_arrays: bad alloc\n"); 194 return 0; 195 } 196 netpgp->name = temp; 197 temp = realloc(netpgp->value, sizeof(char *) * needed); 198 if (temp == NULL) { 199 (void) fprintf(stderr, "size_arrays: bad alloc\n"); 200 return 0; 201 } 202 netpgp->value = temp; 203 } 204 return 1; 205} 206 207/* find the name in the array */ 208static int 209findvar(netpgp_t *netpgp, const char *name) 210{ 211 unsigned i; 212 213 for (i = 0 ; i < netpgp->c && strcmp(netpgp->name[i], name) != 0; i++) { 214 } 215 return (i == netpgp->c) ? -1 : (int)i; 216} 217 218/* read a keyring and return it */ 219static void * 220readkeyring(netpgp_t *netpgp, const char *name) 221{ 222 __ops_keyring_t *keyring; 223 const unsigned noarmor = 0; 224 char f[MAXPATHLEN]; 225 char *filename; 226 char *homedir; 227 228 homedir = netpgp_getvar(netpgp, "homedir"); 229 if ((filename = netpgp_getvar(netpgp, name)) == NULL) { 230 (void) snprintf(f, sizeof(f), "%s/%s.gpg", homedir, name); 231 filename = f; 232 } 233 if ((keyring = calloc(1, sizeof(*keyring))) == NULL) { 234 (void) fprintf(stderr, "readkeyring: bad alloc\n"); 235 return NULL; 236 } 237 if (!__ops_keyring_fileread(keyring, noarmor, filename)) { 238 free(keyring); 239 (void) fprintf(stderr, "Can't read %s %s\n", name, filename); 240 return NULL; 241 } 242 netpgp_setvar(netpgp, name, filename); 243 return keyring; 244} 245 246/* read keys from ssh key files */ 247static int 248readsshkeys(netpgp_t *netpgp, char *homedir) 249{ 250 __ops_keyring_t *pubring; 251 __ops_keyring_t *secring; 252 char f[MAXPATHLEN]; 253 char *filename; 254 255 if ((filename = netpgp_getvar(netpgp, "sshkeyfile")) == NULL) { 256 (void) snprintf(f, sizeof(f), "%s/.ssh/is_rsa.pub", homedir); 257 filename = f; 258 } 259 if ((pubring = calloc(1, sizeof(*pubring))) == NULL) { 260 (void) fprintf(stderr, "readsshkeys: bad alloc\n"); 261 return 0; 262 } 263 if (!__ops_ssh2_readkeys(netpgp->io, pubring, NULL, filename, NULL)) { 264 free(pubring); 265 (void) fprintf(stderr, "readsshkeys: can't read %s\n", 266 filename); 267 return 0; 268 } 269 if (netpgp->pubring == NULL) { 270 netpgp->pubring = pubring; 271 } else { 272 __ops_append_keyring(netpgp->pubring, pubring); 273 } 274 netpgp_setvar(netpgp, "sshpubfile", filename); 275 /* try to take the ".pub" off the end */ 276 if (filename == f) { 277 f[strlen(f) - 4] = 0x0; 278 } else { 279 (void) snprintf(f, sizeof(f), "%.*s", 280 (int)strlen(filename) - 4, filename); 281 filename = f; 282 } 283 if ((secring = calloc(1, sizeof(*secring))) == NULL) { 284 (void) fprintf(stderr, "readsshkeys: bad alloc\n"); 285 return 0; 286 } 287 if (__ops_ssh2_readkeys(netpgp->io, pubring, secring, NULL, filename)) { 288 netpgp->secring = secring; 289 netpgp_setvar(netpgp, "sshsecfile", filename); 290 } else { 291 (void) fprintf(stderr, "readsshkeys: can't read sec %s (%d)\n", 292 filename, errno); 293 } 294 return 1; 295} 296 297/* set ssh uid to first one in ring */ 298static void 299set_ssh_userid(__ops_keyring_t *pubring, char *id, size_t len, int last) 300{ 301 unsigned char *src; 302 int i; 303 int n; 304 305 (void) memset(id, 0x0, len); 306 src = pubring->keys[(last) ? pubring->keyc - 1 : 0].key_id; 307 for (i = 0, n = 0 ; i < OPS_KEY_ID_SIZE ; i += 2) { 308 n += snprintf(&id[n], len - n, "%02x%02x", src[i], src[i + 1]); 309 } 310 id[n] = 0x0; 311} 312 313/* get expiration in seconds */ 314static uint64_t 315get_duration(char *s) 316{ 317 struct tm tm; 318 uint64_t now; 319 char *mult; 320 321 if (s == NULL) { 322 return 0; 323 } 324 now = strtoull(s, NULL, 10); 325 if ((mult = strchr("hdwmy", s[strlen(s) - 1])) != NULL) { 326 switch(*mult) { 327 case 'h': 328 return now * 60 * 60; 329 case 'd': 330 return now * 60 * 60 * 24; 331 case 'w': 332 return now * 60 * 60 * 24 * 7; 333 case 'm': 334 return now * 60 * 60 * 24 * 31; 335 case 'y': 336 return now * 60 * 60 * 24 * 365; 337 } 338 } 339 if (strptime(s, "%Y-%m-%d", &tm) != NULL) { 340 return mktime(&tm); 341 } 342 if (strptime(s, "%Y/%m/%d", &tm) != NULL) { 343 return mktime(&tm); 344 } 345 return (uint64_t)strtoll(s, NULL, 10); 346} 347 348/* get birthtime in seconds */ 349static int64_t 350get_birthtime(char *s) 351{ 352 struct tm tm; 353 354 if (s == NULL) { 355 return time(NULL); 356 } 357 if (strptime(s, "%Y-%m-%d", &tm) != NULL) { 358 return mktime(&tm); 359 } 360 if (strptime(s, "%Y/%m/%d", &tm) != NULL) { 361 return mktime(&tm); 362 } 363 return (uint64_t)strtoll(s, NULL, 10); 364} 365 366/***************************************************************************/ 367/* exported functions start here */ 368/***************************************************************************/ 369 370/* initialise a netpgp_t structure */ 371int 372netpgp_init(netpgp_t *netpgp) 373{ 374 __ops_io_t *io; 375 char id[MAX_ID_LENGTH]; 376 char *homedir; 377 char *userid; 378 char *stream; 379 char *passfd; 380 char *results; 381 int coredumps; 382 int last; 383 384#ifdef HAVE_SYS_RESOURCE_H 385 struct rlimit limit; 386 387 coredumps = netpgp_getvar(netpgp, "coredumps") != NULL; 388 if (!coredumps) { 389 (void) memset(&limit, 0x0, sizeof(limit)); 390 if (setrlimit(RLIMIT_CORE, &limit) != 0) { 391 (void) fprintf(stderr, 392 "netpgp: warning - can't turn off core dumps\n"); 393 coredumps = 1; 394 } 395 } 396#else 397 coredumps = 1; 398#endif 399 if ((io = calloc(1, sizeof(*io))) == NULL) { 400 (void) fprintf(stderr, "netpgp_init: bad alloc\n"); 401 return 0; 402 } 403 io->outs = stdout; 404 if ((stream = netpgp_getvar(netpgp, "stdout")) != NULL && 405 strcmp(stream, "stderr") == 0) { 406 io->outs = stderr; 407 } 408 io->errs = stderr; 409 if ((stream = netpgp_getvar(netpgp, "stderr")) != NULL && 410 strcmp(stream, "stdout") == 0) { 411 io->errs = stdout; 412 } 413 if ((results = netpgp_getvar(netpgp, "results")) == NULL) { 414 io->res = io->errs; 415 } else if ((io->res = fopen(results, "w")) == NULL) { 416 (void) fprintf(io->errs, "Can't open results %s for writing\n", 417 results); 418 return 0; 419 } 420 netpgp->io = io; 421 if ((passfd = netpgp_getvar(netpgp, "pass-fd")) != NULL && 422 (netpgp->passfp = fdopen(atoi(passfd), "r")) == NULL) { 423 (void) fprintf(io->errs, "Can't open fd %s for reading\n", 424 passfd); 425 return 0; 426 } 427 if (coredumps) { 428 (void) fprintf(io->errs, 429 "netpgp: warning: core dumps enabled\n"); 430 } 431 if ((homedir = netpgp_getvar(netpgp, "homedir")) == NULL) { 432 (void) fprintf(io->errs, "netpgp: bad homedir\n"); 433 return 0; 434 } 435 /* read from either gpg files or ssh keys */ 436 if (netpgp_getvar(netpgp, "ssh keys") == NULL) { 437 if ((userid = netpgp_getvar(netpgp, "userid")) == NULL) { 438 (void) memset(id, 0x0, sizeof(id)); 439 (void) conffile(netpgp, homedir, id, sizeof(id)); 440 if (id[0] != 0x0) { 441 netpgp_setvar(netpgp, "userid", userid = id); 442 } 443 } 444 if (userid == NULL) { 445 if (netpgp_getvar(netpgp, "need userid") != NULL) { 446 (void) fprintf(io->errs, 447 "Cannot find user id\n"); 448 return 0; 449 } 450 } else { 451 (void) netpgp_setvar(netpgp, "userid", userid); 452 } 453 netpgp->pubring = readkeyring(netpgp, "pubring"); 454 if (netpgp->pubring == NULL) { 455 (void) fprintf(io->errs, "Can't read pub keyring\n"); 456 return 0; 457 } 458 netpgp->secring = readkeyring(netpgp, "secring"); 459 if (netpgp->secring == NULL) { 460 (void) fprintf(io->errs, "Can't read sec keyring\n"); 461 return 0; 462 } 463 } else { 464 last = (netpgp->pubring != NULL); 465 if (!readsshkeys(netpgp, homedir)) { 466 (void) fprintf(io->errs, "Can't read ssh pub key\n"); 467 return 0; 468 } 469 if ((userid = netpgp_getvar(netpgp, "userid")) == NULL) { 470 set_ssh_userid(netpgp->pubring, id, sizeof(id), last); 471 netpgp_setvar(netpgp, "userid", userid = id); 472 } 473 if (userid == NULL) { 474 if (netpgp_getvar(netpgp, "need userid") != NULL) { 475 (void) fprintf(io->errs, 476 "Cannot find user id\n"); 477 return 0; 478 } 479 } else { 480 (void) netpgp_setvar(netpgp, "userid", userid); 481 } 482 } 483 return 1; 484} 485 486/* finish off with the netpgp_t struct */ 487int 488netpgp_end(netpgp_t *netpgp) 489{ 490 unsigned i; 491 492 for (i = 0 ; i < netpgp->c ; i++) { 493 if (netpgp->name[i] != NULL) { 494 free(netpgp->name[i]); 495 } 496 if (netpgp->value[i] != NULL) { 497 free(netpgp->value[i]); 498 } 499 } 500 if (netpgp->name != NULL) { 501 free(netpgp->name); 502 } 503 if (netpgp->value != NULL) { 504 free(netpgp->value); 505 } 506 if (netpgp->pubring != NULL) { 507 __ops_keyring_free(netpgp->pubring); 508 } 509 if (netpgp->secring != NULL) { 510 __ops_keyring_free(netpgp->secring); 511 } 512 free(netpgp->io); 513 return 1; 514} 515 516/* list the keys in a keyring */ 517int 518netpgp_list_keys(netpgp_t *netpgp) 519{ 520 return __ops_keyring_list(netpgp->io, netpgp->pubring); 521} 522 523DEFINE_ARRAY(strings_t, char *); 524 525#ifndef HKP_VERSION 526#define HKP_VERSION 1 527#endif 528 529/* find and list some keys in a keyring */ 530int 531netpgp_match_keys(netpgp_t *netpgp, char *name, const char *fmt, void *vp) 532{ 533 const __ops_key_t *key; 534 unsigned k; 535 strings_t pubs; 536 FILE *fp = (FILE *)vp; 537 538 (void) memset(&pubs, 0x0, sizeof(pubs)); 539 k = 0; 540 do { 541 key = __ops_getnextkeybyname(netpgp->io, netpgp->pubring, 542 name, &k); 543 if (key != NULL) { 544 ALLOC(char *, pubs.v, pubs.size, pubs.c, 10, 10, 545 "netpgp_match_keys", return 0); 546 if (strcmp(fmt, "mr") == 0) { 547 __ops_hkp_sprint_keydata( 548 key, &pubs.v[pubs.c], 549 &key->key.pubkey); 550 } else { 551 __ops_sprint_keydata( 552 key, &pubs.v[pubs.c], 553 "pub", 554 &key->key.pubkey); 555 } 556 pubs.c += 1; 557 k += 1; 558 } 559 } while (key != NULL); 560 if (strcmp(fmt, "mr") == 0) { 561 (void) fprintf(fp, "info:%d:%d\n", HKP_VERSION, pubs.c); 562 } else { 563 (void) fprintf(fp, "%d keys found\n", pubs.c); 564 } 565 for (k = 0 ; k < pubs.c ; k++) { 566 (void) fprintf(fp, "%s", pubs.v[k]); 567 free(pubs.v[k]); 568 } 569 free(pubs.v); 570 return pubs.c; 571} 572 573/* find and list some public keys in a keyring */ 574int 575netpgp_match_pubkeys(netpgp_t *netpgp, char *name, void *vp) 576{ 577 const __ops_key_t *key; 578 unsigned k; 579 strings_t pubs; 580 FILE *fp = (FILE *)vp; 581 582 (void) memset(&pubs, 0x0, sizeof(pubs)); 583 do { 584 key = __ops_getnextkeybyname(netpgp->io, netpgp->pubring, 585 name, &k); 586 if (key != NULL) { 587 char out[1024 * 64]; 588 589 ALLOC(char *, pubs.v, pubs.size, pubs.c, 10, 10, 590 "netpgp_match_pubkeys", return 0); 591 (void) __ops_sprint_pubkey(key, out, sizeof(out)); 592 pubs.v[pubs.c++] = strdup(out); 593 k += 1; 594 } 595 } while (key != NULL); 596 (void) fprintf(fp, "info:%d:%d\n", HKP_VERSION, pubs.c); 597 for (k = 0 ; k < pubs.c ; k++) { 598 (void) fprintf(fp, "%s", pubs.v[k]); 599 free(pubs.v[k]); 600 } 601 free(pubs.v); 602 return pubs.c; 603} 604 605/* find a key in a keyring */ 606int 607netpgp_find_key(netpgp_t *netpgp, char *id) 608{ 609 __ops_io_t *io; 610 611 io = netpgp->io; 612 if (id == NULL) { 613 (void) fprintf(io->errs, "NULL id to search for\n"); 614 return 0; 615 } 616 return __ops_getkeybyname(netpgp->io, netpgp->pubring, id) != NULL; 617} 618 619/* get a key in a keyring */ 620char * 621netpgp_get_key(netpgp_t *netpgp, const char *id) 622{ 623 const __ops_key_t *key; 624 __ops_io_t *io; 625 char *newkey; 626 627 io = netpgp->io; 628 if (id == NULL) { 629 /* just get the default userid */ 630 id = netpgp_getvar(netpgp, "userid"); 631 } 632 key = __ops_getkeybyname(netpgp->io, netpgp->pubring, id); 633 if (key == NULL) { 634 (void) fprintf(io->errs, "Can't find key '%s'\n", id); 635 return NULL; 636 } 637 return (__ops_sprint_keydata(key, &newkey, "pub", 638 &key->key.pubkey) > 0) ? newkey : NULL; 639} 640 641/* export a given key */ 642int 643netpgp_export_key(netpgp_t *netpgp, char *userid) 644{ 645 const __ops_key_t *keypair; 646 __ops_io_t *io; 647 648 io = netpgp->io; 649 if (userid == NULL) { 650 userid = netpgp_getvar(netpgp, "userid"); 651 } 652 keypair = __ops_getkeybyname(io, netpgp->pubring, userid); 653 if (keypair == NULL) { 654 (void) fprintf(io->errs, 655 "Cannot find own key \"%s\" in keyring\n", userid); 656 return 0; 657 } 658 return __ops_export_key(keypair, NULL); 659} 660 661/* import a key into our keyring */ 662int 663netpgp_import_key(netpgp_t *netpgp, char *f) 664{ 665 const unsigned noarmor = 0; 666 const unsigned armor = 1; 667 __ops_io_t *io; 668 int done; 669 670 io = netpgp->io; 671 if ((done = __ops_keyring_fileread(netpgp->pubring, noarmor, f)) == 0) { 672 done = __ops_keyring_fileread(netpgp->pubring, armor, f); 673 } 674 if (!done) { 675 (void) fprintf(io->errs, "Cannot import key from file %s\n", 676 f); 677 return 0; 678 } 679 return __ops_keyring_list(io, netpgp->pubring); 680} 681 682/* generate a new key */ 683int 684netpgp_generate_key(netpgp_t *netpgp, char *id, int numbits) 685{ 686 __ops_key_t *keypair; 687 __ops_userid_t uid; 688 __ops_output_t *create; 689 const unsigned noarmor = 0; 690 __ops_io_t *io; 691 char *ringfile; 692 int fd; 693 694 (void) memset(&uid, 0x0, sizeof(uid)); 695 io = netpgp->io; 696 /* generate a new key for 'id' */ 697 uid.userid = (unsigned char *) id; 698 keypair = __ops_rsa_new_selfsign_key(numbits, 65537UL, &uid); 699 if (keypair == NULL) { 700 (void) fprintf(io->errs, "Cannot generate key\n"); 701 return 0; 702 } 703 /* write public key, and try to re-read it */ 704 ringfile = netpgp_getvar(netpgp, "pubring"); 705 fd = __ops_setup_file_append(&create, ringfile); 706 if (!__ops_write_xfer_pubkey(create, keypair, noarmor)) { 707 (void) fprintf(io->errs, "Cannot write pubkey\n"); 708 return 0; 709 } 710 __ops_teardown_file_write(create, fd); 711 __ops_keyring_free(netpgp->pubring); 712 if (!__ops_keyring_fileread(netpgp->pubring, noarmor, ringfile)) { 713 (void) fprintf(io->errs, "Cannot read pubring %s\n", ringfile); 714 return 0; 715 } 716 /* write secret key, and try to re-read it */ 717 ringfile = netpgp_getvar(netpgp, "sec ring file"); 718 fd = __ops_setup_file_append(&create, ringfile); 719 if (!__ops_write_xfer_seckey(create, keypair, NULL, 0, noarmor)) { 720 (void) fprintf(io->errs, "Cannot write seckey\n"); 721 return 0; 722 } 723 __ops_teardown_file_write(create, fd); 724 __ops_keyring_free(netpgp->secring); 725 if (!__ops_keyring_fileread(netpgp->secring, noarmor, ringfile)) { 726 (void) fprintf(io->errs, "Can't read secring %s\n", ringfile); 727 return 0; 728 } 729 __ops_keydata_free(keypair); 730 return 1; 731} 732 733/* encrypt a file */ 734int 735netpgp_encrypt_file(netpgp_t *netpgp, 736 const char *userid, 737 const char *f, 738 char *out, 739 int armored) 740{ 741 const __ops_key_t *keypair; 742 const unsigned overwrite = 1; 743 const char *suffix; 744 __ops_io_t *io; 745 char outname[MAXPATHLEN]; 746 747 io = netpgp->io; 748 if (f == NULL) { 749 (void) fprintf(io->errs, 750 "netpgp_encrypt_file: no filename specified\n"); 751 return 0; 752 } 753 if (userid == NULL) { 754 userid = netpgp_getvar(netpgp, "userid"); 755 } 756 suffix = (armored) ? ".asc" : ".gpg"; 757 keypair = __ops_getkeybyname(io, netpgp->pubring, userid); 758 if (keypair == NULL) { 759 (void) fprintf(io->errs, "Userid '%s' not found in keyring\n", 760 userid); 761 return 0; 762 } 763 if (out == NULL) { 764 (void) snprintf(outname, sizeof(outname), "%s%s", f, suffix); 765 out = outname; 766 } 767 return (int)__ops_encrypt_file(io, f, out, keypair, (unsigned)armored, 768 overwrite); 769} 770 771#define ARMOR_HEAD "-----BEGIN PGP MESSAGE-----\r\n" 772 773/* decrypt a file */ 774int 775netpgp_decrypt_file(netpgp_t *netpgp, const char *f, char *out, int armored) 776{ 777 const unsigned overwrite = 1; 778 __ops_io_t *io; 779 unsigned realarmour; 780 FILE *fp; 781 char buf[BUFSIZ]; 782 783 io = netpgp->io; 784 if (f == NULL) { 785 (void) fprintf(io->errs, 786 "netpgp_decrypt_file: no filename specified\n"); 787 return 0; 788 } 789 realarmour = (unsigned)armored; 790 if ((fp = fopen(f, "r")) == NULL) { 791 (void) fprintf(io->errs, 792 "netpgp_decrypt_file: can't open '%s'\n", f); 793 return 0; 794 } 795 if (fgets(buf, sizeof(buf), fp) == NULL) { 796 realarmour = 0; 797 } else { 798 realarmour = (strcmp(buf, ARMOR_HEAD) == 0); 799 } 800 (void) fclose(fp); 801 return __ops_decrypt_file(netpgp->io, f, out, netpgp->secring, 802 (unsigned)realarmour, overwrite, 803 netpgp->passfp, get_passphrase_cb); 804} 805 806/* sign a file */ 807int 808netpgp_sign_file(netpgp_t *netpgp, 809 const char *userid, 810 const char *f, 811 char *out, 812 int armored, 813 int cleartext, 814 int detached) 815{ 816 const __ops_key_t *keypair; 817 const __ops_key_t *pubkey; 818 __ops_seckey_t *seckey; 819 const unsigned overwrite = 1; 820 __ops_io_t *io; 821 char *hashalg; 822 int ret; 823 824 io = netpgp->io; 825 if (f == NULL) { 826 (void) fprintf(io->errs, 827 "netpgp_sign_file: no filename specified\n"); 828 return 0; 829 } 830 if (userid == NULL) { 831 userid = netpgp_getvar(netpgp, "userid"); 832 } 833 /* get key with which to sign */ 834 keypair = __ops_getkeybyname(io, netpgp->secring, userid); 835 if (keypair == NULL) { 836 (void) fprintf(io->errs, "Userid '%s' not found in secring\n", 837 userid); 838 return 0; 839 } 840 ret = 1; 841 do { 842 if (netpgp->passfp == NULL) { 843 /* print out the user id */ 844 pubkey = __ops_getkeybyname(io, netpgp->pubring, userid); 845 if (pubkey == NULL) { 846 (void) fprintf(io->errs, 847 "netpgp: warning - using pubkey from secring\n"); 848 __ops_print_keydata(io, keypair, "pub", 849 &keypair->key.seckey.pubkey); 850 } else { 851 __ops_print_keydata(io, pubkey, "pub", &pubkey->key.pubkey); 852 } 853 } 854 if (netpgp_getvar(netpgp, "ssh keys") == NULL) { 855 /* now decrypt key */ 856 seckey = __ops_decrypt_seckey(keypair, netpgp->passfp); 857 if (seckey == NULL) { 858 (void) fprintf(io->errs, "Bad passphrase\n"); 859 } 860 } else { 861 __ops_keyring_t *secring; 862 863 secring = netpgp->secring; 864 seckey = &secring->keys[0].key.seckey; 865 } 866 } while (seckey == NULL); 867 /* sign file */ 868 hashalg = netpgp_getvar(netpgp, "hash"); 869 if (detached) { 870 ret = __ops_sign_detached(io, f, out, seckey, hashalg, 871 get_birthtime(netpgp_getvar(netpgp, "birthtime")), 872 get_duration(netpgp_getvar(netpgp, "duration"))); 873 } else { 874 ret = __ops_sign_file(io, f, out, seckey, hashalg, 875 get_birthtime(netpgp_getvar(netpgp, "birthtime")), 876 get_duration(netpgp_getvar(netpgp, "duration")), 877 (unsigned)armored, (unsigned)cleartext, 878 overwrite); 879 } 880 __ops_forget(seckey, sizeof(*seckey)); 881 return ret; 882} 883 884/* verify a file */ 885int 886netpgp_verify_file(netpgp_t *netpgp, const char *in, const char *out, int armored) 887{ 888 __ops_validation_t result; 889 __ops_io_t *io; 890 891 (void) memset(&result, 0x0, sizeof(result)); 892 io = netpgp->io; 893 if (in == NULL) { 894 (void) fprintf(io->errs, 895 "netpgp_verify_file: no filename specified\n"); 896 return 0; 897 } 898 if (__ops_validate_file(io, &result, in, out, armored, 899 netpgp->pubring)) { 900 resultp(io, in, &result, netpgp->pubring); 901 return 1; 902 } 903 if (result.validc + result.invalidc + result.unknownc == 0) { 904 (void) fprintf(io->errs, 905 "\"%s\": No signatures found - is this a signed file?\n", 906 in); 907 } else if (result.invalidc == 0 && result.unknownc == 0) { 908 (void) fprintf(io->errs, 909 "\"%s\": file verification failure: invalid signature time\n", in); 910 } else { 911 (void) fprintf(io->errs, 912"\"%s\": verification failure: %u invalid signatures, %u unknown signatures\n", 913 in, result.invalidc, result.unknownc); 914 } 915 return 0; 916} 917 918/* sign some memory */ 919int 920netpgp_sign_memory(netpgp_t *netpgp, 921 const char *userid, 922 char *mem, 923 size_t size, 924 char *out, 925 size_t outsize, 926 const unsigned armored, 927 const unsigned cleartext) 928{ 929 const __ops_key_t *keypair; 930 const __ops_key_t *pubkey; 931 __ops_seckey_t *seckey; 932 __ops_memory_t *signedmem; 933 __ops_io_t *io; 934 char *hashalg; 935 int ret; 936 937 io = netpgp->io; 938 if (mem == NULL) { 939 (void) fprintf(io->errs, 940 "netpgp_sign_memory: no memory to sign\n"); 941 return 0; 942 } 943 if (userid == NULL) { 944 userid = netpgp_getvar(netpgp, "userid"); 945 } 946 /* get key with which to sign */ 947 keypair = __ops_getkeybyname(io, netpgp->secring, userid); 948 if (keypair == NULL) { 949 (void) fprintf(io->errs, "Userid '%s' not found in keyring\n", 950 userid); 951 return 0; 952 } 953 ret = 1; 954 do { 955 if (netpgp->passfp == NULL) { 956 /* print out the user id */ 957 pubkey = __ops_getkeybyname(io, netpgp->pubring, userid); 958 if (pubkey == NULL) { 959 (void) fprintf(io->errs, 960 "netpgp: warning - using pubkey from secring\n"); 961 __ops_print_keydata(io, keypair, "pub", 962 &keypair->key.seckey.pubkey); 963 } else { 964 __ops_print_keydata(io, pubkey, "pub", &pubkey->key.pubkey); 965 } 966 } 967 /* now decrypt key */ 968 seckey = __ops_decrypt_seckey(keypair, netpgp->passfp); 969 if (seckey == NULL) { 970 (void) fprintf(io->errs, "Bad passphrase\n"); 971 } 972 } while (seckey == NULL); 973 /* sign file */ 974 (void) memset(out, 0x0, outsize); 975 hashalg = netpgp_getvar(netpgp, "hash"); 976 signedmem = __ops_sign_buf(io, mem, size, seckey, 977 get_birthtime(netpgp_getvar(netpgp, "birthtime")), 978 get_duration(netpgp_getvar(netpgp, "duration")), 979 hashalg, armored, cleartext); 980 if (signedmem) { 981 size_t m; 982 983 m = MIN(__ops_mem_len(signedmem), outsize); 984 (void) memcpy(out, __ops_mem_data(signedmem), m); 985 __ops_memory_free(signedmem); 986 ret = (int)m; 987 } else { 988 ret = 0; 989 } 990 __ops_forget(seckey, sizeof(*seckey)); 991 return ret; 992} 993 994/* verify memory */ 995int 996netpgp_verify_memory(netpgp_t *netpgp, const void *in, const size_t size, 997 void *out, size_t outsize, const int armored) 998{ 999 __ops_validation_t result; 1000 __ops_memory_t *signedmem; 1001 __ops_memory_t *cat; 1002 __ops_io_t *io; 1003 size_t m; 1004 int ret; 1005 1006 (void) memset(&result, 0x0, sizeof(result)); 1007 io = netpgp->io; 1008 if (in == NULL) { 1009 (void) fprintf(io->errs, 1010 "netpgp_verify_memory: no memory to verify\n"); 1011 return 0; 1012 } 1013 signedmem = __ops_memory_new(); 1014 __ops_memory_add(signedmem, in, size); 1015 ret = __ops_validate_mem(io, &result, signedmem, 1016 (out) ? &cat : NULL, 1017 armored, netpgp->pubring); 1018 __ops_memory_free(signedmem); 1019 if (ret) { 1020 resultp(io, "<stdin>", &result, netpgp->pubring); 1021 if (out) { 1022 m = MIN(__ops_mem_len(cat), outsize); 1023 (void) memcpy(out, __ops_mem_data(cat), m); 1024 __ops_memory_free(cat); 1025 } else { 1026 m = 1; 1027 } 1028 return (int)m; 1029 } 1030 if (result.validc + result.invalidc + result.unknownc == 0) { 1031 (void) fprintf(io->errs, 1032 "No signatures found - is this memory signed?\n"); 1033 } else if (result.invalidc == 0 && result.unknownc == 0) { 1034 (void) fprintf(io->errs, 1035 "memory verification failure: invalid signature time\n"); 1036 } else { 1037 (void) fprintf(io->errs, 1038"memory verification failure: %u invalid signatures, %u unknown signatures\n", 1039 result.invalidc, result.unknownc); 1040 } 1041 return 0; 1042} 1043 1044/* encrypt some memory */ 1045int 1046netpgp_encrypt_memory(netpgp_t *netpgp, 1047 const char *userid, 1048 void *in, 1049 const size_t insize, 1050 char *out, 1051 size_t outsize, 1052 int armored) 1053{ 1054 const __ops_key_t *keypair; 1055 __ops_memory_t *enc; 1056 __ops_io_t *io; 1057 size_t m; 1058 1059 io = netpgp->io; 1060 if (in == NULL) { 1061 (void) fprintf(io->errs, 1062 "netpgp_encrypt_buf: no memory to encrypt\n"); 1063 return 0; 1064 } 1065 if (userid == NULL) { 1066 userid = netpgp_getvar(netpgp, "userid"); 1067 } 1068 keypair = __ops_getkeybyname(io, netpgp->pubring, userid); 1069 if (keypair == NULL) { 1070 (void) fprintf(io->errs, "Userid '%s' not found in keyring\n", 1071 userid); 1072 return 0; 1073 } 1074 if (in == out) { 1075 (void) fprintf(io->errs, 1076 "netpgp_encrypt_buf: input and output bufs need to be different\n"); 1077 return 0; 1078 } 1079 if (outsize < insize) { 1080 (void) fprintf(io->errs, 1081 "netpgp_encrypt_buf: input size is larger than output size\n"); 1082 return 0; 1083 } 1084 enc = __ops_encrypt_buf(io, in, insize, keypair, (unsigned)armored); 1085 m = MIN(__ops_mem_len(enc), outsize); 1086 (void) memcpy(out, __ops_mem_data(enc), m); 1087 __ops_memory_free(enc); 1088 return (int)m; 1089} 1090 1091/* decrypt a chunk of memory */ 1092int 1093netpgp_decrypt_memory(netpgp_t *netpgp, const void *input, const size_t insize, 1094 char *out, size_t outsize, const int armored) 1095{ 1096 __ops_memory_t *mem; 1097 __ops_io_t *io; 1098 unsigned realarmour; 1099 size_t m; 1100 1101 io = netpgp->io; 1102 realarmour = (unsigned) armored; 1103 if (input == NULL) { 1104 (void) fprintf(io->errs, 1105 "netpgp_decrypt_memory: no memory\n"); 1106 return 0; 1107 } 1108 realarmour = (strncmp(input, ARMOR_HEAD, sizeof(ARMOR_HEAD) - 1) == 0); 1109 mem = __ops_decrypt_buf(netpgp->io, input, insize, netpgp->secring, 1110 realarmour, netpgp->passfp, 1111 get_passphrase_cb); 1112 m = MIN(__ops_mem_len(mem), outsize); 1113 (void) memcpy(out, __ops_mem_data(mem), m); 1114 __ops_memory_free(mem); 1115 return (int)m; 1116} 1117 1118/* wrappers for the ops_debug_level functions we added to openpgpsdk */ 1119 1120/* set the debugging level per filename */ 1121int 1122netpgp_set_debug(const char *f) 1123{ 1124 return __ops_set_debug_level(f); 1125} 1126 1127/* get the debugging level per filename */ 1128int 1129netpgp_get_debug(const char *f) 1130{ 1131 return __ops_get_debug_level(f); 1132} 1133 1134/* return the version for the library */ 1135const char * 1136netpgp_get_info(const char *type) 1137{ 1138 return __ops_get_info(type); 1139} 1140 1141/* list all the packets in a file */ 1142int 1143netpgp_list_packets(netpgp_t *netpgp, char *f, int armour, char *pubringname) 1144{ 1145 __ops_keyring_t *keyring; 1146 const unsigned noarmor = 0; 1147 struct stat st; 1148 __ops_io_t *io; 1149 char ringname[MAXPATHLEN]; 1150 char *homedir; 1151 int ret; 1152 1153 io = netpgp->io; 1154 if (f == NULL) { 1155 (void) fprintf(io->errs, "No file containing packets\n"); 1156 return 0; 1157 } 1158 if (stat(f, &st) < 0) { 1159 (void) fprintf(io->errs, "No such file '%s'\n", f); 1160 return 0; 1161 } 1162 homedir = netpgp_getvar(netpgp, "homedir"); 1163 if (pubringname == NULL) { 1164 (void) snprintf(ringname, sizeof(ringname), 1165 "%s/pubring.gpg", homedir); 1166 pubringname = ringname; 1167 } 1168 if ((keyring = calloc(1, sizeof(*keyring))) == NULL) { 1169 (void) fprintf(io->errs, "netpgp_list_packets: bad alloc\n"); 1170 return 0; 1171 } 1172 if (!__ops_keyring_fileread(keyring, noarmor, pubringname)) { 1173 free(keyring); 1174 (void) fprintf(io->errs, "Cannot read pub keyring %s\n", 1175 pubringname); 1176 return 0; 1177 } 1178 netpgp->pubring = keyring; 1179 netpgp_setvar(netpgp, "pubring", pubringname); 1180 ret = __ops_list_packets(io, f, (unsigned)armour, keyring, 1181 netpgp->passfp, 1182 get_passphrase_cb); 1183 free(keyring); 1184 return ret; 1185} 1186 1187/* set a variable */ 1188int 1189netpgp_setvar(netpgp_t *netpgp, const char *name, const char *value) 1190{ 1191 int i; 1192 1193 if ((i = findvar(netpgp, name)) < 0) { 1194 /* add the element to the array */ 1195 if (size_arrays(netpgp, netpgp->size + 15)) { 1196 netpgp->name[i = netpgp->c++] = strdup(name); 1197 } 1198 } else { 1199 /* replace the element in the array */ 1200 if (netpgp->value[i]) { 1201 free(netpgp->value[i]); 1202 netpgp->value[i] = NULL; 1203 } 1204 } 1205 /* sanity checks for range of values */ 1206 if (strcmp(name, "hash") == 0 || strcmp(name, "algorithm") == 0) { 1207 if (__ops_str_to_hash_alg(value) == OPS_HASH_UNKNOWN) { 1208 return 0; 1209 } 1210 } 1211 netpgp->value[i] = strdup(value); 1212 return 1; 1213} 1214 1215/* get a variable's value (NULL if not set) */ 1216char * 1217netpgp_getvar(netpgp_t *netpgp, const char *name) 1218{ 1219 int i; 1220 1221 return ((i = findvar(netpgp, name)) < 0) ? NULL : netpgp->value[i]; 1222} 1223 1224/* increment a value */ 1225int 1226netpgp_incvar(netpgp_t *netpgp, const char *name, const int delta) 1227{ 1228 char *cp; 1229 char num[16]; 1230 int val; 1231 1232 val = 0; 1233 if ((cp = netpgp_getvar(netpgp, name)) != NULL) { 1234 val = atoi(cp); 1235 } 1236 (void) snprintf(num, sizeof(num), "%d", val + delta); 1237 netpgp_setvar(netpgp, name, num); 1238 return 1; 1239} 1240 1241/* set the home directory value to "home/subdir" */ 1242int 1243netpgp_set_homedir(netpgp_t *netpgp, char *home, const char *subdir, const int quiet) 1244{ 1245 struct stat st; 1246 char d[MAXPATHLEN]; 1247 1248 if (home == NULL) { 1249 if (!quiet) { 1250 (void) fprintf(stderr, "NULL HOME directory\n"); 1251 } 1252 return 0; 1253 } 1254 (void) snprintf(d, sizeof(d), "%s%s", home, (subdir) ? subdir : ""); 1255 if (stat(d, &st) == 0) { 1256 if ((st.st_mode & S_IFMT) == S_IFDIR) { 1257 netpgp_setvar(netpgp, "homedir", d); 1258 return 1; 1259 } 1260 (void) fprintf(stderr, "netpgp: homedir \"%s\" is not a dir\n", 1261 d); 1262 return 0; 1263 } 1264 if (!quiet) { 1265 (void) fprintf(stderr, 1266 "netpgp: warning homedir \"%s\" not found\n", d); 1267 } 1268 return 1; 1269} 1270 1271/* validate all sigs in the pub keyring */ 1272int 1273netpgp_validate_sigs(netpgp_t *netpgp) 1274{ 1275 __ops_validation_t result; 1276 1277 return (int)__ops_validate_all_sigs(&result, netpgp->pubring, NULL); 1278} 1279 1280#if 0 1281#include "sshkey.h" 1282 1283int 1284netpgp_pgpkey_to_sshkey(netpgp_t *netpgp, char *name, SSHKey *sshkey) 1285{ 1286 const __ops_key_t *pgpkey; 1287 unsigned k; 1288 1289 k = 0; 1290 pgpkey = __ops_getnextkeybyname(netpgp->io, netpgp->pubring, name, &k); 1291 if (pgpkey == NULL) { 1292 pgpkey = __ops_getkeybyname(io, netpgp->pubring, userid); 1293 } 1294 if (pgpkey == NULL) { 1295 (void) fprintf(stderr, "No key matching '%s'\n", name); 1296 return 0; 1297 } 1298 switch(pgpkey->key.pubkey.alg) { 1299 case OPS_PKA_RSA: 1300 sshkey->type = KEY_RSA; 1301 sshkey->rsa = calloc(1, sizeof(*sshkey->rsa); 1302 if (sshkey->rsa == NULL) { 1303 (void) fprintf(stderr, "RSA memory problems\n"); 1304 return 0; 1305 } 1306 sshkey->rsa->n = pgpkey->key.pubkey.key.rsa.n; 1307 sshkey->rsa->e = pgpkey->key.pubkey.key.rsa.e; 1308 sshkey->rsa->d = pgpkey->key.seckey.key.rsa.d; 1309 sshkey->rsa->p = pgpkey->key.seckey.key.rsa.p; 1310 sshkey->rsa->q = pgpkey->key.seckey.key.rsa.q; 1311 sshkey->rsa->iqmp = pgpkey->key.seckey.key.rsa.u; 1312 break; 1313 case OPS_PKA_DSA: 1314 sshkey->type = KEY_DSA; 1315 sshkey->dsa = calloc(1, sizeof(*sshkey->dsa); 1316 if (sshkey->dsa == NULL) { 1317 (void) fprintf(stderr, "DSA memory problems\n"); 1318 return 0; 1319 } 1320 sshkey->rsa->n = pgpkey->key.pubkey.key.rsa.n; 1321 key->dsa->p = pgpkey->key.pubkey.key.dsa.p; 1322 key->dsa->q = pgpkey->key.pubkey.key.dsa.q; 1323 key->dsa->g = pgpkey->key.pubkey.key.dsa.g; 1324 key->dsa->pub_key = pgpkey->key.pubkey.key.dsa.y; 1325 key->dsa->priv_key = pgpkey->key.seckey.key.dsa.x; 1326 break; 1327 default: 1328 (void) fprintf(stderr, "weird type\n"); 1329 return 0; 1330 } 1331 return 1; 1332} 1333#endif 1334