static void recv_ssh_cmsg_session_key(Conn *c, AuthRpc *rpc) { int i, id, n, serverkeylen, hostkeylen; mpint *a, *b; uchar *buf; Msg *m; RSApriv *ksmall, *kbig; m = recvmsg(c, SSH_CMSG_SESSION_KEY); id = getbyte(m); c->cipher = nil; for(i=0; i<c->nokcipher; i++) if(c->okcipher[i]->id == id) c->cipher = c->okcipher[i]; if(c->cipher == nil) sysfatal("invalid cipher selected"); if(memcmp(getbytes(m, COOKIELEN), c->cookie, COOKIELEN) != 0) sysfatal("bad cookie"); serverkeylen = mpsignif(c->serverkey->n); hostkeylen = mpsignif(c->hostkey->n); ksmall = kbig = nil; if(serverkeylen+128 <= hostkeylen){ ksmall = c->serverpriv; kbig = nil; }else if(hostkeylen+128 <= serverkeylen){ ksmall = nil; kbig = c->serverpriv; }else sysfatal("server session and host keys do not differ by at least 128 bits"); b = getmpint(m); debug(DBG_CRYPTO, "encrypted with kbig is %B\n", b); if(kbig){ a = rsadecrypt(kbig, b, nil); mpfree(b); b = a; }else b = rpcdecrypt(rpc, b); a = rsaunpad(b); mpfree(b); b = a; debug(DBG_CRYPTO, "encrypted with ksmall is %B\n", b); if(ksmall){ a = rsadecrypt(ksmall, b, nil); mpfree(b); b = a; }else b = rpcdecrypt(rpc, b); a = rsaunpad(b); mpfree(b); b = a; debug(DBG_CRYPTO, "munged is %B\n", b); n = (mpsignif(b)+7)/8; if(n > SESSKEYLEN) sysfatal("client sent short session key"); buf = emalloc(SESSKEYLEN); mptoberjust(b, buf, SESSKEYLEN); mpfree(b); for(i=0; i<SESSIDLEN; i++) buf[i] ^= c->sessid[i]; memmove(c->sesskey, buf, SESSKEYLEN); debug(DBG_CRYPTO, "unmunged is %.*H\n", SESSKEYLEN, buf); c->flags = getlong(m); free(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; }
static int dorsa(mpint *mod, mpint *exp, mpint *chal, uint8_t chalbuf[32]) { int afd; AuthRpc *rpc; mpint *m; char buf[4096], *p; mpint *decr, *unpad; USED(exp); snprint(buf, sizeof buf, "proto=rsa service=ssh role=client"); 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; } if(auth_rpc(rpc, "start", buf, strlen(buf)) != ARok){ debug(DBG_AUTH, "auth_rpc start failed: %r\n"); Die: auth_freerpc(rpc); close(afd); return -1; } m = nil; 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); m = strtomp(rpc->arg, nil, 16, nil); if(mpcmp(m, mod) == 0) break; mpfree(m); m = nil; } if(m == nil) goto Die; mpfree(m); p = mptoa(chal, 16, nil, 0); if(p == nil){ debug(DBG_AUTH, "\tmptoa failed: %r\n"); goto Die; } if(auth_rpc(rpc, "write", p, strlen(p)) != ARok){ debug(DBG_AUTH, "\tauth_rpc write failed: %r\n"); free(p); goto Die; } free(p); if(auth_rpc(rpc, "read", nil, 0) != ARok){ debug(DBG_AUTH, "\tauth_rpc read failed: %r\n"); goto Die; } decr = strtomp(rpc->arg, nil, 16, nil); if(decr == nil){ debug(DBG_AUTH, "\tdecr %s failed\n", rpc->arg); goto Die; } debug(DBG_AUTH, "\tdecrypted %B\n", decr); unpad = rsaunpad(decr); if(unpad == nil){ debug(DBG_AUTH, "\tunpad %B failed\n", decr); mpfree(decr); goto Die; } debug(DBG_AUTH, "\tunpadded %B\n", unpad); mpfree(decr); mptoberjust(unpad, chalbuf, 32); mpfree(unpad); auth_freerpc(rpc); close(afd); return 0; }