ssh-sk.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830
  1. /* $OpenBSD: ssh-sk.c,v 1.32 2020/09/09 03:08:02 djm Exp $ */
  2. /*
  3. * Copyright (c) 2019 Google LLC
  4. *
  5. * Permission to use, copy, modify, and distribute this software for any
  6. * purpose with or without fee is hereby granted, provided that the above
  7. * copyright notice and this permission notice appear in all copies.
  8. *
  9. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  10. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  11. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  12. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  13. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  14. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  15. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  16. */
  17. /* #define DEBUG_SK 1 */
  18. #include "includes.h"
  19. #ifdef ENABLE_SK
  20. #include <dlfcn.h>
  21. #include <stddef.h>
  22. #ifdef HAVE_STDINT_H
  23. # include <stdint.h>
  24. #endif
  25. #include <string.h>
  26. #include <stdio.h>
  27. #ifdef WITH_OPENSSL
  28. #include <openssl/objects.h>
  29. #include <openssl/ec.h>
  30. #endif /* WITH_OPENSSL */
  31. #include "log.h"
  32. #include "misc.h"
  33. #include "sshbuf.h"
  34. #include "sshkey.h"
  35. #include "ssherr.h"
  36. #include "digest.h"
  37. #include "ssh-sk.h"
  38. #include "sk-api.h"
  39. #include "crypto_api.h"
  40. struct sshsk_provider {
  41. char *path;
  42. void *dlhandle;
  43. /* Return the version of the middleware API */
  44. uint32_t (*sk_api_version)(void);
  45. /* Enroll a U2F key (private key generation) */
  46. int (*sk_enroll)(int alg, const uint8_t *challenge,
  47. size_t challenge_len, const char *application, uint8_t flags,
  48. const char *pin, struct sk_option **opts,
  49. struct sk_enroll_response **enroll_response);
  50. /* Sign a challenge */
  51. int (*sk_sign)(int alg, const uint8_t *message, size_t message_len,
  52. const char *application,
  53. const uint8_t *key_handle, size_t key_handle_len,
  54. uint8_t flags, const char *pin, struct sk_option **opts,
  55. struct sk_sign_response **sign_response);
  56. /* Enumerate resident keys */
  57. int (*sk_load_resident_keys)(const char *pin, struct sk_option **opts,
  58. struct sk_resident_key ***rks, size_t *nrks);
  59. };
  60. /* Built-in version */
  61. int ssh_sk_enroll(int alg, const uint8_t *challenge,
  62. size_t challenge_len, const char *application, uint8_t flags,
  63. const char *pin, struct sk_option **opts,
  64. struct sk_enroll_response **enroll_response);
  65. int ssh_sk_sign(int alg, const uint8_t *message, size_t message_len,
  66. const char *application,
  67. const uint8_t *key_handle, size_t key_handle_len,
  68. uint8_t flags, const char *pin, struct sk_option **opts,
  69. struct sk_sign_response **sign_response);
  70. int ssh_sk_load_resident_keys(const char *pin, struct sk_option **opts,
  71. struct sk_resident_key ***rks, size_t *nrks);
  72. static void
  73. sshsk_free(struct sshsk_provider *p)
  74. {
  75. if (p == NULL)
  76. return;
  77. free(p->path);
  78. if (p->dlhandle != NULL)
  79. dlclose(p->dlhandle);
  80. free(p);
  81. }
  82. static struct sshsk_provider *
  83. sshsk_open(const char *path)
  84. {
  85. struct sshsk_provider *ret = NULL;
  86. uint32_t version;
  87. if (path == NULL || *path == '\0') {
  88. error("No FIDO SecurityKeyProvider specified");
  89. return NULL;
  90. }
  91. if ((ret = calloc(1, sizeof(*ret))) == NULL) {
  92. error("%s: calloc failed", __func__);
  93. return NULL;
  94. }
  95. if ((ret->path = strdup(path)) == NULL) {
  96. error("%s: strdup failed", __func__);
  97. goto fail;
  98. }
  99. /* Skip the rest if we're using the linked in middleware */
  100. if (strcasecmp(ret->path, "internal") == 0) {
  101. #ifdef ENABLE_SK_INTERNAL
  102. ret->sk_enroll = ssh_sk_enroll;
  103. ret->sk_sign = ssh_sk_sign;
  104. ret->sk_load_resident_keys = ssh_sk_load_resident_keys;
  105. #else
  106. error("internal security key support not enabled");
  107. #endif
  108. return ret;
  109. }
  110. if ((ret->dlhandle = dlopen(path, RTLD_NOW)) == NULL) {
  111. error("Provider \"%s\" dlopen failed: %s", path, dlerror());
  112. goto fail;
  113. }
  114. if ((ret->sk_api_version = dlsym(ret->dlhandle,
  115. "sk_api_version")) == NULL) {
  116. error("Provider \"%s\" dlsym(sk_api_version) failed: %s",
  117. path, dlerror());
  118. goto fail;
  119. }
  120. version = ret->sk_api_version();
  121. debug("%s: provider %s implements version 0x%08lx", __func__,
  122. ret->path, (u_long)version);
  123. if ((version & SSH_SK_VERSION_MAJOR_MASK) != SSH_SK_VERSION_MAJOR) {
  124. error("Provider \"%s\" implements unsupported "
  125. "version 0x%08lx (supported: 0x%08lx)",
  126. path, (u_long)version, (u_long)SSH_SK_VERSION_MAJOR);
  127. goto fail;
  128. }
  129. if ((ret->sk_enroll = dlsym(ret->dlhandle, "sk_enroll")) == NULL) {
  130. error("Provider %s dlsym(sk_enroll) failed: %s",
  131. path, dlerror());
  132. goto fail;
  133. }
  134. if ((ret->sk_sign = dlsym(ret->dlhandle, "sk_sign")) == NULL) {
  135. error("Provider \"%s\" dlsym(sk_sign) failed: %s",
  136. path, dlerror());
  137. goto fail;
  138. }
  139. if ((ret->sk_load_resident_keys = dlsym(ret->dlhandle,
  140. "sk_load_resident_keys")) == NULL) {
  141. error("Provider \"%s\" dlsym(sk_load_resident_keys) "
  142. "failed: %s", path, dlerror());
  143. goto fail;
  144. }
  145. /* success */
  146. return ret;
  147. fail:
  148. sshsk_free(ret);
  149. return NULL;
  150. }
  151. static void
  152. sshsk_free_enroll_response(struct sk_enroll_response *r)
  153. {
  154. if (r == NULL)
  155. return;
  156. freezero(r->key_handle, r->key_handle_len);
  157. freezero(r->public_key, r->public_key_len);
  158. freezero(r->signature, r->signature_len);
  159. freezero(r->attestation_cert, r->attestation_cert_len);
  160. freezero(r->authdata, r->authdata_len);
  161. freezero(r, sizeof(*r));
  162. }
  163. static void
  164. sshsk_free_sign_response(struct sk_sign_response *r)
  165. {
  166. if (r == NULL)
  167. return;
  168. freezero(r->sig_r, r->sig_r_len);
  169. freezero(r->sig_s, r->sig_s_len);
  170. freezero(r, sizeof(*r));
  171. }
  172. #ifdef WITH_OPENSSL
  173. /* Assemble key from response */
  174. static int
  175. sshsk_ecdsa_assemble(struct sk_enroll_response *resp, struct sshkey **keyp)
  176. {
  177. struct sshkey *key = NULL;
  178. struct sshbuf *b = NULL;
  179. EC_POINT *q = NULL;
  180. int r;
  181. *keyp = NULL;
  182. if ((key = sshkey_new(KEY_ECDSA_SK)) == NULL) {
  183. error("%s: sshkey_new failed", __func__);
  184. r = SSH_ERR_ALLOC_FAIL;
  185. goto out;
  186. }
  187. key->ecdsa_nid = NID_X9_62_prime256v1;
  188. if ((key->ecdsa = EC_KEY_new_by_curve_name(key->ecdsa_nid)) == NULL ||
  189. (q = EC_POINT_new(EC_KEY_get0_group(key->ecdsa))) == NULL ||
  190. (b = sshbuf_new()) == NULL) {
  191. error("%s: allocation failed", __func__);
  192. r = SSH_ERR_ALLOC_FAIL;
  193. goto out;
  194. }
  195. if ((r = sshbuf_put_string(b,
  196. resp->public_key, resp->public_key_len)) != 0) {
  197. error("%s: buffer error: %s", __func__, ssh_err(r));
  198. goto out;
  199. }
  200. if ((r = sshbuf_get_ec(b, q, EC_KEY_get0_group(key->ecdsa))) != 0) {
  201. error("%s: parse key: %s", __func__, ssh_err(r));
  202. r = SSH_ERR_INVALID_FORMAT;
  203. goto out;
  204. }
  205. if (sshkey_ec_validate_public(EC_KEY_get0_group(key->ecdsa), q) != 0) {
  206. error("Authenticator returned invalid ECDSA key");
  207. r = SSH_ERR_KEY_INVALID_EC_VALUE;
  208. goto out;
  209. }
  210. if (EC_KEY_set_public_key(key->ecdsa, q) != 1) {
  211. /* XXX assume it is a allocation error */
  212. error("%s: allocation failed", __func__);
  213. r = SSH_ERR_ALLOC_FAIL;
  214. goto out;
  215. }
  216. /* success */
  217. *keyp = key;
  218. key = NULL; /* transferred */
  219. r = 0;
  220. out:
  221. EC_POINT_free(q);
  222. sshkey_free(key);
  223. sshbuf_free(b);
  224. return r;
  225. }
  226. #endif /* WITH_OPENSSL */
  227. static int
  228. sshsk_ed25519_assemble(struct sk_enroll_response *resp, struct sshkey **keyp)
  229. {
  230. struct sshkey *key = NULL;
  231. int r;
  232. *keyp = NULL;
  233. if (resp->public_key_len != ED25519_PK_SZ) {
  234. error("%s: invalid size: %zu", __func__, resp->public_key_len);
  235. r = SSH_ERR_INVALID_FORMAT;
  236. goto out;
  237. }
  238. if ((key = sshkey_new(KEY_ED25519_SK)) == NULL) {
  239. error("%s: sshkey_new failed", __func__);
  240. r = SSH_ERR_ALLOC_FAIL;
  241. goto out;
  242. }
  243. if ((key->ed25519_pk = malloc(ED25519_PK_SZ)) == NULL) {
  244. error("%s: malloc failed", __func__);
  245. r = SSH_ERR_ALLOC_FAIL;
  246. goto out;
  247. }
  248. memcpy(key->ed25519_pk, resp->public_key, ED25519_PK_SZ);
  249. /* success */
  250. *keyp = key;
  251. key = NULL; /* transferred */
  252. r = 0;
  253. out:
  254. sshkey_free(key);
  255. return r;
  256. }
  257. static int
  258. sshsk_key_from_response(int alg, const char *application, uint8_t flags,
  259. struct sk_enroll_response *resp, struct sshkey **keyp)
  260. {
  261. struct sshkey *key = NULL;
  262. int r = SSH_ERR_INTERNAL_ERROR;
  263. *keyp = NULL;
  264. /* Check response validity */
  265. if (resp->public_key == NULL || resp->key_handle == NULL) {
  266. error("%s: sk_enroll response invalid", __func__);
  267. r = SSH_ERR_INVALID_FORMAT;
  268. goto out;
  269. }
  270. switch (alg) {
  271. #ifdef WITH_OPENSSL
  272. case SSH_SK_ECDSA:
  273. if ((r = sshsk_ecdsa_assemble(resp, &key)) != 0)
  274. goto out;
  275. break;
  276. #endif /* WITH_OPENSSL */
  277. case SSH_SK_ED25519:
  278. if ((r = sshsk_ed25519_assemble(resp, &key)) != 0)
  279. goto out;
  280. break;
  281. default:
  282. error("%s: unsupported algorithm %d", __func__, alg);
  283. r = SSH_ERR_INVALID_ARGUMENT;
  284. goto out;
  285. }
  286. key->sk_flags = flags;
  287. if ((key->sk_key_handle = sshbuf_new()) == NULL ||
  288. (key->sk_reserved = sshbuf_new()) == NULL) {
  289. error("%s: allocation failed", __func__);
  290. r = SSH_ERR_ALLOC_FAIL;
  291. goto out;
  292. }
  293. if ((key->sk_application = strdup(application)) == NULL) {
  294. error("%s: strdup application failed", __func__);
  295. r = SSH_ERR_ALLOC_FAIL;
  296. goto out;
  297. }
  298. if ((r = sshbuf_put(key->sk_key_handle, resp->key_handle,
  299. resp->key_handle_len)) != 0) {
  300. error("%s: buffer error: %s", __func__, ssh_err(r));
  301. goto out;
  302. }
  303. /* success */
  304. r = 0;
  305. *keyp = key;
  306. key = NULL;
  307. out:
  308. sshkey_free(key);
  309. return r;
  310. }
  311. static int
  312. skerr_to_ssherr(int skerr)
  313. {
  314. switch (skerr) {
  315. case SSH_SK_ERR_UNSUPPORTED:
  316. return SSH_ERR_FEATURE_UNSUPPORTED;
  317. case SSH_SK_ERR_PIN_REQUIRED:
  318. return SSH_ERR_KEY_WRONG_PASSPHRASE;
  319. case SSH_SK_ERR_DEVICE_NOT_FOUND:
  320. return SSH_ERR_DEVICE_NOT_FOUND;
  321. case SSH_SK_ERR_GENERAL:
  322. default:
  323. return SSH_ERR_INVALID_FORMAT;
  324. }
  325. }
  326. static void
  327. sshsk_free_options(struct sk_option **opts)
  328. {
  329. size_t i;
  330. if (opts == NULL)
  331. return;
  332. for (i = 0; opts[i] != NULL; i++) {
  333. free(opts[i]->name);
  334. free(opts[i]->value);
  335. free(opts[i]);
  336. }
  337. free(opts);
  338. }
  339. static int
  340. sshsk_add_option(struct sk_option ***optsp, size_t *noptsp,
  341. const char *name, const char *value, uint8_t required)
  342. {
  343. struct sk_option **opts = *optsp;
  344. size_t nopts = *noptsp;
  345. if ((opts = recallocarray(opts, nopts, nopts + 2, /* extra for NULL */
  346. sizeof(*opts))) == NULL) {
  347. error("%s: array alloc failed", __func__);
  348. return SSH_ERR_ALLOC_FAIL;
  349. }
  350. *optsp = opts;
  351. *noptsp = nopts + 1;
  352. if ((opts[nopts] = calloc(1, sizeof(**opts))) == NULL) {
  353. error("%s: alloc failed", __func__);
  354. return SSH_ERR_ALLOC_FAIL;
  355. }
  356. if ((opts[nopts]->name = strdup(name)) == NULL ||
  357. (opts[nopts]->value = strdup(value)) == NULL) {
  358. error("%s: alloc failed", __func__);
  359. return SSH_ERR_ALLOC_FAIL;
  360. }
  361. opts[nopts]->required = required;
  362. return 0;
  363. }
  364. static int
  365. make_options(const char *device, const char *user_id,
  366. struct sk_option ***optsp)
  367. {
  368. struct sk_option **opts = NULL;
  369. size_t nopts = 0;
  370. int r, ret = SSH_ERR_INTERNAL_ERROR;
  371. if (device != NULL &&
  372. (r = sshsk_add_option(&opts, &nopts, "device", device, 0)) != 0) {
  373. ret = r;
  374. goto out;
  375. }
  376. if (user_id != NULL &&
  377. (r = sshsk_add_option(&opts, &nopts, "user", user_id, 0)) != 0) {
  378. ret = r;
  379. goto out;
  380. }
  381. /* success */
  382. *optsp = opts;
  383. opts = NULL;
  384. nopts = 0;
  385. ret = 0;
  386. out:
  387. sshsk_free_options(opts);
  388. return ret;
  389. }
  390. static int
  391. fill_attestation_blob(const struct sk_enroll_response *resp,
  392. struct sshbuf *attest)
  393. {
  394. int r;
  395. if (attest == NULL)
  396. return 0; /* nothing to do */
  397. if ((r = sshbuf_put_cstring(attest, "ssh-sk-attest-v01")) != 0 ||
  398. (r = sshbuf_put_string(attest,
  399. resp->attestation_cert, resp->attestation_cert_len)) != 0 ||
  400. (r = sshbuf_put_string(attest,
  401. resp->signature, resp->signature_len)) != 0 ||
  402. (r = sshbuf_put_string(attest,
  403. resp->authdata, resp->authdata_len)) != 0 ||
  404. (r = sshbuf_put_u32(attest, 0)) != 0 || /* resvd flags */
  405. (r = sshbuf_put_string(attest, NULL, 0)) != 0 /* resvd */) {
  406. error("%s: buffer error: %s", __func__, ssh_err(r));
  407. return r;
  408. }
  409. /* success */
  410. return 0;
  411. }
  412. int
  413. sshsk_enroll(int type, const char *provider_path, const char *device,
  414. const char *application, const char *userid, uint8_t flags,
  415. const char *pin, struct sshbuf *challenge_buf,
  416. struct sshkey **keyp, struct sshbuf *attest)
  417. {
  418. struct sshsk_provider *skp = NULL;
  419. struct sshkey *key = NULL;
  420. u_char randchall[32];
  421. const u_char *challenge;
  422. size_t challenge_len;
  423. struct sk_enroll_response *resp = NULL;
  424. struct sk_option **opts = NULL;
  425. int r = SSH_ERR_INTERNAL_ERROR;
  426. int alg;
  427. debug("%s: provider \"%s\", device \"%s\", application \"%s\", "
  428. "userid \"%s\", flags 0x%02x, challenge len %zu%s", __func__,
  429. provider_path, device, application, userid, flags,
  430. challenge_buf == NULL ? 0 : sshbuf_len(challenge_buf),
  431. (pin != NULL && *pin != '\0') ? " with-pin" : "");
  432. *keyp = NULL;
  433. if (attest)
  434. sshbuf_reset(attest);
  435. if ((r = make_options(device, userid, &opts)) != 0)
  436. goto out;
  437. switch (type) {
  438. #ifdef WITH_OPENSSL
  439. case KEY_ECDSA_SK:
  440. alg = SSH_SK_ECDSA;
  441. break;
  442. #endif /* WITH_OPENSSL */
  443. case KEY_ED25519_SK:
  444. alg = SSH_SK_ED25519;
  445. break;
  446. default:
  447. error("%s: unsupported key type", __func__);
  448. r = SSH_ERR_INVALID_ARGUMENT;
  449. goto out;
  450. }
  451. if (provider_path == NULL) {
  452. error("%s: missing provider", __func__);
  453. r = SSH_ERR_INVALID_ARGUMENT;
  454. goto out;
  455. }
  456. if (application == NULL || *application == '\0') {
  457. error("%s: missing application", __func__);
  458. r = SSH_ERR_INVALID_ARGUMENT;
  459. goto out;
  460. }
  461. if (challenge_buf == NULL) {
  462. debug("%s: using random challenge", __func__);
  463. arc4random_buf(randchall, sizeof(randchall));
  464. challenge = randchall;
  465. challenge_len = sizeof(randchall);
  466. } else if (sshbuf_len(challenge_buf) == 0) {
  467. error("Missing enrollment challenge");
  468. r = SSH_ERR_INVALID_ARGUMENT;
  469. goto out;
  470. } else {
  471. challenge = sshbuf_ptr(challenge_buf);
  472. challenge_len = sshbuf_len(challenge_buf);
  473. debug3("%s: using explicit challenge len=%zd",
  474. __func__, challenge_len);
  475. }
  476. if ((skp = sshsk_open(provider_path)) == NULL) {
  477. r = SSH_ERR_INVALID_FORMAT; /* XXX sshsk_open return code? */
  478. goto out;
  479. }
  480. /* XXX validate flags? */
  481. /* enroll key */
  482. if ((r = skp->sk_enroll(alg, challenge, challenge_len, application,
  483. flags, pin, opts, &resp)) != 0) {
  484. debug("%s: provider \"%s\" returned failure %d", __func__,
  485. provider_path, r);
  486. r = skerr_to_ssherr(r);
  487. goto out;
  488. }
  489. if ((r = sshsk_key_from_response(alg, application, flags,
  490. resp, &key)) != 0)
  491. goto out;
  492. /* Optionally fill in the attestation information */
  493. if ((r = fill_attestation_blob(resp, attest)) != 0)
  494. goto out;
  495. /* success */
  496. *keyp = key;
  497. key = NULL; /* transferred */
  498. r = 0;
  499. out:
  500. sshsk_free_options(opts);
  501. sshsk_free(skp);
  502. sshkey_free(key);
  503. sshsk_free_enroll_response(resp);
  504. explicit_bzero(randchall, sizeof(randchall));
  505. return r;
  506. }
  507. #ifdef WITH_OPENSSL
  508. static int
  509. sshsk_ecdsa_sig(struct sk_sign_response *resp, struct sshbuf *sig)
  510. {
  511. struct sshbuf *inner_sig = NULL;
  512. int r = SSH_ERR_INTERNAL_ERROR;
  513. /* Check response validity */
  514. if (resp->sig_r == NULL || resp->sig_s == NULL) {
  515. error("%s: sk_sign response invalid", __func__);
  516. r = SSH_ERR_INVALID_FORMAT;
  517. goto out;
  518. }
  519. if ((inner_sig = sshbuf_new()) == NULL) {
  520. r = SSH_ERR_ALLOC_FAIL;
  521. goto out;
  522. }
  523. /* Prepare and append inner signature object */
  524. if ((r = sshbuf_put_bignum2_bytes(inner_sig,
  525. resp->sig_r, resp->sig_r_len)) != 0 ||
  526. (r = sshbuf_put_bignum2_bytes(inner_sig,
  527. resp->sig_s, resp->sig_s_len)) != 0) {
  528. debug("%s: buffer error: %s", __func__, ssh_err(r));
  529. goto out;
  530. }
  531. if ((r = sshbuf_put_stringb(sig, inner_sig)) != 0 ||
  532. (r = sshbuf_put_u8(sig, resp->flags)) != 0 ||
  533. (r = sshbuf_put_u32(sig, resp->counter)) != 0) {
  534. debug("%s: buffer error: %s", __func__, ssh_err(r));
  535. goto out;
  536. }
  537. #ifdef DEBUG_SK
  538. fprintf(stderr, "%s: sig_r:\n", __func__);
  539. sshbuf_dump_data(resp->sig_r, resp->sig_r_len, stderr);
  540. fprintf(stderr, "%s: sig_s:\n", __func__);
  541. sshbuf_dump_data(resp->sig_s, resp->sig_s_len, stderr);
  542. fprintf(stderr, "%s: inner:\n", __func__);
  543. sshbuf_dump(inner_sig, stderr);
  544. #endif
  545. r = 0;
  546. out:
  547. sshbuf_free(inner_sig);
  548. return r;
  549. }
  550. #endif /* WITH_OPENSSL */
  551. static int
  552. sshsk_ed25519_sig(struct sk_sign_response *resp, struct sshbuf *sig)
  553. {
  554. int r = SSH_ERR_INTERNAL_ERROR;
  555. /* Check response validity */
  556. if (resp->sig_r == NULL) {
  557. error("%s: sk_sign response invalid", __func__);
  558. r = SSH_ERR_INVALID_FORMAT;
  559. goto out;
  560. }
  561. if ((r = sshbuf_put_string(sig,
  562. resp->sig_r, resp->sig_r_len)) != 0 ||
  563. (r = sshbuf_put_u8(sig, resp->flags)) != 0 ||
  564. (r = sshbuf_put_u32(sig, resp->counter)) != 0) {
  565. debug("%s: buffer error: %s", __func__, ssh_err(r));
  566. goto out;
  567. }
  568. #ifdef DEBUG_SK
  569. fprintf(stderr, "%s: sig_r:\n", __func__);
  570. sshbuf_dump_data(resp->sig_r, resp->sig_r_len, stderr);
  571. #endif
  572. r = 0;
  573. out:
  574. return r;
  575. }
  576. int
  577. sshsk_sign(const char *provider_path, struct sshkey *key,
  578. u_char **sigp, size_t *lenp, const u_char *data, size_t datalen,
  579. u_int compat, const char *pin)
  580. {
  581. struct sshsk_provider *skp = NULL;
  582. int r = SSH_ERR_INTERNAL_ERROR;
  583. int type, alg;
  584. struct sk_sign_response *resp = NULL;
  585. struct sshbuf *inner_sig = NULL, *sig = NULL;
  586. struct sk_option **opts = NULL;
  587. debug("%s: provider \"%s\", key %s, flags 0x%02x%s", __func__,
  588. provider_path, sshkey_type(key), key->sk_flags,
  589. (pin != NULL && *pin != '\0') ? " with-pin" : "");
  590. if (sigp != NULL)
  591. *sigp = NULL;
  592. if (lenp != NULL)
  593. *lenp = 0;
  594. type = sshkey_type_plain(key->type);
  595. switch (type) {
  596. #ifdef WITH_OPENSSL
  597. case KEY_ECDSA_SK:
  598. alg = SSH_SK_ECDSA;
  599. break;
  600. #endif /* WITH_OPENSSL */
  601. case KEY_ED25519_SK:
  602. alg = SSH_SK_ED25519;
  603. break;
  604. default:
  605. return SSH_ERR_INVALID_ARGUMENT;
  606. }
  607. if (provider_path == NULL ||
  608. key->sk_key_handle == NULL ||
  609. key->sk_application == NULL || *key->sk_application == '\0') {
  610. r = SSH_ERR_INVALID_ARGUMENT;
  611. goto out;
  612. }
  613. if ((skp = sshsk_open(provider_path)) == NULL) {
  614. r = SSH_ERR_INVALID_FORMAT; /* XXX sshsk_open return code? */
  615. goto out;
  616. }
  617. #ifdef DEBUG_SK
  618. fprintf(stderr, "%s: sk_flags = 0x%02x, sk_application = \"%s\"\n",
  619. __func__, key->sk_flags, key->sk_application);
  620. fprintf(stderr, "%s: sk_key_handle:\n", __func__);
  621. sshbuf_dump(key->sk_key_handle, stderr);
  622. #endif
  623. if ((r = skp->sk_sign(alg, data, datalen, key->sk_application,
  624. sshbuf_ptr(key->sk_key_handle), sshbuf_len(key->sk_key_handle),
  625. key->sk_flags, pin, opts, &resp)) != 0) {
  626. debug("%s: sk_sign failed with code %d", __func__, r);
  627. r = skerr_to_ssherr(r);
  628. goto out;
  629. }
  630. /* Assemble signature */
  631. if ((sig = sshbuf_new()) == NULL) {
  632. r = SSH_ERR_ALLOC_FAIL;
  633. goto out;
  634. }
  635. if ((r = sshbuf_put_cstring(sig, sshkey_ssh_name_plain(key))) != 0) {
  636. debug("%s: buffer error (outer): %s", __func__, ssh_err(r));
  637. goto out;
  638. }
  639. switch (type) {
  640. #ifdef WITH_OPENSSL
  641. case KEY_ECDSA_SK:
  642. if ((r = sshsk_ecdsa_sig(resp, sig)) != 0)
  643. goto out;
  644. break;
  645. #endif /* WITH_OPENSSL */
  646. case KEY_ED25519_SK:
  647. if ((r = sshsk_ed25519_sig(resp, sig)) != 0)
  648. goto out;
  649. break;
  650. }
  651. #ifdef DEBUG_SK
  652. fprintf(stderr, "%s: sig_flags = 0x%02x, sig_counter = %u\n",
  653. __func__, resp->flags, resp->counter);
  654. fprintf(stderr, "%s: data to sign:\n", __func__);
  655. sshbuf_dump_data(data, datalen, stderr);
  656. fprintf(stderr, "%s: sigbuf:\n", __func__);
  657. sshbuf_dump(sig, stderr);
  658. #endif
  659. if (sigp != NULL) {
  660. if ((*sigp = malloc(sshbuf_len(sig))) == NULL) {
  661. r = SSH_ERR_ALLOC_FAIL;
  662. goto out;
  663. }
  664. memcpy(*sigp, sshbuf_ptr(sig), sshbuf_len(sig));
  665. }
  666. if (lenp != NULL)
  667. *lenp = sshbuf_len(sig);
  668. /* success */
  669. r = 0;
  670. out:
  671. sshsk_free_options(opts);
  672. sshsk_free(skp);
  673. sshsk_free_sign_response(resp);
  674. sshbuf_free(sig);
  675. sshbuf_free(inner_sig);
  676. return r;
  677. }
  678. static void
  679. sshsk_free_sk_resident_keys(struct sk_resident_key **rks, size_t nrks)
  680. {
  681. size_t i;
  682. if (nrks == 0 || rks == NULL)
  683. return;
  684. for (i = 0; i < nrks; i++) {
  685. free(rks[i]->application);
  686. freezero(rks[i]->key.key_handle, rks[i]->key.key_handle_len);
  687. freezero(rks[i]->key.public_key, rks[i]->key.public_key_len);
  688. freezero(rks[i]->key.signature, rks[i]->key.signature_len);
  689. freezero(rks[i]->key.attestation_cert,
  690. rks[i]->key.attestation_cert_len);
  691. freezero(rks[i], sizeof(**rks));
  692. }
  693. free(rks);
  694. }
  695. int
  696. sshsk_load_resident(const char *provider_path, const char *device,
  697. const char *pin, struct sshkey ***keysp, size_t *nkeysp)
  698. {
  699. struct sshsk_provider *skp = NULL;
  700. int r = SSH_ERR_INTERNAL_ERROR;
  701. struct sk_resident_key **rks = NULL;
  702. size_t i, nrks = 0, nkeys = 0;
  703. struct sshkey *key = NULL, **keys = NULL, **tmp;
  704. uint8_t flags;
  705. struct sk_option **opts = NULL;
  706. debug("%s: provider \"%s\"%s", __func__, provider_path,
  707. (pin != NULL && *pin != '\0') ? ", have-pin": "");
  708. if (keysp == NULL || nkeysp == NULL)
  709. return SSH_ERR_INVALID_ARGUMENT;
  710. *keysp = NULL;
  711. *nkeysp = 0;
  712. if ((r = make_options(device, NULL, &opts)) != 0)
  713. goto out;
  714. if ((skp = sshsk_open(provider_path)) == NULL) {
  715. r = SSH_ERR_INVALID_FORMAT; /* XXX sshsk_open return code? */
  716. goto out;
  717. }
  718. if ((r = skp->sk_load_resident_keys(pin, opts, &rks, &nrks)) != 0) {
  719. error("Provider \"%s\" returned failure %d", provider_path, r);
  720. r = skerr_to_ssherr(r);
  721. goto out;
  722. }
  723. for (i = 0; i < nrks; i++) {
  724. debug3("%s: rk %zu: slot = %zu, alg = %d, application = \"%s\"",
  725. __func__, i, rks[i]->slot, rks[i]->alg,
  726. rks[i]->application);
  727. /* XXX need better filter here */
  728. if (strncmp(rks[i]->application, "ssh:", 4) != 0)
  729. continue;
  730. switch (rks[i]->alg) {
  731. case SSH_SK_ECDSA:
  732. case SSH_SK_ED25519:
  733. break;
  734. default:
  735. continue;
  736. }
  737. flags = SSH_SK_USER_PRESENCE_REQD|SSH_SK_RESIDENT_KEY;
  738. if ((rks[i]->flags & SSH_SK_USER_VERIFICATION_REQD))
  739. flags |= SSH_SK_USER_VERIFICATION_REQD;
  740. if ((r = sshsk_key_from_response(rks[i]->alg,
  741. rks[i]->application, flags, &rks[i]->key, &key)) != 0)
  742. goto out;
  743. if ((tmp = recallocarray(keys, nkeys, nkeys + 1,
  744. sizeof(*tmp))) == NULL) {
  745. error("%s: recallocarray failed", __func__);
  746. r = SSH_ERR_ALLOC_FAIL;
  747. goto out;
  748. }
  749. keys = tmp;
  750. keys[nkeys++] = key;
  751. key = NULL;
  752. /* XXX synthesise comment */
  753. }
  754. /* success */
  755. *keysp = keys;
  756. *nkeysp = nkeys;
  757. keys = NULL;
  758. nkeys = 0;
  759. r = 0;
  760. out:
  761. sshsk_free_options(opts);
  762. sshsk_free(skp);
  763. sshsk_free_sk_resident_keys(rks, nrks);
  764. sshkey_free(key);
  765. if (nkeys != 0) {
  766. for (i = 0; i < nkeys; i++)
  767. sshkey_free(keys[i]);
  768. free(keys);
  769. }
  770. return r;
  771. }
  772. #endif /* ENABLE_SK */