netpgp.c revision 1.11.2.2
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/param.h> 33 34#ifdef HAVE_OPENSSL_CAST_H 35#include <openssl/cast.h> 36#endif 37 38#include <netpgp.h> 39 40#include "packet.h" 41#include "packet-parse.h" 42#include "keyring.h" 43#include "errors.h" 44#include "packet-show.h" 45#include "create.h" 46#include "netpgpsdk.h" 47#include "memory.h" 48#include "validate.h" 49#include "readerwriter.h" 50#include "netpgpdefs.h" 51#include "parse_local.h" 52 53#ifdef HAVE_ASSERT_H 54#include <assert.h> 55#endif 56 57#include <regex.h> 58#include <stdarg.h> 59#include <stdlib.h> 60#include <string.h> 61 62#ifdef HAVE_UNISTD_H 63#include <unistd.h> 64#endif 65 66#include <errno.h> 67 68#ifdef HAVE_LIMITS_H 69#include <limits.h> 70#endif 71 72enum { 73 MAX_ID_LENGTH = 128, 74 MAX_PASSPHRASE_LENGTH = 256 75}; 76 77/* read any gpg config file */ 78static int 79conffile(char *homedir, char *userid, size_t length, int verbose) 80{ 81 regmatch_t matchv[10]; 82 regex_t r; 83 char buf[BUFSIZ]; 84 FILE *fp; 85 86 (void) snprintf(buf, sizeof(buf), "%s/.gnupg/gpg.conf", homedir); 87 if ((fp = fopen(buf, "r")) == NULL) { 88 return 0; 89 } 90 (void) regcomp(&r, "^[ \t]*default-key[ \t]+([0-9a-zA-F]+)", 91 REG_EXTENDED); 92 while (fgets(buf, sizeof(buf), fp) != NULL) { 93 if (regexec(&r, buf, 10, matchv, 0) == 0) { 94 (void) memcpy(userid, &buf[(int)matchv[1].rm_so], 95 MIN((unsigned)(matchv[1].rm_eo - matchv[1].rm_so), length)); 96 if (verbose) { 97 printf("setting default key to \"%.*s\"\n", 98 (int)(matchv[1].rm_eo - matchv[1].rm_so), 99 &buf[(int)matchv[1].rm_so]); 100 } 101 } 102 } 103 (void) fclose(fp); 104 return 1; 105} 106 107/* wrapper to get a pass phrase from the user */ 108static void 109get_pass_phrase(char *phrase, size_t size) 110{ 111 char *p; 112 113 while ((p = getpass("netpgp passphrase: ")) == NULL) { 114 } 115 (void) snprintf(phrase, size, "%s", p); 116} 117 118/* small function to pretty print an 8-character raw userid */ 119static char * 120userid_to_id(const unsigned char *userid, char *id) 121{ 122 static const char *hexes = "0123456789ABCDEF"; 123 int i; 124 125 for (i = 0; i < 8 ; i++) { 126 id[i * 2] = hexes[(unsigned)(userid[i] & 0xf0) >> 4]; 127 id[(i * 2) + 1] = hexes[userid[i] & 0xf]; 128 } 129 id[8 * 2] = 0x0; 130 return id; 131} 132 133/* print out the successful signature information */ 134static void 135psuccess(char *f, __ops_validation_t *results, __ops_keyring_t *pubring) 136{ 137 const __ops_keydata_t *pubkey; 138 char id[MAX_ID_LENGTH + 1]; 139 int i; 140 141 for (i = 0; i < results->validc; i++) { 142 printf("Good signature for %s made %susing %s key %s\n", 143 f, 144 ctime(&results->valid_sigs[i].creation_time), 145 __ops_show_pka(results->valid_sigs[i].key_algorithm), 146 userid_to_id(results->valid_sigs[i].signer_id, id)); 147 pubkey = __ops_keyring_find_key_by_id(pubring, 148 (const unsigned char *) 149 results->valid_sigs[i].signer_id); 150 __ops_print_public_keydata(pubkey); 151 } 152} 153 154/***************************************************************************/ 155/* exported functions start here */ 156/***************************************************************************/ 157 158/* initialise a netpgp_t structure */ 159int 160netpgp_init(netpgp_t *netpgp, char *userid, char *pubring, char *secring) 161{ 162 __ops_keyring_t *keyring; 163 char *homedir; 164 char ringname[MAXPATHLEN]; 165 char id[MAX_ID_LENGTH]; 166 167 (void) memset(netpgp, 0x0, sizeof(*netpgp)); 168 homedir = getenv("HOME"); 169 if (userid == NULL) { 170 (void) memset(id, 0x0, sizeof(id)); 171 conffile(homedir, id, sizeof(id), 1); 172 if (id[0] != 0x0) { 173 userid = id; 174 } 175 } 176 if (userid == NULL) { 177 (void) fprintf(stderr, "Cannot find user id\n"); 178 return 0; 179 } 180 if (pubring == NULL) { 181 (void) snprintf(ringname, sizeof(ringname), "%s/.gnupg/pubring.gpg", homedir); 182 pubring = ringname; 183 } 184 keyring = calloc(1, sizeof(*keyring)); 185 if (!__ops_keyring_read_from_file(keyring, false, pubring)) { 186 (void) fprintf(stderr, "Cannot read pub keyring %s\n", pubring); 187 return 0; 188 } 189 netpgp->pubring = keyring; 190 netpgp->pubringfile = strdup(pubring); 191 if (secring == NULL) { 192 (void) snprintf(ringname, sizeof(ringname), "%s/.gnupg/secring.gpg", homedir); 193 secring = ringname; 194 } 195 keyring = calloc(1, sizeof(*keyring)); 196 if (!__ops_keyring_read_from_file(keyring, false, secring)) { 197 (void) fprintf(stderr, "Cannot read sec keyring %s\n", secring); 198 return 0; 199 } 200 netpgp->secring = keyring; 201 netpgp->secringfile = strdup(secring); 202 netpgp->userid = strdup(userid); 203 return 1; 204} 205 206/* finish off with the netpgp_t struct */ 207int 208netpgp_end(netpgp_t *netpgp) 209{ 210 if (netpgp->pubring != NULL) { 211 __ops_keyring_free(netpgp->pubring); 212 } 213 if (netpgp->pubringfile != NULL) { 214 (void) free(netpgp->pubringfile); 215 } 216 if (netpgp->secring != NULL) { 217 __ops_keyring_free(netpgp->secring); 218 } 219 if (netpgp->secringfile != NULL) { 220 (void) free(netpgp->secringfile); 221 } 222 (void) free(netpgp->userid); 223 return 1; 224} 225 226/* list the keys in a keyring */ 227int 228netpgp_list_keys(netpgp_t *netpgp) 229{ 230 __ops_keyring_list(netpgp->pubring); 231 return 1; 232} 233 234/* find a key in a keyring */ 235int 236netpgp_find_key(netpgp_t *netpgp, char *id) 237{ 238 if (id == NULL) { 239 (void) fprintf(stderr, "NULL id to search for\n"); 240 return 0; 241 } 242 return __ops_keyring_find_key_by_userid(netpgp->pubring, id) != NULL; 243} 244 245/* export a given key */ 246int 247netpgp_export_key(netpgp_t *netpgp, char *userid) 248{ 249 const __ops_keydata_t *keypair; 250 251 if (userid == NULL) { 252 userid = netpgp->userid; 253 } 254 if ((keypair = __ops_keyring_find_key_by_userid(netpgp->pubring, userid)) == NULL) { 255 (void) fprintf(stderr, "Cannot find own key \"%s\" in keyring\n", userid); 256 return 0; 257 } 258 __ops_export_key(keypair, NULL); 259 return 1; 260} 261 262/* import a key into our keyring */ 263int 264netpgp_import_key(netpgp_t *netpgp, char *f) 265{ 266 int done; 267 268 if ((done = __ops_keyring_read_from_file(netpgp->pubring, false, f)) == 0) { 269 done = __ops_keyring_read_from_file(netpgp->pubring, true, f); 270 } 271 if (!done) { 272 (void) fprintf(stderr, "Cannot import key from file %s\n", f); 273 return 0; 274 } 275 __ops_keyring_list(netpgp->pubring); 276 return 1; 277} 278 279/* generate a new key */ 280int 281netpgp_generate_key(netpgp_t *netpgp, char *id, int numbits) 282{ 283 __ops_create_info_t *create; 284 __ops_keydata_t *keypair; 285 __ops_user_id_t uid; 286 int fd; 287 288 (void) memset(&uid, 0x0, sizeof(uid)); 289 uid.user_id = (unsigned char *) id; 290 if ((keypair = __ops_rsa_create_selfsigned_keypair(numbits, (const unsigned long)65537, &uid)) == NULL) { 291 (void) fprintf(stderr, "Cannot generate key\n"); 292 return 0; 293 } 294 /* write public key */ 295 fd = __ops_setup_file_append(&create, netpgp->pubringfile); 296 __ops_write_transferable_public_key(keypair, false, create); 297 __ops_teardown_file_write(create, fd); 298 __ops_keyring_free(netpgp->pubring); 299 if (!__ops_keyring_read_from_file(netpgp->pubring, false, netpgp->pubringfile)) { 300 (void) fprintf(stderr, "Cannot re-read keyring %s\n", netpgp->pubringfile); 301 return 0; 302 } 303 /* write secret key */ 304 fd = __ops_setup_file_append(&create, netpgp->secringfile); 305 __ops_write_transferable_secret_key(keypair, NULL, 0, false, create); 306 __ops_teardown_file_write(create, fd); 307 __ops_keyring_free(netpgp->secring); 308 if (!__ops_keyring_read_from_file(netpgp->secring, false, netpgp->secringfile)) { 309 fprintf(stderr, "Cannot re-read keyring %s\n", netpgp->secringfile); 310 return 0; 311 } 312 __ops_keydata_free(keypair); 313 return 1; 314} 315 316/* encrypt a file */ 317int 318netpgp_encrypt_file(netpgp_t *netpgp, char *userid, char *f, char *out, int armored) 319{ 320 const __ops_keydata_t *keypair; 321 const char *suffix; 322 char outname[MAXPATHLEN]; 323 324 if (userid == NULL) { 325 userid = netpgp->userid; 326 } 327 suffix = (armored) ? ".asc" : ".gpg"; 328 if ((keypair = __ops_keyring_find_key_by_userid(netpgp->pubring, userid)) == NULL) { 329 (void) fprintf(stderr, "Userid '%s' not found in keyring\n", userid); 330 return 0; 331 } 332 if (out == NULL) { 333 (void) snprintf(outname, sizeof(outname), "%s%s", f, suffix); 334 out = outname; 335 } 336 __ops_encrypt_file(f, out, keypair, armored, true); 337 return 1; 338} 339 340/* decrypt a file */ 341int 342netpgp_decrypt_file(netpgp_t *netpgp, char *f, char *out, int armored) 343{ 344 __ops_decrypt_file(f, out, netpgp->secring, armored, true, 345 get_passphrase_cb); 346 return 1; 347} 348 349/* sign a file */ 350int 351netpgp_sign_file(netpgp_t *netpgp, char *userid, char *f, char *out, int armored, int cleartext) 352{ 353 const __ops_keydata_t *keypair; 354 __ops_secret_key_t *seckey; 355 char passphrase[MAX_PASSPHRASE_LENGTH]; 356 357 if (userid == NULL) { 358 userid = netpgp->userid; 359 } 360 /* get key with which to sign */ 361 if ((keypair = __ops_keyring_find_key_by_userid(netpgp->secring, userid)) == NULL) { 362 (void) fprintf(stderr, "Userid '%s' not found in keyring\n", userid); 363 return 0; 364 } 365 do { 366 /* print out the user id */ 367 __ops_print_public_keydata(keypair); 368 /* get the passphrase */ 369 get_pass_phrase(passphrase, sizeof(passphrase)); 370 /* now decrypt key */ 371 if ((seckey = __ops_decrypt_secret_key_from_data(keypair, passphrase)) == NULL) { 372 (void) fprintf(stderr, "Bad passphrase\n"); 373 } 374 } while (seckey == NULL); 375 /* sign file */ 376 if (cleartext) { 377 __ops_sign_file_as_cleartext(f, out, seckey, true); 378 } else { 379 __ops_sign_file(f, out, seckey, armored, true); 380 } 381 (void) memset(passphrase, 0x0, sizeof(passphrase)); 382 return 1; 383} 384 385/* verify a file */ 386int 387netpgp_verify_file(netpgp_t *netpgp, char *f, int armored) 388{ 389 __ops_validation_t result; 390 391 (void) memset(&result, 0x0, sizeof(result)); 392 if (__ops_validate_file(&result, f, armored, netpgp->pubring)) { 393 psuccess(f, &result, netpgp->pubring); 394 return 1; 395 } 396 if (result.validc + result.invalidc + result.unknownc == 0) { 397 (void) fprintf(stderr, "\"%s\": No signatures found - is this a signed file?\n", f); 398 return 0; 399 } 400 (void) fprintf(stderr, "\"%s\": verification failure: %d invalid signatures, %d unknown signatures\n", 401 f, result.invalidc, result.unknownc); 402 return 0; 403} 404 405/* wrappers for the ops_debug_level functions we added to openpgpsdk */ 406 407/* set the debugging level per filename */ 408int 409netpgp_set_debug(const char *f) 410{ 411 return __ops_set_debug_level(f); 412} 413 414/* get the debugging level per filename */ 415int 416netpgp_get_debug(const char *f) 417{ 418 return __ops_get_debug_level(f); 419} 420 421/* return the version for the library */ 422const char * 423netpgp_get_info(const char *type) 424{ 425 return __ops_get_info(type); 426} 427