1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-09 17:38:00 +00:00

Centralise SSH-2 key fingerprinting into sshpubk.c.

There were ad-hoc functions for fingerprinting a bare key blob in both
cmdgen.c and pageant.c, not quite doing the same thing. Also, every
SSH-2 public key algorithm in the code base included a dedicated
fingerprint() method, which is completely pointless since SSH-2 key
fingerprints are computed in an algorithm-independent way (just hash
the standard-format public key blob), so each of those methods was
just duplicating the work of the public_blob() method with a less
general output mechanism.

Now sshpubk.c centrally provides an ssh2_fingerprint_blob() function
that does all the real work, plus an ssh2_fingerprint() function that
wraps it and deals with calling public_blob() to get something to
fingerprint. And the fingerprint() method has been completely removed
from ssh_signkey and all its implementations, and good riddance.
This commit is contained in:
Simon Tatham 2015-05-12 14:35:44 +01:00
parent eef0235a0f
commit 8682246d33
10 changed files with 71 additions and 213 deletions

View File

@ -192,27 +192,6 @@ static int move(char *from, char *to)
return TRUE;
}
static char *blobfp(char *alg, int bits, unsigned char *blob, int bloblen)
{
char buffer[128];
unsigned char digest[16];
struct MD5Context md5c;
int i;
MD5Init(&md5c);
MD5Update(&md5c, blob, bloblen);
MD5Final(digest, &md5c);
sprintf(buffer, "%s ", alg);
if (bits > 0)
sprintf(buffer + strlen(buffer), "%d ", bits);
for (i = 0; i < 16; i++)
sprintf(buffer + strlen(buffer), "%s%02x", i ? ":" : "",
digest[i]);
return dupstr(buffer);
}
int main(int argc, char **argv)
{
char *infile = NULL;
@ -980,10 +959,11 @@ int main(int argc, char **argv)
rsa_fingerprint(fingerprint, 128, ssh1key);
} else {
if (ssh2key) {
fingerprint = ssh2key->alg->fingerprint(ssh2key->data);
fingerprint = ssh2_fingerprint(ssh2key->alg,
ssh2key->data);
} else {
assert(ssh2blob);
fingerprint = blobfp(ssh2alg, bits, ssh2blob, ssh2bloblen);
fingerprint = ssh2_fingerprint_blob(ssh2blob, ssh2bloblen);
}
}

View File

