зеркало из https://github.com/github/putty.git
125 строки
4.0 KiB
C
125 строки
4.0 KiB
C
/*
|
|
* 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);
|
|
}
|
|
|
|
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) {
|
|
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;
|
|
}
|