1 /* 2 * Copyright (C) 2018 Daniel Golle <daniel@makrotopia.org> 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License version 3 6 * as published by the Free Software Foundation 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU General Public License for more details. 12 */ 13 14 #define _GNU_SOURCE 15 16 #include <fcntl.h> 17 #include <dlfcn.h> 18 #include <errno.h> 19 #include <stdio.h> 20 #include <stdbool.h> 21 #include <stdlib.h> 22 #include <string.h> 23 #include <getopt.h> 24 #include <stdint.h> 25 #include <unistd.h> 26 #include <inttypes.h> 27 #include <sys/stat.h> 28 #include <sys/wait.h> 29 30 #include <json-c/json.h> 31 #include <libubox/blob.h> 32 #include <libubox/utils.h> 33 #include <libubox/list.h> 34 #include <libubox/vlist.h> 35 #include <libubox/blobmsg_json.h> 36 37 #include "usign.h" 38 39 #define CERT_BUF_LEN 4096 40 41 static enum { 42 CMD_APPEND, 43 CMD_DUMP, 44 CMD_ISSUE, 45 CMD_REVOKE, 46 CMD_VERIFY, 47 CMD_NONE, 48 } cmd = CMD_NONE; 49 50 static bool quiet; 51 #ifndef UCERT_STRIP_MESSAGES 52 #define DPRINTF(format, ...) \ 53 do { \ 54 if (!quiet) \ 55 fprintf(stderr, "%s: " format, __func__, ## __VA_ARGS__); \ 56 } while (0) 57 #else 58 #define DPRINTF(format, ...) do { } while (0) 59 #endif 60 61 /* 62 * ucert structure 63 * | BLOB | 64 * | SIGNATURE | PAYLOAD | 65 * | |[ BLOBMSG CONTAINER ]| 66 * | |[[T,i,v,e,f,pubkey ]]| 67 */ 68 enum cert_attr { 69 CERT_ATTR_SIGNATURE, 70 CERT_ATTR_PAYLOAD, 71 CERT_ATTR_MAX 72 }; 73 74 static const struct blob_attr_info cert_policy[CERT_ATTR_MAX] = { 75 [CERT_ATTR_SIGNATURE] = { .type = BLOB_ATTR_BINARY }, 76 [CERT_ATTR_PAYLOAD] = { .type = BLOB_ATTR_NESTED }, 77 }; 78 79 enum cert_cont_attr { 80 CERT_CT_ATTR_PAYLOAD, 81 CERT_CT_ATTR_MAX 82 }; 83 84 static const struct blobmsg_policy cert_cont_policy[CERT_CT_ATTR_MAX] = { 85 [CERT_CT_ATTR_PAYLOAD] = { .name = "ucert", .type = BLOBMSG_TYPE_TABLE }, 86 }; 87 88 enum cert_payload_attr { 89 CERT_PL_ATTR_CERTTYPE, 90 CERT_PL_ATTR_CERTID, 91 CERT_PL_ATTR_VALIDFROMTIME, 92 CERT_PL_ATTR_EXPIRETIME, 93 CERT_PL_ATTR_PUBKEY, 94 CERT_PL_ATTR_KEY_FINGERPRINT, 95 CERT_PL_ATTR_MAX 96 }; 97 98 enum certtype_id { 99 CERTTYPE_UNSPEC, 100 CERTTYPE_AUTH, 101 CERTTYPE_REVOKE 102 }; 103 104 static const struct blobmsg_policy cert_payload_policy[CERT_PL_ATTR_MAX] = { 105 [CERT_PL_ATTR_CERTTYPE] = { .name = "certtype", .type = BLOBMSG_TYPE_INT32 }, 106 [CERT_PL_ATTR_CERTID] = { .name = "certid", .type = BLOBMSG_TYPE_INT32 }, 107 [CERT_PL_ATTR_VALIDFROMTIME] = { .name = "validfrom", .type = BLOBMSG_TYPE_INT64 }, 108 [CERT_PL_ATTR_EXPIRETIME] = { .name = "expiresat", .type = BLOBMSG_TYPE_INT64 }, 109 [CERT_PL_ATTR_PUBKEY] = { .name = "pubkey", .type = BLOBMSG_TYPE_STRING }, 110 [CERT_PL_ATTR_KEY_FINGERPRINT] = { .name = "fingerprint", .type = BLOBMSG_TYPE_STRING }, 111 }; 112 113 /* list to store certificate chain at runtime */ 114 struct cert_object { 115 struct list_head list; 116 struct blob_attr *cert[CERT_ATTR_MAX]; 117 }; 118 119 /* write buffer to file */ 120 static bool write_file(const char *filename, void *buf, size_t len, bool append) { 121 FILE *f; 122 size_t outlen; 123 124 f = fopen(filename, append?"a":"w"); 125 if (!f) 126 return false; 127 128 outlen = fwrite(buf, 1, len, f); 129 fclose(f); 130 return (outlen == len); 131 } 132 133 /* reads a whole file to a buffer - returns -1 on errors and sets errno */ 134 static ssize_t read_file(const char *filename, void *buf, size_t len, size_t minlen) { 135 FILE *f; 136 ssize_t ret; 137 138 f = fopen(filename, "r"); 139 if (!f) 140 return -1; 141 142 ret = fread(buf, 1, len, f); 143 144 /* Ensure that feof() yields the correct result when the file is exactly 145 * len bytes long */ 146 fgetc(f); 147 148 if (ferror(f)) { 149 ret = -1; 150 } else if (!feof(f)) { 151 errno = EOVERFLOW; 152 ret = -1; 153 } else if ((size_t)ret < minlen) { 154 errno = EINVAL; 155 ret = -1; 156 } 157 158 fclose(f); 159 return ret; 160 } 161 162 /* load certfile into list */ 163 static int cert_load(const char *certfile, struct list_head *chain) { 164 struct blob_attr *certtb[CERT_ATTR_MAX]; 165 struct blob_attr *bufpt; 166 struct cert_object *cobj; 167 char filebuf[CERT_BUF_LEN], *end; 168 int ret = 1; 169 ssize_t len; 170 171 len = read_file(certfile, filebuf, sizeof(filebuf) - 1, 0); 172 if (len < 0) { 173 if (!quiet) 174 perror("Unable to load certificate file"); 175 return 1; 176 } 177 178 bufpt = (struct blob_attr *)filebuf; 179 end = filebuf + len; 180 181 while (true) { 182 len = end - (char *)bufpt; 183 if (len <= 0) 184 break; 185 186 if (blob_parse_untrusted(bufpt, len, certtb, cert_policy, CERT_ATTR_MAX) <= 0) 187 /* no attributes found */ 188 break; 189 190 if (!certtb[CERT_ATTR_SIGNATURE]) 191 /* no signature -> drop */ 192 break; 193 194 cobj = calloc(1, sizeof(*cobj)); 195 cobj->cert[CERT_ATTR_SIGNATURE] = blob_memdup(certtb[CERT_ATTR_SIGNATURE]); 196 if (certtb[CERT_ATTR_PAYLOAD]) 197 cobj->cert[CERT_ATTR_PAYLOAD] = blob_memdup(certtb[CERT_ATTR_PAYLOAD]); 198 199 list_add_tail(&cobj->list, chain); 200 ret = 0; 201 202 /* Repeat parsing while there is still enough remaining data in buffer 203 * 204 * Note that blob_next() is only valid for untrusted data because blob_parse_untrusted() 205 * verified that the buffer contains at least one blob, and that it is completely contained 206 * in the buffer */ 207 bufpt = blob_next(bufpt); 208 } 209 210 return ret; 211 } 212 213 #ifdef UCERT_FULL 214 /* append signature to certfile */ 215 static int cert_append(const char *certfile, const char *sigfile) { 216 char filebuf[CERT_BUF_LEN]; 217 struct blob_buf sigbuf = {0}; 218 ssize_t len; 219 int ret; 220 221 len = read_file(sigfile, filebuf, sizeof(filebuf) - 1, 64); 222 if (len < 0) { 223 if (!quiet) 224 perror("Unable to load signature file"); 225 226 return 1; 227 } 228 229 blob_buf_init(&sigbuf, 0); 230 blob_put(&sigbuf, CERT_ATTR_SIGNATURE, filebuf, len); 231 ret = write_file(certfile, sigbuf.head, blob_raw_len(sigbuf.head), true); 232 blob_buf_free(&sigbuf); 233 return ret; 234 } 235 #endif 236 237 /* verify the signature of a single chain element */ 238 static int cert_verify_blob(struct blob_attr *cert[CERT_ATTR_MAX], 239 const char *pubkeyfile, const char *pubkeydir) { 240 int i; 241 char msgfname[256], sigfname[256]; 242 int ret; 243 char tmpdir[] = "/tmp/ucert-XXXXXX"; 244 245 if (mkdtemp(tmpdir) == NULL) 246 return errno; 247 248 snprintf(msgfname, sizeof(msgfname) - 1, "%s/%s", tmpdir, "payload"); 249 snprintf(sigfname, sizeof(sigfname) - 1, "%s/%s", tmpdir, "payload.sig"); 250 251 for (i = 0; i < CERT_ATTR_MAX; i++) { 252 struct blob_attr *v = cert[i]; 253 254 if (!v) 255 break; 256 257 switch(cert_policy[i].type) { 258 case BLOB_ATTR_BINARY: 259 write_file(sigfname, blob_data(v), blob_len(v), false); 260 break; 261 case BLOB_ATTR_NESTED: 262 write_file(msgfname, blob_data(v), blob_len(v), false); 263 break; 264 } 265 } 266 267 ret = usign_v(msgfname, pubkeyfile, pubkeydir, sigfname, quiet); 268 269 unlink(msgfname); 270 unlink(sigfname); 271 rmdir(tmpdir); 272 273 return ret; 274 } 275 276 /* verify cert chain (and message) */ 277 static int chain_verify(const char *msgfile, const char *pubkeyfile, 278 const char *pubkeydir, struct list_head *chain) { 279 struct cert_object *cobj; 280 struct blob_attr *containertb[CERT_CT_ATTR_MAX]; 281 struct blob_attr *payloadtb[CERT_PL_ATTR_MAX]; 282 char tmpdir[] = "/tmp/ucert-XXXXXX"; 283 char chainedpubkey[256] = {0}; 284 char chainedfp[17] = {0}; 285 char extsigfile[256] = {0}; 286 int ret = 1; 287 int checkmsg = 0; 288 struct timeval tv; 289 290 if (mkdtemp(tmpdir) == NULL) 291 return errno; 292 293 if (msgfile) 294 checkmsg = -1; 295 296 gettimeofday(&tv, NULL); 297 298 list_for_each_entry(cobj, chain, list) { 299 /* blob has payload, verify that using signature */ 300 if (cobj->cert[CERT_ATTR_PAYLOAD]) { 301 time_t validfrom; 302 time_t expiresat; 303 uint32_t certtype; 304 305 ret = cert_verify_blob(cobj->cert, chainedpubkey[0]?chainedpubkey:pubkeyfile, pubkeydir); 306 if (ret) 307 goto clean_and_return; 308 309 blobmsg_parse(cert_cont_policy, 310 ARRAY_SIZE(cert_cont_policy), 311 containertb, 312 blob_data(cobj->cert[CERT_ATTR_PAYLOAD]), 313 blob_len(cobj->cert[CERT_ATTR_PAYLOAD])); 314 if (!containertb[CERT_CT_ATTR_PAYLOAD]) { 315 ret = 1; 316 DPRINTF("no ucert in signed payload\n"); 317 goto clean_and_return; 318 } 319 blobmsg_parse(cert_payload_policy, 320 ARRAY_SIZE(cert_payload_policy), 321 payloadtb, 322 blobmsg_data(containertb[CERT_CT_ATTR_PAYLOAD]), 323 blobmsg_data_len(containertb[CERT_CT_ATTR_PAYLOAD])); 324 325 if (!payloadtb[CERT_PL_ATTR_CERTTYPE] || 326 !payloadtb[CERT_PL_ATTR_VALIDFROMTIME] || 327 !payloadtb[CERT_PL_ATTR_EXPIRETIME] || 328 !payloadtb[CERT_PL_ATTR_PUBKEY]) { 329 ret = 1; 330 DPRINTF("missing mandatory ucert attributes\n"); 331 goto clean_and_return; 332 } 333 certtype = blobmsg_get_u32(payloadtb[CERT_PL_ATTR_CERTTYPE]); 334 validfrom = blobmsg_get_u64(payloadtb[CERT_PL_ATTR_VALIDFROMTIME]); 335 expiresat = blobmsg_get_u64(payloadtb[CERT_PL_ATTR_EXPIRETIME]); 336 337 if (certtype != CERTTYPE_AUTH) { 338 ret = 2; 339 DPRINTF("wrong certificate type\n"); 340 goto clean_and_return; 341 } 342 343 if (tv.tv_sec < validfrom || 344 tv.tv_sec >= expiresat) { 345 ret = 3; 346 DPRINTF("certificate expired\n"); 347 goto clean_and_return; 348 } 349 350 snprintf(chainedpubkey, sizeof(chainedpubkey) - 1, "%s/%s", tmpdir, "chained-pubkey"); 351 write_file(chainedpubkey, 352 blobmsg_data(payloadtb[CERT_PL_ATTR_PUBKEY]), 353 blobmsg_data_len(payloadtb[CERT_PL_ATTR_PUBKEY]), 354 false); 355 356 if (usign_f_pubkey(chainedfp, chainedpubkey, quiet)) { 357 DPRINTF("cannot get fingerprint for chained key\n"); 358 ret = 2; 359 goto clean_and_return; 360 } 361 if (pubkeydir && _usign_key_is_revoked(chainedfp, pubkeydir)) { 362 DPRINTF("key %s has been revoked!\n", chainedfp); 363 ret = 4; 364 goto clean_and_return; 365 } 366 } else { 367 /* blob doesn't have payload, verify message using signature */ 368 if (msgfile) { 369 snprintf(extsigfile, sizeof(extsigfile) - 1, "%s/%s", tmpdir, "ext-sig"); 370 write_file(extsigfile, 371 blob_data(cobj->cert[CERT_ATTR_SIGNATURE]), 372 blob_len(cobj->cert[CERT_ATTR_SIGNATURE]), 373 false); 374 checkmsg = ret = usign_v(msgfile, 375 chainedpubkey[0]?chainedpubkey:pubkeyfile, 376 pubkeydir, extsigfile, quiet); 377 unlink(extsigfile); 378 } else { 379 DPRINTF("stray trailing signature without anything to verify!\n"); 380 ret = 1; 381 }; 382 } 383 } 384 385 if (checkmsg == -1) 386 DPRINTF("missing signature to verify message!\n"); 387 388 clean_and_return: 389 if (chainedpubkey[0]) 390 unlink(chainedpubkey); 391 rmdir(tmpdir); 392 return ret | checkmsg; 393 } 394 395 #ifdef UCERT_FULL 396 /* dump single chain element to console */ 397 static void cert_dump_blob(struct blob_attr *cert[CERT_ATTR_MAX]) { 398 int i; 399 char *json = NULL; 400 401 for (i = 0; i < CERT_ATTR_MAX; i++) { 402 struct blob_attr *v = cert[i]; 403 404 if (!v) 405 continue; 406 407 switch(cert_policy[i].type) { 408 case BLOB_ATTR_BINARY: 409 printf("signature:\n---\n%s---\n", (char *) blob_data(v)); 410 break; 411 case BLOB_ATTR_NESTED: 412 json = blobmsg_format_json_indent(blob_data(v), false, 0); 413 if (!json) { 414 DPRINTF("cannot parse payload\n"); 415 continue; 416 } 417 printf("payload:\n---\n%s\n---\n", json); 418 free(json); 419 break; 420 } 421 } 422 } 423 424 /* dump certfile to console */ 425 static int cert_dump(const char *certfile) { 426 struct cert_object *cobj; 427 static LIST_HEAD(certchain); 428 unsigned int count = 0; 429 430 if (cert_load(certfile, &certchain)) { 431 DPRINTF("cannot parse cert\n"); 432 return 1; 433 } 434 435 list_for_each_entry(cobj, &certchain, list) { 436 printf("=== CHAIN ELEMENT %02u ===\n", ++count); 437 cert_dump_blob(cobj->cert); 438 } 439 440 return 0; 441 } 442 443 /* issue an auth certificate for pubkey */ 444 static int cert_issue(const char *certfile, const char *pubkeyfile, const char *seckeyfile) { 445 struct blob_buf payloadbuf = {0}; 446 struct blob_buf certbuf = {0}; 447 struct timeval tv; 448 ssize_t pklen, siglen; 449 int revoker = 1; 450 void *c; 451 char pkb[512]; 452 char sigb[1024]; 453 char fname[256], sfname[256]; 454 char pkfp[17]; 455 char tmpdir[] = "/tmp/ucert-XXXXXX"; 456 457 pklen = read_file(pubkeyfile, pkb, sizeof(pkb) - 1, 32); 458 if (pklen < 0) { 459 if (!quiet) 460 perror("Unable to load public key file"); 461 462 return -1; 463 } 464 465 pkb[pklen] = '\0'; 466 467 if (usign_f_pubkey(pkfp, pubkeyfile, quiet)) 468 return -1; 469 470 gettimeofday(&tv, NULL); 471 472 if (mkdtemp(tmpdir) == NULL) 473 return errno; 474 475 while (revoker >= 0) { 476 blob_buf_init(&payloadbuf, 0); 477 c = blobmsg_open_table(&payloadbuf, "ucert"); 478 blobmsg_add_u32(&payloadbuf, "certtype", revoker?CERTTYPE_REVOKE:CERTTYPE_AUTH); 479 blobmsg_add_u64(&payloadbuf, "validfrom", tv.tv_sec); 480 if (!revoker) { 481 blobmsg_add_u64(&payloadbuf, "expiresat", tv.tv_sec + 60 * 60 * 24 * 365); 482 blobmsg_add_string(&payloadbuf, "pubkey", pkb); 483 } else { 484 blobmsg_add_string(&payloadbuf, "fingerprint", pkfp); 485 } 486 487 blobmsg_close_table(&payloadbuf, c); 488 489 snprintf(fname, sizeof(fname) - 1, "%s/%s", tmpdir, revoker?"revoker":"payload"); 490 write_file(fname, blob_data(payloadbuf.head), blob_len(payloadbuf.head), false); 491 492 snprintf(sfname, sizeof(sfname) - 1, "%s/%s", tmpdir, revoker?"revoker.sig":"payload.sig"); 493 if (usign_s(fname, seckeyfile, sfname, quiet)) 494 return 1; 495 496 siglen = read_file(sfname, sigb, sizeof(sigb) - 1, 1); 497 if (siglen < 0) { 498 if (!quiet) 499 perror("Unable to load signature file"); 500 501 return 1; 502 } 503 504 sigb[siglen] = '\0'; 505 506 unlink(fname); 507 unlink(sfname); 508 509 blob_buf_init(&certbuf, 0); 510 blob_put(&certbuf, CERT_ATTR_SIGNATURE, sigb, siglen); 511 blob_put(&certbuf, CERT_ATTR_PAYLOAD, blob_data(payloadbuf.head), blob_len(payloadbuf.head)); 512 snprintf(fname, sizeof(fname) - 1, "%s%s", certfile, revoker?".revoke":""); 513 write_file(fname, certbuf.head, blob_raw_len(certbuf.head), true); 514 blob_buf_free(&certbuf); 515 blob_buf_free(&payloadbuf); 516 517 revoker--; 518 } 519 520 rmdir(tmpdir); 521 522 return 0; 523 } 524 #endif 525 526 /* process revoker certificate */ 527 static int cert_process_revoker(const char *certfile, const char *pubkeydir) { 528 static LIST_HEAD(certchain); 529 struct cert_object *cobj; 530 struct blob_attr *containertb[CERT_CT_ATTR_MAX]; 531 struct blob_attr *payloadtb[CERT_PL_ATTR_MAX]; 532 struct stat st; 533 struct timeval tv; 534 time_t validfrom; 535 enum certtype_id certtype; 536 char *fingerprint; 537 char rfname[512]; 538 539 int ret = -1; 540 541 if (cert_load(certfile, &certchain)) { 542 DPRINTF("cannot parse cert\n"); 543 return 1; 544 } 545 546 gettimeofday(&tv, NULL); 547 548 list_for_each_entry(cobj, &certchain, list) { 549 if (!cobj->cert[CERT_ATTR_PAYLOAD]) 550 return 2; 551 552 /* blob has payload, verify that using signature */ 553 ret = cert_verify_blob(cobj->cert, NULL, pubkeydir); 554 if (ret) 555 return ret; 556 557 blobmsg_parse(cert_cont_policy, 558 ARRAY_SIZE(cert_cont_policy), 559 containertb, 560 blob_data(cobj->cert[CERT_ATTR_PAYLOAD]), 561 blob_len(cobj->cert[CERT_ATTR_PAYLOAD])); 562 if (!containertb[CERT_CT_ATTR_PAYLOAD]) { 563 DPRINTF("no ucert in signed payload\n"); 564 return 2; 565 } 566 567 blobmsg_parse(cert_payload_policy, 568 ARRAY_SIZE(cert_payload_policy), 569 payloadtb, 570 blobmsg_data(containertb[CERT_CT_ATTR_PAYLOAD]), 571 blobmsg_data_len(containertb[CERT_CT_ATTR_PAYLOAD])); 572 573 if (!payloadtb[CERT_PL_ATTR_CERTTYPE] || 574 !payloadtb[CERT_PL_ATTR_VALIDFROMTIME] || 575 !payloadtb[CERT_PL_ATTR_KEY_FINGERPRINT]) { 576 DPRINTF("missing mandatory ucert attributes\n"); 577 return 2; 578 } 579 580 certtype = blobmsg_get_u32(payloadtb[CERT_PL_ATTR_CERTTYPE]); 581 validfrom = blobmsg_get_u64(payloadtb[CERT_PL_ATTR_VALIDFROMTIME]); 582 fingerprint = blobmsg_get_string(payloadtb[CERT_PL_ATTR_KEY_FINGERPRINT]); 583 584 if (certtype != CERTTYPE_REVOKE) { 585 DPRINTF("wrong certificate type\n"); 586 return 2; 587 } 588 589 if (tv.tv_sec < validfrom) { 590 return 3; 591 } 592 593 snprintf(rfname, sizeof(rfname)-1, "%s/%s", pubkeydir, fingerprint); 594 /* check if entry in pubkeydir exists */ 595 if (stat(rfname, &st) == 0) { 596 if (_usign_key_is_revoked(fingerprint, pubkeydir)) { 597 DPRINTF("existing revoker deadlink for key %s\n", fingerprint); 598 continue; 599 }; 600 601 /* remove any other entry */ 602 if (unlink(rfname)) 603 return -1; 604 } 605 606 ret = symlink(".revoked.", rfname); 607 if (ret) 608 return ret; 609 610 DPRINTF("created revoker deadlink for key %s\n", fingerprint); 611 }; 612 613 return ret; 614 } 615 616 /* load and verify certfile (and message) */ 617 static int cert_verify(const char *certfile, const char *pubkeyfile, const char *pubkeydir, const char *msgfile) { 618 static LIST_HEAD(certchain); 619 620 if (cert_load(certfile, &certchain)) { 621 DPRINTF("cannot parse cert\n"); 622 return 1; 623 } 624 625 return chain_verify(msgfile, pubkeyfile, pubkeydir, &certchain); 626 } 627 628 /* output help */ 629 static int usage(const char *cmd) 630 { 631 #ifndef UCERT_STRIP_MESSAGES 632 fprintf(stderr, 633 "Usage: %s <command> <options>\n" 634 "Commands:\n" 635 #ifdef UCERT_FULL 636 " -A: append signature (needs -c and -x)\n" 637 " -D: dump (needs -c)\n" 638 " -I: issue cert and revoker (needs -c and -p and -s)\n" 639 #endif /* UCERT_FULL */ 640 " -R: process revoker certificate (needs -c and -P)\n" 641 " -V: verify (needs -c and -p|-P, may have -m)\n" 642 "Options:\n" 643 " -c <file>: certificate file\n" 644 " -m <file>: message file (verify only)\n" 645 " -p <file>: public key file\n" 646 " -P <path>: public key directory (verify only)\n" 647 " -q: quiet (do not print verification result, use return code only)\n" 648 #ifdef UCERT_FULL 649 " -s <file>: secret key file (issue only)\n" 650 " -x <file>: signature file (append only)\n" 651 #endif /* UCERT_FULL */ 652 "\n", 653 cmd); 654 #endif /* UCERT_STRIP_MESSAGES */ 655 return 1; 656 } 657 658 /* parse command line options and call functions */ 659 int main(int argc, char *argv[]) { 660 int ch; 661 const char *msgfile = NULL; 662 const char *pubkeyfile = NULL; 663 const char *pubkeydir = NULL; 664 const char *certfile = NULL; 665 #ifdef UCERT_FULL 666 const char *sigfile = NULL; 667 const char *seckeyfile = NULL; 668 #endif 669 670 quiet = false; 671 while ((ch = getopt(argc, argv, 672 "RVc:m:p:P:q" 673 #ifdef UCERT_FULL 674 "ADIs:x:" 675 #endif 676 )) != -1) { 677 switch (ch) { 678 #ifdef UCERT_FULL 679 case 'A': 680 if (cmd != CMD_NONE) 681 return usage(argv[0]); 682 cmd = CMD_APPEND; 683 break; 684 case 'D': 685 if (cmd != CMD_NONE) 686 return usage(argv[0]); 687 cmd = CMD_DUMP; 688 break; 689 case 'I': 690 if (cmd != CMD_NONE) 691 return usage(argv[0]); 692 cmd = CMD_ISSUE; 693 break; 694 #endif 695 case 'R': 696 if (cmd != CMD_NONE) 697 return usage(argv[0]); 698 cmd = CMD_REVOKE; 699 break; 700 case 'V': 701 if (cmd != CMD_NONE) 702 return usage(argv[0]); 703 cmd = CMD_VERIFY; 704 break; 705 case 'c': 706 if (certfile || cmd == CMD_NONE) 707 return usage(argv[0]); 708 certfile = optarg; 709 break; 710 case 'm': 711 if (msgfile || cmd != CMD_VERIFY) 712 return usage(argv[0]); 713 msgfile = optarg; 714 break; 715 case 'p': 716 if (pubkeyfile || (cmd != CMD_VERIFY && cmd != CMD_ISSUE) || cmd == CMD_NONE) 717 return usage(argv[0]); 718 pubkeyfile = optarg; 719 break; 720 case 'P': 721 if (pubkeydir || (cmd != CMD_VERIFY && cmd != CMD_REVOKE) || cmd == CMD_NONE) 722 return usage(argv[0]); 723 pubkeydir = optarg; 724 break; 725 case 'q': 726 if (quiet) 727 return usage(argv[0]); 728 quiet = true; 729 break; 730 #ifdef UCERT_FULL 731 case 's': 732 if (seckeyfile || cmd != CMD_ISSUE || cmd == CMD_NONE) 733 return usage(argv[0]); 734 seckeyfile = optarg; 735 break; 736 case 'x': 737 if (sigfile || cmd != CMD_APPEND || cmd == CMD_NONE) 738 return usage(argv[0]); 739 sigfile = optarg; 740 break; 741 #endif 742 default: 743 return usage(argv[0]); 744 } 745 } 746 747 switch (cmd) { 748 #ifdef UCERT_FULL 749 case CMD_APPEND: 750 if (certfile && sigfile) 751 return cert_append(certfile, sigfile); 752 else 753 return usage(argv[0]); 754 case CMD_DUMP: 755 if (certfile) 756 return cert_dump(certfile); 757 else 758 return usage(argv[0]); 759 case CMD_ISSUE: 760 if (certfile && pubkeyfile && seckeyfile) 761 return cert_issue(certfile, pubkeyfile, seckeyfile); 762 else 763 return usage(argv[0]); 764 #endif 765 case CMD_REVOKE: 766 if (certfile && pubkeydir) 767 return cert_process_revoker(certfile, pubkeydir); 768 else 769 return usage(argv[0]); 770 case CMD_VERIFY: 771 if (certfile && (pubkeyfile || pubkeydir)) 772 return cert_verify(certfile, pubkeyfile, pubkeydir, msgfile); 773 else 774 return usage(argv[0]); 775 default: 776 return usage(argv[0]); 777 } 778 779 /* unreachable */ 780 return usage(argv[0]); 781 } 782
This page was automatically generated by LXR 0.3.1. • OpenWrt