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 #include <sys/types.h> 32 #include <sys/stat.h> 33 #include <sys/param.h> 34 #include <sys/mman.h> 35 36 #ifdef HAVE_SYS_RESOURCE_H 37 #include <sys/resource.h> 38 #endif 39 40 #ifdef HAVE_OPENSSL_CAST_H 41 #include <openssl/cast.h> 42 #endif 43 44 #include <netpgp.h> 45 46 #include "packet.h" 47 #include "packet-parse.h" 48 #include "keyring.h" 49 #include "errors.h" 50 #include "packet-show.h" 51 #include "create.h" 52 #include "netpgpsdk.h" 53 #include "memory.h" 54 #include "validate.h" 55 #include "readerwriter.h" 56 #include "netpgpdefs.h" 57 #include "parse_local.h" 58 59 #ifdef HAVE_FCNTL_H 60 #include <fcntl.h> 61 #endif 62 63 #include <regex.h> 64 #include <stdarg.h> 65 #include <stdlib.h> 66 #include <string.h> 67 #include <time.h> 68 69 #ifdef HAVE_UNISTD_H 70 #include <unistd.h> 71 #endif 72 73 #include <errno.h> 74 75 #ifdef HAVE_LIMITS_H 76 #include <limits.h> 77 #endif 78 79 enum { 80 MAX_ID_LENGTH = 128, 81 MAX_PASSPHRASE_LENGTH = 256 82 }; 83 84 /* read any gpg config file */ 85 static int 86 conffile(char *homedir, char *userid, size_t length, int verbose) 87 { 88 regmatch_t matchv[10]; 89 regex_t keyre; 90 char buf[BUFSIZ]; 91 FILE *fp; 92 93 (void) snprintf(buf, sizeof(buf), "%s/.gnupg/gpg.conf", homedir); 94 if ((fp = fopen(buf, "r")) == NULL) { 95 return 0; 96 } 97 (void) memset(&keyre, 0x0, sizeof(keyre)); 98 (void) regcomp(&keyre, "^[ \t]*default-key[ \t]+([0-9a-zA-F]+)", 99 REG_EXTENDED); 100 while (fgets(buf, sizeof(buf), fp) != NULL) { 101 if (regexec(&keyre, buf, 10, matchv, 0) == 0) { 102 (void) memcpy(userid, &buf[(int)matchv[1].rm_so], 103 MIN((unsigned)(matchv[1].rm_eo - 104 matchv[1].rm_so), length)); 105 if (verbose) { 106 printf("setting default key to \"%.*s\"\n", 107 (int)(matchv[1].rm_eo - matchv[1].rm_so), 108 &buf[(int)matchv[1].rm_so]); 109 } 110 } 111 } 112 (void) fclose(fp); 113 return 1; 114 } 115 116 /* wrapper to get a pass phrase from the user */ 117 static void 118 get_pass_phrase(char *phrase, size_t size) 119 { 120 char *p; 121 122 while ((p = getpass("netpgp passphrase: ")) == NULL) { 123 } 124 (void) snprintf(phrase, size, "%s", p); 125 } 126 127 /* small function to pretty print an 8-character raw userid */ 128 static char * 129 userid_to_id(const unsigned char *userid, char *id) 130 { 131 static const char *hexes = "0123456789ABCDEF"; 132 int i; 133 134 for (i = 0; i < 8 ; i++) { 135 id[i * 2] = hexes[(unsigned)(userid[i] & 0xf0) >> 4]; 136 id[(i * 2) + 1] = hexes[userid[i] & 0xf]; 137 } 138 id[8 * 2] = 0x0; 139 return id; 140 } 141 142 /* print out the successful signature information */ 143 static void 144 psuccess(FILE *fp, char *f, __ops_validation_t *res, __ops_keyring_t *pubring) 145 { 146 const __ops_keydata_t *pubkey; 147 unsigned i; 148 char id[MAX_ID_LENGTH + 1]; 149 150 for (i = 0; i < res->validc; i++) { 151 (void) fprintf(fp, 152 "Good signature for %s made %susing %s key %s\n", 153 f, 154 ctime(&res->valid_sigs[i].birthtime), 155 __ops_show_pka(res->valid_sigs[i].key_alg), 156 userid_to_id(res->valid_sigs[i].signer_id, id)); 157 pubkey = __ops_keyring_find_key_by_id(pubring, 158 (const unsigned char *) res->valid_sigs[i].signer_id); 159 __ops_print_pubkeydata(pubkey); 160 } 161 } 162 163 /* sign a file, and put the signature in a separate file */ 164 static int 165 sign_detached(char *f, char *sigfile, __ops_seckey_t *seckey, 166 const char *hashstr) 167 { 168 __ops_create_sig_t *sig; 169 __ops_hash_alg_t alg; 170 __ops_createinfo_t *info; 171 unsigned char keyid[OPS_KEY_ID_SIZE]; 172 unsigned char *mmapped; 173 struct stat st; 174 time_t t; 175 char fname[MAXPATHLEN]; 176 int fd; 177 178 /* find out which hash algorithm to use */ 179 alg = __ops_str_to_hash_alg(hashstr); 180 if (alg == OPS_HASH_UNKNOWN) { 181 (void) fprintf(stderr,"Unknown hash algorithm: %s\n", hashstr); 182 return 0; 183 } 184 185 /* create a new signature */ 186 sig = __ops_create_sig_new(); 187 __ops_start_sig(sig, seckey, alg, OPS_SIG_BINARY); 188 189 /* read the contents of 'f' */ 190 fd = open(f, O_RDONLY); 191 if (fd < 0) { 192 (void) fprintf(stderr, "can't open file \"%s\" to sign\n", 193 f); 194 return 0; 195 } 196 /* attempt to mmap(2) the file - if that fails, fall back to 197 * standard read(2) */ 198 mmapped = MAP_FAILED; 199 if (fstat(fd, &st) == 0) { 200 mmapped = mmap(NULL, (size_t)st.st_size, PROT_READ, 201 MAP_FILE | MAP_PRIVATE, fd, 0); 202 } 203 if (mmapped == MAP_FAILED) { 204 for (;;) { 205 unsigned char buf[8192]; 206 int n; 207 208 if ((n = read(fd, buf, sizeof(buf))) == 0) { 209 break; 210 } 211 if (n < 0) { 212 (void) fprintf(stderr, "short read \"%s\"\n", 213 f); 214 (void) close(fd); 215 return 0; 216 } 217 __ops_sig_add_data(sig, buf, (unsigned)n); 218 } 219 } else { 220 __ops_sig_add_data(sig, mmapped, (unsigned)st.st_size); 221 (void) munmap(mmapped, (unsigned)st.st_size); 222 } 223 (void) close(fd); 224 225 /* calculate the signature */ 226 t = time(NULL); 227 __ops_sig_add_birthtime(sig, t); 228 __ops_keyid(keyid, OPS_KEY_ID_SIZE, OPS_KEY_ID_SIZE, 229 &seckey->pubkey); 230 __ops_sig_add_issuer_key_id(sig, keyid); 231 __ops_sig_hashed_subpackets_end(sig); 232 233 /* write the signature to the detached file */ 234 if (sigfile == NULL) { 235 (void) snprintf(fname, sizeof(fname), "%s.sig", f); 236 sigfile = fname; 237 } 238 fd = open(sigfile, O_CREAT|O_TRUNC|O_WRONLY, 0666); 239 if (fd < 0) { 240 (void) fprintf(stderr, "can't write signature to \"%s\"\n", 241 sigfile); 242 return 0; 243 } 244 245 info = __ops_createinfo_new(); 246 __ops_writer_set_fd(info, fd); 247 __ops_write_sig(sig, &seckey->pubkey, seckey, info); 248 __ops_seckey_free(seckey); 249 (void) close(fd); 250 251 return 1; 252 } 253 254 /***************************************************************************/ 255 /* exported functions start here */ 256 /***************************************************************************/ 257 258 /* initialise a netpgp_t structure */ 259 int 260 netpgp_init(netpgp_t *netpgp, char *userid, char *pubring, char *secring) 261 { 262 __ops_keyring_t *keyring; 263 char *homedir; 264 char ringname[MAXPATHLEN]; 265 char id[MAX_ID_LENGTH]; 266 267 #ifdef HAVE_SYS_RESOURCE_H 268 struct rlimit limit; 269 270 (void) memset(&limit, 0x0, sizeof(limit)); 271 if (setrlimit(RLIMIT_CORE, &limit) != 0) { 272 (void) fprintf(stderr, 273 "netpgp_init: warning - can't turn off core dumps\n"); 274 } 275 #else 276 (void) fprintf(stderr, 277 "netpgp_init: warning - no way of switching off core dumps\n"); 278 #endif 279 (void) memset(netpgp, 0x0, sizeof(*netpgp)); 280 homedir = getenv("HOME"); 281 if (userid == NULL) { 282 (void) memset(id, 0x0, sizeof(id)); 283 conffile(homedir, id, sizeof(id), 1); 284 if (id[0] != 0x0) { 285 userid = id; 286 } 287 } 288 if (userid == NULL) { 289 (void) fprintf(stderr, "Cannot find user id\n"); 290 return 0; 291 } 292 if (pubring == NULL) { 293 (void) snprintf(ringname, sizeof(ringname), 294 "%s/.gnupg/pubring.gpg", homedir); 295 pubring = ringname; 296 } 297 keyring = calloc(1, sizeof(*keyring)); 298 if (!__ops_keyring_fileread(keyring, false, pubring)) { 299 (void) fprintf(stderr, "Cannot read pub keyring %s\n", pubring); 300 return 0; 301 } 302 netpgp->pubring = keyring; 303 netpgp->pubringfile = strdup(pubring); 304 if (secring == NULL) { 305 (void) snprintf(ringname, sizeof(ringname), 306 "%s/.gnupg/secring.gpg", homedir); 307 secring = ringname; 308 } 309 keyring = calloc(1, sizeof(*keyring)); 310 if (!__ops_keyring_fileread(keyring, false, secring)) { 311 (void) fprintf(stderr, "Cannot read sec keyring %s\n", secring); 312 return 0; 313 } 314 netpgp->secring = keyring; 315 netpgp->secringfile = strdup(secring); 316 netpgp->userid = strdup(userid); 317 return 1; 318 } 319 320 /* finish off with the netpgp_t struct */ 321 int 322 netpgp_end(netpgp_t *netpgp) 323 { 324 if (netpgp->pubring != NULL) { 325 __ops_keyring_free(netpgp->pubring); 326 } 327 if (netpgp->pubringfile != NULL) { 328 (void) free(netpgp->pubringfile); 329 } 330 if (netpgp->secring != NULL) { 331 __ops_keyring_free(netpgp->secring); 332 } 333 if (netpgp->secringfile != NULL) { 334 (void) free(netpgp->secringfile); 335 } 336 (void) free(netpgp->userid); 337 return 1; 338 } 339 340 /* list the keys in a keyring */ 341 int 342 netpgp_list_keys(netpgp_t *netpgp) 343 { 344 __ops_keyring_list(netpgp->pubring); 345 return 1; 346 } 347 348 /* find a key in a keyring */ 349 int 350 netpgp_find_key(netpgp_t *netpgp, char *id) 351 { 352 if (id == NULL) { 353 (void) fprintf(stderr, "NULL id to search for\n"); 354 return 0; 355 } 356 return __ops_keyring_find_key_by_userid(netpgp->pubring, id) != NULL; 357 } 358 359 /* export a given key */ 360 int 361 netpgp_export_key(netpgp_t *netpgp, char *userid) 362 { 363 const __ops_keydata_t *keypair; 364 365 if (userid == NULL) { 366 userid = netpgp->userid; 367 } 368 keypair = __ops_keyring_find_key_by_userid(netpgp->pubring, userid); 369 if (keypair == NULL) { 370 (void) fprintf(stderr, 371 "Cannot find own key \"%s\" in keyring\n", userid); 372 return 0; 373 } 374 __ops_export_key(keypair, NULL); 375 return 1; 376 } 377 378 /* import a key into our keyring */ 379 int 380 netpgp_import_key(netpgp_t *netpgp, char *f) 381 { 382 int done; 383 384 if ((done = __ops_keyring_fileread(netpgp->pubring, false, f)) == 0) { 385 done = __ops_keyring_fileread(netpgp->pubring, true, f); 386 } 387 if (!done) { 388 (void) fprintf(stderr, "Cannot import key from file %s\n", f); 389 return 0; 390 } 391 __ops_keyring_list(netpgp->pubring); 392 return 1; 393 } 394 395 /* generate a new key */ 396 int 397 netpgp_generate_key(netpgp_t *netpgp, char *id, int numbits) 398 { 399 __ops_createinfo_t *create; 400 __ops_keydata_t *keypair; 401 __ops_user_id_t uid; 402 int fd; 403 404 (void) memset(&uid, 0x0, sizeof(uid)); 405 uid.user_id = (unsigned char *) id; 406 keypair = __ops_rsa_create_selfsigned_keypair(numbits, 407 (const unsigned long)65537, &uid); 408 if (keypair == NULL) { 409 (void) fprintf(stderr, "Cannot generate key\n"); 410 return 0; 411 } 412 /* write public key */ 413 fd = __ops_setup_file_append(&create, netpgp->pubringfile); 414 __ops_write_transferable_pubkey(keypair, false, create); 415 __ops_teardown_file_write(create, fd); 416 __ops_keyring_free(netpgp->pubring); 417 if (!__ops_keyring_fileread(netpgp->pubring, false, 418 netpgp->pubringfile)) { 419 (void) fprintf(stderr, "Cannot re-read keyring %s\n", 420 netpgp->pubringfile); 421 return 0; 422 } 423 /* write secret key */ 424 fd = __ops_setup_file_append(&create, netpgp->secringfile); 425 __ops_write_transferable_seckey(keypair, NULL, 0, false, create); 426 __ops_teardown_file_write(create, fd); 427 __ops_keyring_free(netpgp->secring); 428 if (!__ops_keyring_fileread(netpgp->secring, false, 429 netpgp->secringfile)) { 430 fprintf(stderr, "Cannot re-read keyring %s\n", 431 netpgp->secringfile); 432 return 0; 433 } 434 __ops_keydata_free(keypair); 435 return 1; 436 } 437 438 /* encrypt a file */ 439 int 440 netpgp_encrypt_file(netpgp_t *netpgp, char *userid, char *f, char *out, int armored) 441 { 442 const __ops_keydata_t *keypair; 443 const char *suffix; 444 char outname[MAXPATHLEN]; 445 446 if (userid == NULL) { 447 userid = netpgp->userid; 448 } 449 suffix = (armored) ? ".asc" : ".gpg"; 450 keypair = __ops_keyring_find_key_by_userid(netpgp->pubring, userid); 451 if (keypair == NULL) { 452 (void) fprintf(stderr, "Userid '%s' not found in keyring\n", 453 userid); 454 return 0; 455 } 456 if (out == NULL) { 457 (void) snprintf(outname, sizeof(outname), "%s%s", f, suffix); 458 out = outname; 459 } 460 __ops_encrypt_file(f, out, keypair, armored, true); 461 return 1; 462 } 463 464 /* decrypt a file */ 465 int 466 netpgp_decrypt_file(netpgp_t *netpgp, char *f, char *out, int armored) 467 { 468 return __ops_decrypt_file(f, out, netpgp->secring, armored, true, 469 get_passphrase_cb) == true; 470 } 471 472 /* sign a file */ 473 int 474 netpgp_sign_file(netpgp_t *netpgp, char *userid, char *f, char *out, 475 int armored, int cleartext, int detached) 476 { 477 const __ops_keydata_t *keypair; 478 __ops_seckey_t *seckey; 479 char passphrase[MAX_PASSPHRASE_LENGTH]; 480 481 if (userid == NULL) { 482 userid = netpgp->userid; 483 } 484 /* get key with which to sign */ 485 keypair = __ops_keyring_find_key_by_userid(netpgp->secring, userid); 486 if (keypair == NULL) { 487 (void) fprintf(stderr, "Userid '%s' not found in keyring\n", 488 userid); 489 return 0; 490 } 491 do { 492 /* print out the user id */ 493 __ops_print_pubkeydata(keypair); 494 /* get the passphrase */ 495 get_pass_phrase(passphrase, sizeof(passphrase)); 496 /* now decrypt key */ 497 seckey = __ops_decrypt_seckey(keypair, passphrase); 498 if (seckey == NULL) { 499 (void) fprintf(stderr, "Bad passphrase\n"); 500 } 501 } while (seckey == NULL); 502 /* sign file */ 503 if (cleartext) { 504 __ops_sign_file_as_cleartext(f, out, seckey, "SHA256", true); 505 } else if (detached) { 506 sign_detached(f, out, seckey, "SHA256"); 507 } else { 508 __ops_sign_file(f, out, seckey, "SHA256", armored, true); 509 } 510 (void) memset(passphrase, 0x0, sizeof(passphrase)); 511 return 1; 512 } 513 514 /* verify a file */ 515 int 516 netpgp_verify_file(netpgp_t *netpgp, char *infile, const char *outfile, 517 int armored) 518 { 519 __ops_validation_t result; 520 521 (void) memset(&result, 0x0, sizeof(result)); 522 if (__ops_validate_file(&result, infile, outfile, armored, 523 netpgp->pubring)) { 524 psuccess(stderr, infile, &result, netpgp->pubring); 525 return 1; 526 } 527 if (result.validc + result.invalidc + result.unknownc == 0) { 528 (void) fprintf(stderr, 529 "\"%s\": No signatures found - is this a signed file?\n", 530 infile); 531 return 0; 532 } 533 (void) fprintf(stderr, 534 "\"%s\": verification failure: %d invalid signatures, %d unknown signatures\n", 535 infile, result.invalidc, result.unknownc); 536 return 0; 537 } 538 539 /* wrappers for the ops_debug_level functions we added to openpgpsdk */ 540 541 /* set the debugging level per filename */ 542 int 543 netpgp_set_debug(const char *f) 544 { 545 return __ops_set_debug_level(f); 546 } 547 548 /* get the debugging level per filename */ 549 int 550 netpgp_get_debug(const char *f) 551 { 552 return __ops_get_debug_level(f); 553 } 554 555 /* return the version for the library */ 556 const char * 557 netpgp_get_info(const char *type) 558 { 559 return __ops_get_info(type); 560 } 561 562 int 563 netpgp_list_packets(netpgp_t *netpgp, char *f, int armour, char *pubringname) 564 { 565 __ops_keyring_t *keyring; 566 char ringname[MAXPATHLEN]; 567 char *homedir; 568 569 homedir = getenv("HOME"); 570 if (pubringname == NULL) { 571 (void) snprintf(ringname, sizeof(ringname), 572 "%s/.gnupg/pubring.gpg", homedir); 573 pubringname = ringname; 574 } 575 keyring = calloc(1, sizeof(*keyring)); 576 if (!__ops_keyring_fileread(keyring, false, pubringname)) { 577 (void) fprintf(stderr, "Cannot read pub keyring %s\n", 578 pubringname); 579 return 0; 580 } 581 netpgp->pubring = keyring; 582 netpgp->pubringfile = strdup(pubringname); 583 __ops_list_packets(f, armour, keyring, get_passphrase_cb); 584 return 1; 585 } 586