]> asedeno.scripts.mit.edu Git - PuTTY.git/commitdiff
Centralise SSH-2 key fingerprinting into sshpubk.c.
authorSimon Tatham <anakin@pobox.com>
Tue, 12 May 2015 13:35:44 +0000 (14:35 +0100)
committerSimon Tatham <anakin@pobox.com>
Tue, 12 May 2015 13:56:38 +0000 (14:56 +0100)
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.

cmdgen.c
pageant.c
ssh.c
ssh.h
sshdss.c
sshecc.c
sshpubk.c
sshrsa.c
windows/winpgen.c
windows/winpgnt.c

index aa03cb544bacebdf9069c307d2965528d97e9478..df3fd9af57ba69aa48a8140012690f1933c385f8 100644 (file)
--- a/cmdgen.c
+++ b/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);
                }
            }
 
index 754af9c6aca103c2b649446f72a92cb1da706aee..c249a3b7188cc93dd6a7c3458ab1e1dc6f0a5dce 100644 (file)
--- a/pageant.c
+++ b/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;
diff --git a/ssh.c b/ssh.c
index 5d27d5ea6253e859d336dfe0b1538eb68ebb0282..0f4712d89360e622c2a012c09b23148e00323931 100644 (file)
--- a/ssh.c
+++ b/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. */
diff --git a/ssh.h b/ssh.h
index 4e36ad4584ae8aa2893ab7e154926fcce11ca746..1924d9f16ee7595d7af7f3bb41061663483119dc 100644 (file)
--- a/ssh.h
+++ b/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);
 
index 5633e39545bae50393d57f73cf3f8f238afe8740..800562669f322d01ffc56522cbaaac8f830b7998 100644 (file)
--- a/sshdss.c
+++ b/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",
index 5cda17be7d084e6a73ed9cd7584e2e7580b036e5..6915eaf0fc401ed84781ca519b9eb713568169c4 100644 (file)
--- a/sshecc.c
+++ b/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",
index 053eeb6f233b66d0e13b0a9888404d1811bbb152..e5952a0ad29482f1e17a0f23967df5e989449c57 100644 (file)
--- a/sshpubk.c
+++ b/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.
  */
index 3adccfbef1d43eb9fc0787b7e7537ca26d60488a..9042c43a0c9282a03eff72855e3fd2a0b2b39621 100644 (file)
--- a/sshrsa.c
+++ b/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",
index 8806d75f933b972bd17e675585fb7e86a8366c79..20146da60711686c41cbde0e482db4d96a5f3c6b 100644 (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 {
index a82888f6755110c35ca07e415874970b81780302..70f8309eb174307b7995063cb7012ded6ff2bb15 100644 (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);