const static struct ssh_signkey *hostkey_algs[] = { &ssh_rsa, &ssh_dss };
const static struct ssh_mac *macs[] = {
- &ssh_hmac_sha1, &ssh_hmac_sha1_96, &ssh_hmac_md5
+ &ssh_hmac_sha256, &ssh_hmac_sha1, &ssh_hmac_sha1_96, &ssh_hmac_md5
};
const static struct ssh_mac *buggymacs[] = {
&ssh_hmac_sha1_buggy, &ssh_hmac_sha1_96_buggy, &ssh_hmac_md5
static unsigned long ssh_pkt_getuint32(struct Packet *pkt);
static int ssh2_pkt_getbool(struct Packet *pkt);
static void ssh_pkt_getstring(struct Packet *pkt, char **p, int *length);
-static void ssh2_timer(void *ctx, long now);
+static void ssh2_timer(void *ctx, unsigned long now);
static void do_ssh2_transport(Ssh ssh, void *vin, int inlen,
struct Packet *pktin);
static void ssh2_msg_unexpected(Ssh ssh, struct Packet *pktin);
unsigned long incoming_data_size, outgoing_data_size, deferred_data_size;
unsigned long max_data_size;
int kex_in_progress;
- long next_rekey, last_rekey;
+ unsigned long next_rekey, last_rekey;
char *deferred_rekey_reason; /* points to STATIC string; don't free */
/*
/* See if that gives us a valid packet. */
if (ssh->scmac->verresult(ssh->sc_mac_ctx,
st->pktin->data + st->packetlen) &&
- (st->len = GET_32BIT(st->pktin->data)) + 4 == st->packetlen)
+ ((st->len = toint(GET_32BIT(st->pktin->data))) ==
+ st->packetlen-4))
break;
if (st->packetlen >= OUR_V2_PACKETLIMIT) {
bombout(("No valid incoming packet found"));
/*
* Now get the length figure.
*/
- st->len = GET_32BIT(st->pktin->data);
+ st->len = toint(GET_32BIT(st->pktin->data));
/*
* _Completely_ silly lengths should be stomped on before they
*length = 0;
if (pkt->length - pkt->savedpos < 4)
return;
- len = GET_32BIT(pkt->body + pkt->savedpos);
+ len = toint(GET_32BIT(pkt->body + pkt->savedpos));
if (len < 0)
return;
*length = len;
* See if this is in fact an ssh-rsa signature and a buggy
* server; otherwise we can just do this the easy way.
*/
- if ((ssh->remote_bugs & BUG_SSH2_RSA_PADDING) &&
+ if ((ssh->remote_bugs & BUG_SSH2_RSA_PADDING) && pkblob_len > 4+7+4 &&
(GET_32BIT(pkblob) == 7 && !memcmp(pkblob+4, "ssh-rsa", 7))) {
int pos, len, siglen;
*/
pos = 4+7; /* skip over "ssh-rsa" */
- pos += 4 + GET_32BIT(pkblob+pos); /* skip over exponent */
- len = GET_32BIT(pkblob+pos); /* find length of modulus */
+ len = toint(GET_32BIT(pkblob+pos)); /* get length of exponent */
+ if (len < 0 || len > pkblob_len - pos - 4)
+ goto give_up;
+ pos += 4 + len; /* skip over exponent */
+ if (pkblob_len - pos < 4)
+ goto give_up;
+ len = toint(GET_32BIT(pkblob+pos)); /* find length of modulus */
+ if (len < 0 || len > pkblob_len - pos - 4)
+ goto give_up;
pos += 4; /* find modulus itself */
while (len > 0 && pkblob[pos] == 0)
len--, pos++;
* Now find the signature integer.
*/
pos = 4+7; /* skip over "ssh-rsa" */
- siglen = GET_32BIT(sigblob+pos);
+ if (sigblob_len < pos+4)
+ goto give_up;
+ siglen = toint(GET_32BIT(sigblob+pos));
+ if (siglen != sigblob_len - pos - 4)
+ goto give_up;
/* debug(("signature length is %d\n", siglen)); */
if (len != siglen) {
return;
}
- /* Otherwise fall through and do it the easy way. */
+ /* Otherwise fall through and do it the easy way. We also come
+ * here as a fallback if we discover above that the key blob
+ * is misformatted in some way. */
+ give_up:;
}
ssh2_pkt_addstring_start(pkt);
{
int i, j, ret;
unsigned char cookie[8], *ptr;
- struct RSAKey servkey, hostkey;
struct MD5Context md5c;
struct do_ssh1_login_state {
int crLine;
int commentlen;
int dlgret;
Filename *keyfile;
+ struct RSAKey servkey, hostkey;
};
crState(do_ssh1_login_state);
}
memcpy(cookie, ptr, 8);
- if (!ssh1_pkt_getrsakey(pktin, &servkey, &s->keystr1) ||
- !ssh1_pkt_getrsakey(pktin, &hostkey, &s->keystr2)) {
+ if (!ssh1_pkt_getrsakey(pktin, &s->servkey, &s->keystr1) ||
+ !ssh1_pkt_getrsakey(pktin, &s->hostkey, &s->keystr2)) {
bombout(("Failed to read SSH-1 public keys from public key packet"));
crStop(0);
}
char logmsg[80];
logevent("Host key fingerprint is:");
strcpy(logmsg, " ");
- hostkey.comment = NULL;
+ s->hostkey.comment = NULL;
rsa_fingerprint(logmsg + strlen(logmsg),
- sizeof(logmsg) - strlen(logmsg), &hostkey);
+ sizeof(logmsg) - strlen(logmsg), &s->hostkey);
logevent(logmsg);
}
ssh->v1_local_protoflags |= SSH1_PROTOFLAG_SCREEN_NUMBER;
MD5Init(&md5c);
- MD5Update(&md5c, s->keystr2, hostkey.bytes);
- MD5Update(&md5c, s->keystr1, servkey.bytes);
+ MD5Update(&md5c, s->keystr2, s->hostkey.bytes);
+ MD5Update(&md5c, s->keystr1, s->servkey.bytes);
MD5Update(&md5c, cookie, 8);
MD5Final(s->session_id, &md5c);
/*
* Verify that the `bits' and `bytes' parameters match.
*/
- if (hostkey.bits > hostkey.bytes * 8 ||
- servkey.bits > servkey.bytes * 8) {
+ if (s->hostkey.bits > s->hostkey.bytes * 8 ||
+ s->servkey.bits > s->servkey.bytes * 8) {
bombout(("SSH-1 public keys were badly formatted"));
crStop(0);
}
- s->len = (hostkey.bytes > servkey.bytes ? hostkey.bytes : servkey.bytes);
+ s->len = (s->hostkey.bytes > s->servkey.bytes ?
+ s->hostkey.bytes : s->servkey.bytes);
s->rsabuf = snewn(s->len, unsigned char);
/*
* First format the key into a string.
*/
- int len = rsastr_len(&hostkey);
+ int len = rsastr_len(&s->hostkey);
char fingerprint[100];
char *keystr = snewn(len, char);
- rsastr_fmt(keystr, &hostkey);
- rsa_fingerprint(fingerprint, sizeof(fingerprint), &hostkey);
+ rsastr_fmt(keystr, &s->hostkey);
+ rsa_fingerprint(fingerprint, sizeof(fingerprint), &s->hostkey);
ssh_set_frozen(ssh, 1);
s->dlgret = verify_ssh_host_key(ssh->frontend,
s->rsabuf[i] ^= s->session_id[i];
}
- if (hostkey.bytes > servkey.bytes) {
- ret = rsaencrypt(s->rsabuf, 32, &servkey);
+ if (s->hostkey.bytes > s->servkey.bytes) {
+ ret = rsaencrypt(s->rsabuf, 32, &s->servkey);
if (ret)
- ret = rsaencrypt(s->rsabuf, servkey.bytes, &hostkey);
+ ret = rsaencrypt(s->rsabuf, s->servkey.bytes, &s->hostkey);
} else {
- ret = rsaencrypt(s->rsabuf, 32, &hostkey);
+ ret = rsaencrypt(s->rsabuf, 32, &s->hostkey);
if (ret)
- ret = rsaencrypt(s->rsabuf, hostkey.bytes, &servkey);
+ ret = rsaencrypt(s->rsabuf, s->hostkey.bytes, &s->servkey);
}
if (!ret) {
bombout(("SSH-1 public key encryptions failed due to bad formatting"));
ssh->crcda_ctx = crcda_make_context();
logevent("Installing CRC compensation attack detector");
- if (servkey.modulus) {
- sfree(servkey.modulus);
- servkey.modulus = NULL;
+ if (s->servkey.modulus) {
+ sfree(s->servkey.modulus);
+ s->servkey.modulus = NULL;
}
- if (servkey.exponent) {
- sfree(servkey.exponent);
- servkey.exponent = NULL;
+ if (s->servkey.exponent) {
+ sfree(s->servkey.exponent);
+ s->servkey.exponent = NULL;
}
- if (hostkey.modulus) {
- sfree(hostkey.modulus);
- hostkey.modulus = NULL;
+ if (s->hostkey.modulus) {
+ sfree(s->hostkey.modulus);
+ s->hostkey.modulus = NULL;
}
- if (hostkey.exponent) {
- sfree(hostkey.exponent);
- hostkey.exponent = NULL;
+ if (s->hostkey.exponent) {
+ sfree(s->hostkey.exponent);
+ s->hostkey.exponent = NULL;
}
crWaitUntil(pktin);
if (s->response && s->responselen >= 5 &&
s->response[4] == SSH1_AGENT_RSA_IDENTITIES_ANSWER) {
s->p = s->response + 5;
- s->nkeys = GET_32BIT(s->p);
+ s->nkeys = toint(GET_32BIT(s->p));
+ if (s->nkeys < 0) {
+ logeventf(ssh, "Pageant reported negative key count %d",
+ s->nkeys);
+ s->nkeys = 0;
+ }
s->p += 4;
logeventf(ssh, "Pageant has %d SSH-1 keys", s->nkeys);
for (s->keyi = 0; s->keyi < s->nkeys; s->keyi++) {
int n, ok = FALSE;
do { /* do while (0) to make breaking easy */
n = ssh1_read_bignum
- (s->p, s->responselen-(s->p-s->response),
+ (s->p, toint(s->responselen-(s->p-s->response)),
&s->key.exponent);
if (n < 0)
break;
s->p += n;
n = ssh1_read_bignum
- (s->p, s->responselen-(s->p-s->response),
+ (s->p, toint(s->responselen-(s->p-s->response)),
&s->key.modulus);
if (n < 0)
- break;
+ break;
s->p += n;
if (s->responselen - (s->p-s->response) < 4)
break;
- s->commentlen = GET_32BIT(s->p);
+ s->commentlen = toint(GET_32BIT(s->p));
s->p += 4;
- if (s->responselen - (s->p-s->response) <
+ if (s->commentlen < 0 ||
+ toint(s->responselen - (s->p-s->response)) <
s->commentlen)
break;
s->commentp = (char *)s->p;
/* XXX: rport_acceptall may not represent
* what was used to open the original connection,
* since it's reconfigurable. */
- ssh2_pkt_addstring(pktout, "0.0.0.0");
+ ssh2_pkt_addstring(pktout, "");
} else {
- ssh2_pkt_addstring(pktout, "127.0.0.1");
+ ssh2_pkt_addstring(pktout, "localhost");
}
ssh2_pkt_adduint32(pktout, epf->sport);
ssh2_pkt_send(ssh, pktout);
if (epf->saddr) {
ssh2_pkt_addstring(pktout, epf->saddr);
} else if (conf_get_int(conf, CONF_rport_acceptall)) {
- ssh2_pkt_addstring(pktout, "0.0.0.0");
+ ssh2_pkt_addstring(pktout, "");
} else {
- ssh2_pkt_addstring(pktout, "127.0.0.1");
+ ssh2_pkt_addstring(pktout, "localhost");
}
ssh2_pkt_adduint32(pktout, epf->sport);
ssh2_pkt_send(ssh, pktout);
{
/* Remote side is trying to open a channel to talk to a
* forwarded port. Give them back a local channel number. */
- struct ssh_channel *c;
struct ssh_rportfwd pf, *pfp;
int remoteid;
int hostsize, port;
char *host;
const char *e;
- c = snew(struct ssh_channel);
- c->ssh = ssh;
remoteid = ssh_pkt_getuint32(pktin);
ssh_pkt_getstring(pktin, &host, &hostsize);
send_packet(ssh, SSH1_MSG_CHANNEL_OPEN_FAILURE,
PKT_INT, remoteid, PKT_END);
} else {
+ struct ssh_channel *c = snew(struct ssh_channel);
+ c->ssh = ssh;
+
logeventf(ssh, "Received remote port open request for %s:%d",
pf.dhost, port);
e = pfd_newconnect(&c->u.pfd.s, pf.dhost, port,
ssh_pkt_getstring(pktin, &str, &len); /* server->client language */
s->ignorepkt = ssh2_pkt_getbool(pktin) && !s->guessok;
+ ssh->exhash = ssh->kex->hash->init();
+ hash_string(ssh->kex->hash, ssh->exhash, ssh->v_c, strlen(ssh->v_c));
+ hash_string(ssh->kex->hash, ssh->exhash, ssh->v_s, strlen(ssh->v_s));
+ hash_string(ssh->kex->hash, ssh->exhash,
+ s->our_kexinit, s->our_kexinitlen);
+ sfree(s->our_kexinit);
+ if (pktin->length > 5)
+ hash_string(ssh->kex->hash, ssh->exhash,
+ pktin->data + 5, pktin->length - 5);
+
if (s->warn_kex) {
ssh_set_frozen(ssh, 1);
s->dlgret = askalg(ssh->frontend, "key-exchange algorithm",
}
}
- ssh->exhash = ssh->kex->hash->init();
- hash_string(ssh->kex->hash, ssh->exhash, ssh->v_c, strlen(ssh->v_c));
- hash_string(ssh->kex->hash, ssh->exhash, ssh->v_s, strlen(ssh->v_s));
- hash_string(ssh->kex->hash, ssh->exhash,
- s->our_kexinit, s->our_kexinitlen);
- sfree(s->our_kexinit);
- if (pktin->length > 5)
- hash_string(ssh->kex->hash, ssh->exhash,
- pktin->data + 5, pktin->length - 5);
-
if (s->ignorepkt) /* first_kex_packet_follows */
crWaitUntilV(pktin); /* Ignore packet */
}
is_int = FALSE;
} else {
int maybe_int = FALSE, maybe_str = FALSE;
-#define CHECK_HYPOTHESIS(offset, result) \
- do { \
- long q = offset; \
- if (q >= 0 && q+4 <= len) { \
- q = q + 4 + GET_32BIT(p+q); \
- if (q >= 0 && q+4 <= len && \
- ((q = q + 4 + GET_32BIT(p+q))!= 0) && q == len) \
- result = TRUE; \
- } \
- } while(0)
+#define CHECK_HYPOTHESIS(offset, result) \
+ do \
+ { \
+ int q = toint(offset); \
+ if (q >= 0 && q+4 <= len) { \
+ q = toint(q + 4 + GET_32BIT(p+q)); \
+ if (q >= 0 && q+4 <= len && \
+ ((q = toint(q + 4 + GET_32BIT(p+q))) != 0) && \
+ q == len) \
+ result = TRUE; \
+ } \
+ } while(0)
CHECK_HYPOTHESIS(4+1, maybe_int);
CHECK_HYPOTHESIS(4+num+1, maybe_str);
#undef CHECK_HYPOTHESIS
ssh2_pkt_adduint32(pktout, ssh->x11disp->screennum);
ssh2_pkt_send(ssh, pktout);
- crWaitUntilV(pktin);
+ /* Wait to be called back with either a response packet, or NULL
+ * meaning clean up and free our data */
+ crReturnV;
if (pktin) {
if (pktin->type == SSH2_MSG_CHANNEL_SUCCESS) {
ssh2_setup_agent, s);
ssh2_pkt_send(ssh, pktout);
- crWaitUntilV(pktin);
+ /* Wait to be called back with either a response packet, or NULL
+ * meaning clean up and free our data */
+ crReturnV;
if (pktin) {
if (pktin->type == SSH2_MSG_CHANNEL_SUCCESS) {
ssh2_pkt_send(ssh, pktout);
ssh->state = SSH_STATE_INTERMED;
- crWaitUntilV(pktin);
+ /* Wait to be called back with either a response packet, or NULL
+ * meaning clean up and free our data */
+ crReturnV;
if (pktin) {
if (pktin->type == SSH2_MSG_CHANNEL_SUCCESS) {
s->env_left = s->num_env;
while (s->env_left > 0) {
- crWaitUntilV(pktin);
+ /* Wait to be called back with either a response packet,
+ * or NULL meaning clean up and free our data */
+ crReturnV;
if (!pktin) goto out;
if (pktin->type == SSH2_MSG_CHANNEL_SUCCESS)
s->env_ok++;
int keyi;
unsigned char *p;
p = s->agent_response + 5;
- s->nkeys = GET_32BIT(p);
+ s->nkeys = toint(GET_32BIT(p));
+
+ /*
+ * Vet the Pageant response to ensure that the key
+ * count and blob lengths make sense.
+ */
+ if (s->nkeys < 0) {
+ logeventf(ssh, "Pageant response contained a negative"
+ " key count %d", s->nkeys);
+ s->nkeys = 0;
+ goto done_agent_query;
+ } else {
+ unsigned char *q = p + 4;
+ int lenleft = s->agent_responselen - 5 - 4;
+
+ for (keyi = 0; keyi < s->nkeys; keyi++) {
+ int bloblen, commentlen;
+ if (lenleft < 4) {
+ logeventf(ssh, "Pageant response was truncated");
+ s->nkeys = 0;
+ goto done_agent_query;
+ }
+ bloblen = toint(GET_32BIT(q));
+ if (bloblen < 0 || bloblen > lenleft) {
+ logeventf(ssh, "Pageant response was truncated");
+ s->nkeys = 0;
+ goto done_agent_query;
+ }
+ lenleft -= 4 + bloblen;
+ q += 4 + bloblen;
+ commentlen = toint(GET_32BIT(q));
+ if (commentlen < 0 || commentlen > lenleft) {
+ logeventf(ssh, "Pageant response was truncated");
+ s->nkeys = 0;
+ goto done_agent_query;
+ }
+ lenleft -= 4 + commentlen;
+ q += 4 + commentlen;
+ }
+ }
+
p += 4;
logeventf(ssh, "Pageant has %d SSH-2 keys", s->nkeys);
if (s->publickey_blob) {
/* See if configured key is in agent. */
for (keyi = 0; keyi < s->nkeys; keyi++) {
- s->pklen = GET_32BIT(p);
+ s->pklen = toint(GET_32BIT(p));
if (s->pklen == s->publickey_bloblen &&
!memcmp(p+4, s->publickey_blob,
s->publickey_bloblen)) {
break;
}
p += 4 + s->pklen;
- p += GET_32BIT(p) + 4; /* comment */
+ p += toint(GET_32BIT(p)) + 4; /* comment */
}
if (!s->pkblob_in_agent) {
logevent("Configured key file not in Pageant");
} else {
logevent("Failed to get reply from Pageant");
}
+ done_agent_query:;
}
}
logeventf(ssh, "Trying Pageant key #%d", s->keyi);
/* Unpack key from agent response */
- s->pklen = GET_32BIT(s->agentp);
+ s->pklen = toint(GET_32BIT(s->agentp));
s->agentp += 4;
s->pkblob = (char *)s->agentp;
s->agentp += s->pklen;
- s->alglen = GET_32BIT(s->pkblob);
+ s->alglen = toint(GET_32BIT(s->pkblob));
s->alg = s->pkblob + 4;
- s->commentlen = GET_32BIT(s->agentp);
+ s->commentlen = toint(GET_32BIT(s->agentp));
s->agentp += 4;
s->commentp = (char *)s->agentp;
s->agentp += s->commentlen;
s->ret = vret;
sfree(s->agentreq);
if (s->ret) {
- if (s->ret[4] == SSH2_AGENT_SIGN_RESPONSE) {
+ if (s->retlen >= 9 &&
+ s->ret[4] == SSH2_AGENT_SIGN_RESPONSE &&
+ GET_32BIT(s->ret + 5) <= (unsigned)(s->retlen-9)) {
logevent("Sending Pageant's response");
ssh2_add_sigblob(ssh, s->pktout,
s->pkblob, s->pklen,
ssh->packet_dispatch[SSH2_MSG_DEBUG] = ssh2_msg_debug;
}
-static void ssh2_timer(void *ctx, long now)
+static void ssh2_timer(void *ctx, unsigned long now)
{
Ssh ssh = (Ssh)ctx;
return;
if (!ssh->kex_in_progress && conf_get_int(ssh->conf, CONF_ssh_rekey_time) != 0 &&
- now - ssh->next_rekey >= 0) {
+ now == ssh->next_rekey) {
do_ssh2_transport(ssh, "timeout", -1, NULL);
}
}
while (ssh->qhead) {
struct queued_handler *qh = ssh->qhead;
ssh->qhead = qh->next;
- sfree(ssh->qhead);
+ sfree(qh);
}
ssh->qhead = ssh->qtail = NULL;
rekey_time = conf_get_int(conf, CONF_ssh_rekey_time);
if (conf_get_int(ssh->conf, CONF_ssh_rekey_time) != rekey_time &&
rekey_time != 0) {
- long new_next = ssh->last_rekey + rekey_time*60*TICKSPERSEC;
- long now = GETTICKCOUNT();
+ unsigned long new_next = ssh->last_rekey + rekey_time*60*TICKSPERSEC;
+ unsigned long now = GETTICKCOUNT();
- if (new_next - now < 0) {
+ if (now - ssh->last_rekey > rekey_time*60*TICKSPERSEC) {
rekeying = "timeout shortened";
} else {
ssh->next_rekey = schedule_timer(new_next - now, ssh2_timer, ssh);