fmt.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. /* vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80: */
  2. /*
  3. * Copyright 2017 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 "jwe.h"
  18. #include <string.h>
  19. #include <unistd.h>
  20. #define SUMMARY "Converts a JWE between serialization formats"
  21. static const char *prefix =
  22. "jose jwe fmt -i JWE [-I CT] [-o JWE] [-O CT] [-c]\n\n" SUMMARY;
  23. static const jcmd_cfg_t cfgs[] = {
  24. {
  25. .opt = { "input", required_argument, .val = 'i' },
  26. .set = jcmd_opt_io_set_input,
  27. .doc = jcmd_jwe_doc_input,
  28. },
  29. {
  30. .opt = { "detached", required_argument, .val = 'I' },
  31. .off = offsetof(jcmd_opt_io_t, detached),
  32. .set = jcmd_opt_set_ifile,
  33. .doc = jcmd_jwe_doc_detached,
  34. },
  35. {
  36. .opt = { "output", required_argument, .val = 'o' },
  37. .off = offsetof(jcmd_opt_io_t, output),
  38. .set = jcmd_opt_set_ofile,
  39. .doc = jcmd_jwe_doc_input,
  40. .def = "-",
  41. },
  42. {
  43. .opt = { "detach", required_argument, .val = 'O' },
  44. .off = offsetof(jcmd_opt_io_t, detach),
  45. .set = jcmd_opt_set_ofile,
  46. .doc = jcmd_jwe_doc_input,
  47. },
  48. {
  49. .opt = { "compact", no_argument, .val = 'c' },
  50. .off = offsetof(jcmd_opt_io_t, compact),
  51. .set = jcmd_opt_set_flag,
  52. .doc = jcmd_jwe_doc_compact,
  53. },
  54. {}
  55. };
  56. static int
  57. jcmd_jwe_fmt(int argc, char *argv[])
  58. {
  59. jcmd_opt_io_auto_t opt = { .fields = jcmd_jwe_fields };
  60. jose_io_auto_t *io = NULL;
  61. if (!jcmd_opt_parse(argc, argv, cfgs, &opt, prefix))
  62. return EXIT_FAILURE;
  63. if (opt.detach) {
  64. io = jose_io_file(NULL, opt.detach);
  65. } else {
  66. jose_io_auto_t *b64 = NULL;
  67. io = jose_io_file(NULL, opt.output);
  68. if (!io)
  69. return EXIT_FAILURE;
  70. b64 = jose_b64_enc_io(io);
  71. if (!b64)
  72. return EXIT_FAILURE;
  73. jose_io_auto(&io);
  74. io = jose_io_incref(b64);
  75. }
  76. if (!opt.detached) {
  77. jose_io_auto_t *b64 = NULL;
  78. b64 = jose_b64_dec_io(io);
  79. if (!b64)
  80. return EXIT_FAILURE;
  81. jose_io_auto(&io);
  82. io = jose_io_incref(b64);
  83. }
  84. if (opt.compact) {
  85. for (size_t i = 0; strcmp(opt.fields[i].name, "ciphertext") != 0; i++) {
  86. const jcmd_field_t *f = &opt.fields[i];
  87. const char *k = f->name;
  88. const char *v = NULL;
  89. if (json_unpack(opt.obj, "{s:[{s?s}!]}", f->mult, k, &v) < 0 &&
  90. json_unpack(opt.obj, "{s?s}", k, &v) < 0) {
  91. fprintf(stderr, "Input JWS cannot be converted to compact.\n");
  92. return EXIT_FAILURE;
  93. }
  94. fprintf(opt.output, "%s.", v ? v : "");
  95. }
  96. } else {
  97. fprintf(opt.output, "{");
  98. if (!opt.detach)
  99. fprintf(opt.output, "\"ciphertext\":\"");
  100. }
  101. if (opt.detached || opt.input) {
  102. FILE *f = opt.detached ? opt.detached : opt.input;
  103. for (int c = fgetc(f); c != EOF; c = fgetc(f)) {
  104. uint8_t b = c;
  105. if (!opt.detached && b == '.')
  106. break;
  107. if (!io->feed(io, &b, sizeof(b)))
  108. return EXIT_FAILURE;
  109. }
  110. for (int c = 0; opt.detached && opt.input && c != EOF && c != '.'; )
  111. c = fgetc(opt.input);
  112. } else {
  113. const char *ct = NULL;
  114. size_t ctl = 0;
  115. if (json_unpack(opt.obj, "{s:s%}", "ciphertext", &ct, &ctl) < 0)
  116. return EXIT_FAILURE;
  117. if (!io->feed(io, ct, ctl))
  118. return EXIT_FAILURE;
  119. }
  120. if (!io->done(io))
  121. return EXIT_FAILURE;
  122. if (opt.input) {
  123. if (json_object_set_new(opt.obj, "tag",
  124. jcmd_compact_field(opt.input)) < 0) {
  125. fprintf(stderr, "Error reading last compact field!\n");
  126. return EXIT_FAILURE;
  127. }
  128. }
  129. if (opt.compact) {
  130. const char *v = NULL;
  131. if (json_unpack(opt.obj, "{s:s}", "tag", &v) < 0 &&
  132. json_unpack(opt.obj, "{s:[{s:s}!]}", "recipients", "tag", &v) < 0) {
  133. fprintf(stderr, "Missing tag parameter!\n");
  134. return EXIT_FAILURE;
  135. }
  136. fprintf(opt.output, ".%s", v);
  137. } else {
  138. if (!opt.detach)
  139. fprintf(opt.output, "\",");
  140. json_dumpf(opt.obj, opt.output,
  141. JSON_EMBED | JSON_COMPACT | JSON_SORT_KEYS);
  142. fprintf(opt.output, "}");
  143. }
  144. if (isatty(fileno(opt.output)))
  145. fprintf(opt.output, "\n");
  146. return EXIT_SUCCESS;
  147. }
  148. JCMD_REGISTER(SUMMARY, jcmd_jwe_fmt, "jwe", "fmt")