netpgp.c revision 1.73
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.73 2010/09/02 07:31:16 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, (int)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 regfree(&keyre); 119 return 1; 120} 121 122/* small function to pretty print an 8-character raw userid */ 123static char * 124userid_to_id(const uint8_t *userid, char *id) 125{ 126 static const char *hexes = "0123456789abcdef"; 127 int i; 128 129 for (i = 0; i < 8 ; i++) { 130 id[i * 2] = hexes[(unsigned)(userid[i] & 0xf0) >> 4]; 131 id[(i * 2) + 1] = hexes[userid[i] & 0xf]; 132 } 133 id[8 * 2] = 0x0; 134 return id; 135} 136 137/* print out the successful signature information */ 138static void 139resultp(__ops_io_t *io, 140 const char *f, 141 __ops_validation_t *res, 142 __ops_keyring_t *ring) 143{ 144 const __ops_key_t *key; 145 __ops_pubkey_t *sigkey; 146 unsigned from; 147 unsigned i; 148 time_t t; 149 char id[MAX_ID_LENGTH + 1]; 150 151 for (i = 0; i < res->validc; i++) { 152 (void) fprintf(io->res, 153 "Good signature for %s made %s", 154 (f) ? f : "<stdin>", 155 ctime(&res->valid_sigs[i].birthtime)); 156 if (res->duration > 0) { 157 t = res->birthtime + res->duration; 158 (void) fprintf(io->res, "Valid until %s", ctime(&t)); 159 } 160 (void) fprintf(io->res, 161 "using %s key %s\n", 162 __ops_show_pka(res->valid_sigs[i].key_alg), 163 userid_to_id(res->valid_sigs[i].signer_id, id)); 164 from = 0; 165 key = __ops_getkeybyid(io, ring, 166 (const uint8_t *) res->valid_sigs[i].signer_id, 167 &from, &sigkey); 168 if (sigkey == &key->enckey) { 169 (void) fprintf(io->res, 170 "WARNING: signature for %s made with encryption key\n", 171 (f) ? f : "<stdin>"); 172 } 173 __ops_print_keydata(io, ring, key, "signature ", &key->key.pubkey, 0); 174 } 175} 176 177/* check there's enough space in the arrays */ 178static int 179size_arrays(netpgp_t *netpgp, unsigned needed) 180{ 181 char **temp; 182 183 if (netpgp->size == 0) { 184 /* only get here first time around */ 185 netpgp->size = needed; 186 if ((netpgp->name = calloc(sizeof(char *), needed)) == NULL) { 187 (void) fprintf(stderr, "size_arrays: bad alloc\n"); 188 return 0; 189 } 190 if ((netpgp->value = calloc(sizeof(char *), needed)) == NULL) { 191 free(netpgp->name); 192 (void) fprintf(stderr, "size_arrays: bad alloc\n"); 193 return 0; 194 } 195 } else if (netpgp->c == netpgp->size) { 196 /* only uses 'needed' when filled array */ 197 netpgp->size += needed; 198 temp = realloc(netpgp->name, sizeof(char *) * needed); 199 if (temp == NULL) { 200 (void) fprintf(stderr, "size_arrays: bad alloc\n"); 201 return 0; 202 } 203 netpgp->name = temp; 204 temp = realloc(netpgp->value, sizeof(char *) * needed); 205 if (temp == NULL) { 206 (void) fprintf(stderr, "size_arrays: bad alloc\n"); 207 return 0; 208 } 209 netpgp->value = temp; 210 } 211 return 1; 212} 213 214/* find the name in the array */ 215static int 216findvar(netpgp_t *netpgp, const char *name) 217{ 218 unsigned i; 219 220 for (i = 0 ; i < netpgp->c && strcmp(netpgp->name[i], name) != 0; i++) { 221 } 222 return (i == netpgp->c) ? -1 : (int)i; 223} 224 225/* read a keyring and return it */ 226static void * 227readkeyring(netpgp_t *netpgp, const char *name) 228{ 229 __ops_keyring_t *keyring; 230 const unsigned noarmor = 0; 231 char f[MAXPATHLEN]; 232 char *filename; 233 char *homedir; 234 235 homedir = netpgp_getvar(netpgp, "homedir"); 236 if ((filename = netpgp_getvar(netpgp, name)) == NULL) { 237 (void) snprintf(f, sizeof(f), "%s/%s.gpg", homedir, name); 238 filename = f; 239 } 240 if ((keyring = calloc(1, sizeof(*keyring))) == NULL) { 241 (void) fprintf(stderr, "readkeyring: bad alloc\n"); 242 return NULL; 243 } 244 if (!__ops_keyring_fileread(keyring, noarmor, filename)) { 245 free(keyring); 246 (void) fprintf(stderr, "Can't read %s %s\n", name, filename); 247 return NULL; 248 } 249 netpgp_setvar(netpgp, name, filename); 250 return keyring; 251} 252 253/* read keys from ssh key files */ 254static int 255readsshkeys(netpgp_t *netpgp, char *homedir, const char *needseckey) 256{ 257 __ops_keyring_t *pubring; 258 __ops_keyring_t *secring; 259 unsigned hashtype; 260 char *hash; 261 char f[MAXPATHLEN]; 262 char *filename; 263 264 if ((filename = netpgp_getvar(netpgp, "sshkeyfile")) == NULL) { 265 (void) snprintf(f, sizeof(f), "%s/id_rsa.pub", homedir); 266 filename = f; 267 } 268 if ((pubring = calloc(1, sizeof(*pubring))) == NULL) { 269 (void) fprintf(stderr, "readsshkeys: bad alloc\n"); 270 return 0; 271 } 272 /* openssh2 keys use md5 by default */ 273 hashtype = OPS_HASH_MD5; 274 if ((hash = netpgp_getvar(netpgp, "hash")) != NULL) { 275 /* openssh 2 hasn't really caught up to anything else yet */ 276 if (netpgp_strcasecmp(hash, "md5") == 0) { 277 hashtype = OPS_HASH_MD5; 278 } else if (netpgp_strcasecmp(hash, "sha1") == 0) { 279 hashtype = OPS_HASH_SHA1; 280 } else if (netpgp_strcasecmp(hash, "sha256") == 0) { 281 hashtype = OPS_HASH_SHA256; 282 } 283 } 284 if (!__ops_ssh2_readkeys(netpgp->io, pubring, NULL, filename, NULL, hashtype)) { 285 free(pubring); 286 (void) fprintf(stderr, "readsshkeys: can't read %s\n", 287 filename); 288 return 0; 289 } 290 if (netpgp->pubring == NULL) { 291 netpgp->pubring = pubring; 292 } else { 293 __ops_append_keyring(netpgp->pubring, pubring); 294 } 295 if (needseckey) { 296 netpgp_setvar(netpgp, "sshpubfile", filename); 297 /* try to take the ".pub" off the end */ 298 if (filename == f) { 299 f[strlen(f) - 4] = 0x0; 300 } else { 301 (void) snprintf(f, sizeof(f), "%.*s", 302 (int)strlen(filename) - 4, filename); 303 filename = f; 304 } 305 if ((secring = calloc(1, sizeof(*secring))) == NULL) { 306 (void) fprintf(stderr, "readsshkeys: bad alloc\n"); 307 return 0; 308 } 309 if (!__ops_ssh2_readkeys(netpgp->io, pubring, secring, NULL, filename, hashtype)) { 310 (void) fprintf(stderr, "readsshkeys: can't read sec %s\n", filename); 311 return 0; 312 } 313 netpgp->secring = secring; 314 netpgp_setvar(netpgp, "sshsecfile", filename); 315 } 316 return 1; 317} 318 319/* set ssh uid to first one in pubring */ 320static void 321set_first_pubring(__ops_keyring_t *pubring, char *id, size_t len, int last) 322{ 323 uint8_t *src; 324 int i; 325 int n; 326 327 (void) memset(id, 0x0, len); 328 src = pubring->keys[(last) ? pubring->keyc - 1 : 0].sigid; 329 for (i = 0, n = 0 ; i < OPS_KEY_ID_SIZE ; i += 2) { 330 n += snprintf(&id[n], len - n, "%02x%02x", src[i], src[i + 1]); 331 } 332 id[n] = 0x0; 333} 334 335/* find the time - in a specific %Y-%m-%d format - using a regexp */ 336static int 337grabdate(char *s, int64_t *t) 338{ 339 static regex_t r; 340 static int compiled; 341 regmatch_t matches[10]; 342 struct tm tm; 343 344 if (!compiled) { 345 compiled = 1; 346 (void) regcomp(&r, "([0-9][0-9][0-9][0-9])[-/]([0-9][0-9])[-/]([0-9][0-9])", REG_EXTENDED); 347 } 348 if (regexec(&r, s, 10, matches, 0) == 0) { 349 (void) memset(&tm, 0x0, sizeof(tm)); 350 tm.tm_year = (int)strtol(&s[(int)matches[1].rm_so], NULL, 10); 351 tm.tm_mon = (int)strtol(&s[(int)matches[2].rm_so], NULL, 10) - 1; 352 tm.tm_mday = (int)strtol(&s[(int)matches[3].rm_so], NULL, 10); 353 *t = mktime(&tm); 354 return 1; 355 } 356 return 0; 357} 358 359/* get expiration in seconds */ 360static uint64_t 361get_duration(char *s) 362{ 363 uint64_t now; 364 int64_t t; 365 char *mult; 366 367 if (s == NULL) { 368 return 0; 369 } 370 now = (uint64_t)strtoull(s, NULL, 10); 371 if ((mult = strchr("hdwmy", s[strlen(s) - 1])) != NULL) { 372 switch(*mult) { 373 case 'h': 374 return now * 60 * 60; 375 case 'd': 376 return now * 60 * 60 * 24; 377 case 'w': 378 return now * 60 * 60 * 24 * 7; 379 case 'm': 380 return now * 60 * 60 * 24 * 31; 381 case 'y': 382 return now * 60 * 60 * 24 * 365; 383 } 384 } 385 if (grabdate(s, &t)) { 386 return t; 387 } 388 return (uint64_t)strtoll(s, NULL, 10); 389} 390 391/* get birthtime in seconds */ 392static int64_t 393get_birthtime(char *s) 394{ 395 int64_t t; 396 397 if (s == NULL) { 398 return time(NULL); 399 } 400 if (grabdate(s, &t)) { 401 return t; 402 } 403 return (uint64_t)strtoll(s, NULL, 10); 404} 405 406/* resolve the userid */ 407static const __ops_key_t * 408resolve_userid(netpgp_t *netpgp, const __ops_keyring_t *keyring, const char *userid) 409{ 410 const __ops_key_t *key; 411 __ops_io_t *io; 412 413 if (userid == NULL) { 414 userid = netpgp_getvar(netpgp, "userid"); 415 } else if (userid[0] == '0' && userid[1] == 'x') { 416 userid += 2; 417 } 418 io = netpgp->io; 419 if ((key = __ops_getkeybyname(io, keyring, userid)) == NULL) { 420 (void) fprintf(io->errs, "Can't find key '%s'\n", userid); 421 } 422 return key; 423} 424 425/* append a key to a keyring */ 426static int 427appendkey(__ops_io_t *io, __ops_key_t *key, char *ringfile) 428{ 429 __ops_output_t *create; 430 const unsigned noarmor = 0; 431 int fd; 432 433 if ((fd = __ops_setup_file_append(&create, ringfile)) < 0) { 434 fd = __ops_setup_file_write(&create, ringfile, 0); 435 } 436 if (fd < 0) { 437 (void) fprintf(io->errs, "can't open pubring '%s'\n", ringfile); 438 return 0; 439 } 440 if (!__ops_write_xfer_pubkey(create, key, noarmor)) { 441 (void) fprintf(io->errs, "Cannot write pubkey\n"); 442 return 0; 443 } 444 __ops_teardown_file_write(create, fd); 445 return 1; 446} 447 448/* return 1 if the file contains ascii-armoured text */ 449static unsigned 450isarmoured(__ops_io_t *io, const char *f, const void *memory, const char *text) 451{ 452 unsigned armoured; 453 FILE *fp; 454 char buf[BUFSIZ]; 455 456 armoured = 0; 457 if (f) { 458 if ((fp = fopen(f, "r")) == NULL) { 459 (void) fprintf(io->errs, "isarmoured: can't open '%s'\n", f); 460 return 0; 461 } 462 if (fgets(buf, (int)sizeof(buf), fp) != NULL) { 463 armoured = (strncmp(buf, text, strlen(text)) == 0); 464 } 465 (void) fclose(fp); 466 } else { 467 armoured = (strncmp(memory, text, strlen(text)) == 0); 468 } 469 return armoured; 470} 471 472/* vararg print function */ 473static void 474p(FILE *fp, const char *s, ...) 475{ 476 va_list args; 477 478 va_start(args, s); 479 while (s != NULL) { 480 (void) fprintf(fp, "%s", s); 481 s = va_arg(args, char *); 482 } 483 va_end(args); 484} 485 486/* print a JSON object to the FILE stream */ 487static void 488pobj(FILE *fp, mj_t *obj, int depth) 489{ 490 unsigned i; 491 492 if (obj == NULL) { 493 (void) fprintf(stderr, "No object found\n"); 494 return; 495 } 496 for (i = 0 ; i < (unsigned)depth ; i++) { 497 p(fp, " ", NULL); 498 } 499 switch(obj->type) { 500 case MJ_NULL: 501 case MJ_FALSE: 502 case MJ_TRUE: 503 p(fp, (obj->type == MJ_NULL) ? "null" : (obj->type == MJ_FALSE) ? "false" : "true", NULL); 504 break; 505 case MJ_NUMBER: 506 p(fp, obj->value.s, NULL); 507 break; 508 case MJ_STRING: 509 (void) fprintf(fp, "%.*s", (int)(obj->c), obj->value.s); 510 break; 511 case MJ_ARRAY: 512 for (i = 0 ; i < obj->c ; i++) { 513 pobj(fp, &obj->value.v[i], depth + 1); 514 if (i < obj->c - 1) { 515 (void) fprintf(fp, ", "); 516 } 517 } 518 (void) fprintf(fp, "\n"); 519 break; 520 case MJ_OBJECT: 521 for (i = 0 ; i < obj->c ; i += 2) { 522 pobj(fp, &obj->value.v[i], depth + 1); 523 p(fp, ": ", NULL); 524 pobj(fp, &obj->value.v[i + 1], 0); 525 if (i < obj->c - 1) { 526 p(fp, ", ", NULL); 527 } 528 } 529 p(fp, "\n", NULL); 530 break; 531 default: 532 break; 533 } 534} 535 536/* return the time as a string */ 537static char * 538ptimestr(char *dest, size_t size, time_t t) 539{ 540 struct tm *tm; 541 542 tm = gmtime(&t); 543 (void) snprintf(dest, size, "%04d-%02d-%02d", 544 tm->tm_year + 1900, 545 tm->tm_mon + 1, 546 tm->tm_mday); 547 return dest; 548} 549 550/* format a JSON object */ 551static void 552format_json_key(FILE *fp, mj_t *obj, const int psigs) 553{ 554 int64_t birthtime; 555 int64_t duration; 556 time_t now; 557 char tbuf[32]; 558 char *s; 559 mj_t *sub; 560 int i; 561 562 if (__ops_get_debug_level(__FILE__)) { 563 mj_asprint(&s, obj); 564 (void) fprintf(stderr, "formatobj: json is '%s'\n", s); 565 free(s); 566 } 567 if (obj->c == 2 && obj->value.v[1].type == MJ_STRING && 568 strcmp(obj->value.v[1].value.s, "[REVOKED]") == 0) { 569 /* whole key has been rovoked - just return */ 570 return; 571 } 572 pobj(fp, &obj->value.v[mj_object_find(obj, "header", 0, 2) + 1], 0); 573 p(fp, " ", NULL); 574 pobj(fp, &obj->value.v[mj_object_find(obj, "key bits", 0, 2) + 1], 0); 575 p(fp, "/", NULL); 576 pobj(fp, &obj->value.v[mj_object_find(obj, "pka", 0, 2) + 1], 0); 577 p(fp, " ", NULL); 578 pobj(fp, &obj->value.v[mj_object_find(obj, "key id", 0, 2) + 1], 0); 579 birthtime = strtoll(obj->value.v[mj_object_find(obj, "birthtime", 0, 2) + 1].value.s, NULL, 10); 580 p(fp, " ", ptimestr(tbuf, sizeof(tbuf), birthtime), NULL); 581 duration = strtoll(obj->value.v[mj_object_find(obj, "duration", 0, 2) + 1].value.s, NULL, 10); 582 if (duration > 0) { 583 now = time(NULL); 584 p(fp, " ", (birthtime + duration < now) ? "[EXPIRED " : "[EXPIRES ", 585 ptimestr(tbuf, sizeof(tbuf), birthtime + duration), "]", NULL); 586 } 587 p(fp, "\n", "Key fingerprint: ", NULL); 588 pobj(fp, &obj->value.v[mj_object_find(obj, "fingerprint", 0, 2) + 1], 0); 589 p(fp, "\n", NULL); 590 /* go to field after \"duration\" */ 591 for (i = mj_object_find(obj, "duration", 0, 2) + 2; i < mj_arraycount(obj) ; i += 2) { 592 if (strcmp(obj->value.v[i].value.s, "uid") == 0) { 593 sub = &obj->value.v[i + 1]; 594 p(fp, "uid", NULL); 595 pobj(fp, &sub->value.v[0], (psigs) ? 4 : 14); /* human name */ 596 pobj(fp, &sub->value.v[1], 1); /* any revocation */ 597 p(fp, "\n", NULL); 598 } else if (strcmp(obj->value.v[i].value.s, "encryption") == 0) { 599 sub = &obj->value.v[i + 1]; 600 p(fp, "encryption", NULL); 601 pobj(fp, &sub->value.v[0], 1); /* size */ 602 p(fp, "/", NULL); 603 pobj(fp, &sub->value.v[1], 0); /* alg */ 604 p(fp, " ", NULL); 605 pobj(fp, &sub->value.v[2], 0); /* id */ 606 p(fp, " ", ptimestr(tbuf, sizeof(tbuf), strtoll(sub->value.v[3].value.s, NULL, 10)), 607 "\n", NULL); 608 } else if (strcmp(obj->value.v[i].value.s, "sig") == 0) { 609 sub = &obj->value.v[i + 1]; 610 p(fp, "sig", NULL); 611 pobj(fp, &sub->value.v[0], 8); /* size */ 612 p(fp, " ", ptimestr(tbuf, sizeof(tbuf), strtoll(sub->value.v[1].value.s, NULL, 10)), 613 " ", NULL); /* time */ 614 pobj(fp, &sub->value.v[2], 0); /* human name */ 615 p(fp, "\n", NULL); 616 } else { 617 fprintf(stderr, "weird '%s'\n", obj->value.v[i].value.s); 618 pobj(fp, &obj->value.v[i], 0); /* human name */ 619 } 620 } 621 p(fp, "\n", NULL); 622} 623 624/***************************************************************************/ 625/* exported functions start here */ 626/***************************************************************************/ 627 628/* initialise a netpgp_t structure */ 629int 630netpgp_init(netpgp_t *netpgp) 631{ 632 __ops_io_t *io; 633 char id[MAX_ID_LENGTH]; 634 char *homedir; 635 char *userid; 636 char *stream; 637 char *passfd; 638 char *results; 639 int coredumps; 640 int last; 641 642#ifdef HAVE_SYS_RESOURCE_H 643 struct rlimit limit; 644 645 coredumps = netpgp_getvar(netpgp, "coredumps") != NULL; 646 if (!coredumps) { 647 (void) memset(&limit, 0x0, sizeof(limit)); 648 if (setrlimit(RLIMIT_CORE, &limit) != 0) { 649 (void) fprintf(stderr, 650 "netpgp: warning - can't turn off core dumps\n"); 651 coredumps = 1; 652 } 653 } 654#else 655 coredumps = 1; 656#endif 657 if ((io = calloc(1, sizeof(*io))) == NULL) { 658 (void) fprintf(stderr, "netpgp_init: bad alloc\n"); 659 return 0; 660 } 661 io->outs = stdout; 662 if ((stream = netpgp_getvar(netpgp, "outs")) != NULL && 663 strcmp(stream, "<stderr>") == 0) { 664 io->outs = stderr; 665 } 666 io->errs = stderr; 667 if ((stream = netpgp_getvar(netpgp, "errs")) != NULL && 668 strcmp(stream, "<stdout>") == 0) { 669 io->errs = stdout; 670 } 671 if ((results = netpgp_getvar(netpgp, "res")) == NULL) { 672 io->res = io->errs; 673 } else if (strcmp(results, "<stdout>") == 0) { 674 io->res = stdout; 675 } else if (strcmp(results, "<stderr>") == 0) { 676 io->res = stderr; 677 } else { 678 if ((io->res = fopen(results, "w")) == NULL) { 679 (void) fprintf(io->errs, "Can't open results %s for writing\n", 680 results); 681 free(io); 682 return 0; 683 } 684 } 685 netpgp->io = io; 686 if ((passfd = netpgp_getvar(netpgp, "pass-fd")) != NULL && 687 (netpgp->passfp = fdopen(atoi(passfd), "r")) == NULL) { 688 (void) fprintf(io->errs, "Can't open fd %s for reading\n", 689 passfd); 690 return 0; 691 } 692 if (coredumps) { 693 (void) fprintf(io->errs, 694 "netpgp: warning: core dumps enabled\n"); 695 } 696 if ((homedir = netpgp_getvar(netpgp, "homedir")) == NULL) { 697 (void) fprintf(io->errs, "netpgp: bad homedir\n"); 698 return 0; 699 } 700 /* read from either gpg files or ssh keys */ 701 if (netpgp_getvar(netpgp, "ssh keys") == NULL) { 702 if ((userid = netpgp_getvar(netpgp, "userid")) == NULL) { 703 (void) memset(id, 0x0, sizeof(id)); 704 (void) conffile(netpgp, homedir, id, sizeof(id)); 705 if (id[0] != 0x0) { 706 netpgp_setvar(netpgp, "userid", userid = id); 707 } 708 } 709 if (userid == NULL) { 710 if (netpgp_getvar(netpgp, "need userid") != NULL) { 711 (void) fprintf(io->errs, 712 "Cannot find user id\n"); 713 return 0; 714 } 715 } else { 716 (void) netpgp_setvar(netpgp, "userid", userid); 717 } 718 netpgp->pubring = readkeyring(netpgp, "pubring"); 719 if (netpgp->pubring == NULL) { 720 (void) fprintf(io->errs, "Can't read pub keyring\n"); 721 return 0; 722 } 723 netpgp->secring = readkeyring(netpgp, "secring"); 724 if (netpgp->secring == NULL) { 725 (void) fprintf(io->errs, "Can't read sec keyring\n"); 726 return 0; 727 } 728 } else { 729 last = (netpgp->pubring != NULL); 730 if (!readsshkeys(netpgp, homedir, netpgp_getvar(netpgp, "need seckey"))) { 731 (void) fprintf(io->errs, "Can't read ssh keys\n"); 732 return 0; 733 } 734 if ((userid = netpgp_getvar(netpgp, "userid")) == NULL) { 735 set_first_pubring(netpgp->pubring, id, sizeof(id), last); 736 netpgp_setvar(netpgp, "userid", userid = id); 737 } 738 if (userid == NULL) { 739 if (netpgp_getvar(netpgp, "need userid") != NULL) { 740 (void) fprintf(io->errs, 741 "Cannot find user id\n"); 742 return 0; 743 } 744 } else { 745 (void) netpgp_setvar(netpgp, "userid", userid); 746 } 747 } 748 return 1; 749} 750 751/* finish off with the netpgp_t struct */ 752int 753netpgp_end(netpgp_t *netpgp) 754{ 755 unsigned i; 756 757 for (i = 0 ; i < netpgp->c ; i++) { 758 if (netpgp->name[i] != NULL) { 759 free(netpgp->name[i]); 760 } 761 if (netpgp->value[i] != NULL) { 762 free(netpgp->value[i]); 763 } 764 } 765 if (netpgp->name != NULL) { 766 free(netpgp->name); 767 } 768 if (netpgp->value != NULL) { 769 free(netpgp->value); 770 } 771 if (netpgp->pubring != NULL) { 772 __ops_keyring_free(netpgp->pubring); 773 } 774 if (netpgp->secring != NULL) { 775 __ops_keyring_free(netpgp->secring); 776 } 777 free(netpgp->io); 778 return 1; 779} 780 781/* list the keys in a keyring */ 782int 783netpgp_list_keys(netpgp_t *netpgp, const int psigs) 784{ 785 if (netpgp->pubring == NULL) { 786 (void) fprintf(stderr, "No keyring\n"); 787 return 0; 788 } 789 return __ops_keyring_list(netpgp->io, netpgp->pubring, psigs); 790} 791 792/* list the keys in a keyring, returning a JSON string */ 793int 794netpgp_list_keys_json(netpgp_t *netpgp, char **json, const int psigs) 795{ 796 mj_t obj; 797 int ret; 798 799 if (netpgp->pubring == NULL) { 800 (void) fprintf(stderr, "No keyring\n"); 801 return 0; 802 } 803 (void) memset(&obj, 0x0, sizeof(obj)); 804 if (!__ops_keyring_json(netpgp->io, netpgp->pubring, &obj, psigs)) { 805 (void) fprintf(stderr, "No keys in keyring\n"); 806 return 0; 807 } 808 ret = mj_asprint(json, &obj); 809 mj_delete(&obj); 810 return ret; 811} 812 813DEFINE_ARRAY(strings_t, char *); 814 815#ifndef HKP_VERSION 816#define HKP_VERSION 1 817#endif 818 819/* find and list some keys in a keyring */ 820int 821netpgp_match_keys(netpgp_t *netpgp, char *name, const char *fmt, void *vp, const int psigs) 822{ 823 const __ops_key_t *key; 824 unsigned k; 825 strings_t pubs; 826 FILE *fp = (FILE *)vp; 827 828 if (name[0] == '0' && name[1] == 'x') { 829 name += 2; 830 } 831 (void) memset(&pubs, 0x0, sizeof(pubs)); 832 k = 0; 833 do { 834 key = __ops_getnextkeybyname(netpgp->io, netpgp->pubring, 835 name, &k); 836 if (key != NULL) { 837 ALLOC(char *, pubs.v, pubs.size, pubs.c, 10, 10, 838 "netpgp_match_keys", return 0); 839 if (strcmp(fmt, "mr") == 0) { 840 __ops_hkp_sprint_keydata(netpgp->io, netpgp->pubring, 841 key, &pubs.v[pubs.c], 842 &key->key.pubkey, psigs); 843 } else { 844 __ops_sprint_keydata(netpgp->io, netpgp->pubring, 845 key, &pubs.v[pubs.c], 846 "signature ", 847 &key->key.pubkey, psigs); 848 } 849 if (pubs.v[pubs.c] != NULL) { 850 pubs.c += 1; 851 } 852 k += 1; 853 } 854 } while (key != NULL); 855 if (strcmp(fmt, "mr") == 0) { 856 (void) fprintf(fp, "info:%d:%d\n", HKP_VERSION, pubs.c); 857 } else { 858 (void) fprintf(fp, "%d key%s found\n", pubs.c, 859 (pubs.c == 1) ? "" : "s"); 860 } 861 for (k = 0 ; k < pubs.c ; k++) { 862 (void) fprintf(fp, "%s%s", pubs.v[k], (k < pubs.c - 1) ? "\n" : ""); 863 free(pubs.v[k]); 864 } 865 free(pubs.v); 866 return pubs.c; 867} 868 869/* find and list some keys in a keyring - return JSON string */ 870int 871netpgp_match_keys_json(netpgp_t *netpgp, char **json, char *name, const char *fmt, const int psigs) 872{ 873 const __ops_key_t *key; 874 unsigned k; 875 mj_t id_array; 876 int ret; 877 878 if (name[0] == '0' && name[1] == 'x') { 879 name += 2; 880 } 881 (void) memset(&id_array, 0x0, sizeof(id_array)); 882 k = 0; 883 *json = NULL; 884 mj_create(&id_array, "array"); 885 do { 886 key = __ops_getnextkeybyname(netpgp->io, netpgp->pubring, 887 name, &k); 888 if (key != NULL) { 889 if (strcmp(fmt, "mr") == 0) { 890#if 0 891 __ops_hkp_sprint_keydata(netpgp->io, netpgp->pubring, 892 key, &pubs.v[pubs.c], 893 &key->key.pubkey, psigs); 894#endif 895 } else { 896 ALLOC(mj_t, id_array.value.v, id_array.size, 897 id_array.c, 10, 10, "netpgp_match_keys_json", return 0); 898 __ops_sprint_mj(netpgp->io, netpgp->pubring, 899 key, &id_array.value.v[id_array.c++], 900 "signature ", 901 &key->key.pubkey, psigs); 902 } 903 k += 1; 904 } 905 } while (key != NULL); 906 ret = mj_asprint(json, &id_array); 907 mj_delete(&id_array); 908 return ret; 909} 910 911/* find and list some public keys in a keyring */ 912int 913netpgp_match_pubkeys(netpgp_t *netpgp, char *name, void *vp) 914{ 915 const __ops_key_t *key; 916 unsigned k; 917 strings_t pubs; 918 FILE *fp = (FILE *)vp; 919 920 (void) memset(&pubs, 0x0, sizeof(pubs)); 921 do { 922 key = __ops_getnextkeybyname(netpgp->io, netpgp->pubring, 923 name, &k); 924 if (key != NULL) { 925 char out[1024 * 64]; 926 927 ALLOC(char *, pubs.v, pubs.size, pubs.c, 10, 10, 928 "netpgp_match_pubkeys", return 0); 929 (void) __ops_sprint_pubkey(key, out, sizeof(out)); 930 pubs.v[pubs.c++] = netpgp_strdup(out); 931 k += 1; 932 } 933 } while (key != NULL); 934 (void) fprintf(fp, "info:%d:%d\n", HKP_VERSION, pubs.c); 935 for (k = 0 ; k < pubs.c ; k++) { 936 (void) fprintf(fp, "%s", pubs.v[k]); 937 free(pubs.v[k]); 938 } 939 free(pubs.v); 940 return pubs.c; 941} 942 943/* find a key in a keyring */ 944int 945netpgp_find_key(netpgp_t *netpgp, char *id) 946{ 947 __ops_io_t *io; 948 949 io = netpgp->io; 950 if (id == NULL) { 951 (void) fprintf(io->errs, "NULL id to search for\n"); 952 return 0; 953 } 954 return __ops_getkeybyname(netpgp->io, netpgp->pubring, id) != NULL; 955} 956 957/* get a key in a keyring */ 958char * 959netpgp_get_key(netpgp_t *netpgp, const char *name, const char *fmt) 960{ 961 const __ops_key_t *key; 962 char *newkey; 963 964 if ((key = resolve_userid(netpgp, netpgp->pubring, name)) == NULL) { 965 return NULL; 966 } 967 if (strcmp(fmt, "mr") == 0) { 968 return (__ops_hkp_sprint_keydata(netpgp->io, netpgp->pubring, 969 key, &newkey, 970 &key->key.pubkey, 971 netpgp_getvar(netpgp, "subkey sigs") != NULL) > 0) ? newkey : NULL; 972 } 973 return (__ops_sprint_keydata(netpgp->io, netpgp->pubring, 974 key, &newkey, "signature", 975 &key->key.pubkey, 976 netpgp_getvar(netpgp, "subkey sigs") != NULL) > 0) ? newkey : NULL; 977} 978 979/* export a given key */ 980char * 981netpgp_export_key(netpgp_t *netpgp, char *name) 982{ 983 const __ops_key_t *key; 984 __ops_io_t *io; 985 986 io = netpgp->io; 987 if ((key = resolve_userid(netpgp, netpgp->pubring, name)) == NULL) { 988 return NULL; 989 } 990 return __ops_export_key(io, key, NULL); 991} 992 993#define IMPORT_ARMOR_HEAD "-----BEGIN PGP PUBLIC KEY BLOCK-----" 994 995/* import a key into our keyring */ 996int 997netpgp_import_key(netpgp_t *netpgp, char *f) 998{ 999 __ops_io_t *io; 1000 unsigned realarmor; 1001 int done; 1002 1003 io = netpgp->io; 1004 realarmor = isarmoured(io, f, NULL, IMPORT_ARMOR_HEAD); 1005 done = __ops_keyring_fileread(netpgp->pubring, realarmor, f); 1006 if (!done) { 1007 (void) fprintf(io->errs, "Cannot import key from file %s\n", f); 1008 return 0; 1009 } 1010 return __ops_keyring_list(io, netpgp->pubring, 0); 1011} 1012 1013/* generate a new key */ 1014int 1015netpgp_generate_key(netpgp_t *netpgp, char *id, int numbits) 1016{ 1017 __ops_output_t *create; 1018 const unsigned noarmor = 0; 1019 __ops_key_t *key; 1020 __ops_io_t *io; 1021 uint8_t *uid; 1022 char newid[1024]; 1023 char filename[MAXPATHLEN]; 1024 char dir[MAXPATHLEN]; 1025 char *cp; 1026 char *ringfile; 1027 int fd; 1028 1029 uid = NULL; 1030 io = netpgp->io; 1031 /* generate a new key */ 1032 if (id) { 1033 (void) snprintf(newid, sizeof(newid), "%s", id); 1034 } else { 1035 (void) snprintf(newid, sizeof(newid), "RSA %d-bit key <%s@localhost>", numbits, getenv("LOGNAME")); 1036 } 1037 uid = (uint8_t *)newid; 1038 key = __ops_rsa_new_selfsign_key(numbits, 65537UL, uid, netpgp_getvar(netpgp, "hash")); 1039 if (key == NULL) { 1040 (void) fprintf(io->errs, "Cannot generate key\n"); 1041 return 0; 1042 } 1043 cp = NULL; 1044 __ops_sprint_keydata(netpgp->io, NULL, key, &cp, "signature ", &key->key.seckey.pubkey, 0); 1045 (void) fprintf(stdout, "%s", cp); 1046 /* write public key */ 1047 (void) snprintf(dir, sizeof(dir), "%s/%.16s", netpgp_getvar(netpgp, "homedir"), &cp[31]); 1048 if (mkdir(dir, 0700) < 0) { 1049 (void) fprintf(io->errs, "can't mkdir '%s'\n", dir); 1050 return 0; 1051 } 1052 (void) fprintf(io->errs, "netpgp: generated keys in directory %s\n", dir); 1053 (void) snprintf(ringfile = filename, sizeof(filename), "%s/pubring.gpg", dir); 1054 if (!appendkey(io, key, ringfile)) { 1055 (void) fprintf(io->errs, "Cannot write pubkey to '%s'\n", ringfile); 1056 return 0; 1057 } 1058 if (netpgp->pubring != NULL) { 1059 __ops_keyring_free(netpgp->pubring); 1060 } 1061 /* write secret key */ 1062 (void) snprintf(ringfile = filename, sizeof(filename), "%s/secring.gpg", dir); 1063 if ((fd = __ops_setup_file_append(&create, ringfile)) < 0) { 1064 fd = __ops_setup_file_write(&create, ringfile, 0); 1065 } 1066 if (fd < 0) { 1067 (void) fprintf(io->errs, "can't append secring '%s'\n", ringfile); 1068 return 0; 1069 } 1070 if (!__ops_write_xfer_seckey(create, key, NULL, 0, noarmor)) { 1071 (void) fprintf(io->errs, "Cannot write seckey\n"); 1072 return 0; 1073 } 1074 __ops_teardown_file_write(create, fd); 1075 if (netpgp->secring != NULL) { 1076 __ops_keyring_free(netpgp->secring); 1077 } 1078 __ops_keydata_free(key); 1079 free(cp); 1080 return 1; 1081} 1082 1083/* encrypt a file */ 1084int 1085netpgp_encrypt_file(netpgp_t *netpgp, 1086 const char *userid, 1087 const char *f, 1088 char *out, 1089 int armored) 1090{ 1091 const __ops_key_t *key; 1092 const unsigned overwrite = 1; 1093 const char *suffix; 1094 __ops_io_t *io; 1095 char outname[MAXPATHLEN]; 1096 1097 io = netpgp->io; 1098 if (f == NULL) { 1099 (void) fprintf(io->errs, 1100 "netpgp_encrypt_file: no filename specified\n"); 1101 return 0; 1102 } 1103 suffix = (armored) ? ".asc" : ".gpg"; 1104 /* get key with which to sign */ 1105 if ((key = resolve_userid(netpgp, netpgp->pubring, userid)) == NULL) { 1106 return 0; 1107 } 1108 if (out == NULL) { 1109 (void) snprintf(outname, sizeof(outname), "%s%s", f, suffix); 1110 out = outname; 1111 } 1112 return (int)__ops_encrypt_file(io, f, out, key, (unsigned)armored, 1113 overwrite); 1114} 1115 1116#define ARMOR_HEAD "-----BEGIN PGP MESSAGE-----" 1117 1118/* decrypt a file */ 1119int 1120netpgp_decrypt_file(netpgp_t *netpgp, const char *f, char *out, int armored) 1121{ 1122 const unsigned overwrite = 1; 1123 __ops_io_t *io; 1124 unsigned realarmor; 1125 1126 __OPS_USED(armored); 1127 io = netpgp->io; 1128 if (f == NULL) { 1129 (void) fprintf(io->errs, 1130 "netpgp_decrypt_file: no filename specified\n"); 1131 return 0; 1132 } 1133 realarmor = isarmoured(io, f, NULL, ARMOR_HEAD); 1134 return __ops_decrypt_file(netpgp->io, f, out, netpgp->secring, 1135 netpgp->pubring, 1136 realarmor, overwrite, 1137 netpgp->passfp, get_passphrase_cb); 1138} 1139 1140/* sign a file */ 1141int 1142netpgp_sign_file(netpgp_t *netpgp, 1143 const char *userid, 1144 const char *f, 1145 char *out, 1146 int armored, 1147 int cleartext, 1148 int detached) 1149{ 1150 const __ops_key_t *keypair; 1151 const __ops_key_t *pubkey; 1152 __ops_seckey_t *seckey; 1153 const unsigned overwrite = 1; 1154 __ops_io_t *io; 1155 const char *hashalg; 1156 int ret; 1157 1158 io = netpgp->io; 1159 if (f == NULL) { 1160 (void) fprintf(io->errs, 1161 "netpgp_sign_file: no filename specified\n"); 1162 return 0; 1163 } 1164 /* get key with which to sign */ 1165 if ((keypair = resolve_userid(netpgp, netpgp->secring, userid)) == NULL) { 1166 return 0; 1167 } 1168 ret = 1; 1169 do { 1170 if (netpgp->passfp == NULL) { 1171 /* print out the user id */ 1172 pubkey = __ops_getkeybyname(io, netpgp->pubring, userid); 1173 if (pubkey == NULL) { 1174 (void) fprintf(io->errs, 1175 "netpgp: warning - using pubkey from secring\n"); 1176 __ops_print_keydata(io, netpgp->pubring, keypair, "signature ", 1177 &keypair->key.seckey.pubkey, 0); 1178 } else { 1179 __ops_print_keydata(io, netpgp->pubring, pubkey, "signature ", 1180 &pubkey->key.pubkey, 0); 1181 } 1182 } 1183 if (netpgp_getvar(netpgp, "ssh keys") == NULL) { 1184 /* now decrypt key */ 1185 seckey = __ops_decrypt_seckey(keypair, netpgp->passfp); 1186 if (seckey == NULL) { 1187 (void) fprintf(io->errs, "Bad passphrase\n"); 1188 } 1189 } else { 1190 __ops_keyring_t *secring; 1191 1192 secring = netpgp->secring; 1193 seckey = &secring->keys[0].key.seckey; 1194 } 1195 } while (seckey == NULL); 1196 /* sign file */ 1197 hashalg = netpgp_getvar(netpgp, "hash"); 1198 if (seckey->pubkey.alg == OPS_PKA_DSA) { 1199 hashalg = "sha1"; 1200 } 1201 if (detached) { 1202 ret = __ops_sign_detached(io, f, out, seckey, hashalg, 1203 get_birthtime(netpgp_getvar(netpgp, "birthtime")), 1204 get_duration(netpgp_getvar(netpgp, "duration")), 1205 (unsigned)armored, 1206 overwrite); 1207 } else { 1208 ret = __ops_sign_file(io, f, out, seckey, hashalg, 1209 get_birthtime(netpgp_getvar(netpgp, "birthtime")), 1210 get_duration(netpgp_getvar(netpgp, "duration")), 1211 (unsigned)armored, (unsigned)cleartext, 1212 overwrite); 1213 } 1214 __ops_forget(seckey, (unsigned)sizeof(*seckey)); 1215 return ret; 1216} 1217 1218#define ARMOR_SIG_HEAD "-----BEGIN PGP SIGNATURE-----\r\n" 1219 1220/* verify a file */ 1221int 1222netpgp_verify_file(netpgp_t *netpgp, const char *in, const char *out, int armored) 1223{ 1224 __ops_validation_t result; 1225 __ops_io_t *io; 1226 unsigned realarmor; 1227 1228 __OPS_USED(armored); 1229 (void) memset(&result, 0x0, sizeof(result)); 1230 io = netpgp->io; 1231 if (in == NULL) { 1232 (void) fprintf(io->errs, 1233 "netpgp_verify_file: no filename specified\n"); 1234 return 0; 1235 } 1236 realarmor = isarmoured(io, in, NULL, ARMOR_SIG_HEAD); 1237 if (__ops_validate_file(io, &result, in, out, (const int)realarmor, netpgp->pubring)) { 1238 resultp(io, in, &result, netpgp->pubring); 1239 return 1; 1240 } 1241 if (result.validc + result.invalidc + result.unknownc == 0) { 1242 (void) fprintf(io->errs, 1243 "\"%s\": No signatures found - is this a signed file?\n", 1244 in); 1245 } else if (result.invalidc == 0 && result.unknownc == 0) { 1246 (void) fprintf(io->errs, 1247 "\"%s\": file verification failure: invalid signature time\n", in); 1248 } else { 1249 (void) fprintf(io->errs, 1250"\"%s\": verification failure: %u invalid signatures, %u unknown signatures\n", 1251 in, result.invalidc, result.unknownc); 1252 } 1253 return 0; 1254} 1255 1256/* sign some memory */ 1257int 1258netpgp_sign_memory(netpgp_t *netpgp, 1259 const char *userid, 1260 char *mem, 1261 size_t size, 1262 char *out, 1263 size_t outsize, 1264 const unsigned armored, 1265 const unsigned cleartext) 1266{ 1267 const __ops_key_t *keypair; 1268 const __ops_key_t *pubkey; 1269 __ops_seckey_t *seckey; 1270 __ops_memory_t *signedmem; 1271 __ops_io_t *io; 1272 const char *hashalg; 1273 int ret; 1274 1275 io = netpgp->io; 1276 if (mem == NULL) { 1277 (void) fprintf(io->errs, 1278 "netpgp_sign_memory: no memory to sign\n"); 1279 return 0; 1280 } 1281 if ((keypair = resolve_userid(netpgp, netpgp->secring, userid)) == NULL) { 1282 return 0; 1283 } 1284 ret = 1; 1285 do { 1286 if (netpgp->passfp == NULL) { 1287 /* print out the user id */ 1288 pubkey = __ops_getkeybyname(io, netpgp->pubring, userid); 1289 if (pubkey == NULL) { 1290 (void) fprintf(io->errs, 1291 "netpgp: warning - using pubkey from secring\n"); 1292 __ops_print_keydata(io, netpgp->pubring, keypair, "signature ", 1293 &keypair->key.seckey.pubkey, 0); 1294 } else { 1295 __ops_print_keydata(io, netpgp->pubring, pubkey, "signature ", 1296 &pubkey->key.pubkey, 0); 1297 } 1298 } 1299 /* now decrypt key */ 1300 seckey = __ops_decrypt_seckey(keypair, netpgp->passfp); 1301 if (seckey == NULL) { 1302 (void) fprintf(io->errs, "Bad passphrase\n"); 1303 } 1304 } while (seckey == NULL); 1305 /* sign file */ 1306 (void) memset(out, 0x0, outsize); 1307 hashalg = netpgp_getvar(netpgp, "hash"); 1308 if (seckey->pubkey.alg == OPS_PKA_DSA) { 1309 hashalg = "sha1"; 1310 } 1311 signedmem = __ops_sign_buf(io, mem, size, seckey, 1312 get_birthtime(netpgp_getvar(netpgp, "birthtime")), 1313 get_duration(netpgp_getvar(netpgp, "duration")), 1314 hashalg, armored, cleartext); 1315 if (signedmem) { 1316 size_t m; 1317 1318 m = MIN(__ops_mem_len(signedmem), outsize); 1319 (void) memcpy(out, __ops_mem_data(signedmem), m); 1320 __ops_memory_free(signedmem); 1321 ret = (int)m; 1322 } else { 1323 ret = 0; 1324 } 1325 __ops_forget(seckey, (unsigned)sizeof(*seckey)); 1326 return ret; 1327} 1328 1329/* verify memory */ 1330int 1331netpgp_verify_memory(netpgp_t *netpgp, const void *in, const size_t size, 1332 void *out, size_t outsize, const int armored) 1333{ 1334 __ops_validation_t result; 1335 __ops_memory_t *signedmem; 1336 __ops_memory_t *cat; 1337 __ops_io_t *io; 1338 size_t m; 1339 int ret; 1340 1341 (void) memset(&result, 0x0, sizeof(result)); 1342 io = netpgp->io; 1343 if (in == NULL) { 1344 (void) fprintf(io->errs, 1345 "netpgp_verify_memory: no memory to verify\n"); 1346 return 0; 1347 } 1348 signedmem = __ops_memory_new(); 1349 __ops_memory_add(signedmem, in, size); 1350 if (out) { 1351 cat = __ops_memory_new(); 1352 } 1353 ret = __ops_validate_mem(io, &result, signedmem, 1354 (out) ? &cat : NULL, 1355 armored, netpgp->pubring); 1356 __ops_memory_free(signedmem); 1357 if (ret) { 1358 resultp(io, "<stdin>", &result, netpgp->pubring); 1359 if (out) { 1360 m = MIN(__ops_mem_len(cat), outsize); 1361 (void) memcpy(out, __ops_mem_data(cat), m); 1362 __ops_memory_free(cat); 1363 } else { 1364 m = 1; 1365 } 1366 return (int)m; 1367 } 1368 if (result.validc + result.invalidc + result.unknownc == 0) { 1369 (void) fprintf(io->errs, 1370 "No signatures found - is this memory signed?\n"); 1371 } else if (result.invalidc == 0 && result.unknownc == 0) { 1372 (void) fprintf(io->errs, 1373 "memory verification failure: invalid signature time\n"); 1374 } else { 1375 (void) fprintf(io->errs, 1376"memory verification failure: %u invalid signatures, %u unknown signatures\n", 1377 result.invalidc, result.unknownc); 1378 } 1379 return 0; 1380} 1381 1382/* encrypt some memory */ 1383int 1384netpgp_encrypt_memory(netpgp_t *netpgp, 1385 const char *userid, 1386 void *in, 1387 const size_t insize, 1388 char *out, 1389 size_t outsize, 1390 int armored) 1391{ 1392 const __ops_key_t *keypair; 1393 __ops_memory_t *enc; 1394 __ops_io_t *io; 1395 size_t m; 1396 1397 io = netpgp->io; 1398 if (in == NULL) { 1399 (void) fprintf(io->errs, 1400 "netpgp_encrypt_buf: no memory to encrypt\n"); 1401 return 0; 1402 } 1403 if ((keypair = resolve_userid(netpgp, netpgp->pubring, userid)) == NULL) { 1404 return 0; 1405 } 1406 if (in == out) { 1407 (void) fprintf(io->errs, 1408 "netpgp_encrypt_buf: input and output bufs need to be different\n"); 1409 return 0; 1410 } 1411 if (outsize < insize) { 1412 (void) fprintf(io->errs, 1413 "netpgp_encrypt_buf: input size is larger than output size\n"); 1414 return 0; 1415 } 1416 enc = __ops_encrypt_buf(io, in, insize, keypair, (unsigned)armored); 1417 m = MIN(__ops_mem_len(enc), outsize); 1418 (void) memcpy(out, __ops_mem_data(enc), m); 1419 __ops_memory_free(enc); 1420 return (int)m; 1421} 1422 1423/* decrypt a chunk of memory */ 1424int 1425netpgp_decrypt_memory(netpgp_t *netpgp, const void *input, const size_t insize, 1426 char *out, size_t outsize, const int armored) 1427{ 1428 __ops_memory_t *mem; 1429 __ops_io_t *io; 1430 unsigned realarmour; 1431 size_t m; 1432 1433 __OPS_USED(armored); 1434 io = netpgp->io; 1435 if (input == NULL) { 1436 (void) fprintf(io->errs, 1437 "netpgp_decrypt_memory: no memory\n"); 1438 return 0; 1439 } 1440 realarmour = isarmoured(io, NULL, input, ARMOR_HEAD); 1441 mem = __ops_decrypt_buf(netpgp->io, input, insize, netpgp->secring, 1442 netpgp->pubring, 1443 realarmour, netpgp->passfp, 1444 get_passphrase_cb); 1445 m = MIN(__ops_mem_len(mem), outsize); 1446 (void) memcpy(out, __ops_mem_data(mem), m); 1447 __ops_memory_free(mem); 1448 return (int)m; 1449} 1450 1451/* wrappers for the ops_debug_level functions we added to openpgpsdk */ 1452 1453/* set the debugging level per filename */ 1454int 1455netpgp_set_debug(const char *f) 1456{ 1457 return __ops_set_debug_level(f); 1458} 1459 1460/* get the debugging level per filename */ 1461int 1462netpgp_get_debug(const char *f) 1463{ 1464 return __ops_get_debug_level(f); 1465} 1466 1467/* return the version for the library */ 1468const char * 1469netpgp_get_info(const char *type) 1470{ 1471 return __ops_get_info(type); 1472} 1473 1474/* list all the packets in a file */ 1475int 1476netpgp_list_packets(netpgp_t *netpgp, char *f, int armor, char *pubringname) 1477{ 1478 __ops_keyring_t *keyring; 1479 const unsigned noarmor = 0; 1480 struct stat st; 1481 __ops_io_t *io; 1482 char ringname[MAXPATHLEN]; 1483 char *homedir; 1484 int ret; 1485 1486 io = netpgp->io; 1487 if (f == NULL) { 1488 (void) fprintf(io->errs, "No file containing packets\n"); 1489 return 0; 1490 } 1491 if (stat(f, &st) < 0) { 1492 (void) fprintf(io->errs, "No such file '%s'\n", f); 1493 return 0; 1494 } 1495 homedir = netpgp_getvar(netpgp, "homedir"); 1496 if (pubringname == NULL) { 1497 (void) snprintf(ringname, sizeof(ringname), 1498 "%s/pubring.gpg", homedir); 1499 pubringname = ringname; 1500 } 1501 if ((keyring = calloc(1, sizeof(*keyring))) == NULL) { 1502 (void) fprintf(io->errs, "netpgp_list_packets: bad alloc\n"); 1503 return 0; 1504 } 1505 if (!__ops_keyring_fileread(keyring, noarmor, pubringname)) { 1506 free(keyring); 1507 (void) fprintf(io->errs, "Cannot read pub keyring %s\n", 1508 pubringname); 1509 return 0; 1510 } 1511 netpgp->pubring = keyring; 1512 netpgp_setvar(netpgp, "pubring", pubringname); 1513 ret = __ops_list_packets(io, f, (unsigned)armor, 1514 netpgp->secring, 1515 netpgp->pubring, 1516 netpgp->passfp, 1517 get_passphrase_cb); 1518 free(keyring); 1519 return ret; 1520} 1521 1522/* set a variable */ 1523int 1524netpgp_setvar(netpgp_t *netpgp, const char *name, const char *value) 1525{ 1526 char *newval; 1527 int i; 1528 1529 /* protect against the case where 'value' is netpgp->value[i] */ 1530 newval = netpgp_strdup(value); 1531 if ((i = findvar(netpgp, name)) < 0) { 1532 /* add the element to the array */ 1533 if (size_arrays(netpgp, netpgp->size + 15)) { 1534 netpgp->name[i = netpgp->c++] = netpgp_strdup(name); 1535 } 1536 } else { 1537 /* replace the element in the array */ 1538 if (netpgp->value[i]) { 1539 free(netpgp->value[i]); 1540 netpgp->value[i] = NULL; 1541 } 1542 } 1543 /* sanity checks for range of values */ 1544 if (strcmp(name, "hash") == 0 || strcmp(name, "algorithm") == 0) { 1545 if (__ops_str_to_hash_alg(newval) == OPS_HASH_UNKNOWN) { 1546 free(newval); 1547 return 0; 1548 } 1549 } 1550 netpgp->value[i] = newval; 1551 return 1; 1552} 1553 1554/* unset a variable */ 1555int 1556netpgp_unsetvar(netpgp_t *netpgp, const char *name) 1557{ 1558 int i; 1559 1560 if ((i = findvar(netpgp, name)) >= 0) { 1561 if (netpgp->value[i]) { 1562 free(netpgp->value[i]); 1563 netpgp->value[i] = NULL; 1564 } 1565 netpgp->value[i] = NULL; 1566 return 1; 1567 } 1568 return 0; 1569} 1570 1571/* get a variable's value (NULL if not set) */ 1572char * 1573netpgp_getvar(netpgp_t *netpgp, const char *name) 1574{ 1575 int i; 1576 1577 return ((i = findvar(netpgp, name)) < 0) ? NULL : netpgp->value[i]; 1578} 1579 1580/* increment a value */ 1581int 1582netpgp_incvar(netpgp_t *netpgp, const char *name, const int delta) 1583{ 1584 char *cp; 1585 char num[16]; 1586 int val; 1587 1588 val = 0; 1589 if ((cp = netpgp_getvar(netpgp, name)) != NULL) { 1590 val = atoi(cp); 1591 } 1592 (void) snprintf(num, sizeof(num), "%d", val + delta); 1593 netpgp_setvar(netpgp, name, num); 1594 return 1; 1595} 1596 1597/* set the home directory value to "home/subdir" */ 1598int 1599netpgp_set_homedir(netpgp_t *netpgp, char *home, const char *subdir, const int quiet) 1600{ 1601 struct stat st; 1602 char d[MAXPATHLEN]; 1603 1604 if (home == NULL) { 1605 if (!quiet) { 1606 (void) fprintf(stderr, "NULL HOME directory\n"); 1607 } 1608 return 0; 1609 } 1610 (void) snprintf(d, sizeof(d), "%s%s", home, (subdir) ? subdir : ""); 1611 if (stat(d, &st) == 0) { 1612 if ((st.st_mode & S_IFMT) == S_IFDIR) { 1613 netpgp_setvar(netpgp, "homedir", d); 1614 return 1; 1615 } 1616 (void) fprintf(stderr, "netpgp: homedir \"%s\" is not a dir\n", 1617 d); 1618 return 0; 1619 } 1620 if (!quiet) { 1621 (void) fprintf(stderr, 1622 "netpgp: warning homedir \"%s\" not found\n", d); 1623 } 1624 netpgp_setvar(netpgp, "homedir", d); 1625 return 1; 1626} 1627 1628/* validate all sigs in the pub keyring */ 1629int 1630netpgp_validate_sigs(netpgp_t *netpgp) 1631{ 1632 __ops_validation_t result; 1633 1634 return (int)__ops_validate_all_sigs(&result, netpgp->pubring, NULL); 1635} 1636 1637/* print the json out on 'fp' */ 1638int 1639netpgp_format_json(void *vp, const char *json, const int psigs) 1640{ 1641 mj_t ids; 1642 FILE *fp; 1643 int from; 1644 int idc; 1645 int tok; 1646 int to; 1647 int i; 1648 1649 if ((fp = (FILE *)vp) == NULL || json == NULL) { 1650 return 0; 1651 } 1652 /* ids is an array of strings, each containing 1 entry */ 1653 (void) memset(&ids, 0x0, sizeof(ids)); 1654 from = to = tok = 0; 1655 /* convert from string into an mj structure */ 1656 (void) mj_parse(&ids, json, &from, &to, &tok); 1657 if ((idc = mj_arraycount(&ids)) == 1 && strchr(json, '{') == NULL) { 1658 idc = 0; 1659 } 1660 (void) fprintf(fp, "%d key%s found\n", idc, (idc == 1) ? "" : "s"); 1661 for (i = 0 ; i < idc ; i++) { 1662 format_json_key(fp, &ids.value.v[i], psigs); 1663 } 1664 /* clean up */ 1665 mj_delete(&ids); 1666 return idc; 1667} 1668