static void send_ssh_cmsg_session_key(Conn *c) { int i, n, buflen, serverkeylen, hostkeylen; mpint *b; uchar *buf; Msg *m; RSApub *ksmall, *kbig; m = allocmsg(c, SSH_CMSG_SESSION_KEY, 2048); putbyte(m, c->cipher->id); putbytes(m, c->cookie, COOKIELEN); serverkeylen = mpsignif(c->serverkey->n); hostkeylen = mpsignif(c->hostkey->n); ksmall = kbig = nil; if(serverkeylen+128 <= hostkeylen){ ksmall = c->serverkey; kbig = c->hostkey; }else if(hostkeylen+128 <= serverkeylen){ ksmall = c->hostkey; kbig = c->serverkey; }else error("server session and host keys do not differ by at least 128 bits"); buflen = (mpsignif(kbig->n)+7)/8; buf = emalloc(buflen); debug(DBG_CRYPTO, "session key is %.*H\n", SESSKEYLEN, c->sesskey); memmove(buf, c->sesskey, SESSKEYLEN); for(i = 0; i < SESSIDLEN; i++) buf[i] ^= c->sessid[i]; debug(DBG_CRYPTO, "munged session key is %.*H\n", SESSKEYLEN, buf); b = rsaencryptbuf(ksmall, buf, SESSKEYLEN); n = (mpsignif(ksmall->n)+7) / 8; mptoberjust(b, buf, n); mpfree(b); debug(DBG_CRYPTO, "encrypted with ksmall is %.*H\n", n, buf); b = rsaencryptbuf(kbig, buf, n); putmpint(m, b); debug(DBG_CRYPTO, "encrypted with kbig is %B\n", b); mpfree(b); memset(buf, 0, buflen); free(buf); putlong(m, c->flags); sendmsg(m); }
static int authrsafn(Conn *c) { uint8_t chalbuf[32+SESSIDLEN], response[MD5dlen]; char *s, *p; int afd, ret; AuthRpc *rpc; Msg *m; mpint *chal, *decr, *unpad, *mod; debug(DBG_AUTH, "rsa!\n"); if((afd = open("/mnt/factotum/rpc", ORDWR)) < 0){ debug(DBG_AUTH, "open /mnt/factotum/rpc: %r\n"); return -1; } if((rpc = auth_allocrpc(afd)) == nil){ debug(DBG_AUTH, "auth_allocrpc: %r\n"); close(afd); return -1; } s = "proto=rsa role=client"; if(auth_rpc(rpc, "start", s, strlen(s)) != ARok){ debug(DBG_AUTH, "auth_rpc start %s failed: %r\n", s); auth_freerpc(rpc); close(afd); return -1; } ret = -1; debug(DBG_AUTH, "trying factotum rsa keys\n"); while(auth_rpc(rpc, "read", nil, 0) == ARok){ debug(DBG_AUTH, "try %s\n", (char*)rpc->arg); mod = strtomp(rpc->arg, nil, 16, nil); m = allocmsg(c, SSH_CMSG_AUTH_RSA, 16+(mpsignif(mod)+7/8)); putmpint(m, mod); sendmsg(m); mpfree(mod); m = recvmsg(c, -1); switch(m->type){ case SSH_SMSG_FAILURE: debug(DBG_AUTH, "\tnot accepted %s\n", (char*)rpc->arg); free(m); continue; default: badmsg(m, 0); case SSH_SMSG_AUTH_RSA_CHALLENGE: break; } chal = getmpint(m); debug(DBG_AUTH, "\tgot challenge %B\n", chal); free(m); p = mptoa(chal, 16, nil, 0); mpfree(chal); if(p == nil){ debug(DBG_AUTH, "\tmptoa failed: %r\n"); unpad = mpnew(0); goto Keepgoing; } if(auth_rpc(rpc, "write", p, strlen(p)) != ARok){ debug(DBG_AUTH, "\tauth_rpc write failed: %r\n"); free(p); unpad = mpnew(0); /* it will fail, we'll go round again */ goto Keepgoing; } free(p); if(auth_rpc(rpc, "read", nil, 0) != ARok){ debug(DBG_AUTH, "\tauth_rpc read failed: %r\n"); unpad = mpnew(0); goto Keepgoing; } decr = strtomp(rpc->arg, nil, 16, nil); debug(DBG_AUTH, "\tdecrypted %B\n", decr); unpad = rsaunpad(decr); debug(DBG_AUTH, "\tunpadded %B\n", unpad); mpfree(decr); Keepgoing: mptoberjust(unpad, chalbuf, 32); mpfree(unpad); debug(DBG_AUTH, "\trjusted %.*H\n", 32, chalbuf); memmove(chalbuf+32, c->sessid, SESSIDLEN); debug(DBG_AUTH, "\tappend sesskey %.*H\n", 32, chalbuf); md5(chalbuf, 32+SESSIDLEN, response, nil); m = allocmsg(c, SSH_CMSG_AUTH_RSA_RESPONSE, MD5dlen); putbytes(m, response, MD5dlen); sendmsg(m); m = recvmsg(c, -1); switch(m->type){ case SSH_SMSG_FAILURE: free(m); continue; default: badmsg(m, 0); case SSH_SMSG_SUCCESS: break; } ret = 0; break; } auth_freerpc(rpc); close(afd); return ret; }
void handlefullmsg(Conn *c, Achan *a) { int i; uint32_t chan, len, n, rt; uint8_t type; Msg *m, mm; Msg *r; Key *k; int nk; mpint *mod, *ek, *chal; uint8_t sessid[16]; uint8_t chalbuf[32]; uint8_t digest[16]; DigestState *s; static int first; assert(a->len == a->ndata); chan = a->chan; mm.rp = a->data; mm.ep = a->data+a->ndata; mm.c = c; m = &mm; type = getbyte(m); if(first == 0){ first++; fmtinstall('H', encodefmt); } switch(type){ default: debug(DBG_AUTH, "unknown msg type\n"); Failure: debug(DBG_AUTH, "agent sending failure\n"); r = allocmsg(m->c, SSH_MSG_CHANNEL_DATA, 13); putlong(r, chan); putlong(r, 5); putlong(r, 1); putbyte(r, SSH_AGENT_FAILURE); sendmsg(r); return; case SSH_AGENTC_REQUEST_RSA_IDENTITIES: debug(DBG_AUTH, "agent request identities\n"); nk = listkeys(&k); if(nk < 0) goto Failure; len = 1+4; /* type, nk */ for(i=0; i<nk; i++){ len += 4; len += 2+(mpsignif(k[i].ek)+7)/8; len += 2+(mpsignif(k[i].mod)+7)/8; len += 4+strlen(k[i].comment); } r = allocmsg(m->c, SSH_MSG_CHANNEL_DATA, 12+len); putlong(r, chan); putlong(r, len+4); putlong(r, len); putbyte(r, SSH_AGENT_RSA_IDENTITIES_ANSWER); putlong(r, nk); for(i=0; i<nk; i++){ debug(DBG_AUTH, "\t%B %B %s\n", k[i].ek, k[i].mod, k[i].comment); putlong(r, mpsignif(k[i].mod)); putmpint(r, k[i].ek); putmpint(r, k[i].mod); putstring(r, k[i].comment); mpfree(k[i].ek); mpfree(k[i].mod); free(k[i].comment); } free(k); sendmsg(r); break; case SSH_AGENTC_RSA_CHALLENGE: n = getlong(m); USED(n); /* number of bits in key; who cares? */ ek = getmpint(m); mod = getmpint(m); chal = getmpint(m); memmove(sessid, getbytes(m, 16), 16); rt = getlong(m); debug(DBG_AUTH, "agent challenge %B %B %B %ud (%p %p)\n", ek, mod, chal, rt, m->rp, m->ep); if(rt != 1 || dorsa(mod, ek, chal, chalbuf) < 0){ mpfree(ek); mpfree(mod); mpfree(chal); goto Failure; } s = md5(chalbuf, 32, nil, nil); md5(sessid, 16, digest, s); r = allocmsg(m->c, SSH_MSG_CHANNEL_DATA, 12+1+16); putlong(r, chan); putlong(r, 4+16+1); putlong(r, 16+1); putbyte(r, SSH_AGENT_RSA_RESPONSE); putbytes(r, digest, 16); debug(DBG_AUTH, "digest %.16H\n", digest); sendmsg(r); mpfree(ek); mpfree(mod); mpfree(chal); return; case SSH_AGENTC_ADD_RSA_IDENTITY: goto Failure; /* n = getlong(m); pubmod = getmpint(m); pubexp = getmpint(m); privexp = getmpint(m); pinversemodq = getmpint(m); p = getmpint(m); q = getmpint(m); comment = getstring(m); add to factotum; send SSH_AGENT_SUCCESS or SSH_AGENT_FAILURE; */ case SSH_AGENTC_REMOVE_RSA_IDENTITY: goto Failure; /* n = getlong(m); pubmod = getmpint(m); pubexp = getmpint(m); tell factotum to del key send SSH_AGENT_SUCCESS or SSH_AGENT_FAILURE; */ } }