1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-26 01:32:25 +00:00

Change ssh.h crypto APIs to output to BinarySink.

This affects all the functions that generate public and private key
and signature blobs of all kinds, plus ssh_ecdhkex_getpublic. Instead
of returning a bare block of memory and taking an extra 'int *length'
parameter, all these functions now write to a BinarySink, and it's the
caller's job to have prepared an appropriate one where they want the
output to go (usually a strbuf).

The main value of this change is that those blob-generation functions
were chock full of ad-hoc length-counting and data marshalling. You
have only to look at rsa2_{public,private}_blob, for example, to see
the kind of thing I was keen to get rid of!
This commit is contained in:
Simon Tatham 2018-05-24 10:59:39 +01:00
parent a990738aca
commit 67de463cca
12 changed files with 542 additions and 956 deletions

View File

@ -246,10 +246,9 @@ int main(int argc, char **argv)
int sshver = 0; int sshver = 0;
struct ssh2_userkey *ssh2key = NULL; struct ssh2_userkey *ssh2key = NULL;
struct RSAKey *ssh1key = NULL; struct RSAKey *ssh1key = NULL;
unsigned char *ssh2blob = NULL; strbuf *ssh2blob = NULL;
char *ssh2alg = NULL; char *ssh2alg = NULL;
const struct ssh_signkey *ssh2algf = NULL; const struct ssh_signkey *ssh2algf = NULL;
int ssh2bloblen;
char *old_passphrase = NULL, *new_passphrase = NULL; char *old_passphrase = NULL, *new_passphrase = NULL;
int load_encrypted; int load_encrypted;
progfn_t progressfn = is_interactive() ? progress_update : no_progress; progfn_t progressfn = is_interactive() ? progress_update : no_progress;
@ -807,29 +806,33 @@ int main(int argc, char **argv)
case SSH_KEYTYPE_SSH1_PUBLIC: case SSH_KEYTYPE_SSH1_PUBLIC:
ssh1key = snew(struct RSAKey); ssh1key = snew(struct RSAKey);
if (!load_encrypted) { if (!load_encrypted) {
void *vblob; strbuf *blob;
unsigned char *blob; int n, l;
int n, l, bloblen;
ret = rsa_ssh1_loadpub(infilename, &vblob, &bloblen, blob = strbuf_new();
ret = rsa_ssh1_loadpub(infilename, BinarySink_UPCAST(blob),
&origcomment, &error); &origcomment, &error);
blob = (unsigned char *)vblob;
n = 4; /* skip modulus bits */ n = 4; /* skip modulus bits */
l = ssh1_read_bignum(blob + n, bloblen - n, l = ssh1_read_bignum(blob->u + n,
blob->len - n,
&ssh1key->exponent); &ssh1key->exponent);
if (l < 0) { if (l < 0) {
error = "SSH-1 public key blob was too short"; error = "SSH-1 public key blob was too short";
} else { } else {
n += l; n += l;
l = ssh1_read_bignum(blob + n, bloblen - n, l = ssh1_read_bignum(
&ssh1key->modulus); blob->u + n,
blob->len - n, &ssh1key->modulus);
if (l < 0) { if (l < 0) {
error = "SSH-1 public key blob was too short"; error = "SSH-1 public key blob was too short";
} else } else
n += l; n += l;
} }
strbuf_free(blob);
ssh1key->comment = dupstr(origcomment); ssh1key->comment = dupstr(origcomment);
ssh1key->private_exponent = NULL; ssh1key->private_exponent = NULL;
ssh1key->p = NULL; ssh1key->p = NULL;
@ -849,16 +852,18 @@ int main(int argc, char **argv)
case SSH_KEYTYPE_SSH2_PUBLIC_RFC4716: case SSH_KEYTYPE_SSH2_PUBLIC_RFC4716:
case SSH_KEYTYPE_SSH2_PUBLIC_OPENSSH: case SSH_KEYTYPE_SSH2_PUBLIC_OPENSSH:
if (!load_encrypted) { if (!load_encrypted) {
ssh2blob = ssh2_userkey_loadpub(infilename, &ssh2alg, ssh2blob = strbuf_new();
&ssh2bloblen, &origcomment, if (ssh2_userkey_loadpub(infilename, &ssh2alg, BinarySink_UPCAST(ssh2blob),
&error); &origcomment, &error)) {
if (ssh2blob) {
ssh2algf = find_pubkey_alg(ssh2alg); ssh2algf = find_pubkey_alg(ssh2alg);
if (ssh2algf) if (ssh2algf)
bits = ssh2algf->pubkey_bits(ssh2algf, bits = ssh2algf->pubkey_bits(ssh2algf,
ssh2blob, ssh2bloblen); ssh2blob->s,
ssh2blob->len);
else else
bits = -1; bits = -1;
} else {
strbuf_free(ssh2blob);
} }
sfree(ssh2alg); sfree(ssh2alg);
} else { } else {
@ -1007,12 +1012,12 @@ int main(int argc, char **argv)
} else { } else {
if (!ssh2blob) { if (!ssh2blob) {
assert(ssh2key); assert(ssh2key);
ssh2blob = ssh2key->alg->public_blob(ssh2key->data, ssh2blob = strbuf_new();
&ssh2bloblen); ssh2key->alg->public_blob(ssh2key->data, BinarySink_UPCAST(ssh2blob));
} }
ssh2_write_pubkey(fp, ssh2key ? ssh2key->comment : origcomment, ssh2_write_pubkey(fp, ssh2key ? ssh2key->comment : origcomment,
ssh2blob, ssh2bloblen, ssh2blob->s, ssh2blob->len,
(outtype == PUBLIC ? (outtype == PUBLIC ?
SSH_KEYTYPE_SSH2_PUBLIC_RFC4716 : SSH_KEYTYPE_SSH2_PUBLIC_RFC4716 :
SSH_KEYTYPE_SSH2_PUBLIC_OPENSSH)); SSH_KEYTYPE_SSH2_PUBLIC_OPENSSH));
@ -1038,7 +1043,8 @@ int main(int argc, char **argv)
ssh2key->data); ssh2key->data);
} else { } else {
assert(ssh2blob); assert(ssh2blob);
fingerprint = ssh2_fingerprint_blob(ssh2blob, ssh2bloblen); fingerprint = ssh2_fingerprint_blob(
ssh2blob->s, ssh2blob->len);
} }
} }

144
import.c
View File

