openssh-certs.c 43 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163
  1. /*
  2. * Public key type for OpenSSH certificates.
  3. */
  4. #include "ssh.h"
  5. #include "putty.h"
  6. enum {
  7. SSH_CERT_TYPE_USER = 1,
  8. SSH_CERT_TYPE_HOST = 2,
  9. };
  10. typedef struct opensshcert_key {
  11. strbuf *nonce;
  12. uint64_t serial;
  13. uint32_t type;
  14. strbuf *key_id;
  15. strbuf *valid_principals;
  16. uint64_t valid_after, valid_before;
  17. strbuf *critical_options;
  18. strbuf *extensions;
  19. strbuf *reserved;
  20. strbuf *signature_key;
  21. strbuf *signature;
  22. ssh_key *basekey;
  23. ssh_key sshk;
  24. } opensshcert_key;
  25. typedef struct blob_fmt {
  26. const unsigned *fmt;
  27. size_t len;
  28. } blob_fmt;
  29. typedef struct opensshcert_extra {
  30. /*
  31. * OpenSSH certificate formats aren't completely consistent about
  32. * the relationship between the public+private blob uploaded to
  33. * the agent for the certified key type, and the one for the base
  34. * key type. Here we specify the mapping.
  35. *
  36. * Each of these foo_fmt strings indicates the layout of a
  37. * particular version of the key, in the form of an array of
  38. * integers together with a length, with each integer describing
  39. * one of the components of the key. The integers are defined by
  40. * enums, so that they're tightly packed; the general idea is that
  41. * if you're converting from one form to another, then you use the
  42. * format list for the source format to read out a succession of
  43. * SSH strings from the source data and put them in an array
  44. * indexed by the integer ids, and then use the list for the
  45. * destination format to write the strings out to the destination
  46. * in the right (maybe different) order.
  47. *
  48. * pub_fmt describes the format of the public-key blob for the
  49. * base key type, not counting the initial string giving the key
  50. * type identifier itself. As far as I know, this always matches
  51. * the format of the public-key data appearing in the middle of
  52. * the certificate.
  53. *
  54. * base_ossh_fmt describes the format of the full OpenSSH blob
  55. * appearing in the ssh-agent protocol for the base key,
  56. * containing the public and private key data.
  57. *
  58. * cert_ossh_fmt describes the format of the OpenSSH blob for the
  59. * certificate key format, beginning just after the certificate
  60. * string itself.
  61. */
  62. blob_fmt pub_fmt, base_ossh_fmt, cert_ossh_fmt;
  63. /*
  64. * The RSA-SHA2 algorithm names have their SSH id set to names
  65. * like "rsa-sha2-512-cert-...", which is what will be received in
  66. * the KEXINIT algorithm list if a host key in one of those
  67. * algorithms is presented. But the _key_ type id that will appear
  68. * in the public key blob is "ssh-rsa-cert-...". So we need a
  69. * separate field to indicate the key type id we expect to see in
  70. * certified public keys, and also the one we want to put back
  71. * into the artificial public blob we make to pass to the
  72. * constructor for the underlying key.
  73. *
  74. * (In rsa.c this is managed much more simply, because everything
  75. * sharing the same vtable wants the same key type id.)
  76. */
  77. const char *cert_key_ssh_id, *base_key_ssh_id;
  78. } opensshcert_extra;
  79. /*
  80. * The actual integer arrays defining the per-key blob formats.
  81. */
  82. /* DSA is the most orthodox: only the obviously necessary public key
  83. * info appears at all, it's in the same order everywhere, and none of
  84. * it is repeated unnecessarily */
  85. enum { DSA_p, DSA_q, DSA_g, DSA_y, DSA_x };
  86. static const unsigned dsa_pub_fmt[] = { DSA_p, DSA_q, DSA_g, DSA_y };
  87. static const unsigned dsa_base_ossh_fmt[] = {
  88. DSA_p, DSA_q, DSA_g, DSA_y, DSA_x };
  89. static const unsigned dsa_cert_ossh_fmt[] = { DSA_x };
  90. /* ECDSA is almost as nice, except that it pointlessly mentions the
  91. * curve name in the public data, which shouldn't be necessary given
  92. * that the SSH key id has already implied it. But at least that's
  93. * consistent everywhere. */
  94. enum { ECDSA_curve, ECDSA_point, ECDSA_exp };
  95. static const unsigned ecdsa_pub_fmt[] = { ECDSA_curve, ECDSA_point };
  96. static const unsigned ecdsa_base_ossh_fmt[] = {
  97. ECDSA_curve, ECDSA_point, ECDSA_exp };
  98. static const unsigned ecdsa_cert_ossh_fmt[] = { ECDSA_exp };
  99. /* Ed25519 has the oddity that the private data following the
  100. * certificate in the OpenSSH blob is preceded by an extra copy of the
  101. * public data, for no obviously necessary reason since that doesn't
  102. * happen in any of the rest of these formats */
  103. enum { EDDSA_point, EDDSA_exp };
  104. static const unsigned eddsa_pub_fmt[] = { EDDSA_point };
  105. static const unsigned eddsa_base_ossh_fmt[] = { EDDSA_point, EDDSA_exp };
  106. static const unsigned eddsa_cert_ossh_fmt[] = { EDDSA_point, EDDSA_exp };
  107. /* And RSA has the quirk that the modulus and exponent are reversed in
  108. * the base key type's OpenSSH blob! */
  109. enum { RSA_e, RSA_n, RSA_d, RSA_p, RSA_q, RSA_iqmp };
  110. static const unsigned rsa_pub_fmt[] = { RSA_e, RSA_n };
  111. static const unsigned rsa_base_ossh_fmt[] = {
  112. RSA_n, RSA_e, RSA_d, RSA_p, RSA_q, RSA_iqmp };
  113. static const unsigned rsa_cert_ossh_fmt[] = { RSA_d, RSA_p, RSA_q, RSA_iqmp };
  114. /*
  115. * Routines to transform one kind of blob into another based on those
  116. * foo_fmt integer arrays.
  117. */
  118. typedef struct BlobTransformer {
  119. ptrlen *parts;
  120. size_t nparts;
  121. } BlobTransformer;
  122. #define BLOBTRANS_DECLARE(bt) BlobTransformer bt[1] = { { NULL, 0 } }
  123. static inline void blobtrans_clear(BlobTransformer *bt)
  124. {
  125. sfree(bt->parts);
  126. bt->parts = NULL;
  127. bt->nparts = 0;
  128. }
  129. static inline bool blobtrans_read(BlobTransformer *bt, BinarySource *src,
  130. blob_fmt blob)
  131. {
  132. size_t nparts = bt->nparts;
  133. for (size_t i = 0; i < blob.len; i++)
  134. if (nparts < blob.fmt[i]+1)
  135. nparts = blob.fmt[i]+1;
  136. if (nparts > bt->nparts) {
  137. bt->parts = sresize(bt->parts, nparts, ptrlen);
  138. while (bt->nparts < nparts)
  139. bt->parts[bt->nparts++] = make_ptrlen(NULL, 0);
  140. }
  141. for (size_t i = 0; i < blob.len; i++) {
  142. size_t j = blob.fmt[i];
  143. ptrlen part = get_string(src);
  144. if (bt->parts[j].ptr) {
  145. /*
  146. * If the same string appears in both the public blob and
  147. * the private data, check they match. (This happens in
  148. * Ed25519: an extra copy of the public point string
  149. * appears in the certified OpenSSH data after the
  150. * certificate and before the private key.)
  151. */
  152. if (!ptrlen_eq_ptrlen(bt->parts[j], part))
  153. return false;
  154. }
  155. bt->parts[j] = part;
  156. }
  157. return true;
  158. }
  159. static inline void blobtrans_write(BlobTransformer *bt, BinarySink *bs,
  160. blob_fmt blob)
  161. {
  162. for (size_t i = 0; i < blob.len; i++) {
  163. assert(i < bt->nparts);
  164. ptrlen part = bt->parts[blob.fmt[i]];
  165. assert(part.ptr);
  166. put_stringpl(bs, part);
  167. }
  168. }
  169. /*
  170. * Forward declarations.
  171. */
  172. static ssh_key *opensshcert_new_pub(const ssh_keyalg *self, ptrlen pub);
  173. static ssh_key *opensshcert_new_priv(
  174. const ssh_keyalg *self, ptrlen pub, ptrlen priv);
  175. static ssh_key *opensshcert_new_priv_openssh(
  176. const ssh_keyalg *self, BinarySource *src);
  177. static void opensshcert_freekey(ssh_key *key);
  178. static char *opensshcert_invalid(ssh_key *key, unsigned flags);
  179. static void opensshcert_sign(ssh_key *key, ptrlen data, unsigned flags,
  180. BinarySink *bs);
  181. static bool opensshcert_verify(ssh_key *key, ptrlen sig, ptrlen data);
  182. static void opensshcert_public_blob(ssh_key *key, BinarySink *bs);
  183. static void opensshcert_private_blob(ssh_key *key, BinarySink *bs);
  184. static void opensshcert_openssh_blob(ssh_key *key, BinarySink *bs);
  185. static void opensshcert_ca_public_blob(ssh_key *key, BinarySink *bs);
  186. static void opensshcert_cert_id_string(ssh_key *key, BinarySink *bs);
  187. static SeatDialogText *opensshcert_cert_info(ssh_key *key);
  188. static bool opensshcert_has_private(ssh_key *key);
  189. static char *opensshcert_cache_str(ssh_key *key);
  190. static key_components *opensshcert_components(ssh_key *key);
  191. static ssh_key *opensshcert_base_key(ssh_key *key);
  192. static bool opensshcert_check_cert(
  193. ssh_key *key, bool host, ptrlen principal, uint64_t time,
  194. const ca_options *opts, BinarySink *error);
  195. static int opensshcert_pubkey_bits(const ssh_keyalg *self, ptrlen blob);
  196. static unsigned opensshcert_supported_flags(const ssh_keyalg *self);
  197. static const char *opensshcert_alternate_ssh_id(const ssh_keyalg *self,
  198. unsigned flags);
  199. static char *opensshcert_alg_desc(const ssh_keyalg *self);
  200. static bool opensshcert_variable_size(const ssh_keyalg *self);
  201. static const ssh_keyalg *opensshcert_related_alg(const ssh_keyalg *self,
  202. const ssh_keyalg *base);
  203. /*
  204. * Top-level vtables for the certified key formats, defined via a list
  205. * macro so I can also make an array of them all.
  206. */
  207. #define KEYALG_LIST(X) \
  208. X(ssh_dsa, "ssh-dss", "ssh-dss", dsa) \
  209. X(ssh_rsa, "ssh-rsa", "ssh-rsa", rsa) \
  210. X(ssh_rsa_sha256, "rsa-sha2-256", "ssh-rsa", rsa) \
  211. X(ssh_rsa_sha512, "rsa-sha2-512", "ssh-rsa", rsa) \
  212. X(ssh_ecdsa_ed25519, "ssh-ed25519", "ssh-ed25519", eddsa) \
  213. X(ssh_ecdsa_nistp256, "ecdsa-sha2-nistp256","ecdsa-sha2-nistp256", ecdsa) \
  214. X(ssh_ecdsa_nistp384, "ecdsa-sha2-nistp384","ecdsa-sha2-nistp384", ecdsa) \
  215. X(ssh_ecdsa_nistp521, "ecdsa-sha2-nistp521","ecdsa-sha2-nistp521", ecdsa) \
  216. /* end of list */
  217. #define KEYALG_DEF(name, ssh_alg_id_prefix, ssh_key_id_prefix, fmt_prefix) \
  218. static const struct opensshcert_extra opensshcert_##name##_extra = { \
  219. .pub_fmt = { .fmt = fmt_prefix ## _pub_fmt, \
  220. .len = lenof(fmt_prefix ## _pub_fmt) }, \
  221. .base_ossh_fmt = { .fmt = fmt_prefix ## _base_ossh_fmt, \
  222. .len = lenof(fmt_prefix ## _base_ossh_fmt) }, \
  223. .cert_ossh_fmt = { .fmt = fmt_prefix ## _cert_ossh_fmt, \
  224. .len = lenof(fmt_prefix ## _cert_ossh_fmt) }, \
  225. .cert_key_ssh_id = ssh_key_id_prefix "-cert-v01@openssh.com", \
  226. .base_key_ssh_id = ssh_key_id_prefix, \
  227. }; \
  228. \
  229. const ssh_keyalg opensshcert_##name = { \
  230. .new_pub = opensshcert_new_pub, \
  231. .new_priv = opensshcert_new_priv, \
  232. .new_priv_openssh = opensshcert_new_priv_openssh, \
  233. .freekey = opensshcert_freekey, \
  234. .invalid = opensshcert_invalid, \
  235. .sign = opensshcert_sign, \
  236. .verify = opensshcert_verify, \
  237. .public_blob = opensshcert_public_blob, \
  238. .private_blob = opensshcert_private_blob, \
  239. .openssh_blob = opensshcert_openssh_blob, \
  240. .has_private = opensshcert_has_private, \
  241. .cache_str = opensshcert_cache_str, \
  242. .components = opensshcert_components, \
  243. .base_key = opensshcert_base_key, \
  244. .ca_public_blob = opensshcert_ca_public_blob, \
  245. .check_cert = opensshcert_check_cert, \
  246. .cert_id_string = opensshcert_cert_id_string, \
  247. .cert_info = opensshcert_cert_info, \
  248. .pubkey_bits = opensshcert_pubkey_bits, \
  249. .supported_flags = opensshcert_supported_flags, \
  250. .alternate_ssh_id = opensshcert_alternate_ssh_id, \
  251. .alg_desc = opensshcert_alg_desc, \
  252. .variable_size = opensshcert_variable_size, \
  253. .related_alg = opensshcert_related_alg, \
  254. .ssh_id = ssh_alg_id_prefix "-cert-v01@openssh.com", \
  255. .cache_id = "opensshcert-" ssh_key_id_prefix, \
  256. .extra = &opensshcert_##name##_extra, \
  257. .is_certificate = true, \
  258. .base_alg = &name, \
  259. };
  260. KEYALG_LIST(KEYALG_DEF)
  261. #undef KEYALG_DEF
  262. #define KEYALG_LIST_ENTRY(name, algid, keyid, fmt) &opensshcert_##name,
  263. static const ssh_keyalg *const opensshcert_all_keyalgs[] = {
  264. KEYALG_LIST(KEYALG_LIST_ENTRY)
  265. };
  266. #undef KEYALG_LIST_ENTRY
  267. static strbuf *get_base_public_blob(BinarySource *src,
  268. const opensshcert_extra *extra)
  269. {
  270. strbuf *basepub = strbuf_new();
  271. put_stringz(basepub, extra->base_key_ssh_id);
  272. /* Make the base public key blob out of the public key
  273. * material in the certificate. This invocation of the
  274. * blobtrans system doesn't do any format translation, but it
  275. * does ensure that the right amount of data is copied so that
  276. * src ends up in the right position to read the remaining
  277. * certificate fields. */
  278. BLOBTRANS_DECLARE(bt);
  279. blobtrans_read(bt, src, extra->pub_fmt);
  280. blobtrans_write(bt, BinarySink_UPCAST(basepub), extra->pub_fmt);
  281. blobtrans_clear(bt);
  282. return basepub;
  283. }
  284. static opensshcert_key *opensshcert_new_shared(
  285. const ssh_keyalg *self, ptrlen blob, strbuf **basepub_out)
  286. {
  287. const opensshcert_extra *extra = self->extra;
  288. BinarySource src[1];
  289. BinarySource_BARE_INIT_PL(src, blob);
  290. /* Check the initial key-type string */
  291. if (!ptrlen_eq_string(get_string(src), extra->cert_key_ssh_id))
  292. return NULL;
  293. opensshcert_key *ck = snew(opensshcert_key);
  294. memset(ck, 0, sizeof(*ck));
  295. ck->sshk.vt = self;
  296. ck->nonce = strbuf_dup(get_string(src));
  297. strbuf *basepub = get_base_public_blob(src, extra);
  298. ck->serial = get_uint64(src);
  299. ck->type = get_uint32(src);
  300. ck->key_id = strbuf_dup(get_string(src));
  301. ck->valid_principals = strbuf_dup(get_string(src));
  302. ck->valid_after = get_uint64(src);
  303. ck->valid_before = get_uint64(src);
  304. ck->critical_options = strbuf_dup(get_string(src));
  305. ck->extensions = strbuf_dup(get_string(src));
  306. ck->reserved = strbuf_dup(get_string(src));
  307. ck->signature_key = strbuf_dup(get_string(src));
  308. ck->signature = strbuf_dup(get_string(src));
  309. if (get_err(src)) {
  310. ssh_key_free(&ck->sshk);
  311. strbuf_free(basepub);
  312. return NULL;
  313. }
  314. *basepub_out = basepub;
  315. return ck;
  316. }
  317. static ssh_key *opensshcert_new_pub(const ssh_keyalg *self, ptrlen pub)
  318. {
  319. strbuf *basepub;
  320. opensshcert_key *ck = opensshcert_new_shared(self, pub, &basepub);
  321. if (!ck)
  322. return NULL;
  323. ck->basekey = ssh_key_new_pub(self->base_alg, ptrlen_from_strbuf(basepub));
  324. strbuf_free(basepub);
  325. if (!ck->basekey) {
  326. ssh_key_free(&ck->sshk);
  327. return NULL;
  328. }
  329. return &ck->sshk;
  330. }
  331. static ssh_key *opensshcert_new_priv(
  332. const ssh_keyalg *self, ptrlen pub, ptrlen priv)
  333. {
  334. strbuf *basepub;
  335. opensshcert_key *ck = opensshcert_new_shared(self, pub, &basepub);
  336. if (!ck)
  337. return NULL;
  338. ck->basekey = ssh_key_new_priv(self->base_alg,
  339. ptrlen_from_strbuf(basepub), priv);
  340. strbuf_free(basepub);
  341. if (!ck->basekey) {
  342. ssh_key_free(&ck->sshk);
  343. return NULL;
  344. }
  345. return &ck->sshk;
  346. }
  347. static ssh_key *opensshcert_new_priv_openssh(
  348. const ssh_keyalg *self, BinarySource *src)
  349. {
  350. const opensshcert_extra *extra = self->extra;
  351. ptrlen cert = get_string(src);
  352. strbuf *basepub;
  353. opensshcert_key *ck = opensshcert_new_shared(self, cert, &basepub);
  354. if (!ck)
  355. return NULL;
  356. strbuf *baseossh = strbuf_new();
  357. /* Make the base OpenSSH key blob out of the public key blob
  358. * returned from opensshcert_new_shared, and the trailing
  359. * private data following the certificate */
  360. BLOBTRANS_DECLARE(bt);
  361. BinarySource pubsrc[1];
  362. BinarySource_BARE_INIT_PL(pubsrc, ptrlen_from_strbuf(basepub));
  363. get_string(pubsrc); /* skip key type id */
  364. /* blobtrans_read might fail in this case, because we're reading
  365. * from two sources and they might fail to match */
  366. bool success = blobtrans_read(bt, pubsrc, extra->pub_fmt) &&
  367. blobtrans_read(bt, src, extra->cert_ossh_fmt);
  368. blobtrans_write(bt, BinarySink_UPCAST(baseossh), extra->base_ossh_fmt);
  369. blobtrans_clear(bt);
  370. if (!success) {
  371. ssh_key_free(&ck->sshk);
  372. strbuf_free(basepub);
  373. strbuf_free(baseossh);
  374. return NULL;
  375. }
  376. strbuf_free(basepub);
  377. BinarySource osshsrc[1];
  378. BinarySource_BARE_INIT_PL(osshsrc, ptrlen_from_strbuf(baseossh));
  379. ck->basekey = ssh_key_new_priv_openssh(self->base_alg, osshsrc);
  380. strbuf_free(baseossh);
  381. if (!ck->basekey) {
  382. ssh_key_free(&ck->sshk);
  383. return NULL;
  384. }
  385. return &ck->sshk;
  386. }
  387. static void opensshcert_freekey(ssh_key *key)
  388. {
  389. opensshcert_key *ck = container_of(key, opensshcert_key, sshk);
  390. /* If this function is called from one of the above constructors
  391. * because it failed part way through, we might not have managed
  392. * to construct ck->basekey, so it might be NULL. */
  393. if (ck->basekey)
  394. ssh_key_free(ck->basekey);
  395. strbuf_free(ck->nonce);
  396. strbuf_free(ck->key_id);
  397. strbuf_free(ck->valid_principals);
  398. strbuf_free(ck->critical_options);
  399. strbuf_free(ck->extensions);
  400. strbuf_free(ck->reserved);
  401. strbuf_free(ck->signature_key);
  402. strbuf_free(ck->signature);
  403. sfree(ck);
  404. }
  405. static ssh_key *opensshcert_base_key(ssh_key *key)
  406. {
  407. opensshcert_key *ck = container_of(key, opensshcert_key, sshk);
  408. return ck->basekey;
  409. }
  410. /*
  411. * Make a public key object from the CA public blob, potentially
  412. * taking into account that the signature might override the algorithm
  413. * name
  414. */
  415. static ssh_key *opensshcert_ca_pub_key(
  416. opensshcert_key *ck, ptrlen sig, ptrlen *algname)
  417. {
  418. ptrlen ca_keyblob = ptrlen_from_strbuf(ck->signature_key);
  419. ptrlen alg_source = sig.ptr ? sig : ca_keyblob;
  420. if (algname)
  421. *algname = pubkey_blob_to_alg_name(alg_source);
  422. const ssh_keyalg *ca_alg = pubkey_blob_to_alg(alg_source);
  423. if (!ca_alg)
  424. return NULL; /* don't even recognise the certifying key type */
  425. return ssh_key_new_pub(ca_alg, ca_keyblob);
  426. }
  427. static void opensshcert_signature_preimage(opensshcert_key *ck, BinarySink *bs)
  428. {
  429. const opensshcert_extra *extra = ck->sshk.vt->extra;
  430. put_stringz(bs, extra->cert_key_ssh_id);
  431. put_stringpl(bs, ptrlen_from_strbuf(ck->nonce));
  432. strbuf *basepub = strbuf_new();
  433. ssh_key_public_blob(ck->basekey, BinarySink_UPCAST(basepub));
  434. BinarySource src[1];
  435. BinarySource_BARE_INIT_PL(src, ptrlen_from_strbuf(basepub));
  436. get_string(src); /* skip initial key type string */
  437. put_data(bs, get_ptr(src), get_avail(src));
  438. strbuf_free(basepub);
  439. put_uint64(bs, ck->serial);
  440. put_uint32(bs, ck->type);
  441. put_stringpl(bs, ptrlen_from_strbuf(ck->key_id));
  442. put_stringpl(bs, ptrlen_from_strbuf(ck->valid_principals));
  443. put_uint64(bs, ck->valid_after);
  444. put_uint64(bs, ck->valid_before);
  445. put_stringpl(bs, ptrlen_from_strbuf(ck->critical_options));
  446. put_stringpl(bs, ptrlen_from_strbuf(ck->extensions));
  447. put_stringpl(bs, ptrlen_from_strbuf(ck->reserved));
  448. put_stringpl(bs, ptrlen_from_strbuf(ck->signature_key));
  449. }
  450. static void opensshcert_public_blob(ssh_key *key, BinarySink *bs)
  451. {
  452. opensshcert_key *ck = container_of(key, opensshcert_key, sshk);
  453. opensshcert_signature_preimage(ck, bs);
  454. put_stringpl(bs, ptrlen_from_strbuf(ck->signature));
  455. }
  456. static void opensshcert_private_blob(ssh_key *key, BinarySink *bs)
  457. {
  458. opensshcert_key *ck = container_of(key, opensshcert_key, sshk);
  459. ssh_key_private_blob(ck->basekey, bs);
  460. }
  461. static void opensshcert_openssh_blob(ssh_key *key, BinarySink *bs)
  462. {
  463. opensshcert_key *ck = container_of(key, opensshcert_key, sshk);
  464. const opensshcert_extra *extra = key->vt->extra;
  465. strbuf *cert = strbuf_new();
  466. ssh_key_public_blob(key, BinarySink_UPCAST(cert));
  467. put_stringsb(bs, cert);
  468. strbuf *baseossh = strbuf_new_nm();
  469. ssh_key_openssh_blob(ck->basekey, BinarySink_UPCAST(baseossh));
  470. BinarySource basesrc[1];
  471. BinarySource_BARE_INIT_PL(basesrc, ptrlen_from_strbuf(baseossh));
  472. BLOBTRANS_DECLARE(bt);
  473. blobtrans_read(bt, basesrc, extra->base_ossh_fmt);
  474. blobtrans_write(bt, bs, extra->cert_ossh_fmt);
  475. blobtrans_clear(bt);
  476. strbuf_free(baseossh);
  477. }
  478. static void opensshcert_ca_public_blob(ssh_key *key, BinarySink *bs)
  479. {
  480. opensshcert_key *ck = container_of(key, opensshcert_key, sshk);
  481. put_datapl(bs, ptrlen_from_strbuf(ck->signature_key));
  482. }
  483. static void opensshcert_cert_id_string(ssh_key *key, BinarySink *bs)
  484. {
  485. opensshcert_key *ck = container_of(key, opensshcert_key, sshk);
  486. put_datapl(bs, ptrlen_from_strbuf(ck->key_id));
  487. }
  488. static bool opensshcert_has_private(ssh_key *key)
  489. {
  490. opensshcert_key *ck = container_of(key, opensshcert_key, sshk);
  491. return ssh_key_has_private(ck->basekey);
  492. }
  493. static char *opensshcert_cache_str(ssh_key *key)
  494. {
  495. opensshcert_key *ck = container_of(key, opensshcert_key, sshk);
  496. return ssh_key_cache_str(ck->basekey);
  497. }
  498. static void opensshcert_time_to_iso8601(BinarySink *bs, uint64_t time)
  499. {
  500. time_t t = time;
  501. char buf[256];
  502. put_data(bs, buf, strftime(buf, sizeof(buf),
  503. "%Y-%m-%d %H:%M:%S UTC", gmtime(&t)));
  504. }
  505. static void opensshcert_string_list_key_components(
  506. key_components *kc, strbuf *input, const char *title, const char *title2)
  507. {
  508. BinarySource src[1];
  509. BinarySource_BARE_INIT_PL(src, ptrlen_from_strbuf(input));
  510. const char *titles[2] = { title, title2 };
  511. size_t ntitles = (title2 ? 2 : 1);
  512. unsigned index = 0;
  513. while (get_avail(src)) {
  514. for (size_t ti = 0; ti < ntitles; ti++) {
  515. ptrlen value = get_string(src);
  516. if (get_err(src))
  517. break;
  518. char *name = dupprintf("%s_%u", titles[ti], index);
  519. key_components_add_text_pl(kc, name, value);
  520. sfree(name);
  521. }
  522. index++;
  523. }
  524. }
  525. static key_components *opensshcert_components(ssh_key *key)
  526. {
  527. opensshcert_key *ck = container_of(key, opensshcert_key, sshk);
  528. key_components *kc = ssh_key_components(ck->basekey);
  529. key_components_add_binary(kc, "cert_nonce", ptrlen_from_strbuf(ck->nonce));
  530. key_components_add_uint(kc, "cert_serial", ck->serial);
  531. switch (ck->type) {
  532. case SSH_CERT_TYPE_HOST:
  533. key_components_add_text(kc, "cert_type", "host");
  534. break;
  535. case SSH_CERT_TYPE_USER:
  536. key_components_add_text(kc, "cert_type", "user");
  537. break;
  538. default:
  539. key_components_add_uint(kc, "cert_type", ck->type);
  540. break;
  541. }
  542. key_components_add_text(kc, "cert_key_id", ck->key_id->s);
  543. opensshcert_string_list_key_components(kc, ck->valid_principals,
  544. "cert_valid_principal", NULL);
  545. key_components_add_uint(kc, "cert_valid_after", ck->valid_after);
  546. key_components_add_uint(kc, "cert_valid_before", ck->valid_before);
  547. /* Translate the validity period into human-legible dates, but
  548. * only if they're not the min/max integer. Rationale: if you see
  549. * "584554051223-11-09 07:00:15 UTC" as the expiry time you'll be
  550. * as likely to think it's a weird buffer overflow as half a
  551. * trillion years in the future! */
  552. if (ck->valid_after != 0) {
  553. strbuf *date = strbuf_new();
  554. opensshcert_time_to_iso8601(BinarySink_UPCAST(date), ck->valid_after);
  555. key_components_add_text_pl(kc, "cert_valid_after_date",
  556. ptrlen_from_strbuf(date));
  557. strbuf_free(date);
  558. }
  559. if (ck->valid_before != 0xFFFFFFFFFFFFFFFF) {
  560. strbuf *date = strbuf_new();
  561. opensshcert_time_to_iso8601(BinarySink_UPCAST(date), ck->valid_before);
  562. key_components_add_text_pl(kc, "cert_valid_before_date",
  563. ptrlen_from_strbuf(date));
  564. strbuf_free(date);
  565. }
  566. opensshcert_string_list_key_components(kc, ck->critical_options,
  567. "cert_critical_option",
  568. "cert_critical_option_data");
  569. opensshcert_string_list_key_components(kc, ck->extensions,
  570. "cert_extension",
  571. "cert_extension_data");
  572. key_components_add_binary(kc, "cert_ca_key", ptrlen_from_strbuf(
  573. ck->signature_key));
  574. ptrlen ca_algname;
  575. ssh_key *ca_key = opensshcert_ca_pub_key(ck, make_ptrlen(NULL, 0),
  576. &ca_algname);
  577. key_components_add_text_pl(kc, "cert_ca_key_algorithm_id", ca_algname);
  578. if (ca_key) {
  579. key_components *kc_ca_key = ssh_key_components(ca_key);
  580. for (size_t i = 0; i < kc_ca_key->ncomponents; i++) {
  581. key_component *comp = &kc_ca_key->components[i];
  582. char *subname = dupcat("cert_ca_key_", comp->name);
  583. key_components_add_copy(kc, subname, comp);
  584. sfree(subname);
  585. }
  586. key_components_free(kc_ca_key);
  587. ssh_key_free(ca_key);
  588. }
  589. key_components_add_binary(kc, "cert_ca_sig", ptrlen_from_strbuf(
  590. ck->signature));
  591. return kc;
  592. }
  593. static SeatDialogText *opensshcert_cert_info(ssh_key *key)
  594. {
  595. opensshcert_key *ck = container_of(key, opensshcert_key, sshk);
  596. SeatDialogText *text = seat_dialog_text_new();
  597. strbuf *tmp = strbuf_new();
  598. seat_dialog_text_append(text, SDT_MORE_INFO_KEY,
  599. "Certificate type");
  600. switch (ck->type) {
  601. case SSH_CERT_TYPE_HOST:
  602. seat_dialog_text_append(text, SDT_MORE_INFO_VALUE_SHORT,
  603. "host key");
  604. seat_dialog_text_append(text, SDT_MORE_INFO_KEY,
  605. "Valid host names");
  606. break;
  607. case SSH_CERT_TYPE_USER:
  608. seat_dialog_text_append(text, SDT_MORE_INFO_VALUE_SHORT,
  609. "user authentication key");
  610. seat_dialog_text_append(text, SDT_MORE_INFO_KEY,
  611. "Valid user names");
  612. break;
  613. default:
  614. seat_dialog_text_append(text, SDT_MORE_INFO_VALUE_SHORT,
  615. "unknown type %" PRIu32, ck->type);
  616. seat_dialog_text_append(text, SDT_MORE_INFO_KEY,
  617. "Valid principals");
  618. break;
  619. }
  620. {
  621. BinarySource src[1];
  622. BinarySource_BARE_INIT_PL(src, ptrlen_from_strbuf(
  623. ck->valid_principals));
  624. const char *sep = "";
  625. strbuf_clear(tmp);
  626. while (get_avail(src)) {
  627. ptrlen principal = get_string(src);
  628. if (get_err(src))
  629. break;
  630. put_dataz(tmp, sep);
  631. sep = ",";
  632. put_datapl(tmp, principal);
  633. }
  634. seat_dialog_text_append(text, SDT_MORE_INFO_VALUE_SHORT,
  635. "%s", tmp->s);
  636. }
  637. seat_dialog_text_append(text, SDT_MORE_INFO_KEY,
  638. "Validity period");
  639. strbuf_clear(tmp);
  640. if (ck->valid_after == 0) {
  641. if (ck->valid_before == 0xFFFFFFFFFFFFFFFF) {
  642. put_dataz(tmp, "forever");
  643. } else {
  644. put_dataz(tmp, "until ");
  645. opensshcert_time_to_iso8601(BinarySink_UPCAST(tmp),
  646. ck->valid_before);
  647. }
  648. } else {
  649. if (ck->valid_before == 0xFFFFFFFFFFFFFFFF) {
  650. put_dataz(tmp, "after ");
  651. opensshcert_time_to_iso8601(BinarySink_UPCAST(tmp),
  652. ck->valid_after);
  653. } else {
  654. opensshcert_time_to_iso8601(BinarySink_UPCAST(tmp),
  655. ck->valid_after);
  656. put_dataz(tmp, " - ");
  657. opensshcert_time_to_iso8601(BinarySink_UPCAST(tmp),
  658. ck->valid_before);
  659. }
  660. }
  661. seat_dialog_text_append(text, SDT_MORE_INFO_VALUE_SHORT, "%s", tmp->s);
  662. /*
  663. * List critical options we know about. (This is everything listed
  664. * in PROTOCOL.certkeys that isn't specific to U2F/FIDO key types
  665. * that PuTTY doesn't currently support.)
  666. */
  667. {
  668. BinarySource src[1];
  669. BinarySource_BARE_INIT_PL(src, ptrlen_from_strbuf(
  670. ck->critical_options));
  671. strbuf_clear(tmp);
  672. while (get_avail(src)) {
  673. ptrlen key = get_string(src);
  674. ptrlen value = get_string(src);
  675. if (get_err(src))
  676. break;
  677. if (ck->type == SSH_CERT_TYPE_USER &&
  678. ptrlen_eq_string(key, "source-address")) {
  679. BinarySource src2[1];
  680. BinarySource_BARE_INIT_PL(src2, value);
  681. ptrlen addresslist = get_string(src2);
  682. seat_dialog_text_append(text, SDT_MORE_INFO_KEY,
  683. "Permitted client IP addresses");
  684. seat_dialog_text_append(text, SDT_MORE_INFO_VALUE_SHORT,
  685. "%.*s", PTRLEN_PRINTF(addresslist));
  686. } else if (ck->type == SSH_CERT_TYPE_USER &&
  687. ptrlen_eq_string(key, "force-command")) {
  688. BinarySource src2[1];
  689. BinarySource_BARE_INIT_PL(src2, value);
  690. ptrlen command = get_string(src2);
  691. seat_dialog_text_append(text, SDT_MORE_INFO_KEY,
  692. "Forced remote command");
  693. seat_dialog_text_append(text, SDT_MORE_INFO_VALUE_SHORT,
  694. "%.*s", PTRLEN_PRINTF(command));
  695. }
  696. }
  697. }
  698. /*
  699. * List certificate extensions. Again, we go through everything in
  700. * PROTOCOL.certkeys that isn't specific to U2F/FIDO key types.
  701. * But we also flip the sense round for user-readability: I think
  702. * it's more likely that the typical key will permit all these
  703. * things, so we emit no output in that case, and only mention the
  704. * things that _aren't_ enabled.
  705. */
  706. bool x11_ok = false, agent_ok = false, portfwd_ok = false;
  707. bool pty_ok = false, user_rc_ok = false;
  708. {
  709. BinarySource src[1];
  710. BinarySource_BARE_INIT_PL(src, ptrlen_from_strbuf(
  711. ck->extensions));
  712. while (get_avail(src)) {
  713. ptrlen key = get_string(src);
  714. /* ptrlen value = */ get_string(src); // nothing needs this yet
  715. if (get_err(src))
  716. break;
  717. if (ptrlen_eq_string(key, "permit-X11-forwarding")) {
  718. x11_ok = true;
  719. } else if (ptrlen_eq_string(key, "permit-agent-forwarding")) {
  720. agent_ok = true;
  721. } else if (ptrlen_eq_string(key, "permit-port-forwarding")) {
  722. portfwd_ok = true;
  723. } else if (ptrlen_eq_string(key, "permit-pty")) {
  724. pty_ok = true;
  725. } else if (ptrlen_eq_string(key, "permit-user-rc")) {
  726. user_rc_ok = true;
  727. }
  728. }
  729. }
  730. if (ck->type == SSH_CERT_TYPE_USER) {
  731. if (!x11_ok) {
  732. seat_dialog_text_append(text, SDT_MORE_INFO_KEY,
  733. "X11 forwarding permitted");
  734. seat_dialog_text_append(text, SDT_MORE_INFO_VALUE_SHORT, "no");
  735. }
  736. if (!agent_ok) {
  737. seat_dialog_text_append(text, SDT_MORE_INFO_KEY,
  738. "Agent forwarding permitted");
  739. seat_dialog_text_append(text, SDT_MORE_INFO_VALUE_SHORT, "no");
  740. }
  741. if (!portfwd_ok) {
  742. seat_dialog_text_append(text, SDT_MORE_INFO_KEY,
  743. "Port forwarding permitted");
  744. seat_dialog_text_append(text, SDT_MORE_INFO_VALUE_SHORT, "no");
  745. }
  746. if (!pty_ok) {
  747. seat_dialog_text_append(text, SDT_MORE_INFO_KEY,
  748. "PTY allocation permitted");
  749. seat_dialog_text_append(text, SDT_MORE_INFO_VALUE_SHORT, "no");
  750. }
  751. if (!user_rc_ok) {
  752. seat_dialog_text_append(text, SDT_MORE_INFO_KEY,
  753. "Running user ~/.ssh.rc permitted");
  754. seat_dialog_text_append(text, SDT_MORE_INFO_VALUE_SHORT, "no");
  755. }
  756. }
  757. seat_dialog_text_append(text, SDT_MORE_INFO_KEY,
  758. "Certificate ID string");
  759. seat_dialog_text_append(text, SDT_MORE_INFO_VALUE_SHORT,
  760. "%s", ck->key_id->s);
  761. seat_dialog_text_append(text, SDT_MORE_INFO_KEY,
  762. "Certificate serial number");
  763. seat_dialog_text_append(text, SDT_MORE_INFO_VALUE_SHORT,
  764. "%" PRIu64, ck->serial);
  765. char *fp = ssh2_fingerprint_blob(ptrlen_from_strbuf(ck->signature_key),
  766. SSH_FPTYPE_DEFAULT);
  767. seat_dialog_text_append(text, SDT_MORE_INFO_KEY,
  768. "Fingerprint of signing CA key");
  769. seat_dialog_text_append(text, SDT_MORE_INFO_VALUE_SHORT, "%s", fp);
  770. sfree(fp);
  771. fp = ssh2_fingerprint(key, ssh_fptype_to_cert(SSH_FPTYPE_DEFAULT));
  772. seat_dialog_text_append(text, SDT_MORE_INFO_KEY,
  773. "Fingerprint including certificate");
  774. seat_dialog_text_append(text, SDT_MORE_INFO_VALUE_SHORT, "%s", fp);
  775. sfree(fp);
  776. strbuf_free(tmp);
  777. return text;
  778. }
  779. static int opensshcert_pubkey_bits(const ssh_keyalg *self, ptrlen blob)
  780. {
  781. BinarySource src[1];
  782. BinarySource_BARE_INIT_PL(src, blob);
  783. get_string(src); /* key type */
  784. get_string(src); /* nonce */
  785. strbuf *basepub = get_base_public_blob(src, self->extra);
  786. int bits = ssh_key_public_bits(
  787. self->base_alg, ptrlen_from_strbuf(basepub));
  788. strbuf_free(basepub);
  789. return bits;
  790. }
  791. static unsigned opensshcert_supported_flags(const ssh_keyalg *self)
  792. {
  793. return ssh_keyalg_supported_flags(self->base_alg);
  794. }
  795. static const char *opensshcert_alternate_ssh_id(const ssh_keyalg *self,
  796. unsigned flags)
  797. {
  798. const char *base_id = ssh_keyalg_alternate_ssh_id(self->base_alg, flags);
  799. for (size_t i = 0; i < lenof(opensshcert_all_keyalgs); i++) {
  800. const ssh_keyalg *alg_i = opensshcert_all_keyalgs[i];
  801. if (!strcmp(base_id, alg_i->base_alg->ssh_id))
  802. return alg_i->ssh_id;
  803. }
  804. return self->ssh_id;
  805. }
  806. static char *opensshcert_alg_desc(const ssh_keyalg *self)
  807. {
  808. char *base_desc = ssh_keyalg_desc(self->base_alg);
  809. char *our_desc = dupcat(base_desc, " cert");
  810. sfree(base_desc);
  811. return our_desc;
  812. }
  813. static bool opensshcert_variable_size(const ssh_keyalg *self)
  814. {
  815. return ssh_keyalg_variable_size(self->base_alg);
  816. }
  817. static const ssh_keyalg *opensshcert_related_alg(const ssh_keyalg *self,
  818. const ssh_keyalg *base)
  819. {
  820. for (size_t i = 0; i < lenof(opensshcert_all_keyalgs); i++) {
  821. const ssh_keyalg *alg_i = opensshcert_all_keyalgs[i];
  822. if (base == alg_i->base_alg)
  823. return alg_i;
  824. }
  825. return self;
  826. }
  827. static char *opensshcert_invalid(ssh_key *key, unsigned flags)
  828. {
  829. opensshcert_key *ck = container_of(key, opensshcert_key, sshk);
  830. return ssh_key_invalid(ck->basekey, flags);
  831. }
  832. static bool opensshcert_check_cert(
  833. ssh_key *key, bool host, ptrlen principal, uint64_t time,
  834. const ca_options *opts, BinarySink *error)
  835. {
  836. opensshcert_key *ck = container_of(key, opensshcert_key, sshk);
  837. bool result = false;
  838. ssh_key *ca_key = NULL;
  839. strbuf *preimage = strbuf_new();
  840. BinarySource src[1];
  841. ptrlen signature = ptrlen_from_strbuf(ck->signature);
  842. /*
  843. * The OpenSSH certificate spec is one-layer only: it explicitly
  844. * forbids using a certified key in turn as the CA.
  845. *
  846. * If it did not, then we'd also have to recursively verify
  847. * everything up the CA chain until we reached the ultimate root,
  848. * and then make sure _that_ was something we trusted. (Not to
  849. * mention that there'd probably be an additional SSH_CERT_TYPE_CA
  850. * or some such, and certificate options saying what kinds of
  851. * certificate a CA was trusted to sign for, and ...)
  852. */
  853. ca_key = opensshcert_ca_pub_key(ck, make_ptrlen(NULL, 0), NULL);
  854. if (!ca_key) {
  855. put_fmt(error, "Certificate's signing key is invalid");
  856. goto out;
  857. }
  858. if (ssh_key_alg(ca_key)->is_certificate) {
  859. put_fmt(error, "Certificate is signed with a certified key "
  860. "(forbidden by OpenSSH certificate specification)");
  861. goto out;
  862. }
  863. /*
  864. * Now re-instantiate the key in a way that matches the signature
  865. * (i.e. so that if the key is an RSA one we get the right subtype
  866. * of RSA).
  867. */
  868. ssh_key_free(ca_key);
  869. ca_key = opensshcert_ca_pub_key(ck, signature, NULL);
  870. if (!ca_key) {
  871. put_fmt(error, "Certificate's signing key does not match "
  872. "signature type");
  873. goto out;
  874. }
  875. /* Check which signature algorithm is actually in use, because
  876. * that might be a reason to reject the certificate (e.g. ssh-rsa
  877. * when we wanted rsa-sha2-*). */
  878. const ssh_keyalg *sig_alg = ssh_key_alg(ca_key);
  879. if ((sig_alg == &ssh_rsa && !opts->permit_rsa_sha1) ||
  880. (sig_alg == &ssh_rsa_sha256 && !opts->permit_rsa_sha256) ||
  881. (sig_alg == &ssh_rsa_sha512 && !opts->permit_rsa_sha512)) {
  882. put_fmt(error, "Certificate signature uses '%s' signature type "
  883. "(forbidden by user configuration)", sig_alg->ssh_id);
  884. goto out;
  885. }
  886. opensshcert_signature_preimage(ck, BinarySink_UPCAST(preimage));
  887. if (!ssh_key_verify(ca_key, signature, ptrlen_from_strbuf(preimage))) {
  888. put_fmt(error, "Certificate's signature is invalid");
  889. goto out;
  890. }
  891. uint32_t expected_type = host ? SSH_CERT_TYPE_HOST : SSH_CERT_TYPE_USER;
  892. if (ck->type != expected_type) {
  893. put_fmt(error, "Certificate type is ");
  894. switch (ck->type) {
  895. case SSH_CERT_TYPE_HOST:
  896. put_fmt(error, "host");
  897. break;
  898. case SSH_CERT_TYPE_USER:
  899. put_fmt(error, "user");
  900. break;
  901. default:
  902. put_fmt(error, "unknown value %" PRIu32, ck->type);
  903. break;
  904. }
  905. put_fmt(error, "; expected %s", host ? "host" : "user");
  906. goto out;
  907. }
  908. /*
  909. * Check the time bounds on the certificate.
  910. */
  911. if (time < ck->valid_after) {
  912. put_fmt(error, "Certificate is not valid until ");
  913. opensshcert_time_to_iso8601(BinarySink_UPCAST(error),
  914. ck->valid_after);
  915. goto out;
  916. }
  917. if (time >= ck->valid_before) {
  918. put_fmt(error, "Certificate expired at ");
  919. opensshcert_time_to_iso8601(BinarySink_UPCAST(error),
  920. ck->valid_before);
  921. goto out;
  922. }
  923. /*
  924. * Check that this certificate is for the right thing.
  925. *
  926. * If valid_principals is a zero-length string then this is
  927. * specified to be a carte-blanche certificate valid for any
  928. * principal (at least, provided you trust the CA that issued it).
  929. */
  930. if (ck->valid_principals->len != 0) {
  931. BinarySource_BARE_INIT_PL(
  932. src, ptrlen_from_strbuf(ck->valid_principals));
  933. while (get_avail(src)) {
  934. ptrlen valid_principal = get_string(src);
  935. if (get_err(src)) {
  936. put_fmt(error, "Certificate's valid principals list is "
  937. "incorrectly formatted");
  938. goto out;
  939. }
  940. if (ptrlen_eq_ptrlen(valid_principal, principal))
  941. goto principal_ok;
  942. }
  943. /*
  944. * No valid principal matched. Now go through the list a
  945. * second time writing the cert contents into the error
  946. * message, so that the user can see at a glance what went
  947. * wrong.
  948. *
  949. * (If you've typed the wrong spelling of the host name, you
  950. * really need to see "This cert is for 'foo.example.com' and
  951. * I was trying to match it against 'foo'", rather than just
  952. * "Computer says no".)
  953. */
  954. put_fmt(error, "Certificate's %s list [",
  955. host ? "hostname" : "username");
  956. BinarySource_BARE_INIT_PL(
  957. src, ptrlen_from_strbuf(ck->valid_principals));
  958. const char *sep = "";
  959. while (get_avail(src)) {
  960. ptrlen valid_principal = get_string(src);
  961. put_fmt(error, "%s\"", sep);
  962. put_c_string_literal(error, valid_principal);
  963. put_fmt(error, "\"");
  964. sep = ", ";
  965. }
  966. put_fmt(error, "] does not contain expected %s \"",
  967. host ? "hostname" : "username");
  968. put_c_string_literal(error, principal);
  969. put_fmt(error, "\"");
  970. goto out;
  971. principal_ok:;
  972. }
  973. /*
  974. * Check for critical options.
  975. */
  976. {
  977. BinarySource_BARE_INIT_PL(
  978. src, ptrlen_from_strbuf(ck->critical_options));
  979. while (get_avail(src)) {
  980. ptrlen option = get_string(src);
  981. ptrlen data = get_string(src);
  982. if (get_err(src)) {
  983. put_fmt(error, "Certificate's critical options list is "
  984. "incorrectly formatted");
  985. goto out;
  986. }
  987. /*
  988. * If we ever do support any options, this will be where
  989. * we insert code to recognise and validate them.
  990. *
  991. * At present, we implement no critical options at all.
  992. * (For host certs, as of 2022-04-20, OpenSSH hasn't
  993. * defined any. For user certs, the only SSH server using
  994. * this is Uppity, which doesn't support key restrictions
  995. * in general.)
  996. */
  997. (void)data; /* no options supported => no use made of the data */
  998. /*
  999. * Report an unrecognised literal.
  1000. */
  1001. put_fmt(error, "Certificate specifies an unsupported critical "
  1002. "option \"");
  1003. put_c_string_literal(error, option);
  1004. put_fmt(error, "\"");
  1005. goto out;
  1006. }
  1007. }
  1008. /* If we get here without failing any check, accept the certificate! */
  1009. result = true;
  1010. out:
  1011. if (ca_key)
  1012. ssh_key_free(ca_key);
  1013. strbuf_free(preimage);
  1014. return result;
  1015. }
  1016. static bool opensshcert_verify(ssh_key *key, ptrlen sig, ptrlen data)
  1017. {
  1018. /* This method is pure *signature* verification; checking the
  1019. * certificate is done elsewhere. */
  1020. opensshcert_key *ck = container_of(key, opensshcert_key, sshk);
  1021. return ssh_key_verify(ck->basekey, sig, data);
  1022. }
  1023. static void opensshcert_sign(ssh_key *key, ptrlen data, unsigned flags,
  1024. BinarySink *bs)
  1025. {
  1026. opensshcert_key *ck = container_of(key, opensshcert_key, sshk);
  1027. ssh_key_sign(ck->basekey, data, flags, bs);
  1028. }