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.40 2010/02/23 01:24:44 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 */ 88 static int 89 conffile(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 */ 122 static char * 123 userid_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 */ 137 static void 138 resultp(__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 */ 171 static int 172 size_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 */ 208 static int 209 findvar(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 */ 219 static void * 220 readkeyring(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 */ 247 static int 248 readsshkeys(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 */ 298 static void 299 set_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 */ 314 static uint64_t 315 get_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 */ 349 static int64_t 350 get_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 */ 371 int 372 netpgp_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 free(io); 419 return 0; 420 } 421 netpgp->io = io; 422 if ((passfd = netpgp_getvar(netpgp, "pass-fd")) != NULL && 423 (netpgp->passfp = fdopen(atoi(passfd), "r")) == NULL) { 424 (void) fprintf(io->errs, "Can't open fd %s for reading\n", 425 passfd); 426 return 0; 427 } 428 if (coredumps) { 429 (void) fprintf(io->errs, 430 "netpgp: warning: core dumps enabled\n"); 431 } 432 if ((homedir = netpgp_getvar(netpgp, "homedir")) == NULL) { 433 (void) fprintf(io->errs, "netpgp: bad homedir\n"); 434 return 0; 435 } 436 /* read from either gpg files or ssh keys */ 437 if (netpgp_getvar(netpgp, "ssh keys") == NULL) { 438 if ((userid = netpgp_getvar(netpgp, "userid")) == NULL) { 439 (void) memset(id, 0x0, sizeof(id)); 440 (void) conffile(netpgp, homedir, id, sizeof(id)); 441 if (id[0] != 0x0) { 442 netpgp_setvar(netpgp, "userid", userid = id); 443 } 444 } 445 if (userid == NULL) { 446 if (netpgp_getvar(netpgp, "need userid") != NULL) { 447 (void) fprintf(io->errs, 448 "Cannot find user id\n"); 449 return 0; 450 } 451 } else { 452 (void) netpgp_setvar(netpgp, "userid", userid); 453 } 454 netpgp->pubring = readkeyring(netpgp, "pubring"); 455 if (netpgp->pubring == NULL) { 456 (void) fprintf(io->errs, "Can't read pub keyring\n"); 457 return 0; 458 } 459 netpgp->secring = readkeyring(netpgp, "secring"); 460 if (netpgp->secring == NULL) { 461 (void) fprintf(io->errs, "Can't read sec keyring\n"); 462 return 0; 463 } 464 } else { 465 last = (netpgp->pubring != NULL); 466 if (!readsshkeys(netpgp, homedir)) { 467 (void) fprintf(io->errs, "Can't read ssh pub key\n"); 468 return 0; 469 } 470 if ((userid = netpgp_getvar(netpgp, "userid")) == NULL) { 471 set_ssh_userid(netpgp->pubring, id, sizeof(id), last); 472 netpgp_setvar(netpgp, "userid", userid = id); 473 } 474 if (userid == NULL) { 475 if (netpgp_getvar(netpgp, "need userid") != NULL) { 476 (void) fprintf(io->errs, 477 "Cannot find user id\n"); 478 return 0; 479 } 480 } else { 481 (void) netpgp_setvar(netpgp, "userid", userid); 482 } 483 } 484 return 1; 485 } 486 487 /* finish off with the netpgp_t struct */ 488 int 489 netpgp_end(netpgp_t *netpgp) 490 { 491 unsigned i; 492 493 for (i = 0 ; i < netpgp->c ; i++) { 494 if (netpgp->name[i] != NULL) { 495 free(netpgp->name[i]); 496 } 497 if (netpgp->value[i] != NULL) { 498 free(netpgp->value[i]); 499 } 500 } 501 if (netpgp->name != NULL) { 502 free(netpgp->name); 503 } 504 if (netpgp->value != NULL) { 505 free(netpgp->value); 506 } 507 if (netpgp->pubring != NULL) { 508 __ops_keyring_free(netpgp->pubring); 509 } 510 if (netpgp->secring != NULL) { 511 __ops_keyring_free(netpgp->secring); 512 } 513 free(netpgp->io); 514 return 1; 515 } 516 517 /* list the keys in a keyring */ 518 int 519 netpgp_list_keys(netpgp_t *netpgp) 520 { 521 return __ops_keyring_list(netpgp->io, netpgp->pubring); 522 } 523 524 DEFINE_ARRAY(strings_t, char *); 525 526 #ifndef HKP_VERSION 527 #define HKP_VERSION 1 528 #endif 529 530 /* find and list some keys in a keyring */ 531 int 532 netpgp_match_keys(netpgp_t *netpgp, char *name, const char *fmt, void *vp) 533 { 534 const __ops_key_t *key; 535 unsigned k; 536 strings_t pubs; 537 FILE *fp = (FILE *)vp; 538 539 (void) memset(&pubs, 0x0, sizeof(pubs)); 540 k = 0; 541 do { 542 key = __ops_getnextkeybyname(netpgp->io, netpgp->pubring, 543 name, &k); 544 if (key != NULL) { 545 ALLOC(char *, pubs.v, pubs.size, pubs.c, 10, 10, 546 "netpgp_match_keys", return 0); 547 if (strcmp(fmt, "mr") == 0) { 548 __ops_hkp_sprint_keydata( 549 key, &pubs.v[pubs.c], 550 &key->key.pubkey); 551 } else { 552 __ops_sprint_keydata( 553 key, &pubs.v[pubs.c], 554 "pub", 555 &key->key.pubkey); 556 } 557 pubs.c += 1; 558 k += 1; 559 } 560 } while (key != NULL); 561 if (strcmp(fmt, "mr") == 0) { 562 (void) fprintf(fp, "info:%d:%d\n", HKP_VERSION, pubs.c); 563 } else { 564 (void) fprintf(fp, "%d keys found\n", pubs.c); 565 } 566 for (k = 0 ; k < pubs.c ; k++) { 567 (void) fprintf(fp, "%s", pubs.v[k]); 568 free(pubs.v[k]); 569 } 570 free(pubs.v); 571 return pubs.c; 572 } 573 574 /* find and list some public keys in a keyring */ 575 int 576 netpgp_match_pubkeys(netpgp_t *netpgp, char *name, void *vp) 577 { 578 const __ops_key_t *key; 579 unsigned k; 580 strings_t pubs; 581 FILE *fp = (FILE *)vp; 582 583 (void) memset(&pubs, 0x0, sizeof(pubs)); 584 do { 585 key = __ops_getnextkeybyname(netpgp->io, netpgp->pubring, 586 name, &k); 587 if (key != NULL) { 588 char out[1024 * 64]; 589 590 ALLOC(char *, pubs.v, pubs.size, pubs.c, 10, 10, 591 "netpgp_match_pubkeys", return 0); 592 (void) __ops_sprint_pubkey(key, out, sizeof(out)); 593 pubs.v[pubs.c++] = strdup(out); 594 k += 1; 595 } 596 } while (key != NULL); 597 (void) fprintf(fp, "info:%d:%d\n", HKP_VERSION, pubs.c); 598 for (k = 0 ; k < pubs.c ; k++) { 599 (void) fprintf(fp, "%s", pubs.v[k]); 600 free(pubs.v[k]); 601 } 602 free(pubs.v); 603 return pubs.c; 604 } 605 606 /* find a key in a keyring */ 607 int 608 netpgp_find_key(netpgp_t *netpgp, char *id) 609 { 610 __ops_io_t *io; 611 612 io = netpgp->io; 613 if (id == NULL) { 614 (void) fprintf(io->errs, "NULL id to search for\n"); 615 return 0; 616 } 617 return __ops_getkeybyname(netpgp->io, netpgp->pubring, id) != NULL; 618 } 619 620 /* get a key in a keyring */ 621 char * 622 netpgp_get_key(netpgp_t *netpgp, const char *id) 623 { 624 const __ops_key_t *key; 625 __ops_io_t *io; 626 char *newkey; 627 628 io = netpgp->io; 629 if (id == NULL) { 630 /* just get the default userid */ 631 id = netpgp_getvar(netpgp, "userid"); 632 } 633 key = __ops_getkeybyname(netpgp->io, netpgp->pubring, id); 634 if (key == NULL) { 635 (void) fprintf(io->errs, "Can't find key '%s'\n", id); 636 return NULL; 637 } 638 return (__ops_sprint_keydata(key, &newkey, "pub", 639 &key->key.pubkey) > 0) ? newkey : NULL; 640 } 641 642 /* export a given key */ 643 int 644 netpgp_export_key(netpgp_t *netpgp, char *userid) 645 { 646 const __ops_key_t *keypair; 647 __ops_io_t *io; 648 649 io = netpgp->io; 650 if (userid == NULL) { 651 userid = netpgp_getvar(netpgp, "userid"); 652 } 653 keypair = __ops_getkeybyname(io, netpgp->pubring, userid); 654 if (keypair == NULL) { 655 (void) fprintf(io->errs, 656 "Cannot find own key \"%s\" in keyring\n", userid); 657 return 0; 658 } 659 return __ops_export_key(keypair, NULL); 660 } 661 662 /* import a key into our keyring */ 663 int 664 netpgp_import_key(netpgp_t *netpgp, char *f) 665 { 666 const unsigned noarmor = 0; 667 const unsigned armor = 1; 668 __ops_io_t *io; 669 int done; 670 671 io = netpgp->io; 672 if ((done = __ops_keyring_fileread(netpgp->pubring, noarmor, f)) == 0) { 673 done = __ops_keyring_fileread(netpgp->pubring, armor, f); 674 } 675 if (!done) { 676 (void) fprintf(io->errs, "Cannot import key from file %s\n", 677 f); 678 return 0; 679 } 680 return __ops_keyring_list(io, netpgp->pubring); 681 } 682 683 /* generate a new key */ 684 int 685 netpgp_generate_key(netpgp_t *netpgp, char *id, int numbits) 686 { 687 __ops_key_t *keypair; 688 __ops_userid_t uid; 689 __ops_output_t *create; 690 const unsigned noarmor = 0; 691 __ops_io_t *io; 692 char *ringfile; 693 int fd; 694 695 (void) memset(&uid, 0x0, sizeof(uid)); 696 io = netpgp->io; 697 /* generate a new key for 'id' */ 698 uid.userid = (unsigned char *) id; 699 keypair = __ops_rsa_new_selfsign_key(numbits, 65537UL, &uid); 700 if (keypair == NULL) { 701 (void) fprintf(io->errs, "Cannot generate key\n"); 702 return 0; 703 } 704 /* write public key, and try to re-read it */ 705 ringfile = netpgp_getvar(netpgp, "pubring"); 706 fd = __ops_setup_file_append(&create, ringfile); 707 if (!__ops_write_xfer_pubkey(create, keypair, noarmor)) { 708 (void) fprintf(io->errs, "Cannot write pubkey\n"); 709 return 0; 710 } 711 __ops_teardown_file_write(create, fd); 712 __ops_keyring_free(netpgp->pubring); 713 if (!__ops_keyring_fileread(netpgp->pubring, noarmor, ringfile)) { 714 (void) fprintf(io->errs, "Cannot read pubring %s\n", ringfile); 715 return 0; 716 } 717 /* write secret key, and try to re-read it */ 718 ringfile = netpgp_getvar(netpgp, "sec ring file"); 719 fd = __ops_setup_file_append(&create, ringfile); 720 if (!__ops_write_xfer_seckey(create, keypair, NULL, 0, noarmor)) { 721 (void) fprintf(io->errs, "Cannot write seckey\n"); 722 return 0; 723 } 724 __ops_teardown_file_write(create, fd); 725 __ops_keyring_free(netpgp->secring); 726 if (!__ops_keyring_fileread(netpgp->secring, noarmor, ringfile)) { 727 (void) fprintf(io->errs, "Can't read secring %s\n", ringfile); 728 return 0; 729 } 730 __ops_keydata_free(keypair); 731 return 1; 732 } 733 734 /* encrypt a file */ 735 int 736 netpgp_encrypt_file(netpgp_t *netpgp, 737 const char *userid, 738 const char *f, 739 char *out, 740 int armored) 741 { 742 const __ops_key_t *keypair; 743 const unsigned overwrite = 1; 744 const char *suffix; 745 __ops_io_t *io; 746 char outname[MAXPATHLEN]; 747 748 io = netpgp->io; 749 if (f == NULL) { 750 (void) fprintf(io->errs, 751 "netpgp_encrypt_file: no filename specified\n"); 752 return 0; 753 } 754 if (userid == NULL) { 755 userid = netpgp_getvar(netpgp, "userid"); 756 } 757 suffix = (armored) ? ".asc" : ".gpg"; 758 keypair = __ops_getkeybyname(io, netpgp->pubring, userid); 759 if (keypair == NULL) { 760 (void) fprintf(io->errs, "Userid '%s' not found in keyring\n", 761 userid); 762 return 0; 763 } 764 if (out == NULL) { 765 (void) snprintf(outname, sizeof(outname), "%s%s", f, suffix); 766 out = outname; 767 } 768 return (int)__ops_encrypt_file(io, f, out, keypair, (unsigned)armored, 769 overwrite); 770 } 771 772 #define ARMOR_HEAD "-----BEGIN PGP MESSAGE-----\r\n" 773 774 /* decrypt a file */ 775 int 776 netpgp_decrypt_file(netpgp_t *netpgp, const char *f, char *out, int armored) 777 { 778 const unsigned overwrite = 1; 779 __ops_io_t *io; 780 unsigned realarmour; 781 FILE *fp; 782 char buf[BUFSIZ]; 783 784 io = netpgp->io; 785 if (f == NULL) { 786 (void) fprintf(io->errs, 787 "netpgp_decrypt_file: no filename specified\n"); 788 return 0; 789 } 790 realarmour = (unsigned)armored; 791 if ((fp = fopen(f, "r")) == NULL) { 792 (void) fprintf(io->errs, 793 "netpgp_decrypt_file: can't open '%s'\n", f); 794 return 0; 795 } 796 if (fgets(buf, sizeof(buf), fp) == NULL) { 797 realarmour = 0; 798 } else { 799 realarmour = (strcmp(buf, ARMOR_HEAD) == 0); 800 } 801 (void) fclose(fp); 802 return __ops_decrypt_file(netpgp->io, f, out, netpgp->secring, 803 netpgp->pubring, 804 (unsigned)realarmour, overwrite, 805 netpgp->passfp, get_passphrase_cb); 806 } 807 808 /* sign a file */ 809 int 810 netpgp_sign_file(netpgp_t *netpgp, 811 const char *userid, 812 const char *f, 813 char *out, 814 int armored, 815 int cleartext, 816 int detached) 817 { 818 const __ops_key_t *keypair; 819 const __ops_key_t *pubkey; 820 __ops_seckey_t *seckey; 821 const unsigned overwrite = 1; 822 __ops_io_t *io; 823 char *hashalg; 824 int ret; 825 826 io = netpgp->io; 827 if (f == NULL) { 828 (void) fprintf(io->errs, 829 "netpgp_sign_file: no filename specified\n"); 830 return 0; 831 } 832 if (userid == NULL) { 833 userid = netpgp_getvar(netpgp, "userid"); 834 } 835 /* get key with which to sign */ 836 keypair = __ops_getkeybyname(io, netpgp->secring, userid); 837 if (keypair == NULL) { 838 (void) fprintf(io->errs, "Userid '%s' not found in secring\n", 839 userid); 840 return 0; 841 } 842 ret = 1; 843 do { 844 if (netpgp->passfp == NULL) { 845 /* print out the user id */ 846 pubkey = __ops_getkeybyname(io, netpgp->pubring, userid); 847 if (pubkey == NULL) { 848 (void) fprintf(io->errs, 849 "netpgp: warning - using pubkey from secring\n"); 850 __ops_print_keydata(io, keypair, "pub", 851 &keypair->key.seckey.pubkey); 852 } else { 853 __ops_print_keydata(io, pubkey, "pub", &pubkey->key.pubkey); 854 } 855 } 856 if (netpgp_getvar(netpgp, "ssh keys") == NULL) { 857 /* now decrypt key */ 858 seckey = __ops_decrypt_seckey(keypair, netpgp->passfp); 859 if (seckey == NULL) { 860 (void) fprintf(io->errs, "Bad passphrase\n"); 861 } 862 } else { 863 __ops_keyring_t *secring; 864 865 secring = netpgp->secring; 866 seckey = &secring->keys[0].key.seckey; 867 } 868 } while (seckey == NULL); 869 /* sign file */ 870 hashalg = netpgp_getvar(netpgp, "hash"); 871 if (detached) { 872 ret = __ops_sign_detached(io, f, out, seckey, hashalg, 873 get_birthtime(netpgp_getvar(netpgp, "birthtime")), 874 get_duration(netpgp_getvar(netpgp, "duration"))); 875 } else { 876 ret = __ops_sign_file(io, f, out, seckey, hashalg, 877 get_birthtime(netpgp_getvar(netpgp, "birthtime")), 878 get_duration(netpgp_getvar(netpgp, "duration")), 879 (unsigned)armored, (unsigned)cleartext, 880 overwrite); 881 } 882 __ops_forget(seckey, sizeof(*seckey)); 883 return ret; 884 } 885 886 /* verify a file */ 887 int 888 netpgp_verify_file(netpgp_t *netpgp, const char *in, const char *out, int armored) 889 { 890 __ops_validation_t result; 891 __ops_io_t *io; 892 893 (void) memset(&result, 0x0, sizeof(result)); 894 io = netpgp->io; 895 if (in == NULL) { 896 (void) fprintf(io->errs, 897 "netpgp_verify_file: no filename specified\n"); 898 return 0; 899 } 900 if (__ops_validate_file(io, &result, in, out, armored, 901 netpgp->pubring)) { 902 resultp(io, in, &result, netpgp->pubring); 903 return 1; 904 } 905 if (result.validc + result.invalidc + result.unknownc == 0) { 906 (void) fprintf(io->errs, 907 "\"%s\": No signatures found - is this a signed file?\n", 908 in); 909 } else if (result.invalidc == 0 && result.unknownc == 0) { 910 (void) fprintf(io->errs, 911 "\"%s\": file verification failure: invalid signature time\n", in); 912 } else { 913 (void) fprintf(io->errs, 914 "\"%s\": verification failure: %u invalid signatures, %u unknown signatures\n", 915 in, result.invalidc, result.unknownc); 916 } 917 return 0; 918 } 919 920 /* sign some memory */ 921 int 922 netpgp_sign_memory(netpgp_t *netpgp, 923 const char *userid, 924 char *mem, 925 size_t size, 926 char *out, 927 size_t outsize, 928 const unsigned armored, 929 const unsigned cleartext) 930 { 931 const __ops_key_t *keypair; 932 const __ops_key_t *pubkey; 933 __ops_seckey_t *seckey; 934 __ops_memory_t *signedmem; 935 __ops_io_t *io; 936 char *hashalg; 937 int ret; 938 939 io = netpgp->io; 940 if (mem == NULL) { 941 (void) fprintf(io->errs, 942 "netpgp_sign_memory: no memory to sign\n"); 943 return 0; 944 } 945 if (userid == NULL) { 946 userid = netpgp_getvar(netpgp, "userid"); 947 } 948 /* get key with which to sign */ 949 keypair = __ops_getkeybyname(io, netpgp->secring, userid); 950 if (keypair == NULL) { 951 (void) fprintf(io->errs, "Userid '%s' not found in keyring\n", 952 userid); 953 return 0; 954 } 955 ret = 1; 956 do { 957 if (netpgp->passfp == NULL) { 958 /* print out the user id */ 959 pubkey = __ops_getkeybyname(io, netpgp->pubring, userid); 960 if (pubkey == NULL) { 961 (void) fprintf(io->errs, 962 "netpgp: warning - using pubkey from secring\n"); 963 __ops_print_keydata(io, keypair, "pub", 964 &keypair->key.seckey.pubkey); 965 } else { 966 __ops_print_keydata(io, pubkey, "pub", &pubkey->key.pubkey); 967 } 968 } 969 /* now decrypt key */ 970 seckey = __ops_decrypt_seckey(keypair, netpgp->passfp); 971 if (seckey == NULL) { 972 (void) fprintf(io->errs, "Bad passphrase\n"); 973 } 974 } while (seckey == NULL); 975 /* sign file */ 976 (void) memset(out, 0x0, outsize); 977 hashalg = netpgp_getvar(netpgp, "hash"); 978 signedmem = __ops_sign_buf(io, mem, size, seckey, 979 get_birthtime(netpgp_getvar(netpgp, "birthtime")), 980 get_duration(netpgp_getvar(netpgp, "duration")), 981 hashalg, armored, cleartext); 982 if (signedmem) { 983 size_t m; 984 985 m = MIN(__ops_mem_len(signedmem), outsize); 986 (void) memcpy(out, __ops_mem_data(signedmem), m); 987 __ops_memory_free(signedmem); 988 ret = (int)m; 989 } else { 990 ret = 0; 991 } 992 __ops_forget(seckey, sizeof(*seckey)); 993 return ret; 994 } 995 996 /* verify memory */ 997 int 998 netpgp_verify_memory(netpgp_t *netpgp, const void *in, const size_t size, 999 void *out, size_t outsize, const int armored) 1000 { 1001 __ops_validation_t result; 1002 __ops_memory_t *signedmem; 1003 __ops_memory_t *cat; 1004 __ops_io_t *io; 1005 size_t m; 1006 int ret; 1007 1008 (void) memset(&result, 0x0, sizeof(result)); 1009 io = netpgp->io; 1010 if (in == NULL) { 1011 (void) fprintf(io->errs, 1012 "netpgp_verify_memory: no memory to verify\n"); 1013 return 0; 1014 } 1015 signedmem = __ops_memory_new(); 1016 __ops_memory_add(signedmem, in, size); 1017 if (out) { 1018 cat = __ops_memory_new(); 1019 } 1020 ret = __ops_validate_mem(io, &result, signedmem, 1021 (out) ? &cat : NULL, 1022 armored, netpgp->pubring); 1023 __ops_memory_free(signedmem); 1024 if (ret) { 1025 resultp(io, "<stdin>", &result, netpgp->pubring); 1026 if (out) { 1027 m = MIN(__ops_mem_len(cat), outsize); 1028 (void) memcpy(out, __ops_mem_data(cat), m); 1029 __ops_memory_free(cat); 1030 } else { 1031 m = 1; 1032 } 1033 return (int)m; 1034 } 1035 if (result.validc + result.invalidc + result.unknownc == 0) { 1036 (void) fprintf(io->errs, 1037 "No signatures found - is this memory signed?\n"); 1038 } else if (result.invalidc == 0 && result.unknownc == 0) { 1039 (void) fprintf(io->errs, 1040 "memory verification failure: invalid signature time\n"); 1041 } else { 1042 (void) fprintf(io->errs, 1043 "memory verification failure: %u invalid signatures, %u unknown signatures\n", 1044 result.invalidc, result.unknownc); 1045 } 1046 return 0; 1047 } 1048 1049 /* encrypt some memory */ 1050 int 1051 netpgp_encrypt_memory(netpgp_t *netpgp, 1052 const char *userid, 1053 void *in, 1054 const size_t insize, 1055 char *out, 1056 size_t outsize, 1057 int armored) 1058 { 1059 const __ops_key_t *keypair; 1060 __ops_memory_t *enc; 1061 __ops_io_t *io; 1062 size_t m; 1063 1064 io = netpgp->io; 1065 if (in == NULL) { 1066 (void) fprintf(io->errs, 1067 "netpgp_encrypt_buf: no memory to encrypt\n"); 1068 return 0; 1069 } 1070 if (userid == NULL) { 1071 userid = netpgp_getvar(netpgp, "userid"); 1072 } 1073 keypair = __ops_getkeybyname(io, netpgp->pubring, userid); 1074 if (keypair == NULL) { 1075 (void) fprintf(io->errs, "Userid '%s' not found in keyring\n", 1076 userid); 1077 return 0; 1078 } 1079 if (in == out) { 1080 (void) fprintf(io->errs, 1081 "netpgp_encrypt_buf: input and output bufs need to be different\n"); 1082 return 0; 1083 } 1084 if (outsize < insize) { 1085 (void) fprintf(io->errs, 1086 "netpgp_encrypt_buf: input size is larger than output size\n"); 1087 return 0; 1088 } 1089 enc = __ops_encrypt_buf(io, in, insize, keypair, (unsigned)armored); 1090 m = MIN(__ops_mem_len(enc), outsize); 1091 (void) memcpy(out, __ops_mem_data(enc), m); 1092 __ops_memory_free(enc); 1093 return (int)m; 1094 } 1095 1096 /* decrypt a chunk of memory */ 1097 int 1098 netpgp_decrypt_memory(netpgp_t *netpgp, const void *input, const size_t insize, 1099 char *out, size_t outsize, const int armored) 1100 { 1101 __ops_memory_t *mem; 1102 __ops_io_t *io; 1103 unsigned realarmour; 1104 size_t m; 1105 1106 io = netpgp->io; 1107 realarmour = (unsigned) armored; 1108 if (input == NULL) { 1109 (void) fprintf(io->errs, 1110 "netpgp_decrypt_memory: no memory\n"); 1111 return 0; 1112 } 1113 realarmour = (strncmp(input, ARMOR_HEAD, sizeof(ARMOR_HEAD) - 1) == 0); 1114 mem = __ops_decrypt_buf(netpgp->io, input, insize, netpgp->secring, 1115 netpgp->pubring, 1116 realarmour, netpgp->passfp, 1117 get_passphrase_cb); 1118 m = MIN(__ops_mem_len(mem), outsize); 1119 (void) memcpy(out, __ops_mem_data(mem), m); 1120 __ops_memory_free(mem); 1121 return (int)m; 1122 } 1123 1124 /* wrappers for the ops_debug_level functions we added to openpgpsdk */ 1125 1126 /* set the debugging level per filename */ 1127 int 1128 netpgp_set_debug(const char *f) 1129 { 1130 return __ops_set_debug_level(f); 1131 } 1132 1133 /* get the debugging level per filename */ 1134 int 1135 netpgp_get_debug(const char *f) 1136 { 1137 return __ops_get_debug_level(f); 1138 } 1139 1140 /* return the version for the library */ 1141 const char * 1142 netpgp_get_info(const char *type) 1143 { 1144 return __ops_get_info(type); 1145 } 1146 1147 /* list all the packets in a file */ 1148 int 1149 netpgp_list_packets(netpgp_t *netpgp, char *f, int armour, char *pubringname) 1150 { 1151 __ops_keyring_t *keyring; 1152 const unsigned noarmor = 0; 1153 struct stat st; 1154 __ops_io_t *io; 1155 char ringname[MAXPATHLEN]; 1156 char *homedir; 1157 int ret; 1158 1159 io = netpgp->io; 1160 if (f == NULL) { 1161 (void) fprintf(io->errs, "No file containing packets\n"); 1162 return 0; 1163 } 1164 if (stat(f, &st) < 0) { 1165 (void) fprintf(io->errs, "No such file '%s'\n", f); 1166 return 0; 1167 } 1168 homedir = netpgp_getvar(netpgp, "homedir"); 1169 if (pubringname == NULL) { 1170 (void) snprintf(ringname, sizeof(ringname), 1171 "%s/pubring.gpg", homedir); 1172 pubringname = ringname; 1173 } 1174 if ((keyring = calloc(1, sizeof(*keyring))) == NULL) { 1175 (void) fprintf(io->errs, "netpgp_list_packets: bad alloc\n"); 1176 return 0; 1177 } 1178 if (!__ops_keyring_fileread(keyring, noarmor, pubringname)) { 1179 free(keyring); 1180 (void) fprintf(io->errs, "Cannot read pub keyring %s\n", 1181 pubringname); 1182 return 0; 1183 } 1184 netpgp->pubring = keyring; 1185 netpgp_setvar(netpgp, "pubring", pubringname); 1186 ret = __ops_list_packets(io, f, (unsigned)armour, 1187 netpgp->secring, 1188 netpgp->pubring, 1189 netpgp->passfp, 1190 get_passphrase_cb); 1191 free(keyring); 1192 return ret; 1193 } 1194 1195 /* set a variable */ 1196 int 1197 netpgp_setvar(netpgp_t *netpgp, const char *name, const char *value) 1198 { 1199 int i; 1200 1201 if ((i = findvar(netpgp, name)) < 0) { 1202 /* add the element to the array */ 1203 if (size_arrays(netpgp, netpgp->size + 15)) { 1204 netpgp->name[i = netpgp->c++] = strdup(name); 1205 } 1206 } else { 1207 /* replace the element in the array */ 1208 if (netpgp->value[i]) { 1209 free(netpgp->value[i]); 1210 netpgp->value[i] = NULL; 1211 } 1212 } 1213 /* sanity checks for range of values */ 1214 if (strcmp(name, "hash") == 0 || strcmp(name, "algorithm") == 0) { 1215 if (__ops_str_to_hash_alg(value) == OPS_HASH_UNKNOWN) { 1216 return 0; 1217 } 1218 } 1219 netpgp->value[i] = strdup(value); 1220 return 1; 1221 } 1222 1223 /* get a variable's value (NULL if not set) */ 1224 char * 1225 netpgp_getvar(netpgp_t *netpgp, const char *name) 1226 { 1227 int i; 1228 1229 return ((i = findvar(netpgp, name)) < 0) ? NULL : netpgp->value[i]; 1230 } 1231 1232 /* increment a value */ 1233 int 1234 netpgp_incvar(netpgp_t *netpgp, const char *name, const int delta) 1235 { 1236 char *cp; 1237 char num[16]; 1238 int val; 1239 1240 val = 0; 1241 if ((cp = netpgp_getvar(netpgp, name)) != NULL) { 1242 val = atoi(cp); 1243 } 1244 (void) snprintf(num, sizeof(num), "%d", val + delta); 1245 netpgp_setvar(netpgp, name, num); 1246 return 1; 1247 } 1248 1249 /* set the home directory value to "home/subdir" */ 1250 int 1251 netpgp_set_homedir(netpgp_t *netpgp, char *home, const char *subdir, const int quiet) 1252 { 1253 struct stat st; 1254 char d[MAXPATHLEN]; 1255 1256 if (home == NULL) { 1257 if (!quiet) { 1258 (void) fprintf(stderr, "NULL HOME directory\n"); 1259 } 1260 return 0; 1261 } 1262 (void) snprintf(d, sizeof(d), "%s%s", home, (subdir) ? subdir : ""); 1263 if (stat(d, &st) == 0) { 1264 if ((st.st_mode & S_IFMT) == S_IFDIR) { 1265 netpgp_setvar(netpgp, "homedir", d); 1266 return 1; 1267 } 1268 (void) fprintf(stderr, "netpgp: homedir \"%s\" is not a dir\n", 1269 d); 1270 return 0; 1271 } 1272 if (!quiet) { 1273 (void) fprintf(stderr, 1274 "netpgp: warning homedir \"%s\" not found\n", d); 1275 } 1276 return 1; 1277 } 1278 1279 /* validate all sigs in the pub keyring */ 1280 int 1281 netpgp_validate_sigs(netpgp_t *netpgp) 1282 { 1283 __ops_validation_t result; 1284 1285 return (int)__ops_validate_all_sigs(&result, netpgp->pubring, NULL); 1286 } 1287 1288 #if 0 1289 #include "sshkey.h" 1290 1291 int 1292 netpgp_pgpkey_to_sshkey(netpgp_t *netpgp, char *name, SSHKey *sshkey) 1293 { 1294 const __ops_key_t *pgpkey; 1295 unsigned k; 1296 1297 k = 0; 1298 pgpkey = __ops_getnextkeybyname(netpgp->io, netpgp->pubring, name, &k); 1299 if (pgpkey == NULL) { 1300 pgpkey = __ops_getkeybyname(io, netpgp->pubring, userid); 1301 } 1302 if (pgpkey == NULL) { 1303 (void) fprintf(stderr, "No key matching '%s'\n", name); 1304 return 0; 1305 } 1306 switch(pgpkey->key.pubkey.alg) { 1307 case OPS_PKA_RSA: 1308 sshkey->type = KEY_RSA; 1309 sshkey->rsa = calloc(1, sizeof(*sshkey->rsa); 1310 if (sshkey->rsa == NULL) { 1311 (void) fprintf(stderr, "RSA memory problems\n"); 1312 return 0; 1313 } 1314 sshkey->rsa->n = pgpkey->key.pubkey.key.rsa.n; 1315 sshkey->rsa->e = pgpkey->key.pubkey.key.rsa.e; 1316 sshkey->rsa->d = pgpkey->key.seckey.key.rsa.d; 1317 sshkey->rsa->p = pgpkey->key.seckey.key.rsa.p; 1318 sshkey->rsa->q = pgpkey->key.seckey.key.rsa.q; 1319 sshkey->rsa->iqmp = pgpkey->key.seckey.key.rsa.u; 1320 break; 1321 case OPS_PKA_DSA: 1322 sshkey->type = KEY_DSA; 1323 sshkey->dsa = calloc(1, sizeof(*sshkey->dsa); 1324 if (sshkey->dsa == NULL) { 1325 (void) fprintf(stderr, "DSA memory problems\n"); 1326 return 0; 1327 } 1328 sshkey->rsa->n = pgpkey->key.pubkey.key.rsa.n; 1329 key->dsa->p = pgpkey->key.pubkey.key.dsa.p; 1330 key->dsa->q = pgpkey->key.pubkey.key.dsa.q; 1331 key->dsa->g = pgpkey->key.pubkey.key.dsa.g; 1332 key->dsa->pub_key = pgpkey->key.pubkey.key.dsa.y; 1333 key->dsa->priv_key = pgpkey->key.seckey.key.dsa.x; 1334 break; 1335 default: 1336 (void) fprintf(stderr, "weird type\n"); 1337 return 0; 1338 } 1339 return 1; 1340 } 1341 #endif 1342