Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mRemoteNG/PuTTYNG.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'ssh/transient-hostkey-cache.c')
-rw-r--r--ssh/transient-hostkey-cache.c126
1 files changed, 126 insertions, 0 deletions
diff --git a/ssh/transient-hostkey-cache.c b/ssh/transient-hostkey-cache.c
new file mode 100644
index 00000000..2e77fdf9
--- /dev/null
+++ b/ssh/transient-hostkey-cache.c
@@ -0,0 +1,126 @@
+/*
+ * Data structure managing host keys in sessions based on GSSAPI KEX.
+ *
+ * In a session we started with a GSSAPI key exchange, the concept of
+ * 'host key' has completely different lifetime and security semantics
+ * from the usual ones. Per RFC 4462 section 2.1, we assume that any
+ * host key delivered to us in the course of a GSSAPI key exchange is
+ * _solely_ there to use as a transient fallback within the same
+ * session, if at the time of a subsequent rekey the GSS credentials
+ * are temporarily invalid and so a non-GSS KEX method has to be used.
+ *
+ * In particular, in a GSS-based SSH deployment, host keys may not
+ * even _be_ persistent identities for the server; it would be
+ * legitimate for a server to generate a fresh one routinely if it
+ * wanted to, like SSH-1 server keys.
+ *
+ * So, in this mode, we never touch the persistent host key cache at
+ * all, either to check keys against it _or_ to store keys in it.
+ * Instead, we maintain an in-memory cache of host keys that have been
+ * mentioned in GSS key exchanges within this particular session, and
+ * we permit precisely those host keys in non-GSS rekeys.
+ */
+
+#include <assert.h>
+
+#include "putty.h"
+#include "ssh.h"
+
+struct ssh_transient_hostkey_cache {
+ tree234 *cache;
+};
+
+struct ssh_transient_hostkey_cache_entry {
+ const ssh_keyalg *alg;
+ strbuf *pub_blob;
+};
+
+static int ssh_transient_hostkey_cache_cmp(void *av, void *bv)
+{
+ const struct ssh_transient_hostkey_cache_entry
+ *a = (const struct ssh_transient_hostkey_cache_entry *)av,
+ *b = (const struct ssh_transient_hostkey_cache_entry *)bv;
+ return strcmp(a->alg->ssh_id, b->alg->ssh_id);
+}
+
+static int ssh_transient_hostkey_cache_find(void *av, void *bv)
+{
+ const ssh_keyalg *aalg = (const ssh_keyalg *)av;
+ const struct ssh_transient_hostkey_cache_entry
+ *b = (const struct ssh_transient_hostkey_cache_entry *)bv;
+ return strcmp(aalg->ssh_id, b->alg->ssh_id);
+}
+
+ssh_transient_hostkey_cache *ssh_transient_hostkey_cache_new(void)
+{
+ ssh_transient_hostkey_cache *thc = snew(ssh_transient_hostkey_cache);
+ thc->cache = newtree234(ssh_transient_hostkey_cache_cmp);
+ return thc;
+}
+
+void ssh_transient_hostkey_cache_free(ssh_transient_hostkey_cache *thc)
+{
+ struct ssh_transient_hostkey_cache_entry *ent;
+ while ((ent = delpos234(thc->cache, 0)) != NULL) {
+ strbuf_free(ent->pub_blob);
+ sfree(ent);
+ }
+ freetree234(thc->cache);
+ sfree(thc);
+}
+
+void ssh_transient_hostkey_cache_add(
+ ssh_transient_hostkey_cache *thc, ssh_key *key)
+{
+ struct ssh_transient_hostkey_cache_entry *ent, *retd;
+
+ if ((ent = find234(thc->cache, (void *)ssh_key_alg(key),
+ ssh_transient_hostkey_cache_find)) != NULL) {
+ del234(thc->cache, ent);
+ strbuf_free(ent->pub_blob);
+ sfree(ent);
+ }
+
+ ent = snew(struct ssh_transient_hostkey_cache_entry);
+ ent->alg = ssh_key_alg(key);
+ ent->pub_blob = strbuf_new();
+ ssh_key_public_blob(key, BinarySink_UPCAST(ent->pub_blob));
+ retd = add234(thc->cache, ent);
+ assert(retd == ent);
+}
+
+bool ssh_transient_hostkey_cache_verify(
+ ssh_transient_hostkey_cache *thc, ssh_key *key)
+{
+ struct ssh_transient_hostkey_cache_entry *ent;
+ bool toret = false;
+
+ if ((ent = find234(thc->cache, (void *)ssh_key_alg(key),
+ ssh_transient_hostkey_cache_find)) != NULL) {
+ strbuf *this_blob = strbuf_new();
+ ssh_key_public_blob(key, BinarySink_UPCAST(this_blob));
+
+ if (this_blob->len == ent->pub_blob->len &&
+ !memcmp(this_blob->s, ent->pub_blob->s,
+ this_blob->len))
+ toret = true;
+
+ strbuf_free(this_blob);
+ }
+
+ return toret;
+}
+
+bool ssh_transient_hostkey_cache_has(
+ ssh_transient_hostkey_cache *thc, const ssh_keyalg *alg)
+{
+ struct ssh_transient_hostkey_cache_entry *ent =
+ find234(thc->cache, (void *)alg,
+ ssh_transient_hostkey_cache_find);
+ return ent != NULL;
+}
+
+bool ssh_transient_hostkey_cache_non_empty(ssh_transient_hostkey_cache *thc)
+{
+ return count234(thc->cache) > 0;
+}