test-keys.c.in 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. /* vim: set tabstop=8 shiftwidth=4 softtabstop=4 expandtab smarttab colorcolumn=80: */
  2. /*
  3. * Copyright (c) 2020 Red Hat, Inc.
  4. * Author: Sergio Correia <scorreia@redhat.com>
  5. *
  6. * This program is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include "keys.c"
  20. #include "test-util.h"
  21. const char* jwkdir = "@testjwkdir@";
  22. struct thp_result {
  23. const char* thp;
  24. int valid;
  25. };
  26. struct test_result_int {
  27. const char* data;
  28. int expected;
  29. };
  30. static void
  31. test_create_new_keys(void)
  32. {
  33. __attribute__((cleanup(cleanup_str))) char* newdir = create_tempdir();
  34. ASSERT(newdir);
  35. __attribute__((cleanup(cleanup_tang_keys_info))) struct tang_keys_info* tki = read_keys(newdir);
  36. ASSERT(tki);
  37. ASSERT(tki->m_keys_count == 2);
  38. remove_tempdir(newdir);
  39. }
  40. static void
  41. test_is_hash(void)
  42. {
  43. const struct test_result_int test_data[] = {
  44. {NULL, 0},
  45. {"", 0},
  46. {"ES512", 0},
  47. {"ECMR", 0},
  48. {"foobar", 0},
  49. {"{", 0},
  50. {"[}", 0},
  51. {"[]", 0},
  52. {"S1", 1},
  53. {"S224", 1},
  54. {"S256", 1},
  55. {"S384", 1},
  56. {"S512", 1},
  57. {"S42", 0}
  58. };
  59. for (int i = 0, len = ARRAY_COUNT(test_data); i < len; i++) {
  60. int ret = is_hash(test_data[i].data);
  61. ASSERT_WITH_MSG(ret == test_data[i].expected, "i = %d, alg = %s", i, test_data[i].data);
  62. };
  63. }
  64. static void
  65. test_jwk_generate(void)
  66. {
  67. const struct test_result_int test_data[] = {
  68. {NULL, 0},
  69. {"", 0},
  70. {"ES512", 1},
  71. {"ECMR", 1},
  72. {"foobar", 0},
  73. {"{", 0},
  74. {"[}", 0},
  75. {"[]", 0}
  76. };
  77. for (int i = 0, len = ARRAY_COUNT(test_data); i < len; i++) {
  78. json_auto_t* jwk = jwk_generate(test_data[i].data);
  79. ASSERT_WITH_MSG(!!jwk == test_data[i].expected, "i = %d, alg = %s", i, test_data[i].data);
  80. };
  81. }
  82. static void
  83. test_find_jws(void)
  84. {
  85. const struct thp_result test_data[] = {
  86. {"00BUQM4A7NYxbOrBR9QDfkzGVGj3k57Fs4jCbJxcLYAgRFHu5B7jtbL97x1T7stQ", 1},
  87. {"dd5qbN1lQ6UWdZszbfx2oIcH34ShklzFL1SUQg", 1},
  88. {"dOZkUtZ_gLDUP53GIlyAxHMNuyrk8vdY-XXND32GccqNbT_MKpqGC-13-GNEye48", 1},
  89. {"DZrlBQvfvlwPQlvH_IieBdc_KpesEramLygVL_rFr7g", 1},
  90. {"FL_Zt5fFadUL4syeMMpUnss8aKdCrPGFy3102JGR3EE", 1},
  91. {"qgmqJSo6AEEuVQY7zVlklqdTMqY", 1},
  92. {"r4E2wG1u_YyKUo0N0rIK7jJF5Xg", 1},
  93. {"ugJ4Ula-YABQIiJ-0g3B_jpFpF2nl3W-DNpfLdXArhTusV0QCcd1vtgDeGHEPzpm7jEsyC7VYYSSOkZicK22mw", 1},
  94. {"up0Z4fRhpd4O5QwBaMCXDTlrvxCmZacU0MD8kw", 1},
  95. {"vllHS-M0aQFCo2yUCcAahMU4TAtXACyeuRf-zbmmTPBg7V0Pb-RRFGo5C6MnpzdirK8B3ORLOsN8RyXClvtjxA", 1},
  96. {NULL, 1},
  97. {"a", 0},
  98. {"foo", 0},
  99. {"bar", 0},
  100. {"XXXXXXXXXXXXXXXXXX", 0}
  101. };
  102. __attribute__((cleanup(cleanup_tang_keys_info))) struct tang_keys_info* tki = read_keys(jwkdir);
  103. for (int i = 0, len = ARRAY_COUNT(test_data); i < len; i++) {
  104. json_auto_t* jws = find_jws(tki, test_data[i].thp);
  105. ASSERT_WITH_MSG(!!jws == test_data[i].valid, "i = %d, thp = %s", i, test_data[i].thp);
  106. }
  107. /* Passing NULL to find_jws should return the default advertisement */
  108. json_auto_t* adv = find_jws(tki, NULL);
  109. ASSERT(adv);
  110. /*
  111. * The default set of signing keys are the signing keys that are not
  112. * rotated. The payload is made of deriving keys that are also not
  113. * rotated. The default advertisement should be signed by this set of
  114. * default signing keys.
  115. */
  116. ASSERT(jose_jws_ver(NULL, adv, NULL, tki->m_sign, 1));
  117. /* find_jws should be able to respond to thumbprints of keys using any
  118. * of jose supported hash algorithms. */
  119. const char** hashes = supported_hashes();
  120. size_t idx;
  121. json_t* jwk;
  122. /* Let's put together all the keys, including rotated ones. */
  123. json_auto_t* keys = json_deep_copy(tki->m_keys);
  124. ASSERT(keys);
  125. ASSERT(json_array_extend(keys, tki->m_rotated_keys) == 0);
  126. ASSERT(json_array_size(keys) == (size_t)tki->m_keys_count);
  127. for (int i = 0; hashes[i]; i++) {
  128. json_array_foreach(keys, idx, jwk) {
  129. if (!jwk_valid_for_signing(jwk)) {
  130. continue;
  131. }
  132. __attribute__((cleanup(cleanup_str))) char* thp = jwk_thumbprint(jwk, hashes[i]);
  133. ASSERT_WITH_MSG(thp, "i = %d, hash = %s, key idx = %d", i, hashes[i], idx);
  134. json_auto_t* jws = find_jws(tki, thp);
  135. ASSERT_WITH_MSG(jws, "i = %d, hash = %s, key idx = %d, thp = %s", i, hashes[i], idx, thp);
  136. /* Signing keys should sign the payload, in addition to the
  137. * default set of signing keys. */
  138. json_auto_t* sign = json_deep_copy(tki->m_sign);
  139. ASSERT_WITH_MSG(sign, "i = %d, hash = %s, key idx = %d, thp = %s", i, hashes[i], idx, thp);
  140. ASSERT_WITH_MSG(json_array_append(sign, jwk) == 0, "i = %d, hash = %s, key idx = %d, thp = %s", i, hashes[i], idx, thp);
  141. ASSERT_WITH_MSG(jose_jws_ver(NULL, jws, NULL, sign, 1), "i = %d, hash = %s, key idx = %d, thp = %s", i, hashes[i], idx, thp);
  142. }
  143. }
  144. }
  145. static void
  146. test_find_jwk(void)
  147. {
  148. const struct thp_result test_data[] = {
  149. {"1HdF3XKRSsuZdkpXNurBPoL_pvxdvCOlHuhB4DP-4xWFqbZ51zo29kR4fSiT3BGy9UrHVJ26JMBLOA1vKq3lxA", 1},
  150. {"9U8qgy_YjyY6Isuq6QuiKEiYZgNJShcGgJx5FJzCu6m3N6zFaIPy_HDkxkVqAZ9E", 1},
  151. {"-bWkGaJi0Zdvxaj4DCp28umLcRA", 1},
  152. {"Cy73glFjs6B6RU7wy6vWxAc-2bJy5VJOT9LyK80eKgZ8k27wXZ-3rjsuNU5tua_yHWtluyoSYtjoKXfI0E8ESw", 1},
  153. {"kfjbqx_b3BsgPC87HwlOWL9daGMMHBzxcFLClw", 1},
  154. {"L4xg2tZXTEVbsK39bzOZM1jGWn3HtOxF5gh6F9YVf5Q", 1},
  155. {"LsVAV2ig5LlfstM8TRSf-c7IAkLpNYbIysNuRCVlxocRCGqAh6-f9PklM4nU4N-J", 1},
  156. {"OkAcDxYHNlo7-tul8OubYuWXB8CPEhAkcacCmhTclMU", 1},
  157. {"uZ0s8YTXcGcuWduWWBSiR2OjOVg", 1},
  158. {"WEpfFyeoNKkE2-TosN_bP-gd9UgRvQCZpVasZQ", 1},
  159. {NULL, 0},
  160. {"a", 0},
  161. {"foo", 0},
  162. {"bar", 0},
  163. {"XXXXXXXXXXXXXXXXXX", 0},
  164. };
  165. __attribute__((cleanup(cleanup_tang_keys_info))) struct tang_keys_info* tki = read_keys(jwkdir);
  166. for (int i = 0, len = ARRAY_COUNT(test_data); i < len; i++) {
  167. json_auto_t* tjwk = find_jwk(tki, test_data[i].thp);
  168. ASSERT_WITH_MSG(!!tjwk == test_data[i].valid, "i = %d, thp = %s", i, test_data[i].thp);
  169. }
  170. /* Passing NULL to find_jwk should fail */
  171. json_auto_t* bad_jwk = find_jwk(tki, NULL);
  172. ASSERT(bad_jwk == NULL);
  173. /* find_jwk should be able to respond to thumbprints of keys using any
  174. * of jose supported hash algorithms. */
  175. const char** hashes = supported_hashes();
  176. size_t idx;
  177. json_t* jwk;
  178. /* Let's put together all the keys, including rotated ones. */
  179. json_auto_t* keys = json_deep_copy(tki->m_keys);
  180. ASSERT(keys);
  181. ASSERT(json_array_extend(keys, tki->m_rotated_keys) == 0);
  182. ASSERT(json_array_size(keys) == (size_t)tki->m_keys_count);
  183. for (int i = 0; hashes[i]; i++) {
  184. json_array_foreach(keys, idx, jwk) {
  185. if (!jwk_valid_for_deriving_keys(jwk)) {
  186. continue;
  187. }
  188. __attribute__((cleanup(cleanup_str))) char* thp = jwk_thumbprint(jwk, hashes[i]);
  189. json_auto_t* tjwk = find_jwk(tki, thp);
  190. ASSERT_WITH_MSG(tjwk, "i = %d, hash = %s, key idx = %d, thp = %s", i, hashes[i], idx, thp);
  191. }
  192. }
  193. }
  194. static void
  195. test_read_keys(void)
  196. {
  197. __attribute__((cleanup(cleanup_tang_keys_info))) struct tang_keys_info* tki = read_keys(jwkdir);
  198. ASSERT(tki);
  199. /*
  200. * Keys in tests/keys:
  201. * - .uZ0s8YTXcGcuWduWWBSiR2OjOVg.jwk
  202. * - .r4E2wG1u_YyKUo0N0rIK7jJF5Xg.jwk
  203. * - qgmqJSo6AEEuVQY7zVlklqdTMqY.jwk
  204. * - -bWkGaJi0Zdvxaj4DCp28umLcRA.jwk
  205. */
  206. ASSERT(tki->m_keys_count == 4);
  207. ASSERT(json_array_size(tki->m_keys) == 2);
  208. ASSERT(json_array_size(tki->m_rotated_keys) == 2);
  209. const char* invalid_jwkdir = "foobar";
  210. __attribute__((cleanup(cleanup_tang_keys_info))) struct tang_keys_info* tki2 = read_keys(invalid_jwkdir);
  211. ASSERT(tki2 == NULL);
  212. }
  213. static void
  214. run_tests(void)
  215. {
  216. test_read_keys();
  217. test_find_jwk();
  218. test_find_jws();
  219. test_jwk_generate();
  220. test_is_hash();
  221. test_create_new_keys();
  222. }
  223. int main(int argc, char** argv)
  224. {
  225. run_tests();
  226. return 0;
  227. }