ver.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. /* vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80: */
  2. /*
  3. * Copyright 2016 Red Hat, Inc.
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. #include "jws.h"
  18. #include <string.h>
  19. #include <unistd.h>
  20. #define BLOCKS 1024
  21. #define SUMMARY "Verifies a JWS using the supplied JWKs and outputs payload"
  22. typedef struct {
  23. jcmd_opt_io_t io;
  24. json_t *keys;
  25. bool all;
  26. } jcmd_opt_t;
  27. static const char *prefix =
  28. "jose jws ver -i JWS [-I PAY] -k JWK [-a] [-O PAY]\n\n" SUMMARY;
  29. static const jcmd_doc_t doc_all[] = {
  30. { .doc="Ensure the JWS validates with all keys" },
  31. {}
  32. };
  33. static const jcmd_doc_t doc_detach[] = {
  34. { .arg = "FILE", .doc="Decode payload to FILE" },
  35. { .arg = "-", .doc="Decode payload to standard output" },
  36. {}
  37. };
  38. static const jcmd_cfg_t cfgs[] = {
  39. {
  40. .opt = { "input", required_argument, .val = 'i' },
  41. .off = offsetof(jcmd_opt_t, io),
  42. .set = jcmd_opt_io_set_input,
  43. .doc = jcmd_jws_doc_input,
  44. },
  45. {
  46. .opt = { "detached", required_argument, .val = 'I' },
  47. .off = offsetof(jcmd_opt_t, io.detached),
  48. .set = jcmd_opt_set_ifile,
  49. .doc = jcmd_jws_doc_detached,
  50. },
  51. {
  52. .opt = { "key", required_argument, .val = 'k' },
  53. .off = offsetof(jcmd_opt_t, keys),
  54. .set = jcmd_opt_set_jwks,
  55. .doc = jcmd_doc_key,
  56. },
  57. {
  58. .opt = { "detach", required_argument, .val = 'O' },
  59. .off = offsetof(jcmd_opt_t, io.detach),
  60. .set = jcmd_opt_set_ofile,
  61. .doc = doc_detach,
  62. },
  63. {
  64. .opt = { "all", no_argument, .val = 'a' },
  65. .off = offsetof(jcmd_opt_t, all),
  66. .set = jcmd_opt_set_flag,
  67. .doc = doc_all,
  68. },
  69. {}
  70. };
  71. static void
  72. jcmd_opt_cleanup(jcmd_opt_t *sig)
  73. {
  74. jcmd_opt_io_cleanup(&sig->io);
  75. json_decref(sig->keys);
  76. }
  77. static bool
  78. validate_input(const jcmd_opt_t *opt, json_t **sigs)
  79. {
  80. if (json_array_size(opt->keys) == 0) {
  81. fprintf(stderr, "MUST specify a JWK(Set)!\n");
  82. return false;
  83. }
  84. if (!opt->io.obj) {
  85. fprintf(stderr, "Invalid JWS!\n");
  86. return false;
  87. }
  88. *sigs = json_incref(json_object_get(opt->io.obj, "signatures"));
  89. if (!*sigs)
  90. *sigs = json_pack("[O]", opt->io.obj);
  91. if (!json_is_array(*sigs)) {
  92. fprintf(stderr, "Signatures value must be an array!\n");
  93. return false;
  94. }
  95. return true;
  96. }
  97. static int
  98. jcmd_jws_ver(int argc, char *argv[])
  99. {
  100. jcmd_opt_auto_t opt = { .io.fields = jcmd_jws_fields };
  101. jose_io_auto_t *io = NULL;
  102. json_auto_t *sigs = NULL;
  103. if (!jcmd_opt_parse(argc, argv, cfgs, &opt, prefix))
  104. return EXIT_FAILURE;
  105. if (!validate_input(&opt, &sigs))
  106. return EXIT_FAILURE;
  107. io = jose_jws_ver_io(NULL, opt.io.obj, NULL, opt.keys, opt.all);
  108. io = jcmd_jws_prep_io(&opt.io, io);
  109. if (!io) {
  110. fprintf(stderr, "Error initializing signature context!\n");
  111. return EXIT_FAILURE;
  112. }
  113. if (opt.io.detached || opt.io.input) {
  114. FILE *f = opt.io.detached ? opt.io.detached : opt.io.input;
  115. for (int c = fgetc(f); c != EOF; c = fgetc(f)) {
  116. uint8_t b = c;
  117. if (!opt.io.detached && b == '.')
  118. break;
  119. if (!io->feed(io, &b, sizeof(b)))
  120. return EXIT_FAILURE;
  121. }
  122. for (int c = 0; opt.io.detached && opt.io.input && c != EOF && c != '.'; )
  123. c = fgetc(opt.io.input);
  124. } else {
  125. const char *pay = NULL;
  126. size_t payl = 0;
  127. if (json_unpack(opt.io.obj, "{s?s%}", "payload", &pay, &payl) < 0)
  128. return EXIT_FAILURE;
  129. if (!io->feed(io, pay ? pay : "", payl))
  130. return EXIT_FAILURE;
  131. }
  132. if (opt.io.input) {
  133. if (json_object_set_new(opt.io.obj, "signature",
  134. jcmd_compact_field(opt.io.input)) < 0) {
  135. fprintf(stderr, "Error reading last compact field!\n");
  136. return EXIT_FAILURE;
  137. }
  138. }
  139. if (!io->done(io)) {
  140. fprintf(stderr, "Signature validation failed!\n");
  141. return EXIT_FAILURE;
  142. }
  143. return EXIT_SUCCESS;
  144. }
  145. JCMD_REGISTER(SUMMARY, jcmd_jws_ver, "jws", "ver")