tests.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. /*
  2. * Copyright (c) 2017 Red Hat
  3. *
  4. * Authors: Jakub Jelen <jjelen@redhat.com>
  5. *
  6. * Permission to use, copy, modify, and distribute this software for any
  7. * purpose with or without fee is hereby granted, provided that the above
  8. * copyright notice and this permission notice appear in all copies.
  9. *
  10. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  11. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  12. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  13. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  14. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  15. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  16. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  17. */
  18. #include "includes.h"
  19. #include <locale.h>
  20. #include <string.h>
  21. #include "../test_helper/test_helper.h"
  22. #include "sshbuf.h"
  23. #include "ssh-pkcs11-uri.h"
  24. #define EMPTY_URI compose_uri(NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL)
  25. /* prototypes are not public -- specify them here internally for tests */
  26. struct sshbuf *percent_encode(const char *, size_t, char *);
  27. int percent_decode(char *, char **);
  28. void
  29. compare_uri(struct pkcs11_uri *a, struct pkcs11_uri *b)
  30. {
  31. ASSERT_PTR_NE(a, NULL);
  32. ASSERT_PTR_NE(b, NULL);
  33. ASSERT_SIZE_T_EQ(a->id_len, b->id_len);
  34. ASSERT_MEM_EQ(a->id, b->id, a->id_len);
  35. if (b->object != NULL)
  36. ASSERT_STRING_EQ(a->object, b->object);
  37. else /* both should be null */
  38. ASSERT_PTR_EQ(a->object, b->object);
  39. if (b->module_path != NULL)
  40. ASSERT_STRING_EQ(a->module_path, b->module_path);
  41. else /* both should be null */
  42. ASSERT_PTR_EQ(a->module_path, b->module_path);
  43. if (b->token != NULL)
  44. ASSERT_STRING_EQ(a->token, b->token);
  45. else /* both should be null */
  46. ASSERT_PTR_EQ(a->token, b->token);
  47. if (b->manuf != NULL)
  48. ASSERT_STRING_EQ(a->manuf, b->manuf);
  49. else /* both should be null */
  50. ASSERT_PTR_EQ(a->manuf, b->manuf);
  51. if (b->lib_manuf != NULL)
  52. ASSERT_STRING_EQ(a->lib_manuf, b->lib_manuf);
  53. else /* both should be null */
  54. ASSERT_PTR_EQ(a->lib_manuf, b->lib_manuf);
  55. }
  56. void
  57. check_parse_rv(char *uri, struct pkcs11_uri *expect, int expect_rv)
  58. {
  59. char *buf = NULL, *str;
  60. struct pkcs11_uri *pkcs11uri = NULL;
  61. int rv;
  62. if (expect_rv == 0)
  63. str = "Valid";
  64. else
  65. str = "Invalid";
  66. asprintf(&buf, "%s PKCS#11 URI parsing: %s", str, uri);
  67. TEST_START(buf);
  68. free(buf);
  69. pkcs11uri = pkcs11_uri_init();
  70. rv = pkcs11_uri_parse(uri, pkcs11uri);
  71. ASSERT_INT_EQ(rv, expect_rv);
  72. if (rv == 0) /* in case of failure result is undefined */
  73. compare_uri(pkcs11uri, expect);
  74. pkcs11_uri_cleanup(pkcs11uri);
  75. free(expect);
  76. TEST_DONE();
  77. }
  78. void
  79. check_parse(char *uri, struct pkcs11_uri *expect)
  80. {
  81. check_parse_rv(uri, expect, 0);
  82. }
  83. struct pkcs11_uri *
  84. compose_uri(unsigned char *id, size_t id_len, char *token, char *lib_manuf,
  85. char *manuf, char *module_path, char *object, char *pin)
  86. {
  87. struct pkcs11_uri *uri = pkcs11_uri_init();
  88. if (id_len > 0) {
  89. uri->id_len = id_len;
  90. uri->id = id;
  91. }
  92. uri->module_path = module_path;
  93. uri->token = token;
  94. uri->lib_manuf = lib_manuf;
  95. uri->manuf = manuf;
  96. uri->object = object;
  97. uri->pin = pin;
  98. return uri;
  99. }
  100. static void
  101. test_parse_valid(void)
  102. {
  103. /* path arguments */
  104. check_parse("pkcs11:id=%01",
  105. compose_uri("\x01", 1, NULL, NULL, NULL, NULL, NULL, NULL));
  106. check_parse("pkcs11:id=%00%01",
  107. compose_uri("\x00\x01", 2, NULL, NULL, NULL, NULL, NULL, NULL));
  108. check_parse("pkcs11:token=SSH%20Keys",
  109. compose_uri(NULL, 0, "SSH Keys", NULL, NULL, NULL, NULL, NULL));
  110. check_parse("pkcs11:library-manufacturer=OpenSC",
  111. compose_uri(NULL, 0, NULL, "OpenSC", NULL, NULL, NULL, NULL));
  112. check_parse("pkcs11:manufacturer=piv_II",
  113. compose_uri(NULL, 0, NULL, NULL, "piv_II", NULL, NULL, NULL));
  114. check_parse("pkcs11:object=SIGN%20Key",
  115. compose_uri(NULL, 0, NULL, NULL, NULL, NULL, "SIGN Key", NULL));
  116. /* query arguments */
  117. check_parse("pkcs11:?module-path=/usr/lib64/p11-kit-proxy.so",
  118. compose_uri(NULL, 0, NULL, NULL, NULL, "/usr/lib64/p11-kit-proxy.so", NULL, NULL));
  119. check_parse("pkcs11:?pin-value=123456",
  120. compose_uri(NULL, 0, NULL, NULL, NULL, NULL, NULL, "123456"));
  121. /* combinations */
  122. /* ID SHOULD be percent encoded */
  123. check_parse("pkcs11:token=SSH%20Key;id=0",
  124. compose_uri("0", 1, "SSH Key", NULL, NULL, NULL, NULL, NULL));
  125. check_parse(
  126. "pkcs11:manufacturer=CAC?module-path=/usr/lib64/p11-kit-proxy.so",
  127. compose_uri(NULL, 0, NULL, NULL, "CAC",
  128. "/usr/lib64/p11-kit-proxy.so", NULL, NULL));
  129. check_parse(
  130. "pkcs11:object=RSA%20Key?module-path=/usr/lib64/pkcs11/opencryptoki.so",
  131. compose_uri(NULL, 0, NULL, NULL, NULL,
  132. "/usr/lib64/pkcs11/opencryptoki.so", "RSA Key", NULL));
  133. check_parse("pkcs11:?module-path=/usr/lib64/p11-kit-proxy.so&pin-value=123456",
  134. compose_uri(NULL, 0, NULL, NULL, NULL, "/usr/lib64/p11-kit-proxy.so", NULL, "123456"));
  135. /* empty path component matches everything */
  136. check_parse("pkcs11:", EMPTY_URI);
  137. /* empty string is a valid to match against (and different from NULL) */
  138. check_parse("pkcs11:token=",
  139. compose_uri(NULL, 0, "", NULL, NULL, NULL, NULL, NULL));
  140. /* Percent character needs to be percent-encoded */
  141. check_parse("pkcs11:token=%25",
  142. compose_uri(NULL, 0, "%", NULL, NULL, NULL, NULL, NULL));
  143. }
  144. static void
  145. test_parse_invalid(void)
  146. {
  147. /* Invalid percent encoding */
  148. check_parse_rv("pkcs11:id=%0", EMPTY_URI, -1);
  149. /* Invalid percent encoding */
  150. check_parse_rv("pkcs11:id=%ZZ", EMPTY_URI, -1);
  151. /* Space MUST be percent encoded -- XXX not enforced yet */
  152. check_parse("pkcs11:token=SSH Keys",
  153. compose_uri(NULL, 0, "SSH Keys", NULL, NULL, NULL, NULL, NULL));
  154. /* MUST NOT contain duplicate attributes of the same name */
  155. check_parse_rv("pkcs11:id=%01;id=%02", EMPTY_URI, -1);
  156. /* MUST NOT contain duplicate attributes of the same name */
  157. check_parse_rv("pkcs11:?pin-value=111111&pin-value=123456", EMPTY_URI, -1);
  158. /* Unrecognized attribute in path are ignored with log message */
  159. check_parse("pkcs11:key_name=SSH", EMPTY_URI);
  160. /* Unrecognized attribute in query SHOULD be ignored */
  161. check_parse("pkcs11:?key_name=SSH", EMPTY_URI);
  162. }
  163. void
  164. check_gen(char *expect, struct pkcs11_uri *uri)
  165. {
  166. char *buf = NULL, *uri_str;
  167. asprintf(&buf, "Valid PKCS#11 URI generation: %s", expect);
  168. TEST_START(buf);
  169. free(buf);
  170. uri_str = pkcs11_uri_get(uri);
  171. ASSERT_PTR_NE(uri_str, NULL);
  172. ASSERT_STRING_EQ(uri_str, expect);
  173. free(uri_str);
  174. TEST_DONE();
  175. }
  176. static void
  177. test_generate_valid(void)
  178. {
  179. /* path arguments */
  180. check_gen("pkcs11:id=%01",
  181. compose_uri("\x01", 1, NULL, NULL, NULL, NULL, NULL, NULL));
  182. check_gen("pkcs11:id=%00%01",
  183. compose_uri("\x00\x01", 2, NULL, NULL, NULL, NULL, NULL, NULL));
  184. check_gen("pkcs11:token=SSH%20Keys", /* space must be percent encoded */
  185. compose_uri(NULL, 0, "SSH Keys", NULL, NULL, NULL, NULL, NULL));
  186. /* library-manufacturer is not implmented now */
  187. /*check_gen("pkcs11:library-manufacturer=OpenSC",
  188. compose_uri(NULL, 0, NULL, "OpenSC", NULL, NULL, NULL, NULL));*/
  189. check_gen("pkcs11:manufacturer=piv_II",
  190. compose_uri(NULL, 0, NULL, NULL, "piv_II", NULL, NULL, NULL));
  191. check_gen("pkcs11:object=RSA%20Key",
  192. compose_uri(NULL, 0, NULL, NULL, NULL, NULL, "RSA Key", NULL));
  193. /* query arguments */
  194. check_gen("pkcs11:?module-path=/usr/lib64/p11-kit-proxy.so",
  195. compose_uri(NULL, 0, NULL, NULL, NULL, "/usr/lib64/p11-kit-proxy.so", NULL, NULL));
  196. /* combinations */
  197. check_gen("pkcs11:id=%02;token=SSH%20Keys",
  198. compose_uri("\x02", 1, "SSH Keys", NULL, NULL, NULL, NULL, NULL));
  199. check_gen("pkcs11:id=%EE%02?module-path=/usr/lib64/p11-kit-proxy.so",
  200. compose_uri("\xEE\x02", 2, NULL, NULL, NULL, "/usr/lib64/p11-kit-proxy.so", NULL, NULL));
  201. check_gen("pkcs11:object=Encryption%20Key;manufacturer=piv_II",
  202. compose_uri(NULL, 0, NULL, NULL, "piv_II", NULL, "Encryption Key", NULL));
  203. /* empty path component matches everything */
  204. check_gen("pkcs11:", EMPTY_URI);
  205. }
  206. void
  207. check_encode(char *source, size_t len, char *allow_list, char *expect)
  208. {
  209. char *buf = NULL;
  210. struct sshbuf *b;
  211. asprintf(&buf, "percent_encode: expected %s", expect);
  212. TEST_START(buf);
  213. free(buf);
  214. b = percent_encode(source, len, allow_list);
  215. ASSERT_STRING_EQ(sshbuf_ptr(b), expect);
  216. sshbuf_free(b);
  217. TEST_DONE();
  218. }
  219. static void
  220. test_percent_encode_multibyte(void)
  221. {
  222. /* SHOULD be encoded as octets according to the UTF-8 character encoding */
  223. /* multi-byte characters are "for free" */
  224. check_encode("$", 1, "", "%24");
  225. check_encode("¢", 2, "", "%C2%A2");
  226. check_encode("€", 3, "", "%E2%82%AC");
  227. check_encode("𐍈", 4, "", "%F0%90%8D%88");
  228. /* CK_UTF8CHAR is unsigned char (1 byte) */
  229. /* labels SHOULD be normalized to NFC [UAX15] */
  230. }
  231. static void
  232. test_percent_encode(void)
  233. {
  234. /* Without allow list encodes everything (for CKA_ID) */
  235. check_encode("A*", 2, "", "%41%2A");
  236. check_encode("\x00", 1, "", "%00");
  237. check_encode("\x7F", 1, "", "%7F");
  238. check_encode("\x80", 1, "", "%80");
  239. check_encode("\xff", 1, "", "%FF");
  240. /* Default allow list encodes anything but safe letters */
  241. check_encode("test" "\x00" "0alpha", 11, PKCS11_URI_WHITELIST,
  242. "test%000alpha");
  243. check_encode(" ", 1, PKCS11_URI_WHITELIST,
  244. "%20"); /* Space MUST be percent encoded */
  245. check_encode("/", 1, PKCS11_URI_WHITELIST,
  246. "%2F"); /* '/' delimiter MUST be percent encoded (in the path) */
  247. check_encode("?", 1, PKCS11_URI_WHITELIST,
  248. "%3F"); /* delimiter '?' MUST be percent encoded (in the path) */
  249. check_encode("#", 1, PKCS11_URI_WHITELIST,
  250. "%23"); /* '#' MUST be always percent encoded */
  251. check_encode("key=value;separator?query&amp;#anch", 35, PKCS11_URI_WHITELIST,
  252. "key%3Dvalue%3Bseparator%3Fquery%26amp%3B%23anch");
  253. /* Components in query can have '/' unencoded (useful for paths) */
  254. check_encode("/path/to.file", 13, PKCS11_URI_WHITELIST "/",
  255. "/path/to.file");
  256. }
  257. void
  258. check_decode(char *source, char *expect, int expect_len)
  259. {
  260. char *buf = NULL, *out = NULL;
  261. int rv;
  262. asprintf(&buf, "percent_decode: %s", source);
  263. TEST_START(buf);
  264. free(buf);
  265. rv = percent_decode(source, &out);
  266. ASSERT_INT_EQ(rv, expect_len);
  267. if (rv >= 0)
  268. ASSERT_MEM_EQ(out, expect, expect_len);
  269. free(out);
  270. TEST_DONE();
  271. }
  272. static void
  273. test_percent_decode(void)
  274. {
  275. /* simple valid cases */
  276. check_decode("%00", "\x00", 1);
  277. check_decode("%FF", "\xFF", 1);
  278. /* normal strings shold be kept intact */
  279. check_decode("strings are left", "strings are left", 16);
  280. check_decode("10%25 of trees", "10% of trees", 12);
  281. /* make sure no more than 2 bytes are parsed */
  282. check_decode("%222", "\x22" "2", 2);
  283. /* invalid expects failure */
  284. check_decode("%0", "", -1);
  285. check_decode("%Z", "", -1);
  286. check_decode("%FG", "", -1);
  287. }
  288. void
  289. tests(void)
  290. {
  291. test_percent_encode();
  292. test_percent_encode_multibyte();
  293. test_percent_decode();
  294. test_parse_valid();
  295. test_parse_invalid();
  296. test_generate_valid();
  297. }