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;
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);
}
}
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)))
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);
}
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);
}
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);
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);
}
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;
* 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. */
* 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,
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);
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)
{
dss_openssh_fmtkey,
5 /* p,q,g,y,x */,
dss_pubkey_bits,
- dss_fingerprint,
dss_verifysig,
dss_sign,
"ssh-dss",
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)
{
ed25519_openssh_fmtkey,
2 /* point, private exponent */,
ecdsa_pubkey_bits,
- ecdsa_fingerprint,
ecdsa_verifysig,
ecdsa_sign,
"ssh-ed25519",
ecdsa_openssh_fmtkey,
3 /* curve name, point, private exponent */,
ecdsa_pubkey_bits,
- ecdsa_fingerprint,
ecdsa_verifysig,
ecdsa_sign,
"ecdsa-sha2-nistp256",
ecdsa_openssh_fmtkey,
3 /* curve name, point, private exponent */,
ecdsa_pubkey_bits,
- ecdsa_fingerprint,
ecdsa_verifysig,
ecdsa_sign,
"ecdsa-sha2-nistp384",
ecdsa_openssh_fmtkey,
3 /* curve name, point, private exponent */,
ecdsa_pubkey_bits,
- ecdsa_fingerprint,
ecdsa_verifysig,
ecdsa_sign,
"ecdsa-sha2-nistp521",
}
}
+/* ----------------------------------------------------------------------
+ * 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.
*/
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
rsa2_openssh_fmtkey,
6 /* n,e,d,iqmp,q,p */,
rsa2_pubkey_bits,
- rsa2_fingerprint,
rsa2_verifysig,
rsa2_sign,
"ssh-rsa",
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);
*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 {
* 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);