void aesctr_packet_put(struct buf *b) { long long pos; crypto_uint8 paddinglen; struct buf *sendbuf = &packet.sendbuf; pos = sendbuf->len; /* get position */ buf_putnum32(sendbuf, 0); /* packet id, for MAC */ buf_putnum32(sendbuf, 0); /* packet length */ buf_putnum8(sendbuf, 0); /* padding length */ buf_put(sendbuf, b->buf, b->len); /* add data */ /* add padding */ paddinglen = 2 * BB - ((sendbuf->len - pos - 4) % BB); paddinglen += randommod(2) * BB; buf_putpadding(sendbuf, paddinglen); /* add space for mac */ buf_putzerobytes(sendbuf, AB); /* add packet ID */ uint32_pack_big(sendbuf->buf + pos, packet.sendpacketid++); /* add packet length */ uint32_pack_big(sendbuf->buf + pos + 4, sendbuf->len - pos - AB - 4 - 4); /* add padding length*/ sendbuf->buf[pos + 8] = paddinglen; /* get mac */ if (sshcrypto_auth( sendbuf->buf + sendbuf->len - AB, /* a */ sendbuf->buf + pos, /* m */ sendbuf->len - pos - AB, /* mlen */ packet.servermackey /* k */ ) != 0) bug_proto(); /* encrypt */ if (sshcrypto_stream_xor( sendbuf->buf + pos + 4, /* c */ sendbuf->buf + pos + 4, /* m */ sendbuf->len - pos - 4 - AB, /* mlen */ packet.servernonce, /* n */ packet.serverkey /* k */ ) != 0) bug_proto(); /* remove packet id */ byte_copy(sendbuf->buf + pos, sendbuf->len - pos - 4, sendbuf->buf + pos + 4); sendbuf->len -= 4; /* cleanup */ purge(sendbuf->buf + sendbuf->len, 4); }
int multiipparse(unsigned char *y,const char *x) { long long pos; long long pos2; long long ynum; long long ypos; long long j; long long k; long long d; for (j = 0;j < 4 * NUMIP;++j) y[j] = 0; ynum = 0; while (ynum < 1000) { ++ynum; ypos = randommod(ynum); for (k = 0;k < 4;++k) { pos = ypos * 4 + k; pos2 = (ynum - 1) * 4 + k; if (pos >= 0 && pos < 4 * NUMIP && pos2 >= 0 && pos2 < 4 * NUMIP) y[pos2] = y[pos]; d = 0; for (j = 0;j < 3 && x[j] >= '0' && x[j] <= '9';++j) d = d * 10 + (x[j] - '0'); if (j == 0) return 0; x += j; if (pos >= 0 && pos < 4 * NUMIP) y[pos] = d; if (k < 3) { if (*x != '.') return 0; ++x; } } if (!*x) break; if (*x != ',') return 0; ++x; } /* if fewer than 8 IP addresses, cycle through them: */ pos = 0; pos2 = ynum * 4; while (pos2 < 4 * NUMIP) { if (pos >= 0 && pos < 4 * NUMIP && pos2 >= 0 && pos2 < 4 * NUMIP) y[pos2] = y[pos]; ++pos2; ++pos; } return 1; }
void log_init(int level, const char *text, int line, int flagsyslog) { long long i; loglevel = level; logtext = text; logflagfnln = line; for (i = 0; i < sizeof logstring; ++i) { logstring[i] = chars[randommod(sizeof chars - 1)]; } logstring[sizeof logstring - 1] = 0; if (flagsyslog) { openlog(text, 0, LOG_DAEMON); logflagsyslog = 1; } errno = 0; }
int main(int argc,char **argv) { long long pos; long long len; long long u; long long r; long long i; long long k; long long recent; long long nextaction; long long timeout; struct pollfd *q; struct pollfd *watch8; struct pollfd *watchtochild; struct pollfd *watchfromchild; 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') { flagserver = 0; wantping = 2; continue; } if (*x == 'C') { flagserver = 0; wantping = 1; continue; } if (*x == 's') { flagserver = 1; wantping = 0; continue; } die_usage(0); } } 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 (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); blocking_enable(tochild[0]); blocking_enable(fromchild[1]); child = fork(); if (child == -1) die_fatal("unable to fork",0,0); if (child == 0) { close(8); close(9); if (flagserver) { close(0); if (dup(tochild[0]) != 0) die_fatal("unable to dup",0,0); close(1); if (dup(fromchild[1]) != 1) die_fatal("unable to dup",0,0); } else { close(6); if (dup(tochild[0]) != 6) die_fatal("unable to dup",0,0); close(7); if (dup(fromchild[1]) != 7) die_fatal("unable to dup",0,0); } signal(SIGPIPE,SIG_DFL); execvp(*argv,argv); die_fatal("unable to run",*argv,0); } close(tochild[0]); close(fromchild[1]); recent = nanoseconds(); lastspeedadjustment = recent; if (flagserver) maxblocklen = 1024; for (;;) { if (sendeofacked) if (receivewritten == receivetotalbytes) if (receiveeof) if (tochild[1] < 0) break; /* XXX: to re-ack should enter a TIME-WAIT state here */ q = p; watch8 = q; if (watch8) { q->fd = 8; q->events = POLLIN; ++q; } watchtochild = q; if (tochild[1] < 0) watchtochild = 0; if (receivewritten >= receivebytes) watchtochild = 0; if (watchtochild) { q->fd = tochild[1]; q->events = POLLOUT; ++q; } watchfromchild = q; if (sendeof) watchfromchild = 0; if (sendbytes + 4096 > sizeof sendbuf) watchfromchild = 0; if (watchfromchild) { q->fd = fromchild[0]; q->events = POLLIN; ++q; } nextaction = recent + 60000000000LL; if (wantping == 1) nextaction = recent + 1000000000; if (wantping == 2) nextaction = 0; if (blocknum < OUTGOING) if (!(sendeof ? sendeofprocessed : sendprocessed >= sendbytes)) if (nextaction > lastblocktime + nsecperblock) nextaction = lastblocktime + nsecperblock; if (earliestblocktime) { long long nextretry = earliestblocktime + rtt_timeout; if (nextretry < lastblocktime + nsecperblock) nextretry = lastblocktime + nsecperblock; if (nextretry < nextaction) nextaction = nextretry; } if (messagenum) if (!watchtochild) nextaction = 0; if (nextaction <= recent) timeout = 0; else timeout = (nextaction - recent) / 1000000 + 1; /* XXX */ if (childdied) timeout = 10; pollret = poll(p,q - p,timeout); if (pollret < 0) { watch8 = 0; watchtochild = 0; watchfromchild = 0; } else { if (watch8) if (!watch8->revents) watch8 = 0; if (watchtochild) if (!watchtochild->revents) watchtochild = 0; if (watchfromchild) if (!watchfromchild->revents) watchfromchild = 0; } /* XXX */ if (childdied && !pollret) { if (childdied++ > 999) goto finish; } /* XXX: keepalives */ do { /* try receiving data from child: */ if (!watchfromchild) break; if (sendeof) break; if (sendbytes + 4096 > sizeof sendbuf) break; pos = (sendacked & (sizeof sendbuf - 1)) + sendbytes; if (pos < sizeof sendbuf) { r = read(fromchild[0],sendbuf + pos,sizeof sendbuf - pos); } else { r = read(fromchild[0],sendbuf + pos - sizeof sendbuf,sizeof sendbuf - sendbytes); } if (r == -1) if (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN) break; if (r < 0) { sendeof = 4096; break; } if (r == 0) { sendeof = 2048; break; } sendbytes += r; if (sendbytes >= 1152921504606846976LL) die_internalerror(); } while(0); recent = nanoseconds(); do { /* try re-sending an old block: */ if (recent < lastblocktime + nsecperblock) break; if (earliestblocktime == 0) break; if (recent < earliestblocktime + rtt_timeout) break; for (i = 0;i < blocknum;++i) { pos = (blockfirst + i) & (OUTGOING - 1); if (blocktime[pos] == earliestblocktime) { if (recent > lastpanic + 4 * rtt_timeout) { nsecperblock *= 2; lastpanic = recent; lastedge = recent; } goto sendblock; } } } while(0); do { /* try sending a new block: */ if (recent < lastblocktime + nsecperblock) break; if (blocknum >= OUTGOING) break; if (!wantping) if (sendeof ? sendeofprocessed : sendprocessed >= sendbytes) break; /* XXX: if any Nagle-type processing is desired, do it here */ pos = (blockfirst + blocknum) & (OUTGOING - 1); ++blocknum; blockpos[pos] = sendacked + sendprocessed; blocklen[pos] = sendbytes - sendprocessed; if (blocklen[pos] > maxblocklen) blocklen[pos] = maxblocklen; if ((blockpos[pos] & (sizeof sendbuf - 1)) + blocklen[pos] > sizeof sendbuf) blocklen[pos] = sizeof sendbuf - (blockpos[pos] & (sizeof sendbuf - 1)); /* XXX: or could have the full block in post-buffer space */ sendprocessed += blocklen[pos]; blockeof[pos] = 0; if (sendprocessed == sendbytes) { blockeof[pos] = sendeof; if (sendeof) sendeofprocessed = 1; } blocktransmissions[pos] = 0; sendblock: blocktransmissions[pos] += 1; blocktime[pos] = recent; blockid[pos] = nextmessageid; if (!++nextmessageid) ++nextmessageid; /* constraints: u multiple of 16; u >= 16; u <= 1088; u >= 48 + blocklen[pos] */ u = 64 + blocklen[pos]; if (u <= 192) u = 192; else if (u <= 320) u = 320; else if (u <= 576) u = 576; else if (u <= 1088) u = 1088; else die_internalerror(); if (blocklen[pos] < 0 || blocklen[pos] > 1024) die_internalerror(); byte_zero(buf + 8,u); buf[7] = u / 16; uint32_pack(buf + 8,blockid[pos]); /* XXX: include any acknowledgments that have piled up */ uint16_pack(buf + 46,blockeof[pos] | (crypto_uint16) blocklen[pos]); uint64_pack(buf + 48,blockpos[pos]); byte_copy(buf + 8 + u - blocklen[pos],blocklen[pos],sendbuf + (blockpos[pos] & (sizeof sendbuf - 1))); if (writeall(9,buf + 7,u + 1) == -1) die_fatal("unable to write descriptor 9",0,0); lastblocktime = recent; wantping = 0; earliestblocktime_compute(); } while(0); do { /* try receiving messages: */ if (!watch8) break; r = read(8,buf,sizeof buf); if (r == -1) if (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN) break; if (r == 0) die_badmessage(); if (r < 0) die_fatal("unable to read from file descriptor 8",0,0); for (k = 0;k < r;++k) { messagetodo[messagetodolen++] = buf[k]; u = 16 * (unsigned long long) messagetodo[0]; if (u < 16) die_badmessage(); if (u > 1088) die_badmessage(); if (messagetodolen == 1 + u) { if (messagenum < INCOMING) { pos = (messagefirst + messagenum) & (INCOMING - 1); messagelen[pos] = messagetodo[0]; byte_copy(message[pos],u,messagetodo + 1); ++messagenum; } else { ; /* drop tail */ } messagetodolen = 0; } } } while(0); do { /* try processing a message: */ if (!messagenum) break; if (tochild[1] >= 0 && receivewritten < receivebytes) break; maxblocklen = 1024; pos = messagefirst & (INCOMING - 1); len = 16 * (unsigned long long) messagelen[pos]; do { /* handle this message if it's comprehensible: */ unsigned long long D; unsigned long long SF; unsigned long long startbyte; unsigned long long stopbyte; crypto_uint32 id; long long i; if (len < 48) break; if (len > 1088) break; id = uint32_unpack(message[pos] + 4); for (i = 0;i < blocknum;++i) { k = (blockfirst + i) & (OUTGOING - 1); if (blockid[k] == id) { rtt = recent - blocktime[k]; if (!rtt_average) { nsecperblock = rtt; rtt_average = rtt; rtt_deviation = rtt / 2; rtt_highwater = rtt; rtt_lowwater = rtt; } /* Jacobson's retransmission timeout calculation: */ rtt_delta = rtt - rtt_average; rtt_average += rtt_delta / 8; if (rtt_delta < 0) rtt_delta = -rtt_delta; rtt_delta -= rtt_deviation; rtt_deviation += rtt_delta / 4; rtt_timeout = rtt_average + 4 * rtt_deviation; /* adjust for delayed acks with anti-spiking: */ rtt_timeout += 8 * nsecperblock; /* recognizing top and bottom of congestion cycle: */ rtt_delta = rtt - rtt_highwater; rtt_highwater += rtt_delta / 1024; rtt_delta = rtt - rtt_lowwater; if (rtt_delta > 0) rtt_lowwater += rtt_delta / 8192; else rtt_lowwater += rtt_delta / 256; if (rtt_average > rtt_highwater + 5000000) rtt_seenrecenthigh = 1; else if (rtt_average < rtt_lowwater) rtt_seenrecentlow = 1; if (recent >= lastspeedadjustment + 16 * nsecperblock) { if (recent - lastspeedadjustment > 10000000000LL) { nsecperblock = 1000000000; /* slow restart */ nsecperblock += randommod(nsecperblock / 8); } lastspeedadjustment = recent; if (nsecperblock >= 131072) { /* additive increase: adjust 1/N by a constant c */ /* rtt-fair additive increase: adjust 1/N by a constant c every nanosecond */ /* approximation: adjust 1/N by cN every N nanoseconds */ /* i.e., N <- 1/(1/N + cN) = N/(1 + cN^2) every N nanoseconds */ if (nsecperblock < 16777216) { /* N/(1+cN^2) approx N - cN^3 */ u = nsecperblock / 131072; nsecperblock -= u * u * u; } else { double d = nsecperblock; nsecperblock = d/(1 + d*d / 2251799813685248.0); } } if (rtt_phase == 0) { if (rtt_seenolderhigh) { rtt_phase = 1; lastedge = recent; nsecperblock += randommod(nsecperblock / 4); } } else { if (rtt_seenolderlow) { rtt_phase = 0; } } rtt_seenolderhigh = rtt_seenrecenthigh; rtt_seenolderlow = rtt_seenrecentlow; rtt_seenrecenthigh = 0; rtt_seenrecentlow = 0; } do { if (recent - lastedge < 60000000000LL) { if (recent < lastdoubling + 4 * nsecperblock + 64 * rtt_timeout + 5000000000LL) break; } else { if (recent < lastdoubling + 4 * nsecperblock + 2 * rtt_timeout) break; } if (nsecperblock <= 65535) break; nsecperblock /= 2; lastdoubling = recent; if (lastedge) lastedge = recent; } while(0); } } stopbyte = uint64_unpack(message[pos] + 8); acknowledged(0,stopbyte); startbyte = stopbyte + (unsigned long long) uint32_unpack(message[pos] + 16); stopbyte = startbyte + (unsigned long long) uint16_unpack(message[pos] + 20); acknowledged(startbyte,stopbyte); startbyte = stopbyte + (unsigned long long) uint16_unpack(message[pos] + 22); stopbyte = startbyte + (unsigned long long) uint16_unpack(message[pos] + 24); acknowledged(startbyte,stopbyte); startbyte = stopbyte + (unsigned long long) uint16_unpack(message[pos] + 26); stopbyte = startbyte + (unsigned long long) uint16_unpack(message[pos] + 28); acknowledged(startbyte,stopbyte); startbyte = stopbyte + (unsigned long long) uint16_unpack(message[pos] + 30); stopbyte = startbyte + (unsigned long long) uint16_unpack(message[pos] + 32); acknowledged(startbyte,stopbyte); startbyte = stopbyte + (unsigned long long) uint16_unpack(message[pos] + 34); stopbyte = startbyte + (unsigned long long) uint16_unpack(message[pos] + 36); acknowledged(startbyte,stopbyte); D = uint16_unpack(message[pos] + 38); SF = D & (2048 + 4096); D -= SF; if (D > 1024) break; if (48 + D > len) break; startbyte = uint64_unpack(message[pos] + 40); stopbyte = startbyte + D; if (stopbyte > receivewritten + sizeof receivebuf) { break; /* of course, flow control would avoid this case */ } if (SF) { receiveeof = SF; receivetotalbytes = stopbyte; } for (k = 0;k < D;++k) { unsigned char ch = message[pos][len - D + k]; unsigned long long where = startbyte + k; if (where >= receivewritten && where < receivewritten + sizeof receivebuf) { receivevalid[where & (sizeof receivebuf - 1)] = 1; receivebuf[where & (sizeof receivebuf - 1)] = ch; } } for (;;) { if (receivebytes >= receivewritten + sizeof receivebuf) break; if (!receivevalid[receivebytes & (sizeof receivebuf - 1)]) break; ++receivebytes; } if (!uint32_unpack(message[pos])) break; /* never acknowledge a pure acknowledgment */ /* XXX: delay acknowledgments */ u = 192; byte_zero(buf + 8,u); buf[7] = u / 16; byte_copy(buf + 12,4,message[pos]); if (receiveeof && receivebytes == receivetotalbytes) { uint64_pack(buf + 16,receivebytes + 1); } else uint64_pack(buf + 16,receivebytes); /* XXX: incorporate selective acknowledgments */ if (writeall(9,buf + 7,u + 1) == -1) die_fatal("unable to write descriptor 9",0,0); } while(0); ++messagefirst; --messagenum; } while(0); do { /* try sending data to child: */ if (!watchtochild) break; if (tochild[1] < 0) { receivewritten = receivebytes; break; } if (receivewritten >= receivebytes) break; pos = receivewritten & (sizeof receivebuf - 1); len = receivebytes - receivewritten; if (pos + len > sizeof receivebuf) len = sizeof receivebuf - pos; r = write(tochild[1],receivebuf + pos,len); if (r == -1) if (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN) break; if (r <= 0) { close(tochild[1]); tochild[1] = -1; break; } byte_zero(receivevalid + pos,r); receivewritten += r; } while(0); do { /* try closing pipe to child: */ if (!receiveeof) break; if (receivewritten < receivetotalbytes) break; if (tochild[1] < 0) break; if (receiveeof == 4096) ; /* XXX: UNIX doesn't provide a way to signal an error through a pipe */ close(tochild[1]); tochild[1] = -1; } while(0); /* XXX */ if (!childdied){ if (waitpid(child,&childstatus, WNOHANG) > 0) { close(tochild[1]); tochild[1] = -1; childdied = 1; } } } if (!childdied) { do { r = waitpid(child,&childstatus,0); } while (r == -1 && errno == EINTR); } finish: if (!WIFEXITED(childstatus)) { errno = 0; die_fatal("process killed by signal",0,0); } return WEXITSTATUS(childstatus); }
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); }
int handle_run(uint64_t con_id, struct message_request *request, char *pluginkey, struct api_error *error) { uint64_t callid; array *meta = NULL; string function_name; char *targetpluginkey; struct message_object args_object; if (!error || !request) return (-1); /* check params size */ if (request->params.size != 3) { error_set(error, API_ERROR_TYPE_VALIDATION, "Error dispatching run API request. Invalid params size"); return (-1); } if (request->params.obj[0].type == OBJECT_TYPE_ARRAY) meta = &request->params.obj[0].data.params; else { error_set(error, API_ERROR_TYPE_VALIDATION, "Error dispatching run API request. meta params has wrong type"); return (-1); } if (!meta) { error_set(error, API_ERROR_TYPE_VALIDATION, "Error dispatching run API request. meta params is NULL"); return (-1); } /* meta = [targetpluginkey, nil]*/ if (meta->size != 2) { error_set(error, API_ERROR_TYPE_VALIDATION, "Error dispatching run API request. Invalid meta params size"); return (-1); } /* extract meta information */ if (meta->obj[0].type != OBJECT_TYPE_STR) { error_set(error, API_ERROR_TYPE_VALIDATION, "Error dispatching run API request. meta elements have wrong type"); return (-1); } if (!meta->obj[0].data.string.str || meta->obj[0].data.string.length+1 != PLUGINKEY_STRING_SIZE) { error_set(error, API_ERROR_TYPE_VALIDATION, "Error dispatching run API request. Invalid meta params size"); return (-1); } targetpluginkey = meta->obj[0].data.string.str; to_upper(targetpluginkey); if (meta->obj[1].type != OBJECT_TYPE_NIL) { error_set(error, API_ERROR_TYPE_VALIDATION, "Error dispatching run API request. meta elements have wrong type"); return (-1); } if (request->params.obj[1].type != OBJECT_TYPE_STR) { error_set(error, API_ERROR_TYPE_VALIDATION, "Error dispatching run API request. function string has wrong type"); return (-1); } if (!request->params.obj[1].data.string.str) { error_set(error, API_ERROR_TYPE_VALIDATION, "Error dispatching register API request. Invalid meta params size"); return (-1); } function_name = request->params.obj[1].data.string; if (request->params.obj[2].type != OBJECT_TYPE_ARRAY) { error_set(error, API_ERROR_TYPE_VALIDATION, "Error dispatching run API request. function string has wrong type"); return (-1); } args_object = request->params.obj[2]; callid = (uint64_t) randommod(281474976710656LL); LOG_VERBOSE(VERBOSE_LEVEL_1, "generated callid %lu\n", callid); hashmap_put(uint64_t, ptr_t)(callids, callid, pluginkey); if (api_run(targetpluginkey, function_name, callid, args_object, con_id, request->msgid, error) == -1) { if (false == error->isset) error_set(error, API_ERROR_TYPE_VALIDATION, "Error executing run API request."); return (-1); } return (0); }
struct plugin *helper_get_example_plugin(void) { struct plugin *p = MALLOC(struct plugin); struct function *f = MALLOC(struct function); if (!p || !f) LOG_ERROR("[test] Failed to alloc mem for example plugin.\n"); p->key = (string) {.str = "0123456789ABCDEF", .length = sizeof("0123456789ABCDEF") - 1}; p->name = (string) {.str = "plugin name", .length = sizeof("plugin name") - 1}; p->description = (string) {.str = "plugin desc", .length = sizeof("plugin desc") - 1}; p->license = (string) {.str = "plugin license", .length = sizeof("plugin license") - 1}; p->author = (string) {.str = "plugin author", .length = sizeof("plugin author") - 1}; p->callid = 0; f->name = (string) {.str = "function name", .length = sizeof("function name") - 1}; f->description = (string) {.str = "function desc", .length = sizeof("function desc") - 1}; f->args[0] = (string) {.str = "arg 1", .length = sizeof("arg 1") - 1}; f->args[1] = (string) {.str = "arg 2", .length = sizeof("arg 2") - 1}; p->function = f; return p; } void helper_free_plugin(struct plugin *p) { FREE(p->function); FREE(p); } /* Builds a register call and executes handle_register in order * to register the plugin. */ void helper_register_plugin(struct plugin *p) { connection_request_event_info info; struct message_request *register_request; array *meta, *functions, *func1, *args; struct api_error err = ERROR_INIT; info.request.msgid = 1; register_request = &info.request; assert_non_null(register_request); info.api_error = err; info.con = CALLOC(1, struct connection); info.con->closed = true; info.con->msgid = 1; info.con->id = (uint64_t) randommod(281474976710656LL); assert_non_null(info.con); strlcpy(info.con->cc.pluginkeystring, p->key.str, p->key.length+1); connect_to_db(); assert_int_equal(0, connection_init()); /* first level arrays: * * [meta] args->obj[0] * [functions] args->obj[1] */ register_request->params.size = 2; register_request->params.obj = CALLOC(2, struct message_object); register_request->params.obj[0].type = OBJECT_TYPE_ARRAY; register_request->params.obj[1].type = OBJECT_TYPE_ARRAY; /* meta array: * * [name] * [desciption] * [author] * [license] */ meta = ®ister_request->params.obj[0].data.params; meta->size = 4; meta->obj = CALLOC(meta->size, struct message_object); meta->obj[0].type = OBJECT_TYPE_STR; meta->obj[0].data.string = cstring_copy_string(p->name.str); meta->obj[1].type = OBJECT_TYPE_STR; meta->obj[1].data.string = cstring_copy_string(p->description.str); meta->obj[2].type = OBJECT_TYPE_STR; meta->obj[2].data.string = cstring_copy_string(p->author.str); meta->obj[3].type = OBJECT_TYPE_STR; meta->obj[3].data.string = cstring_copy_string(p->license.str); functions = ®ister_request->params.obj[1].data.params; functions->size = 1; functions->obj = CALLOC(functions->size, struct message_object); functions->obj[0].type = OBJECT_TYPE_ARRAY; func1 = &functions->obj[0].data.params; func1->size = 3; func1->obj = CALLOC(3, struct message_object); func1->obj[0].type = OBJECT_TYPE_STR; func1->obj[0].data.string = cstring_copy_string(p->function->name.str); func1->obj[1].type = OBJECT_TYPE_STR; func1->obj[1].data.string = cstring_copy_string(p->function->description.str); func1->obj[2].type = OBJECT_TYPE_ARRAY; /* function arguments */ args = &func1->obj[2].data.params; args->size = 2; args->obj = CALLOC(2, struct message_object); args->obj[0].type = OBJECT_TYPE_STR; args->obj[0].data.string = cstring_copy_string(p->function->args[0].str); args->obj[1].type = OBJECT_TYPE_STR; args->obj[1].data.string = cstring_copy_string(p->function->args[1].str); /* before running function, it must be registered successfully */ info.api_error.isset = false; expect_check(__wrap_crypto_write, &deserialized, validate_register_response, NULL); info.con->refcount++; connection_hashmap_put(info.con->id, info.con); pluginkeys_hashmap_put(info.con->cc.pluginkeystring, info.con->id); assert_int_equal(0, handle_register(info.con->id, &info.request, info.con->cc.pluginkeystring, &info.api_error)); assert_false(info.api_error.isset); //hashmap_put(uint64_t, ptr_t)(connections, info.con->id, info.con); free_params(register_request->params); //FREE(args->obj); //FREE(func1->obj); //FREE(functions->obj); //FREE(meta->obj); //FREE(register_request->params.obj); } /* Builds a run request */ void helper_build_run_request(struct message_request *rr, struct plugin *plugin, message_object_type metaarraytype, size_t metasize, message_object_type metaclientidtype, message_object_type metacallidtype, message_object_type functionnametype, message_object_type argstype ) { array argsarray = ARRAY_INIT; array *meta; rr->msgid = 1; rr->params.size = 3; rr->params.obj = CALLOC(rr->params.size, struct message_object); rr->params.obj[0].type = metaarraytype; meta = &rr->params.obj[0].data.params; meta->size = metasize; meta->obj = CALLOC(meta->size, struct message_object); meta->obj[0].type = metaclientidtype; meta->obj[0].data.string = cstring_copy_string(plugin->key.str); meta->obj[1].type = metacallidtype; rr->params.obj[1].type = functionnametype; rr->params.obj[1].data.string = cstring_copy_string(plugin->function->name.str); argsarray.size = 2; argsarray.obj = CALLOC(argsarray.size, struct message_object); argsarray.obj[0].type = OBJECT_TYPE_STR; /* first argument */ argsarray.obj[0].data.string = cstring_copy_string(plugin->function->args[0].str); argsarray.obj[1].type = OBJECT_TYPE_STR; /* second argument */ argsarray.obj[1].data.string = cstring_copy_string(plugin->function->args[1].str); rr->params.obj[2].type = argstype; rr->params.obj[2].data.params = argsarray; } void helper_build_result_request(struct message_request *rr, struct plugin *plugin, message_object_type metaarraytype, size_t metasize, message_object_type metacallidtype, message_object_type argstype) { array argsarray = ARRAY_INIT; array *meta; rr->msgid = 1; rr->params.size = 2; rr->params.obj = CALLOC(rr->params.size, struct message_object); rr->params.obj[0].type = metaarraytype; meta = &rr->params.obj[0].data.params; meta->size = metasize; meta->obj = CALLOC(meta->size, struct message_object); meta->obj[0].type = metacallidtype; meta->obj[0].data.uinteger = plugin->callid; argsarray.size = 2; argsarray.obj = CALLOC(argsarray.size, struct message_object); argsarray.obj[0].type = OBJECT_TYPE_STR; /* first argument */ argsarray.obj[0].data.string = cstring_copy_string(plugin->function->args[0].str); argsarray.obj[1].type = OBJECT_TYPE_STR; /* second argument */ argsarray.obj[1].data.string = cstring_copy_string(plugin->function->args[1].str); rr->params.obj[1].type = argstype; rr->params.obj[1].data.params = argsarray; } void helper_request_set_callid(struct message_request *rr, message_object_type callidtype) { array *meta = &rr->params.obj[0].data.params; meta->obj[0].type = callidtype; } void helper_request_set_meta_size(struct message_request *rr, message_object_type metatype, uint64_t metasize) { rr->params.obj[0].type = metatype; rr->params.obj[0].data.params.size = metasize; } void helper_request_set_args_size(struct message_request *rr, message_object_type argstype, uint64_t argssize) { rr->params.obj[1].type = argstype; rr->params.obj[1].data.params.size = argssize; } void helper_request_set_function_name(struct message_request *rr, message_object_type nametype, char *name) { free_string(rr->params.obj[1].data.string); rr->params.obj[1].type = nametype; rr->params.obj[1].data.string = cstring_copy_string(name); } void helper_request_set_pluginkey_type(struct message_request *rr, message_object_type pluginkeytype, char *pluginkey) { array *meta = &rr->params.obj[0].data.params; free_string(meta->obj[0].data.string); meta->obj[0].data.string = cstring_copy_string(pluginkey); meta->obj[0].type = pluginkeytype; }
void functional_crypto(UNUSED(void **state)) { unsigned char nonce[crypto_box_NONCEBYTES]; unsigned char initiatenonce[crypto_box_NONCEBYTES]; unsigned char hellopacket[192] = {0}; unsigned char initiatepacket[256] = {0}; unsigned char messagepacket[120]; unsigned char messagepacketout[120] = {0}; unsigned char allzeroboxed[96] = {0}; unsigned char initiatebox[160] = {0}; unsigned char pubkeybox[96] = {0}; unsigned char lengthbox[40] = {0}; uint64_t plaintextlen; uint64_t readlen; outputstream write; connect_to_db(); wrap_crypto_write = false; assert_int_equal(0, filesystem_load(".keys/server-long-term.pub", serverlongtermpk, sizeof serverlongtermpk)); cc.nonce = (uint64_t) randommod(281474976710656LL); if (!ISODD(cc.nonce)) { cc.nonce++; } cc.receivednonce = 0; cc.state = TUNNEL_INITIAL; memcpy(nonce, "splonebox-client", 16); uint64_pack(nonce + 16, cc.nonce); /* pack hello packet */ memcpy(hellopacket, "oqQN2kaH", 8); /* pack compressed nonce */ memcpy(hellopacket + 104, nonce + 16, 8); /* generate client ephemeral keys */ if (crypto_box_keypair(clientlongtermpk, clientlongtermsk) != 0) return; /* generate client ephemeral keys */ if (crypto_box_keypair(clientshorttermpk, clientshorttermsk) != 0) return; memcpy(hellopacket + 8, clientshorttermpk, 32); assert_int_equal(0, crypto_box(allzeroboxed, allzeroboxed, 96, nonce, serverlongtermpk, clientshorttermsk)); memcpy(hellopacket + 112, allzeroboxed + 16, 80); crypto_init(); /* positiv test */ assert_int_equal(0, crypto_recv_hello_send_cookie(&cc, hellopacket, &write)); /* wrong identifier */ memcpy(hellopacket, "deadbeef", 8); assert_int_not_equal(0, crypto_recv_hello_send_cookie(&cc, hellopacket, &write)); memcpy(hellopacket, "oqQN2kaH", 8); /* wrong nonce */ cc.receivednonce = cc.nonce + 1; assert_int_not_equal(0, crypto_recv_hello_send_cookie(&cc, hellopacket, &write)); cc.receivednonce = 0; /* wrong pubkey */ memset(hellopacket + 8, '0', 32); assert_int_not_equal(0, crypto_recv_hello_send_cookie(&cc, hellopacket, &write)); memcpy(hellopacket + 8, clientshorttermpk, 32); assert_int_equal(0, crypto_recv_hello_send_cookie(&cc, hellopacket, &write)); /* crypto_recv_initiate() test */ /* pack initiate packet */ memcpy(initiatepacket, "oqQN2kaI", 8); memcpy(initiatepacket + 8, cookie, 96); /* pack compressed nonce */ memcpy(initiatepacket + 104, nonce + 16, 8); memcpy(initiatebox + 32, clientlongtermpk, 32); randombytes(initiatebox + 64, 16); memcpy(initiatenonce, "splonePV", 8); memcpy(initiatenonce + 8, initiatebox + 64, 16); memcpy(pubkeybox + 32, clientshorttermpk, 32); memcpy(pubkeybox + 64, servershorttermpk, 32); assert_int_equal(0, crypto_box(pubkeybox, pubkeybox, 96, initiatenonce, serverlongtermpk, clientlongtermsk)); memcpy(initiatebox + 80, pubkeybox + 16, 80); assert_int_equal(0, crypto_box(initiatebox, initiatebox, 160, nonce, servershorttermpk, clientshorttermsk)); memcpy(initiatepacket + 112, initiatebox + 16, 144); /* without valid certificate */ assert_int_not_equal(0, crypto_recv_initiate(&cc, initiatepacket)); /* all plugins are allowed to connect */ db_authorized_set_whitelist_all(); assert_int_equal(0, crypto_recv_initiate(&cc, initiatepacket)); /* crypto_write() test */ assert_int_equal(0, crypto_write(&cc, (char*) allzeroboxed, sizeof(allzeroboxed), &write)); /* crypto_read() test */ /* pack message packet */ memcpy(messagepacket, "oqQN2kaM", 8); /* pack compressed nonce */ memcpy(nonce, "splonebox-client", 16); uint64_pack(nonce + 16, cc.nonce); memcpy(messagepacket + 8, nonce + 16, 8); uint64_pack(lengthbox + 32, 120); assert_int_equal(0, crypto_box(lengthbox, lengthbox, 40, nonce, servershorttermpk, clientshorttermsk)); memcpy(messagepacket + 16, lengthbox + 16, 24); uint64_pack(nonce + 16, cc.nonce + 2); memset(allzeroboxed, 0, 96); assert_int_equal(0, crypto_box_afternm(allzeroboxed, allzeroboxed, 96, nonce, cc.clientshortservershort)); memcpy(messagepacket + 40, allzeroboxed + 16, 80); assert_int_equal(0, crypto_verify_header(&cc, messagepacket, &readlen)); assert_int_equal(0, crypto_read(&cc, messagepacket, (char*)messagepacketout, readlen, &plaintextlen)); db_close(); }