diff options
Diffstat (limited to 'ssh/transient-hostkey-cache.c')
-rw-r--r-- | ssh/transient-hostkey-cache.c | 126 |
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; +} |