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
Родитель a990738aca
Коммит 67de463cca
12 изменённых файлов: 542 добавлений и 956 удалений

Просмотреть файл

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

144
import.c
Просмотреть файл

@ -924,8 +924,9 @@ struct ssh2_userkey *openssh_pem_read(const Filename *filename,
int openssh_pem_write(const Filename *filename, struct ssh2_userkey *key,
char *passphrase)
{
unsigned char *pubblob, *privblob, *spareblob;
int publen, privlen, sparelen = 0;
strbuf *pubblob, *privblob;
unsigned char *spareblob;
int sparelen = 0;
unsigned char *outblob;
int outlen;
struct mpint_pos numbers[9];
@ -939,8 +940,10 @@ int openssh_pem_write(const Filename *filename, struct ssh2_userkey *key,
/*
* Fetch the key blobs.
*/
pubblob = key->alg->public_blob(key->data, &publen);
privblob = key->alg->private_blob(key->data, &privlen);
pubblob = strbuf_new();
key->alg->public_blob(key->data, BinarySink_UPCAST(pubblob));
privblob = strbuf_new();
key->alg->private_blob(key->data, BinarySink_UPCAST(privblob));
spareblob = 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
* treat them as untrusted.
*/
pos = 4 + GET_32BIT(pubblob);
pos += ssh2_read_mpint(pubblob+pos, publen-pos, &e);
pos += ssh2_read_mpint(pubblob+pos, publen-pos, &n);
pos = 4 + GET_32BIT(pubblob->u);
pos += ssh2_read_mpint(pubblob->u+pos, pubblob->len-pos, &e);
pos += ssh2_read_mpint(pubblob->u+pos, pubblob->len-pos, &n);
pos = 0;
pos += ssh2_read_mpint(privblob+pos, privlen-pos, &d);
pos += ssh2_read_mpint(privblob+pos, privlen-pos, &p);
pos += ssh2_read_mpint(privblob+pos, privlen-pos, &q);
pos += ssh2_read_mpint(privblob+pos, privlen-pos, &iqmp);
pos += ssh2_read_mpint(privblob->u+pos, privblob->len-pos, &d);
pos += ssh2_read_mpint(privblob->u+pos, privblob->len-pos, &p);
pos += ssh2_read_mpint(privblob->u+pos, privblob->len-pos, &q);
pos += ssh2_read_mpint(privblob->u+pos, privblob->len-pos, &iqmp);
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
* treat them as untrusted.
*/
pos = 4 + GET_32BIT(pubblob);
pos += ssh2_read_mpint(pubblob+pos, publen-pos, &p);
pos += ssh2_read_mpint(pubblob+pos, publen-pos, &q);
pos += ssh2_read_mpint(pubblob+pos, publen-pos, &g);
pos += ssh2_read_mpint(pubblob+pos, publen-pos, &y);
pos = 4 + GET_32BIT(pubblob->u);
pos += ssh2_read_mpint(pubblob->u+pos, pubblob->len-pos, &p);
pos += ssh2_read_mpint(pubblob->u+pos, pubblob->len-pos, &q);
pos += ssh2_read_mpint(pubblob->u+pos, pubblob->len-pos, &g);
pos += ssh2_read_mpint(pubblob->u+pos, pubblob->len-pos, &y);
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 */
@ -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 += 1;
len += ber_write_id_len(NULL, 4, privlen - 4, 0);
len+= privlen - 4;
len += ber_write_id_len(NULL, 4, privblob->len - 4, 0);
len+= privblob->len - 4;
len += ber_write_id_len(NULL, 0, oidlen +
ber_write_id_len(NULL, 6, oidlen, 0),
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, 2, 1, 0);
outblob[pos++] = 1;
pos += ber_write_id_len(outblob+pos, 4, privlen - 4, 0);
memcpy(outblob+pos, privblob + 4, privlen - 4);
pos += privlen - 4;
pos += ber_write_id_len(outblob+pos, 4, privblob->len - 4, 0);
memcpy(outblob+pos, privblob->u + 4, privblob->len - 4);
pos += privblob->len - 4;
pos += ber_write_id_len(outblob+pos, 0, oidlen +
ber_write_id_len(NULL, 6, oidlen, 0),
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);
pos += ber_write_id_len(outblob+pos, 3, 2 + pointlen, 0);
outblob[pos++] = 0;
memcpy(outblob+pos, pubblob+39, 1 + pointlen);
memcpy(outblob+pos, pubblob->u+39, 1 + pointlen);
pos += 1 + pointlen;
header = "-----BEGIN EC PRIVATE KEY-----\n";
@ -1254,14 +1257,10 @@ int openssh_pem_write(const Filename *filename, struct ssh2_userkey *key,
smemclr(spareblob, sparelen);
sfree(spareblob);
}
if (privblob) {
smemclr(privblob, privlen);
sfree(privblob);
}
if (pubblob) {
smemclr(pubblob, publen);
sfree(pubblob);
}
if (privblob)
strbuf_free(privblob);
if (pubblob)
strbuf_free(pubblob);
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,
char *passphrase)
{
unsigned char *pubblob, *privblob, *outblob, *p;
strbuf *pubblob, *privblob;
unsigned char *outblob, *p;
unsigned char *private_section_start, *private_section_length_field;
int publen, privlen, commentlen, maxsize, padvalue, i;
int commentlen, maxsize, padvalue, i;
unsigned checkint;
int ret = 0;
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.
*/
pubblob = key->alg->public_blob(key->data, &publen);
i = key->alg->openssh_fmtkey(key->data, NULL, 0);
privblob = snewn(i, unsigned char);
privlen = key->alg->openssh_fmtkey(key->data, privblob, i);
assert(privlen == i);
pubblob = strbuf_new();
key->alg->public_blob(key->data, BinarySink_UPCAST(pubblob));
privblob = strbuf_new();
key->alg->openssh_fmtkey(key->data, BinarySink_UPCAST(privblob));
commentlen = strlen(key->comment);
/*
@ -1775,11 +1774,11 @@ int openssh_new_write(const Filename *filename, struct ssh2_userkey *key,
32 + /* kdf name string */
64 + /* kdf options string */
4 + /* key count */
4+publen + /* public key string */
4+pubblob->len + /* public key string */
4 + /* string header for private section */
8 + /* checkint x 2 */
4+strlen(key->alg->name) + /* key type string */
privlen + /* private blob */
privblob->len + /* private blob */
4+commentlen + /* comment string */
16); /* padding at end of private section */
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);
/* Public blob. */
p += write_string(p, pubblob, publen);
p += write_string(p, pubblob->u, pubblob->len);
/* Begin private section. */
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
* wrapper. */
p += write_string_z(p, key->alg->name);
memcpy(p, privblob, privlen);
p += privlen;
memcpy(p, privblob->u, privblob->len);
p += privblob->len;
/* 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);
sfree(outblob);
}
if (privblob) {
smemclr(privblob, privlen);
sfree(privblob);
}
if (pubblob) {
smemclr(pubblob, publen);
sfree(pubblob);
}
if (privblob)
strbuf_free(privblob);
if (pubblob)
strbuf_free(pubblob);
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,
char *passphrase)
{
unsigned char *pubblob, *privblob;
int publen, privlen;
strbuf *pubblob, *privblob;
unsigned char *outblob;
int outlen;
struct mpint_pos numbers[6];
@ -2512,8 +2506,10 @@ int sshcom_write(const Filename *filename, struct ssh2_userkey *key,
/*
* Fetch the key blobs.
*/
pubblob = key->alg->public_blob(key->data, &publen);
privblob = key->alg->private_blob(key->data, &privlen);
pubblob = strbuf_new();
key->alg->public_blob(key->data, BinarySink_UPCAST(pubblob));
privblob = strbuf_new();
key->alg->private_blob(key->data, BinarySink_UPCAST(privblob));
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
* treat them as untrusted.
*/
pos = 4 + GET_32BIT(pubblob);
pos += ssh2_read_mpint(pubblob+pos, publen-pos, &e);
pos += ssh2_read_mpint(pubblob+pos, publen-pos, &n);
pos = 4 + GET_32BIT(pubblob->u);
pos += ssh2_read_mpint(pubblob->u+pos, pubblob->len-pos, &e);
pos += ssh2_read_mpint(pubblob->u+pos, pubblob->len-pos, &n);
pos = 0;
pos += ssh2_read_mpint(privblob+pos, privlen-pos, &d);
pos += ssh2_read_mpint(privblob+pos, privlen-pos, &p);
pos += ssh2_read_mpint(privblob+pos, privlen-pos, &q);
pos += ssh2_read_mpint(privblob+pos, privlen-pos, &iqmp);
pos += ssh2_read_mpint(privblob->u+pos, privblob->len-pos, &d);
pos += ssh2_read_mpint(privblob->u+pos, privblob->len-pos, &p);
pos += ssh2_read_mpint(privblob->u+pos, privblob->len-pos, &q);
pos += ssh2_read_mpint(privblob->u+pos, privblob->len-pos, &iqmp);
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
* treat them as untrusted.
*/
pos = 4 + GET_32BIT(pubblob);
pos += ssh2_read_mpint(pubblob+pos, publen-pos, &p);
pos += ssh2_read_mpint(pubblob+pos, publen-pos, &q);
pos += ssh2_read_mpint(pubblob+pos, publen-pos, &g);
pos += ssh2_read_mpint(pubblob+pos, publen-pos, &y);
pos = 4 + GET_32BIT(pubblob->u);
pos += ssh2_read_mpint(pubblob->u+pos, pubblob->len-pos, &p);
pos += ssh2_read_mpint(pubblob->u+pos, pubblob->len-pos, &q);
pos += ssh2_read_mpint(pubblob->u+pos, pubblob->len-pos, &g);
pos += ssh2_read_mpint(pubblob->u+pos, pubblob->len-pos, &y);
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 */
@ -2700,13 +2696,9 @@ int sshcom_write(const Filename *filename, struct ssh2_userkey *key,
smemclr(outblob, outlen);
sfree(outblob);
}
if (privblob) {
smemclr(privblob, privlen);
sfree(privblob);
}
if (pubblob) {
smemclr(pubblob, publen);
sfree(pubblob);
}
if (privblob)
strbuf_free(privblob);
if (pubblob)
strbuf_free(pubblob);
return ret;
}

