123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948 |
- #include <u.h>
- #include <libc.h>
- #include <mp.h>
- #include <libsec.h>
- #include <fcall.h>
- #include <thread.h>
- #include <9p.h>
- #include <auth.h>
- #include <ip.h>
- #include <pool.h>
- #include "netssh.h"
- #undef VERIFYKEYS /* TODO until it's fixed */
- enum {
- Errnokey = -2, /* no key on keyring */
- Errnoverify, /* factotum found a key, but verification failed */
- Errfactotum, /* factotum failure (e.g., no key) */
- Errnone, /* key verified */
- };
- static int dh_server(Conn *, Packet *, mpint *, int);
- static void genkeys(Conn *, uchar [], mpint *);
- /*
- * Second Oakley Group from RFC 2409
- */
- static char *group1p =
- "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
- "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
- "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
- "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
- "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381"
- "FFFFFFFFFFFFFFFF";
- /*
- * 2048-bit MODP group (id 14) from RFC 3526
- */
- static char *group14p =
- "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
- "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
- "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
- "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
- "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
- "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
- "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
- "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
- "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
- "DE2BCBF6955817183995497CEA956AE515D2261898FA0510"
- "15728E5A8AACAA68FFFFFFFFFFFFFFFF";
- mpint *two, *p1, *p14;
- int nokeyverify;
- static DSApriv mydsskey;
- static RSApriv myrsakey;
- void
- dh_init(PKA *pkas[])
- {
- char *buf, *p, *st, *end;
- int fd, n, k;
- if(debug > 1)
- sshdebug(nil, "dh_init");
- k = 0;
- pkas[k] = nil;
- fmtinstall('M', mpfmt);
- two = strtomp("2", nil, 10, nil);
- p1 = strtomp(group1p, nil, 16, nil);
- p14 = strtomp(group14p, nil, 16, nil);
- /*
- * this really should be done through factotum
- */
- p = getenv("rsakey");
- if (p != nil) {
- remove("/env/rsakey");
- st = buf = p;
- end = buf + strlen(p);
- } else {
- /*
- * it would be better to use bio and rdline here instead of
- * reading all of factotum's contents into memory at once.
- */
- buf = emalloc9p(Maxfactotum);
- fd = open("rsakey", OREAD);
- if (fd < 0 && (fd = open("/mnt/factotum/ctl", OREAD)) < 0)
- goto norsa;
- n = readn(fd, buf, Maxfactotum - 1);
- buf[n >= 0? n: 0] = 0;
- close(fd);
- assert(n < Maxfactotum - 1);
- st = strstr(buf, "proto=rsa");
- if (st == nil) {
- sshlog(nil, "no proto=rsa key in factotum");
- goto norsa;
- }
- end = st;
- for (; st > buf && *st != '\n'; --st)
- ;
- for (; end < buf + Maxfactotum && *end != '\n'; ++end)
- ;
- }
- p = strstr(st, " n=");
- if (p == nil || p > end) {
- sshlog(nil, "no key (n) found");
- free(buf);
- return;
- }
- myrsakey.pub.n = strtomp(p+3, nil, 16, nil);
- if (debug > 1)
- sshdebug(nil, "n=%M", myrsakey.pub.n);
- p = strstr(st, " ek=");
- if (p == nil || p > end) {
- sshlog(nil, "no key (ek) found");
- free(buf);
- return;
- }
- pkas[k++] = &rsa_pka;
- pkas[k] = nil;
- myrsakey.pub.ek = strtomp(p+4, nil, 16, nil);
- if (debug > 1)
- sshdebug(nil, "ek=%M", myrsakey.pub.ek);
- p = strstr(st, " !dk=");
- if (p == nil) {
- p = strstr(st, "!dk?");
- if (p == nil || p > end) {
- // sshlog(nil, "no key (dk) found");
- free(buf);
- return;
- }
- goto norsa;
- }
- myrsakey.dk = strtomp(p+5, nil, 16, nil);
- if (debug > 1)
- sshdebug(nil, "dk=%M", myrsakey.dk);
- norsa:
- free(buf);
- p = getenv("dsskey");
- if (p != nil) {
- remove("/env/dsskey");
- buf = p;
- end = buf + strlen(p);
- } else {
- /*
- * it would be better to use bio and rdline here instead of
- * reading all of factotum's contents into memory at once.
- */
- buf = emalloc9p(Maxfactotum);
- fd = open("dsskey", OREAD);
- if (fd < 0 && (fd = open("/mnt/factotum/ctl", OREAD)) < 0)
- return;
- n = readn(fd, buf, Maxfactotum - 1);
- buf[n >= 0? n: 0] = 0;
- close(fd);
- assert(n < Maxfactotum - 1);
- st = strstr(buf, "proto=dsa");
- if (st == nil) {
- sshlog(nil, "no proto=dsa key in factotum");
- free(buf);
- return;
- }
- end = st;
- for (; st > buf && *st != '\n'; --st)
- ;
- for (; end < buf + Maxfactotum && *end != '\n'; ++end)
- ;
- }
- p = strstr(buf, " p=");
- if (p == nil || p > end) {
- sshlog(nil, "no key (p) found");
- free(buf);
- return;
- }
- mydsskey.pub.p = strtomp(p+3, nil, 16, nil);
- p = strstr(buf, " q=");
- if (p == nil || p > end) {
- sshlog(nil, "no key (q) found");
- free(buf);
- return;
- }
- mydsskey.pub.q = strtomp(p+3, nil, 16, nil);
- p = strstr(buf, " alpha=");
- if (p == nil || p > end) {
- sshlog(nil, "no key (g) found");
- free(buf);
- return;
- }
- mydsskey.pub.alpha = strtomp(p+7, nil, 16, nil);
- p = strstr(buf, " key=");
- if (p == nil || p > end) {
- sshlog(nil, "no key (y) found");
- free(buf);
- return;
- }
- mydsskey.pub.key = strtomp(p+5, nil, 16, nil);
- pkas[k++] = &dss_pka;
- pkas[k] = nil;
- p = strstr(buf, " !secret=");
- if (p == nil) {
- p = strstr(buf, "!secret?");
- if (p == nil || p > end)
- sshlog(nil, "no key (x) found");
- free(buf);
- return;
- }
- mydsskey.secret = strtomp(p+9, nil, 16, nil);
- free(buf);
- }
- static Packet *
- rsa_ks(Conn *c)
- {
- Packet *ks;
- if (myrsakey.pub.ek == nil || myrsakey.pub.n == nil) {
- sshlog(c, "no public RSA key info");
- return nil;
- }
- ks = new_packet(c);
- add_string(ks, "ssh-rsa");
- add_mp(ks, myrsakey.pub.ek);
- add_mp(ks, myrsakey.pub.n);
- return ks;
- }
- static void
- esma_encode(uchar *h, uchar *em, int nb)
- {
- int n, i;
- uchar hh[SHA1dlen];
- static uchar sha1der[] = {
- 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e,
- 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14,
- };
- sha1(h, SHA1dlen, hh, nil);
- n = nb - (nelem(sha1der) + SHA1dlen) - 3;
- i = 0;
- em[i++] = 0;
- em[i++] = 1;
- memset(em + i, 0xff, n);
- i += n;
- em[i++] = 0;
- memmove(em + i, sha1der, sizeof sha1der);
- i += sizeof sha1der;
- memmove(em + i, hh, SHA1dlen);
- }
- static Packet *
- rsa_sign(Conn *c, uchar *m, int nm)
- {
- AuthRpc *ar;
- Packet *sig;
- mpint *s, *mm;
- int fd, n, nbit;
- uchar hh[SHA1dlen];
- uchar *sstr, *em;
- if (myrsakey.dk) {
- nbit = mpsignif (myrsakey.pub.n);
- n = (nbit + 7) / 8;
- sstr = emalloc9p(n);
- em = emalloc9p(n);
- /* Compute s: RFC 3447 */
- esma_encode(m, em, n);
- mm = betomp(em, n, nil);
- s = mpnew(nbit);
- mpexp(mm, myrsakey.dk, myrsakey.pub.n, s);
- mptobe(s, sstr, n, nil);
- mpfree(mm);
- mpfree(s);
- free(em);
- } else {
- fd = open("/mnt/factotum/rpc", ORDWR);
- if (fd < 0)
- return nil;
- sha1(m, nm, hh, nil);
- ar = auth_allocrpc(fd);
- if (ar == nil ||
- auth_rpc(ar, "start", "role=sign proto=rsa", 19) != ARok ||
- auth_rpc(ar, "write", hh, SHA1dlen) != ARok ||
- auth_rpc(ar, "read", nil, 0) != ARok ||
- ar->arg == nil) {
- sshdebug(c, "got error in factotum: %r");
- auth_freerpc(ar);
- close(fd);
- return nil;
- }
- sstr = emalloc9p(ar->narg);
- memmove(sstr, ar->arg, ar->narg);
- n = ar->narg;
- auth_freerpc(ar);
- close(fd);
- }
- sig = new_packet(c);
- add_string(sig, pkas[c->pkalg]->name);
- add_block(sig, sstr, n);
- free(sstr);
- return sig;
- }
- /*
- * 0 - If factotum failed, e.g. no key
- * 1 - If key is verified
- * -1 - If factotum found a key, but the verification fails
- */
- static int
- rsa_verify(Conn *c, uchar *m, int nm, char *user, char *sig, int)
- {
- int fd, n, retval, nbit;
- char *buf, *p, *sigblob;
- uchar *sstr, *em;
- uchar hh[SHA1dlen];
- mpint *s, *mm, *rsa_exponent, *host_modulus;
- AuthRpc *ar;
- sshdebug(c, "in rsa_verify for connection: %d", c->id);
- SET(rsa_exponent, host_modulus);
- USED(rsa_exponent, host_modulus);
- if (0 && rsa_exponent) {
- nbit = mpsignif(host_modulus);
- n = (nbit + 7) / 8;
- em = emalloc9p(n);
- /* Compute s: RFC 3447 */
- esma_encode(m, em, n);
- mm = betomp(em, n, nil);
- s = mpnew(1024);
- mpexp(mm, rsa_exponent, host_modulus, s);
- sstr = emalloc9p(n);
- mptobe(s, sstr, n, nil);
- free(em);
- mpfree(mm);
- mpfree(s);
- retval = memcmp(sig, sstr, n);
- free(sstr);
- retval = (retval == 0);
- } else {
- retval = 1;
- fd = open("/mnt/factotum/rpc", ORDWR);
- if (fd < 0) {
- sshdebug(c, "could not open factotum RPC: %r");
- return 0;
- }
- buf = emalloc9p(Blobsz / 2);
- sigblob = emalloc9p(Blobsz);
- p = (char *)get_string(nil, (uchar *)sig, buf, Blobsz / 2, nil);
- get_string(nil, (uchar *)p, sigblob, Blobsz, &n);
- sha1(m, nm, hh, nil);
- if (user != nil)
- p = smprint("role=verify proto=rsa user=%s", user);
- else
- p = smprint("role=verify proto=rsa sys=%s", c->remote);
- ar = auth_allocrpc(fd);
- if (ar == nil || auth_rpc(ar, "start", p, strlen(p)) != ARok ||
- auth_rpc(ar, "write", hh, SHA1dlen) != ARok ||
- auth_rpc(ar, "write", sigblob, n) != ARok ||
- auth_rpc(ar, "read", nil, 0) != ARok) {
- sshdebug(c, "got error in factotum: %r");
- retval = 0;
- } else {
- sshdebug(c, "factotum returned %s", ar->ibuf);
- if (strstr(ar->ibuf, "does not verify") != nil)
- retval = -1;
- }
- if (ar != nil)
- auth_freerpc(ar);
- free(p);
- close(fd);
- free(sigblob);
- free(buf);
- }
- return retval;
- }
- static Packet *
- dss_ks(Conn *c)
- {
- Packet *ks;
- if (mydsskey.pub.p == nil)
- return nil;
- ks = new_packet(c);
- add_string(ks, "ssh-dss");
- add_mp(ks, mydsskey.pub.p);
- add_mp(ks, mydsskey.pub.q);
- add_mp(ks, mydsskey.pub.alpha);
- add_mp(ks, mydsskey.pub.key);
- return ks;
- }
- static Packet *
- dss_sign(Conn *c, uchar *m, int nm)
- {
- AuthRpc *ar;
- DSAsig *s;
- Packet *sig;
- mpint *mm;
- int fd;
- uchar sstr[2*SHA1dlen];
- sha1(m, nm, sstr, nil);
- sig = new_packet(c);
- add_string(sig, pkas[c->pkalg]->name);
- if (mydsskey.secret) {
- mm = betomp(sstr, SHA1dlen, nil);
- s = dsasign(&mydsskey, mm);
- mptobe(s->r, sstr, SHA1dlen, nil);
- mptobe(s->s, sstr+SHA1dlen, SHA1dlen, nil);
- dsasigfree(s);
- mpfree(mm);
- } else {
- fd = open("/mnt/factotum/rpc", ORDWR);
- if (fd < 0)
- return nil;
- ar = auth_allocrpc(fd);
- if (ar == nil ||
- auth_rpc(ar, "start", "role=sign proto=dsa", 19) != ARok ||
- auth_rpc(ar, "write", sstr, SHA1dlen) != ARok ||
- auth_rpc(ar, "read", nil, 0) != ARok) {
- sshdebug(c, "got error in factotum: %r");
- auth_freerpc(ar);
- close(fd);
- return nil;
- }
- memmove(sstr, ar->arg, ar->narg);
- auth_freerpc(ar);
- close(fd);
- }
- add_block(sig, sstr, 2*SHA1dlen);
- return sig;
- }
- static int
- dss_verify(Conn *c, uchar *m, int nm, char *user, char *sig, int nsig)
- {
- sshdebug(c, "in dss_verify for connection: %d", c->id);
- USED(m, nm, user, sig, nsig);
- return 0;
- }
- static int
- dh_server1(Conn *c, Packet *pack1)
- {
- return dh_server(c, pack1, p1, 1024);
- }
- static int
- dh_server14(Conn *c, Packet *pack1)
- {
- return dh_server(c, pack1, p14, 2048);
- }
- static int
- dh_server(Conn *c, Packet *pack1, mpint *grp, int nbit)
- {
- Packet *pack2, *ks, *sig;
- mpint *y, *e, *f, *k;
- int n, ret;
- uchar h[SHA1dlen];
- ret = -1;
- qlock(&c->l);
- f = mpnew(nbit);
- k = mpnew(nbit);
- /* Compute f: RFC4253 */
- y = mprand(nbit / 8, genrandom, nil);
- if (debug > 1)
- sshdebug(c, "y=%M", y);
- mpexp(two, y, grp, f);
- if (debug > 1)
- sshdebug(c, "f=%M", f);
- /* Compute k: RFC4253 */
- if (debug > 1)
- dump_packet(pack1);
- e = get_mp(pack1->payload+1);
- if (debug > 1)
- sshdebug(c, "e=%M", e);
- mpexp(e, y, grp, k);
- if (debug > 1)
- sshdebug(c, "k=%M", k);
- /* Compute H: RFC 4253 */
- pack2 = new_packet(c);
- sshdebug(c, "ID strings: %s---%s", c->otherid, MYID);
- add_string(pack2, c->otherid);
- add_string(pack2, MYID);
- if (debug > 1) {
- fprint(2, "received kexinit:");
- dump_packet(c->rkexinit);
- fprint(2, "\nsent kexinit:");
- dump_packet(c->skexinit);
- }
- add_block(pack2, c->rkexinit->payload, c->rkexinit->rlength - 1);
- add_block(pack2, c->skexinit->payload,
- c->skexinit->rlength - c->skexinit->pad_len - 1);
- sig = nil;
- ks = pkas[c->pkalg]->ks(c);
- if (ks == nil)
- goto err;
- add_block(pack2, ks->payload, ks->rlength - 1);
- add_mp(pack2, e);
- add_mp(pack2, f);
- add_mp(pack2, k);
- sha1(pack2->payload, pack2->rlength - 1, h, nil);
- if (c->got_sessid == 0) {
- memmove(c->sessid, h, SHA1dlen);
- c->got_sessid = 1;
- }
- sig = pkas[c->pkalg]->sign(c, h, SHA1dlen);
- if (sig == nil) {
- sshlog(c, "failed to generate signature: %r");
- goto err;
- }
- /* Send (K_s || f || s) to client: RFC4253 */
- init_packet(pack2);
- pack2->c = c;
- add_byte(pack2, SSH_MSG_KEXDH_REPLY);
- add_block(pack2, ks->payload, ks->rlength - 1);
- add_mp(pack2, f);
- add_block(pack2, sig->payload, sig->rlength - 1);
- if (debug > 1)
- dump_packet(pack2);
- n = finish_packet(pack2);
- if (debug > 1) {
- sshdebug(c, "writing %d bytes: len %d", n, nhgetl(pack2->nlength));
- dump_packet(pack2);
- }
- iowrite(c->dio, c->datafd, pack2->nlength, n);
- genkeys(c, h, k);
- /* Send SSH_MSG_NEWKEYS */
- init_packet(pack2);
- pack2->c = c;
- add_byte(pack2, SSH_MSG_NEWKEYS);
- n = finish_packet(pack2);
- iowrite(c->dio, c->datafd, pack2->nlength, n);
- ret = 0;
- err:
- mpfree(f);
- mpfree(e);
- mpfree(k);
- mpfree(y);
- free(sig);
- free(ks);
- free(pack2);
- qunlock(&c->l);
- return ret;
- }
- static int
- dh_client11(Conn *c, Packet *)
- {
- Packet *p;
- int n;
- if (c->e)
- mpfree(c->e);
- c->e = mpnew(1024);
- /* Compute e: RFC4253 */
- if (c->x)
- mpfree(c->x);
- c->x = mprand(128, genrandom, nil);
- mpexp(two, c->x, p1, c->e);
- p = new_packet(c);
- add_byte(p, SSH_MSG_KEXDH_INIT);
- add_mp(p, c->e);
- n = finish_packet(p);
- iowrite(c->dio, c->datafd, p->nlength, n);
- free(p);
- return 0;
- }
- static int
- findkeyinuserring(Conn *c, RSApub *srvkey)
- {
- int n;
- char *home, *newkey, *r;
- home = getenv("home");
- if (home == nil) {
- newkey = "No home directory for key file";
- free(keymbox.msg);
- keymbox.msg = smprint("b%04ld%s", strlen(newkey), newkey);
- return -1;
- }
- r = smprint("%s/lib/keyring", home);
- free(home);
- if ((n = findkey(r, c->remote, srvkey)) != KeyOk) {
- newkey = smprint("ek=%M n=%M", srvkey->ek, srvkey->n);
- free(keymbox.msg);
- keymbox.msg = smprint("%c%04ld%s", n == NoKeyFile || n == NoKey?
- 'c': 'b', strlen(newkey), newkey);
- free(newkey);
- nbsendul(keymbox.mchan, 1);
- recvul(keymbox.mchan);
- if (keymbox.msg == nil || keymbox.msg[0] == 'n') {
- free(keymbox.msg);
- keymbox.msg = nil;
- newkey = "Server key reject";
- keymbox.msg = smprint("f%04ld%s", strlen(newkey), newkey);
- return -1;
- }
- sshdebug(c, "adding key");
- if (keymbox.msg[0] == 'y')
- appendkey(r, c->remote, srvkey);
- else if (keymbox.msg[0] == 'r')
- replacekey(r, c->remote, srvkey);
- }
- free(r);
- return 0;
- }
- static int
- verifyhostkey(Conn *c, RSApub *srvkey, Packet *sig)
- {
- int fd, n;
- char *newkey;
- uchar h[SHA1dlen];
- sshdebug(c, "verifying server signature");
- if (findkey("/sys/lib/ssh/keyring", c->remote, srvkey) != KeyOk &&
- findkeyinuserring(c, srvkey) < 0) {
- nbsendul(keymbox.mchan, 1);
- mpfree(srvkey->ek);
- mpfree(srvkey->n);
- return Errnokey;
- }
- newkey = smprint("key proto=rsa role=verify sys=%s size=%d ek=%M n=%M",
- c->remote, mpsignif(srvkey->n), srvkey->ek, srvkey->n);
- if (newkey == nil) {
- sshlog(c, "out of memory");
- threadexits("out of memory");
- }
- fd = open("/mnt/factotum/ctl", OWRITE);
- if (fd >= 0)
- write(fd, newkey, strlen(newkey));
- /* leave fd open */
- else
- sshdebug(c, "factotum open failed: %r");
- free(newkey);
- mpfree(srvkey->ek);
- mpfree(srvkey->n);
- free(keymbox.msg);
- keymbox.msg = nil;
- n = pkas[c->pkalg]->verify(c, h, SHA1dlen, nil, (char *)sig->payload,
- sig->rlength);
- /* fd is perhaps still open */
- if (fd >= 0) {
- /* sys here is a dotted-quad ip address */
- newkey = smprint("delkey proto=rsa role=verify sys=%s",
- c->remote);
- if (newkey) {
- seek(fd, 0, 0);
- write(fd, newkey, strlen(newkey));
- free(newkey);
- }
- close(fd);
- }
- return n;
- }
- static int
- dh_client12(Conn *c, Packet *p)
- {
- int n, retval;
- #ifdef VERIFYKEYS
- char *newkey;
- #endif
- char buf[10];
- uchar *q;
- uchar h[SHA1dlen];
- mpint *f, *k;
- Packet *ks, *sig, *pack2;
- RSApub *srvkey;
- ks = new_packet(c);
- sig = new_packet(c);
- pack2 = new_packet(c);
- q = get_string(p, p->payload+1, (char *)ks->payload, Maxpktpay, &n);
- ks->rlength = n + 1;
- f = get_mp(q);
- q += nhgetl(q) + 4;
- get_string(p, q, (char *)sig->payload, Maxpktpay, &n);
- sig->rlength = n;
- k = mpnew(1024);
- mpexp(f, c->x, p1, k);
- /* Compute H: RFC 4253 */
- init_packet(pack2);
- pack2->c = c;
- if (debug > 1)
- sshdebug(c, "ID strings: %s---%s", c->otherid, MYID);
- add_string(pack2, MYID);
- add_string(pack2, c->otherid);
- if (debug > 1) {
- fprint(2, "received kexinit:");
- dump_packet(c->rkexinit);
- fprint(2, "\nsent kexinit:");
- dump_packet(c->skexinit);
- }
- add_block(pack2, c->skexinit->payload,
- c->skexinit->rlength - c->skexinit->pad_len - 1);
- add_block(pack2, c->rkexinit->payload, c->rkexinit->rlength - 1);
- add_block(pack2, ks->payload, ks->rlength - 1);
- add_mp(pack2, c->e);
- add_mp(pack2, f);
- add_mp(pack2, k);
- sha1(pack2->payload, pack2->rlength - 1, h, nil);
- mpfree(f);
- if (c->got_sessid == 0) {
- memmove(c->sessid, h, SHA1dlen);
- c->got_sessid = 1;
- }
- q = get_string(ks, ks->payload, buf, sizeof buf, nil);
- srvkey = emalloc9p(sizeof (RSApub));
- srvkey->ek = get_mp(q);
- q += nhgetl(q) + 4;
- srvkey->n = get_mp(q);
- /*
- * key verification is really pretty pedantic and
- * not doing it lets us talk to ssh v1 implementations.
- */
- if (nokeyverify)
- n = Errnone;
- else
- n = verifyhostkey(c, srvkey, sig);
- retval = -1;
- USED(retval);
- switch (n) {
- #ifdef VERIFYKEYS
- case Errnokey:
- goto out;
- case Errnoverify:
- newkey = "signature verification failed; try netssh -v";
- keymbox.msg = smprint("f%04ld%s", strlen(newkey), newkey);
- break;
- case Errfactotum:
- newkey = "factotum dialogue failed; try netssh -v";
- keymbox.msg = smprint("f%04ld%s", strlen(newkey), newkey);
- break;
- case Errnone:
- #else
- default:
- #endif
- keymbox.msg = smprint("o0000");
- retval = 0;
- break;
- }
- nbsendul(keymbox.mchan, 1);
- if (retval == 0)
- genkeys(c, h, k);
- #ifdef VERIFYKEYS
- out:
- #endif
- mpfree(k);
- free(ks);
- free(sig);
- free(pack2);
- free(srvkey);
- return retval;
- }
- static int
- dh_client141(Conn *c, Packet *)
- {
- Packet *p;
- mpint *e, *x;
- int n;
- /* Compute e: RFC4253 */
- e = mpnew(2048);
- x = mprand(256, genrandom, nil);
- mpexp(two, x, p14, e);
- p = new_packet(c);
- add_byte(p, SSH_MSG_KEXDH_INIT);
- add_mp(p, e);
- n = finish_packet(p);
- iowrite(c->dio, c->datafd, p->nlength, n);
- free(p);
- mpfree(e);
- mpfree(x);
- return 0;
- }
- static int
- dh_client142(Conn *, Packet *)
- {
- return 0;
- }
- static void
- initsha1pkt(Packet *pack2, mpint *k, uchar *h)
- {
- init_packet(pack2);
- add_mp(pack2, k);
- add_packet(pack2, h, SHA1dlen);
- }
- static void
- genkeys(Conn *c, uchar h[], mpint *k)
- {
- Packet *pack2;
- char buf[82], *bp, *be; /* magic 82 */
- int n;
- pack2 = new_packet(c);
- /* Compute 40 bytes (320 bits) of keys: each alg can use what it needs */
- /* Client to server IV */
- if (debug > 1) {
- fprint(2, "k=%M\nh=", k);
- for (n = 0; n < SHA1dlen; ++n)
- fprint(2, "%02ux", h[n]);
- fprint(2, "\nsessid=");
- for (n = 0; n < SHA1dlen; ++n)
- fprint(2, "%02ux", c->sessid[n]);
- fprint(2, "\n");
- }
- initsha1pkt(pack2, k, h);
- add_byte(pack2, 'A');
- add_packet(pack2, c->sessid, SHA1dlen);
- sha1(pack2->payload, pack2->rlength - 1, c->nc2siv, nil);
- initsha1pkt(pack2, k, h);
- add_packet(pack2, c->nc2siv, SHA1dlen);
- sha1(pack2->payload, pack2->rlength - 1, c->nc2siv + SHA1dlen, nil);
- /* Server to client IV */
- initsha1pkt(pack2, k, h);
- add_byte(pack2, 'B');
- add_packet(pack2, c->sessid, SHA1dlen);
- sha1(pack2->payload, pack2->rlength - 1, c->ns2civ, nil);
- initsha1pkt(pack2, k, h);
- add_packet(pack2, c->ns2civ, SHA1dlen);
- sha1(pack2->payload, pack2->rlength - 1, c->ns2civ + SHA1dlen, nil);
- /* Client to server encryption key */
- initsha1pkt(pack2, k, h);
- add_byte(pack2, 'C');
- add_packet(pack2, c->sessid, SHA1dlen);
- sha1(pack2->payload, pack2->rlength - 1, c->nc2sek, nil);
- initsha1pkt(pack2, k, h);
- add_packet(pack2, c->nc2sek, SHA1dlen);
- sha1(pack2->payload, pack2->rlength - 1, c->nc2sek + SHA1dlen, nil);
- /* Server to client encryption key */
- initsha1pkt(pack2, k, h);
- add_byte(pack2, 'D');
- add_packet(pack2, c->sessid, SHA1dlen);
- sha1(pack2->payload, pack2->rlength - 1, c->ns2cek, nil);
- initsha1pkt(pack2, k, h);
- add_packet(pack2, c->ns2cek, SHA1dlen);
- sha1(pack2->payload, pack2->rlength - 1, c->ns2cek + SHA1dlen, nil);
- /* Client to server integrity key */
- initsha1pkt(pack2, k, h);
- add_byte(pack2, 'E');
- add_packet(pack2, c->sessid, SHA1dlen);
- sha1(pack2->payload, pack2->rlength - 1, c->nc2sik, nil);
- initsha1pkt(pack2, k, h);
- add_packet(pack2, c->nc2sik, SHA1dlen);
- sha1(pack2->payload, pack2->rlength - 1, c->nc2sik + SHA1dlen, nil);
- /* Server to client integrity key */
- initsha1pkt(pack2, k, h);
- add_byte(pack2, 'F');
- add_packet(pack2, c->sessid, SHA1dlen);
- sha1(pack2->payload, pack2->rlength - 1, c->ns2cik, nil);
- initsha1pkt(pack2, k, h);
- add_packet(pack2, c->ns2cik, SHA1dlen);
- sha1(pack2->payload, pack2->rlength - 1, c->ns2cik + SHA1dlen, nil);
- if (debug > 1) {
- be = buf + sizeof buf;
- fprint(2, "Client to server IV:\n");
- for (n = 0, bp = buf; n < SHA1dlen*2; ++n)
- bp = seprint(bp, be, "%02x", c->nc2siv[n]);
- fprint(2, "%s\n", buf);
- fprint(2, "Server to client IV:\n");
- for (n = 0, bp = buf; n < SHA1dlen*2; ++n)
- bp = seprint(bp, be, "%02x", c->ns2civ[n]);
- fprint(2, "%s\n", buf);
- fprint(2, "Client to server EK:\n");
- for (n = 0, bp = buf; n < SHA1dlen*2; ++n)
- bp = seprint(bp, be, "%02x", c->nc2sek[n]);
- fprint(2, "%s\n", buf);
- fprint(2, "Server to client EK:\n");
- for (n = 0, bp = buf; n < SHA1dlen*2; ++n)
- bp = seprint(bp, be, "%02x", c->ns2cek[n]);
- fprint(2, "%s\n", buf);
- }
- free(pack2);
- }
- Kex dh1sha1 = {
- "diffie-hellman-group1-sha1",
- dh_server1,
- dh_client11,
- dh_client12
- };
- Kex dh14sha1 = {
- "diffie-hellman-group14-sha1",
- dh_server14,
- dh_client141,
- dh_client142
- };
- PKA rsa_pka = {
- "ssh-rsa",
- rsa_ks,
- rsa_sign,
- rsa_verify
- };
- PKA dss_pka = {
- "ssh-dss",
- dss_ks,
- dss_sign,
- dss_verify
- };
|