163afb9a5SDavid du Colombier #include <u.h>
263afb9a5SDavid du Colombier #include <libc.h>
363afb9a5SDavid du Colombier #include <mp.h>
463afb9a5SDavid du Colombier #include <libsec.h>
563afb9a5SDavid du Colombier #include <fcall.h>
663afb9a5SDavid du Colombier #include <thread.h>
763afb9a5SDavid du Colombier #include <9p.h>
863afb9a5SDavid du Colombier #include <auth.h>
963afb9a5SDavid du Colombier #include <ip.h>
1063afb9a5SDavid du Colombier #include <pool.h>
1163afb9a5SDavid du Colombier #include "netssh.h"
1263afb9a5SDavid du Colombier
13998526ebSDavid du Colombier #undef VERIFYKEYS /* TODO until it's fixed */
14998526ebSDavid du Colombier
15998526ebSDavid du Colombier enum {
16998526ebSDavid du Colombier Errnokey = -2, /* no key on keyring */
17998526ebSDavid du Colombier Errnoverify, /* factotum found a key, but verification failed */
18998526ebSDavid du Colombier Errfactotum, /* factotum failure (e.g., no key) */
19998526ebSDavid du Colombier Errnone, /* key verified */
20998526ebSDavid du Colombier };
21998526ebSDavid du Colombier
2263afb9a5SDavid du Colombier static int dh_server(Conn *, Packet *, mpint *, int);
23*c59d18e2SDavid du Colombier static int dh_client1(Conn *, mpint *, int, int);
24*c59d18e2SDavid du Colombier static int dh_client2(Conn *, Packet *, mpint *, int);
2563afb9a5SDavid du Colombier static void genkeys(Conn *, uchar [], mpint *);
2663afb9a5SDavid du Colombier
2763afb9a5SDavid du Colombier /*
2863afb9a5SDavid du Colombier * Second Oakley Group from RFC 2409
2963afb9a5SDavid du Colombier */
3063afb9a5SDavid du Colombier static char *group1p =
3163afb9a5SDavid du Colombier "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
3263afb9a5SDavid du Colombier "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
3363afb9a5SDavid du Colombier "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
3463afb9a5SDavid du Colombier "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
3563afb9a5SDavid du Colombier "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381"
3663afb9a5SDavid du Colombier "FFFFFFFFFFFFFFFF";
3763afb9a5SDavid du Colombier
3863afb9a5SDavid du Colombier /*
3963afb9a5SDavid du Colombier * 2048-bit MODP group (id 14) from RFC 3526
4063afb9a5SDavid du Colombier */
4163afb9a5SDavid du Colombier static char *group14p =
4263afb9a5SDavid du Colombier "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
4363afb9a5SDavid du Colombier "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
4463afb9a5SDavid du Colombier "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
4563afb9a5SDavid du Colombier "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
4663afb9a5SDavid du Colombier "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
4763afb9a5SDavid du Colombier "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
4863afb9a5SDavid du Colombier "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
4963afb9a5SDavid du Colombier "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B"
5063afb9a5SDavid du Colombier "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9"
5163afb9a5SDavid du Colombier "DE2BCBF6955817183995497CEA956AE515D2261898FA0510"
5263afb9a5SDavid du Colombier "15728E5A8AACAA68FFFFFFFFFFFFFFFF";
5363afb9a5SDavid du Colombier
5463afb9a5SDavid du Colombier mpint *two, *p1, *p14;
5563afb9a5SDavid du Colombier int nokeyverify;
5663afb9a5SDavid du Colombier
5763afb9a5SDavid du Colombier static DSApriv mydsskey;
5863afb9a5SDavid du Colombier static RSApriv myrsakey;
5963afb9a5SDavid du Colombier
6063afb9a5SDavid du Colombier void
dh_init(PKA * pkas[])6163afb9a5SDavid du Colombier dh_init(PKA *pkas[])
6263afb9a5SDavid du Colombier {
6363afb9a5SDavid du Colombier char *buf, *p, *st, *end;
6463afb9a5SDavid du Colombier int fd, n, k;
6563afb9a5SDavid du Colombier
6663afb9a5SDavid du Colombier if(debug > 1)
6763afb9a5SDavid du Colombier sshdebug(nil, "dh_init");
6863afb9a5SDavid du Colombier k = 0;
6963afb9a5SDavid du Colombier pkas[k] = nil;
7063afb9a5SDavid du Colombier fmtinstall('M', mpfmt);
7163afb9a5SDavid du Colombier two = strtomp("2", nil, 10, nil);
7263afb9a5SDavid du Colombier p1 = strtomp(group1p, nil, 16, nil);
7363afb9a5SDavid du Colombier p14 = strtomp(group14p, nil, 16, nil);
7463afb9a5SDavid du Colombier
7563afb9a5SDavid du Colombier /*
7663afb9a5SDavid du Colombier * this really should be done through factotum
7763afb9a5SDavid du Colombier */
7863afb9a5SDavid du Colombier p = getenv("rsakey");
7963afb9a5SDavid du Colombier if (p != nil) {
8063afb9a5SDavid du Colombier remove("/env/rsakey");
8163afb9a5SDavid du Colombier st = buf = p;
8263afb9a5SDavid du Colombier end = buf + strlen(p);
8363afb9a5SDavid du Colombier } else {
8463afb9a5SDavid du Colombier /*
8563afb9a5SDavid du Colombier * it would be better to use bio and rdline here instead of
8663afb9a5SDavid du Colombier * reading all of factotum's contents into memory at once.
8763afb9a5SDavid du Colombier */
8863afb9a5SDavid du Colombier buf = emalloc9p(Maxfactotum);
8963afb9a5SDavid du Colombier fd = open("rsakey", OREAD);
9063afb9a5SDavid du Colombier if (fd < 0 && (fd = open("/mnt/factotum/ctl", OREAD)) < 0)
9163afb9a5SDavid du Colombier goto norsa;
9263afb9a5SDavid du Colombier n = readn(fd, buf, Maxfactotum - 1);
9363afb9a5SDavid du Colombier buf[n >= 0? n: 0] = 0;
9463afb9a5SDavid du Colombier close(fd);
9563afb9a5SDavid du Colombier assert(n < Maxfactotum - 1);
9663afb9a5SDavid du Colombier
9763afb9a5SDavid du Colombier st = strstr(buf, "proto=rsa");
9863afb9a5SDavid du Colombier if (st == nil) {
9963afb9a5SDavid du Colombier sshlog(nil, "no proto=rsa key in factotum");
10063afb9a5SDavid du Colombier goto norsa;
10163afb9a5SDavid du Colombier }
10263afb9a5SDavid du Colombier end = st;
10363afb9a5SDavid du Colombier for (; st > buf && *st != '\n'; --st)
10463afb9a5SDavid du Colombier ;
10563afb9a5SDavid du Colombier for (; end < buf + Maxfactotum && *end != '\n'; ++end)
10663afb9a5SDavid du Colombier ;
10763afb9a5SDavid du Colombier }
10863afb9a5SDavid du Colombier p = strstr(st, " n=");
10963afb9a5SDavid du Colombier if (p == nil || p > end) {
11063afb9a5SDavid du Colombier sshlog(nil, "no key (n) found");
11163afb9a5SDavid du Colombier free(buf);
11263afb9a5SDavid du Colombier return;
11363afb9a5SDavid du Colombier }
11463afb9a5SDavid du Colombier myrsakey.pub.n = strtomp(p+3, nil, 16, nil);
11563afb9a5SDavid du Colombier if (debug > 1)
11663afb9a5SDavid du Colombier sshdebug(nil, "n=%M", myrsakey.pub.n);
11763afb9a5SDavid du Colombier p = strstr(st, " ek=");
11863afb9a5SDavid du Colombier if (p == nil || p > end) {
11963afb9a5SDavid du Colombier sshlog(nil, "no key (ek) found");
12063afb9a5SDavid du Colombier free(buf);
12163afb9a5SDavid du Colombier return;
12263afb9a5SDavid du Colombier }
12363afb9a5SDavid du Colombier pkas[k++] = &rsa_pka;
12463afb9a5SDavid du Colombier pkas[k] = nil;
12563afb9a5SDavid du Colombier myrsakey.pub.ek = strtomp(p+4, nil, 16, nil);
12663afb9a5SDavid du Colombier if (debug > 1)
12763afb9a5SDavid du Colombier sshdebug(nil, "ek=%M", myrsakey.pub.ek);
12863afb9a5SDavid du Colombier p = strstr(st, " !dk=");
12963afb9a5SDavid du Colombier if (p == nil) {
13063afb9a5SDavid du Colombier p = strstr(st, "!dk?");
13163afb9a5SDavid du Colombier if (p == nil || p > end) {
13263afb9a5SDavid du Colombier // sshlog(nil, "no key (dk) found");
13363afb9a5SDavid du Colombier free(buf);
13463afb9a5SDavid du Colombier return;
13563afb9a5SDavid du Colombier }
13663afb9a5SDavid du Colombier goto norsa;
13763afb9a5SDavid du Colombier }
13863afb9a5SDavid du Colombier myrsakey.dk = strtomp(p+5, nil, 16, nil);
13963afb9a5SDavid du Colombier if (debug > 1)
14063afb9a5SDavid du Colombier sshdebug(nil, "dk=%M", myrsakey.dk);
14163afb9a5SDavid du Colombier norsa:
14263afb9a5SDavid du Colombier free(buf);
14363afb9a5SDavid du Colombier
14463afb9a5SDavid du Colombier p = getenv("dsskey");
14563afb9a5SDavid du Colombier if (p != nil) {
14663afb9a5SDavid du Colombier remove("/env/dsskey");
14763afb9a5SDavid du Colombier buf = p;
14863afb9a5SDavid du Colombier end = buf + strlen(p);
14963afb9a5SDavid du Colombier } else {
15063afb9a5SDavid du Colombier /*
15163afb9a5SDavid du Colombier * it would be better to use bio and rdline here instead of
15263afb9a5SDavid du Colombier * reading all of factotum's contents into memory at once.
15363afb9a5SDavid du Colombier */
15463afb9a5SDavid du Colombier buf = emalloc9p(Maxfactotum);
15563afb9a5SDavid du Colombier fd = open("dsskey", OREAD);
15663afb9a5SDavid du Colombier if (fd < 0 && (fd = open("/mnt/factotum/ctl", OREAD)) < 0)
15763afb9a5SDavid du Colombier return;
15863afb9a5SDavid du Colombier n = readn(fd, buf, Maxfactotum - 1);
15963afb9a5SDavid du Colombier buf[n >= 0? n: 0] = 0;
16063afb9a5SDavid du Colombier close(fd);
16163afb9a5SDavid du Colombier assert(n < Maxfactotum - 1);
16263afb9a5SDavid du Colombier
16363afb9a5SDavid du Colombier st = strstr(buf, "proto=dsa");
16463afb9a5SDavid du Colombier if (st == nil) {
16563afb9a5SDavid du Colombier sshlog(nil, "no proto=dsa key in factotum");
16663afb9a5SDavid du Colombier free(buf);
16763afb9a5SDavid du Colombier return;
16863afb9a5SDavid du Colombier }
16963afb9a5SDavid du Colombier end = st;
17063afb9a5SDavid du Colombier for (; st > buf && *st != '\n'; --st)
17163afb9a5SDavid du Colombier ;
17263afb9a5SDavid du Colombier for (; end < buf + Maxfactotum && *end != '\n'; ++end)
17363afb9a5SDavid du Colombier ;
17463afb9a5SDavid du Colombier }
17563afb9a5SDavid du Colombier p = strstr(buf, " p=");
17663afb9a5SDavid du Colombier if (p == nil || p > end) {
17763afb9a5SDavid du Colombier sshlog(nil, "no key (p) found");
17863afb9a5SDavid du Colombier free(buf);
17963afb9a5SDavid du Colombier return;
18063afb9a5SDavid du Colombier }
18163afb9a5SDavid du Colombier mydsskey.pub.p = strtomp(p+3, nil, 16, nil);
18263afb9a5SDavid du Colombier p = strstr(buf, " q=");
18363afb9a5SDavid du Colombier if (p == nil || p > end) {
18463afb9a5SDavid du Colombier sshlog(nil, "no key (q) found");
18563afb9a5SDavid du Colombier free(buf);
18663afb9a5SDavid du Colombier return;
18763afb9a5SDavid du Colombier }
18863afb9a5SDavid du Colombier mydsskey.pub.q = strtomp(p+3, nil, 16, nil);
18963afb9a5SDavid du Colombier p = strstr(buf, " alpha=");
19063afb9a5SDavid du Colombier if (p == nil || p > end) {
19163afb9a5SDavid du Colombier sshlog(nil, "no key (g) found");
19263afb9a5SDavid du Colombier free(buf);
19363afb9a5SDavid du Colombier return;
19463afb9a5SDavid du Colombier }
19563afb9a5SDavid du Colombier mydsskey.pub.alpha = strtomp(p+7, nil, 16, nil);
19663afb9a5SDavid du Colombier p = strstr(buf, " key=");
19763afb9a5SDavid du Colombier if (p == nil || p > end) {
19863afb9a5SDavid du Colombier sshlog(nil, "no key (y) found");
19963afb9a5SDavid du Colombier free(buf);
20063afb9a5SDavid du Colombier return;
20163afb9a5SDavid du Colombier }
20263afb9a5SDavid du Colombier mydsskey.pub.key = strtomp(p+5, nil, 16, nil);
20363afb9a5SDavid du Colombier pkas[k++] = &dss_pka;
20463afb9a5SDavid du Colombier pkas[k] = nil;
20563afb9a5SDavid du Colombier p = strstr(buf, " !secret=");
20663afb9a5SDavid du Colombier if (p == nil) {
20763afb9a5SDavid du Colombier p = strstr(buf, "!secret?");
20863afb9a5SDavid du Colombier if (p == nil || p > end)
20963afb9a5SDavid du Colombier sshlog(nil, "no key (x) found");
21063afb9a5SDavid du Colombier free(buf);
21163afb9a5SDavid du Colombier return;
21263afb9a5SDavid du Colombier }
21363afb9a5SDavid du Colombier mydsskey.secret = strtomp(p+9, nil, 16, nil);
21463afb9a5SDavid du Colombier free(buf);
21563afb9a5SDavid du Colombier }
21663afb9a5SDavid du Colombier
21763afb9a5SDavid du Colombier static Packet *
rsa_ks(Conn * c)21863afb9a5SDavid du Colombier rsa_ks(Conn *c)
21963afb9a5SDavid du Colombier {
22063afb9a5SDavid du Colombier Packet *ks;
22163afb9a5SDavid du Colombier
22263afb9a5SDavid du Colombier if (myrsakey.pub.ek == nil || myrsakey.pub.n == nil) {
22363afb9a5SDavid du Colombier sshlog(c, "no public RSA key info");
22463afb9a5SDavid du Colombier return nil;
22563afb9a5SDavid du Colombier }
22663afb9a5SDavid du Colombier ks = new_packet(c);
22763afb9a5SDavid du Colombier add_string(ks, "ssh-rsa");
22863afb9a5SDavid du Colombier add_mp(ks, myrsakey.pub.ek);
22963afb9a5SDavid du Colombier add_mp(ks, myrsakey.pub.n);
23063afb9a5SDavid du Colombier return ks;
23163afb9a5SDavid du Colombier }
23263afb9a5SDavid du Colombier
23363afb9a5SDavid du Colombier static void
esma_encode(uchar * h,uchar * em,int nb)23463afb9a5SDavid du Colombier esma_encode(uchar *h, uchar *em, int nb)
23563afb9a5SDavid du Colombier {
23663afb9a5SDavid du Colombier int n, i;
23763afb9a5SDavid du Colombier uchar hh[SHA1dlen];
23863afb9a5SDavid du Colombier static uchar sha1der[] = {
23963afb9a5SDavid du Colombier 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e,
24063afb9a5SDavid du Colombier 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14,
24163afb9a5SDavid du Colombier };
24263afb9a5SDavid du Colombier
24363afb9a5SDavid du Colombier sha1(h, SHA1dlen, hh, nil);
24463afb9a5SDavid du Colombier n = nb - (nelem(sha1der) + SHA1dlen) - 3;
24563afb9a5SDavid du Colombier i = 0;
24663afb9a5SDavid du Colombier em[i++] = 0;
24763afb9a5SDavid du Colombier em[i++] = 1;
24863afb9a5SDavid du Colombier memset(em + i, 0xff, n);
24963afb9a5SDavid du Colombier i += n;
25063afb9a5SDavid du Colombier em[i++] = 0;
25163afb9a5SDavid du Colombier memmove(em + i, sha1der, sizeof sha1der);
25263afb9a5SDavid du Colombier i += sizeof sha1der;
25363afb9a5SDavid du Colombier memmove(em + i, hh, SHA1dlen);
25463afb9a5SDavid du Colombier }
25563afb9a5SDavid du Colombier
25663afb9a5SDavid du Colombier static Packet *
rsa_sign(Conn * c,uchar * m,int nm)25763afb9a5SDavid du Colombier rsa_sign(Conn *c, uchar *m, int nm)
25863afb9a5SDavid du Colombier {
25963afb9a5SDavid du Colombier AuthRpc *ar;
26063afb9a5SDavid du Colombier Packet *sig;
26163afb9a5SDavid du Colombier mpint *s, *mm;
26263afb9a5SDavid du Colombier int fd, n, nbit;
26363afb9a5SDavid du Colombier uchar hh[SHA1dlen];
26463afb9a5SDavid du Colombier uchar *sstr, *em;
26563afb9a5SDavid du Colombier
26663afb9a5SDavid du Colombier if (myrsakey.dk) {
26763afb9a5SDavid du Colombier nbit = mpsignif (myrsakey.pub.n);
26863afb9a5SDavid du Colombier n = (nbit + 7) / 8;
26963afb9a5SDavid du Colombier sstr = emalloc9p(n);
27063afb9a5SDavid du Colombier em = emalloc9p(n);
27163afb9a5SDavid du Colombier /* Compute s: RFC 3447 */
27263afb9a5SDavid du Colombier esma_encode(m, em, n);
27363afb9a5SDavid du Colombier mm = betomp(em, n, nil);
27463afb9a5SDavid du Colombier s = mpnew(nbit);
27563afb9a5SDavid du Colombier mpexp(mm, myrsakey.dk, myrsakey.pub.n, s);
27663afb9a5SDavid du Colombier mptobe(s, sstr, n, nil);
27763afb9a5SDavid du Colombier mpfree(mm);
27863afb9a5SDavid du Colombier mpfree(s);
27963afb9a5SDavid du Colombier free(em);
28063afb9a5SDavid du Colombier } else {
28163afb9a5SDavid du Colombier fd = open("/mnt/factotum/rpc", ORDWR);
28263afb9a5SDavid du Colombier if (fd < 0)
28363afb9a5SDavid du Colombier return nil;
28463afb9a5SDavid du Colombier sha1(m, nm, hh, nil);
28563afb9a5SDavid du Colombier ar = auth_allocrpc(fd);
28663afb9a5SDavid du Colombier if (ar == nil ||
28763afb9a5SDavid du Colombier auth_rpc(ar, "start", "role=sign proto=rsa", 19) != ARok ||
28863afb9a5SDavid du Colombier auth_rpc(ar, "write", hh, SHA1dlen) != ARok ||
28963afb9a5SDavid du Colombier auth_rpc(ar, "read", nil, 0) != ARok ||
29063afb9a5SDavid du Colombier ar->arg == nil) {
29163afb9a5SDavid du Colombier sshdebug(c, "got error in factotum: %r");
29263afb9a5SDavid du Colombier auth_freerpc(ar);
29363afb9a5SDavid du Colombier close(fd);
29463afb9a5SDavid du Colombier return nil;
29563afb9a5SDavid du Colombier }
29663afb9a5SDavid du Colombier sstr = emalloc9p(ar->narg);
29763afb9a5SDavid du Colombier memmove(sstr, ar->arg, ar->narg);
29863afb9a5SDavid du Colombier n = ar->narg;
29963afb9a5SDavid du Colombier
30063afb9a5SDavid du Colombier auth_freerpc(ar);
30163afb9a5SDavid du Colombier close(fd);
30263afb9a5SDavid du Colombier }
30363afb9a5SDavid du Colombier sig = new_packet(c);
30463afb9a5SDavid du Colombier add_string(sig, pkas[c->pkalg]->name);
30563afb9a5SDavid du Colombier add_block(sig, sstr, n);
30663afb9a5SDavid du Colombier free(sstr);
30763afb9a5SDavid du Colombier return sig;
30863afb9a5SDavid du Colombier }
30963afb9a5SDavid du Colombier
31063afb9a5SDavid du Colombier /*
31163afb9a5SDavid du Colombier * 0 - If factotum failed, e.g. no key
31263afb9a5SDavid du Colombier * 1 - If key is verified
31363afb9a5SDavid du Colombier * -1 - If factotum found a key, but the verification fails
31463afb9a5SDavid du Colombier */
31563afb9a5SDavid du Colombier static int
rsa_verify(Conn * c,uchar * m,int nm,char * user,char * sig,int)31663afb9a5SDavid du Colombier rsa_verify(Conn *c, uchar *m, int nm, char *user, char *sig, int)
31763afb9a5SDavid du Colombier {
31863afb9a5SDavid du Colombier int fd, n, retval, nbit;
31963afb9a5SDavid du Colombier char *buf, *p, *sigblob;
32063afb9a5SDavid du Colombier uchar *sstr, *em;
32163afb9a5SDavid du Colombier uchar hh[SHA1dlen];
32263afb9a5SDavid du Colombier mpint *s, *mm, *rsa_exponent, *host_modulus;
32363afb9a5SDavid du Colombier AuthRpc *ar;
32463afb9a5SDavid du Colombier
32563afb9a5SDavid du Colombier sshdebug(c, "in rsa_verify for connection: %d", c->id);
32663afb9a5SDavid du Colombier SET(rsa_exponent, host_modulus);
32763afb9a5SDavid du Colombier USED(rsa_exponent, host_modulus);
32863afb9a5SDavid du Colombier if (0 && rsa_exponent) {
32963afb9a5SDavid du Colombier nbit = mpsignif(host_modulus);
33063afb9a5SDavid du Colombier n = (nbit + 7) / 8;
33163afb9a5SDavid du Colombier em = emalloc9p(n);
33263afb9a5SDavid du Colombier /* Compute s: RFC 3447 */
33363afb9a5SDavid du Colombier esma_encode(m, em, n);
33463afb9a5SDavid du Colombier mm = betomp(em, n, nil);
33563afb9a5SDavid du Colombier s = mpnew(1024);
33663afb9a5SDavid du Colombier mpexp(mm, rsa_exponent, host_modulus, s);
33763afb9a5SDavid du Colombier sstr = emalloc9p(n);
33863afb9a5SDavid du Colombier mptobe(s, sstr, n, nil);
33963afb9a5SDavid du Colombier free(em);
34063afb9a5SDavid du Colombier mpfree(mm);
34163afb9a5SDavid du Colombier mpfree(s);
34263afb9a5SDavid du Colombier retval = memcmp(sig, sstr, n);
34363afb9a5SDavid du Colombier free(sstr);
34463afb9a5SDavid du Colombier retval = (retval == 0);
34563afb9a5SDavid du Colombier } else {
34663afb9a5SDavid du Colombier retval = 1;
34763afb9a5SDavid du Colombier fd = open("/mnt/factotum/rpc", ORDWR);
34863afb9a5SDavid du Colombier if (fd < 0) {
34963afb9a5SDavid du Colombier sshdebug(c, "could not open factotum RPC: %r");
35063afb9a5SDavid du Colombier return 0;
35163afb9a5SDavid du Colombier }
35263afb9a5SDavid du Colombier buf = emalloc9p(Blobsz / 2);
35363afb9a5SDavid du Colombier sigblob = emalloc9p(Blobsz);
35463afb9a5SDavid du Colombier p = (char *)get_string(nil, (uchar *)sig, buf, Blobsz / 2, nil);
35563afb9a5SDavid du Colombier get_string(nil, (uchar *)p, sigblob, Blobsz, &n);
35663afb9a5SDavid du Colombier sha1(m, nm, hh, nil);
35763afb9a5SDavid du Colombier if (user != nil)
35863afb9a5SDavid du Colombier p = smprint("role=verify proto=rsa user=%s", user);
35963afb9a5SDavid du Colombier else
36063afb9a5SDavid du Colombier p = smprint("role=verify proto=rsa sys=%s", c->remote);
36163afb9a5SDavid du Colombier
36263afb9a5SDavid du Colombier ar = auth_allocrpc(fd);
36363afb9a5SDavid du Colombier if (ar == nil || auth_rpc(ar, "start", p, strlen(p)) != ARok ||
36463afb9a5SDavid du Colombier auth_rpc(ar, "write", hh, SHA1dlen) != ARok ||
36563afb9a5SDavid du Colombier auth_rpc(ar, "write", sigblob, n) != ARok ||
36663afb9a5SDavid du Colombier auth_rpc(ar, "read", nil, 0) != ARok) {
36763afb9a5SDavid du Colombier sshdebug(c, "got error in factotum: %r");
36863afb9a5SDavid du Colombier retval = 0;
36963afb9a5SDavid du Colombier } else {
37063afb9a5SDavid du Colombier sshdebug(c, "factotum returned %s", ar->ibuf);
37163afb9a5SDavid du Colombier if (strstr(ar->ibuf, "does not verify") != nil)
37263afb9a5SDavid du Colombier retval = -1;
37363afb9a5SDavid du Colombier }
37463afb9a5SDavid du Colombier if (ar != nil)
37563afb9a5SDavid du Colombier auth_freerpc(ar);
37663afb9a5SDavid du Colombier free(p);
37763afb9a5SDavid du Colombier close(fd);
37863afb9a5SDavid du Colombier free(sigblob);
37963afb9a5SDavid du Colombier free(buf);
38063afb9a5SDavid du Colombier }
38163afb9a5SDavid du Colombier return retval;
38263afb9a5SDavid du Colombier }
38363afb9a5SDavid du Colombier
38463afb9a5SDavid du Colombier static Packet *
dss_ks(Conn * c)38563afb9a5SDavid du Colombier dss_ks(Conn *c)
38663afb9a5SDavid du Colombier {
38763afb9a5SDavid du Colombier Packet *ks;
38863afb9a5SDavid du Colombier
38963afb9a5SDavid du Colombier if (mydsskey.pub.p == nil)
39063afb9a5SDavid du Colombier return nil;
39163afb9a5SDavid du Colombier ks = new_packet(c);
39263afb9a5SDavid du Colombier add_string(ks, "ssh-dss");
39363afb9a5SDavid du Colombier add_mp(ks, mydsskey.pub.p);
39463afb9a5SDavid du Colombier add_mp(ks, mydsskey.pub.q);
39563afb9a5SDavid du Colombier add_mp(ks, mydsskey.pub.alpha);
39663afb9a5SDavid du Colombier add_mp(ks, mydsskey.pub.key);
39763afb9a5SDavid du Colombier return ks;
39863afb9a5SDavid du Colombier }
39963afb9a5SDavid du Colombier
40063afb9a5SDavid du Colombier static Packet *
dss_sign(Conn * c,uchar * m,int nm)40163afb9a5SDavid du Colombier dss_sign(Conn *c, uchar *m, int nm)
40263afb9a5SDavid du Colombier {
40363afb9a5SDavid du Colombier AuthRpc *ar;
40463afb9a5SDavid du Colombier DSAsig *s;
40563afb9a5SDavid du Colombier Packet *sig;
40663afb9a5SDavid du Colombier mpint *mm;
40763afb9a5SDavid du Colombier int fd;
40863afb9a5SDavid du Colombier uchar sstr[2*SHA1dlen];
40963afb9a5SDavid du Colombier
41063afb9a5SDavid du Colombier sha1(m, nm, sstr, nil);
41163afb9a5SDavid du Colombier sig = new_packet(c);
41263afb9a5SDavid du Colombier add_string(sig, pkas[c->pkalg]->name);
41363afb9a5SDavid du Colombier if (mydsskey.secret) {
41463afb9a5SDavid du Colombier mm = betomp(sstr, SHA1dlen, nil);
41563afb9a5SDavid du Colombier s = dsasign(&mydsskey, mm);
41663afb9a5SDavid du Colombier mptobe(s->r, sstr, SHA1dlen, nil);
41763afb9a5SDavid du Colombier mptobe(s->s, sstr+SHA1dlen, SHA1dlen, nil);
41863afb9a5SDavid du Colombier dsasigfree(s);
41963afb9a5SDavid du Colombier mpfree(mm);
42063afb9a5SDavid du Colombier } else {
42163afb9a5SDavid du Colombier fd = open("/mnt/factotum/rpc", ORDWR);
42263afb9a5SDavid du Colombier if (fd < 0)
42363afb9a5SDavid du Colombier return nil;
42463afb9a5SDavid du Colombier ar = auth_allocrpc(fd);
42563afb9a5SDavid du Colombier if (ar == nil ||
42663afb9a5SDavid du Colombier auth_rpc(ar, "start", "role=sign proto=dsa", 19) != ARok ||
42763afb9a5SDavid du Colombier auth_rpc(ar, "write", sstr, SHA1dlen) != ARok ||
42863afb9a5SDavid du Colombier auth_rpc(ar, "read", nil, 0) != ARok) {
42963afb9a5SDavid du Colombier sshdebug(c, "got error in factotum: %r");
43063afb9a5SDavid du Colombier auth_freerpc(ar);
43163afb9a5SDavid du Colombier close(fd);
43263afb9a5SDavid du Colombier return nil;
43363afb9a5SDavid du Colombier }
43463afb9a5SDavid du Colombier memmove(sstr, ar->arg, ar->narg);
43563afb9a5SDavid du Colombier auth_freerpc(ar);
43663afb9a5SDavid du Colombier close(fd);
43763afb9a5SDavid du Colombier }
43863afb9a5SDavid du Colombier add_block(sig, sstr, 2*SHA1dlen);
43963afb9a5SDavid du Colombier return sig;
44063afb9a5SDavid du Colombier }
44163afb9a5SDavid du Colombier
44263afb9a5SDavid du Colombier static int
dss_verify(Conn * c,uchar * m,int nm,char * user,char * sig,int nsig)44363afb9a5SDavid du Colombier dss_verify(Conn *c, uchar *m, int nm, char *user, char *sig, int nsig)
44463afb9a5SDavid du Colombier {
44563afb9a5SDavid du Colombier sshdebug(c, "in dss_verify for connection: %d", c->id);
44663afb9a5SDavid du Colombier USED(m, nm, user, sig, nsig);
44763afb9a5SDavid du Colombier return 0;
44863afb9a5SDavid du Colombier }
44963afb9a5SDavid du Colombier
45063afb9a5SDavid du Colombier static int
dh_server1(Conn * c,Packet * pack1)45163afb9a5SDavid du Colombier dh_server1(Conn *c, Packet *pack1)
45263afb9a5SDavid du Colombier {
45363afb9a5SDavid du Colombier return dh_server(c, pack1, p1, 1024);
45463afb9a5SDavid du Colombier }
45563afb9a5SDavid du Colombier
45663afb9a5SDavid du Colombier static int
dh_server14(Conn * c,Packet * pack1)45763afb9a5SDavid du Colombier dh_server14(Conn *c, Packet *pack1)
45863afb9a5SDavid du Colombier {
45963afb9a5SDavid du Colombier return dh_server(c, pack1, p14, 2048);
46063afb9a5SDavid du Colombier }
46163afb9a5SDavid du Colombier
46263afb9a5SDavid du Colombier static int
dh_server(Conn * c,Packet * pack1,mpint * grp,int nbit)46363afb9a5SDavid du Colombier dh_server(Conn *c, Packet *pack1, mpint *grp, int nbit)
46463afb9a5SDavid du Colombier {
46563afb9a5SDavid du Colombier Packet *pack2, *ks, *sig;
46663afb9a5SDavid du Colombier mpint *y, *e, *f, *k;
46763afb9a5SDavid du Colombier int n, ret;
46863afb9a5SDavid du Colombier uchar h[SHA1dlen];
46963afb9a5SDavid du Colombier
47063afb9a5SDavid du Colombier ret = -1;
47163afb9a5SDavid du Colombier qlock(&c->l);
47263afb9a5SDavid du Colombier f = mpnew(nbit);
47363afb9a5SDavid du Colombier k = mpnew(nbit);
47463afb9a5SDavid du Colombier
47563afb9a5SDavid du Colombier /* Compute f: RFC4253 */
47663afb9a5SDavid du Colombier y = mprand(nbit / 8, genrandom, nil);
47763afb9a5SDavid du Colombier if (debug > 1)
47863afb9a5SDavid du Colombier sshdebug(c, "y=%M", y);
47963afb9a5SDavid du Colombier mpexp(two, y, grp, f);
48063afb9a5SDavid du Colombier if (debug > 1)
48163afb9a5SDavid du Colombier sshdebug(c, "f=%M", f);
48263afb9a5SDavid du Colombier
48363afb9a5SDavid du Colombier /* Compute k: RFC4253 */
48463afb9a5SDavid du Colombier if (debug > 1)
48563afb9a5SDavid du Colombier dump_packet(pack1);
48663afb9a5SDavid du Colombier e = get_mp(pack1->payload+1);
48763afb9a5SDavid du Colombier if (debug > 1)
48863afb9a5SDavid du Colombier sshdebug(c, "e=%M", e);
48963afb9a5SDavid du Colombier mpexp(e, y, grp, k);
49063afb9a5SDavid du Colombier if (debug > 1)
49163afb9a5SDavid du Colombier sshdebug(c, "k=%M", k);
49263afb9a5SDavid du Colombier
49363afb9a5SDavid du Colombier /* Compute H: RFC 4253 */
49463afb9a5SDavid du Colombier pack2 = new_packet(c);
49563afb9a5SDavid du Colombier sshdebug(c, "ID strings: %s---%s", c->otherid, MYID);
49663afb9a5SDavid du Colombier add_string(pack2, c->otherid);
49763afb9a5SDavid du Colombier add_string(pack2, MYID);
49863afb9a5SDavid du Colombier if (debug > 1) {
49963afb9a5SDavid du Colombier fprint(2, "received kexinit:");
50063afb9a5SDavid du Colombier dump_packet(c->rkexinit);
50163afb9a5SDavid du Colombier fprint(2, "\nsent kexinit:");
50263afb9a5SDavid du Colombier dump_packet(c->skexinit);
50363afb9a5SDavid du Colombier }
50463afb9a5SDavid du Colombier add_block(pack2, c->rkexinit->payload, c->rkexinit->rlength - 1);
50563afb9a5SDavid du Colombier add_block(pack2, c->skexinit->payload,
50663afb9a5SDavid du Colombier c->skexinit->rlength - c->skexinit->pad_len - 1);
50763afb9a5SDavid du Colombier sig = nil;
50863afb9a5SDavid du Colombier ks = pkas[c->pkalg]->ks(c);
50963afb9a5SDavid du Colombier if (ks == nil)
51063afb9a5SDavid du Colombier goto err;
51163afb9a5SDavid du Colombier add_block(pack2, ks->payload, ks->rlength - 1);
51263afb9a5SDavid du Colombier add_mp(pack2, e);
51363afb9a5SDavid du Colombier add_mp(pack2, f);
51463afb9a5SDavid du Colombier add_mp(pack2, k);
51563afb9a5SDavid du Colombier sha1(pack2->payload, pack2->rlength - 1, h, nil);
51663afb9a5SDavid du Colombier
51763afb9a5SDavid du Colombier if (c->got_sessid == 0) {
51863afb9a5SDavid du Colombier memmove(c->sessid, h, SHA1dlen);
51963afb9a5SDavid du Colombier c->got_sessid = 1;
52063afb9a5SDavid du Colombier }
52163afb9a5SDavid du Colombier sig = pkas[c->pkalg]->sign(c, h, SHA1dlen);
52263afb9a5SDavid du Colombier if (sig == nil) {
52363afb9a5SDavid du Colombier sshlog(c, "failed to generate signature: %r");
52463afb9a5SDavid du Colombier goto err;
52563afb9a5SDavid du Colombier }
52663afb9a5SDavid du Colombier
52763afb9a5SDavid du Colombier /* Send (K_s || f || s) to client: RFC4253 */
52863afb9a5SDavid du Colombier init_packet(pack2);
52963afb9a5SDavid du Colombier pack2->c = c;
53063afb9a5SDavid du Colombier add_byte(pack2, SSH_MSG_KEXDH_REPLY);
53163afb9a5SDavid du Colombier add_block(pack2, ks->payload, ks->rlength - 1);
53263afb9a5SDavid du Colombier add_mp(pack2, f);
53363afb9a5SDavid du Colombier add_block(pack2, sig->payload, sig->rlength - 1);
53463afb9a5SDavid du Colombier if (debug > 1)
53563afb9a5SDavid du Colombier dump_packet(pack2);
53663afb9a5SDavid du Colombier n = finish_packet(pack2);
53763afb9a5SDavid du Colombier if (debug > 1) {
53863afb9a5SDavid du Colombier sshdebug(c, "writing %d bytes: len %d", n, nhgetl(pack2->nlength));
53963afb9a5SDavid du Colombier dump_packet(pack2);
54063afb9a5SDavid du Colombier }
54163afb9a5SDavid du Colombier iowrite(c->dio, c->datafd, pack2->nlength, n);
54263afb9a5SDavid du Colombier
54363afb9a5SDavid du Colombier genkeys(c, h, k);
54463afb9a5SDavid du Colombier
54563afb9a5SDavid du Colombier /* Send SSH_MSG_NEWKEYS */
54663afb9a5SDavid du Colombier init_packet(pack2);
54763afb9a5SDavid du Colombier pack2->c = c;
54863afb9a5SDavid du Colombier add_byte(pack2, SSH_MSG_NEWKEYS);
54963afb9a5SDavid du Colombier n = finish_packet(pack2);
55063afb9a5SDavid du Colombier iowrite(c->dio, c->datafd, pack2->nlength, n);
55163afb9a5SDavid du Colombier ret = 0;
55263afb9a5SDavid du Colombier err:
55363afb9a5SDavid du Colombier mpfree(f);
55463afb9a5SDavid du Colombier mpfree(e);
55563afb9a5SDavid du Colombier mpfree(k);
55663afb9a5SDavid du Colombier mpfree(y);
55763afb9a5SDavid du Colombier free(sig);
55863afb9a5SDavid du Colombier free(ks);
55963afb9a5SDavid du Colombier free(pack2);
56063afb9a5SDavid du Colombier qunlock(&c->l);
56163afb9a5SDavid du Colombier return ret;
56263afb9a5SDavid du Colombier }
56363afb9a5SDavid du Colombier
56463afb9a5SDavid du Colombier static int
dh_client11(Conn * c,Packet *)56563afb9a5SDavid du Colombier dh_client11(Conn *c, Packet *)
56663afb9a5SDavid du Colombier {
567*c59d18e2SDavid du Colombier return dh_client1(c, p1, 128, 1024);
568*c59d18e2SDavid du Colombier }
569*c59d18e2SDavid du Colombier
570*c59d18e2SDavid du Colombier static int
dh_client141(Conn * c,Packet *)571*c59d18e2SDavid du Colombier dh_client141(Conn *c, Packet *)
572*c59d18e2SDavid du Colombier {
573*c59d18e2SDavid du Colombier return dh_client1(c, p14, 256, 2014);
574*c59d18e2SDavid du Colombier }
575*c59d18e2SDavid du Colombier
576*c59d18e2SDavid du Colombier static int
dh_client1(Conn * c,mpint * grp,int nrand,int nbit)577*c59d18e2SDavid du Colombier dh_client1(Conn *c, mpint *grp, int nrand, int nbit)
578*c59d18e2SDavid du Colombier {
57963afb9a5SDavid du Colombier Packet *p;
58063afb9a5SDavid du Colombier int n;
58163afb9a5SDavid du Colombier
58263afb9a5SDavid du Colombier if (c->e)
58363afb9a5SDavid du Colombier mpfree(c->e);
584*c59d18e2SDavid du Colombier c->e = mpnew(nbit);
58563afb9a5SDavid du Colombier
58663afb9a5SDavid du Colombier /* Compute e: RFC4253 */
58763afb9a5SDavid du Colombier if (c->x)
58863afb9a5SDavid du Colombier mpfree(c->x);
589*c59d18e2SDavid du Colombier c->x = mprand(nrand, genrandom, nil);
590*c59d18e2SDavid du Colombier mpexp(two, c->x, grp, c->e);
59163afb9a5SDavid du Colombier
59263afb9a5SDavid du Colombier p = new_packet(c);
59363afb9a5SDavid du Colombier add_byte(p, SSH_MSG_KEXDH_INIT);
59463afb9a5SDavid du Colombier add_mp(p, c->e);
59563afb9a5SDavid du Colombier n = finish_packet(p);
59663afb9a5SDavid du Colombier iowrite(c->dio, c->datafd, p->nlength, n);
59763afb9a5SDavid du Colombier free(p);
59863afb9a5SDavid du Colombier return 0;
59963afb9a5SDavid du Colombier }
60063afb9a5SDavid du Colombier
60163afb9a5SDavid du Colombier static int
findkeyinuserring(Conn * c,RSApub * srvkey)60263afb9a5SDavid du Colombier findkeyinuserring(Conn *c, RSApub *srvkey)
60363afb9a5SDavid du Colombier {
60463afb9a5SDavid du Colombier int n;
60563afb9a5SDavid du Colombier char *home, *newkey, *r;
60663afb9a5SDavid du Colombier
60763afb9a5SDavid du Colombier home = getenv("home");
60863afb9a5SDavid du Colombier if (home == nil) {
60963afb9a5SDavid du Colombier newkey = "No home directory for key file";
61063afb9a5SDavid du Colombier free(keymbox.msg);
61163afb9a5SDavid du Colombier keymbox.msg = smprint("b%04ld%s", strlen(newkey), newkey);
61263afb9a5SDavid du Colombier return -1;
61363afb9a5SDavid du Colombier }
61463afb9a5SDavid du Colombier
61563afb9a5SDavid du Colombier r = smprint("%s/lib/keyring", home);
61663afb9a5SDavid du Colombier free(home);
61763afb9a5SDavid du Colombier if ((n = findkey(r, c->remote, srvkey)) != KeyOk) {
61863afb9a5SDavid du Colombier newkey = smprint("ek=%M n=%M", srvkey->ek, srvkey->n);
61963afb9a5SDavid du Colombier free(keymbox.msg);
62063afb9a5SDavid du Colombier keymbox.msg = smprint("%c%04ld%s", n == NoKeyFile || n == NoKey?
62163afb9a5SDavid du Colombier 'c': 'b', strlen(newkey), newkey);
62263afb9a5SDavid du Colombier free(newkey);
62363afb9a5SDavid du Colombier
62463afb9a5SDavid du Colombier nbsendul(keymbox.mchan, 1);
62563afb9a5SDavid du Colombier recvul(keymbox.mchan);
62663afb9a5SDavid du Colombier if (keymbox.msg == nil || keymbox.msg[0] == 'n') {
62763afb9a5SDavid du Colombier free(keymbox.msg);
62863afb9a5SDavid du Colombier keymbox.msg = nil;
62963afb9a5SDavid du Colombier newkey = "Server key reject";
63063afb9a5SDavid du Colombier keymbox.msg = smprint("f%04ld%s", strlen(newkey), newkey);
63163afb9a5SDavid du Colombier return -1;
63263afb9a5SDavid du Colombier }
63363afb9a5SDavid du Colombier sshdebug(c, "adding key");
63463afb9a5SDavid du Colombier if (keymbox.msg[0] == 'y')
63563afb9a5SDavid du Colombier appendkey(r, c->remote, srvkey);
63663afb9a5SDavid du Colombier else if (keymbox.msg[0] == 'r')
63763afb9a5SDavid du Colombier replacekey(r, c->remote, srvkey);
63863afb9a5SDavid du Colombier }
63963afb9a5SDavid du Colombier free(r);
64063afb9a5SDavid du Colombier return 0;
64163afb9a5SDavid du Colombier }
64263afb9a5SDavid du Colombier
64363afb9a5SDavid du Colombier static int
verifyhostkey(Conn * c,RSApub * srvkey,Packet * sig)64463afb9a5SDavid du Colombier verifyhostkey(Conn *c, RSApub *srvkey, Packet *sig)
64563afb9a5SDavid du Colombier {
64663afb9a5SDavid du Colombier int fd, n;
64763afb9a5SDavid du Colombier char *newkey;
64863afb9a5SDavid du Colombier uchar h[SHA1dlen];
64963afb9a5SDavid du Colombier
65063afb9a5SDavid du Colombier sshdebug(c, "verifying server signature");
65163afb9a5SDavid du Colombier if (findkey("/sys/lib/ssh/keyring", c->remote, srvkey) != KeyOk &&
65263afb9a5SDavid du Colombier findkeyinuserring(c, srvkey) < 0) {
65363afb9a5SDavid du Colombier nbsendul(keymbox.mchan, 1);
65463afb9a5SDavid du Colombier mpfree(srvkey->ek);
65563afb9a5SDavid du Colombier mpfree(srvkey->n);
656998526ebSDavid du Colombier return Errnokey;
65763afb9a5SDavid du Colombier }
65863afb9a5SDavid du Colombier
65963afb9a5SDavid du Colombier newkey = smprint("key proto=rsa role=verify sys=%s size=%d ek=%M n=%M",
66063afb9a5SDavid du Colombier c->remote, mpsignif(srvkey->n), srvkey->ek, srvkey->n);
66163afb9a5SDavid du Colombier if (newkey == nil) {
66263afb9a5SDavid du Colombier sshlog(c, "out of memory");
663998526ebSDavid du Colombier threadexits("out of memory");
66463afb9a5SDavid du Colombier }
66563afb9a5SDavid du Colombier
66663afb9a5SDavid du Colombier fd = open("/mnt/factotum/ctl", OWRITE);
66763afb9a5SDavid du Colombier if (fd >= 0)
66863afb9a5SDavid du Colombier write(fd, newkey, strlen(newkey));
66963afb9a5SDavid du Colombier /* leave fd open */
67063afb9a5SDavid du Colombier else
67163afb9a5SDavid du Colombier sshdebug(c, "factotum open failed: %r");
67263afb9a5SDavid du Colombier
67363afb9a5SDavid du Colombier free(newkey);
67463afb9a5SDavid du Colombier mpfree(srvkey->ek);
67563afb9a5SDavid du Colombier mpfree(srvkey->n);
67663afb9a5SDavid du Colombier free(keymbox.msg);
67763afb9a5SDavid du Colombier keymbox.msg = nil;
67863afb9a5SDavid du Colombier
67963afb9a5SDavid du Colombier n = pkas[c->pkalg]->verify(c, h, SHA1dlen, nil, (char *)sig->payload,
68063afb9a5SDavid du Colombier sig->rlength);
68163afb9a5SDavid du Colombier
68263afb9a5SDavid du Colombier /* fd is perhaps still open */
68363afb9a5SDavid du Colombier if (fd >= 0) {
68463afb9a5SDavid du Colombier /* sys here is a dotted-quad ip address */
68563afb9a5SDavid du Colombier newkey = smprint("delkey proto=rsa role=verify sys=%s",
68663afb9a5SDavid du Colombier c->remote);
68763afb9a5SDavid du Colombier if (newkey) {
68863afb9a5SDavid du Colombier seek(fd, 0, 0);
68963afb9a5SDavid du Colombier write(fd, newkey, strlen(newkey));
69063afb9a5SDavid du Colombier free(newkey);
69163afb9a5SDavid du Colombier }
69263afb9a5SDavid du Colombier close(fd);
69363afb9a5SDavid du Colombier }
69463afb9a5SDavid du Colombier return n;
69563afb9a5SDavid du Colombier }
69663afb9a5SDavid du Colombier
69763afb9a5SDavid du Colombier static int
dh_client12(Conn * c,Packet * p)69863afb9a5SDavid du Colombier dh_client12(Conn *c, Packet *p)
69963afb9a5SDavid du Colombier {
700*c59d18e2SDavid du Colombier return dh_client2(c, p, p1, 1024);
701*c59d18e2SDavid du Colombier }
702*c59d18e2SDavid du Colombier
703*c59d18e2SDavid du Colombier static int
dh_client142(Conn * c,Packet * p)704*c59d18e2SDavid du Colombier dh_client142(Conn *c, Packet *p)
705*c59d18e2SDavid du Colombier {
706*c59d18e2SDavid du Colombier return dh_client2(c, p, p14, 2048);
707*c59d18e2SDavid du Colombier }
708*c59d18e2SDavid du Colombier
709*c59d18e2SDavid du Colombier static int
dh_client2(Conn * c,Packet * p,mpint * grp,int nbits)710*c59d18e2SDavid du Colombier dh_client2(Conn *c, Packet *p, mpint *grp, int nbits)
711*c59d18e2SDavid du Colombier {
71263afb9a5SDavid du Colombier int n, retval;
71348207d97SDavid du Colombier #ifdef VERIFYKEYS
71463afb9a5SDavid du Colombier char *newkey;
71548207d97SDavid du Colombier #endif
71663afb9a5SDavid du Colombier char buf[10];
71763afb9a5SDavid du Colombier uchar *q;
71863afb9a5SDavid du Colombier uchar h[SHA1dlen];
71963afb9a5SDavid du Colombier mpint *f, *k;
72063afb9a5SDavid du Colombier Packet *ks, *sig, *pack2;
72163afb9a5SDavid du Colombier RSApub *srvkey;
72263afb9a5SDavid du Colombier
72363afb9a5SDavid du Colombier ks = new_packet(c);
72463afb9a5SDavid du Colombier sig = new_packet(c);
72563afb9a5SDavid du Colombier pack2 = new_packet(c);
72663afb9a5SDavid du Colombier
72763afb9a5SDavid du Colombier q = get_string(p, p->payload+1, (char *)ks->payload, Maxpktpay, &n);
72863afb9a5SDavid du Colombier ks->rlength = n + 1;
72963afb9a5SDavid du Colombier f = get_mp(q);
73063afb9a5SDavid du Colombier q += nhgetl(q) + 4;
73163afb9a5SDavid du Colombier get_string(p, q, (char *)sig->payload, Maxpktpay, &n);
73263afb9a5SDavid du Colombier sig->rlength = n;
733*c59d18e2SDavid du Colombier k = mpnew(nbits);
734*c59d18e2SDavid du Colombier mpexp(f, c->x, grp, k);
73563afb9a5SDavid du Colombier
73663afb9a5SDavid du Colombier /* Compute H: RFC 4253 */
73763afb9a5SDavid du Colombier init_packet(pack2);
73863afb9a5SDavid du Colombier pack2->c = c;
73963afb9a5SDavid du Colombier if (debug > 1)
74063afb9a5SDavid du Colombier sshdebug(c, "ID strings: %s---%s", c->otherid, MYID);
74163afb9a5SDavid du Colombier add_string(pack2, MYID);
74263afb9a5SDavid du Colombier add_string(pack2, c->otherid);
74363afb9a5SDavid du Colombier if (debug > 1) {
74463afb9a5SDavid du Colombier fprint(2, "received kexinit:");
74563afb9a5SDavid du Colombier dump_packet(c->rkexinit);
74663afb9a5SDavid du Colombier fprint(2, "\nsent kexinit:");
74763afb9a5SDavid du Colombier dump_packet(c->skexinit);
74863afb9a5SDavid du Colombier }
74963afb9a5SDavid du Colombier add_block(pack2, c->skexinit->payload,
75063afb9a5SDavid du Colombier c->skexinit->rlength - c->skexinit->pad_len - 1);
75163afb9a5SDavid du Colombier add_block(pack2, c->rkexinit->payload, c->rkexinit->rlength - 1);
75263afb9a5SDavid du Colombier add_block(pack2, ks->payload, ks->rlength - 1);
75363afb9a5SDavid du Colombier add_mp(pack2, c->e);
75463afb9a5SDavid du Colombier add_mp(pack2, f);
75563afb9a5SDavid du Colombier add_mp(pack2, k);
75663afb9a5SDavid du Colombier sha1(pack2->payload, pack2->rlength - 1, h, nil);
75763afb9a5SDavid du Colombier mpfree(f);
75863afb9a5SDavid du Colombier
75963afb9a5SDavid du Colombier if (c->got_sessid == 0) {
76063afb9a5SDavid du Colombier memmove(c->sessid, h, SHA1dlen);
76163afb9a5SDavid du Colombier c->got_sessid = 1;
76263afb9a5SDavid du Colombier }
76363afb9a5SDavid du Colombier
76463afb9a5SDavid du Colombier q = get_string(ks, ks->payload, buf, sizeof buf, nil);
76563afb9a5SDavid du Colombier srvkey = emalloc9p(sizeof (RSApub));
76663afb9a5SDavid du Colombier srvkey->ek = get_mp(q);
76763afb9a5SDavid du Colombier q += nhgetl(q) + 4;
76863afb9a5SDavid du Colombier srvkey->n = get_mp(q);
76963afb9a5SDavid du Colombier
77063afb9a5SDavid du Colombier /*
77163afb9a5SDavid du Colombier * key verification is really pretty pedantic and
77263afb9a5SDavid du Colombier * not doing it lets us talk to ssh v1 implementations.
77363afb9a5SDavid du Colombier */
77463afb9a5SDavid du Colombier if (nokeyverify)
775998526ebSDavid du Colombier n = Errnone;
77663afb9a5SDavid du Colombier else
77763afb9a5SDavid du Colombier n = verifyhostkey(c, srvkey, sig);
77848207d97SDavid du Colombier retval = -1;
77948207d97SDavid du Colombier USED(retval);
78063afb9a5SDavid du Colombier switch (n) {
781998526ebSDavid du Colombier #ifdef VERIFYKEYS
782998526ebSDavid du Colombier case Errnokey:
78363afb9a5SDavid du Colombier goto out;
784998526ebSDavid du Colombier case Errnoverify:
785d7e44d0dSDavid du Colombier newkey = "signature verification failed; try netssh -v";
78663afb9a5SDavid du Colombier keymbox.msg = smprint("f%04ld%s", strlen(newkey), newkey);
78763afb9a5SDavid du Colombier break;
788998526ebSDavid du Colombier case Errfactotum:
789998526ebSDavid du Colombier newkey = "factotum dialogue failed; try netssh -v";
79063afb9a5SDavid du Colombier keymbox.msg = smprint("f%04ld%s", strlen(newkey), newkey);
79163afb9a5SDavid du Colombier break;
792998526ebSDavid du Colombier case Errnone:
793998526ebSDavid du Colombier #else
794998526ebSDavid du Colombier default:
795998526ebSDavid du Colombier #endif
79663afb9a5SDavid du Colombier keymbox.msg = smprint("o0000");
79763afb9a5SDavid du Colombier retval = 0;
79863afb9a5SDavid du Colombier break;
79963afb9a5SDavid du Colombier }
80063afb9a5SDavid du Colombier nbsendul(keymbox.mchan, 1);
80163afb9a5SDavid du Colombier if (retval == 0)
80263afb9a5SDavid du Colombier genkeys(c, h, k);
80348207d97SDavid du Colombier #ifdef VERIFYKEYS
80463afb9a5SDavid du Colombier out:
80548207d97SDavid du Colombier #endif
80663afb9a5SDavid du Colombier mpfree(k);
80763afb9a5SDavid du Colombier free(ks);
80863afb9a5SDavid du Colombier free(sig);
80963afb9a5SDavid du Colombier free(pack2);
81063afb9a5SDavid du Colombier free(srvkey);
81163afb9a5SDavid du Colombier return retval;
81263afb9a5SDavid du Colombier }
81363afb9a5SDavid du Colombier
81463afb9a5SDavid du Colombier static void
initsha1pkt(Packet * pack2,mpint * k,uchar * h)81563afb9a5SDavid du Colombier initsha1pkt(Packet *pack2, mpint *k, uchar *h)
81663afb9a5SDavid du Colombier {
81763afb9a5SDavid du Colombier init_packet(pack2);
81863afb9a5SDavid du Colombier add_mp(pack2, k);
81963afb9a5SDavid du Colombier add_packet(pack2, h, SHA1dlen);
82063afb9a5SDavid du Colombier }
82163afb9a5SDavid du Colombier
82263afb9a5SDavid du Colombier static void
genkeys(Conn * c,uchar h[],mpint * k)82363afb9a5SDavid du Colombier genkeys(Conn *c, uchar h[], mpint *k)
82463afb9a5SDavid du Colombier {
82563afb9a5SDavid du Colombier Packet *pack2;
82663afb9a5SDavid du Colombier char buf[82], *bp, *be; /* magic 82 */
82763afb9a5SDavid du Colombier int n;
82863afb9a5SDavid du Colombier
82963afb9a5SDavid du Colombier pack2 = new_packet(c);
83063afb9a5SDavid du Colombier /* Compute 40 bytes (320 bits) of keys: each alg can use what it needs */
83163afb9a5SDavid du Colombier
83263afb9a5SDavid du Colombier /* Client to server IV */
83363afb9a5SDavid du Colombier if (debug > 1) {
83463afb9a5SDavid du Colombier fprint(2, "k=%M\nh=", k);
83563afb9a5SDavid du Colombier for (n = 0; n < SHA1dlen; ++n)
83663afb9a5SDavid du Colombier fprint(2, "%02ux", h[n]);
83763afb9a5SDavid du Colombier fprint(2, "\nsessid=");
83863afb9a5SDavid du Colombier for (n = 0; n < SHA1dlen; ++n)
83963afb9a5SDavid du Colombier fprint(2, "%02ux", c->sessid[n]);
84063afb9a5SDavid du Colombier fprint(2, "\n");
84163afb9a5SDavid du Colombier }
84263afb9a5SDavid du Colombier initsha1pkt(pack2, k, h);
84363afb9a5SDavid du Colombier add_byte(pack2, 'A');
84463afb9a5SDavid du Colombier add_packet(pack2, c->sessid, SHA1dlen);
84563afb9a5SDavid du Colombier sha1(pack2->payload, pack2->rlength - 1, c->nc2siv, nil);
84663afb9a5SDavid du Colombier initsha1pkt(pack2, k, h);
84763afb9a5SDavid du Colombier add_packet(pack2, c->nc2siv, SHA1dlen);
84863afb9a5SDavid du Colombier sha1(pack2->payload, pack2->rlength - 1, c->nc2siv + SHA1dlen, nil);
84963afb9a5SDavid du Colombier
85063afb9a5SDavid du Colombier /* Server to client IV */
85163afb9a5SDavid du Colombier initsha1pkt(pack2, k, h);
85263afb9a5SDavid du Colombier add_byte(pack2, 'B');
85363afb9a5SDavid du Colombier add_packet(pack2, c->sessid, SHA1dlen);
85463afb9a5SDavid du Colombier sha1(pack2->payload, pack2->rlength - 1, c->ns2civ, nil);
85563afb9a5SDavid du Colombier initsha1pkt(pack2, k, h);
85663afb9a5SDavid du Colombier add_packet(pack2, c->ns2civ, SHA1dlen);
85763afb9a5SDavid du Colombier sha1(pack2->payload, pack2->rlength - 1, c->ns2civ + SHA1dlen, nil);
85863afb9a5SDavid du Colombier
85963afb9a5SDavid du Colombier /* Client to server encryption key */
86063afb9a5SDavid du Colombier initsha1pkt(pack2, k, h);
86163afb9a5SDavid du Colombier add_byte(pack2, 'C');
86263afb9a5SDavid du Colombier add_packet(pack2, c->sessid, SHA1dlen);
86363afb9a5SDavid du Colombier sha1(pack2->payload, pack2->rlength - 1, c->nc2sek, nil);
86463afb9a5SDavid du Colombier initsha1pkt(pack2, k, h);
86563afb9a5SDavid du Colombier add_packet(pack2, c->nc2sek, SHA1dlen);
86663afb9a5SDavid du Colombier sha1(pack2->payload, pack2->rlength - 1, c->nc2sek + SHA1dlen, nil);
86763afb9a5SDavid du Colombier
86863afb9a5SDavid du Colombier /* Server to client encryption key */
86963afb9a5SDavid du Colombier initsha1pkt(pack2, k, h);
87063afb9a5SDavid du Colombier add_byte(pack2, 'D');
87163afb9a5SDavid du Colombier add_packet(pack2, c->sessid, SHA1dlen);
87263afb9a5SDavid du Colombier sha1(pack2->payload, pack2->rlength - 1, c->ns2cek, nil);
87363afb9a5SDavid du Colombier initsha1pkt(pack2, k, h);
87463afb9a5SDavid du Colombier add_packet(pack2, c->ns2cek, SHA1dlen);
87563afb9a5SDavid du Colombier sha1(pack2->payload, pack2->rlength - 1, c->ns2cek + SHA1dlen, nil);
87663afb9a5SDavid du Colombier
87763afb9a5SDavid du Colombier /* Client to server integrity key */
87863afb9a5SDavid du Colombier initsha1pkt(pack2, k, h);
87963afb9a5SDavid du Colombier add_byte(pack2, 'E');
88063afb9a5SDavid du Colombier add_packet(pack2, c->sessid, SHA1dlen);
88163afb9a5SDavid du Colombier sha1(pack2->payload, pack2->rlength - 1, c->nc2sik, nil);
88263afb9a5SDavid du Colombier initsha1pkt(pack2, k, h);
88363afb9a5SDavid du Colombier add_packet(pack2, c->nc2sik, SHA1dlen);
88463afb9a5SDavid du Colombier sha1(pack2->payload, pack2->rlength - 1, c->nc2sik + SHA1dlen, nil);
88563afb9a5SDavid du Colombier
88663afb9a5SDavid du Colombier /* Server to client integrity key */
88763afb9a5SDavid du Colombier initsha1pkt(pack2, k, h);
88863afb9a5SDavid du Colombier add_byte(pack2, 'F');
88963afb9a5SDavid du Colombier add_packet(pack2, c->sessid, SHA1dlen);
89063afb9a5SDavid du Colombier sha1(pack2->payload, pack2->rlength - 1, c->ns2cik, nil);
89163afb9a5SDavid du Colombier initsha1pkt(pack2, k, h);
89263afb9a5SDavid du Colombier add_packet(pack2, c->ns2cik, SHA1dlen);
89363afb9a5SDavid du Colombier sha1(pack2->payload, pack2->rlength - 1, c->ns2cik + SHA1dlen, nil);
89463afb9a5SDavid du Colombier
89563afb9a5SDavid du Colombier if (debug > 1) {
89663afb9a5SDavid du Colombier be = buf + sizeof buf;
89763afb9a5SDavid du Colombier fprint(2, "Client to server IV:\n");
89863afb9a5SDavid du Colombier for (n = 0, bp = buf; n < SHA1dlen*2; ++n)
89963afb9a5SDavid du Colombier bp = seprint(bp, be, "%02x", c->nc2siv[n]);
90063afb9a5SDavid du Colombier fprint(2, "%s\n", buf);
90163afb9a5SDavid du Colombier
90263afb9a5SDavid du Colombier fprint(2, "Server to client IV:\n");
90363afb9a5SDavid du Colombier for (n = 0, bp = buf; n < SHA1dlen*2; ++n)
90463afb9a5SDavid du Colombier bp = seprint(bp, be, "%02x", c->ns2civ[n]);
90563afb9a5SDavid du Colombier fprint(2, "%s\n", buf);
90663afb9a5SDavid du Colombier
90763afb9a5SDavid du Colombier fprint(2, "Client to server EK:\n");
90863afb9a5SDavid du Colombier for (n = 0, bp = buf; n < SHA1dlen*2; ++n)
90963afb9a5SDavid du Colombier bp = seprint(bp, be, "%02x", c->nc2sek[n]);
91063afb9a5SDavid du Colombier fprint(2, "%s\n", buf);
91163afb9a5SDavid du Colombier
91263afb9a5SDavid du Colombier fprint(2, "Server to client EK:\n");
91363afb9a5SDavid du Colombier for (n = 0, bp = buf; n < SHA1dlen*2; ++n)
91463afb9a5SDavid du Colombier bp = seprint(bp, be, "%02x", c->ns2cek[n]);
91563afb9a5SDavid du Colombier fprint(2, "%s\n", buf);
91663afb9a5SDavid du Colombier }
91763afb9a5SDavid du Colombier free(pack2);
91863afb9a5SDavid du Colombier }
91963afb9a5SDavid du Colombier
92063afb9a5SDavid du Colombier Kex dh1sha1 = {
92163afb9a5SDavid du Colombier "diffie-hellman-group1-sha1",
92263afb9a5SDavid du Colombier dh_server1,
92363afb9a5SDavid du Colombier dh_client11,
92463afb9a5SDavid du Colombier dh_client12
92563afb9a5SDavid du Colombier };
92663afb9a5SDavid du Colombier
92763afb9a5SDavid du Colombier Kex dh14sha1 = {
92863afb9a5SDavid du Colombier "diffie-hellman-group14-sha1",
92963afb9a5SDavid du Colombier dh_server14,
93063afb9a5SDavid du Colombier dh_client141,
93163afb9a5SDavid du Colombier dh_client142
93263afb9a5SDavid du Colombier };
93363afb9a5SDavid du Colombier
93463afb9a5SDavid du Colombier PKA rsa_pka = {
93563afb9a5SDavid du Colombier "ssh-rsa",
93663afb9a5SDavid du Colombier rsa_ks,
93763afb9a5SDavid du Colombier rsa_sign,
93863afb9a5SDavid du Colombier rsa_verify
93963afb9a5SDavid du Colombier };
94063afb9a5SDavid du Colombier
94163afb9a5SDavid du Colombier PKA dss_pka = {
94263afb9a5SDavid du Colombier "ssh-dss",
94363afb9a5SDavid du Colombier dss_ks,
94463afb9a5SDavid du Colombier dss_sign,
94563afb9a5SDavid du Colombier dss_verify
94663afb9a5SDavid du Colombier };
947