320
pageant.c
Просмотреть файл

@ -34,16 +34,6 @@ static int pageant_local = FALSE;
*/
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.
*/
@ -84,128 +74,77 @@ static int cmpkeys_rsa(void *av, void *bv)
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
* of SSH-2 keys.
*/
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;
int i;
int alen, blen;
const unsigned char *ablob;
unsigned char *bblob;
int c;
strbuf *bblob;
int i, c;
/*
* Compare purely by public blob.
*/
ablob = a->blob;
alen = a->len;
bblob = b->alg->public_blob(b->data, &blen);
bblob = strbuf_new();
b->alg->public_blob(b->data, BinarySink_UPCAST(bblob));
c = 0;
for (i = 0; i < alen && i < blen; i++) {
if (ablob[i] < bblob[i]) {
for (i = 0; i < ablob->len && i < bblob->len; i++) {
if (ablob->u[i] < bblob->u[i]) {
c = -1;
break;
} else if (ablob[i] > bblob[i]) {
} else if (ablob->u[i] > bblob->u[i]) {
c = +1;
break;
}
}
if (c == 0 && i < alen)
if (c == 0 && i < ablob->len)
c = +1; /* a is longer */
if (c == 0 && i < blen)
if (c == 0 && i < bblob->len)
c = -1; /* a is longer */
sfree(bblob);
strbuf_free(bblob);
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
* 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;
unsigned char *blob, *p, *ret;
int bloblen;
/*
* Count up the number and length of keys we hold.
*/
len = 4;
nkeys = 0;
put_uint32(bs, count234(rsakeys));
for (i = 0; NULL != (key = index234(rsakeys, i)); i++) {
nkeys++;
blob = rsa_ssh1_public_blob(key, &bloblen, RSA_SSH1_EXPONENT_FIRST);
len += bloblen;
sfree(blob);
len += 4 + strlen(key->comment);
rsa_ssh1_public_blob(bs, key, RSA_SSH1_EXPONENT_FIRST);
put_stringz(bs, key->comment);
}
/* Allocate the buffer. */
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;
return strbuf_to_str(buf);
}
/*
@ -214,49 +153,20 @@ void *pageant_make_keylist1(int *length)
*/
void *pageant_make_keylist2(int *length)
{
strbuf *buf = strbuf_new();
BinarySink *bs = BinarySink_UPCAST(buf);
int i;
struct ssh2_userkey *key;
int i, len, nkeys;
unsigned char *blob, *p, *ret;
int bloblen;
/*
* Count up the number and length of keys we hold.
*/
len = 4;
nkeys = 0;
put_uint32(bs, count234(ssh2keys));
for (i = 0; NULL != (key = index234(ssh2keys, i)); i++) {
nkeys++;
len += 4; /* length field */
blob = key->alg->public_blob(key->data, &bloblen);
len += bloblen;
sfree(blob);
len += 4 + strlen(key->comment);
strbuf *blob = strbuf_new();
key->alg->public_blob(key->data, BinarySink_UPCAST(blob));
put_stringsb(bs, blob);
put_stringz(bs, key->comment);
}
/* Allocate the buffer. */
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;
return strbuf_to_str(buf);
}
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 blob b;
const void *blobp;
int bloblen;
const unsigned char *data;
unsigned char *signature;
int datalen, siglen, len;
strbuf *signature;
int datalen, len;
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";
goto failure;
}
b.len = toint(GET_32BIT(p));
if (b.len < 0 || b.len > msgend - (p+4)) {
bloblen = toint(GET_32BIT(p));
if (bloblen < 0 || bloblen > msgend - (p+4)) {
fail_reason = "request truncated before public key";
goto failure;
}
p += 4;
b.blob = p;
p += b.len;
blobp = p;
p += bloblen;
if (msgend < p+4) {
fail_reason = "request truncated before string to sign";
goto failure;
@ -511,23 +422,29 @@ void *pageant_handle_msg(const void *msg, int msglen, int *outlen,
}
data = p;
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);
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) {
fail_reason = "key not found";
goto failure;
}
signature = key->alg->sign(key->data, (const char *)data,
datalen, &siglen);
len = 5 + 4 + siglen;
signature = strbuf_new();
key->alg->sign(key->data, (const char *)data, datalen,
BinarySink_UPCAST(signature));
len = 5 + 4 + signature->len;
PUT_32BIT(ret, len - 4);
ret[4] = SSH2_AGENT_SIGN_RESPONSE;
PUT_32BIT(ret + 5, siglen);
memcpy(ret + 5 + 4, signature, siglen);
sfree(signature);
PUT_32BIT(ret + 5, signature->len);
memcpy(ret + 5 + 4, signature->s, signature->len);
strbuf_free(signature);
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 blob b;
const void *blobp;
int bloblen;
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";
goto failure;
}
b.len = toint(GET_32BIT(p));
bloblen = toint(GET_32BIT(p));
p += 4;
if (b.len < 0 || b.len > msgend - p) {
if (bloblen < 0 || bloblen > msgend - p) {
fail_reason = "request truncated before public key";
goto failure;
}
b.blob = p;
p += b.len;
blobp = p;
p += bloblen;
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);
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) {
fail_reason = "key not found";
goto failure;
@ -1283,55 +1206,53 @@ int pageant_add_keyfile(Filename *filename, const char *passphrase,
* which may or may not be us).
*/
{
void *blob;
strbuf *blob = strbuf_new();
unsigned char *keylist, *p;
int i, nkeys, bloblen, keylistlen;
int i, nkeys, keylistlen;
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);
strbuf_free(blob);
return PAGEANT_ACTION_FAILURE;
}
keylist = pageant_get_keylist1(&keylistlen);
} else {
unsigned char *blob2;
blob = ssh2_userkey_loadpub(filename, NULL, &bloblen,
NULL, &error);
if (!blob) {
/* For our purposes we want the blob prefixed with its
* length, so add a placeholder here to fill in
* afterwards */
put_uint32(blob, 0);
if (!ssh2_userkey_loadpub(filename, NULL, BinarySink_UPCAST(blob),
NULL, &error)) {
*retstr = dupprintf("Couldn't load private key (%s)", error);
strbuf_free(blob);
return PAGEANT_ACTION_FAILURE;
}
/* For our purposes we want the blob prefixed with its length */
blob2 = snewn(bloblen+4, unsigned char);
PUT_32BIT(blob2, bloblen);
memcpy(blob2 + 4, blob, bloblen);
sfree(blob);
blob = blob2;
PUT_32BIT(blob->s, blob->len - 4);
keylist = pageant_get_keylist2(&keylistlen);
}
if (keylist) {
if (keylistlen < 4) {
*retstr = dupstr("Received broken key list from agent");
sfree(keylist);
sfree(blob);
strbuf_free(blob);
return PAGEANT_ACTION_FAILURE;
}
nkeys = toint(GET_32BIT(keylist));
if (nkeys < 0) {
*retstr = dupstr("Received broken key list from agent");
sfree(keylist);
sfree(blob);
strbuf_free(blob);
return PAGEANT_ACTION_FAILURE;
}
p = keylist + 4;
keylistlen -= 4;
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. */
sfree(keylist);
sfree(blob);
strbuf_free(blob);
return PAGEANT_ACTION_OK;
}
/* Now skip over public blob */
@ -1340,7 +1261,7 @@ int pageant_add_keyfile(Filename *filename, const char *passphrase,
if (n < 0) {
*retstr = dupstr("Received broken key list from agent");
sfree(keylist);
sfree(blob);
strbuf_free(blob);
return PAGEANT_ACTION_FAILURE;
}
p += n;
@ -1350,7 +1271,7 @@ int pageant_add_keyfile(Filename *filename, const char *passphrase,
if (keylistlen < 4) {
*retstr = dupstr("Received broken key list from agent");
sfree(keylist);
sfree(blob);
strbuf_free(blob);
return PAGEANT_ACTION_FAILURE;
}
n = GET_32BIT(p);
@ -1360,7 +1281,7 @@ int pageant_add_keyfile(Filename *filename, const char *passphrase,
if (n < 0 || n > keylistlen) {
*retstr = dupstr("Received broken key list from agent");
sfree(keylist);
sfree(blob);
strbuf_free(blob);
return PAGEANT_ACTION_FAILURE;
}
p += n;
@ -1372,7 +1293,7 @@ int pageant_add_keyfile(Filename *filename, const char *passphrase,
if (keylistlen < 4) {
*retstr = dupstr("Received broken key list from agent");
sfree(keylist);
sfree(blob);
strbuf_free(blob);
return PAGEANT_ACTION_FAILURE;
}
n = GET_32BIT(p);
@ -1382,7 +1303,7 @@ int pageant_add_keyfile(Filename *filename, const char *passphrase,
if (n < 0 || n > keylistlen) {
*retstr = dupstr("Received broken key list from agent");
sfree(keylist);
sfree(blob);
strbuf_free(blob);
return PAGEANT_ACTION_FAILURE;
}
p += n;
@ -1393,7 +1314,7 @@ int pageant_add_keyfile(Filename *filename, const char *passphrase,
sfree(keylist);
}
sfree(blob);
strbuf_free(blob);
}
error = NULL;
@ -1551,15 +1472,17 @@ int pageant_add_keyfile(Filename *filename, const char *passphrase,
if (!pageant_local) {
unsigned char *request, *response;
void *vresponse;
int reqlen, alglen, clen, keybloblen, resplen;
strbuf *keyblob;
int reqlen, alglen, clen, resplen;
alglen = strlen(skey->alg->name);
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 */
4 + alglen + /* algorithm name */
keybloblen + /* key data */
keyblob->len + /* key data */
4 + clen /* comment */
;
@ -1571,9 +1494,8 @@ int pageant_add_keyfile(Filename *filename, const char *passphrase,
reqlen += 4;
memcpy(request + reqlen, skey->alg->name, alglen);
reqlen += alglen;
reqlen += skey->alg->openssh_fmtkey(skey->data,
request + reqlen,
keybloblen);
memcpy(request + reqlen, keyblob->s, keyblob->len);
reqlen += keyblob->len;
PUT_32BIT(request + reqlen, clen);
memcpy(request + reqlen + 4, skey->comment, clen);
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);
p += n, keylistlen -= n;
cbkey.blob = rsa_ssh1_public_blob(&rkey, &cbkey.bloblen,
RSA_SSH1_EXPONENT_FIRST);
cbkey.blob = strbuf_new();
rsa_ssh1_public_blob(BinarySink_UPCAST(cbkey.blob), &rkey,
RSA_SSH1_EXPONENT_FIRST);
cbkey.comment = comment;
cbkey.ssh_version = 1;
callback(callback_ctx, fingerprint, comment, &cbkey);
sfree(cbkey.blob);
strbuf_free(cbkey.blob);
freersakey(&rkey);
sfree(comment);
}
@ -1710,8 +1633,8 @@ int pageant_enum_keys(pageant_key_enum_fn_t callback, void *callback_ctx,
return PAGEANT_ACTION_FAILURE;
}
fingerprint = ssh2_fingerprint_blob(p, n);
cbkey.blob = p;
cbkey.bloblen = n;
cbkey.blob = strbuf_new();
put_data(cbkey.blob, p, n);
p += n, keylistlen -= n;
/* comment */
@ -1756,18 +1679,18 @@ int pageant_delete_key(struct pageant_pubkey *key, char **retstr)
void *vresponse;
if (key->ssh_version == 1) {
reqlen = 5 + key->bloblen;
reqlen = 5 + key->blob->len;
request = snewn(reqlen, unsigned char);
PUT_32BIT(request, reqlen - 4);
request[4] = SSH1_AGENTC_REMOVE_RSA_IDENTITY;
memcpy(request + 5, key->blob, key->bloblen);
memcpy(request + 5, key->blob->s, key->blob->len);
} else {
reqlen = 9 + key->bloblen;
reqlen = 9 + key->blob->len;
request = snewn(reqlen, unsigned char);
PUT_32BIT(request, reqlen - 4);
request[4] = SSH2_AGENTC_REMOVE_IDENTITY;
PUT_32BIT(request + 5, key->bloblen);
memcpy(request + 9, key->blob, key->bloblen);
PUT_32BIT(request + 5, key->blob->len);
memcpy(request + 9, key->blob->s, key->blob->len);
}
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 *ret = snew(struct pageant_pubkey);
ret->blob = snewn(key->bloblen, unsigned char);
memcpy(ret->blob, key->blob, key->bloblen);
ret->bloblen = key->bloblen;
ret->blob = strbuf_new();
put_data(ret->blob, key->blob->s, key->blob->len);
ret->comment = key->comment ? dupstr(key->comment) : NULL;
ret->ssh_version = key->ssh_version;
return ret;
@ -1832,6 +1754,6 @@ struct pageant_pubkey *pageant_pubkey_copy(struct pageant_pubkey *key)
void pageant_pubkey_free(struct pageant_pubkey *key)
{
sfree(key->comment);
sfree(key->blob);
strbuf_free(key->blob);
sfree(key);
}

Просмотреть файл

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

156
ssh.c
Просмотреть файл

@ -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
* that's listed.
*/
unsigned char *binblob;
strbuf *binblob;
char *base64blob;
int binlen, atoms, i;
binblob = ssh2keytype->public_blob(ssh2keydata, &binlen);
atoms = (binlen + 2) / 3;
int atoms, i;
binblob = strbuf_new();
ssh2keytype->public_blob(ssh2keydata, BinarySink_UPCAST(binblob));
atoms = (binblob->len + 2) / 3;
base64blob = snewn(atoms * 4 + 1, char);
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';
sfree(binblob);
strbuf_free(binblob);
if (conf_get_str_str_opt(ssh->conf, CONF_ssh_manual_hostkeys,
base64blob)) {
sfree(base64blob);
@ -4191,8 +4193,7 @@ static void do_ssh1_login(void *vctx)
unsigned char cookie[8];
unsigned char session_id[16];
int cipher_type;
void *publickey_blob;
int publickey_bloblen;
strbuf *publickey_blob;
char *publickey_comment;
int privatekey_available, privatekey_encrypted;
prompts_t *cur_prompt;
@ -4529,8 +4530,9 @@ static void do_ssh1_login(void *vctx)
if (keytype == SSH_KEYTYPE_SSH1 ||
keytype == SSH_KEYTYPE_SSH1_PUBLIC) {
const char *error;
s->publickey_blob = strbuf_new();
if (rsa_ssh1_loadpub(s->keyfile,
&s->publickey_blob, &s->publickey_bloblen,
BinarySink_UPCAST(s->publickey_blob),
&s->publickey_comment, &error)) {
s->privatekey_available = (keytype == SSH_KEYTYPE_SSH1);
if (!s->privatekey_available)
@ -4545,7 +4547,8 @@ static void do_ssh1_login(void *vctx)
error);
c_write_str(ssh, msgbuf);
sfree(msgbuf);
s->publickey_blob = NULL;
strbuf_free(s->publickey_blob);
s->publickey_blob = NULL;
}
} else {
char *msgbuf;
@ -4634,8 +4637,8 @@ static void do_ssh1_login(void *vctx)
}
}
if (s->publickey_blob) {
if (!memcmp(pkblob, s->publickey_blob,
s->publickey_bloblen)) {
if (!memcmp(pkblob, s->publickey_blob->s,
s->publickey_blob->len)) {
logeventf(ssh, "Pageant key #%d matches "
"configured key file", s->keyi);
s->tried_publickey = 1;
@ -5161,7 +5164,7 @@ static void do_ssh1_login(void *vctx)
/* Clear up */
if (s->publickey_blob) {
sfree(s->publickey_blob);
strbuf_free(s->publickey_blob);
sfree(s->publickey_comment);
}
@ -6456,8 +6459,7 @@ static struct kexinit_algorithm *ssh2_kexinit_addalg(struct kexinit_algorithm
*/
struct ssh_transient_hostkey_cache_entry {
const struct ssh_signkey *alg;
unsigned char *pub_blob;
int pub_len;
strbuf *pub_blob;
};
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;
while ((ent = delpos234(ssh->transient_hostkey_cache, 0)) != NULL) {
sfree(ent->pub_blob);
strbuf_free(ent->pub_blob);
sfree(ent);
}
freetree234(ssh->transient_hostkey_cache);
@ -6499,13 +6501,14 @@ static void ssh_store_transient_hostkey(
if ((ent = find234(ssh->transient_hostkey_cache, (void *)alg,
ssh_transient_hostkey_cache_find)) != NULL) {
sfree(ent->pub_blob);
strbuf_free(ent->pub_blob);
sfree(ent);
}
ent = snew(struct ssh_transient_hostkey_cache_entry);
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);
assert(retd == ent);
}
@ -6518,14 +6521,15 @@ static int ssh_verify_transient_hostkey(
if ((ent = find234(ssh->transient_hostkey_cache, (void *)alg,
ssh_transient_hostkey_cache_find)) != NULL) {
int this_len;
unsigned char *this_blob = alg->public_blob(key, &this_len);
strbuf *this_blob = strbuf_new();
alg->public_blob(key, BinarySink_UPCAST(this_blob));
if (this_len == ent->pub_len &&
!memcmp(this_blob, ent->pub_blob, this_len))
if (this_blob->len == ent->pub_blob->len &&
!memcmp(this_blob->s, ent->pub_blob->s,
this_blob->len))
toret = TRUE;
sfree(this_blob);
strbuf_free(this_blob);
}
return toret;
@ -7430,18 +7434,11 @@ static void do_ssh2_transport(void *vctx)
crStopV;
}
s->pktout = ssh2_pkt_init(SSH2_MSG_KEX_ECDH_INIT);
{
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);
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);
@ -7463,17 +7460,11 @@ static void do_ssh2_transport(void *vctx)
s->hostkeydata, s->hostkeylen);
{
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 hash"));
crStopV;
}
strbuf *pubpoint = strbuf_new();
ssh_ecdhkex_getpublic(s->eckey, BinarySink_UPCAST(pubpoint));
hash_string(ssh->kex->hash, ssh->exhash,
publicPoint, publicPointLength);
sfree(publicPoint);
pubpoint->u, pubpoint->len);
strbuf_free(pubpoint);
}
{
@ -9955,8 +9946,7 @@ static void do_ssh2_userauth(void *vctx)
char *username;
char *password;
int got_username;
void *publickey_blob;
int publickey_bloblen;
strbuf *publickey_blob;
int privatekey_available, privatekey_encrypted;
char *publickey_algorithm;
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_OPENSSH) {
const char *error;
s->publickey_blob =
ssh2_userkey_loadpub(s->keyfile,
s->publickey_blob = strbuf_new();
if (ssh2_userkey_loadpub(s->keyfile,
&s->publickey_algorithm,
&s->publickey_bloblen,
&s->publickey_comment, &error);
if (s->publickey_blob) {
BinarySink_UPCAST(s->publickey_blob),
&s->publickey_comment, &error)) {
s->privatekey_available = (keytype == SSH_KEYTYPE_SSH2);
if (!s->privatekey_available)
logeventf(ssh, "Key file contains public key only");
@ -10074,6 +10063,8 @@ static void do_ssh2_userauth(void *vctx)
error);
c_write_str(ssh, msgbuf);
sfree(msgbuf);
strbuf_free(s->publickey_blob);
s->publickey_blob = NULL;
}
} else {
char *msgbuf;
@ -10171,9 +10162,9 @@ static void do_ssh2_userauth(void *vctx)
/* See if configured key is in agent. */
for (keyi = 0; keyi < s->nkeys; keyi++) {
s->pklen = toint(GET_32BIT(p));
if (s->pklen == s->publickey_bloblen &&
!memcmp(p+4, s->publickey_blob,
s->publickey_bloblen)) {
if (s->pklen == s->publickey_blob->len &&
!memcmp(p+4, s->publickey_blob->s,
s->publickey_blob->len)) {
logeventf(ssh, "Pageant key #%d matches "
"configured key file", keyi);
s->keyi = keyi;
@ -10626,7 +10617,8 @@ static void do_ssh2_userauth(void *vctx)
put_bool(s->pktout, FALSE);
/* no signature included */
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);
logevent("Offered public key");
@ -10720,9 +10712,7 @@ static void do_ssh2_userauth(void *vctx)
}
if (key) {
unsigned char *pkblob, *sigblob, *sigdata;
int pkblob_len, sigblob_len, sigdata_len;
int p;
strbuf *pkblob, *sigdata, *sigblob;
/*
* 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_bool(s->pktout, TRUE); /* signature follows */
put_stringz(s->pktout, key->alg->name);
pkblob = key->alg->public_blob(key->data,
&pkblob_len);
put_string(s->pktout, pkblob, pkblob_len);
pkblob = strbuf_new();
key->alg->public_blob(key->data, BinarySink_UPCAST(pkblob));
put_string(s->pktout, pkblob->s, pkblob->len);
/*
* 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
* outgoing packet.
*/
sigdata_len = s->pktout->length - 5 + 4 +
ssh->v2_session_id_len;
if (ssh->remote_bugs & BUG_SSH2_PK_SESSIONID)
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);
p += ssh->v2_session_id_len;
memcpy(sigdata+p, s->pktout->data + 5,
s->pktout->length - 5);
p += s->pktout->length - 5;
assert(p == sigdata_len);
sigblob = key->alg->sign(key->data, (char *)sigdata,
sigdata_len, &sigblob_len);
ssh2_add_sigblob(ssh, s->pktout, pkblob, pkblob_len,
sigblob, sigblob_len);
sfree(pkblob);
sfree(sigblob);
sfree(sigdata);
sigdata = strbuf_new();
if (ssh->remote_bugs & BUG_SSH2_PK_SESSIONID) {
put_data(sigdata, ssh->v2_session_id,
ssh->v2_session_id_len);
} else {
put_string(sigdata, ssh->v2_session_id,
ssh->v2_session_id_len);
}
put_data(sigdata, s->pktout->data + 5,
s->pktout->length - 5);
sigblob = strbuf_new();
key->alg->sign(key->data, sigdata->s, sigdata->len,
BinarySink_UPCAST(sigblob));
strbuf_free(sigdata);
ssh2_add_sigblob(ssh, s->pktout, pkblob->s, pkblob->len,
sigblob->s, sigblob->len);
strbuf_free(pkblob);
strbuf_free(sigblob);
ssh2_pkt_send(ssh, s->pktout);
logevent("Sent public key signature");
@ -11363,7 +11347,7 @@ static void do_ssh2_userauth(void *vctx)
/* Clear up various bits and pieces from authentication. */
if (s->publickey_blob) {
sfree(s->publickey_algorithm);
sfree(s->publickey_blob);
strbuf_free(s->publickey_blob);
sfree(s->publickey_comment);
}
if (s->agent_response)

23
ssh.h
Просмотреть файл

@ -194,8 +194,8 @@ int rsastr_len(struct RSAKey *key);
void rsastr_fmt(char *str, struct RSAKey *key);
void rsa_fingerprint(char *str, int len, struct RSAKey *key);
int rsa_verify(struct RSAKey *key);
unsigned char *rsa_ssh1_public_blob(struct RSAKey *key, int *len,
RsaSsh1Order order);
void rsa_ssh1_public_blob(BinarySink *bs, struct RSAKey *key,
RsaSsh1Order order);
int rsa_public_blob_len(void *data, int maxlen);
void freersakey(struct RSAKey *key);
@ -228,7 +228,7 @@ struct ssh_kex;
const char *ssh_ecdhkex_curve_textname(const struct ssh_kex *kex);
void *ssh_ecdhkex_newkey(const struct ssh_kex *kex);
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);
/*
@ -400,14 +400,14 @@ struct ssh_signkey {
const char *data, int len);
void (*freekey) (void *key);
char *(*fmtkey) (void *key);
unsigned char *(*public_blob) (void *key, int *len);
unsigned char *(*private_blob) (void *key, int *len);
void (*public_blob)(void *key, BinarySink *);
void (*private_blob)(void *key, BinarySink *);
void *(*createkey) (const struct ssh_signkey *self,
const unsigned char *pub_blob, int pub_len,
const unsigned char *priv_blob, int priv_len);
void *(*openssh_createkey) (const struct ssh_signkey *self,
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
* consumed by openssh_createkey, always (at least so far...) take
* the form of a number of SSH-2 strings / mpints concatenated
@ -421,8 +421,7 @@ struct ssh_signkey {
const void *blob, int len);
int (*verifysig) (void *key, const char *sig, int siglen,
const char *data, int datalen);
unsigned char *(*sign) (void *key, const char *data, int datalen,
int *siglen);
void (*sign) (void *key, const char *data, int datalen, BinarySink *);
const char *name;
const char *keytype; /* for host key cache */
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);
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);
int rsa_ssh1_loadkey(const Filename *filename, struct RSAKey *key,
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,
const char *passphrase,
const char **errorstr);
unsigned char *ssh2_userkey_loadpub(const Filename *filename, char **algorithm,
int *pub_blob_len, char **commentptr,
const char **errorstr);
int ssh2_userkey_loadpub(const Filename *filename, char **algorithm,
BinarySink *bs,
char **commentptr, const char **errorstr);
int ssh2_save_userkey(const Filename *filename, struct ssh2_userkey *key,
char *passphrase);
const struct ssh_signkey *find_pubkey_alg(const char *name);

128
sshdss.c
Просмотреть файл

@ -271,72 +271,22 @@ static int dss_verifysig(void *key, const char *sig, int siglen,
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;
int plen, qlen, glen, ylen, bloblen;
int i;
unsigned char *blob, *p;
plen = (bignum_bitcount(dss->p) + 8) / 8;
qlen = (bignum_bitcount(dss->q) + 8) / 8;
glen = (bignum_bitcount(dss->g) + 8) / 8;
ylen = (bignum_bitcount(dss->y) + 8) / 8;
/*
* 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;
put_stringz(bs, "ssh-dss");
put_mp_ssh2(bs, dss->p);
put_mp_ssh2(bs, dss->q);
put_mp_ssh2(bs, dss->g);
put_mp_ssh2(bs, dss->y);
}
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;
int xlen, bloblen;
int i;
unsigned char *blob, *p;
xlen = (bignum_bitcount(dss->x) + 8) / 8;
/*
* 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;
put_mp_ssh2(bs, dss->x);
}
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;
}
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;
int bloblen, i;
bloblen =
ssh2_bignum_length(dss->p) +
ssh2_bignum_length(dss->q) +
ssh2_bignum_length(dss->g) +
ssh2_bignum_length(dss->y) +
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;
put_mp_ssh2(bs, dss->p);
put_mp_ssh2(bs, dss->q);
put_mp_ssh2(bs, dss->g);
put_mp_ssh2(bs, dss->y);
put_mp_ssh2(bs, dss->x);
}
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,
int *siglen)
static void dss_sign(void *key, const char *data, int datalen,
BinarySink *bs)
{
struct dss_key *dss = (struct dss_key *) key;
Bignum k, gkp, hash, kinv, hxr, r, s;
unsigned char digest[20];
unsigned char *bytes;
int nbytes, i;
int i;
SHA_Simple(data, datalen, digest);
@ -609,28 +541,14 @@ static unsigned char *dss_sign(void *key, const char *data, int datalen,
freebn(k);
freebn(hash);
/*
* Signature blob is
*
* string "ssh-dss"
* string two 20-byte numbers r and s, end to end
*
* 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);
}
put_stringz(bs, "ssh-dss");
put_uint32(bs, 40);
for (i = 0; i < 20; i++)
put_byte(bs, bignum_byte(r, 19 - i));
for (i = 0; i < 20; i++)
put_byte(bs, bignum_byte(s, 19 - i));
freebn(r);
freebn(s);
*siglen = nbytes;
return bytes;
}
const struct ssh_signkey ssh_dss = {

294
sshecc.c
Просмотреть файл

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

204
sshpubk.c
Просмотреть файл

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

145
sshrsa.c
Просмотреть файл

@ -439,28 +439,17 @@ int rsa_verify(struct RSAKey *key)
return 1;
}
unsigned char *rsa_ssh1_public_blob(struct RSAKey *key, int *len,
RsaSsh1Order order)
void rsa_ssh1_public_blob(BinarySink *bs, struct RSAKey *key,
RsaSsh1Order order)
{
int length, pos;
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;
put_uint32(bs, bignum_bitcount(key->modulus));
if (order == RSA_SSH1_EXPONENT_FIRST) {
pos += ssh1_write_bignum(ret + pos, key->exponent);
pos += ssh1_write_bignum(ret + pos, key->modulus);
put_mp_ssh1(bs, key->exponent);
put_mp_ssh1(bs, key->modulus);
} else {
pos += ssh1_write_bignum(ret + pos, key->modulus);
pos += ssh1_write_bignum(ret + pos, key->exponent);
put_mp_ssh1(bs, key->modulus);
put_mp_ssh1(bs, key->exponent);
}
*len = length;
return ret;
}
/* Given a public blob, determine its length. */
@ -588,78 +577,23 @@ static char *rsa2_fmtkey(void *key)
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;
int elen, mlen, bloblen;
int i;
unsigned char *blob, *p;
elen = (bignum_bitcount(rsa->exponent) + 8) / 8;
mlen = (bignum_bitcount(rsa->modulus) + 8) / 8;
/*
* 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;
put_stringz(bs, "ssh-rsa");
put_mp_ssh2(bs, rsa->exponent);
put_mp_ssh2(bs, rsa->modulus);
}
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;
int dlen, plen, qlen, ulen, bloblen;
int i;
unsigned char *blob, *p;
dlen = (bignum_bitcount(rsa->private_exponent) + 8) / 8;
plen = (bignum_bitcount(rsa->p) + 8) / 8;
qlen = (bignum_bitcount(rsa->q) + 8) / 8;
ulen = (bignum_bitcount(rsa->iqmp) + 8) / 8;
/*
* 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;
put_mp_ssh2(bs, rsa->private_exponent);
put_mp_ssh2(bs, rsa->p);
put_mp_ssh2(bs, rsa->q);
put_mp_ssh2(bs, rsa->iqmp);
}
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;
}
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;
int bloblen, i;
bloblen =
ssh2_bignum_length(rsa->modulus) +
ssh2_bignum_length(rsa->exponent) +
ssh2_bignum_length(rsa->private_exponent) +
ssh2_bignum_length(rsa->iqmp) +
ssh2_bignum_length(rsa->p) + ssh2_bignum_length(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;
put_mp_ssh2(bs, rsa->modulus);
put_mp_ssh2(bs, rsa->exponent);
put_mp_ssh2(bs, rsa->private_exponent);
put_mp_ssh2(bs, rsa->iqmp);
put_mp_ssh2(bs, rsa->p);
put_mp_ssh2(bs, rsa->q);
}
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;
}
static unsigned char *rsa2_sign(void *key, const char *data, int datalen,
int *siglen)
static void rsa2_sign(void *key, const char *data, int datalen,
BinarySink *bs)
{
struct RSAKey *rsa = (struct RSAKey *) key;
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);
freebn(in);
put_stringz(bs, "ssh-rsa");
nbytes = (bignum_bitcount(out) + 7) / 8;
bytes = snewn(4 + 7 + 4 + nbytes, unsigned char);
PUT_32BIT(bytes, 7);
memcpy(bytes + 4, "ssh-rsa", 7);
PUT_32BIT(bytes + 4 + 7, nbytes);
put_uint32(bs, nbytes);
for (i = 0; i < nbytes; i++)
bytes[4 + 7 + 4 + i] = bignum_byte(out, nbytes - 1 - i);
freebn(out);
put_byte(bs, bignum_byte(out, nbytes - 1 - i));
*siglen = 4 + 7 + 4 + nbytes;
return bytes;
freebn(out);
}
const struct ssh_signkey ssh_rsa = {

Просмотреть файл

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

Просмотреть файл

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