@ -259,25 +259,6 @@ void *pageant_make_keylist2(int *length)
return ret;
}
char *fingerprint_ssh2_blob(const void *blob, int bloblen)
{
unsigned char digest[16];
char fingerprint_str[16*3];
unsigned stringlen;
int i;
MD5Simple(blob, bloblen, digest);
for (i = 0; i < 16; i++)
sprintf(fingerprint_str + i*3, "%02x%s", digest[i], i==15 ? "" : ":");
stringlen = GET_32BIT((const unsigned char *)blob);
if (stringlen < bloblen-4)
return dupprintf("%.*s %s", (int)stringlen, (const char *)blob + 4,
fingerprint_str);
else
return dupstr(fingerprint_str);
}
static void plog(void *logctx, pageant_logfn_t logfn, const char *fmt, ...)
#ifdef __GNUC__
__attribute__ ((format (printf, 3, 4)))
@ -381,7 +362,8 @@ void *pageant_handle_msg(const void *msg, int msglen, int *outlen,
int i;
struct ssh2_userkey *skey;
for (i = 0; NULL != (skey = pageant_nth_ssh2_key(i)); i++) {
char *fingerprint = skey->alg->fingerprint(skey->data);
char *fingerprint = ssh2_fingerprint(skey->alg,
skey->data);
plog(logctx, logfn, "returned key: %s %s",
fingerprint, skey->comment);
sfree(fingerprint);
@ -528,7 +510,7 @@ void *pageant_handle_msg(const void *msg, int msglen, int *outlen,
}
data = p;
if (logfn) {
char *fingerprint = fingerprint_ssh2_blob(b.blob, b.len);
char *fingerprint = ssh2_fingerprint_blob(b.blob, b.len);
plog(logctx, logfn, "requested key: %s", fingerprint);
sfree(fingerprint);
}
@ -728,7 +710,7 @@ void *pageant_handle_msg(const void *msg, int msglen, int *outlen,
key->comment = comment;
if (logfn) {
char *fingerprint = key->alg->fingerprint(key->data);
char *fingerprint = ssh2_fingerprint(key->alg, key->data);
plog(logctx, logfn, "submitted key: %s %s",
fingerprint, key->comment);
sfree(fingerprint);
@ -822,7 +804,7 @@ void *pageant_handle_msg(const void *msg, int msglen, int *outlen,
p += b.len;
if (logfn) {
char *fingerprint = fingerprint_ssh2_blob(b.blob, b.len);
char *fingerprint = ssh2_fingerprint_blob(b.blob, b.len);
plog(logctx, logfn, "unwanted key: %s", fingerprint);
sfree(fingerprint);
}
@ -1688,7 +1670,7 @@ int pageant_enum_keys(pageant_key_enum_fn_t callback, void *callback_ctx,
sfree(keylist);
return PAGEANT_ACTION_FAILURE;
}
fingerprint = fingerprint_ssh2_blob(p, n);
fingerprint = ssh2_fingerprint_blob(p, n);
cbkey.blob = p;
cbkey.bloblen = n;
p += n, keylistlen -= n;

2
ssh.c
View File

@ -7042,7 +7042,7 @@ static void do_ssh2_transport(Ssh ssh, void *vin, int inlen,
* Authenticate remote host: verify host key. (We've already
* checked the signature of the exchange hash.)
*/
s->fingerprint = ssh->hostkey->fingerprint(s->hkey);
s->fingerprint = ssh2_fingerprint(ssh->hostkey, s->hkey);
logevent("Host key fingerprint is:");
logevent(s->fingerprint);
/* First check against manually configured host keys. */

3
ssh.h
View File

@ -375,7 +375,6 @@ struct ssh_signkey {
* openssh_private_npieces gives that information. */
int openssh_private_npieces;
int (*pubkey_bits) (const void *blob, int len);
char *(*fingerprint) (void *key);
int (*verifysig) (void *key, const char *sig, int siglen,
const char *data, int datalen);
unsigned char *(*sign) (void *key, const char *data, int datalen,
@ -722,6 +721,8 @@ char *ssh2_pubkey_openssh_str(struct ssh2_userkey *key);
void ssh2_write_pubkey(FILE *fp, const char *comment,
const void *v_pub_blob, int pub_len,
int keytype);
char *ssh2_fingerprint_blob(const void *blob, int bloblen);
char *ssh2_fingerprint(const struct ssh_signkey *alg, void *data);
int key_type(const Filename *filename);
char *key_type_to_str(int type);

View File

@ -190,43 +190,6 @@ static char *dss_fmtkey(void *key)
return p;
}
static char *dss_fingerprint(void *key)
{
struct dss_key *dss = (struct dss_key *) key;
struct MD5Context md5c;
unsigned char digest[16], lenbuf[4];
char buffer[16 * 3 + 40];
char *ret;
int numlen, i;
MD5Init(&md5c);
MD5Update(&md5c, (unsigned char *)"\0\0\0\7ssh-dss", 11);
#define ADD_BIGNUM(bignum) \
numlen = (bignum_bitcount(bignum)+8)/8; \
PUT_32BIT(lenbuf, numlen); MD5Update(&md5c, lenbuf, 4); \
for (i = numlen; i-- ;) { \
unsigned char c = bignum_byte(bignum, i); \
MD5Update(&md5c, &c, 1); \
}
ADD_BIGNUM(dss->p);
ADD_BIGNUM(dss->q);
ADD_BIGNUM(dss->g);
ADD_BIGNUM(dss->y);
#undef ADD_BIGNUM
MD5Final(digest, &md5c);
sprintf(buffer, "ssh-dss %d ", bignum_bitcount(dss->p));
for (i = 0; i < 16; i++)
sprintf(buffer + strlen(buffer), "%s%02x", i ? ":" : "",
digest[i]);
ret = snewn(strlen(buffer) + 1, char);
if (ret)
strcpy(ret, buffer);
return ret;
}
static int dss_verifysig(void *key, const char *sig, int siglen,
const char *data, int datalen)
{
@ -705,7 +668,6 @@ const struct ssh_signkey ssh_dss = {
dss_openssh_fmtkey,
5 /* p,q,g,y,x */,
dss_pubkey_bits,
dss_fingerprint,
dss_verifysig,
dss_sign,
"ssh-dss",

View File

@ -3082,87 +3082,6 @@ static int ecdsa_pubkey_bits(const void *blob, int len)
return ret;
}
static char *ecdsa_fingerprint(void *key)
{
struct ec_key *ec = (struct ec_key *) key;
struct MD5Context md5c;
unsigned char digest[16], lenbuf[4];
char *ret;
unsigned char *name, *fullname;
int pointlen, namelen, fullnamelen, i, j;
MD5Init(&md5c);
namelen = ec_curve_to_name(EC_TYPE_DSA, ec->publicKey.curve, NULL, 0);
name = snewn(namelen, unsigned char);
ec_curve_to_name(EC_TYPE_DSA, ec->publicKey.curve, name, namelen);
if (ec->publicKey.curve->type == EC_EDWARDS) {
unsigned char b;
/* Do it with the weird encoding */
PUT_32BIT(lenbuf, namelen);
MD5Update(&md5c, lenbuf, 4);
MD5Update(&md5c, name, namelen);
pointlen = ec->publicKey.curve->fieldBits / 8;
PUT_32BIT(lenbuf, pointlen);
MD5Update(&md5c, lenbuf, 4);
for (i = 0; i < pointlen - 1; ++i) {
b = bignum_byte(ec->publicKey.y, i);
MD5Update(&md5c, &b, 1);
}
/* Unset last bit of y and set first bit of x in its place */
b = bignum_byte(ec->publicKey.y, i) & 0x7f;
b |= bignum_bit(ec->publicKey.x, 0) << 7;
MD5Update(&md5c, &b, 1);
} else if (ec->publicKey.curve->type == EC_WEIERSTRASS) {
fullnamelen = ec_curve_to_name(EC_TYPE_CURVE, ec->publicKey.curve, NULL, 0);
fullname = snewn(namelen, unsigned char);
ec_curve_to_name(EC_TYPE_DSA, ec->publicKey.curve, fullname, fullnamelen);
PUT_32BIT(lenbuf, fullnamelen);
MD5Update(&md5c, lenbuf, 4);
MD5Update(&md5c, fullname, fullnamelen);
sfree(fullname);
PUT_32BIT(lenbuf, namelen);
MD5Update(&md5c, lenbuf, 4);
MD5Update(&md5c, name, namelen);
pointlen = (bignum_bitcount(ec->publicKey.curve->p) + 7) / 8;
PUT_32BIT(lenbuf, 1 + (pointlen * 2));
MD5Update(&md5c, lenbuf, 4);
MD5Update(&md5c, (const unsigned char *)"\x04", 1);
for (i = pointlen; i--; ) {
unsigned char c = bignum_byte(ec->publicKey.x, i);
MD5Update(&md5c, &c, 1);
}
for (i = pointlen; i--; ) {
unsigned char c = bignum_byte(ec->publicKey.y, i);
MD5Update(&md5c, &c, 1);
}
} else {
sfree(name);
return NULL;
}
MD5Final(digest, &md5c);
ret = snewn(namelen + 1 + (16 * 3), char);
i = 0;
memcpy(ret, name, namelen);
i += namelen;
sfree(name);
ret[i++] = ' ';
for (j = 0; j < 16; j++) {
i += sprintf(ret + i, "%s%02x", j ? ":" : "", digest[j]);
}
return ret;
}
static int ecdsa_verifysig(void *key, const char *sig, int siglen,
const char *data, int datalen)
{
@ -3545,7 +3464,6 @@ const struct ssh_signkey ssh_ecdsa_ed25519 = {
ed25519_openssh_fmtkey,
2 /* point, private exponent */,
ecdsa_pubkey_bits,
ecdsa_fingerprint,
ecdsa_verifysig,
ecdsa_sign,
"ssh-ed25519",
@ -3563,7 +3481,6 @@ const struct ssh_signkey ssh_ecdsa_nistp256 = {
ecdsa_openssh_fmtkey,
3 /* curve name, point, private exponent */,
ecdsa_pubkey_bits,
ecdsa_fingerprint,
ecdsa_verifysig,
ecdsa_sign,
"ecdsa-sha2-nistp256",
@ -3581,7 +3498,6 @@ const struct ssh_signkey ssh_ecdsa_nistp384 = {
ecdsa_openssh_fmtkey,
3 /* curve name, point, private exponent */,
ecdsa_pubkey_bits,
ecdsa_fingerprint,
ecdsa_verifysig,
ecdsa_sign,
"ecdsa-sha2-nistp384",
@ -3599,7 +3515,6 @@ const struct ssh_signkey ssh_ecdsa_nistp521 = {
ecdsa_openssh_fmtkey,
3 /* curve name, point, private exponent */,
ecdsa_pubkey_bits,
ecdsa_fingerprint,
ecdsa_verifysig,
ecdsa_sign,
"ecdsa-sha2-nistp521",

View File

@ -1568,6 +1568,62 @@ void ssh2_write_pubkey(FILE *fp, const char *comment,
}
}
/* ----------------------------------------------------------------------
* Utility functions to compute SSH-2 fingerprints in a uniform way.
*/
char *ssh2_fingerprint_blob(const void *blob, int bloblen)
{
unsigned char digest[16];
char fingerprint_str[16*3];
const char *algstr;
int alglen;
const struct ssh_signkey *alg;
int i;
/*
* The fingerprint hash itself is always just the MD5 of the blob.
*/
MD5Simple(blob, bloblen, digest);
for (i = 0; i < 16; i++)
sprintf(fingerprint_str + i*3, "%02x%s", digest[i], i==15 ? "" : ":");
/*
* Identify the key algorithm, if possible.
*/
alglen = toint(GET_32BIT((const unsigned char *)blob));
if (alglen > 0 && alglen < bloblen-4) {
algstr = (const char *)blob + 4;
/*
* If we can actually identify the algorithm as one we know
* about, get hold of the key's bit count too.
*/
alg = find_pubkey_alg_len(alglen, algstr);
if (alg) {
int bits = alg->pubkey_bits(blob, bloblen);
return dupprintf("%.*s %d %s", alglen, algstr,
bits, fingerprint_str);
} else {
return dupprintf("%.*s %s", alglen, algstr, fingerprint_str);
}
} else {
/*
* No algorithm available (which means a seriously confused
* key blob, but there we go). Return only the hash.
*/
return dupstr(fingerprint_str);
}
}
char *ssh2_fingerprint(const struct ssh_signkey *alg, void *data)
{
int len;
unsigned char *blob = alg->public_blob(data, &len);
char *ret = ssh2_fingerprint_blob(blob, len);
sfree(blob);
return ret;
}
/* ----------------------------------------------------------------------
* Determine the type of a private key file.
*/

View File

@ -775,41 +775,6 @@ static int rsa2_pubkey_bits(const void *blob, int len)
return ret;
}
static char *rsa2_fingerprint(void *key)
{
struct RSAKey *rsa = (struct RSAKey *) key;
struct MD5Context md5c;
unsigned char digest[16], lenbuf[4];
char buffer[16 * 3 + 40];
char *ret;
int numlen, i;
MD5Init(&md5c);
MD5Update(&md5c, (unsigned char *)"\0\0\0\7ssh-rsa", 11);
#define ADD_BIGNUM(bignum) \
numlen = (bignum_bitcount(bignum)+8)/8; \
PUT_32BIT(lenbuf, numlen); MD5Update(&md5c, lenbuf, 4); \
for (i = numlen; i-- ;) { \
unsigned char c = bignum_byte(bignum, i); \
MD5Update(&md5c, &c, 1); \
}
ADD_BIGNUM(rsa->exponent);
ADD_BIGNUM(rsa->modulus);
#undef ADD_BIGNUM
MD5Final(digest, &md5c);
sprintf(buffer, "ssh-rsa %d ", bignum_bitcount(rsa->modulus));
for (i = 0; i < 16; i++)
sprintf(buffer + strlen(buffer), "%s%02x", i ? ":" : "",
digest[i]);
ret = snewn(strlen(buffer) + 1, char);
if (ret)
strcpy(ret, buffer);
return ret;
}
/*
* This is the magic ASN.1/DER prefix that goes in the decoded
* signature, between the string of FFs and the actual SHA hash
@ -945,7 +910,6 @@ const struct ssh_signkey ssh_rsa = {
rsa2_openssh_fmtkey,
6 /* n,e,d,iqmp,q,p */,
rsa2_pubkey_bits,
rsa2_fingerprint,
rsa2_verifysig,
rsa2_sign,
"ssh-rsa",

View File

@ -753,9 +753,7 @@ void load_key_file(HWND hwnd, struct MainDlgState *state,
savecomment = state->ssh2key.comment;
state->ssh2key.comment = NULL;
fp =
state->ssh2key.alg->
fingerprint(state->ssh2key.data);
fp = ssh2_fingerprint(state->ssh2key.alg, state->ssh2key.data);
state->ssh2key.comment = savecomment;
SetDlgItemText(hwnd, IDC_FINGERPRINT, fp);
@ -1395,7 +1393,7 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg,
*state->commentptr = NULL;
if (state->ssh2) {
char *fp;
fp = state->ssh2key.alg->fingerprint(state->ssh2key.data);
fp = ssh2_fingerprint(state->ssh2key.alg, state->ssh2key.data);
SetDlgItemText(hwnd, IDC_FINGERPRINT, fp);
sfree(fp);
} else {

View File

@ -297,7 +297,7 @@ void keylist_update(void)
* nice alignment in the list box, until we encounter a :
* meaning we're into the fingerprint proper.
*/
p = skey->alg->fingerprint(skey->data);
p = ssh2_fingerprint(skey->alg, skey->data);
listentry = dupprintf("%s\t%s", p, skey->comment);
fp_len = strlen(listentry);
sfree(p);