2 * Data structure managing host keys in sessions based on GSSAPI KEX.
4 * In a session we started with a GSSAPI key exchange, the concept of
5 * 'host key' has completely different lifetime and security semantics
6 * from the usual ones. Per RFC 4462 section 2.1, we assume that any
7 * host key delivered to us in the course of a GSSAPI key exchange is
8 * _solely_ there to use as a transient fallback within the same
9 * session, if at the time of a subsequent rekey the GSS credentials
10 * are temporarily invalid and so a non-GSS KEX method has to be used.
12 * In particular, in a GSS-based SSH deployment, host keys may not
13 * even _be_ persistent identities for the server; it would be
14 * legitimate for a server to generate a fresh one routinely if it
15 * wanted to, like SSH-1 server keys.
17 * So, in this mode, we never touch the persistent host key cache at
18 * all, either to check keys against it _or_ to store keys in it.
19 * Instead, we maintain an in-memory cache of host keys that have been
20 * mentioned in GSS key exchanges within this particular session, and
21 * we permit precisely those host keys in non-GSS rekeys.
29 struct ssh_transient_hostkey_cache
{
33 struct ssh_transient_hostkey_cache_entry
{
34 const ssh_keyalg
*alg
;
38 static int ssh_transient_hostkey_cache_cmp(void *av
, void *bv
)
40 const struct ssh_transient_hostkey_cache_entry
41 *a
= (const struct ssh_transient_hostkey_cache_entry
*)av
,
42 *b
= (const struct ssh_transient_hostkey_cache_entry
*)bv
;
43 return strcmp(a
->alg
->ssh_id
, b
->alg
->ssh_id
);
46 static int ssh_transient_hostkey_cache_find(void *av
, void *bv
)
48 const ssh_keyalg
*aalg
= (const ssh_keyalg
*)av
;
49 const struct ssh_transient_hostkey_cache_entry
50 *b
= (const struct ssh_transient_hostkey_cache_entry
*)bv
;
51 return strcmp(aalg
->ssh_id
, b
->alg
->ssh_id
);
54 ssh_transient_hostkey_cache
*ssh_transient_hostkey_cache_new(void)
56 ssh_transient_hostkey_cache
*thc
= snew(ssh_transient_hostkey_cache
);
57 thc
->cache
= newtree234(ssh_transient_hostkey_cache_cmp
);
61 void ssh_transient_hostkey_cache_free(ssh_transient_hostkey_cache
*thc
)
63 struct ssh_transient_hostkey_cache_entry
*ent
;
64 while ((ent
= delpos234(thc
->cache
, 0)) != NULL
) {
65 strbuf_free(ent
->pub_blob
);
68 freetree234(thc
->cache
);
72 void ssh_transient_hostkey_cache_add(
73 ssh_transient_hostkey_cache
*thc
, ssh_key
*key
)
75 struct ssh_transient_hostkey_cache_entry
*ent
, *retd
;
77 if ((ent
= find234(thc
->cache
, (void *)ssh_key_alg(key
),
78 ssh_transient_hostkey_cache_find
)) != NULL
) {
79 del234(thc
->cache
, ent
);
80 strbuf_free(ent
->pub_blob
);
84 ent
= snew(struct ssh_transient_hostkey_cache_entry
);
85 ent
->alg
= ssh_key_alg(key
);
86 ent
->pub_blob
= strbuf_new();
87 ssh_key_public_blob(key
, BinarySink_UPCAST(ent
->pub_blob
));
88 retd
= add234(thc
->cache
, ent
);
92 bool ssh_transient_hostkey_cache_verify(
93 ssh_transient_hostkey_cache
*thc
, ssh_key
*key
)
95 struct ssh_transient_hostkey_cache_entry
*ent
;
98 if ((ent
= find234(thc
->cache
, (void *)ssh_key_alg(key
),
99 ssh_transient_hostkey_cache_find
)) != NULL
) {
100 strbuf
*this_blob
= strbuf_new();
101 ssh_key_public_blob(key
, BinarySink_UPCAST(this_blob
));
103 if (this_blob
->len
== ent
->pub_blob
->len
&&
104 !memcmp(this_blob
->s
, ent
->pub_blob
->s
,
108 strbuf_free(this_blob
);
114 bool ssh_transient_hostkey_cache_has(
115 ssh_transient_hostkey_cache
*thc
, const ssh_keyalg
*alg
)
117 struct ssh_transient_hostkey_cache_entry
*ent
=
118 find234(thc
->cache
, (void *)alg
,
119 ssh_transient_hostkey_cache_find
);
123 bool ssh_transient_hostkey_cache_non_empty(ssh_transient_hostkey_cache
*thc
)
125 return count234(thc
->cache
) > 0;