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