1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-07-02 03:52:49 -05:00

Introduce OpenSSH-compatible SHA256 key fingerprinting.

There's a new enumeration of fingerprint types, and you tell
ssh2_fingerprint() or ssh2_fingerprint_blob() which of them to use.

So far, this is only implemented behind the scenes, and exposed for
testcrypt to test. All the call sites of ssh2_fingerprint pass a fixed
default fptype, which is still set to the old MD5. That will change
shortly.
This commit is contained in:
Simon Tatham
2021-03-13 09:52:56 +00:00
parent 0bc78dea68
commit 1da353e649
11 changed files with 133 additions and 45 deletions

View File

@ -1732,51 +1732,73 @@ void ssh2_write_pubkey(FILE *fp, const char *comment,
/* ----------------------------------------------------------------------
* Utility functions to compute SSH-2 fingerprints in a uniform way.
*/
char *ssh2_fingerprint_blob(ptrlen blob)
static void ssh2_fingerprint_blob_md5(ptrlen blob, strbuf *sb)
{
unsigned char digest[16];
char fingerprint_str[16*3];
ptrlen algname;
const ssh_keyalg *alg;
int i;
BinarySource src[1];
/*
* The fingerprint hash itself is always just the MD5 of the blob.
*/
hash_simple(&ssh_md5, blob, digest);
for (i = 0; i < 16; i++)
sprintf(fingerprint_str + i*3, "%02x%s", digest[i], i==15 ? "" : ":");
for (unsigned i = 0; i < 16; i++)
strbuf_catf(sb, "%02x%s", digest[i], i==15 ? "" : ":");
}
static void ssh2_fingerprint_blob_sha256(ptrlen blob, strbuf *sb)
{
unsigned char digest[32];
hash_simple(&ssh_sha256, blob, digest);
put_datapl(sb, PTRLEN_LITERAL("SHA256:"));
for (unsigned i = 0; i < 32; i += 3) {
char buf[5];
unsigned len = 32-i;
if (len > 3)
len = 3;
base64_encode_atom(digest + i, len, buf);
put_data(sb, buf, 4);
}
strbuf_chomp(sb, '=');
}
char *ssh2_fingerprint_blob(ptrlen blob, FingerprintType fptype)
{
strbuf *sb = strbuf_new();
/*
* Identify the key algorithm, if possible.
*
* If we can't do that, then we have a seriously confused key
* blob, in which case we return only the hash.
*/
BinarySource src[1];
BinarySource_BARE_INIT_PL(src, blob);
algname = get_string(src);
ptrlen algname = get_string(src);
if (!get_err(src)) {
alg = find_pubkey_alg_len(algname);
const ssh_keyalg *alg = find_pubkey_alg_len(algname);
if (alg) {
int bits = ssh_key_public_bits(alg, blob);
return dupprintf("%.*s %d %s", PTRLEN_PRINTF(algname),
bits, fingerprint_str);
strbuf_catf(sb, "%.*s %d ", PTRLEN_PRINTF(algname), bits);
} else {
return dupprintf("%.*s %s", PTRLEN_PRINTF(algname),
fingerprint_str);
strbuf_catf(sb, "%.*s ", PTRLEN_PRINTF(algname));
}
} else {
/*
* No algorithm available (which means a seriously confused
* key blob, but there we go). Return only the hash.
*/
return dupstr(fingerprint_str);
}
switch (fptype) {
case SSH_FPTYPE_MD5:
ssh2_fingerprint_blob_md5(blob, sb);
break;
case SSH_FPTYPE_SHA256:
ssh2_fingerprint_blob_sha256(blob, sb);
break;
}
return strbuf_to_str(sb);
}
char *ssh2_fingerprint(ssh_key *data)
char *ssh2_fingerprint(ssh_key *data, FingerprintType fptype)
{
strbuf *blob = strbuf_new();
ssh_key_public_blob(data, BinarySink_UPCAST(blob));
char *ret = ssh2_fingerprint_blob(ptrlen_from_strbuf(blob));
char *ret = ssh2_fingerprint_blob(ptrlen_from_strbuf(blob), fptype);
strbuf_free(blob);
return ret;
}