123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760 |
- /*
- * Copyright (C) 2018 Daniel Golle <daniel@makrotopia.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3
- * as published by the Free Software Foundation
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
- #define _GNU_SOURCE
- #include <fcntl.h>
- #include <dlfcn.h>
- #include <stdio.h>
- #include <stdbool.h>
- #include <stdlib.h>
- #include <string.h>
- #include <getopt.h>
- #include <stdint.h>
- #include <unistd.h>
- #include <inttypes.h>
- #include <sys/stat.h>
- #include <sys/wait.h>
- #include <json-c/json.h>
- #include <libubox/blob.h>
- #include <libubox/utils.h>
- #include <libubox/list.h>
- #include <libubox/vlist.h>
- #include <libubox/blobmsg_json.h>
- #include "usign.h"
- #define CERT_BUF_LEN 4096
- static enum {
- CMD_APPEND,
- CMD_DUMP,
- CMD_ISSUE,
- CMD_REVOKE,
- CMD_VERIFY,
- CMD_NONE,
- } cmd = CMD_NONE;
- static bool quiet;
- #ifndef UCERT_STRIP_MESSAGES
- #define DPRINTF(format, ...) \
- do { \
- if (!quiet) \
- fprintf(stderr, "%s(%d): " format, __func__, __LINE__, ## __VA_ARGS__); \
- } while (0)
- #else
- #define DPRINTF(format, ...) do { } while (0)
- #endif
- /*
- * ucert structure
- * | BLOB |
- * | SIGNATURE | PAYLOAD |
- * | |[ BLOBMSG CONTAINER ]|
- * | |[[T,i,v,e,f,pubkey ]]|
- */
- enum cert_attr {
- CERT_ATTR_SIGNATURE,
- CERT_ATTR_PAYLOAD,
- CERT_ATTR_MAX
- };
- static const struct blob_attr_info cert_policy[CERT_ATTR_MAX] = {
- [CERT_ATTR_SIGNATURE] = { .type = BLOB_ATTR_BINARY },
- [CERT_ATTR_PAYLOAD] = { .type = BLOB_ATTR_NESTED },
- };
- enum cert_cont_attr {
- CERT_CT_ATTR_PAYLOAD,
- CERT_CT_ATTR_MAX
- };
- static const struct blobmsg_policy cert_cont_policy[CERT_CT_ATTR_MAX] = {
- [CERT_CT_ATTR_PAYLOAD] = { .name = "ucert", .type = BLOBMSG_TYPE_TABLE },
- };
- enum cert_payload_attr {
- CERT_PL_ATTR_CERTTYPE,
- CERT_PL_ATTR_CERTID,
- CERT_PL_ATTR_VALIDFROMTIME,
- CERT_PL_ATTR_EXPIRETIME,
- CERT_PL_ATTR_PUBKEY,
- CERT_PL_ATTR_KEY_FINGERPRINT,
- CERT_PL_ATTR_MAX
- };
- enum certtype_id {
- CERTTYPE_UNSPEC,
- CERTTYPE_AUTH,
- CERTTYPE_REVOKE
- };
- static const struct blobmsg_policy cert_payload_policy[CERT_PL_ATTR_MAX] = {
- [CERT_PL_ATTR_CERTTYPE] = { .name = "certtype", .type = BLOBMSG_TYPE_INT32 },
- [CERT_PL_ATTR_CERTID] = { .name = "certid", .type = BLOBMSG_TYPE_INT32 },
- [CERT_PL_ATTR_VALIDFROMTIME] = { .name = "validfrom", .type = BLOBMSG_TYPE_INT64 },
- [CERT_PL_ATTR_EXPIRETIME] = { .name = "expiresat", .type = BLOBMSG_TYPE_INT64 },
- [CERT_PL_ATTR_PUBKEY] = { .name = "pubkey", .type = BLOBMSG_TYPE_STRING },
- [CERT_PL_ATTR_KEY_FINGERPRINT] = { .name = "fingerprint", .type = BLOBMSG_TYPE_STRING },
- };
- /* list to store certificate chain at runtime */
- struct cert_object {
- struct list_head list;
- struct blob_attr *cert[CERT_ATTR_MAX];
- };
- /* write buffer to file */
- static int write_file(const char *filename, void *buf, size_t len, bool append) {
- FILE *f;
- size_t outlen;
- f = fopen(filename, append?"a":"w");
- if (!f)
- return 1;
- outlen = fwrite(buf, 1, len, f);
- fclose(f);
- return (outlen == len);
- }
- /* load certfile into list */
- static int cert_load(const char *certfile, struct list_head *chain) {
- FILE *f;
- struct blob_attr *certtb[CERT_ATTR_MAX];
- struct blob_attr *bufpt;
- struct cert_object *cobj;
- char filebuf[CERT_BUF_LEN];
- int ret = 0, pret = 0;
- size_t len, pos = 0;
- f = fopen(certfile, "r");
- if (!f)
- return 1;
- len = fread(&filebuf, 1, CERT_BUF_LEN - 1, f);
- if (len < 64)
- return 1;
- ret = ferror(f) || !feof(f);
- fclose(f);
- if (ret)
- return 1;
- bufpt = (struct blob_attr *)filebuf;
- do {
- pret = blob_parse_untrusted(bufpt, len, certtb, cert_policy, CERT_ATTR_MAX);
- if (pret <= 0)
- /* no attributes found */
- break;
- if (pos + blob_pad_len(bufpt) > len)
- /* blob exceeds filebuffer */
- break;
- else
- pos += blob_pad_len(bufpt);
- if (!certtb[CERT_ATTR_SIGNATURE])
- /* no signature -> drop */
- break;
- cobj = calloc(1, sizeof(*cobj));
- cobj->cert[CERT_ATTR_SIGNATURE] = blob_memdup(certtb[CERT_ATTR_SIGNATURE]);
- if (certtb[CERT_ATTR_PAYLOAD])
- cobj->cert[CERT_ATTR_PAYLOAD] = blob_memdup(certtb[CERT_ATTR_PAYLOAD]);
- list_add_tail(&cobj->list, chain);
- ret += pret;
- /* repeat parsing while there is still enough remaining data in buffer */
- } while(len > pos + sizeof(struct blob_attr) && (bufpt = blob_next(bufpt)));
- return (ret <= 0);
- }
- #ifdef UCERT_FULL
- /* append signature to certfile */
- static int cert_append(const char *certfile, const char *sigfile) {
- FILE *fs;
- char filebuf[CERT_BUF_LEN];
- struct blob_buf sigbuf = {0};
- int len;
- int ret;
- fs = fopen(sigfile, "r");
- if (!fs)
- return 1;
- len = fread(&filebuf, 1, CERT_BUF_LEN - 1, fs);
- ret = ferror(fs) || !feof(fs) || (len < 64);
- fclose(fs);
- if (ret)
- return 1;
- blob_buf_init(&sigbuf, 0);
- blob_put(&sigbuf, CERT_ATTR_SIGNATURE, filebuf, len);
- ret = write_file(certfile, sigbuf.head, blob_raw_len(sigbuf.head), true);
- blob_buf_free(&sigbuf);
- return ret;
- }
- #endif
- /* verify the signature of a single chain element */
- static int cert_verify_blob(struct blob_attr *cert[CERT_ATTR_MAX],
- const char *pubkeyfile, const char *pubkeydir) {
- int i;
- char msgfname[256], sigfname[256];
- int ret;
- char tmpdir[] = "/tmp/ucert-XXXXXX";
- if (mkdtemp(tmpdir) == NULL)
- return errno;
- snprintf(msgfname, sizeof(msgfname) - 1, "%s/%s", tmpdir, "payload");
- snprintf(sigfname, sizeof(sigfname) - 1, "%s/%s", tmpdir, "payload.sig");
- for (i = 0; i < CERT_ATTR_MAX; i++) {
- struct blob_attr *v = cert[i];
- if (!v)
- break;
- switch(cert_policy[i].type) {
- case BLOB_ATTR_BINARY:
- write_file(sigfname, blob_data(v), blob_len(v), false);
- break;
- case BLOB_ATTR_NESTED:
- write_file(msgfname, blob_data(v), blob_len(v), false);
- break;
- }
- }
- ret = usign_v(msgfname, pubkeyfile, pubkeydir, sigfname, quiet);
- unlink(msgfname);
- unlink(sigfname);
- rmdir(tmpdir);
- return ret;
- }
- /* verify cert chain (and message) */
- static int chain_verify(const char *msgfile, const char *pubkeyfile,
- const char *pubkeydir, struct list_head *chain) {
- struct cert_object *cobj;
- struct blob_attr *containertb[CERT_CT_ATTR_MAX];
- struct blob_attr *payloadtb[CERT_PL_ATTR_MAX];
- char tmpdir[] = "/tmp/ucert-XXXXXX";
- char chainedpubkey[256] = {0};
- char chainedfp[17] = {0};
- char extsigfile[256] = {0};
- int ret = 1;
- int checkmsg = 0;
- struct timeval tv;
- if (mkdtemp(tmpdir) == NULL)
- return errno;
- if (msgfile)
- checkmsg = -1;
- gettimeofday(&tv, NULL);
- list_for_each_entry(cobj, chain, list) {
- /* blob has payload, verify that using signature */
- if (cobj->cert[CERT_ATTR_PAYLOAD]) {
- time_t validfrom;
- time_t expiresat;
- uint32_t certtype;
- ret = cert_verify_blob(cobj->cert, chainedpubkey[0]?chainedpubkey:pubkeyfile, pubkeydir);
- if (ret)
- goto clean_and_return;
- blobmsg_parse(cert_cont_policy,
- ARRAY_SIZE(cert_cont_policy),
- containertb,
- blob_data(cobj->cert[CERT_ATTR_PAYLOAD]),
- blob_len(cobj->cert[CERT_ATTR_PAYLOAD]));
- if (!containertb[CERT_CT_ATTR_PAYLOAD]) {
- ret = 1;
- DPRINTF("no ucert in signed payload\n");
- goto clean_and_return;
- }
- blobmsg_parse(cert_payload_policy,
- ARRAY_SIZE(cert_payload_policy),
- payloadtb,
- blobmsg_data(containertb[CERT_CT_ATTR_PAYLOAD]),
- blobmsg_data_len(containertb[CERT_CT_ATTR_PAYLOAD]));
- if (!payloadtb[CERT_PL_ATTR_CERTTYPE] ||
- !payloadtb[CERT_PL_ATTR_VALIDFROMTIME] ||
- !payloadtb[CERT_PL_ATTR_EXPIRETIME] ||
- !payloadtb[CERT_PL_ATTR_PUBKEY]) {
- ret = 1;
- DPRINTF("missing mandatory ucert attributes\n");
- goto clean_and_return;
- }
- certtype = blobmsg_get_u32(payloadtb[CERT_PL_ATTR_CERTTYPE]);
- validfrom = blobmsg_get_u64(payloadtb[CERT_PL_ATTR_VALIDFROMTIME]);
- expiresat = blobmsg_get_u64(payloadtb[CERT_PL_ATTR_EXPIRETIME]);
- if (certtype != CERTTYPE_AUTH) {
- ret = 2;
- DPRINTF("wrong certificate type\n");
- goto clean_and_return;
- }
- if (tv.tv_sec < validfrom ||
- tv.tv_sec >= expiresat) {
- ret = 3;
- DPRINTF("certificate expired\n");
- goto clean_and_return;
- }
- snprintf(chainedpubkey, sizeof(chainedpubkey) - 1, "%s/%s", tmpdir, "chained-pubkey");
- write_file(chainedpubkey,
- blobmsg_data(payloadtb[CERT_PL_ATTR_PUBKEY]),
- blobmsg_data_len(payloadtb[CERT_PL_ATTR_PUBKEY]),
- false);
- if (usign_f_pubkey(chainedfp, chainedpubkey)) {
- DPRINTF("cannot get fingerprint for chained key\n");
- ret = 2;
- goto clean_and_return;
- }
- if (pubkeydir && _usign_key_is_revoked(chainedfp, pubkeydir)) {
- DPRINTF("key %s has been revoked!\n", chainedfp);
- ret = 4;
- goto clean_and_return;
- }
- } else {
- /* blob doesn't have payload, verify message using signature */
- if (msgfile) {
- snprintf(extsigfile, sizeof(extsigfile) - 1, "%s/%s", tmpdir, "ext-sig");
- write_file(extsigfile,
- blob_data(cobj->cert[CERT_ATTR_SIGNATURE]),
- blob_len(cobj->cert[CERT_ATTR_SIGNATURE]),
- false);
- checkmsg = ret = usign_v(msgfile,
- chainedpubkey[0]?chainedpubkey:pubkeyfile,
- pubkeydir, extsigfile, quiet);
- unlink(extsigfile);
- } else {
- DPRINTF("stray trailing signature without anything to verify!\n");
- ret = 1;
- };
- }
- }
- if (checkmsg == -1)
- DPRINTF("missing signature to verify message!\n");
- clean_and_return:
- if (chainedpubkey[0])
- unlink(chainedpubkey);
- rmdir(tmpdir);
- return ret | checkmsg;
- }
- #ifdef UCERT_FULL
- /* dump single chain element to console */
- static void cert_dump_blob(struct blob_attr *cert[CERT_ATTR_MAX]) {
- int i;
- char *json = NULL;
- for (i = 0; i < CERT_ATTR_MAX; i++) {
- struct blob_attr *v = cert[i];
- if (!v)
- continue;
- switch(cert_policy[i].type) {
- case BLOB_ATTR_BINARY:
- fprintf(stdout, "signature:\n---\n%s---\n", (char *) blob_data(v));
- break;
- case BLOB_ATTR_NESTED:
- json = blobmsg_format_json_indent(blob_data(v), false, 0);
- if (!json) {
- DPRINTF("cannot parse payload\n");
- continue;
- }
- fprintf(stdout, "payload:\n---\n%s\n---\n", json);
- free(json);
- break;
- }
- }
- }
- /* dump certfile to console */
- static int cert_dump(const char *certfile) {
- struct cert_object *cobj;
- static LIST_HEAD(certchain);
- unsigned int count = 0;
- if (cert_load(certfile, &certchain)) {
- DPRINTF("cannot parse cert\n");
- return 1;
- }
- list_for_each_entry(cobj, &certchain, list) {
- fprintf(stdout, "=== CHAIN ELEMENT %02u ===\n", ++count);
- cert_dump_blob(cobj->cert);
- }
- return 0;
- }
- /* issue an auth certificate for pubkey */
- static int cert_issue(const char *certfile, const char *pubkeyfile, const char *seckeyfile) {
- struct blob_buf payloadbuf = {0};
- struct blob_buf certbuf = {0};
- struct timeval tv;
- int pklen, siglen;
- int revoker = 1;
- void *c;
- FILE *pkf, *sigf;
- char pkb[512];
- char sigb[1024];
- char fname[256], sfname[256];
- char pkfp[17];
- char tmpdir[] = "/tmp/ucert-XXXXXX";
- pkf = fopen(pubkeyfile, "r");
- if (!pkf)
- return -1;
- pklen = fread(pkb, 1, 512, pkf);
- pkb[pklen] = '\0';
- if (pklen < 32)
- return -1;
- fclose(pkf);
- if (usign_f_pubkey(pkfp, pubkeyfile))
- return -1;
- gettimeofday(&tv, NULL);
- if (mkdtemp(tmpdir) == NULL)
- return errno;
- while (revoker >= 0) {
- blob_buf_init(&payloadbuf, 0);
- c = blobmsg_open_table(&payloadbuf, "ucert");
- blobmsg_add_u32(&payloadbuf, "certtype", revoker?CERTTYPE_REVOKE:CERTTYPE_AUTH);
- blobmsg_add_u64(&payloadbuf, "validfrom", tv.tv_sec);
- if (!revoker) {
- blobmsg_add_u64(&payloadbuf, "expiresat", tv.tv_sec + 60 * 60 * 24 * 365);
- blobmsg_add_string(&payloadbuf, "pubkey", pkb);
- } else {
- blobmsg_add_string(&payloadbuf, "fingerprint", pkfp);
- }
- blobmsg_close_table(&payloadbuf, c);
- snprintf(fname, sizeof(fname) - 1, "%s/%s", tmpdir, revoker?"revoker":"payload");
- write_file(fname, blob_data(payloadbuf.head), blob_len(payloadbuf.head), false);
- snprintf(sfname, sizeof(sfname) - 1, "%s/%s", tmpdir, revoker?"revoker.sig":"payload.sig");
- if (usign_s(fname, seckeyfile, sfname, quiet))
- return 1;
- sigf = fopen(sfname, "r");
- if (!sigf)
- return 1;
- siglen = fread(sigb, 1, 1024, sigf);
- if (siglen < 1)
- return 1;
- sigb[siglen] = '\0';
- fclose(sigf);
- unlink(fname);
- unlink(sfname);
- blob_buf_init(&certbuf, 0);
- blob_put(&certbuf, CERT_ATTR_SIGNATURE, sigb, siglen);
- blob_put(&certbuf, CERT_ATTR_PAYLOAD, blob_data(payloadbuf.head), blob_len(payloadbuf.head));
- snprintf(fname, sizeof(fname) - 1, "%s%s", certfile, revoker?".revoke":"");
- write_file(fname, certbuf.head, blob_raw_len(certbuf.head), true);
- blob_buf_free(&certbuf);
- blob_buf_free(&payloadbuf);
- revoker--;
- }
- rmdir(tmpdir);
- return 0;
- }
- #endif
- /* process revoker certificate */
- static int cert_process_revoker(const char *certfile, const char *pubkeydir) {
- static LIST_HEAD(certchain);
- struct cert_object *cobj;
- struct blob_attr *containertb[CERT_CT_ATTR_MAX];
- struct blob_attr *payloadtb[CERT_PL_ATTR_MAX];
- struct stat st;
- struct timeval tv;
- time_t validfrom;
- enum certtype_id certtype;
- char *fingerprint;
- char rfname[512];
- int ret = -1;
- if (cert_load(certfile, &certchain)) {
- DPRINTF("cannot parse cert\n");
- return 1;
- }
- gettimeofday(&tv, NULL);
- list_for_each_entry(cobj, &certchain, list) {
- if (!cobj->cert[CERT_ATTR_PAYLOAD])
- return 2;
- /* blob has payload, verify that using signature */
- ret = cert_verify_blob(cobj->cert, NULL, pubkeydir);
- if (ret)
- return ret;
- blobmsg_parse(cert_cont_policy,
- ARRAY_SIZE(cert_cont_policy),
- containertb,
- blob_data(cobj->cert[CERT_ATTR_PAYLOAD]),
- blob_len(cobj->cert[CERT_ATTR_PAYLOAD]));
- if (!containertb[CERT_CT_ATTR_PAYLOAD]) {
- DPRINTF("no ucert in signed payload\n");
- return 2;
- }
- blobmsg_parse(cert_payload_policy,
- ARRAY_SIZE(cert_payload_policy),
- payloadtb,
- blobmsg_data(containertb[CERT_CT_ATTR_PAYLOAD]),
- blobmsg_data_len(containertb[CERT_CT_ATTR_PAYLOAD]));
- if (!payloadtb[CERT_PL_ATTR_CERTTYPE] ||
- !payloadtb[CERT_PL_ATTR_VALIDFROMTIME] ||
- !payloadtb[CERT_PL_ATTR_KEY_FINGERPRINT]) {
- DPRINTF("missing mandatory ucert attributes\n");
- return 2;
- }
- certtype = blobmsg_get_u32(payloadtb[CERT_PL_ATTR_CERTTYPE]);
- validfrom = blobmsg_get_u64(payloadtb[CERT_PL_ATTR_VALIDFROMTIME]);
- fingerprint = blobmsg_get_string(payloadtb[CERT_PL_ATTR_KEY_FINGERPRINT]);
- if (certtype != CERTTYPE_REVOKE) {
- DPRINTF("wrong certificate type\n");
- return 2;
- }
- if (tv.tv_sec < validfrom) {
- return 3;
- }
- snprintf(rfname, sizeof(rfname)-1, "%s/%s", pubkeydir, fingerprint);
- /* check if entry in pubkeydir exists */
- if (stat(rfname, &st) == 0) {
- if (_usign_key_is_revoked(fingerprint, pubkeydir)) {
- DPRINTF("existing revoker deadlink for key %s\n", fingerprint);
- continue;
- };
- /* remove any other entry */
- if (unlink(rfname))
- return -1;
- }
- ret = symlink(".revoked.", rfname);
- if (ret)
- return ret;
- DPRINTF("created revoker deadlink for key %s\n", fingerprint);
- };
- return ret;
- }
- /* load and verify certfile (and message) */
- static int cert_verify(const char *certfile, const char *pubkeyfile, const char *pubkeydir, const char *msgfile) {
- static LIST_HEAD(certchain);
- if (cert_load(certfile, &certchain)) {
- DPRINTF("cannot parse cert\n");
- return 1;
- }
- return chain_verify(msgfile, pubkeyfile, pubkeydir, &certchain);
- }
- /* output help */
- static int usage(const char *cmd)
- {
- #ifndef UCERT_STRIP_MESSAGES
- fprintf(stderr,
- "Usage: %s <command> <options>\n"
- "Commands:\n"
- #ifdef UCERT_FULL
- " -A: append signature (needs -c and -x)\n"
- " -D: dump (needs -c)\n"
- " -I: issue cert and revoker (needs -c and -p and -s)\n"
- #endif /* UCERT_FULL */
- " -R: process revoker certificate (needs -c and -P)\n"
- " -V: verify (needs -c and -p|-P, may have -m)\n"
- "Options:\n"
- " -c <file>: certificate file\n"
- " -m <file>: message file (verify only)\n"
- " -p <file>: public key file\n"
- " -P <path>: public key directory (verify only)\n"
- " -q: quiet (do not print verification result, use return code only)\n"
- #ifdef UCERT_FULL
- " -s <file>: secret key file (issue only)\n"
- " -x <file>: signature file (append only)\n"
- #endif /* UCERT_FULL */
- "\n",
- cmd);
- #endif /* UCERT_STRIP_MESSAGES */
- return 1;
- }
- /* parse command line options and call functions */
- int main(int argc, char *argv[]) {
- int ch;
- const char *msgfile = NULL;
- const char *pubkeyfile = NULL;
- const char *pubkeydir = NULL;
- const char *certfile = NULL;
- #ifdef UCERT_FULL
- const char *sigfile = NULL;
- const char *seckeyfile = NULL;
- #endif
- quiet = false;
- while ((ch = getopt(argc, argv,
- "RVc:m:p:P:q"
- #ifdef UCERT_FULL
- "ADIs:x:"
- #endif
- )) != -1) {
- switch (ch) {
- #ifdef UCERT_FULL
- case 'A':
- if (cmd != CMD_NONE)
- return usage(argv[0]);
- cmd = CMD_APPEND;
- break;
- case 'D':
- if (cmd != CMD_NONE)
- return usage(argv[0]);
- cmd = CMD_DUMP;
- break;
- case 'I':
- if (cmd != CMD_NONE)
- return usage(argv[0]);
- cmd = CMD_ISSUE;
- break;
- #endif
- case 'R':
- if (cmd != CMD_NONE)
- return usage(argv[0]);
- cmd = CMD_REVOKE;
- break;
- case 'V':
- if (cmd != CMD_NONE)
- return usage(argv[0]);
- cmd = CMD_VERIFY;
- break;
- case 'c':
- if (certfile || cmd == CMD_NONE)
- return usage(argv[0]);
- certfile = optarg;
- break;
- case 'm':
- if (msgfile || cmd != CMD_VERIFY)
- return usage(argv[0]);
- msgfile = optarg;
- break;
- case 'p':
- if (pubkeyfile || (cmd != CMD_VERIFY && cmd != CMD_ISSUE) || cmd == CMD_NONE)
- return usage(argv[0]);
- pubkeyfile = optarg;
- break;
- case 'P':
- if (pubkeydir || (cmd != CMD_VERIFY && cmd != CMD_REVOKE) || cmd == CMD_NONE)
- return usage(argv[0]);
- pubkeydir = optarg;
- break;
- case 'q':
- if (quiet)
- return usage(argv[0]);
- quiet = true;
- break;
- #ifdef UCERT_FULL
- case 's':
- if (seckeyfile || cmd != CMD_ISSUE || cmd == CMD_NONE)
- return usage(argv[0]);
- seckeyfile = optarg;
- break;
- case 'x':
- if (sigfile || cmd != CMD_APPEND || cmd == CMD_NONE)
- return usage(argv[0]);
- sigfile = optarg;
- break;
- #endif
- default:
- return usage(argv[0]);
- }
- }
- switch (cmd) {
- #ifdef UCERT_FULL
- case CMD_APPEND:
- if (certfile && sigfile)
- return cert_append(certfile, sigfile);
- else
- return usage(argv[0]);
- case CMD_DUMP:
- if (certfile)
- return cert_dump(certfile);
- else
- return usage(argv[0]);
- case CMD_ISSUE:
- if (certfile && pubkeyfile && seckeyfile)
- return cert_issue(certfile, pubkeyfile, seckeyfile);
- else
- return usage(argv[0]);
- #endif
- case CMD_REVOKE:
- if (certfile && pubkeydir)
- return cert_process_revoker(certfile, pubkeydir);
- else
- return usage(argv[0]);
- case CMD_VERIFY:
- if (certfile && (pubkeyfile || pubkeydir))
- return cert_verify(certfile, pubkeyfile, pubkeydir, msgfile);
- else
- return usage(argv[0]);
- default:
- return usage(argv[0]);
- }
- /* unreachable */
- return usage(argv[0]);
- }
|