tpm2_alg_util.c 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041
  1. /* SPDX-License-Identifier: BSD-3-Clause */
  2. #include <stdbool.h>
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <string.h>
  6. #include "files.h"
  7. #include "log.h"
  8. #include "pcr.h"
  9. #include "tpm2.h"
  10. #include "tpm2_alg_util.h"
  11. #include "tpm2_attr_util.h"
  12. #include "tpm2_errata.h"
  13. typedef struct alg_pair alg_pair;
  14. struct alg_pair {
  15. const char *name;
  16. TPM2_ALG_ID id;
  17. tpm2_alg_util_flags flags;
  18. tpm2_alg_util_flags _flags;
  19. };
  20. typedef enum alg_iter_res alg_iter_res;
  21. enum alg_iter_res {
  22. stop,
  23. go,
  24. found
  25. };
  26. typedef enum alg_parser_rc alg_parser_rc;
  27. enum alg_parser_rc {
  28. alg_parser_rc_error,
  29. alg_parser_rc_continue,
  30. alg_parser_rc_done
  31. };
  32. typedef alg_iter_res (*alg_iter)(TPM2_ALG_ID id, const char *name,
  33. tpm2_alg_util_flags flags, void *userdata);
  34. static void tpm2_alg_util_for_each_alg(alg_iter iterator, void *userdata) {
  35. static const alg_pair algs[] = {
  36. // Assymetric
  37. { .name = "rsa", .id = TPM2_ALG_RSA, .flags = tpm2_alg_util_flags_asymmetric|tpm2_alg_util_flags_base },
  38. { .name = "ecc", .id = TPM2_ALG_ECC, .flags = tpm2_alg_util_flags_asymmetric|tpm2_alg_util_flags_base },
  39. // Symmetric
  40. { .name = "tdes", .id = TPM2_ALG_TDES, .flags = tpm2_alg_util_flags_symmetric },
  41. { .name = "aes", .id = TPM2_ALG_AES, .flags = tpm2_alg_util_flags_symmetric },
  42. { .name = "camellia", .id = TPM2_ALG_CAMELLIA, .flags = tpm2_alg_util_flags_symmetric },
  43. // Hash
  44. { .name = "sha1", .id = TPM2_ALG_SHA1, .flags = tpm2_alg_util_flags_hash },
  45. { .name = "sha256", .id = TPM2_ALG_SHA256, .flags = tpm2_alg_util_flags_hash },
  46. { .name = "sha384", .id = TPM2_ALG_SHA384, .flags = tpm2_alg_util_flags_hash },
  47. { .name = "sha512", .id = TPM2_ALG_SHA512, .flags = tpm2_alg_util_flags_hash },
  48. { .name = "sm3_256", .id = TPM2_ALG_SM3_256, .flags = tpm2_alg_util_flags_hash },
  49. { .name = "sha3_256", .id = TPM2_ALG_SHA3_256, .flags = tpm2_alg_util_flags_hash },
  50. { .name = "sha3_384", .id = TPM2_ALG_SHA3_384, .flags = tpm2_alg_util_flags_hash },
  51. { .name = "sha3_512", .id = TPM2_ALG_SHA3_512, .flags = tpm2_alg_util_flags_hash },
  52. // Keyed hash
  53. { .name = "hmac", .id = TPM2_ALG_HMAC, tpm2_alg_util_flags_keyedhash | tpm2_alg_util_flags_sig },
  54. { .name = "xor", .id = TPM2_ALG_XOR, tpm2_alg_util_flags_keyedhash },
  55. { .name = "cmac", .id = TPM2_ALG_CMAC, .flags = tpm2_alg_util_flags_sig },
  56. // Mask Generation Functions
  57. { .name = "mgf1", .id = TPM2_ALG_MGF1, .flags = tpm2_alg_util_flags_mgf },
  58. // Signature Schemes
  59. { .name = "rsassa", .id = TPM2_ALG_RSASSA, .flags = tpm2_alg_util_flags_sig },
  60. { .name = "rsapss", .id = TPM2_ALG_RSAPSS, .flags = tpm2_alg_util_flags_sig },
  61. { .name = "ecdsa", .id = TPM2_ALG_ECDSA, .flags = tpm2_alg_util_flags_sig },
  62. { .name = "ecdaa", .id = TPM2_ALG_ECDAA, .flags = tpm2_alg_util_flags_sig },
  63. { .name = "ecschnorr", .id = TPM2_ALG_ECSCHNORR, .flags = tpm2_alg_util_flags_sig },
  64. // Assyemtric Encryption Scheme
  65. { .name = "oaep", .id = TPM2_ALG_OAEP, .flags = tpm2_alg_util_flags_enc_scheme | tpm2_alg_util_flags_rsa_scheme },
  66. { .name = "rsaes", .id = TPM2_ALG_RSAES, .flags = tpm2_alg_util_flags_enc_scheme | tpm2_alg_util_flags_rsa_scheme },
  67. { .name = "ecdh", .id = TPM2_ALG_ECDH, .flags = tpm2_alg_util_flags_enc_scheme },
  68. // XXX are these sigs?
  69. { .name = "sm2", .id = TPM2_ALG_SM2, .flags = tpm2_alg_util_flags_sig },
  70. { .name = "sm4", .id = TPM2_ALG_SM4, .flags = tpm2_alg_util_flags_sig },
  71. // Key derivation functions
  72. { .name = "kdf1_sp800_56a", .id = TPM2_ALG_KDF1_SP800_56A, .flags = tpm2_alg_util_flags_kdf },
  73. { .name = "kdf2", .id = TPM2_ALG_KDF2, .flags = tpm2_alg_util_flags_kdf },
  74. { .name = "kdf1_sp800_108", .id = TPM2_ALG_KDF1_SP800_108, .flags = tpm2_alg_util_flags_kdf },
  75. { .name = "ecmqv", .id = TPM2_ALG_ECMQV, .flags = tpm2_alg_util_flags_kdf },
  76. // Modes
  77. { .name = "ctr", .id = TPM2_ALG_CTR, .flags = tpm2_alg_util_flags_mode },
  78. { .name = "ofb", .id = TPM2_ALG_OFB, .flags = tpm2_alg_util_flags_mode },
  79. { .name = "cbc", .id = TPM2_ALG_CBC, .flags = tpm2_alg_util_flags_mode },
  80. { .name = "cfb", .id = TPM2_ALG_CFB, .flags = tpm2_alg_util_flags_mode },
  81. { .name = "ecb", .id = TPM2_ALG_ECB, .flags = tpm2_alg_util_flags_mode },
  82. { .name = "symcipher", .id = TPM2_ALG_SYMCIPHER, .flags = tpm2_alg_util_flags_base },
  83. { .name = "keyedhash", .id = TPM2_ALG_KEYEDHASH, .flags = tpm2_alg_util_flags_base },
  84. // Misc
  85. { .name = "null", .id = TPM2_ALG_NULL, .flags = tpm2_alg_util_flags_misc | tpm2_alg_util_flags_rsa_scheme },
  86. };
  87. size_t i;
  88. for (i = 0; i < ARRAY_LEN(algs); i++) {
  89. const alg_pair *alg = &algs[i];
  90. alg_iter_res result = iterator(alg->id, alg->name, alg->flags,
  91. userdata);
  92. if (result != go) {
  93. return;
  94. }
  95. }
  96. }
  97. static alg_parser_rc handle_sym_common(const char *ext, TPMT_SYM_DEF_OBJECT *s) {
  98. if (ext == NULL || ext[0] == '\0') {
  99. ext = "128";
  100. }
  101. if (!strncmp(ext, "128", 3)) {
  102. s->keyBits.sym = 128;
  103. } else if (!strncmp(ext, "192", 3)) {
  104. s->keyBits.sym = 192;
  105. } else if (!strncmp(ext, "256", 3)) {
  106. s->keyBits.sym = 256;
  107. } else {
  108. return alg_parser_rc_error;
  109. }
  110. ext += 3;
  111. if (*ext == '\0') {
  112. ext = "null";
  113. }
  114. s->mode.sym = tpm2_alg_util_strtoalg(ext,
  115. tpm2_alg_util_flags_mode | tpm2_alg_util_flags_misc);
  116. if (s->mode.sym == TPM2_ALG_ERROR) {
  117. return alg_parser_rc_error;
  118. }
  119. return alg_parser_rc_done;
  120. }
  121. /*
  122. * Macro for redundant code collapse in handle_asym_scheme_common
  123. * You cannot change all the variables in this, as they are dependent
  124. * on names in that routine; this is for simplicity.
  125. */
  126. #define do_scheme_halg(scheme, advance, alg) \
  127. do { \
  128. scheme += advance; \
  129. s->scheme.scheme = alg; \
  130. do_scheme_hash_alg = true; \
  131. found = true; \
  132. } while (0)
  133. static alg_parser_rc handle_scheme_sign(const char *scheme,
  134. TPM2B_PUBLIC *public) {
  135. char buf[256];
  136. if (!scheme || scheme[0] == '\0') {
  137. scheme = "null";
  138. }
  139. int rc = snprintf(buf, sizeof(buf), "%s", scheme);
  140. if (rc < 0 || (size_t) rc >= sizeof(buf)) {
  141. return alg_parser_rc_error;
  142. }
  143. // Get the scheme and symetric details
  144. TPMS_ASYM_PARMS *s = &public->publicArea.parameters.asymDetail;
  145. if (!strcmp(scheme, "null")) {
  146. public->publicArea.parameters.asymDetail.scheme.scheme = TPM2_ALG_NULL;
  147. return alg_parser_rc_continue;
  148. }
  149. char *halg = NULL;
  150. char *split = strchr(scheme, '-');
  151. if (split) {
  152. *split = '\0';
  153. halg = split + 1;
  154. }
  155. bool found = false;
  156. bool do_scheme_hash_alg = false;
  157. if (public->publicArea.type == TPM2_ALG_ECC) {
  158. if (!strncmp(scheme, "oaep", 4)) {
  159. do_scheme_halg(scheme, 4, TPM2_ALG_OAEP);
  160. } else if (!strncmp(scheme, "ecdsa", 5)) {
  161. do_scheme_halg(scheme, 5, TPM2_ALG_ECDSA);
  162. } else if (!strncmp(scheme, "ecdh", 4)) {
  163. do_scheme_halg(scheme, 4, TPM2_ALG_ECDH);
  164. } else if (!strncmp(scheme, "ecschnorr", 9)) {
  165. do_scheme_halg(scheme, 9, TPM2_ALG_ECSCHNORR);
  166. } else if (!strncmp(scheme, "ecdaa", 5)) {
  167. do_scheme_halg(scheme, 5, TPM2_ALG_ECDAA);
  168. /*
  169. * ECDAA has both a commit-counter value and hashing algorithm.
  170. * The default commit-counter value is set to zero to use the first
  171. * commit-id.
  172. */
  173. if (scheme[0] == '\0') {
  174. scheme = "0";
  175. }
  176. TPMS_SIG_SCHEME_ECDAA *e = &s->scheme.details.ecdaa;
  177. bool res = tpm2_util_string_to_uint16(scheme, &e->count);
  178. if (!res) {
  179. return alg_parser_rc_error;
  180. }
  181. } else if (!strcmp("null", scheme)) {
  182. s->scheme.scheme = TPM2_ALG_NULL;
  183. }
  184. } else {
  185. if (!strcmp(scheme, "rsaes")) {
  186. /*
  187. * rsaes has no hash alg or details, so it MUST
  188. * match exactly, notice strcmp and NOT strNcmp!
  189. */
  190. s->scheme.scheme = TPM2_ALG_RSAES;
  191. found = true;
  192. } else if (!strcmp("null", scheme)) {
  193. s->scheme.scheme = TPM2_ALG_NULL;
  194. found = true;
  195. } else if (!strncmp("rsapss", scheme, 6)) {
  196. do_scheme_halg(scheme, 6, TPM2_ALG_RSAPSS);
  197. } else if (!strncmp("rsassa", scheme, 6)) {
  198. do_scheme_halg(scheme, 6, TPM2_ALG_RSASSA);
  199. }
  200. }
  201. /* If we're not expecting a hash alg then halg should be NULL */
  202. if ((!do_scheme_hash_alg && halg) || !found) {
  203. return alg_parser_rc_error;
  204. }
  205. /* if we're expecting a hash alg and none provided default */
  206. if (do_scheme_hash_alg && !halg) {
  207. halg = "sha256";
  208. }
  209. /*
  210. * If the scheme is set, both the encrypt and decrypt attributes cannot be set,
  211. * check to see if this is the case, and turn down:
  212. * - DECRYPT - If its a signing scheme.
  213. * - ENCRYPT - If its an asymmetric enc scheme.
  214. */
  215. if (s->scheme.scheme != TPM2_ALG_NULL) {
  216. bool is_both_set = !!(public->publicArea.objectAttributes
  217. & (TPMA_OBJECT_SIGN_ENCRYPT | TPMA_OBJECT_DECRYPT));
  218. if (is_both_set) {
  219. tpm2_alg_util_flags flags = tpm2_alg_util_algtoflags(
  220. s->scheme.scheme);
  221. TPMA_OBJECT turn_down_flags =
  222. (flags & tpm2_alg_util_flags_sig) ?
  223. TPMA_OBJECT_DECRYPT : TPMA_OBJECT_SIGN_ENCRYPT;
  224. public->publicArea.objectAttributes &= ~turn_down_flags;
  225. }
  226. }
  227. if (do_scheme_hash_alg) {
  228. public->publicArea.parameters.asymDetail.scheme.details.anySig.hashAlg =
  229. tpm2_alg_util_strtoalg(halg, tpm2_alg_util_flags_hash);
  230. if (public->publicArea.parameters.asymDetail.scheme.details.anySig.hashAlg
  231. == TPM2_ALG_ERROR) {
  232. return alg_parser_rc_error;
  233. }
  234. }
  235. return alg_parser_rc_continue;
  236. }
  237. static alg_parser_rc handle_rsa(const char *ext, TPM2B_PUBLIC *public) {
  238. public->publicArea.type = TPM2_ALG_RSA;
  239. TPMS_RSA_PARMS *r = &public->publicArea.parameters.rsaDetail;
  240. r->exponent = 0;
  241. size_t len = ext ? strlen(ext) : 0;
  242. if (len == 0 || ext[0] == '\0') {
  243. ext = "2048";
  244. }
  245. // Deal with bit size
  246. if (!strncmp(ext, "1024", 4)) {
  247. r->keyBits = 1024;
  248. ext += 4;
  249. } else if (!strncmp(ext, "2048", 4)) {
  250. r->keyBits = 2048;
  251. ext += 4;
  252. } else if (!strncmp(ext, "4096", 4)) {
  253. r->keyBits = 4096;
  254. ext += 4;
  255. } else if (!strncmp(ext, "3072", 4)) {
  256. r->keyBits = 3072;
  257. ext += 4;
  258. } else {
  259. r->keyBits = 2048;
  260. }
  261. /* rsa extension should be consumed at this point */
  262. return ext[0] == '\0' ? alg_parser_rc_continue : alg_parser_rc_error;
  263. }
  264. static alg_parser_rc handle_ecc(const char *ext, TPM2B_PUBLIC *public) {
  265. public->publicArea.type = TPM2_ALG_ECC;
  266. size_t len = ext ? strlen(ext) : 0;
  267. if (len == 0 || ext[0] == '\0') {
  268. ext = "256";
  269. }
  270. TPMS_ECC_PARMS *e = &public->publicArea.parameters.eccDetail;
  271. e->kdf.scheme = TPM2_ALG_NULL;
  272. if (!strncmp(ext, "192", 3)) {
  273. e->curveID = TPM2_ECC_NIST_P192;
  274. ext += 3;
  275. } else if (!strncmp(ext, "224", 3)) {
  276. e->curveID = TPM2_ECC_NIST_P224;
  277. ext += 3;
  278. } else if (!strncmp(ext, "256", 3)) {
  279. e->curveID = TPM2_ECC_NIST_P256;
  280. ext += 3;
  281. } else if (!strncmp(ext, "384", 3)) {
  282. e->curveID = TPM2_ECC_NIST_P384;
  283. ext += 3;
  284. } else if (!strncmp(ext, "521", 3)) {
  285. e->curveID = TPM2_ECC_NIST_P521;
  286. ext += 3;
  287. } else {
  288. e->curveID = TPM2_ECC_NIST_P256;
  289. }
  290. /* ecc extension should be consumed at this point */
  291. return ext[0] == '\0' ? alg_parser_rc_continue : alg_parser_rc_error;
  292. }
  293. static alg_parser_rc handle_aes(const char *ext, TPM2B_PUBLIC *public) {
  294. public->publicArea.type = TPM2_ALG_SYMCIPHER;
  295. tpm2_errata_fixup(SPEC_116_ERRATA_2_7,
  296. &public->publicArea.objectAttributes);
  297. TPMT_SYM_DEF_OBJECT *s = &public->publicArea.parameters.symDetail.sym;
  298. s->algorithm = TPM2_ALG_AES;
  299. return handle_sym_common(ext, s);
  300. }
  301. static alg_parser_rc handle_camellia(const char *ext, TPM2B_PUBLIC *public) {
  302. public->publicArea.type = TPM2_ALG_SYMCIPHER;
  303. TPMT_SYM_DEF_OBJECT *s = &public->publicArea.parameters.symDetail.sym;
  304. s->algorithm = TPM2_ALG_CAMELLIA;
  305. return handle_sym_common(ext, s);
  306. }
  307. static alg_parser_rc handle_xor(TPM2B_PUBLIC *public) {
  308. public->publicArea.type = TPM2_ALG_KEYEDHASH;
  309. public->publicArea.parameters.keyedHashDetail.scheme.scheme = TPM2_ALG_XOR;
  310. return alg_parser_rc_continue;
  311. }
  312. static alg_parser_rc handle_hmac(TPM2B_PUBLIC *public) {
  313. public->publicArea.type = TPM2_ALG_KEYEDHASH;
  314. public->publicArea.parameters.keyedHashDetail.scheme.scheme = TPM2_ALG_HMAC;
  315. return alg_parser_rc_continue;
  316. }
  317. static alg_parser_rc handle_keyedhash(TPM2B_PUBLIC *public) {
  318. public->publicArea.type = TPM2_ALG_KEYEDHASH;
  319. public->publicArea.parameters.keyedHashDetail.scheme.scheme = TPM2_ALG_NULL;
  320. return alg_parser_rc_done;
  321. }
  322. static alg_parser_rc handle_object(const char *object, TPM2B_PUBLIC *public) {
  323. if (!strncmp(object, "rsa", 3)) {
  324. object += 3;
  325. return handle_rsa(object, public);
  326. } else if (!strncmp(object, "ecc", 3)) {
  327. object += 3;
  328. return handle_ecc(object, public);
  329. } else if (!strncmp(object, "aes", 3)) {
  330. object += 3;
  331. return handle_aes(object, public);
  332. } else if (!strncmp(object, "camellia", 8)) {
  333. object += 8;
  334. return handle_camellia(object, public);
  335. } else if (!strcmp(object, "hmac")) {
  336. return handle_hmac(public);
  337. } else if (!strcmp(object, "xor")) {
  338. return handle_xor(public);
  339. } else if (!strcmp(object, "keyedhash")) {
  340. return handle_keyedhash(public);
  341. }
  342. return alg_parser_rc_error;
  343. }
  344. static alg_parser_rc handle_scheme_keyedhash(const char *scheme,
  345. TPM2B_PUBLIC *public) {
  346. if (!scheme || scheme[0] == '\0') {
  347. scheme = "sha256";
  348. }
  349. TPM2_ALG_ID alg = tpm2_alg_util_strtoalg(scheme, tpm2_alg_util_flags_hash);
  350. if (alg == TPM2_ALG_ERROR) {
  351. return alg_parser_rc_error;
  352. }
  353. switch (public->publicArea.parameters.keyedHashDetail.scheme.scheme) {
  354. case TPM2_ALG_HMAC:
  355. public->publicArea.parameters.keyedHashDetail.scheme.details.hmac.hashAlg =
  356. alg;
  357. break;
  358. case TPM2_ALG_XOR:
  359. public->publicArea.parameters.keyedHashDetail.scheme.details.exclusiveOr.kdf =
  360. TPM2_ALG_KDF1_SP800_108;
  361. public->publicArea.parameters.keyedHashDetail.scheme.details.exclusiveOr.hashAlg =
  362. alg;
  363. break;
  364. default:
  365. return alg_parser_rc_error;
  366. }
  367. return alg_parser_rc_done;
  368. }
  369. static alg_parser_rc handle_scheme(const char *scheme, TPM2B_PUBLIC *public) {
  370. switch (public->publicArea.type) {
  371. case TPM2_ALG_RSA:
  372. case TPM2_ALG_ECC:
  373. return handle_scheme_sign(scheme, public);
  374. case TPM2_ALG_KEYEDHASH:
  375. return handle_scheme_keyedhash(scheme, public);
  376. default:
  377. return alg_parser_rc_error;
  378. }
  379. return alg_parser_rc_error;
  380. }
  381. static alg_parser_rc handle_asym_detail(const char *detail,
  382. TPM2B_PUBLIC *public) {
  383. bool is_restricted = !!(public->publicArea.objectAttributes
  384. & TPMA_OBJECT_RESTRICTED);
  385. bool is_rsapps = public->publicArea.parameters.asymDetail.scheme.scheme
  386. == TPM2_ALG_RSAPSS;
  387. switch (public->publicArea.type) {
  388. case TPM2_ALG_RSA:
  389. case TPM2_ALG_ECC:
  390. if (!detail || detail[0] == '\0') {
  391. detail = is_restricted || is_rsapps ? "aes128cfb" : "null";
  392. }
  393. TPMT_SYM_DEF_OBJECT *s = &public->publicArea.parameters.symDetail.sym;
  394. if (!strncmp(detail, "aes", 3)) {
  395. s->algorithm = TPM2_ALG_AES;
  396. return handle_sym_common(detail + 3, s);
  397. } else if (!strncmp(detail, "camellia", 8)) {
  398. s->algorithm = TPM2_ALG_CAMELLIA;
  399. return handle_sym_common(detail + 8, s);
  400. } else if (!strcmp(detail, "null")) {
  401. s->algorithm = TPM2_ALG_NULL;
  402. return alg_parser_rc_done;
  403. }
  404. /* no default */
  405. }
  406. return alg_parser_rc_error;
  407. }
  408. bool tpm2_alg_util_handle_ext_alg(const char *alg_spec, TPM2B_PUBLIC *public) {
  409. char buf[256];
  410. if (!alg_spec) {
  411. return false;
  412. }
  413. int rc = snprintf(buf, sizeof(buf), "%s", alg_spec);
  414. if (rc < 0 || (size_t) rc >= sizeof(buf)) {
  415. goto error;
  416. }
  417. char *object = NULL;
  418. char *scheme = NULL;
  419. char *symdetail = NULL;
  420. char *b = buf;
  421. char *tok = NULL;
  422. char *saveptr = NULL;
  423. unsigned i = 0;
  424. while ((tok = strtok_r(b, ":", &saveptr))) {
  425. b = NULL;
  426. switch (i) {
  427. case 0:
  428. object = tok;
  429. break;
  430. case 1:
  431. scheme = tok;
  432. break;
  433. case 2:
  434. symdetail = tok;
  435. break;
  436. default:
  437. goto error;
  438. }
  439. i++;
  440. }
  441. if (i == 0) {
  442. goto error;
  443. }
  444. alg_parser_rc prc = handle_object(object, public);
  445. if (prc == alg_parser_rc_done) {
  446. /* we must have exhausted all the entries or it's an error */
  447. return scheme || symdetail ? false : true;
  448. }
  449. if (prc == alg_parser_rc_error) {
  450. return false;
  451. }
  452. /*
  453. * at this point we either have scheme or asym detail, if it
  454. * doesn't process as a scheme shuffle it to asym detail
  455. */
  456. for (i = 0; i < 2; i++) {
  457. prc = handle_scheme(scheme, public);
  458. if (prc == alg_parser_rc_done) {
  459. /* we must have exhausted all the entries or it's an error */
  460. return symdetail ? false : true;
  461. }
  462. if (prc == alg_parser_rc_error) {
  463. /*
  464. * if symdetail is set scheme must be consumed
  465. * unless scheme has been skipped by setting it
  466. * to NULL
  467. */
  468. if (symdetail && scheme) {
  469. return false;
  470. }
  471. symdetail = scheme;
  472. scheme = NULL;
  473. continue;
  474. }
  475. /* success in processing scheme */
  476. break;
  477. }
  478. /* handle asym detail */
  479. prc = handle_asym_detail(symdetail, public);
  480. if (prc != alg_parser_rc_done) {
  481. goto error;
  482. }
  483. return true;
  484. error:
  485. LOG_ERR("Could not handle algorithm spec: \"%s\"", alg_spec);
  486. return false;
  487. }
  488. static alg_iter_res find_match(TPM2_ALG_ID id, const char *name,
  489. tpm2_alg_util_flags flags, void *userdata) {
  490. alg_pair *search_data = (alg_pair *) userdata;
  491. /*
  492. * if name, then search on name, else
  493. * search by id.
  494. */
  495. if (search_data->name && !strcmp(search_data->name, name)) {
  496. alg_iter_res res = search_data->flags & flags ? found : stop;
  497. if (res == found) {
  498. search_data->id = id;
  499. search_data->_flags = flags;
  500. }
  501. return res;
  502. } else if (search_data->id == id) {
  503. alg_iter_res res = search_data->flags & flags ? found : stop;
  504. if (res == found) {
  505. search_data->name = name;
  506. search_data->_flags = flags;
  507. }
  508. return res;
  509. }
  510. return go;
  511. }
  512. TPM2_ALG_ID tpm2_alg_util_strtoalg(const char *name, tpm2_alg_util_flags flags) {
  513. alg_pair userdata = { .name = name, .id = TPM2_ALG_ERROR, .flags = flags };
  514. if (name) {
  515. tpm2_alg_util_for_each_alg(find_match, &userdata);
  516. }
  517. return userdata.id;
  518. }
  519. const char *tpm2_alg_util_algtostr(TPM2_ALG_ID id, tpm2_alg_util_flags flags) {
  520. alg_pair userdata = { .name = NULL, .id = id, .flags = flags };
  521. tpm2_alg_util_for_each_alg(find_match, &userdata);
  522. return userdata.name;
  523. }
  524. tpm2_alg_util_flags tpm2_alg_util_algtoflags(TPM2_ALG_ID id) {
  525. alg_pair userdata = { .name = NULL, .id = id, .flags =
  526. tpm2_alg_util_flags_any, ._flags = tpm2_alg_util_flags_none };
  527. tpm2_alg_util_for_each_alg(find_match, &userdata);
  528. return userdata._flags;
  529. }
  530. TPM2_ALG_ID tpm2_alg_util_from_optarg(const char *optarg,
  531. tpm2_alg_util_flags flags) {
  532. TPM2_ALG_ID halg;
  533. bool res = tpm2_util_string_to_uint16(optarg, &halg);
  534. if (!res) {
  535. halg = tpm2_alg_util_strtoalg(optarg, flags);
  536. } else {
  537. if (!tpm2_alg_util_algtostr(halg, flags)) {
  538. return TPM2_ALG_ERROR;
  539. }
  540. }
  541. return halg;
  542. }
  543. UINT16 tpm2_alg_util_get_hash_size(TPMI_ALG_HASH id) {
  544. switch (id) {
  545. case TPM2_ALG_SHA1:
  546. return TPM2_SHA1_DIGEST_SIZE;
  547. case TPM2_ALG_SHA256:
  548. return TPM2_SHA256_DIGEST_SIZE;
  549. case TPM2_ALG_SHA384:
  550. return TPM2_SHA384_DIGEST_SIZE;
  551. case TPM2_ALG_SHA512:
  552. return TPM2_SHA512_DIGEST_SIZE;
  553. case TPM2_ALG_SM3_256:
  554. return TPM2_SM3_256_DIGEST_SIZE;
  555. /* no default */
  556. }
  557. return 0;
  558. }
  559. static const char *hex_to_byte_err(int rc) {
  560. switch (rc) {
  561. case -2:
  562. return "String not even in length";
  563. case -3:
  564. return "Non hex digit found";
  565. case -4:
  566. return "Hex value too big for digest";
  567. }
  568. return "unknown";
  569. }
  570. bool pcr_parse_digest_list(char **argv, int len,
  571. tpm2_pcr_digest_spec *digest_spec) {
  572. /*
  573. * int is chosen because of what is passed in from main, avoids
  574. * sign differences.
  575. * */
  576. int i;
  577. for (i = 0; i < len; i++) {
  578. tpm2_pcr_digest_spec *dspec = &digest_spec[i];
  579. UINT32 count = 0;
  580. /*
  581. * Split <pcr index>:<hash alg>=<hash value>,... on : and separate with null byte, ie:
  582. * <pce index> '\0' <hash alg>'\0'<data>
  583. *
  584. * Start by splitting out the pcr index, and validating it.
  585. */
  586. char *spec_str = argv[i];
  587. char *pcr_index_str = spec_str;
  588. char *digest_spec_str = strchr(spec_str, ':');
  589. if (!digest_spec_str) {
  590. LOG_ERR("Expecting : in digest spec, not found, got: \"%s\"",
  591. spec_str);
  592. return false;
  593. }
  594. *digest_spec_str = '\0';
  595. digest_spec_str++;
  596. bool result = pcr_get_id(pcr_index_str, &dspec->pcr_index);
  597. if (!result) {
  598. LOG_ERR("Got invalid PCR Index: \"%s\", in digest spec: \"%s\"",
  599. pcr_index_str, spec_str);
  600. return false;
  601. }
  602. /* now that the pcr_index is removed, parse the remaining <hash_name>=<hash_value>,.. */
  603. char *digest_hash_tok;
  604. char *save_ptr = NULL;
  605. /* keep track of digests we have seen */
  606. while ((digest_hash_tok = strtok_r(digest_spec_str, ",", &save_ptr))) {
  607. digest_spec_str = NULL;
  608. if (count >= ARRAY_LEN(dspec->digests.digests)) {
  609. LOG_ERR("Specified too many digests per spec, max is: %zu",
  610. ARRAY_LEN(dspec->digests.digests));
  611. return false;
  612. }
  613. TPMT_HA *d = &dspec->digests.digests[count];
  614. char *stralg = digest_hash_tok;
  615. char *split = strchr(digest_hash_tok, '=');
  616. if (!split) {
  617. LOG_ERR("Expecting = in <hash alg>=<hash value> spec, got: "
  618. "\"%s\"", digest_hash_tok);
  619. return false;
  620. }
  621. *split = '\0';
  622. split++;
  623. char *data = split;
  624. /*
  625. * Convert and validate the hash algorithm. It should be a hash algorithm
  626. */
  627. TPM2_ALG_ID alg = tpm2_alg_util_from_optarg(stralg,
  628. tpm2_alg_util_flags_hash);
  629. if (alg == TPM2_ALG_ERROR) {
  630. LOG_ERR("Could not convert algorithm, got: \"%s\"", stralg);
  631. return false;
  632. }
  633. d->hashAlg = alg;
  634. /* fill up the TPMT_HA structure with algorithm and digest */
  635. BYTE *digest_data = (BYTE *) &d->digest;
  636. UINT16 expected_hash_size = tpm2_alg_util_get_hash_size(alg);
  637. /* strip any preceding hex on the data as tpm2_util_hex_to_byte_structure doesn't support it */
  638. bool is_hex = !strncmp("0x", data, 2);
  639. if (is_hex) {
  640. data += 2;
  641. }
  642. UINT16 size = expected_hash_size;
  643. int rc = tpm2_util_hex_to_byte_structure(data, &size, digest_data);
  644. if (rc) {
  645. LOG_ERR("Error \"%s\" converting hex string as data, got:"
  646. " \"%s\"", hex_to_byte_err(rc), data);
  647. return false;
  648. }
  649. if (expected_hash_size != size) {
  650. LOG_ERR("Algorithm \"%s\" expects a size of %u bytes, got: %u",
  651. stralg, expected_hash_size, size);
  652. return false;
  653. }
  654. count++;
  655. }
  656. if (!count) {
  657. LOG_ERR("Missing or invalid <hash alg>=<hash value> spec for pcr:"
  658. " \"%s\"", pcr_index_str);
  659. return false;
  660. }
  661. /* assign count at the end, so count is 0 on error */
  662. dspec->digests.count = count;
  663. }
  664. return true;
  665. }
  666. static tool_rc tpm2_public_to_scheme(ESYS_CONTEXT *ectx, ESYS_TR key, TPMI_ALG_PUBLIC *type,
  667. TPMT_SIG_SCHEME *sigscheme) {
  668. tool_rc rc = tool_rc_general_error;
  669. TPM2B_PUBLIC *out_public = NULL;
  670. rc = tpm2_readpublic(ectx, key, &out_public, NULL, NULL);
  671. if (rc != tool_rc_success) {
  672. return rc;
  673. }
  674. *type = out_public->publicArea.type;
  675. TPMU_PUBLIC_PARMS *pp = &out_public->publicArea.parameters;
  676. /*
  677. * Symmetric ciphers do not have signature algorithms
  678. */
  679. if (*type == TPM2_ALG_SYMCIPHER) {
  680. LOG_ERR("Cannot convert symmetric cipher to signature algorithm");
  681. goto out;
  682. }
  683. /*
  684. * Now we are looking at specific algorithms that the keys
  685. * are bound to, so we need to populate that in the scheme
  686. */
  687. if ((*type == TPM2_ALG_RSA || *type == TPM2_ALG_ECC)) {
  688. sigscheme->scheme = pp->asymDetail.scheme.scheme;
  689. /* they all have a hash alg, and for most schemes' thats it */
  690. sigscheme->details.any.hashAlg
  691. = pp->asymDetail.scheme.details.anySig.hashAlg;
  692. rc = tool_rc_success;
  693. goto out;
  694. }
  695. /* keyed hash could be the only one left */
  696. sigscheme->scheme = pp->keyedHashDetail.scheme.scheme;
  697. sigscheme->details.hmac.hashAlg = pp->keyedHashDetail.scheme.details.hmac.hashAlg;
  698. rc = tool_rc_success;
  699. out:
  700. Esys_Free(out_public);
  701. return rc;
  702. }
  703. static bool is_null_alg(TPM2_ALG_ID alg) {
  704. return !alg || alg == TPM2_ALG_NULL;
  705. }
  706. tool_rc tpm2_alg_util_get_signature_scheme(ESYS_CONTEXT *ectx,
  707. ESYS_TR key_handle, TPMI_ALG_HASH *halg, TPMI_ALG_SIG_SCHEME sig_scheme,
  708. TPMT_SIG_SCHEME *scheme) {
  709. TPMI_ALG_PUBLIC type = TPM2_ALG_NULL;
  710. TPMT_SIG_SCHEME object_sigscheme = { 0 };
  711. tool_rc rc = tpm2_public_to_scheme(ectx, key_handle, &type, &object_sigscheme);
  712. if (rc != tool_rc_success) {
  713. return rc;
  714. }
  715. LOG_INFO("hashing alg in: 0x%x", *halg);
  716. LOG_INFO("sig scheme in: 0x%x", sig_scheme);
  717. /*
  718. * if scheme is requested by the user, verify the scheme will work
  719. */
  720. if (!is_null_alg(sig_scheme) && !is_null_alg(object_sigscheme.scheme)
  721. && object_sigscheme.scheme != sig_scheme) {
  722. LOG_ERR("Requested sign scheme \"%s\" but object only supports sign scheme \%s\")",
  723. tpm2_alg_util_algtostr(sig_scheme, tpm2_alg_util_flags_any),
  724. tpm2_alg_util_algtostr(object_sigscheme.scheme, tpm2_alg_util_flags_any));
  725. return tool_rc_general_error;
  726. } else {
  727. /*
  728. * set a default for RSA, ECC or KEYEDHASH
  729. * Not ECDAA, it wasn't chosen because it needs count as well,
  730. * so any.hashAlg doesn't work. Aksim what would you pick for count?
  731. * See bug #2071 to figure out what to do if an ECDAA scheme comes back.
  732. *
  733. * Assign scheme based on type:
  734. * TPM2_ALG_RSA --> TPM2_ALG_RSSASSA
  735. * TPM2_ALG_ECC --> TPM2_ALG_ECDSA
  736. * TPM2_ALG_KEYEDHASH --> TPM2_ALG_HMAC
  737. */
  738. if (is_null_alg(sig_scheme)) {
  739. object_sigscheme.scheme = (type == TPM2_ALG_RSA) ? TPM2_ALG_RSASSA :
  740. (type == TPM2_ALG_ECC) ? TPM2_ALG_ECDSA : TPM2_ALG_HMAC;
  741. } else {
  742. object_sigscheme.scheme = sig_scheme;
  743. }
  744. }
  745. /* if hash alg is requested by the user, verify the hash alg will work */
  746. if (!is_null_alg(*halg) && !is_null_alg(object_sigscheme.details.any.hashAlg)
  747. && object_sigscheme.details.any.hashAlg != *halg) {
  748. LOG_ERR("Requested signature hash alg \"%s\" but object only supports signature hash alg \%s\")",
  749. tpm2_alg_util_algtostr(*halg, tpm2_alg_util_flags_any),
  750. tpm2_alg_util_algtostr(object_sigscheme.details.any.hashAlg, tpm2_alg_util_flags_any));
  751. return tool_rc_general_error;
  752. } else {
  753. object_sigscheme.details.any.hashAlg = is_null_alg(*halg) ? TPM2_ALG_SHA256 :
  754. *halg;
  755. }
  756. /* everything requested matches, or we got defaults move along */
  757. *halg = object_sigscheme.details.any.hashAlg;
  758. *scheme = object_sigscheme;
  759. LOG_INFO("halg out: 0x%x", *halg);
  760. LOG_INFO("sig scheme out: 0x%x", scheme->scheme);
  761. return tool_rc_success;
  762. }
  763. tool_rc tpm2_alg_util_public_init(char *alg_details, char *name_halg, char *attrs,
  764. char *auth_policy, TPMA_OBJECT def_attrs, TPM2B_PUBLIC *public) {
  765. memset(public, 0, sizeof(*public));
  766. /* load a policy from a path if present */
  767. if (auth_policy) {
  768. public->publicArea.authPolicy.size =
  769. sizeof(public->publicArea.authPolicy.buffer);
  770. bool res = files_load_bytes_from_path(auth_policy,
  771. public->publicArea.authPolicy.buffer,
  772. &public->publicArea.authPolicy.size);
  773. if (!res) {
  774. return tool_rc_general_error;
  775. }
  776. }
  777. /* Set the hashing algorithm used for object name */
  778. public->publicArea.nameAlg = name_halg ?
  779. tpm2_alg_util_from_optarg(name_halg, tpm2_alg_util_flags_hash) :
  780. TPM2_ALG_SHA256;
  781. if (public->publicArea.nameAlg == TPM2_ALG_ERROR) {
  782. LOG_ERR("Invalid name hashing algorithm, got\"%s\"", name_halg);
  783. return tool_rc_unsupported;
  784. }
  785. /* Set specified attributes or use default */
  786. if (attrs) {
  787. bool res = tpm2_attr_util_obj_from_optarg(attrs,
  788. &public->publicArea.objectAttributes);
  789. if (!res) {
  790. return tool_rc_unsupported;
  791. }
  792. } else {
  793. public->publicArea.objectAttributes = def_attrs;
  794. }
  795. /*
  796. * Some defaults may not be OK with the specified algorithms, if their defaults,
  797. * tweak the Object Attributes, if specified by user, complain things will not
  798. * work together and suggest attributes. This allows the user to verify what the
  799. * want.
  800. */
  801. TPM2B_PUBLIC tmp = *public;
  802. bool res = tpm2_alg_util_handle_ext_alg(alg_details, &tmp);
  803. if (!res) {
  804. return tool_rc_unsupported;
  805. }
  806. if (attrs && tmp.publicArea.objectAttributes !=
  807. public->publicArea.objectAttributes) {
  808. char *proposed_attrs = tpm2_attr_util_obj_attrtostr(
  809. tmp.publicArea.objectAttributes);
  810. LOG_ERR("Specified attributes \"%s\" and algorithm specifier \"%s\" do "
  811. "not work together, try attributes: \"%s\"", attrs, alg_details,
  812. proposed_attrs);
  813. free(proposed_attrs);
  814. return tool_rc_unsupported;
  815. }
  816. *public = tmp;
  817. return tool_rc_success;
  818. }
  819. const char *tpm2_alg_util_ecc_to_str(TPM2_ECC_CURVE curve_id) {
  820. switch (curve_id) {
  821. case TPM2_ECC_NIST_P192:
  822. return "NIST p192";
  823. case TPM2_ECC_NIST_P224:
  824. return "NIST p224";
  825. case TPM2_ECC_NIST_P256:
  826. return "NIST p256";
  827. case TPM2_ECC_NIST_P384:
  828. return "NIST p384";
  829. case TPM2_ECC_NIST_P521:
  830. return "NIST 521";
  831. case TPM2_ECC_BN_P256:
  832. return "BN P256";
  833. case TPM2_ECC_BN_P638:
  834. return "BN P638";
  835. case TPM2_ECC_SM2_P256:
  836. return "SM2 p256";
  837. /* no default */
  838. }
  839. return NULL;
  840. }
  841. bool tpm2_alg_util_is_aes_size_valid(UINT16 size_in_bytes) {
  842. switch (size_in_bytes) {
  843. case 16:
  844. case 24:
  845. case 32:
  846. return true;
  847. default:
  848. LOG_ERR("Invalid AES key size, got %u bytes, expected 16,24 or 32",
  849. size_in_bytes);
  850. return false;
  851. }
  852. }