/* read a keyring and return it */ static void * readkeyring(netpgp_t *netpgp, const char *name) { pgp_keyring_t *keyring; const unsigned noarmor = 0; char f[MAXPATHLEN]; char *filename; char *homedir; homedir = netpgp_getvar(netpgp, "homedir"); if ((filename = netpgp_getvar(netpgp, name)) == NULL) { (void) snprintf(f, sizeof(f), "%s/%s.gpg", homedir, name); filename = f; } if ((keyring = calloc(1, sizeof(*keyring))) == NULL) { (void) fprintf(stderr, "readkeyring: bad alloc\n"); return NULL; } if (!pgp_keyring_fileread(keyring, noarmor, filename)) { free(keyring); (void) fprintf(stderr, "Can't read %s %s\n", name, filename); return NULL; } netpgp_setvar(netpgp, name, filename); return keyring; }
/* read all of stdin into memory */ static int stdin_to_mem(netpgp_t *netpgp, char **temp, char **out, unsigned *maxsize) { unsigned newsize; unsigned size; char buf[BUFSIZ * 8]; char *loc; int n; *maxsize = (unsigned)atoi(netpgp_getvar(netpgp, "max mem alloc")); size = 0; *temp = NULL; while ((n = read(STDIN_FILENO, buf, sizeof(buf))) > 0) { /* round up the allocation */ newsize = size + ((n / BUFSIZ) + 1) * BUFSIZ; if (newsize > *maxsize) { (void) fprintf(stderr, "bounds check\n"); return size; } loc = realloc(*temp, newsize); if (loc == NULL) { (void) fprintf(stderr, "short read\n"); return size; } *temp = loc; (void) memcpy(&(*temp)[size], buf, n); size += n; } if ((*out = calloc(1, *maxsize)) == NULL) { (void) fprintf(stderr, "Bad alloc\n"); return 0; } return (int)size; }
/* do a command once for a specified file 'f' */ static int netpgp_cmd(netpgp_t *netpgp, prog_t *p, char *f) { char *key; char *s; switch (p->cmd) { case LIST_KEYS: case LIST_SIGS: return match_keys(netpgp, stdout, f, (p->cmd == LIST_SIGS)); case FIND_KEY: if ((key = f) == NULL) { key = netpgp_getvar(netpgp, "userid"); } return netpgp_find_key(netpgp, key); case EXPORT_KEY: if ((key = f) == NULL) { key = netpgp_getvar(netpgp, "userid"); } if (key) { if ((s = netpgp_export_key(netpgp, key)) != NULL) { printf("%s", s); return 1; } } (void) fprintf(stderr, "key '%s' not found\n", f); return 0; case IMPORT_KEY: return netpgp_import_key(netpgp, f); case GENERATE_KEY: return netpgp_generate_key(netpgp, f, p->numbits); case GET_KEY: key = netpgp_get_key(netpgp, f, netpgp_getvar(netpgp, "format")); if (key) { printf("%s", key); return 1; } (void) fprintf(stderr, "key '%s' not found\n", f); return 0; case TRUSTED_KEYS: return netpgp_match_pubkeys(netpgp, f, stdout); case HELP_CMD: default: print_usage(usage, p->progname); exit(EXIT_SUCCESS); } }
/* resolve the userid */ static const pgp_key_t * resolve_userid(netpgp_t *netpgp, const pgp_keyring_t *keyring, const char *userid) { const pgp_key_t *key; pgp_io_t *io; if (userid == NULL) { userid = netpgp_getvar(netpgp, "userid"); if (userid == NULL) return NULL; } else if (userid[0] == '0' && userid[1] == 'x') { userid += 2; } io = netpgp->io; if ((key = pgp_getkeybyname(io, keyring, userid)) == NULL) { (void) fprintf(io->errs, "Can't find key '%s'\n", userid); } return key; }
/* match keys, decoding from json if we do find any */ static int match_keys(netpgp_t *netpgp, FILE *fp, char *f, const int psigs) { char *json; int idc; if (f == NULL) { if (!netpgp_list_keys_json(netpgp, &json, psigs)) { return 0; } } else { if (netpgp_match_keys_json(netpgp, &json, f, netpgp_getvar(netpgp, "format"), psigs) == 0) { return 0; } } idc = netpgp_format_json(fp, json, psigs); /* clean up */ free(json); return idc; }
int main(int argc, char **argv) { struct stat st; netpgp_t netpgp; prog_t p; int homeset; int optindex; int ret; int ch; int i; (void) memset(&p, 0x0, sizeof(p)); (void) memset(&netpgp, 0x0, sizeof(netpgp)); homeset = 0; p.progname = argv[0]; p.numbits = DEFAULT_NUMBITS; if (argc < 2) { print_usage(usage, p.progname); exit(EXIT_ERROR); } /* set some defaults */ netpgp_setvar(&netpgp, "sshkeydir", "/etc/ssh"); netpgp_setvar(&netpgp, "res", "<stdout>"); netpgp_setvar(&netpgp, "hash", DEFAULT_HASH_ALG); netpgp_setvar(&netpgp, "format", "human"); optindex = 0; while ((ch = getopt_long(argc, argv, "S:Vglo:s", options, &optindex)) != -1) { if (ch >= LIST_KEYS) { /* getopt_long returns 0 for long options */ if (!setoption(&netpgp, &p, options[optindex].val, optarg, &homeset)) { (void) fprintf(stderr, "Bad setoption result %d\n", ch); } } else { switch (ch) { case 'S': netpgp_setvar(&netpgp, "ssh keys", "1"); netpgp_setvar(&netpgp, "sshkeyfile", optarg); break; case 'V': printf( "%s\nAll bug reports, praise and chocolate, please, to:\n%s\n", netpgp_get_info("version"), netpgp_get_info("maintainer")); exit(EXIT_SUCCESS); case 'g': p.cmd = GENERATE_KEY; break; case 'l': p.cmd = LIST_KEYS; break; case 'o': if (!parse_option(&netpgp, &p, optarg, &homeset)) { (void) fprintf(stderr, "Bad parse_option\n"); } break; case 's': p.cmd = LIST_SIGS; break; default: p.cmd = HELP_CMD; break; } } } if (!homeset) { netpgp_set_homedir(&netpgp, getenv("HOME"), netpgp_getvar(&netpgp, "ssh keys") ? "/.ssh" : "/.gnupg", 1); } /* initialise, and read keys from file */ if (!netpgp_init(&netpgp)) { if (stat(netpgp_getvar(&netpgp, "homedir"), &st) < 0) { (void) mkdir(netpgp_getvar(&netpgp, "homedir"), 0700); } if (stat(netpgp_getvar(&netpgp, "homedir"), &st) < 0) { (void) fprintf(stderr, "can't create home directory '%s'\n", netpgp_getvar(&netpgp, "homedir")); exit(EXIT_ERROR); } } /* now do the required action for each of the command line args */ ret = EXIT_SUCCESS; if (optind == argc) { if (!netpgp_cmd(&netpgp, &p, NULL)) { ret = EXIT_FAILURE; } } else { for (i = optind; i < argc; i++) { if (!netpgp_cmd(&netpgp, &p, argv[i])) { ret = EXIT_FAILURE; } } } netpgp_end(&netpgp); exit(ret); }
/* read keys from ssh key files */ static int readsshkeys(netpgp_t *netpgp, char *homedir, const char *needseckey) { pgp_keyring_t *pubring; pgp_keyring_t *secring; struct stat st; unsigned hashtype; char *hash; char f[MAXPATHLEN]; char *filename; if ((filename = netpgp_getvar(netpgp, "sshkeyfile")) == NULL) { /* set reasonable default for RSA key */ (void) snprintf(f, sizeof(f), "%s/id_rsa.pub", homedir); filename = f; } else if (strcmp(&filename[strlen(filename) - 4], ".pub") != 0) { /* got ssh keys, check for pub file name */ (void) snprintf(f, sizeof(f), "%s.pub", filename); filename = f; } /* check the pub file exists */ if (stat(filename, &st) != 0) { (void) fprintf(stderr, "readsshkeys: bad pubkey filename '%s'\n", filename); return 0; } if ((pubring = calloc(1, sizeof(*pubring))) == NULL) { (void) fprintf(stderr, "readsshkeys: bad alloc\n"); return 0; } /* openssh2 keys use md5 by default */ hashtype = PGP_HASH_MD5; if ((hash = netpgp_getvar(netpgp, "hash")) != NULL) { /* openssh 2 hasn't really caught up to anything else yet */ if (netpgp_strcasecmp(hash, "md5") == 0) { hashtype = PGP_HASH_MD5; } else if (netpgp_strcasecmp(hash, "sha1") == 0) { hashtype = PGP_HASH_SHA1; } else if (netpgp_strcasecmp(hash, "sha256") == 0) { hashtype = PGP_HASH_SHA256; } } if (!pgp_ssh2_readkeys(netpgp->io, pubring, NULL, filename, NULL, hashtype)) { free(pubring); (void) fprintf(stderr, "readsshkeys: can't read %s\n", filename); return 0; } if (netpgp->pubring == NULL) { netpgp->pubring = pubring; } else { pgp_append_keyring(netpgp->pubring, pubring); } if (needseckey) { netpgp_setvar(netpgp, "sshpubfile", filename); /* try to take the ".pub" off the end */ if (filename == f) { f[strlen(f) - 4] = 0x0; } else { (void) snprintf(f, sizeof(f), "%.*s", (int)strlen(filename) - 4, filename); filename = f; } if ((secring = calloc(1, sizeof(*secring))) == NULL) { free(pubring); (void) fprintf(stderr, "readsshkeys: bad alloc\n"); return 0; } if (!pgp_ssh2_readkeys(netpgp->io, pubring, secring, NULL, filename, hashtype)) { free(pubring); free(secring); (void) fprintf(stderr, "readsshkeys: can't read sec %s\n", filename); return 0; } netpgp->secring = secring; netpgp_setvar(netpgp, "sshsecfile", filename); } return 1; }
int main(int argc, char **argv) { netpgp_t netpgp; prog_t p; int homeset; int optindex; int ret; int ch; int i; (void) memset(&p, 0x0, sizeof(p)); (void) memset(&netpgp, 0x0, sizeof(netpgp)); p.progname = argv[0]; p.overwrite = 1; p.output = NULL; if (argc < 2) { print_usage(usage, p.progname); exit(EXIT_ERROR); } /* set some defaults */ netpgp_setvar(&netpgp, "hash", DEFAULT_HASH_ALG); /* 4 MiB for a memory file */ netpgp_setvar(&netpgp, "max mem alloc", "4194304"); homeset = 0; optindex = 0; while ((ch = getopt_long(argc, argv, "S:Vdeo:sv", options, &optindex)) != -1) { if (ch >= ENCRYPT) { /* getopt_long returns 0 for long options */ if (!setoption(&netpgp, &p, options[optindex].val, optarg, &homeset)) { (void) fprintf(stderr, "Bad option\n"); } } else { switch (ch) { case 'S': netpgp_setvar(&netpgp, "ssh keys", "1"); netpgp_setvar(&netpgp, "sshkeyfile", optarg); break; case 'V': printf( "%s\nAll bug reports, praise and chocolate, please, to:\n%s\n", netpgp_get_info("version"), netpgp_get_info("maintainer")); exit(EXIT_SUCCESS); case 'd': /* for decryption, we need the seckey */ netpgp_setvar(&netpgp, "need seckey", "1"); p.cmd = DECRYPT; break; case 'e': /* for encryption, we need a userid */ netpgp_setvar(&netpgp, "need userid", "1"); p.cmd = ENCRYPT; break; case 'o': if (!parse_option(&netpgp, &p, optarg, &homeset)) { (void) fprintf(stderr, "Bad option\n"); } break; case 's': /* for signing, we need a userid and a seckey */ netpgp_setvar(&netpgp, "need seckey", "1"); netpgp_setvar(&netpgp, "need userid", "1"); p.cmd = SIGN; break; case 'v': p.cmd = VERIFY; break; default: p.cmd = HELP_CMD; break; } } } if (!homeset) { netpgp_set_homedir(&netpgp, getenv("HOME"), netpgp_getvar(&netpgp, "ssh keys") ? "/.ssh" : "/.gnupg", 1); } /* initialise, and read keys from file */ if (!netpgp_init(&netpgp)) { printf("can't initialise\n"); exit(EXIT_ERROR); } /* now do the required action for each of the command line args */ ret = EXIT_SUCCESS; if (optind == argc) { if (!netpgp_cmd(&netpgp, &p, NULL)) { ret = EXIT_FAILURE; } } else { for (i = optind; i < argc; i++) { if (!netpgp_cmd(&netpgp, &p, argv[i])) { ret = EXIT_FAILURE; } } } netpgp_end(&netpgp); exit(ret); }
/* do a command once for a specified file 'f' */ static int netpgp_cmd(netpgp_t *netpgp, prog_t *p, char *f) { const int cleartext = 1; unsigned maxsize; char *out; char *in; int ret; int cc; switch (p->cmd) { case ENCRYPT: if (f == NULL) { cc = stdin_to_mem(netpgp, &in, &out, &maxsize); ret = netpgp_encrypt_memory(netpgp, netpgp_getvar(netpgp, "userid"), in, cc, out, maxsize, p->armour); ret = show_output(out, ret, "Bad memory encryption"); free(in); free(out); return ret; } return netpgp_encrypt_file(netpgp, netpgp_getvar(netpgp, "userid"), f, p->output, p->armour); case DECRYPT: if (f == NULL) { cc = stdin_to_mem(netpgp, &in, &out, &maxsize); ret = netpgp_decrypt_memory(netpgp, in, cc, out, maxsize, 0); ret = show_output(out, ret, "Bad memory decryption"); free(in); free(out); return ret; } return netpgp_decrypt_file(netpgp, f, p->output, p->armour); case CLEARSIGN: case SIGN: if (f == NULL) { cc = stdin_to_mem(netpgp, &in, &out, &maxsize); ret = netpgp_sign_memory(netpgp, netpgp_getvar(netpgp, "userid"), in, cc, out, maxsize, p->armour, (p->cmd == CLEARSIGN) ? cleartext : !cleartext); ret = show_output(out, ret, "Bad memory signature"); free(in); free(out); return ret; } return netpgp_sign_file(netpgp, netpgp_getvar(netpgp, "userid"), f, p->output, p->armour, (p->cmd == CLEARSIGN) ? cleartext : !cleartext, p->detached); case VERIFY: case VERIFY_CAT: if (f == NULL) { cc = stdin_to_mem(netpgp, &in, &out, &maxsize); ret = netpgp_verify_memory(netpgp, in, cc, (p->cmd == VERIFY_CAT) ? out : NULL, (p->cmd == VERIFY_CAT) ? maxsize : 0, p->armour); ret = show_output(out, ret, "Bad memory verification"); free(in); free(out); return ret; } return netpgp_verify_file(netpgp, f, (p->cmd == VERIFY) ? NULL : (p->output) ? p->output : "-", p->armour); case LIST_PACKETS: if (f == NULL) { (void) fprintf(stderr, "%s: No filename provided\n", p->progname); return 0; } return netpgp_list_packets(netpgp, f, p->armour, NULL); case SHOW_KEYS: return netpgp_validate_sigs(netpgp); case HELP_CMD: default: print_usage(usage, p->progname); exit(EXIT_SUCCESS); } }