Пример #1
0
static void stringstringparser_test1(void) {

    unsigned char *buf;
    long long i, pos = 0;
    unsigned char *x;
    long long xlen, len;

    for (i = 0; testvectors[i].buf; ++i) {
        buf = (unsigned char *)testvectors[i].buf;
        len = str_len(testvectors[i].buf);
        pos = 0;

        pos = stringparser(buf, len, pos, &x, &xlen); if (!pos) fail("parsing error");
        if (xlen != 3) fail("parsing error");
        if (!byte_isequal(x, xlen, "aaa")) fail("parsing error");

        pos = stringparser(buf, len, pos, &x, &xlen); if (!pos) fail("parsing error");
        if (xlen != 2) fail("parsing error");
        if (!byte_isequal(x, xlen, "bb")) fail("parsing error");

        pos = stringparser(buf, len, pos, &x, &xlen); if (!pos) fail("parsing error");
        if (xlen != 1) fail("parsing error");
        if (!byte_isequal(x, xlen, "c")) fail("parsing error");

        if (stringparser(buf, len, pos, &x, &xlen)) fail("overflow");
    }
}
Пример #2
0
int main(void) {

    unsigned char b1[32];
    unsigned char b2[32];
    long long i, j;
    const char *x = "abcdefgh";
    char y[8];

    /* byte_zero test */
    for (i = 0; i < 32; ++i) {
        for (j = 0; j < sizeof b1; ++j) b1[j] = 0;
        for (j = 0; j < sizeof b2; ++j) b2[j] = 0;
        b1[i] = 0xff; b2[i] = 0xff;
        byte_zero(b1, sizeof b1);

        if (byte_isequal(b1, 32, b2) != 0) fail("byte_zero failure");
    }

    /* byte_isequal test */
    for (i = 0; i < sizeof b1; ++i) b1[i] = 0xff;
    for (i = 0; i < sizeof b2; ++i) b2[i] = 0xff;

    if (byte_isequal(b1, 32, b2) == 0) fail("byte_isequal failure");

    for (i = 0; i < 32; ++i) {
        b1[i] = 0;
        if (byte_isequal(b1, 32, b2) != 0) fail("byte_isequal failure");
        b1[i] = 0xff;
    }

    /* byte_copy test */
    for (i = 0; i < sizeof b1; ++i) b1[i] = 0xff;
    for (i = 0; i < sizeof b2; ++i) b2[i] = 0x00;

    byte_copy(b1, 32, b2);
    if (byte_isequal(b1, 32, b2) == 0) fail("byte_copy failure");
    
    for (i = 0; i < 32; ++i) {
        b1[i] = 0;
        byte_copy(b1, 32, b2);
        if (byte_isequal(b1, 32, b2) == 0) fail("byte_copy failure");
        b1[i] = 0xff;
    }

    byte_zero(y, 8);
    if (!byte_isequal(y, 8, "\0\0\0\0\0\0\0\0")) fail("byte_zero/byte_isequal failure");

    byte_copy(y, 8, x);
    if (!byte_isequal(y, 8, x)) fail("byte_copy/byte_isequal failure");

    byte_copy(y, 7, y + 1);
    if (!byte_isequal(y, 8, "bcdefghh")) fail("byte_copy/byte_isequal failure");

    byte_zero(y, 8);
    if (!byte_isequal(y, 8, "\0\0\0\0\0\0\0\0")) fail("byte_zero/byte_isequal failure");

    return 0;
}
Пример #3
0
static void run(void (*op)(void), const char *exp) {

    pid_t pid;
    int status, fromchild[2];
    long long r, i;

    if (pipe(fromchild) == -1) fail("pipe() failure");
    pid = fork();
    if (pid == -1) fail("fork() failure");
    if (pid == 0) {
        close(fromchild[0]);
        if (dup2(fromchild[1], 2) == -1) _exit(111);
        op();
        _exit(0);
    }
    close(fromchild[1]);
    r = readall(fromchild[0], logbuf, sizeof logbuf);
    if (r == -1) fail("read() failure");

    for (i = 0; i < r; ++i) if (logbuf[i] == '\n') break;
    r = i;
    for (i = 0; i < r; ++i) if (logbuf[i] == '/') break;
    r -= i;
    byte_copy(logbuf, r, logbuf + i);

    /* fprintf(stderr, "xxx: %s\n", logbuf); fflush(stderr); */

    if (r < globalpathlen + 1) fail("log error");
    if (!byte_isequal(globalpath, globalpathlen, logbuf)) fail("log error");
    r -= globalpathlen + 1;
    byte_copy(logbuf, r, logbuf + globalpathlen + 1);

    for (i = 0; i < r; ++i) if (logbuf[i] == '{') break;
    r = i;
    logbuf[r] = 0;

    while (waitpid(pid, &status, 0) != pid) {};
    if (!WIFEXITED(status)) fail("process killed");
    if (WEXITSTATUS(status)) fail("process exited with status != 0");

    i = str_len(exp);
    if (r != i) fail("failed");
    if (!byte_isequal(logbuf, i, exp)) fail("failed");
}
Пример #4
0
/*
The 'iptostr(strbuf,ip)' function converts IP address 'ip'
from network byte order into the 0-terminated string.
The 'ip' length is always 16 bytes. The caller must 
allocate at least IPTOSTR_LEN bytes for 'strbuf'.
*/
char *iptostr(char *strbuf, const unsigned char *ip) {

    static char staticbuf[IPTOSTR_LEN];

    if (!strbuf) strbuf = staticbuf; /* not thread-safe */

    if (byte_isequal("\0\0\0\0\0\0\0\0\0\0\377\377", 12, ip)) {
        return iptostr4(strbuf, ip + 12);
    }
    return iptostr6(strbuf, ip);
}
Пример #5
0
static int xsocket_connect4(int s, const unsigned char *ip, const unsigned char *port, long long id) {

    struct sockaddr_in sa;

    if (!byte_isequal("\0\0\0\0\0\0\0\0\0\0\377\377", 12, ip)) { errno = EPROTO; return -1; }

    byte_zero(&sa, sizeof sa);
    sa.sin_family = PF_INET;
    byte_copy(&sa.sin_addr, 4, ip + 12);
    byte_copy(&sa.sin_port, 2, port);
    return connect(s, (struct sockaddr *)&sa, sizeof sa);
}
Пример #6
0
static int xsocket_connect6(int s, const unsigned char *ip, const unsigned char *port, long long id) {
#ifdef HASIPV6
    struct sockaddr_in6 sa;

    if (byte_isequal("\0\0\0\0\0\0\0\0\0\0\377\377", 12, ip)) { errno = EPROTO; return -1; }

    byte_zero(&sa, sizeof sa);
    sa.sin6_family = PF_INET6;
    byte_copy(&sa.sin6_addr, 16, ip);
    byte_copy(&sa.sin6_port, 2, port);
    sa.sin6_scope_id = id;
    return connect(s, (struct sockaddr *)&sa, sizeof sa);
#else
    errno = EPROTONOSUPPORT;
    return -1;
#endif
}
Пример #7
0
void dns_sortip(unsigned char *s, long long nn) {

    long long i;
    long long n = nn;

    if (nn < 0) return;

    n >>= 4;
    while (n > 1) {
        i = fastrandommod(n);
        --n;
        swap(s + 16 * i, 16, s + 16 * n);
    }

    for (i = 0; i + 16 <= nn; i += 16) {
        if (!byte_isequal(s + i, 12, "\0\0\0\0\0\0\0\0\0\0\377\377")) {
            swap(s + i, 16, s);
            break;
        }
    }
}
Пример #8
0
int packet_auth(struct buf *b, struct buf *b2) {

    crypto_uint8 ch, flagsignature;
    long long pos, i, count, sign_bytes = 0;
    crypto_uint32 len;
    const char *pkname;
    int (*sign_open)(unsigned char *,unsigned long long *,const unsigned char *,unsigned long long,const unsigned char *) = 0;
    int (*parsesignpk)(unsigned char *, const unsigned char *, long long) = 0;
    int (*parsesignature)(unsigned char *, const unsigned char *, long long) = 0;
    void (*putsignpk)(struct buf *, const unsigned char *) = 0;
    void (*putsignpkbase64)(struct buf *, const unsigned char *) = 0;
    unsigned char pk[sshcrypto_sign_PUBLICKEYMAX];
    unsigned char sig[sshcrypto_sign_MAX];
    unsigned long long smlen;

    buf_purge(b);

    /* parse "ssh-userauth" */
    pos = 0;
    if (!packet_getall(b, SSH_MSG_SERVICE_REQUEST)) bug();
    pos = packetparser_uint8(b->buf, b->len, pos, &ch);       /* SSH_MSG_SERVICE_REQUEST */
    if (ch != SSH_MSG_SERVICE_REQUEST) bug_proto();
    pos = packetparser_uint32(b->buf, b->len, pos, &len);     /* "ssh-userauth" */
    if (len != 12) bug_proto();
    pos = packetparser_skip(b->buf, b->len, pos, len);
    if (!byte_isequal(b->buf + pos - len, len, "ssh-userauth")) bug_proto();
    pos = packetparser_end(b->buf, b->len, pos);

    /* send service accept */
    b->buf[0] = SSH_MSG_SERVICE_ACCEPT;
    packet_put(b);
    if (!packet_sendall()) bug();


    for (count = 0; count < 32; ++count) {
        /* receive userauth request */
        pkname = "unknown";
        pos = 0;
        buf_purge(b);
        if (!packet_getall(b, SSH_MSG_USERAUTH_REQUEST)) bug();
        pos = packetparser_uint8(b->buf, b->len, pos, &ch);         /* SSH_MSG_USERAUTH_REQUEST */
        if (ch != SSH_MSG_USERAUTH_REQUEST) bug_proto();
        pos = packetparser_uint32(b->buf, b->len, pos, &len);       /* name */
        if (len >= PACKET_NAMESIZE) bug_proto();
        pos = packetparser_copy(b->buf, b->len, pos, (unsigned char *)packet.name, len);
        packet.name[len] = 0;
        pos = packetparser_uint32(b->buf, b->len, pos, &len);       /* "ssh-connection" */
        if (len != 14) bug_proto();
        pos = packetparser_skip(b->buf, b->len, pos, len);
        if (!byte_isequal(b->buf + pos - len, len, "ssh-connection")) bug_proto();

        pos = packetparser_uint32(b->buf, b->len, pos, &len);       /* publickey/password/hostbased/none */
        pos = packetparser_skip(b->buf, b->len, pos, len);

        if (str_equaln((char *)b->buf + pos - len, len, "none")) pkname = "none";
        if (str_equaln((char *)b->buf + pos - len, len, "password")) pkname = "password";
        if (str_equaln((char *)b->buf + pos - len, len, "hostbased")) pkname = "hostbased";
        if (str_equaln((char *)b->buf + pos - len, len, "publickey")) {
            pos = packetparser_uint8(b->buf, b->len, pos, &flagsignature);

            pos = packetparser_uint32(b->buf, b->len, pos, &len);   /* public key algorithm name */
            pos = packetparser_skip(b->buf, b->len, pos, len);
            if (b->buf[pos] != 0) bug_proto();
            pkname = (char *)b->buf + pos - len; /* XXX */

            sign_open = 0; parsesignpk = 0; putsignpk = 0; putsignpkbase64 = 0; parsesignature = 0; sign_bytes = 0;
            for (i = 0; sshcrypto_keys[i].name; ++i) {
                if (!sshcrypto_keys[i].sign_flagclient) continue;
                if (!str_equaln(pkname, len, sshcrypto_keys[i].name)) continue;
                pkname = sshcrypto_keys[i].name;
                sign_open = sshcrypto_keys[i].sign_open;
                parsesignature = sshcrypto_keys[i].parsesignature;
                parsesignpk = sshcrypto_keys[i].parsesignpk;
                putsignpk = sshcrypto_keys[i].buf_putsignpk;
                putsignpkbase64 = sshcrypto_keys[i].buf_putsignpkbase64;
                sign_bytes = sshcrypto_keys[i].sign_bytes;
                break;
            }
            if (sign_open && parsesignpk && putsignpk && putsignpkbase64 && parsesignature) {
                pos = packetparser_uint32(b->buf, b->len, pos, &len);   /* public key blob */
                pos = packetparser_skip(b->buf, b->len, pos, len);
                if (!parsesignpk(pk, b->buf + pos - len, len)) bug_proto();

                if (!flagsignature) {
                    /* 'publickey' ... without signature */
                    buf_purge(b);
                    buf_putnum8(b, SSH_MSG_USERAUTH_PK_OK);
                    buf_putstring(b, pkname);
                    putsignpk(b, pk);
                    packet_put(b);
                    if (!packet_sendall()) bug();
                    continue;
                }


                /* 'publickey' ... with signature */
                pos = packetparser_uint32(b->buf, b->len, pos, &len);   /* signature blob */
                pos = packetparser_skip(b->buf, b->len, pos, len);
                if (!parsesignature(sig, b->buf + pos - len, len)) bug_proto();
                pos = packetparser_end(b->buf, b->len, pos);
                purge(b->buf + b->len - len - 4, len + 4);
                b->len -= len + 4;


                /* authenticate user - verify signature */
                buf_purge(b2);
                buf_put(b2, sig, sign_bytes);
                buf_putstringlen(b2, packet.sessionid, sshcrypto_hash_bytes);
                buf_put(b2, b->buf, b->len);

                buf_purge(b);
                if (b->alloc <= b2->len) bug_nomem();
                if (sign_open(b->buf, &smlen, b2->buf, b2->len, pk) != 0) { errno = EAUTH; bug(); }
                b->len = smlen; buf_purge(b);

                /* authorize user -  using authorized_keys */
                buf_purge(b);
                putsignpkbase64(b, pk);
                buf_putnum8(b, 0);
                if (subprocess_auth(packet.name, pkname, (char *)b->buf) == 0) goto authorized;
            }
        }

        /* reject */
        log_i5("auth: ", packet.name, ": ", pkname, " rejected");
        buf_purge(b);
        buf_putnum8(b, SSH_MSG_USERAUTH_FAILURE);
        buf_putstring(b,"publickey");
        buf_putnum8(b, 0);
        packet_put(b);
        if (!packet_sendall()) bug();
    }
    log_w1("auth: too many authentication tries");
    return 0;


authorized:
    /* authenticated + authorized */
    log_i5("auth: ", packet.name, ": ", pkname, " accepted");
    buf_purge(b);
    buf_putnum8(b, SSH_MSG_USERAUTH_SUCCESS);
    buf_putstring(b,"ssh-connection");
    packet_put(b);
    if (!packet_sendall()) bug();

    purge(pk, sizeof pk);
    purge(sig, sizeof sig);
    return 1;
}
Пример #9
0
void dns_sortipkey(unsigned char *s, unsigned char *t, long long nn) {

    long long i, j, k;
    long long n;
    unsigned char *key;

    nn >>=4;
    n = nn;

    while (n > 1) {
        i = fastrandommod(n);
        --n;
        swap(s + 16 * i, 16, s + 16 * n);
        swap(t + 33 * i, 33, t + 33 * n);
    }

    n = nn;
    j = 0;
    k = 0;
    for (i = k; i < n; ++i) {
        key = t + 33 * i;
        if (key[0] == 1) {
            swap(s + 16 * i, 16, s + 16 * j);
            swap(t + 33 * i, 33, t + 33 * j);
            ++j;
        }
    }
    for (i = k; i < j; ++i) {
        key = t + 33 * i;
        if (key[0] != 1) continue;
        if (!byte_isequal(s + 16 * i, 12, "\0\0\0\0\0\0\0\0\0\0\377\377")) {
            swap(s + 16 * i, 16, s + 16 * k);
            swap(t + 33 * i, 33, t + 33 * k);
            break;
        }
    }

    k = j;
    for (i = k; i < n; ++i) {
        key = t + 33 * i;
        if (key[0] == 2) {
            swap(s + 16 * i, 16, s + 16 * j);
            swap(t + 33 * i, 33, t + 33 * j);
            ++j;
        }
    }
    for (i = k; i < j; ++i) {
        key = t + 33 * i;
        if (key[0] != 2) continue;
        if (!byte_isequal(s + 16 * i, 12, "\0\0\0\0\0\0\0\0\0\0\377\377")) {
            swap(s + 16 * i, 16, s + 16 * k);
            swap(t + 33 * i, 33, t + 33 * k);
            break;
        }
    }

    k = j;
    for (i = k; i < n; ++i) {
        key = t + 33 * i;
        if (!byte_isequal(s + 16 * i, 16, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0")) {
            swap(s + 16 * i, 16, s + 16 * j);
            swap(t + 33 * i, 33, t + 33 * j);
            ++j;
        }
    }
    for (i = k; i < j; ++i) {
        key = t + 33 * i;
        if (key[0] != 0) continue;
        if (!byte_isequal(s + 16 * i, 12, "\0\0\0\0\0\0\0\0\0\0\377\377")) {
            swap(s + 16 * i, 16, s + 16 * k);
            swap(t + 33 * i, 33, t + 33 * k);
            break;
        }
    }
}
Пример #10
0
int main(int argc,char **argv)
{
  long long hellopackets;
  long long r;
  long long nextaction;

  signal(SIGPIPE,SIG_IGN);

  if (!argv[0]) die_usage(0);
  for (;;) {
    char *x;
    if (!argv[1]) break;
    if (argv[1][0] != '-') break;
    x = *++argv;
    if (x[0] == '-' && x[1] == 0) break;
    if (x[0] == '-' && x[1] == '-' && x[2] == 0) break;
    while (*++x) {
      if (*x == 'q') { flagverbose = 0; continue; }
      if (*x == 'Q') { flagverbose = 1; continue; }
      if (*x == 'v') { if (flagverbose == 2) flagverbose = 3; else flagverbose = 2; continue; }
      if (*x == 'c') {
        if (x[1]) { keydir = x + 1; break; }
        if (argv[1]) { keydir = *++argv; break; }
      }
      die_usage(0);
    }
  }
  if (!nameparse(servername,*++argv)) die_usage("sname must be at most 255 bytes, at most 63 bytes between dots");
  if (!hexparse(serverlongtermpk,32,*++argv)) die_usage("pk must be exactly 64 hex characters");
  if (!multiipparse(serverip,*++argv)) die_usage("ip must be a comma-separated series of IPv4 addresses");
  if (!portparse(serverport,*++argv)) die_usage("port must be an integer between 0 and 65535");
  if (!hexparse(serverextension,16,*++argv)) die_usage("ext must be exactly 32 hex characters");
  if (!*++argv) die_usage("missing prog");

  for (;;) {
    r = open_read("/dev/null");
    if (r == -1) die_fatal("unable to open /dev/null",0,0);
    if (r > 9) { close(r); break; }
  }

  if (keydir) {
    fdwd = open_cwd();
    if (fdwd == -1) die_fatal("unable to open current working directory",0,0);
    if (chdir(keydir) == -1) die_fatal("unable to change to directory",keydir,0);
    if (load("publickey",clientlongtermpk,sizeof clientlongtermpk) == -1) die_fatal("unable to read public key from",keydir,0);
    if (load(".expertsonly/secretkey",clientlongtermsk,sizeof clientlongtermsk) == -1) die_fatal("unable to read secret key from",keydir,0);
  } else {
    crypto_box_keypair(clientlongtermpk,clientlongtermsk);
  }

  crypto_box_keypair(clientshorttermpk,clientshorttermsk);
  clientshorttermnonce = randommod(281474976710656LL);
  crypto_box_beforenm(clientshortserverlong,serverlongtermpk,clientshorttermsk);
  crypto_box_beforenm(clientlongserverlong,serverlongtermpk,clientlongtermsk);

  udpfd = socket_udp();
  if (udpfd == -1) die_fatal("unable to create socket",0,0);

  for (hellopackets = 0;hellopackets < NUMIP;++hellopackets) {
    recent = nanoseconds();

    /* send a Hello packet: */

    clientextension_init();

    clientshorttermnonce_update();
    byte_copy(nonce,16,"CurveCP-client-H");
    uint64_pack(nonce + 16,clientshorttermnonce);

    byte_copy(packet,8,"QvnQ5XlH");
    byte_copy(packet + 8,16,serverextension);
    byte_copy(packet + 24,16,clientextension);
    byte_copy(packet + 40,32,clientshorttermpk);
    byte_copy(packet + 72,64,allzero);
    byte_copy(packet + 136,8,nonce + 16);
    crypto_box_afternm(text,allzero,96,nonce,clientshortserverlong);
    byte_copy(packet + 144,80,text + 16);

    socket_send(udpfd,packet,224,serverip + 4 * hellopackets,serverport);

    nextaction = recent + hellowait[hellopackets] + randommod(hellowait[hellopackets]);

    for (;;) {
      long long timeout = nextaction - recent;
      if (timeout <= 0) break;
      p[0].fd = udpfd;
      p[0].events = POLLIN;
      if (poll(p,1,timeout / 1000000 + 1) < 0) p[0].revents = 0;

      do { /* try receiving a Cookie packet: */
        if (!p[0].revents) break;
        r = socket_recv(udpfd,packet,sizeof packet,packetip,packetport);
        if (r != 200) break;
        if (!(byte_isequal(packetip,4,serverip + 4 * hellopackets) &
              byte_isequal(packetport,2,serverport) &
              byte_isequal(packet,8,"RL3aNMXK") &
              byte_isequal(packet + 8,16,clientextension) &
              byte_isequal(packet + 24,16,serverextension)
           )) break;
        byte_copy(nonce,8,"CurveCPK");
        byte_copy(nonce + 8,16,packet + 40);
        byte_zero(text,16);
        byte_copy(text + 16,144,packet + 56);
        if (crypto_box_open_afternm(text,text,160,nonce,clientshortserverlong)) break;
        byte_copy(servershorttermpk,32,text + 32);
        byte_copy(servercookie,96,text + 64);
        byte_copy(serverip,4,serverip + 4 * hellopackets);
        goto receivedcookie;
      } while (0);

      recent = nanoseconds();
    }
  }

  errno = ETIMEDOUT; die_fatal("no response from server",0,0);

  receivedcookie:

  crypto_box_beforenm(clientshortservershort,servershorttermpk,clientshorttermsk);

  byte_copy(nonce,8,"CurveCPV");
  if (keydir) {
    if (safenonce(nonce + 8,0) == -1) die_fatal("nonce-generation disaster",0,0);
  } else {
    randombytes(nonce + 8,16);
  }

  byte_zero(text,32);
  byte_copy(text + 32,32,clientshorttermpk);
  crypto_box_afternm(text,text,64,nonce,clientlongserverlong);
  byte_copy(vouch,16,nonce + 8);
  byte_copy(vouch + 16,48,text + 16);

  /* server is responding, so start child: */

  if (open_pipe(tochild) == -1) die_fatal("unable to create pipe",0,0);
  if (open_pipe(fromchild) == -1) die_fatal("unable to create pipe",0,0);

  child = fork();
  if (child == -1) die_fatal("unable to fork",0,0);
  if (child == 0) {
    if (keydir) if (fchdir(fdwd) == -1) die_fatal("unable to chdir to original directory",0,0);
    close(8);
    if (dup(tochild[0]) != 8) die_fatal("unable to dup",0,0);
    close(9);
    if (dup(fromchild[1]) != 9) die_fatal("unable to dup",0,0);
    /* XXX: set up environment variables */
    signal(SIGPIPE,SIG_DFL);
    execvp(*argv,argv);
    die_fatal("unable to run",*argv,0);
  }

  close(fromchild[1]);
  close(tochild[0]);


  for (;;) {
    p[0].fd = udpfd;
    p[0].events = POLLIN;
    p[1].fd = fromchild[0];
    p[1].events = POLLIN;

    if (poll(p,2,-1) < 0) {
      p[0].revents = 0;
      p[1].revents = 0;
    }

    do { /* try receiving a Message packet: */
      if (!p[0].revents) break;
      r = socket_recv(udpfd,packet,sizeof packet,packetip,packetport);
      if (r < 80) break;
      if (r > 1152) break;
      if (r & 15) break;
      packetnonce = uint64_unpack(packet + 40);
      if (flagreceivedmessage && packetnonce <= receivednonce) break;
      if (!(byte_isequal(packetip,4,serverip + 4 * hellopackets) &
            byte_isequal(packetport,2,serverport) &
            byte_isequal(packet,8,"RL3aNMXM") &
            byte_isequal(packet + 8,16,clientextension) &
            byte_isequal(packet + 24,16,serverextension)
         )) break;
      byte_copy(nonce,16,"CurveCP-server-M");
      byte_copy(nonce + 16,8,packet + 40);
      byte_zero(text,16);
      byte_copy(text + 16,r - 48,packet + 48);
      if (crypto_box_open_afternm(text,text,r - 32,nonce,clientshortservershort)) break;

      if (!flagreceivedmessage) {
        flagreceivedmessage = 1;
	randombytes(clientlongtermpk,sizeof clientlongtermpk);
	randombytes(vouch,sizeof vouch);
	randombytes(servername,sizeof servername);
	randombytes(servercookie,sizeof servercookie);
      }

      receivednonce = packetnonce;
      text[31] = (r - 64) >> 4;
      /* child is responsible for reading all data immediately, so we won't block: */
      if (writeall(tochild[1],text + 31,r - 63) == -1) goto done;
    } while (0);

    do { /* try receiving data from child: */
      long long i;
      if (!p[1].revents) break;
      r = read(fromchild[0],childbuf,sizeof childbuf);
      if (r == -1) if (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN) break;
      if (r <= 0) goto done;
      childbuflen = r;
      for (i = 0;i < childbuflen;++i) {
	if (childmessagelen < 0) goto done;
	if (childmessagelen >= sizeof childmessage) goto done;
        childmessage[childmessagelen++] = childbuf[i];
	if (childmessage[0] & 128) goto done;
	if (childmessagelen == 1 + 16 * (unsigned long long) childmessage[0]) {
	  clientextension_init();
	  clientshorttermnonce_update();
          uint64_pack(nonce + 16,clientshorttermnonce);
	  if (flagreceivedmessage) {
	    r = childmessagelen - 1;
	    if (r < 16) goto done;
	    if (r > 1088) goto done;
            byte_copy(nonce,16,"CurveCP-client-M");
	    byte_zero(text,32);
	    byte_copy(text + 32,r,childmessage + 1);
	    crypto_box_afternm(text,text,r + 32,nonce,clientshortservershort);
	    byte_copy(packet,8,"QvnQ5XlM");
	    byte_copy(packet + 8,16,serverextension);
	    byte_copy(packet + 24,16,clientextension);
	    byte_copy(packet + 40,32,clientshorttermpk);
	    byte_copy(packet + 72,8,nonce + 16);
	    byte_copy(packet + 80,r + 16,text + 16);
            socket_send(udpfd,packet,r + 96,serverip,serverport);
	  } else {
	    r = childmessagelen - 1;
	    if (r < 16) goto done;
	    if (r > 640) goto done;
	    byte_copy(nonce,16,"CurveCP-client-I");
	    byte_zero(text,32);
	    byte_copy(text + 32,32,clientlongtermpk);
	    byte_copy(text + 64,64,vouch);
	    byte_copy(text + 128,256,servername);
	    byte_copy(text + 384,r,childmessage + 1);
	    crypto_box_afternm(text,text,r + 384,nonce,clientshortservershort);
	    byte_copy(packet,8,"QvnQ5XlI");
	    byte_copy(packet + 8,16,serverextension);
	    byte_copy(packet + 24,16,clientextension);
	    byte_copy(packet + 40,32,clientshorttermpk);
	    byte_copy(packet + 72,96,servercookie);
	    byte_copy(packet + 168,8,nonce + 16);
	    byte_copy(packet + 176,r + 368,text + 16);
            socket_send(udpfd,packet,r + 544,serverip,serverport);
	  }
	  childmessagelen = 0;
	}
      }
    } while (0);
  }


  done:

  do {
    r = waitpid(child,&childstatus,0);
  } while (r == -1 && errno == EINTR);

  if (!WIFEXITED(childstatus)) { errno = 0; die_fatal("process killed by signal",0,0); }
  return WEXITSTATUS(childstatus);
}