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