@ -924,8 +924,9 @@ struct ssh2_userkey *openssh_pem_read(const Filename *filename,
int openssh_pem_write(const Filename *filename, struct ssh2_userkey *key, int openssh_pem_write(const Filename *filename, struct ssh2_userkey *key,
char *passphrase) char *passphrase)
{ {
unsigned char *pubblob, *privblob, *spareblob; strbuf *pubblob, *privblob;
int publen, privlen, sparelen = 0; unsigned char *spareblob;
int sparelen = 0;
unsigned char *outblob; unsigned char *outblob;
int outlen; int outlen;
struct mpint_pos numbers[9]; struct mpint_pos numbers[9];
@ -939,8 +940,10 @@ int openssh_pem_write(const Filename *filename, struct ssh2_userkey *key,
/* /*
* Fetch the key blobs. * Fetch the key blobs.
*/ */
pubblob = key->alg->public_blob(key->data, &publen); pubblob = strbuf_new();
privblob = key->alg->private_blob(key->data, &privlen); key->alg->public_blob(key->data, BinarySink_UPCAST(pubblob));
privblob = strbuf_new();
key->alg->private_blob(key->data, BinarySink_UPCAST(privblob));
spareblob = outblob = NULL; spareblob = outblob = NULL;
outblob = NULL; outblob = NULL;
@ -967,14 +970,14 @@ int openssh_pem_write(const Filename *filename, struct ssh2_userkey *key,
* These blobs were generated from inside PuTTY, so we needn't * These blobs were generated from inside PuTTY, so we needn't
* treat them as untrusted. * treat them as untrusted.
*/ */
pos = 4 + GET_32BIT(pubblob); pos = 4 + GET_32BIT(pubblob->u);
pos += ssh2_read_mpint(pubblob+pos, publen-pos, &e); pos += ssh2_read_mpint(pubblob->u+pos, pubblob->len-pos, &e);
pos += ssh2_read_mpint(pubblob+pos, publen-pos, &n); pos += ssh2_read_mpint(pubblob->u+pos, pubblob->len-pos, &n);
pos = 0; pos = 0;
pos += ssh2_read_mpint(privblob+pos, privlen-pos, &d); pos += ssh2_read_mpint(privblob->u+pos, privblob->len-pos, &d);
pos += ssh2_read_mpint(privblob+pos, privlen-pos, &p); pos += ssh2_read_mpint(privblob->u+pos, privblob->len-pos, &p);
pos += ssh2_read_mpint(privblob+pos, privlen-pos, &q); pos += ssh2_read_mpint(privblob->u+pos, privblob->len-pos, &q);
pos += ssh2_read_mpint(privblob+pos, privlen-pos, &iqmp); pos += ssh2_read_mpint(privblob->u+pos, privblob->len-pos, &iqmp);
assert(e.start && iqmp.start); /* can't go wrong */ assert(e.start && iqmp.start); /* can't go wrong */
@ -1024,13 +1027,13 @@ int openssh_pem_write(const Filename *filename, struct ssh2_userkey *key,
* These blobs were generated from inside PuTTY, so we needn't * These blobs were generated from inside PuTTY, so we needn't
* treat them as untrusted. * treat them as untrusted.
*/ */
pos = 4 + GET_32BIT(pubblob); pos = 4 + GET_32BIT(pubblob->u);
pos += ssh2_read_mpint(pubblob+pos, publen-pos, &p); pos += ssh2_read_mpint(pubblob->u+pos, pubblob->len-pos, &p);
pos += ssh2_read_mpint(pubblob+pos, publen-pos, &q); pos += ssh2_read_mpint(pubblob->u+pos, pubblob->len-pos, &q);
pos += ssh2_read_mpint(pubblob+pos, publen-pos, &g); pos += ssh2_read_mpint(pubblob->u+pos, pubblob->len-pos, &g);
pos += ssh2_read_mpint(pubblob+pos, publen-pos, &y); pos += ssh2_read_mpint(pubblob->u+pos, pubblob->len-pos, &y);
pos = 0; pos = 0;
pos += ssh2_read_mpint(privblob+pos, privlen-pos, &x); pos += ssh2_read_mpint(privblob->u+pos, privblob->len-pos, &x);
assert(y.start && x.start); /* can't go wrong */ assert(y.start && x.start); /* can't go wrong */
@ -1097,8 +1100,8 @@ int openssh_pem_write(const Filename *filename, struct ssh2_userkey *key,
len = ber_write_id_len(NULL, 2, 1, 0); len = ber_write_id_len(NULL, 2, 1, 0);
len += 1; len += 1;
len += ber_write_id_len(NULL, 4, privlen - 4, 0); len += ber_write_id_len(NULL, 4, privblob->len - 4, 0);
len+= privlen - 4; len+= privblob->len - 4;
len += ber_write_id_len(NULL, 0, oidlen + len += ber_write_id_len(NULL, 0, oidlen +
ber_write_id_len(NULL, 6, oidlen, 0), ber_write_id_len(NULL, 6, oidlen, 0),
ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED); ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED);
@ -1120,9 +1123,9 @@ int openssh_pem_write(const Filename *filename, struct ssh2_userkey *key,
pos += ber_write_id_len(outblob+pos, 16, seqlen, ASN1_CONSTRUCTED); pos += ber_write_id_len(outblob+pos, 16, seqlen, ASN1_CONSTRUCTED);
pos += ber_write_id_len(outblob+pos, 2, 1, 0); pos += ber_write_id_len(outblob+pos, 2, 1, 0);
outblob[pos++] = 1; outblob[pos++] = 1;
pos += ber_write_id_len(outblob+pos, 4, privlen - 4, 0); pos += ber_write_id_len(outblob+pos, 4, privblob->len - 4, 0);
memcpy(outblob+pos, privblob + 4, privlen - 4); memcpy(outblob+pos, privblob->u + 4, privblob->len - 4);
pos += privlen - 4; pos += privblob->len - 4;
pos += ber_write_id_len(outblob+pos, 0, oidlen + pos += ber_write_id_len(outblob+pos, 0, oidlen +
ber_write_id_len(NULL, 6, oidlen, 0), ber_write_id_len(NULL, 6, oidlen, 0),
ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED); ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED);
@ -1134,7 +1137,7 @@ int openssh_pem_write(const Filename *filename, struct ssh2_userkey *key,
ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED); ASN1_CLASS_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED);
pos += ber_write_id_len(outblob+pos, 3, 2 + pointlen, 0); pos += ber_write_id_len(outblob+pos, 3, 2 + pointlen, 0);
outblob[pos++] = 0; outblob[pos++] = 0;
memcpy(outblob+pos, pubblob+39, 1 + pointlen); memcpy(outblob+pos, pubblob->u+39, 1 + pointlen);
pos += 1 + pointlen; pos += 1 + pointlen;
header = "-----BEGIN EC PRIVATE KEY-----\n"; header = "-----BEGIN EC PRIVATE KEY-----\n";
@ -1254,14 +1257,10 @@ int openssh_pem_write(const Filename *filename, struct ssh2_userkey *key,
smemclr(spareblob, sparelen); smemclr(spareblob, sparelen);
sfree(spareblob); sfree(spareblob);
} }
if (privblob) { if (privblob)
smemclr(privblob, privlen); strbuf_free(privblob);
sfree(privblob); if (pubblob)
} strbuf_free(pubblob);
if (pubblob) {
smemclr(pubblob, publen);
sfree(pubblob);
}
return ret; return ret;
} }
@ -1747,9 +1746,10 @@ struct ssh2_userkey *openssh_new_read(const Filename *filename,
int openssh_new_write(const Filename *filename, struct ssh2_userkey *key, int openssh_new_write(const Filename *filename, struct ssh2_userkey *key,
char *passphrase) char *passphrase)
{ {
unsigned char *pubblob, *privblob, *outblob, *p; strbuf *pubblob, *privblob;
unsigned char *outblob, *p;
unsigned char *private_section_start, *private_section_length_field; unsigned char *private_section_start, *private_section_length_field;
int publen, privlen, commentlen, maxsize, padvalue, i; int commentlen, maxsize, padvalue, i;
unsigned checkint; unsigned checkint;
int ret = 0; int ret = 0;
unsigned char bcrypt_salt[16]; unsigned char bcrypt_salt[16];
@ -1759,11 +1759,10 @@ int openssh_new_write(const Filename *filename, struct ssh2_userkey *key,
/* /*
* Fetch the key blobs and find out the lengths of things. * Fetch the key blobs and find out the lengths of things.
*/ */
pubblob = key->alg->public_blob(key->data, &publen); pubblob = strbuf_new();
i = key->alg->openssh_fmtkey(key->data, NULL, 0); key->alg->public_blob(key->data, BinarySink_UPCAST(pubblob));
privblob = snewn(i, unsigned char); privblob = strbuf_new();
privlen = key->alg->openssh_fmtkey(key->data, privblob, i); key->alg->openssh_fmtkey(key->data, BinarySink_UPCAST(privblob));
assert(privlen == i);
commentlen = strlen(key->comment); commentlen = strlen(key->comment);
/* /*
@ -1775,11 +1774,11 @@ int openssh_new_write(const Filename *filename, struct ssh2_userkey *key,
32 + /* kdf name string */ 32 + /* kdf name string */
64 + /* kdf options string */ 64 + /* kdf options string */
4 + /* key count */ 4 + /* key count */
4+publen + /* public key string */ 4+pubblob->len + /* public key string */
4 + /* string header for private section */ 4 + /* string header for private section */
8 + /* checkint x 2 */ 8 + /* checkint x 2 */
4+strlen(key->alg->name) + /* key type string */ 4+strlen(key->alg->name) + /* key type string */
privlen + /* private blob */ privblob->len + /* private blob */
4+commentlen + /* comment string */ 4+commentlen + /* comment string */
16); /* padding at end of private section */ 16); /* padding at end of private section */
outblob = snewn(maxsize, unsigned char); outblob = snewn(maxsize, unsigned char);
@ -1816,7 +1815,7 @@ int openssh_new_write(const Filename *filename, struct ssh2_userkey *key,
p += write_uint32(p, 1); p += write_uint32(p, 1);
/* Public blob. */ /* Public blob. */
p += write_string(p, pubblob, publen); p += write_string(p, pubblob->u, pubblob->len);
/* Begin private section. */ /* Begin private section. */
private_section_length_field = p; private_section_length_field = p;
@ -1833,8 +1832,8 @@ int openssh_new_write(const Filename *filename, struct ssh2_userkey *key,
/* Private key. The main private blob goes inline, with no string /* Private key. The main private blob goes inline, with no string
* wrapper. */ * wrapper. */
p += write_string_z(p, key->alg->name); p += write_string_z(p, key->alg->name);
memcpy(p, privblob, privlen); memcpy(p, privblob->u, privblob->len);
p += privlen; p += privblob->len;
/* Comment. */ /* Comment. */
p += write_string_z(p, key->comment); p += write_string_z(p, key->comment);
@ -1891,14 +1890,10 @@ int openssh_new_write(const Filename *filename, struct ssh2_userkey *key,
smemclr(outblob, maxsize); smemclr(outblob, maxsize);
sfree(outblob); sfree(outblob);
} }
if (privblob) { if (privblob)
smemclr(privblob, privlen); strbuf_free(privblob);
sfree(privblob); if (pubblob)
} strbuf_free(pubblob);
if (pubblob) {
smemclr(pubblob, publen);
sfree(pubblob);
}
return ret; return ret;
} }
@ -2497,8 +2492,7 @@ struct ssh2_userkey *sshcom_read(const Filename *filename, char *passphrase,
int sshcom_write(const Filename *filename, struct ssh2_userkey *key, int sshcom_write(const Filename *filename, struct ssh2_userkey *key,
char *passphrase) char *passphrase)
{ {
unsigned char *pubblob, *privblob; strbuf *pubblob, *privblob;
int publen, privlen;
unsigned char *outblob; unsigned char *outblob;
int outlen; int outlen;
struct mpint_pos numbers[6]; struct mpint_pos numbers[6];
@ -2512,8 +2506,10 @@ int sshcom_write(const Filename *filename, struct ssh2_userkey *key,
/* /*
* Fetch the key blobs. * Fetch the key blobs.
*/ */
pubblob = key->alg->public_blob(key->data, &publen); pubblob = strbuf_new();
privblob = key->alg->private_blob(key->data, &privlen); key->alg->public_blob(key->data, BinarySink_UPCAST(pubblob));
privblob = strbuf_new();
key->alg->private_blob(key->data, BinarySink_UPCAST(privblob));
outblob = NULL; outblob = NULL;
/* /*
@ -2528,14 +2524,14 @@ int sshcom_write(const Filename *filename, struct ssh2_userkey *key,
* These blobs were generated from inside PuTTY, so we needn't * These blobs were generated from inside PuTTY, so we needn't
* treat them as untrusted. * treat them as untrusted.
*/ */
pos = 4 + GET_32BIT(pubblob); pos = 4 + GET_32BIT(pubblob->u);
pos += ssh2_read_mpint(pubblob+pos, publen-pos, &e); pos += ssh2_read_mpint(pubblob->u+pos, pubblob->len-pos, &e);
pos += ssh2_read_mpint(pubblob+pos, publen-pos, &n); pos += ssh2_read_mpint(pubblob->u+pos, pubblob->len-pos, &n);
pos = 0; pos = 0;
pos += ssh2_read_mpint(privblob+pos, privlen-pos, &d); pos += ssh2_read_mpint(privblob->u+pos, privblob->len-pos, &d);
pos += ssh2_read_mpint(privblob+pos, privlen-pos, &p); pos += ssh2_read_mpint(privblob->u+pos, privblob->len-pos, &p);
pos += ssh2_read_mpint(privblob+pos, privlen-pos, &q); pos += ssh2_read_mpint(privblob->u+pos, privblob->len-pos, &q);
pos += ssh2_read_mpint(privblob+pos, privlen-pos, &iqmp); pos += ssh2_read_mpint(privblob->u+pos, privblob->len-pos, &iqmp);
assert(e.start && iqmp.start); /* can't go wrong */ assert(e.start && iqmp.start); /* can't go wrong */
@ -2557,13 +2553,13 @@ int sshcom_write(const Filename *filename, struct ssh2_userkey *key,
* These blobs were generated from inside PuTTY, so we needn't * These blobs were generated from inside PuTTY, so we needn't
* treat them as untrusted. * treat them as untrusted.
*/ */
pos = 4 + GET_32BIT(pubblob); pos = 4 + GET_32BIT(pubblob->u);
pos += ssh2_read_mpint(pubblob+pos, publen-pos, &p); pos += ssh2_read_mpint(pubblob->u+pos, pubblob->len-pos, &p);
pos += ssh2_read_mpint(pubblob+pos, publen-pos, &q); pos += ssh2_read_mpint(pubblob->u+pos, pubblob->len-pos, &q);
pos += ssh2_read_mpint(pubblob+pos, publen-pos, &g); pos += ssh2_read_mpint(pubblob->u+pos, pubblob->len-pos, &g);
pos += ssh2_read_mpint(pubblob+pos, publen-pos, &y); pos += ssh2_read_mpint(pubblob->u+pos, pubblob->len-pos, &y);
pos = 0; pos = 0;
pos += ssh2_read_mpint(privblob+pos, privlen-pos, &x); pos += ssh2_read_mpint(privblob->u+pos, privblob->len-pos, &x);
assert(y.start && x.start); /* can't go wrong */ assert(y.start && x.start); /* can't go wrong */
@ -2700,13 +2696,9 @@ int sshcom_write(const Filename *filename, struct ssh2_userkey *key,
smemclr(outblob, outlen); smemclr(outblob, outlen);
sfree(outblob); sfree(outblob);
} }
if (privblob) { if (privblob)
smemclr(privblob, privlen); strbuf_free(privblob);
sfree(privblob); if (pubblob)
} strbuf_free(pubblob);
if (pubblob) {
smemclr(pubblob, publen);
sfree(pubblob);
}
return ret; return ret;
} }

318
pageant.c
View File

@ -34,16 +34,6 @@ static int pageant_local = FALSE;
*/ */
static tree234 *rsakeys, *ssh2keys; static tree234 *rsakeys, *ssh2keys;
/*
* Blob structure for passing to the asymmetric SSH-2 key compare
* function, prototyped here.
*/
struct blob {
const unsigned char *blob;
int len;
};
static int cmpkeys_ssh2_asymm(void *av, void *bv);
/* /*
* Key comparison function for the 2-3-4 tree of RSA keys. * Key comparison function for the 2-3-4 tree of RSA keys.
*/ */
@ -84,128 +74,77 @@ static int cmpkeys_rsa(void *av, void *bv)
return 0; return 0;
} }
/*
* Key comparison function for the 2-3-4 tree of SSH-2 keys.
*/
static int cmpkeys_ssh2(void *av, void *bv)
{
struct ssh2_userkey *a = (struct ssh2_userkey *) av;
struct ssh2_userkey *b = (struct ssh2_userkey *) bv;
int i;
int alen, blen;
unsigned char *ablob, *bblob;
int c;
/*
* Compare purely by public blob.
*/
ablob = a->alg->public_blob(a->data, &alen);
bblob = b->alg->public_blob(b->data, &blen);
c = 0;
for (i = 0; i < alen && i < blen; i++) {
if (ablob[i] < bblob[i]) {
c = -1;
break;
} else if (ablob[i] > bblob[i]) {
c = +1;
break;
}
}
if (c == 0 && i < alen)
c = +1; /* a is longer */
if (c == 0 && i < blen)
c = -1; /* a is longer */
sfree(ablob);
sfree(bblob);
return c;
}
/* /*
* Key comparison function for looking up a blob in the 2-3-4 tree * Key comparison function for looking up a blob in the 2-3-4 tree
* of SSH-2 keys. * of SSH-2 keys.
*/ */
static int cmpkeys_ssh2_asymm(void *av, void *bv) static int cmpkeys_ssh2_asymm(void *av, void *bv)
{ {
struct blob *a = (struct blob *) av; strbuf *ablob = (strbuf *) av;
struct ssh2_userkey *b = (struct ssh2_userkey *) bv; struct ssh2_userkey *b = (struct ssh2_userkey *) bv;
int i; strbuf *bblob;
int alen, blen; int i, c;
const unsigned char *ablob;
unsigned char *bblob;
int c;
/* /*
* Compare purely by public blob. * Compare purely by public blob.
*/ */
ablob = a->blob; bblob = strbuf_new();
alen = a->len; b->alg->public_blob(b->data, BinarySink_UPCAST(bblob));
bblob = b->alg->public_blob(b->data, &blen);
c = 0; c = 0;
for (i = 0; i < alen && i < blen; i++) { for (i = 0; i < ablob->len && i < bblob->len; i++) {
if (ablob[i] < bblob[i]) { if (ablob->u[i] < bblob->u[i]) {
c = -1; c = -1;
break; break;
} else if (ablob[i] > bblob[i]) { } else if (ablob->u[i] > bblob->u[i]) {
c = +1; c = +1;
break; break;
} }
} }
if (c == 0 && i < alen) if (c == 0 && i < ablob->len)
c = +1; /* a is longer */ c = +1; /* a is longer */
if (c == 0 && i < blen) if (c == 0 && i < bblob->len)
c = -1; /* a is longer */ c = -1; /* a is longer */
sfree(bblob); strbuf_free(bblob);
return c; return c;
} }
/*
* Main key comparison function for the 2-3-4 tree of SSH-2 keys.
*/
static int cmpkeys_ssh2(void *av, void *bv)
{
struct ssh2_userkey *a = (struct ssh2_userkey *) av;
strbuf *ablob;
int toret;
ablob = strbuf_new();
a->alg->public_blob(a->data, BinarySink_UPCAST(ablob));
toret = cmpkeys_ssh2_asymm(ablob, bv);
strbuf_free(ablob);
return toret;
}
/* /*
* Create an SSH-1 key list in a malloc'ed buffer; return its * Create an SSH-1 key list in a malloc'ed buffer; return its
* length. * length.
*/ */
void *pageant_make_keylist1(int *length) void *pageant_make_keylist1(int *length)
{ {
int i, nkeys, len; strbuf *buf = strbuf_new();
BinarySink *bs = BinarySink_UPCAST(buf);
int i;
struct RSAKey *key; struct RSAKey *key;
unsigned char *blob, *p, *ret;
int bloblen;
/* put_uint32(bs, count234(rsakeys));
* Count up the number and length of keys we hold.
*/
len = 4;
nkeys = 0;
for (i = 0; NULL != (key = index234(rsakeys, i)); i++) { for (i = 0; NULL != (key = index234(rsakeys, i)); i++) {
nkeys++; rsa_ssh1_public_blob(bs, key, RSA_SSH1_EXPONENT_FIRST);
blob = rsa_ssh1_public_blob(key, &bloblen, RSA_SSH1_EXPONENT_FIRST); put_stringz(bs, key->comment);
len += bloblen;
sfree(blob);
len += 4 + strlen(key->comment);
} }
/* Allocate the buffer. */ return strbuf_to_str(buf);
p = ret = snewn(len, unsigned char);
if (length) *length = len;
PUT_32BIT(p, nkeys);
p += 4;
for (i = 0; NULL != (key = index234(rsakeys, i)); i++) {
blob = rsa_ssh1_public_blob(key, &bloblen, RSA_SSH1_EXPONENT_FIRST);
memcpy(p, blob, bloblen);
p += bloblen;
sfree(blob);
PUT_32BIT(p, strlen(key->comment));
memcpy(p + 4, key->comment, strlen(key->comment));
p += 4 + strlen(key->comment);
}
assert(p - ret == len);
return ret;
} }
/* /*
@ -214,49 +153,20 @@ void *pageant_make_keylist1(int *length)
*/ */
void *pageant_make_keylist2(int *length) void *pageant_make_keylist2(int *length)
{ {
strbuf *buf = strbuf_new();
BinarySink *bs = BinarySink_UPCAST(buf);
int i;
struct ssh2_userkey *key; struct ssh2_userkey *key;
int i, len, nkeys;
unsigned char *blob, *p, *ret;
int bloblen;
/* put_uint32(bs, count234(ssh2keys));
* Count up the number and length of keys we hold.
*/
len = 4;
nkeys = 0;
for (i = 0; NULL != (key = index234(ssh2keys, i)); i++) { for (i = 0; NULL != (key = index234(ssh2keys, i)); i++) {
nkeys++; strbuf *blob = strbuf_new();
len += 4; /* length field */ key->alg->public_blob(key->data, BinarySink_UPCAST(blob));
blob = key->alg->public_blob(key->data, &bloblen); put_stringsb(bs, blob);
len += bloblen; put_stringz(bs, key->comment);
sfree(blob);
len += 4 + strlen(key->comment);
} }
/* Allocate the buffer. */ return strbuf_to_str(buf);
p = ret = snewn(len, unsigned char);
if (length) *length = len;
/*
* Packet header is the obvious five bytes, plus four
* bytes for the key count.
*/
PUT_32BIT(p, nkeys);
p += 4;
for (i = 0; NULL != (key = index234(ssh2keys, i)); i++) {
blob = key->alg->public_blob(key->data, &bloblen);
PUT_32BIT(p, bloblen);
p += 4;
memcpy(p, blob, bloblen);
p += bloblen;
sfree(blob);
PUT_32BIT(p, strlen(key->comment));
memcpy(p + 4, key->comment, strlen(key->comment));
p += 4 + strlen(key->comment);
}
assert(p - ret == len);
return ret;
} }
static void plog(void *logctx, pageant_logfn_t logfn, const char *fmt, ...) static void plog(void *logctx, pageant_logfn_t logfn, const char *fmt, ...)
@ -480,10 +390,11 @@ void *pageant_handle_msg(const void *msg, int msglen, int *outlen,
*/ */
{ {
struct ssh2_userkey *key; struct ssh2_userkey *key;
struct blob b; const void *blobp;
int bloblen;
const unsigned char *data; const unsigned char *data;
unsigned char *signature; strbuf *signature;
int datalen, siglen, len; int datalen, len;
plog(logctx, logfn, "request: SSH2_AGENTC_SIGN_REQUEST"); plog(logctx, logfn, "request: SSH2_AGENTC_SIGN_REQUEST");
@ -491,14 +402,14 @@ void *pageant_handle_msg(const void *msg, int msglen, int *outlen,
fail_reason = "request truncated before public key"; fail_reason = "request truncated before public key";
goto failure; goto failure;
} }
b.len = toint(GET_32BIT(p)); bloblen = toint(GET_32BIT(p));
if (b.len < 0 || b.len > msgend - (p+4)) { if (bloblen < 0 || bloblen > msgend - (p+4)) {
fail_reason = "request truncated before public key"; fail_reason = "request truncated before public key";
goto failure; goto failure;
} }
p += 4; p += 4;
b.blob = p; blobp = p;
p += b.len; p += bloblen;
if (msgend < p+4) { if (msgend < p+4) {
fail_reason = "request truncated before string to sign"; fail_reason = "request truncated before string to sign";
goto failure; goto failure;
@ -511,23 +422,29 @@ void *pageant_handle_msg(const void *msg, int msglen, int *outlen,
} }
data = p; data = p;
if (logfn) { if (logfn) {
char *fingerprint = ssh2_fingerprint_blob(b.blob, b.len); char *fingerprint = ssh2_fingerprint_blob(blobp, bloblen);
plog(logctx, logfn, "requested key: %s", fingerprint); plog(logctx, logfn, "requested key: %s", fingerprint);
sfree(fingerprint); sfree(fingerprint);
} }
key = find234(ssh2keys, &b, cmpkeys_ssh2_asymm); {
strbuf *blob = strbuf_new();
put_data(blob, blobp, bloblen);
key = find234(ssh2keys, blob, cmpkeys_ssh2_asymm);
strbuf_free(blob);
}
if (!key) { if (!key) {
fail_reason = "key not found"; fail_reason = "key not found";
goto failure; goto failure;
} }
signature = key->alg->sign(key->data, (const char *)data, signature = strbuf_new();
datalen, &siglen); key->alg->sign(key->data, (const char *)data, datalen,
len = 5 + 4 + siglen; BinarySink_UPCAST(signature));
len = 5 + 4 + signature->len;
PUT_32BIT(ret, len - 4); PUT_32BIT(ret, len - 4);
ret[4] = SSH2_AGENT_SIGN_RESPONSE; ret[4] = SSH2_AGENT_SIGN_RESPONSE;
PUT_32BIT(ret + 5, siglen); PUT_32BIT(ret + 5, signature->len);
memcpy(ret + 5 + 4, signature, siglen); memcpy(ret + 5 + 4, signature->s, signature->len);
sfree(signature); strbuf_free(signature);
plog(logctx, logfn, "reply: SSH2_AGENT_SIGN_RESPONSE"); plog(logctx, logfn, "reply: SSH2_AGENT_SIGN_RESPONSE");
} }
@ -788,7 +705,8 @@ void *pageant_handle_msg(const void *msg, int msglen, int *outlen,
*/ */
{ {
struct ssh2_userkey *key; struct ssh2_userkey *key;
struct blob b; const void *blobp;
int bloblen;
plog(logctx, logfn, "request: SSH2_AGENTC_REMOVE_IDENTITY"); plog(logctx, logfn, "request: SSH2_AGENTC_REMOVE_IDENTITY");
@ -796,23 +714,28 @@ void *pageant_handle_msg(const void *msg, int msglen, int *outlen,
fail_reason = "request truncated before public key"; fail_reason = "request truncated before public key";
goto failure; goto failure;
} }
b.len = toint(GET_32BIT(p)); bloblen = toint(GET_32BIT(p));
p += 4; p += 4;
if (b.len < 0 || b.len > msgend - p) { if (bloblen < 0 || bloblen > msgend - p) {
fail_reason = "request truncated before public key"; fail_reason = "request truncated before public key";
goto failure; goto failure;
} }
b.blob = p; blobp = p;
p += b.len; p += bloblen;
if (logfn) { if (logfn) {
char *fingerprint = ssh2_fingerprint_blob(b.blob, b.len); char *fingerprint = ssh2_fingerprint_blob(blobp, bloblen);
plog(logctx, logfn, "unwanted key: %s", fingerprint); plog(logctx, logfn, "unwanted key: %s", fingerprint);
sfree(fingerprint); sfree(fingerprint);
} }
key = find234(ssh2keys, &b, cmpkeys_ssh2_asymm); {
strbuf *blob = strbuf_new();
put_data(blob, blobp, bloblen);
key = find234(ssh2keys, blob, cmpkeys_ssh2_asymm);
strbuf_free(blob);
}
if (!key) { if (!key) {
fail_reason = "key not found"; fail_reason = "key not found";
goto failure; goto failure;
@ -1283,55 +1206,53 @@ int pageant_add_keyfile(Filename *filename, const char *passphrase,
* which may or may not be us). * which may or may not be us).
*/ */
{ {
void *blob; strbuf *blob = strbuf_new();
unsigned char *keylist, *p; unsigned char *keylist, *p;
int i, nkeys, bloblen, keylistlen; int i, nkeys, keylistlen;
if (type == SSH_KEYTYPE_SSH1) { if (type == SSH_KEYTYPE_SSH1) {
if (!rsa_ssh1_loadpub(filename, &blob, &bloblen, NULL, &error)) { if (!rsa_ssh1_loadpub(filename, BinarySink_UPCAST(blob), NULL, &error)) {
*retstr = dupprintf("Couldn't load private key (%s)", error); *retstr = dupprintf("Couldn't load private key (%s)", error);
strbuf_free(blob);
return PAGEANT_ACTION_FAILURE; return PAGEANT_ACTION_FAILURE;
} }
keylist = pageant_get_keylist1(&keylistlen); keylist = pageant_get_keylist1(&keylistlen);
} else { } else {
unsigned char *blob2; /* For our purposes we want the blob prefixed with its
blob = ssh2_userkey_loadpub(filename, NULL, &bloblen, * length, so add a placeholder here to fill in
NULL, &error); * afterwards */
if (!blob) { put_uint32(blob, 0);
if (!ssh2_userkey_loadpub(filename, NULL, BinarySink_UPCAST(blob),
NULL, &error)) {
*retstr = dupprintf("Couldn't load private key (%s)", error); *retstr = dupprintf("Couldn't load private key (%s)", error);
strbuf_free(blob);
return PAGEANT_ACTION_FAILURE; return PAGEANT_ACTION_FAILURE;
} }
/* For our purposes we want the blob prefixed with its length */ PUT_32BIT(blob->s, blob->len - 4);
blob2 = snewn(bloblen+4, unsigned char);
PUT_32BIT(blob2, bloblen);
memcpy(blob2 + 4, blob, bloblen);
sfree(blob);
blob = blob2;
keylist = pageant_get_keylist2(&keylistlen); keylist = pageant_get_keylist2(&keylistlen);
} }
if (keylist) { if (keylist) {
if (keylistlen < 4) { if (keylistlen < 4) {
*retstr = dupstr("Received broken key list from agent"); *retstr = dupstr("Received broken key list from agent");
sfree(keylist); sfree(keylist);
sfree(blob); strbuf_free(blob);
return PAGEANT_ACTION_FAILURE; return PAGEANT_ACTION_FAILURE;
} }
nkeys = toint(GET_32BIT(keylist)); nkeys = toint(GET_32BIT(keylist));
if (nkeys < 0) { if (nkeys < 0) {
*retstr = dupstr("Received broken key list from agent"); *retstr = dupstr("Received broken key list from agent");
sfree(keylist); sfree(keylist);
sfree(blob); strbuf_free(blob);
return PAGEANT_ACTION_FAILURE; return PAGEANT_ACTION_FAILURE;
} }
p = keylist + 4; p = keylist + 4;
keylistlen -= 4; keylistlen -= 4;
for (i = 0; i < nkeys; i++) { for (i = 0; i < nkeys; i++) {
if (!memcmp(blob, p, bloblen)) { if (!memcmp(blob->s, p, blob->len)) {
/* Key is already present; we can now leave. */ /* Key is already present; we can now leave. */
sfree(keylist); sfree(keylist);
sfree(blob); strbuf_free(blob);
return PAGEANT_ACTION_OK; return PAGEANT_ACTION_OK;
} }
/* Now skip over public blob */ /* Now skip over public blob */
@ -1340,7 +1261,7 @@ int pageant_add_keyfile(Filename *filename, const char *passphrase,
if (n < 0) { if (n < 0) {
*retstr = dupstr("Received broken key list from agent"); *retstr = dupstr("Received broken key list from agent");
sfree(keylist); sfree(keylist);
sfree(blob); strbuf_free(blob);
return PAGEANT_ACTION_FAILURE; return PAGEANT_ACTION_FAILURE;
} }
p += n; p += n;
@ -1350,7 +1271,7 @@ int pageant_add_keyfile(Filename *filename, const char *passphrase,
if (keylistlen < 4) { if (keylistlen < 4) {
*retstr = dupstr("Received broken key list from agent"); *retstr = dupstr("Received broken key list from agent");
sfree(keylist); sfree(keylist);
sfree(blob); strbuf_free(blob);
return PAGEANT_ACTION_FAILURE; return PAGEANT_ACTION_FAILURE;
} }
n = GET_32BIT(p); n = GET_32BIT(p);
@ -1360,7 +1281,7 @@ int pageant_add_keyfile(Filename *filename, const char *passphrase,
if (n < 0 || n > keylistlen) { if (n < 0 || n > keylistlen) {
*retstr = dupstr("Received broken key list from agent"); *retstr = dupstr("Received broken key list from agent");
sfree(keylist); sfree(keylist);
sfree(blob); strbuf_free(blob);
return PAGEANT_ACTION_FAILURE; return PAGEANT_ACTION_FAILURE;
} }
p += n; p += n;
@ -1372,7 +1293,7 @@ int pageant_add_keyfile(Filename *filename, const char *passphrase,
if (keylistlen < 4) { if (keylistlen < 4) {
*retstr = dupstr("Received broken key list from agent"); *retstr = dupstr("Received broken key list from agent");
sfree(keylist); sfree(keylist);
sfree(blob); strbuf_free(blob);
return PAGEANT_ACTION_FAILURE; return PAGEANT_ACTION_FAILURE;
} }
n = GET_32BIT(p); n = GET_32BIT(p);
@ -1382,7 +1303,7 @@ int pageant_add_keyfile(Filename *filename, const char *passphrase,
if (n < 0 || n > keylistlen) { if (n < 0 || n > keylistlen) {
*retstr = dupstr("Received broken key list from agent"); *retstr = dupstr("Received broken key list from agent");
sfree(keylist); sfree(keylist);
sfree(blob); strbuf_free(blob);
return PAGEANT_ACTION_FAILURE; return PAGEANT_ACTION_FAILURE;
} }
p += n; p += n;
@ -1393,7 +1314,7 @@ int pageant_add_keyfile(Filename *filename, const char *passphrase,
sfree(keylist); sfree(keylist);
} }
sfree(blob); strbuf_free(blob);
} }
error = NULL; error = NULL;
@ -1551,15 +1472,17 @@ int pageant_add_keyfile(Filename *filename, const char *passphrase,
if (!pageant_local) { if (!pageant_local) {
unsigned char *request, *response; unsigned char *request, *response;
void *vresponse; void *vresponse;
int reqlen, alglen, clen, keybloblen, resplen; strbuf *keyblob;
int reqlen, alglen, clen, resplen;
alglen = strlen(skey->alg->name); alglen = strlen(skey->alg->name);
clen = strlen(skey->comment); clen = strlen(skey->comment);
keybloblen = skey->alg->openssh_fmtkey(skey->data, NULL, 0); keyblob = strbuf_new();
skey->alg->openssh_fmtkey(skey->data, BinarySink_UPCAST(keyblob));
reqlen = 4 + 1 + /* length, message type */ reqlen = 4 + 1 + /* length, message type */
4 + alglen + /* algorithm name */ 4 + alglen + /* algorithm name */
keybloblen + /* key data */ keyblob->len + /* key data */
4 + clen /* comment */ 4 + clen /* comment */
; ;
@ -1571,9 +1494,8 @@ int pageant_add_keyfile(Filename *filename, const char *passphrase,
reqlen += 4; reqlen += 4;
memcpy(request + reqlen, skey->alg->name, alglen); memcpy(request + reqlen, skey->alg->name, alglen);
reqlen += alglen; reqlen += alglen;
reqlen += skey->alg->openssh_fmtkey(skey->data, memcpy(request + reqlen, keyblob->s, keyblob->len);
request + reqlen, reqlen += keyblob->len;
keybloblen);
PUT_32BIT(request + reqlen, clen); PUT_32BIT(request + reqlen, clen);
memcpy(request + reqlen + 4, skey->comment, clen); memcpy(request + reqlen + 4, skey->comment, clen);
reqlen += clen + 4; reqlen += clen + 4;
@ -1660,12 +1582,13 @@ int pageant_enum_keys(pageant_key_enum_fn_t callback, void *callback_ctx,
comment = dupprintf("%.*s", (int)n, (const char *)p); comment = dupprintf("%.*s", (int)n, (const char *)p);
p += n, keylistlen -= n; p += n, keylistlen -= n;
cbkey.blob = rsa_ssh1_public_blob(&rkey, &cbkey.bloblen, cbkey.blob = strbuf_new();
rsa_ssh1_public_blob(BinarySink_UPCAST(cbkey.blob), &rkey,
RSA_SSH1_EXPONENT_FIRST); RSA_SSH1_EXPONENT_FIRST);
cbkey.comment = comment; cbkey.comment = comment;
cbkey.ssh_version = 1; cbkey.ssh_version = 1;
callback(callback_ctx, fingerprint, comment, &cbkey); callback(callback_ctx, fingerprint, comment, &cbkey);
sfree(cbkey.blob); strbuf_free(cbkey.blob);
freersakey(&rkey); freersakey(&rkey);
sfree(comment); sfree(comment);
} }
@ -1710,8 +1633,8 @@ int pageant_enum_keys(pageant_key_enum_fn_t callback, void *callback_ctx,
return PAGEANT_ACTION_FAILURE; return PAGEANT_ACTION_FAILURE;
} }
fingerprint = ssh2_fingerprint_blob(p, n); fingerprint = ssh2_fingerprint_blob(p, n);
cbkey.blob = p; cbkey.blob = strbuf_new();
cbkey.bloblen = n; put_data(cbkey.blob, p, n);
p += n, keylistlen -= n; p += n, keylistlen -= n;
/* comment */ /* comment */
@ -1756,18 +1679,18 @@ int pageant_delete_key(struct pageant_pubkey *key, char **retstr)
void *vresponse; void *vresponse;
if (key->ssh_version == 1) { if (key->ssh_version == 1) {
reqlen = 5 + key->bloblen; reqlen = 5 + key->blob->len;
request = snewn(reqlen, unsigned char); request = snewn(reqlen, unsigned char);
PUT_32BIT(request, reqlen - 4); PUT_32BIT(request, reqlen - 4);
request[4] = SSH1_AGENTC_REMOVE_RSA_IDENTITY; request[4] = SSH1_AGENTC_REMOVE_RSA_IDENTITY;
memcpy(request + 5, key->blob, key->bloblen); memcpy(request + 5, key->blob->s, key->blob->len);
} else { } else {
reqlen = 9 + key->bloblen; reqlen = 9 + key->blob->len;
request = snewn(reqlen, unsigned char); request = snewn(reqlen, unsigned char);
PUT_32BIT(request, reqlen - 4); PUT_32BIT(request, reqlen - 4);
request[4] = SSH2_AGENTC_REMOVE_IDENTITY; request[4] = SSH2_AGENTC_REMOVE_IDENTITY;
PUT_32BIT(request + 5, key->bloblen); PUT_32BIT(request + 5, key->blob->len);
memcpy(request + 9, key->blob, key->bloblen); memcpy(request + 9, key->blob->s, key->blob->len);
} }
agent_query_synchronous(request, reqlen, &vresponse, &resplen); agent_query_synchronous(request, reqlen, &vresponse, &resplen);
@ -1821,9 +1744,8 @@ int pageant_delete_all_keys(char **retstr)
struct pageant_pubkey *pageant_pubkey_copy(struct pageant_pubkey *key) struct pageant_pubkey *pageant_pubkey_copy(struct pageant_pubkey *key)
{ {
struct pageant_pubkey *ret = snew(struct pageant_pubkey); struct pageant_pubkey *ret = snew(struct pageant_pubkey);
ret->blob = snewn(key->bloblen, unsigned char); ret->blob = strbuf_new();
memcpy(ret->blob, key->blob, key->bloblen); put_data(ret->blob, key->blob->s, key->blob->len);
ret->bloblen = key->bloblen;
ret->comment = key->comment ? dupstr(key->comment) : NULL; ret->comment = key->comment ? dupstr(key->comment) : NULL;
ret->ssh_version = key->ssh_version; ret->ssh_version = key->ssh_version;
return ret; return ret;
@ -1832,6 +1754,6 @@ struct pageant_pubkey *pageant_pubkey_copy(struct pageant_pubkey *key)
void pageant_pubkey_free(struct pageant_pubkey *key) void pageant_pubkey_free(struct pageant_pubkey *key)
{ {
sfree(key->comment); sfree(key->comment);
sfree(key->blob); strbuf_free(key->blob);
sfree(key); sfree(key);
} }

View File

@ -125,8 +125,7 @@ struct pageant_pubkey {
/* Everything needed to identify a public key found by /* Everything needed to identify a public key found by
* pageant_enum_keys and pass it back to the agent or other code * pageant_enum_keys and pass it back to the agent or other code
* later */ * later */
void *blob; strbuf *blob;
int bloblen;
char *comment; char *comment;
int ssh_version; int ssh_version;
}; };

150
ssh.c
View File

@ -4144,16 +4144,18 @@ int verify_ssh_manual_host_key(Ssh ssh, const char *fingerprint,
* Construct the base64-encoded public key blob and see if * Construct the base64-encoded public key blob and see if
* that's listed. * that's listed.
*/ */
unsigned char *binblob; strbuf *binblob;
char *base64blob; char *base64blob;
int binlen, atoms, i; int atoms, i;
binblob = ssh2keytype->public_blob(ssh2keydata, &binlen); binblob = strbuf_new();
atoms = (binlen + 2) / 3; ssh2keytype->public_blob(ssh2keydata, BinarySink_UPCAST(binblob));
atoms = (binblob->len + 2) / 3;
base64blob = snewn(atoms * 4 + 1, char); base64blob = snewn(atoms * 4 + 1, char);
for (i = 0; i < atoms; i++) for (i = 0; i < atoms; i++)
base64_encode_atom(binblob + 3*i, binlen - 3*i, base64blob + 4*i); base64_encode_atom(binblob->u + 3*i,
binblob->len - 3*i, base64blob + 4*i);
base64blob[atoms * 4] = '\0'; base64blob[atoms * 4] = '\0';
sfree(binblob); strbuf_free(binblob);
if (conf_get_str_str_opt(ssh->conf, CONF_ssh_manual_hostkeys, if (conf_get_str_str_opt(ssh->conf, CONF_ssh_manual_hostkeys,
base64blob)) { base64blob)) {
sfree(base64blob); sfree(base64blob);
@ -4191,8 +4193,7 @@ static void do_ssh1_login(void *vctx)
unsigned char cookie[8]; unsigned char cookie[8];
unsigned char session_id[16]; unsigned char session_id[16];
int cipher_type; int cipher_type;
void *publickey_blob; strbuf *publickey_blob;
int publickey_bloblen;
char *publickey_comment; char *publickey_comment;
int privatekey_available, privatekey_encrypted; int privatekey_available, privatekey_encrypted;
prompts_t *cur_prompt; prompts_t *cur_prompt;
@ -4529,8 +4530,9 @@ static void do_ssh1_login(void *vctx)
if (keytype == SSH_KEYTYPE_SSH1 || if (keytype == SSH_KEYTYPE_SSH1 ||
keytype == SSH_KEYTYPE_SSH1_PUBLIC) { keytype == SSH_KEYTYPE_SSH1_PUBLIC) {
const char *error; const char *error;
s->publickey_blob = strbuf_new();
if (rsa_ssh1_loadpub(s->keyfile, if (rsa_ssh1_loadpub(s->keyfile,
&s->publickey_blob, &s->publickey_bloblen, BinarySink_UPCAST(s->publickey_blob),
&s->publickey_comment, &error)) { &s->publickey_comment, &error)) {
s->privatekey_available = (keytype == SSH_KEYTYPE_SSH1); s->privatekey_available = (keytype == SSH_KEYTYPE_SSH1);
if (!s->privatekey_available) if (!s->privatekey_available)
@ -4545,6 +4547,7 @@ static void do_ssh1_login(void *vctx)
error); error);
c_write_str(ssh, msgbuf); c_write_str(ssh, msgbuf);
sfree(msgbuf); sfree(msgbuf);
strbuf_free(s->publickey_blob);
s->publickey_blob = NULL; s->publickey_blob = NULL;
} }
} else { } else {
@ -4634,8 +4637,8 @@ static void do_ssh1_login(void *vctx)
} }
} }
if (s->publickey_blob) { if (s->publickey_blob) {
if (!memcmp(pkblob, s->publickey_blob, if (!memcmp(pkblob, s->publickey_blob->s,
s->publickey_bloblen)) { s->publickey_blob->len)) {
logeventf(ssh, "Pageant key #%d matches " logeventf(ssh, "Pageant key #%d matches "
"configured key file", s->keyi); "configured key file", s->keyi);
s->tried_publickey = 1; s->tried_publickey = 1;
@ -5161,7 +5164,7 @@ static void do_ssh1_login(void *vctx)
/* Clear up */ /* Clear up */
if (s->publickey_blob) { if (s->publickey_blob) {
sfree(s->publickey_blob); strbuf_free(s->publickey_blob);
sfree(s->publickey_comment); sfree(s->publickey_comment);
} }
@ -6456,8 +6459,7 @@ static struct kexinit_algorithm *ssh2_kexinit_addalg(struct kexinit_algorithm
*/ */
struct ssh_transient_hostkey_cache_entry { struct ssh_transient_hostkey_cache_entry {
const struct ssh_signkey *alg; const struct ssh_signkey *alg;
unsigned char *pub_blob; strbuf *pub_blob;
int pub_len;
}; };
static int ssh_transient_hostkey_cache_cmp(void *av, void *bv) static int ssh_transient_hostkey_cache_cmp(void *av, void *bv)
@ -6486,7 +6488,7 @@ static void ssh_cleanup_transient_hostkey_store(Ssh ssh)
{ {
struct ssh_transient_hostkey_cache_entry *ent; struct ssh_transient_hostkey_cache_entry *ent;
while ((ent = delpos234(ssh->transient_hostkey_cache, 0)) != NULL) { while ((ent = delpos234(ssh->transient_hostkey_cache, 0)) != NULL) {
sfree(ent->pub_blob); strbuf_free(ent->pub_blob);
sfree(ent); sfree(ent);
} }
freetree234(ssh->transient_hostkey_cache); freetree234(ssh->transient_hostkey_cache);
@ -6499,13 +6501,14 @@ static void ssh_store_transient_hostkey(
if ((ent = find234(ssh->transient_hostkey_cache, (void *)alg, if ((ent = find234(ssh->transient_hostkey_cache, (void *)alg,
ssh_transient_hostkey_cache_find)) != NULL) { ssh_transient_hostkey_cache_find)) != NULL) {
sfree(ent->pub_blob); strbuf_free(ent->pub_blob);
sfree(ent); sfree(ent);
} }
ent = snew(struct ssh_transient_hostkey_cache_entry); ent = snew(struct ssh_transient_hostkey_cache_entry);
ent->alg = alg; ent->alg = alg;
ent->pub_blob = alg->public_blob(key, &ent->pub_len); ent->pub_blob = strbuf_new();
alg->public_blob(key, BinarySink_UPCAST(ent->pub_blob));
retd = add234(ssh->transient_hostkey_cache, ent); retd = add234(ssh->transient_hostkey_cache, ent);
assert(retd == ent); assert(retd == ent);
} }
@ -6518,14 +6521,15 @@ static int ssh_verify_transient_hostkey(
if ((ent = find234(ssh->transient_hostkey_cache, (void *)alg, if ((ent = find234(ssh->transient_hostkey_cache, (void *)alg,
ssh_transient_hostkey_cache_find)) != NULL) { ssh_transient_hostkey_cache_find)) != NULL) {
int this_len; strbuf *this_blob = strbuf_new();
unsigned char *this_blob = alg->public_blob(key, &this_len); alg->public_blob(key, BinarySink_UPCAST(this_blob));
if (this_len == ent->pub_len && if (this_blob->len == ent->pub_blob->len &&
!memcmp(this_blob, ent->pub_blob, this_len)) !memcmp(this_blob->s, ent->pub_blob->s,
this_blob->len))
toret = TRUE; toret = TRUE;
sfree(this_blob); strbuf_free(this_blob);
} }
return toret; return toret;
@ -7430,18 +7434,11 @@ static void do_ssh2_transport(void *vctx)
crStopV; crStopV;
} }
{
char *publicPoint;
int publicPointLength;
publicPoint = ssh_ecdhkex_getpublic(s->eckey, &publicPointLength);
if (!publicPoint) {
ssh_ecdhkex_freekey(s->eckey);
bombout(("Unable to encode public key for ECDH"));
crStopV;
}
s->pktout = ssh2_pkt_init(SSH2_MSG_KEX_ECDH_INIT); s->pktout = ssh2_pkt_init(SSH2_MSG_KEX_ECDH_INIT);
put_string(s->pktout, publicPoint, publicPointLength); {
sfree(publicPoint); strbuf *pubpoint = strbuf_new();
ssh_ecdhkex_getpublic(s->eckey, BinarySink_UPCAST(pubpoint));
put_stringsb(s->pktout, pubpoint);
} }
ssh2_pkt_send_noqueue(ssh, s->pktout); ssh2_pkt_send_noqueue(ssh, s->pktout);
@ -7463,17 +7460,11 @@ static void do_ssh2_transport(void *vctx)
s->hostkeydata, s->hostkeylen); s->hostkeydata, s->hostkeylen);
{ {
char *publicPoint; strbuf *pubpoint = strbuf_new();
int publicPointLength; ssh_ecdhkex_getpublic(s->eckey, BinarySink_UPCAST(pubpoint));
publicPoint = ssh_ecdhkex_getpublic(s->eckey, &publicPointLength);
if (!publicPoint) {
ssh_ecdhkex_freekey(s->eckey);
bombout(("Unable to encode public key for ECDH hash"));
crStopV;
}
hash_string(ssh->kex->hash, ssh->exhash, hash_string(ssh->kex->hash, ssh->exhash,
publicPoint, publicPointLength); pubpoint->u, pubpoint->len);
sfree(publicPoint); strbuf_free(pubpoint);
} }
{ {
@ -9955,8 +9946,7 @@ static void do_ssh2_userauth(void *vctx)
char *username; char *username;
char *password; char *password;
int got_username; int got_username;
void *publickey_blob; strbuf *publickey_blob;
int publickey_bloblen;
int privatekey_available, privatekey_encrypted; int privatekey_available, privatekey_encrypted;
char *publickey_algorithm; char *publickey_algorithm;
char *publickey_comment; char *publickey_comment;
@ -10053,12 +10043,11 @@ static void do_ssh2_userauth(void *vctx)
keytype == SSH_KEYTYPE_SSH2_PUBLIC_RFC4716 || keytype == SSH_KEYTYPE_SSH2_PUBLIC_RFC4716 ||
keytype == SSH_KEYTYPE_SSH2_PUBLIC_OPENSSH) { keytype == SSH_KEYTYPE_SSH2_PUBLIC_OPENSSH) {
const char *error; const char *error;
s->publickey_blob = s->publickey_blob = strbuf_new();
ssh2_userkey_loadpub(s->keyfile, if (ssh2_userkey_loadpub(s->keyfile,
&s->publickey_algorithm, &s->publickey_algorithm,
&s->publickey_bloblen, BinarySink_UPCAST(s->publickey_blob),
&s->publickey_comment, &error); &s->publickey_comment, &error)) {
if (s->publickey_blob) {
s->privatekey_available = (keytype == SSH_KEYTYPE_SSH2); s->privatekey_available = (keytype == SSH_KEYTYPE_SSH2);
if (!s->privatekey_available) if (!s->privatekey_available)
logeventf(ssh, "Key file contains public key only"); logeventf(ssh, "Key file contains public key only");
@ -10074,6 +10063,8 @@ static void do_ssh2_userauth(void *vctx)
error); error);
c_write_str(ssh, msgbuf); c_write_str(ssh, msgbuf);
sfree(msgbuf); sfree(msgbuf);
strbuf_free(s->publickey_blob);
s->publickey_blob = NULL;
} }
} else { } else {
char *msgbuf; char *msgbuf;
@ -10171,9 +10162,9 @@ static void do_ssh2_userauth(void *vctx)
/* See if configured key is in agent. */ /* See if configured key is in agent. */
for (keyi = 0; keyi < s->nkeys; keyi++) { for (keyi = 0; keyi < s->nkeys; keyi++) {
s->pklen = toint(GET_32BIT(p)); s->pklen = toint(GET_32BIT(p));
if (s->pklen == s->publickey_bloblen && if (s->pklen == s->publickey_blob->len &&
!memcmp(p+4, s->publickey_blob, !memcmp(p+4, s->publickey_blob->s,
s->publickey_bloblen)) { s->publickey_blob->len)) {
logeventf(ssh, "Pageant key #%d matches " logeventf(ssh, "Pageant key #%d matches "
"configured key file", keyi); "configured key file", keyi);
s->keyi = keyi; s->keyi = keyi;
@ -10626,7 +10617,8 @@ static void do_ssh2_userauth(void *vctx)
put_bool(s->pktout, FALSE); put_bool(s->pktout, FALSE);
/* no signature included */ /* no signature included */
put_stringz(s->pktout, s->publickey_algorithm); put_stringz(s->pktout, s->publickey_algorithm);
put_string(s->pktout, s->publickey_blob, s->publickey_bloblen); put_string(s->pktout, s->publickey_blob->s,
s->publickey_blob->len);
ssh2_pkt_send(ssh, s->pktout); ssh2_pkt_send(ssh, s->pktout);
logevent("Offered public key"); logevent("Offered public key");
@ -10720,9 +10712,7 @@ static void do_ssh2_userauth(void *vctx)
} }
if (key) { if (key) {
unsigned char *pkblob, *sigblob, *sigdata; strbuf *pkblob, *sigdata, *sigblob;
int pkblob_len, sigblob_len, sigdata_len;
int p;
/* /*
* We have loaded the private key and the server * We have loaded the private key and the server
@ -10736,9 +10726,9 @@ static void do_ssh2_userauth(void *vctx)
put_stringz(s->pktout, "publickey"); /* method */ put_stringz(s->pktout, "publickey"); /* method */
put_bool(s->pktout, TRUE); /* signature follows */ put_bool(s->pktout, TRUE); /* signature follows */
put_stringz(s->pktout, key->alg->name); put_stringz(s->pktout, key->alg->name);
pkblob = key->alg->public_blob(key->data, pkblob = strbuf_new();
&pkblob_len); key->alg->public_blob(key->data, BinarySink_UPCAST(pkblob));
put_string(s->pktout, pkblob, pkblob_len); put_string(s->pktout, pkblob->s, pkblob->len);
/* /*
* The data to be signed is: * The data to be signed is:
@ -10748,30 +10738,24 @@ static void do_ssh2_userauth(void *vctx)
* followed by everything so far placed in the * followed by everything so far placed in the
* outgoing packet. * outgoing packet.
*/ */
sigdata_len = s->pktout->length - 5 + 4 + sigdata = strbuf_new();
ssh->v2_session_id_len; if (ssh->remote_bugs & BUG_SSH2_PK_SESSIONID) {
if (ssh->remote_bugs & BUG_SSH2_PK_SESSIONID) put_data(sigdata, ssh->v2_session_id,
sigdata_len -= 4;
sigdata = snewn(sigdata_len, unsigned char);
p = 0;
if (!(ssh->remote_bugs & BUG_SSH2_PK_SESSIONID)) {
PUT_32BIT(sigdata+p, ssh->v2_session_id_len);
p += 4;
}
memcpy(sigdata+p, ssh->v2_session_id,
ssh->v2_session_id_len); ssh->v2_session_id_len);
p += ssh->v2_session_id_len; } else {
memcpy(sigdata+p, s->pktout->data + 5, put_string(sigdata, ssh->v2_session_id,
ssh->v2_session_id_len);
}
put_data(sigdata, s->pktout->data + 5,
s->pktout->length - 5); s->pktout->length - 5);
p += s->pktout->length - 5; sigblob = strbuf_new();
assert(p == sigdata_len); key->alg->sign(key->data, sigdata->s, sigdata->len,
sigblob = key->alg->sign(key->data, (char *)sigdata, BinarySink_UPCAST(sigblob));
sigdata_len, &sigblob_len); strbuf_free(sigdata);
ssh2_add_sigblob(ssh, s->pktout, pkblob, pkblob_len, ssh2_add_sigblob(ssh, s->pktout, pkblob->s, pkblob->len,
sigblob, sigblob_len); sigblob->s, sigblob->len);
sfree(pkblob); strbuf_free(pkblob);
sfree(sigblob); strbuf_free(sigblob);
sfree(sigdata);
ssh2_pkt_send(ssh, s->pktout); ssh2_pkt_send(ssh, s->pktout);
logevent("Sent public key signature"); logevent("Sent public key signature");
@ -11363,7 +11347,7 @@ static void do_ssh2_userauth(void *vctx)
/* Clear up various bits and pieces from authentication. */ /* Clear up various bits and pieces from authentication. */
if (s->publickey_blob) { if (s->publickey_blob) {
sfree(s->publickey_algorithm); sfree(s->publickey_algorithm);
sfree(s->publickey_blob); strbuf_free(s->publickey_blob);
sfree(s->publickey_comment); sfree(s->publickey_comment);
} }
if (s->agent_response) if (s->agent_response)

21
ssh.h
View File

@ -194,7 +194,7 @@ int rsastr_len(struct RSAKey *key);
void rsastr_fmt(char *str, struct RSAKey *key); void rsastr_fmt(char *str, struct RSAKey *key);
void rsa_fingerprint(char *str, int len, struct RSAKey *key); void rsa_fingerprint(char *str, int len, struct RSAKey *key);
int rsa_verify(struct RSAKey *key); int rsa_verify(struct RSAKey *key);
unsigned char *rsa_ssh1_public_blob(struct RSAKey *key, int *len, void rsa_ssh1_public_blob(BinarySink *bs, struct RSAKey *key,
RsaSsh1Order order); RsaSsh1Order order);
int rsa_public_blob_len(void *data, int maxlen); int rsa_public_blob_len(void *data, int maxlen);
void freersakey(struct RSAKey *key); void freersakey(struct RSAKey *key);
@ -228,7 +228,7 @@ struct ssh_kex;
const char *ssh_ecdhkex_curve_textname(const struct ssh_kex *kex); const char *ssh_ecdhkex_curve_textname(const struct ssh_kex *kex);
void *ssh_ecdhkex_newkey(const struct ssh_kex *kex); void *ssh_ecdhkex_newkey(const struct ssh_kex *kex);
void ssh_ecdhkex_freekey(void *key); void ssh_ecdhkex_freekey(void *key);
char *ssh_ecdhkex_getpublic(void *key, int *len); void ssh_ecdhkex_getpublic(void *key, BinarySink *bs);
Bignum ssh_ecdhkex_getkey(void *key, char *remoteKey, int remoteKeyLen); Bignum ssh_ecdhkex_getkey(void *key, char *remoteKey, int remoteKeyLen);
/* /*
@ -400,14 +400,14 @@ struct ssh_signkey {
const char *data, int len); const char *data, int len);
void (*freekey) (void *key); void (*freekey) (void *key);
char *(*fmtkey) (void *key); char *(*fmtkey) (void *key);
unsigned char *(*public_blob) (void *key, int *len); void (*public_blob)(void *key, BinarySink *);
unsigned char *(*private_blob) (void *key, int *len); void (*private_blob)(void *key, BinarySink *);
void *(*createkey) (const struct ssh_signkey *self, void *(*createkey) (const struct ssh_signkey *self,
const unsigned char *pub_blob, int pub_len, const unsigned char *pub_blob, int pub_len,
const unsigned char *priv_blob, int priv_len); const unsigned char *priv_blob, int priv_len);
void *(*openssh_createkey) (const struct ssh_signkey *self, void *(*openssh_createkey) (const struct ssh_signkey *self,
const unsigned char **blob, int *len); const unsigned char **blob, int *len);
int (*openssh_fmtkey) (void *key, unsigned char *blob, int len); void (*openssh_fmtkey) (void *key, BinarySink *);
/* OpenSSH private key blobs, as created by openssh_fmtkey and /* OpenSSH private key blobs, as created by openssh_fmtkey and
* consumed by openssh_createkey, always (at least so far...) take * consumed by openssh_createkey, always (at least so far...) take
* the form of a number of SSH-2 strings / mpints concatenated * the form of a number of SSH-2 strings / mpints concatenated
@ -421,8 +421,7 @@ struct ssh_signkey {
const void *blob, int len); const void *blob, int len);
int (*verifysig) (void *key, const char *sig, int siglen, int (*verifysig) (void *key, const char *sig, int siglen,
const char *data, int datalen); const char *data, int datalen);
unsigned char *(*sign) (void *key, const char *data, int datalen, void (*sign) (void *key, const char *data, int datalen, BinarySink *);
int *siglen);
const char *name; const char *name;
const char *keytype; /* for host key cache */ const char *keytype; /* for host key cache */
const void *extra; /* private to the public key methods */ const void *extra; /* private to the public key methods */
@ -719,7 +718,7 @@ const char *dh_validate_f(void *handle, Bignum f);
Bignum dh_find_K(void *, Bignum f); Bignum dh_find_K(void *, Bignum f);
int rsa_ssh1_encrypted(const Filename *filename, char **comment); int rsa_ssh1_encrypted(const Filename *filename, char **comment);
int rsa_ssh1_loadpub(const Filename *filename, void **blob, int *bloblen, int rsa_ssh1_loadpub(const Filename *filename, BinarySink *bs,
char **commentptr, const char **errorstr); char **commentptr, const char **errorstr);
int rsa_ssh1_loadkey(const Filename *filename, struct RSAKey *key, int rsa_ssh1_loadkey(const Filename *filename, struct RSAKey *key,
const char *passphrase, const char **errorstr); const char *passphrase, const char **errorstr);
@ -740,9 +739,9 @@ int ssh2_userkey_encrypted(const Filename *filename, char **comment);
struct ssh2_userkey *ssh2_load_userkey(const Filename *filename, struct ssh2_userkey *ssh2_load_userkey(const Filename *filename,
const char *passphrase, const char *passphrase,
const char **errorstr); const char **errorstr);
unsigned char *ssh2_userkey_loadpub(const Filename *filename, char **algorithm, int ssh2_userkey_loadpub(const Filename *filename, char **algorithm,
int *pub_blob_len, char **commentptr, BinarySink *bs,
const char **errorstr); char **commentptr, const char **errorstr);
int ssh2_save_userkey(const Filename *filename, struct ssh2_userkey *key, int ssh2_save_userkey(const Filename *filename, struct ssh2_userkey *key,
char *passphrase); char *passphrase);
const struct ssh_signkey *find_pubkey_alg(const char *name); const struct ssh_signkey *find_pubkey_alg(const char *name);

128
sshdss.c
View File

@ -271,72 +271,22 @@ static int dss_verifysig(void *key, const char *sig, int siglen,
return ret; return ret;
} }
static unsigned char *dss_public_blob(void *key, int *len) static void dss_public_blob(void *key, BinarySink *bs)
{ {
struct dss_key *dss = (struct dss_key *) key; struct dss_key *dss = (struct dss_key *) key;
int plen, qlen, glen, ylen, bloblen;
int i;
unsigned char *blob, *p;
plen = (bignum_bitcount(dss->p) + 8) / 8; put_stringz(bs, "ssh-dss");
qlen = (bignum_bitcount(dss->q) + 8) / 8; put_mp_ssh2(bs, dss->p);
glen = (bignum_bitcount(dss->g) + 8) / 8; put_mp_ssh2(bs, dss->q);
ylen = (bignum_bitcount(dss->y) + 8) / 8; put_mp_ssh2(bs, dss->g);
put_mp_ssh2(bs, dss->y);
/*
* string "ssh-dss", mpint p, mpint q, mpint g, mpint y. Total
* 27 + sum of lengths. (five length fields, 20+7=27).
*/
bloblen = 27 + plen + qlen + glen + ylen;
blob = snewn(bloblen, unsigned char);
p = blob;
PUT_32BIT(p, 7);
p += 4;
memcpy(p, "ssh-dss", 7);
p += 7;
PUT_32BIT(p, plen);
p += 4;
for (i = plen; i--;)
*p++ = bignum_byte(dss->p, i);
PUT_32BIT(p, qlen);
p += 4;
for (i = qlen; i--;)
*p++ = bignum_byte(dss->q, i);
PUT_32BIT(p, glen);
p += 4;
for (i = glen; i--;)
*p++ = bignum_byte(dss->g, i);
PUT_32BIT(p, ylen);
p += 4;
for (i = ylen; i--;)
*p++ = bignum_byte(dss->y, i);
assert(p == blob + bloblen);
*len = bloblen;
return blob;
} }
static unsigned char *dss_private_blob(void *key, int *len) static void dss_private_blob(void *key, BinarySink *bs)
{ {
struct dss_key *dss = (struct dss_key *) key; struct dss_key *dss = (struct dss_key *) key;
int xlen, bloblen;
int i;
unsigned char *blob, *p;
xlen = (bignum_bitcount(dss->x) + 8) / 8; put_mp_ssh2(bs, dss->x);
/*
* mpint x, string[20] the SHA of p||q||g. Total 4 + xlen.
*/
bloblen = 4 + xlen;
blob = snewn(bloblen, unsigned char);
p = blob;
PUT_32BIT(p, xlen);
p += 4;
for (i = xlen; i--;)
*p++ = bignum_byte(dss->x, i);
assert(p == blob + bloblen);
*len = bloblen;
return blob;
} }
static void *dss_createkey(const struct ssh_signkey *self, static void *dss_createkey(const struct ssh_signkey *self,
@ -415,32 +365,15 @@ static void *dss_openssh_createkey(const struct ssh_signkey *self,
return dss; return dss;
} }
static int dss_openssh_fmtkey(void *key, unsigned char *blob, int len) static void dss_openssh_fmtkey(void *key, BinarySink *bs)
{ {
struct dss_key *dss = (struct dss_key *) key; struct dss_key *dss = (struct dss_key *) key;
int bloblen, i;
bloblen = put_mp_ssh2(bs, dss->p);
ssh2_bignum_length(dss->p) + put_mp_ssh2(bs, dss->q);
ssh2_bignum_length(dss->q) + put_mp_ssh2(bs, dss->g);
ssh2_bignum_length(dss->g) + put_mp_ssh2(bs, dss->y);
ssh2_bignum_length(dss->y) + put_mp_ssh2(bs, dss->x);
ssh2_bignum_length(dss->x);
if (bloblen > len)
return bloblen;
bloblen = 0;
#define ENC(x) \
PUT_32BIT(blob+bloblen, ssh2_bignum_length((x))-4); bloblen += 4; \
for (i = ssh2_bignum_length((x))-4; i-- ;) blob[bloblen++]=bignum_byte((x),i);
ENC(dss->p);
ENC(dss->q);
ENC(dss->g);
ENC(dss->y);
ENC(dss->x);
return bloblen;
} }
static int dss_pubkey_bits(const struct ssh_signkey *self, static int dss_pubkey_bits(const struct ssh_signkey *self,
@ -578,14 +511,13 @@ Bignum *dss_gen_k(const char *id_string, Bignum modulus, Bignum private_key,
} }
} }
static unsigned char *dss_sign(void *key, const char *data, int datalen, static void dss_sign(void *key, const char *data, int datalen,
int *siglen) BinarySink *bs)
{ {
struct dss_key *dss = (struct dss_key *) key; struct dss_key *dss = (struct dss_key *) key;
Bignum k, gkp, hash, kinv, hxr, r, s; Bignum k, gkp, hash, kinv, hxr, r, s;
unsigned char digest[20]; unsigned char digest[20];
unsigned char *bytes; int i;
int nbytes, i;
SHA_Simple(data, datalen, digest); SHA_Simple(data, datalen, digest);
@ -609,28 +541,14 @@ static unsigned char *dss_sign(void *key, const char *data, int datalen,
freebn(k); freebn(k);
freebn(hash); freebn(hash);
/* put_stringz(bs, "ssh-dss");
* Signature blob is put_uint32(bs, 40);
* for (i = 0; i < 20; i++)
* string "ssh-dss" put_byte(bs, bignum_byte(r, 19 - i));
* string two 20-byte numbers r and s, end to end for (i = 0; i < 20; i++)
* put_byte(bs, bignum_byte(s, 19 - i));
* i.e. 4+7 + 4+40 bytes.
*/
nbytes = 4 + 7 + 4 + 40;
bytes = snewn(nbytes, unsigned char);
PUT_32BIT(bytes, 7);
memcpy(bytes + 4, "ssh-dss", 7);
PUT_32BIT(bytes + 4 + 7, 40);
for (i = 0; i < 20; i++) {
bytes[4 + 7 + 4 + i] = bignum_byte(r, 19 - i);
bytes[4 + 7 + 4 + 20 + i] = bignum_byte(s, 19 - i);
}
freebn(r); freebn(r);
freebn(s); freebn(s);
*siglen = nbytes;
return bytes;
} }
const struct ssh_signkey ssh_dss = { const struct ssh_signkey ssh_dss = {

294
sshecc.c
View File

@ -1837,89 +1837,53 @@ static char *ecdsa_fmtkey(void *key)
return p; return p;
} }
static unsigned char *ecdsa_public_blob(void *key, int *len) static void ecdsa_public_blob(void *key, BinarySink *bs)
{ {
struct ec_key *ec = (struct ec_key *) key; struct ec_key *ec = (struct ec_key *) key;
int pointlen, bloblen, fullnamelen, namelen; int pointlen;
int i; int i;
unsigned char *blob, *p;
fullnamelen = strlen(ec->signalg->name);
if (ec->publicKey.curve->type == EC_EDWARDS) { if (ec->publicKey.curve->type == EC_EDWARDS) {
/* Edwards compressed form "ssh-ed25519" point y[:-1] + x[0:1] */ /* Edwards compressed form "ssh-ed25519" point y[:-1] + x[0:1] */
pointlen = ec->publicKey.curve->fieldBits / 8; pointlen = ec->publicKey.curve->fieldBits / 8;
/* Can't handle this in our loop */ assert(pointlen >= 2);
if (pointlen < 2) return NULL;
bloblen = 4 + fullnamelen + 4 + pointlen; put_stringz(bs, ec->signalg->name);
blob = snewn(bloblen, unsigned char); put_uint32(bs, pointlen);
p = blob;
PUT_32BIT(p, fullnamelen);
p += 4;
memcpy(p, ec->signalg->name, fullnamelen);
p += fullnamelen;
PUT_32BIT(p, pointlen);
p += 4;
/* Unset last bit of y and set first bit of x in its place */ /* Unset last bit of y and set first bit of x in its place */
for (i = 0; i < pointlen - 1; ++i) { for (i = 0; i < pointlen - 1; ++i)
*p++ = bignum_byte(ec->publicKey.y, i); put_byte(bs, bignum_byte(ec->publicKey.y, i));
}
/* Unset last bit of y and set first bit of x in its place */ /* Unset last bit of y and set first bit of x in its place */
*p = bignum_byte(ec->publicKey.y, i) & 0x7f; put_byte(bs, ((bignum_byte(ec->publicKey.y, i) & 0x7f) |
*p++ |= bignum_bit(ec->publicKey.x, 0) << 7; (bignum_bit(ec->publicKey.x, 0) << 7)));
} else if (ec->publicKey.curve->type == EC_WEIERSTRASS) { } else if (ec->publicKey.curve->type == EC_WEIERSTRASS) {
assert(ec->publicKey.curve->name); assert(ec->publicKey.curve->name);
namelen = strlen(ec->publicKey.curve->name);
pointlen = (bignum_bitcount(ec->publicKey.curve->p) + 7) / 8; pointlen = (bignum_bitcount(ec->publicKey.curve->p) + 7) / 8;
/* put_stringz(bs, ec->signalg->name);
* string "ecdsa-sha2-<name>", string "<name>", 0x04 point x, y. put_stringz(bs, ec->publicKey.curve->name);
*/ put_uint32(bs, (2 * pointlen) + 1);
bloblen = 4 + fullnamelen + 4 + namelen + 4 + 1 + (pointlen * 2); put_byte(bs, 0x04);
blob = snewn(bloblen, unsigned char); for (i = pointlen; i--;)
put_byte(bs, bignum_byte(ec->publicKey.x, i));
p = blob; for (i = pointlen; i--;)
PUT_32BIT(p, fullnamelen); put_byte(bs, bignum_byte(ec->publicKey.y, i));
p += 4;
memcpy(p, ec->signalg->name, fullnamelen);
p += fullnamelen;
PUT_32BIT(p, namelen);
p += 4;
memcpy(p, ec->publicKey.curve->name, namelen);
p += namelen;
PUT_32BIT(p, (2 * pointlen) + 1);
p += 4;
*p++ = 0x04;
for (i = pointlen; i--;) {
*p++ = bignum_byte(ec->publicKey.x, i);
}
for (i = pointlen; i--;) {
*p++ = bignum_byte(ec->publicKey.y, i);
}
} else { } else {
return NULL; assert(0 && "Bad key type in ecdsa_public_blob");
} }
assert(p == blob + bloblen);
*len = bloblen;
return blob;
} }
static unsigned char *ecdsa_private_blob(void *key, int *len) static void ecdsa_private_blob(void *key, BinarySink *bs)
{ {
struct ec_key *ec = (struct ec_key *) key; struct ec_key *ec = (struct ec_key *) key;
int keylen, bloblen; int keylen;
int i; int i;
unsigned char *blob, *p;
if (!ec->privateKey) return NULL; assert(ec->privateKey);
if (ec->publicKey.curve->type == EC_EDWARDS) { if (ec->publicKey.curve->type == EC_EDWARDS) {
/* Unsigned */ /* Unsigned */
@ -1929,27 +1893,15 @@ static unsigned char *ecdsa_private_blob(void *key, int *len)
keylen = (bignum_bitcount(ec->privateKey) + 8) / 8; keylen = (bignum_bitcount(ec->privateKey) + 8) / 8;
} }
/* put_uint32(bs, keylen);
* mpint privateKey. Total 4 + keylen.
*/
bloblen = 4 + keylen;
blob = snewn(bloblen, unsigned char);
p = blob;
PUT_32BIT(p, keylen);
p += 4;
if (ec->publicKey.curve->type == EC_EDWARDS) { if (ec->publicKey.curve->type == EC_EDWARDS) {
/* Little endian */ /* Little endian */
for (i = 0; i < keylen; ++i) for (i = 0; i < keylen; ++i)
*p++ = bignum_byte(ec->privateKey, i); put_byte(bs, bignum_byte(ec->privateKey, i));
} else { } else {
for (i = keylen; i--;) for (i = keylen; i--;)
*p++ = bignum_byte(ec->privateKey, i); put_byte(bs, bignum_byte(ec->privateKey, i));
} }
assert(p == blob + bloblen);
*len = bloblen;
return blob;
} }
static void *ecdsa_createkey(const struct ssh_signkey *self, static void *ecdsa_createkey(const struct ssh_signkey *self,
@ -2060,53 +2012,40 @@ static void *ed25519_openssh_createkey(const struct ssh_signkey *self,
return ec; return ec;
} }
static int ed25519_openssh_fmtkey(void *key, unsigned char *blob, int len) static void ed25519_openssh_fmtkey(void *key, BinarySink *bs)
{ {
struct ec_key *ec = (struct ec_key *) key; struct ec_key *ec = (struct ec_key *) key;
strbuf *pub;
int pointlen; int pointlen;
int keylen; int keylen;
int bloblen;
int i; int i;
if (ec->publicKey.curve->type != EC_EDWARDS) { assert(ec->publicKey.curve->type == EC_EDWARDS);
return 0;
}
pointlen = (bignum_bitcount(ec->publicKey.y) + 7) / 8; pointlen = (bignum_bitcount(ec->publicKey.y) + 7) / 8;
keylen = (bignum_bitcount(ec->privateKey) + 7) / 8; keylen = (bignum_bitcount(ec->privateKey) + 7) / 8;
bloblen = 4 + pointlen + 4 + keylen + pointlen;
if (bloblen > len)
return bloblen;
/* Encode the public point */ /* Encode the public point */
PUT_32BIT(blob, pointlen); pub = strbuf_new();
blob += 4; put_uint32(pub, pointlen);
for (i = 0; i < pointlen - 1; ++i)
for (i = 0; i < pointlen - 1; ++i) { put_byte(pub, bignum_byte(ec->publicKey.y, i));
*blob++ = bignum_byte(ec->publicKey.y, i);
}
/* Unset last bit of y and set first bit of x in its place */ /* Unset last bit of y and set first bit of x in its place */
*blob = bignum_byte(ec->publicKey.y, i) & 0x7f; put_byte(pub, ((bignum_byte(ec->publicKey.y, i) & 0x7f) |
*blob++ |= bignum_bit(ec->publicKey.x, 0) << 7; (bignum_bit(ec->publicKey.x, 0) << 7)));
PUT_32BIT(blob, keylen + pointlen); put_data(bs, pub->s, pub->len);
blob += 4;
for (i = 0; i < keylen; ++i) { put_uint32(bs, keylen + pointlen);
*blob++ = bignum_byte(ec->privateKey, i); for (i = 0; i < keylen; ++i)
} put_byte(bs, bignum_byte(ec->privateKey, i));
/* Now encode an extra copy of the public point as the second half /* Now encode an extra copy of the public point as the second half
* of the private key string, as the OpenSSH format for some * of the private key string, as the OpenSSH format for some
* reason requires */ * reason requires */
for (i = 0; i < pointlen - 1; ++i) { put_data(bs, pub->s + 4, pub->len - 4);
*blob++ = bignum_byte(ec->publicKey.y, i);
}
/* Unset last bit of y and set first bit of x in its place */
*blob = bignum_byte(ec->publicKey.y, i) & 0x7f;
*blob++ |= bignum_bit(ec->publicKey.x, 0) << 7;
return bloblen; strbuf_free(pub);
} }
static void *ecdsa_openssh_createkey(const struct ssh_signkey *self, static void *ecdsa_openssh_createkey(const struct ssh_signkey *self,
@ -2180,51 +2119,27 @@ static void *ecdsa_openssh_createkey(const struct ssh_signkey *self,
return ec; return ec;
} }
static int ecdsa_openssh_fmtkey(void *key, unsigned char *blob, int len) static void ecdsa_openssh_fmtkey(void *key, BinarySink *bs)
{ {
struct ec_key *ec = (struct ec_key *) key; struct ec_key *ec = (struct ec_key *) key;
int pointlen; int pointlen;
int namelen;
int bloblen;
int i; int i;
if (ec->publicKey.curve->type != EC_WEIERSTRASS) { assert(ec->publicKey.curve->type == EC_WEIERSTRASS);
return 0;
}
pointlen = (bignum_bitcount(ec->publicKey.curve->p) + 7) / 8; pointlen = (bignum_bitcount(ec->publicKey.curve->p) + 7) / 8;
namelen = strlen(ec->publicKey.curve->name);
bloblen =
4 + namelen /* <LEN> nistpXXX */
+ 4 + 1 + (pointlen * 2) /* <LEN> 0x04 pX pY */
+ ssh2_bignum_length(ec->privateKey);
if (bloblen > len) put_stringz(bs, ec->publicKey.curve->name);
return bloblen;
bloblen = 0; put_uint32(bs, 1 + (pointlen * 2));
put_byte(bs, 0x04);
PUT_32BIT(blob+bloblen, namelen);
bloblen += 4;
memcpy(blob+bloblen, ec->publicKey.curve->name, namelen);
bloblen += namelen;
PUT_32BIT(blob+bloblen, 1 + (pointlen * 2));
bloblen += 4;
blob[bloblen++] = 0x04;
for (i = pointlen; i--; ) for (i = pointlen; i--; )
blob[bloblen++] = bignum_byte(ec->publicKey.x, i); put_byte(bs, bignum_byte(ec->publicKey.x, i));
for (i = pointlen; i--; ) for (i = pointlen; i--; )
blob[bloblen++] = bignum_byte(ec->publicKey.y, i); put_byte(bs, bignum_byte(ec->publicKey.y, i));
pointlen = (bignum_bitcount(ec->privateKey) + 8) / 8; put_mp_ssh2(bs, ec->privateKey);
PUT_32BIT(blob+bloblen, pointlen);
bloblen += 4;
for (i = pointlen; i--; )
blob[bloblen++] = bignum_byte(ec->privateKey, i);
return bloblen;
} }
static int ecdsa_pubkey_bits(const struct ssh_signkey *self, static int ecdsa_pubkey_bits(const struct ssh_signkey *self,
@ -2392,8 +2307,8 @@ static int ecdsa_verifysig(void *key, const char *sig, int siglen,
return ret; return ret;
} }
static unsigned char *ecdsa_sign(void *key, const char *data, int datalen, static void ecdsa_sign(void *key, const char *data, int datalen,
int *siglen) BinarySink *bs)
{ {
struct ec_key *ec = (struct ec_key *) key; struct ec_key *ec = (struct ec_key *) key;
const struct ecsign_extra *extra = const struct ecsign_extra *extra =
@ -2401,13 +2316,10 @@ static unsigned char *ecdsa_sign(void *key, const char *data, int datalen,
unsigned char digest[512 / 8]; unsigned char digest[512 / 8];
int digestLen; int digestLen;
Bignum r = NULL, s = NULL; Bignum r = NULL, s = NULL;
unsigned char *buf, *p;
int rlen, slen, namelen;
int i; int i;
if (!ec->privateKey || !ec->publicKey.curve) { assert(ec->privateKey);
return NULL; assert(ec->publicKey.curve);
}
if (ec->publicKey.curve->type == EC_EDWARDS) { if (ec->publicKey.curve->type == EC_EDWARDS) {
struct ec_point *rp; struct ec_point *rp;
@ -2448,11 +2360,7 @@ static unsigned char *ecdsa_sign(void *key, const char *data, int datalen,
r = bignum_from_bytes_le(hash, 512/8); r = bignum_from_bytes_le(hash, 512/8);
rp = ecp_mul(&ec->publicKey.curve->e.B, r); rp = ecp_mul(&ec->publicKey.curve->e.B, r);
if (!rp) { assert(rp);
freebn(r);
freebn(a);
return NULL;
}
/* Now calculate s */ /* Now calculate s */
SHA512_Init(&hs); SHA512_Init(&hs);
@ -2490,34 +2398,25 @@ static unsigned char *ecdsa_sign(void *key, const char *data, int datalen,
} }
/* Format the output */ /* Format the output */
namelen = strlen(ec->signalg->name); put_stringz(bs, ec->signalg->name);
*siglen = 4+namelen+4+((ec->publicKey.curve->fieldBits / 8)*2); pointlen = ec->publicKey.curve->fieldBits / 8;
buf = snewn(*siglen, unsigned char); put_uint32(bs, pointlen * 2);
p = buf;
PUT_32BIT(p, namelen);
p += 4;
memcpy(p, ec->signalg->name, namelen);
p += namelen;
PUT_32BIT(p, ((ec->publicKey.curve->fieldBits / 8)*2));
p += 4;
/* Encode the point */ /* Encode the point */
pointlen = ec->publicKey.curve->fieldBits / 8; for (i = 0; i < pointlen - 1; ++i)
for (i = 0; i < pointlen - 1; ++i) { put_byte(bs, bignum_byte(rp->y, i));
*p++ = bignum_byte(rp->y, i);
}
/* Unset last bit of y and set first bit of x in its place */ /* Unset last bit of y and set first bit of x in its place */
*p = bignum_byte(rp->y, i) & 0x7f; put_byte(bs, ((bignum_byte(rp->y, i) & 0x7f) |
*p++ |= bignum_bit(rp->x, 0) << 7; (bignum_bit(rp->x, 0) << 7)));
ec_point_free(rp); ec_point_free(rp);
/* Encode the int */ /* Encode the int */
for (i = 0; i < pointlen; ++i) { for (i = 0; i < pointlen; ++i)
*p++ = bignum_byte(s, i); put_byte(bs, bignum_byte(s, i));
}
freebn(s); freebn(s);
} else { } else {
void *hashctx; void *hashctx;
strbuf *substr;
digestLen = extra->hash->hlen; digestLen = extra->hash->hlen;
assert(digestLen <= sizeof(digest)); assert(digestLen <= sizeof(digest));
@ -2527,41 +2426,20 @@ static unsigned char *ecdsa_sign(void *key, const char *data, int datalen,
/* Do the signature */ /* Do the signature */
_ecdsa_sign(ec->privateKey, ec->publicKey.curve, digest, digestLen, &r, &s); _ecdsa_sign(ec->privateKey, ec->publicKey.curve, digest, digestLen, &r, &s);
if (!r || !s) { assert(r);
if (r) freebn(r); assert(s);
if (s) freebn(s);
return NULL;
}
rlen = (bignum_bitcount(r) + 8) / 8;
slen = (bignum_bitcount(s) + 8) / 8;
namelen = strlen(ec->signalg->name);
/* Format the output */ /* Format the output */
*siglen = 8+namelen+rlen+slen+8; put_stringz(bs, ec->signalg->name);
buf = snewn(*siglen, unsigned char);
p = buf; substr = strbuf_new();
PUT_32BIT(p, namelen); put_mp_ssh2(substr, r);
p += 4; put_mp_ssh2(substr, s);
memcpy(p, ec->signalg->name, namelen); put_stringsb(bs, substr);
p += namelen;
PUT_32BIT(p, rlen + slen + 8);
p += 4;
PUT_32BIT(p, rlen);
p += 4;
for (i = rlen; i--;)
*p++ = bignum_byte(r, i);
PUT_32BIT(p, slen);
p += 4;
for (i = slen; i--;)
*p++ = bignum_byte(s, i);
freebn(r); freebn(r);
freebn(s); freebn(s);
} }
return buf;
} }
const struct ecsign_extra sign_extra_ed25519 = { const struct ecsign_extra sign_extra_ed25519 = {
@ -2782,38 +2660,24 @@ void *ssh_ecdhkex_newkey(const struct ssh_kex *kex)
return key; return key;
} }
char *ssh_ecdhkex_getpublic(void *key, int *len) void ssh_ecdhkex_getpublic(void *key, BinarySink *bs)
{ {
struct ec_key *ec = (struct ec_key*)key; struct ec_key *ec = (struct ec_key*)key;
char *point, *p;
int i; int i;
int pointlen; int pointlen;
pointlen = (bignum_bitcount(ec->publicKey.curve->p) + 7) / 8; pointlen = (bignum_bitcount(ec->publicKey.curve->p) + 7) / 8;
if (ec->publicKey.curve->type == EC_WEIERSTRASS) { if (ec->publicKey.curve->type == EC_WEIERSTRASS) {
*len = 1 + pointlen * 2; put_byte(bs, 0x04);
for (i = pointlen; i--;)
put_byte(bs, bignum_byte(ec->publicKey.x, i));
for (i = pointlen; i--;)
put_byte(bs, bignum_byte(ec->publicKey.y, i));
} else { } else {
*len = pointlen; for (i = 0; i < pointlen; ++i)
put_byte(bs, bignum_byte(ec->publicKey.x, i));
} }
point = (char*)snewn(*len, char);
p = point;
if (ec->publicKey.curve->type == EC_WEIERSTRASS) {
*p++ = 0x04;
for (i = pointlen; i--;) {
*p++ = bignum_byte(ec->publicKey.x, i);
}
for (i = pointlen; i--;) {
*p++ = bignum_byte(ec->publicKey.y, i);
}
} else {
for (i = 0; i < pointlen; ++i) {
*p++ = bignum_byte(ec->publicKey.x, i);
}
}
return point;
} }
Bignum ssh_ecdhkex_getkey(void *key, char *remoteKey, int remoteKeyLen) Bignum ssh_ecdhkex_getkey(void *key, char *remoteKey, int remoteKeyLen)

204
sshpubk.c
View File

@ -226,11 +226,10 @@ int rsa_ssh1_encrypted(const Filename *filename, char **comment)
} }
/* /*
* Return a malloc'ed chunk of memory containing the public blob of * Read the public part of an SSH-1 RSA key from a file (public or
* an RSA key, as given in the agent protocol (modulus bits, * private), and generate its public blob in exponent-first order.
* exponent, modulus).
*/ */
int rsa_ssh1_loadpub(const Filename *filename, void **blob, int *bloblen, int rsa_ssh1_loadpub(const Filename *filename, BinarySink *bs,
char **commentptr, const char **errorstr) char **commentptr, const char **errorstr)
{ {
FILE *fp; FILE *fp;
@ -240,9 +239,7 @@ int rsa_ssh1_loadpub(const Filename *filename, void **blob, int *bloblen,
const char *error = NULL; const char *error = NULL;
/* Default return if we fail. */ /* Default return if we fail. */
*blob = NULL; ret = FALSE;
*bloblen = 0;
ret = 0;
fp = f_open(filename, "rb", FALSE); fp = f_open(filename, "rb", FALSE);
if (!fp) { if (!fp) {
@ -257,10 +254,9 @@ int rsa_ssh1_loadpub(const Filename *filename, void **blob, int *bloblen,
if (fgets(buf, sizeof(buf), fp) && !strcmp(buf, rsa_signature)) { if (fgets(buf, sizeof(buf), fp) && !strcmp(buf, rsa_signature)) {
memset(&key, 0, sizeof(key)); memset(&key, 0, sizeof(key));
if (rsa_ssh1_load_main(fp, &key, TRUE, commentptr, NULL, &error)) { if (rsa_ssh1_load_main(fp, &key, TRUE, commentptr, NULL, &error)) {
*blob = rsa_ssh1_public_blob(&key, bloblen, rsa_ssh1_public_blob(bs, &key, RSA_SSH1_EXPONENT_FIRST);
RSA_SSH1_EXPONENT_FIRST);
freersakey(&key); freersakey(&key);
ret = 1; ret = TRUE;
} }
fp = NULL; /* rsa_ssh1_load_main unconditionally closes fp */ fp = NULL; /* rsa_ssh1_load_main unconditionally closes fp */
} else { } else {
@ -308,11 +304,11 @@ int rsa_ssh1_loadpub(const Filename *filename, void **blob, int *bloblen,
} }
if (commentptr) if (commentptr)
*commentptr = commentp ? dupstr(commentp) : NULL; *commentptr = commentp ? dupstr(commentp) : NULL;
*blob = rsa_ssh1_public_blob(&key, bloblen, RSA_SSH1_EXPONENT_FIRST); rsa_ssh1_public_blob(bs, &key, RSA_SSH1_EXPONENT_FIRST);
freersakey(&key); freersakey(&key);
sfree(line); sfree(line);
fclose(fp); fclose(fp);
return 1; return TRUE;
not_public_either: not_public_either:
sfree(line); sfree(line);
@ -569,41 +565,40 @@ static char *read_body(FILE * fp)
} }
} }
static unsigned char *read_blob(FILE * fp, int nlines, int *bloblen) static int read_blob(FILE *fp, int nlines, BinarySink *bs)
{ {
unsigned char *blob; unsigned char *blob;
char *line; char *line;
int linelen, len; int linelen;
int i, j, k; int i, j, k;
/* We expect at most 64 base64 characters, ie 48 real bytes, per line. */ /* We expect at most 64 base64 characters, ie 48 real bytes, per line. */
blob = snewn(48 * nlines, unsigned char); blob = snewn(48 * nlines, unsigned char);
len = 0;
for (i = 0; i < nlines; i++) { for (i = 0; i < nlines; i++) {
line = read_body(fp); line = read_body(fp);
if (!line) { if (!line) {
sfree(blob); sfree(blob);
return NULL; return FALSE;
} }
linelen = strlen(line); linelen = strlen(line);
if (linelen % 4 != 0 || linelen > 64) { if (linelen % 4 != 0 || linelen > 64) {
sfree(blob); sfree(blob);
sfree(line); sfree(line);
return NULL; return FALSE;
} }
for (j = 0; j < linelen; j += 4) { for (j = 0; j < linelen; j += 4) {
k = base64_decode_atom(line + j, blob + len); unsigned char decoded[3];
k = base64_decode_atom(line + j, decoded);
if (!k) { if (!k) {
sfree(line); sfree(line);
sfree(blob); sfree(blob);
return NULL; return FALSE;
} }
len += k; put_data(bs, decoded, k);
} }
sfree(line); sfree(line);
} }
*bloblen = len; return TRUE;
return blob;
} }
/* /*
@ -645,8 +640,7 @@ struct ssh2_userkey *ssh2_load_userkey(const Filename *filename,
const struct ssh_signkey *alg; const struct ssh_signkey *alg;
struct ssh2_userkey *ret; struct ssh2_userkey *ret;
int cipher, cipherblk; int cipher, cipherblk;
unsigned char *public_blob, *private_blob; strbuf *public_blob, *private_blob;
int public_blob_len, private_blob_len;
int i, is_mac, old_fmt; int i, is_mac, old_fmt;
int passlen = passphrase ? strlen(passphrase) : 0; int passlen = passphrase ? strlen(passphrase) : 0;
const char *error = NULL; const char *error = NULL;
@ -718,7 +712,8 @@ struct ssh2_userkey *ssh2_load_userkey(const Filename *filename,
goto error; goto error;
i = atoi(b); i = atoi(b);
sfree(b); sfree(b);
if ((public_blob = read_blob(fp, i, &public_blob_len)) == NULL) public_blob = strbuf_new();
if (!read_blob(fp, i, BinarySink_UPCAST(public_blob)))
goto error; goto error;
/* Read the Private-Lines header line and the Private blob. */ /* Read the Private-Lines header line and the Private blob. */
@ -728,7 +723,8 @@ struct ssh2_userkey *ssh2_load_userkey(const Filename *filename,
goto error; goto error;
i = atoi(b); i = atoi(b);
sfree(b); sfree(b);
if ((private_blob = read_blob(fp, i, &private_blob_len)) == NULL) private_blob = strbuf_new();
if (!read_blob(fp, i, BinarySink_UPCAST(private_blob)))
goto error; goto error;
/* Read the Private-MAC or Private-Hash header line. */ /* Read the Private-MAC or Private-Hash header line. */
@ -757,7 +753,7 @@ struct ssh2_userkey *ssh2_load_userkey(const Filename *filename,
if (!passphrase) if (!passphrase)
goto error; goto error;
if (private_blob_len % cipherblk) if (private_blob->len % cipherblk)
goto error; goto error;
SHA_Init(&s); SHA_Init(&s);
@ -768,7 +764,7 @@ struct ssh2_userkey *ssh2_load_userkey(const Filename *filename,
put_uint32(&s, 1); put_uint32(&s, 1);
put_data(&s, passphrase, passlen); put_data(&s, passphrase, passlen);
SHA_Final(&s, key + 20); SHA_Final(&s, key + 20);
aes256_decrypt_pubkey(key, private_blob, private_blob_len); aes256_decrypt_pubkey(key, private_blob->u, private_blob->len);
} }
/* /*
@ -783,8 +779,8 @@ struct ssh2_userkey *ssh2_load_userkey(const Filename *filename,
if (old_fmt) { if (old_fmt) {
/* MAC (or hash) only covers the private blob. */ /* MAC (or hash) only covers the private blob. */
macdata = private_blob; macdata = private_blob->u;
maclen = private_blob_len; maclen = private_blob->len;
free_macdata = 0; free_macdata = 0;
} else { } else {
unsigned char *p; unsigned char *p;
@ -794,16 +790,16 @@ struct ssh2_userkey *ssh2_load_userkey(const Filename *filename,
maclen = (4 + namelen + maclen = (4 + namelen +
4 + enclen + 4 + enclen +
4 + commlen + 4 + commlen +
4 + public_blob_len + 4 + public_blob->len +
4 + private_blob_len); 4 + private_blob->len);
macdata = snewn(maclen, unsigned char); macdata = snewn(maclen, unsigned char);
p = macdata; p = macdata;
#define DO_STR(s,len) PUT_32BIT(p,(len));memcpy(p+4,(s),(len));p+=4+(len) #define DO_STR(s,len) PUT_32BIT(p,(len));memcpy(p+4,(s),(len));p+=4+(len)
DO_STR(alg->name, namelen); DO_STR(alg->name, namelen);
DO_STR(encryption, enclen); DO_STR(encryption, enclen);
DO_STR(comment, commlen); DO_STR(comment, commlen);
DO_STR(public_blob, public_blob_len); DO_STR(public_blob->s, public_blob->len);
DO_STR(private_blob, private_blob_len); DO_STR(private_blob->s, private_blob->len);
free_macdata = 1; free_macdata = 1;
} }
@ -857,17 +853,16 @@ struct ssh2_userkey *ssh2_load_userkey(const Filename *filename,
ret = snew(struct ssh2_userkey); ret = snew(struct ssh2_userkey);
ret->alg = alg; ret->alg = alg;
ret->comment = comment; ret->comment = comment;
ret->data = alg->createkey(alg, public_blob, public_blob_len, ret->data = alg->createkey(alg, public_blob->u, public_blob->len,
private_blob, private_blob_len); private_blob->u, private_blob->len);
if (!ret->data) { if (!ret->data) {
sfree(ret); sfree(ret);
ret = NULL; ret = NULL;
error = "createkey failed"; error = "createkey failed";
goto error; goto error;
} }
sfree(public_blob); strbuf_free(public_blob);
smemclr(private_blob, private_blob_len); strbuf_free(private_blob);
sfree(private_blob);
sfree(encryption); sfree(encryption);
if (errorstr) if (errorstr)
*errorstr = NULL; *errorstr = NULL;
@ -886,19 +881,17 @@ struct ssh2_userkey *ssh2_load_userkey(const Filename *filename,
if (mac) if (mac)
sfree(mac); sfree(mac);
if (public_blob) if (public_blob)
sfree(public_blob); strbuf_free(public_blob);
if (private_blob) { if (private_blob)
smemclr(private_blob, private_blob_len); strbuf_free(private_blob);
sfree(private_blob);
}
if (errorstr) if (errorstr)
*errorstr = error; *errorstr = error;
return ret; return ret;
} }
unsigned char *rfc4716_loadpub(FILE *fp, char **algorithm, int rfc4716_loadpub(FILE *fp, char **algorithm,
int *pub_blob_len, char **commentptr, BinarySink *bs,
const char **errorstr) char **commentptr, const char **errorstr)
{ {
const char *error; const char *error;
char *line, *colon, *value; char *line, *colon, *value;
@ -1013,13 +1006,13 @@ unsigned char *rfc4716_loadpub(FILE *fp, char **algorithm,
} }
if (algorithm) if (algorithm)
*algorithm = dupprintf("%.*s", alglen, pubblob+4); *algorithm = dupprintf("%.*s", alglen, pubblob+4);
if (pub_blob_len)
*pub_blob_len = pubbloblen;
if (commentptr) if (commentptr)
*commentptr = comment; *commentptr = comment;
else else
sfree(comment); sfree(comment);
return pubblob; put_data(bs, pubblob, pubbloblen);
sfree(pubblob);
return TRUE;
error: error:
sfree(line); sfree(line);
@ -1027,12 +1020,12 @@ unsigned char *rfc4716_loadpub(FILE *fp, char **algorithm,
sfree(pubblob); sfree(pubblob);
if (errorstr) if (errorstr)
*errorstr = error; *errorstr = error;
return NULL; return FALSE;
} }
unsigned char *openssh_loadpub(FILE *fp, char **algorithm, int openssh_loadpub(FILE *fp, char **algorithm,
int *pub_blob_len, char **commentptr, BinarySink *bs,
const char **errorstr) char **commentptr, const char **errorstr)
{ {
const char *error; const char *error;
char *line, *base64; char *line, *base64;
@ -1088,14 +1081,14 @@ unsigned char *openssh_loadpub(FILE *fp, char **algorithm,
*/ */
if (algorithm) if (algorithm)
*algorithm = dupstr(line); *algorithm = dupstr(line);
if (pub_blob_len)
*pub_blob_len = pubbloblen;
if (commentptr) if (commentptr)
*commentptr = comment; *commentptr = comment;
else else
sfree(comment); sfree(comment);
sfree(line); sfree(line);
return pubblob; put_data(bs, pubblob, pubbloblen);
sfree(pubblob);
return TRUE;
error: error:
sfree(line); sfree(line);
@ -1103,24 +1096,20 @@ unsigned char *openssh_loadpub(FILE *fp, char **algorithm,
sfree(pubblob); sfree(pubblob);
if (errorstr) if (errorstr)
*errorstr = error; *errorstr = error;
return NULL; return FALSE;
} }
unsigned char *ssh2_userkey_loadpub(const Filename *filename, char **algorithm, int ssh2_userkey_loadpub(const Filename *filename, char **algorithm,
int *pub_blob_len, char **commentptr, BinarySink *bs,
const char **errorstr) char **commentptr, const char **errorstr)
{ {
FILE *fp; FILE *fp;
char header[40], *b; char header[40], *b;
const struct ssh_signkey *alg; const struct ssh_signkey *alg;
unsigned char *public_blob;
int public_blob_len;
int type, i; int type, i;
const char *error = NULL; const char *error = NULL;
char *comment = NULL; char *comment = NULL;
public_blob = NULL;
fp = f_open(filename, "rb", FALSE); fp = f_open(filename, "rb", FALSE);
if (!fp) { if (!fp) {
error = "can't open file"; error = "can't open file";
@ -1131,13 +1120,11 @@ unsigned char *ssh2_userkey_loadpub(const Filename *filename, char **algorithm,
* we'll be asked to read a public blob from one of those. */ * we'll be asked to read a public blob from one of those. */
type = key_type_fp(fp); type = key_type_fp(fp);
if (type == SSH_KEYTYPE_SSH2_PUBLIC_RFC4716) { if (type == SSH_KEYTYPE_SSH2_PUBLIC_RFC4716) {
unsigned char *ret = rfc4716_loadpub(fp, algorithm, pub_blob_len, int ret = rfc4716_loadpub(fp, algorithm, bs, commentptr, errorstr);
commentptr, errorstr);
fclose(fp); fclose(fp);
return ret; return ret;
} else if (type == SSH_KEYTYPE_SSH2_PUBLIC_OPENSSH) { } else if (type == SSH_KEYTYPE_SSH2_PUBLIC_OPENSSH) {
unsigned char *ret = openssh_loadpub(fp, algorithm, pub_blob_len, int ret = openssh_loadpub(fp, algorithm, bs, commentptr, errorstr);
commentptr, errorstr);
fclose(fp); fclose(fp);
return ret; return ret;
} else if (type != SSH_KEYTYPE_SSH2) { } else if (type != SSH_KEYTYPE_SSH2) {
@ -1190,15 +1177,13 @@ unsigned char *ssh2_userkey_loadpub(const Filename *filename, char **algorithm,
goto error; goto error;
i = atoi(b); i = atoi(b);
sfree(b); sfree(b);
if ((public_blob = read_blob(fp, i, &public_blob_len)) == NULL) if (!read_blob(fp, i, bs))
goto error; goto error;
fclose(fp); fclose(fp);
if (pub_blob_len)
*pub_blob_len = public_blob_len;
if (algorithm) if (algorithm)
*algorithm = dupstr(alg->name); *algorithm = dupstr(alg->name);
return public_blob; return TRUE;
/* /*
* Error processing. * Error processing.
@ -1206,15 +1191,13 @@ unsigned char *ssh2_userkey_loadpub(const Filename *filename, char **algorithm,
error: error:
if (fp) if (fp)
fclose(fp); fclose(fp);
if (public_blob)
sfree(public_blob);
if (errorstr) if (errorstr)
*errorstr = error; *errorstr = error;
if (comment && commentptr) { if (comment && commentptr) {
sfree(comment); sfree(comment);
*commentptr = NULL; *commentptr = NULL;
} }
return NULL; return FALSE;
} }
int ssh2_userkey_encrypted(const Filename *filename, char **commentptr) int ssh2_userkey_encrypted(const Filename *filename, char **commentptr)
@ -1309,8 +1292,9 @@ int ssh2_save_userkey(const Filename *filename, struct ssh2_userkey *key,
char *passphrase) char *passphrase)
{ {
FILE *fp; FILE *fp;
unsigned char *pub_blob, *priv_blob, *priv_blob_encrypted; strbuf *pub_blob, *priv_blob;
int pub_blob_len, priv_blob_len, priv_encrypted_len; unsigned char *priv_blob_encrypted;
int priv_encrypted_len;
int passlen; int passlen;
int cipherblk; int cipherblk;
int i; int i;
@ -1320,13 +1304,10 @@ int ssh2_save_userkey(const Filename *filename, struct ssh2_userkey *key,
/* /*
* Fetch the key component blobs. * Fetch the key component blobs.
*/ */
pub_blob = key->alg->public_blob(key->data, &pub_blob_len); pub_blob = strbuf_new();
priv_blob = key->alg->private_blob(key->data, &priv_blob_len); key->alg->public_blob(key->data, BinarySink_UPCAST(pub_blob));
if (!pub_blob || !priv_blob) { priv_blob = strbuf_new();
sfree(pub_blob); key->alg->private_blob(key->data, BinarySink_UPCAST(priv_blob));
sfree(priv_blob);
return 0;
}
/* /*
* Determine encryption details, and encrypt the private blob. * Determine encryption details, and encrypt the private blob.
@ -1338,17 +1319,17 @@ int ssh2_save_userkey(const Filename *filename, struct ssh2_userkey *key,
cipherstr = "none"; cipherstr = "none";
cipherblk = 1; cipherblk = 1;
} }
priv_encrypted_len = priv_blob_len + cipherblk - 1; priv_encrypted_len = priv_blob->len + cipherblk - 1;
priv_encrypted_len -= priv_encrypted_len % cipherblk; priv_encrypted_len -= priv_encrypted_len % cipherblk;
priv_blob_encrypted = snewn(priv_encrypted_len, unsigned char); priv_blob_encrypted = snewn(priv_encrypted_len, unsigned char);
memset(priv_blob_encrypted, 0, priv_encrypted_len); memset(priv_blob_encrypted, 0, priv_encrypted_len);
memcpy(priv_blob_encrypted, priv_blob, priv_blob_len); memcpy(priv_blob_encrypted, priv_blob->u, priv_blob->len);
/* Create padding based on the SHA hash of the unpadded blob. This prevents /* Create padding based on the SHA hash of the unpadded blob. This prevents
* too easy a known-plaintext attack on the last block. */ * too easy a known-plaintext attack on the last block. */
SHA_Simple(priv_blob, priv_blob_len, priv_mac); SHA_Simple(priv_blob->u, priv_blob->len, priv_mac);
assert(priv_encrypted_len - priv_blob_len < 20); assert(priv_encrypted_len - priv_blob->len < 20);
memcpy(priv_blob_encrypted + priv_blob_len, priv_mac, memcpy(priv_blob_encrypted + priv_blob->len, priv_mac,
priv_encrypted_len - priv_blob_len); priv_encrypted_len - priv_blob->len);
/* Now create the MAC. */ /* Now create the MAC. */
{ {
@ -1365,7 +1346,7 @@ int ssh2_save_userkey(const Filename *filename, struct ssh2_userkey *key,
maclen = (4 + namelen + maclen = (4 + namelen +
4 + enclen + 4 + enclen +
4 + commlen + 4 + commlen +
4 + pub_blob_len + 4 + pub_blob->len +
4 + priv_encrypted_len); 4 + priv_encrypted_len);
macdata = snewn(maclen, unsigned char); macdata = snewn(maclen, unsigned char);
p = macdata; p = macdata;
@ -1373,7 +1354,7 @@ int ssh2_save_userkey(const Filename *filename, struct ssh2_userkey *key,
DO_STR(key->alg->name, namelen); DO_STR(key->alg->name, namelen);
DO_STR(cipherstr, enclen); DO_STR(cipherstr, enclen);
DO_STR(key->comment, commlen); DO_STR(key->comment, commlen);
DO_STR(pub_blob, pub_blob_len); DO_STR(pub_blob->u, pub_blob->len);
DO_STR(priv_blob_encrypted, priv_encrypted_len); DO_STR(priv_blob_encrypted, priv_encrypted_len);
SHA_Init(&s); SHA_Init(&s);
@ -1411,18 +1392,17 @@ int ssh2_save_userkey(const Filename *filename, struct ssh2_userkey *key,
fp = f_open(filename, "w", TRUE); fp = f_open(filename, "w", TRUE);
if (!fp) { if (!fp) {
sfree(pub_blob); strbuf_free(pub_blob);
smemclr(priv_blob, priv_blob_len); strbuf_free(priv_blob);
sfree(priv_blob); smemclr(priv_blob_encrypted, priv_encrypted_len);
smemclr(priv_blob_encrypted, priv_blob_len);
sfree(priv_blob_encrypted); sfree(priv_blob_encrypted);
return 0; return 0;
} }
fprintf(fp, "PuTTY-User-Key-File-2: %s\n", key->alg->name); fprintf(fp, "PuTTY-User-Key-File-2: %s\n", key->alg->name);
fprintf(fp, "Encryption: %s\n", cipherstr); fprintf(fp, "Encryption: %s\n", cipherstr);
fprintf(fp, "Comment: %s\n", key->comment); fprintf(fp, "Comment: %s\n", key->comment);
fprintf(fp, "Public-Lines: %d\n", base64_lines(pub_blob_len)); fprintf(fp, "Public-Lines: %d\n", base64_lines(pub_blob->len));
base64_encode(fp, pub_blob, pub_blob_len, 64); base64_encode(fp, pub_blob->u, pub_blob->len, 64);
fprintf(fp, "Private-Lines: %d\n", base64_lines(priv_encrypted_len)); fprintf(fp, "Private-Lines: %d\n", base64_lines(priv_encrypted_len));
base64_encode(fp, priv_blob_encrypted, priv_encrypted_len, 64); base64_encode(fp, priv_blob_encrypted, priv_encrypted_len, 64);
fprintf(fp, "Private-MAC: "); fprintf(fp, "Private-MAC: ");
@ -1431,10 +1411,9 @@ int ssh2_save_userkey(const Filename *filename, struct ssh2_userkey *key,
fprintf(fp, "\n"); fprintf(fp, "\n");
fclose(fp); fclose(fp);
sfree(pub_blob); strbuf_free(pub_blob);
smemclr(priv_blob, priv_blob_len); strbuf_free(priv_blob);
sfree(priv_blob); smemclr(priv_blob_encrypted, priv_encrypted_len);
smemclr(priv_blob_encrypted, priv_blob_len);
sfree(priv_blob_encrypted); sfree(priv_blob_encrypted);
return 1; return 1;
} }
@ -1513,13 +1492,14 @@ static char *ssh2_pubkey_openssh_str_internal(const char *comment,
char *ssh2_pubkey_openssh_str(struct ssh2_userkey *key) char *ssh2_pubkey_openssh_str(struct ssh2_userkey *key)
{ {
int bloblen; strbuf *blob;
unsigned char *blob;
char *ret; char *ret;
blob = key->alg->public_blob(key->data, &bloblen); blob = strbuf_new();
ret = ssh2_pubkey_openssh_str_internal(key->comment, blob, bloblen); key->alg->public_blob(key->data, BinarySink_UPCAST(blob));
sfree(blob); ret = ssh2_pubkey_openssh_str_internal(
key->comment, blob->s, blob->len);
strbuf_free(blob);
return ret; return ret;
} }
@ -1623,10 +1603,10 @@ char *ssh2_fingerprint_blob(const void *blob, int bloblen)
char *ssh2_fingerprint(const struct ssh_signkey *alg, void *data) char *ssh2_fingerprint(const struct ssh_signkey *alg, void *data)
{ {
int len; strbuf *blob = strbuf_new();
unsigned char *blob = alg->public_blob(data, &len); alg->public_blob(data, BinarySink_UPCAST(blob));
char *ret = ssh2_fingerprint_blob(blob, len); char *ret = ssh2_fingerprint_blob(blob->s, blob->len);
sfree(blob); strbuf_free(blob);
return ret; return ret;
} }

143
sshrsa.c
View File

@ -439,28 +439,17 @@ int rsa_verify(struct RSAKey *key)
return 1; return 1;
} }
unsigned char *rsa_ssh1_public_blob(struct RSAKey *key, int *len, void rsa_ssh1_public_blob(BinarySink *bs, struct RSAKey *key,
RsaSsh1Order order) RsaSsh1Order order)
{ {
int length, pos; put_uint32(bs, bignum_bitcount(key->modulus));
unsigned char *ret;
length = (ssh1_bignum_length(key->modulus) +
ssh1_bignum_length(key->exponent) + 4);
ret = snewn(length, unsigned char);
PUT_32BIT(ret, bignum_bitcount(key->modulus));
pos = 4;
if (order == RSA_SSH1_EXPONENT_FIRST) { if (order == RSA_SSH1_EXPONENT_FIRST) {
pos += ssh1_write_bignum(ret + pos, key->exponent); put_mp_ssh1(bs, key->exponent);
pos += ssh1_write_bignum(ret + pos, key->modulus); put_mp_ssh1(bs, key->modulus);
} else { } else {
pos += ssh1_write_bignum(ret + pos, key->modulus); put_mp_ssh1(bs, key->modulus);
pos += ssh1_write_bignum(ret + pos, key->exponent); put_mp_ssh1(bs, key->exponent);
} }
*len = length;
return ret;
} }
/* Given a public blob, determine its length. */ /* Given a public blob, determine its length. */
@ -588,78 +577,23 @@ static char *rsa2_fmtkey(void *key)
return p; return p;
} }
static unsigned char *rsa2_public_blob(void *key, int *len) static void rsa2_public_blob(void *key, BinarySink *bs)
{ {
struct RSAKey *rsa = (struct RSAKey *) key; struct RSAKey *rsa = (struct RSAKey *) key;
int elen, mlen, bloblen;
int i;
unsigned char *blob, *p;
elen = (bignum_bitcount(rsa->exponent) + 8) / 8; put_stringz(bs, "ssh-rsa");
mlen = (bignum_bitcount(rsa->modulus) + 8) / 8; put_mp_ssh2(bs, rsa->exponent);
put_mp_ssh2(bs, rsa->modulus);
/*
* string "ssh-rsa", mpint exp, mpint mod. Total 19+elen+mlen.
* (three length fields, 12+7=19).
*/
bloblen = 19 + elen + mlen;
blob = snewn(bloblen, unsigned char);
p = blob;
PUT_32BIT(p, 7);
p += 4;
memcpy(p, "ssh-rsa", 7);
p += 7;
PUT_32BIT(p, elen);
p += 4;
for (i = elen; i--;)
*p++ = bignum_byte(rsa->exponent, i);
PUT_32BIT(p, mlen);
p += 4;
for (i = mlen; i--;)
*p++ = bignum_byte(rsa->modulus, i);
assert(p == blob + bloblen);
*len = bloblen;
return blob;
} }
static unsigned char *rsa2_private_blob(void *key, int *len) static void rsa2_private_blob(void *key, BinarySink *bs)
{ {
struct RSAKey *rsa = (struct RSAKey *) key; struct RSAKey *rsa = (struct RSAKey *) key;
int dlen, plen, qlen, ulen, bloblen;
int i;
unsigned char *blob, *p;
dlen = (bignum_bitcount(rsa->private_exponent) + 8) / 8; put_mp_ssh2(bs, rsa->private_exponent);
plen = (bignum_bitcount(rsa->p) + 8) / 8; put_mp_ssh2(bs, rsa->p);
qlen = (bignum_bitcount(rsa->q) + 8) / 8; put_mp_ssh2(bs, rsa->q);
ulen = (bignum_bitcount(rsa->iqmp) + 8) / 8; put_mp_ssh2(bs, rsa->iqmp);
/*
* mpint private_exp, mpint p, mpint q, mpint iqmp. Total 16 +
* sum of lengths.
*/
bloblen = 16 + dlen + plen + qlen + ulen;
blob = snewn(bloblen, unsigned char);
p = blob;
PUT_32BIT(p, dlen);
p += 4;
for (i = dlen; i--;)
*p++ = bignum_byte(rsa->private_exponent, i);
PUT_32BIT(p, plen);
p += 4;
for (i = plen; i--;)
*p++ = bignum_byte(rsa->p, i);
PUT_32BIT(p, qlen);
p += 4;
for (i = qlen; i--;)
*p++ = bignum_byte(rsa->q, i);
PUT_32BIT(p, ulen);
p += 4;
for (i = ulen; i--;)
*p++ = bignum_byte(rsa->iqmp, i);
assert(p == blob + bloblen);
*len = bloblen;
return blob;
} }
static void *rsa2_createkey(const struct ssh_signkey *self, static void *rsa2_createkey(const struct ssh_signkey *self,
@ -713,33 +647,16 @@ static void *rsa2_openssh_createkey(const struct ssh_signkey *self,
return rsa; return rsa;
} }
static int rsa2_openssh_fmtkey(void *key, unsigned char *blob, int len) static void rsa2_openssh_fmtkey(void *key, BinarySink *bs)
{ {
struct RSAKey *rsa = (struct RSAKey *) key; struct RSAKey *rsa = (struct RSAKey *) key;
int bloblen, i;
bloblen = put_mp_ssh2(bs, rsa->modulus);
ssh2_bignum_length(rsa->modulus) + put_mp_ssh2(bs, rsa->exponent);
ssh2_bignum_length(rsa->exponent) + put_mp_ssh2(bs, rsa->private_exponent);
ssh2_bignum_length(rsa->private_exponent) + put_mp_ssh2(bs, rsa->iqmp);
ssh2_bignum_length(rsa->iqmp) + put_mp_ssh2(bs, rsa->p);
ssh2_bignum_length(rsa->p) + ssh2_bignum_length(rsa->q); put_mp_ssh2(bs, rsa->q);
if (bloblen > len)
return bloblen;
bloblen = 0;
#define ENC(x) \
PUT_32BIT(blob+bloblen, ssh2_bignum_length((x))-4); bloblen += 4; \
for (i = ssh2_bignum_length((x))-4; i-- ;) blob[bloblen++]=bignum_byte((x),i);
ENC(rsa->modulus);
ENC(rsa->exponent);
ENC(rsa->private_exponent);
ENC(rsa->iqmp);
ENC(rsa->p);
ENC(rsa->q);
return bloblen;
} }
static int rsa2_pubkey_bits(const struct ssh_signkey *self, static int rsa2_pubkey_bits(const struct ssh_signkey *self,
@ -838,8 +755,8 @@ static int rsa2_verifysig(void *key, const char *sig, int siglen,
return ret; return ret;
} }
static unsigned char *rsa2_sign(void *key, const char *data, int datalen, static void rsa2_sign(void *key, const char *data, int datalen,
int *siglen) BinarySink *bs)
{ {
struct RSAKey *rsa = (struct RSAKey *) key; struct RSAKey *rsa = (struct RSAKey *) key;
unsigned char *bytes; unsigned char *bytes;
@ -868,17 +785,13 @@ static unsigned char *rsa2_sign(void *key, const char *data, int datalen,
out = rsa_privkey_op(in, rsa); out = rsa_privkey_op(in, rsa);
freebn(in); freebn(in);
put_stringz(bs, "ssh-rsa");
nbytes = (bignum_bitcount(out) + 7) / 8; nbytes = (bignum_bitcount(out) + 7) / 8;
bytes = snewn(4 + 7 + 4 + nbytes, unsigned char); put_uint32(bs, nbytes);
PUT_32BIT(bytes, 7);
memcpy(bytes + 4, "ssh-rsa", 7);
PUT_32BIT(bytes + 4 + 7, nbytes);
for (i = 0; i < nbytes; i++) for (i = 0; i < nbytes; i++)
bytes[4 + 7 + 4 + i] = bignum_byte(out, nbytes - 1 - i); put_byte(bs, bignum_byte(out, nbytes - 1 - i));
freebn(out);
*siglen = 4 + 7 + 4 + nbytes; freebn(out);
return bytes;
} }
const struct ssh_signkey ssh_rsa = { const struct ssh_signkey ssh_rsa = {

View File

@ -556,8 +556,11 @@ struct pageant_pubkey *find_key(const char *string, char **retstr)
keytype == SSH_KEYTYPE_SSH1_PUBLIC) { keytype == SSH_KEYTYPE_SSH1_PUBLIC) {
const char *error; const char *error;
if (!rsa_ssh1_loadpub(fn, &key_in.blob, &key_in.bloblen, key_in.blob = strbuf_new();
if (!rsa_ssh1_loadpub(fn, BinarySink_UPCAST(key_in.blob),
NULL, &error)) { NULL, &error)) {
strbuf_free(key_in.blob);
key_in.blob = NULL;
if (file_errors) { if (file_errors) {
*retstr = dupprintf("unable to load file '%s': %s", *retstr = dupprintf("unable to load file '%s': %s",
string, error); string, error);
@ -573,7 +576,8 @@ struct pageant_pubkey *find_key(const char *string, char **retstr)
key_in.ssh_version = 1; key_in.ssh_version = 1;
key_in.comment = NULL; key_in.comment = NULL;
key_ret = pageant_pubkey_copy(&key_in); key_ret = pageant_pubkey_copy(&key_in);
sfree(key_in.blob); strbuf_free(key_in.blob);
key_in.blob = NULL;
filename_free(fn); filename_free(fn);
return key_ret; return key_ret;
} }
@ -582,9 +586,11 @@ struct pageant_pubkey *find_key(const char *string, char **retstr)
keytype == SSH_KEYTYPE_SSH2_PUBLIC_OPENSSH) { keytype == SSH_KEYTYPE_SSH2_PUBLIC_OPENSSH) {
const char *error; const char *error;
if ((key_in.blob = ssh2_userkey_loadpub(fn, NULL, key_in.blob = strbuf_new();
&key_in.bloblen, if (!ssh2_userkey_loadpub(fn, NULL, BinarySink_UPCAST(key_in.blob),
NULL, &error)) == NULL) { NULL, &error)) {
strbuf_free(key_in.blob);
key_in.blob = NULL;
if (file_errors) { if (file_errors) {
*retstr = dupprintf("unable to load file '%s': %s", *retstr = dupprintf("unable to load file '%s': %s",
string, error); string, error);
@ -600,7 +606,8 @@ struct pageant_pubkey *find_key(const char *string, char **retstr)
key_in.ssh_version = 2; key_in.ssh_version = 2;
key_in.comment = NULL; key_in.comment = NULL;
key_ret = pageant_pubkey_copy(&key_in); key_ret = pageant_pubkey_copy(&key_in);
sfree(key_in.blob); strbuf_free(key_in.blob);
key_in.blob = NULL;
filename_free(fn); filename_free(fn);
return key_ret; return key_ret;
} }
@ -696,12 +703,14 @@ void run_client(void)
struct RSAKey rkey; struct RSAKey rkey;
memset(&rkey, 0, sizeof(rkey)); memset(&rkey, 0, sizeof(rkey));
rkey.comment = dupstr(key->comment); rkey.comment = dupstr(key->comment);
rsa_ssh1_readpub(key->blob, key->bloblen, &rkey, NULL, rsa_ssh1_readpub(key->blob->u, key->blob->len, &rkey, NULL,
RSA_SSH1_EXPONENT_FIRST); RSA_SSH1_EXPONENT_FIRST);
ssh1_write_pubkey(fp, &rkey); ssh1_write_pubkey(fp, &rkey);
freersakey(&rkey); freersakey(&rkey);
} else { } else {
ssh2_write_pubkey(fp, key->comment, key->blob,key->bloblen, ssh2_write_pubkey(fp, key->comment,
key->blob->u,
key->blob->len,
(act->action == KEYACT_CLIENT_PUBLIC ? (act->action == KEYACT_CLIENT_PUBLIC ?
SSH_KEYTYPE_SSH2_PUBLIC_RFC4716 : SSH_KEYTYPE_SSH2_PUBLIC_RFC4716 :
SSH_KEYTYPE_SSH2_PUBLIC_OPENSSH)); SSH_KEYTYPE_SSH2_PUBLIC_OPENSSH));

View File

@ -1321,13 +1321,13 @@ static INT_PTR CALLBACK MainDlgProc(HWND hwnd, UINT msg,
"PuTTYgen Error", MB_OK | MB_ICONERROR); "PuTTYgen Error", MB_OK | MB_ICONERROR);
} else { } else {
if (state->ssh2) { if (state->ssh2) {
int bloblen; strbuf *blob = strbuf_new();
unsigned char *blob; state->ssh2key.alg->public_blob(
blob = state->ssh2key.alg->public_blob state->ssh2key.data, BinarySink_UPCAST(blob));
(state->ssh2key.data, &bloblen);
ssh2_write_pubkey(fp, state->ssh2key.comment, ssh2_write_pubkey(fp, state->ssh2key.comment,
blob, bloblen, blob->u, blob->len,
SSH_KEYTYPE_SSH2_PUBLIC_RFC4716); SSH_KEYTYPE_SSH2_PUBLIC_RFC4716);
strbuf_free(blob);
} else { } else {
ssh1_write_pubkey(fp, &state->key); ssh1_write_pubkey(fp, &state->key);
} }