1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-07-05 21:42:47 -05: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

156
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
* 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)