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