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:
parent
eef0235a0f
commit
8682246d33
26
cmdgen.c
26
cmdgen.c
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
30
pageant.c
30
pageant.c
@ -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
2
ssh.c
@ -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
3
ssh.h
@ -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);
|
||||
|
||||
|
38
sshdss.c
38
sshdss.c
@ -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",
|
||||
|
85
sshecc.c
85
sshecc.c
@ -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",
|
||||
|
56
sshpubk.c
56
sshpubk.c
@ -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.
|
||||
*/
|
||||
|
36
sshrsa.c
36
sshrsa.c
@ -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",
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user