1
0

curvecpclient.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476
  1. #include <signal.h>
  2. #include <sys/types.h>
  3. #include <sys/stat.h>
  4. #include <sys/wait.h>
  5. #include <fcntl.h>
  6. #include <poll.h>
  7. #include <unistd.h>
  8. #include "e.h"
  9. #include "die.h"
  10. #include "load.h"
  11. #include "open.h"
  12. #include "byte.h"
  13. #include "socket.h"
  14. #include "uint64_pack.h"
  15. #include "uint64_unpack.h"
  16. #include "nanoseconds.h"
  17. #include "hexparse.h"
  18. #include "nameparse.h"
  19. #include "portparse.h"
  20. #include "writeall.h"
  21. #include "safenonce.h"
  22. #include "randommod.h"
  23. long long recent = 0;
  24. #define NUMIP 8
  25. long long hellowait[NUMIP] = {
  26. 1000000000
  27. , 1500000000
  28. , 2250000000
  29. , 3375000000
  30. , 5062500000
  31. , 7593750000
  32. , 11390625000
  33. , 17085937500
  34. } ;
  35. #include "crypto_box.h"
  36. #include "randombytes.h"
  37. #if crypto_box_PUBLICKEYBYTES != 32
  38. error!
  39. #endif
  40. #if crypto_box_NONCEBYTES != 24
  41. error!
  42. #endif
  43. #if crypto_box_BOXZEROBYTES != 16
  44. error!
  45. #endif
  46. #if crypto_box_ZEROBYTES != 32
  47. error!
  48. #endif
  49. #if crypto_box_BEFORENMBYTES != 32
  50. error!
  51. #endif
  52. int flagverbose = 1;
  53. #define USAGE "\
  54. curvecpclient: how to use:\n\
  55. curvecpclient: -q (optional): no error messages\n\
  56. curvecpclient: -Q (optional): print error messages (default)\n\
  57. curvecpclient: -v (optional): print extra information\n\
  58. curvecpclient: -c keydir (optional): use this public-key directory\n\
  59. curvecpclient: sname: server's name\n\
  60. curvecpclient: pk: server's public key\n\
  61. curvecpclient: ip: server's IP address\n\
  62. curvecpclient: port: server's UDP port\n\
  63. curvecpclient: ext: server's extension\n\
  64. curvecpclient: prog: run this client\n\
  65. "
  66. void die_usage(const char *s)
  67. {
  68. if (s) die_4(100,USAGE,"curvecpclient: fatal: ",s,"\n");
  69. die_1(100,USAGE);
  70. }
  71. void die_fatal(const char *trouble,const char *d,const char *fn)
  72. {
  73. /* XXX: clean up? OS can do it much more reliably */
  74. if (!flagverbose) die_0(111);
  75. if (d) {
  76. if (fn) die_9(111,"curvecpclient: fatal: ",trouble," ",d,"/",fn,": ",e_str(errno),"\n");
  77. die_7(111,"curvecpclient: fatal: ",trouble," ",d,": ",e_str(errno),"\n");
  78. }
  79. if (errno) die_5(111,"curvecpclient: fatal: ",trouble,": ",e_str(errno),"\n");
  80. die_3(111,"curvecpclient: fatal: ",trouble,"\n");
  81. }
  82. int multiipparse(unsigned char *y,const char *x)
  83. {
  84. long long pos;
  85. long long pos2;
  86. long long ynum;
  87. long long ypos;
  88. long long j;
  89. long long k;
  90. long long d;
  91. for (j = 0;j < 4 * NUMIP;++j) y[j] = 0;
  92. ynum = 0;
  93. while (ynum < 1000) {
  94. ++ynum;
  95. ypos = randommod(ynum);
  96. for (k = 0;k < 4;++k) {
  97. pos = ypos * 4 + k;
  98. pos2 = (ynum - 1) * 4 + k;
  99. if (pos >= 0 && pos < 4 * NUMIP && pos2 >= 0 && pos2 < 4 * NUMIP) y[pos2] = y[pos];
  100. d = 0;
  101. for (j = 0;j < 3 && x[j] >= '0' && x[j] <= '9';++j) d = d * 10 + (x[j] - '0');
  102. if (j == 0) return 0;
  103. x += j;
  104. if (pos >= 0 && pos < 4 * NUMIP) y[pos] = d;
  105. if (k < 3) {
  106. if (*x != '.') return 0;
  107. ++x;
  108. }
  109. }
  110. if (!*x) break;
  111. if (*x != ',') return 0;
  112. ++x;
  113. }
  114. /* if fewer than 8 IP addresses, cycle through them: */
  115. pos = 0;
  116. pos2 = ynum * 4;
  117. while (pos2 < 4 * NUMIP) {
  118. if (pos >= 0 && pos < 4 * NUMIP && pos2 >= 0 && pos2 < 4 * NUMIP) y[pos2] = y[pos];
  119. ++pos2;
  120. ++pos;
  121. }
  122. return 1;
  123. }
  124. /* routing to the client: */
  125. unsigned char clientextension[16];
  126. long long clientextensionloadtime = 0;
  127. int udpfd = -1;
  128. void clientextension_init(void)
  129. {
  130. if (recent >= clientextensionloadtime) {
  131. clientextensionloadtime = recent + 30000000000LL;
  132. if (load("/etc/curvecpextension",clientextension,16) == -1)
  133. if (errno == ENOENT || errno == ENAMETOOLONG)
  134. byte_zero(clientextension,16);
  135. }
  136. }
  137. /* client security: */
  138. char *keydir = 0;
  139. unsigned char clientlongtermpk[32];
  140. unsigned char clientlongtermsk[32];
  141. unsigned char clientshorttermpk[32];
  142. unsigned char clientshorttermsk[32];
  143. crypto_uint64 clientshorttermnonce;
  144. unsigned char vouch[64];
  145. void clientshorttermnonce_update(void)
  146. {
  147. ++clientshorttermnonce;
  148. if (clientshorttermnonce) return;
  149. errno = EPROTO;
  150. die_fatal("nonce space expired",0,0);
  151. }
  152. /* routing to the server: */
  153. unsigned char serverip[4 * NUMIP];
  154. unsigned char serverport[2];
  155. unsigned char serverextension[16];
  156. /* server security: */
  157. unsigned char servername[256];
  158. unsigned char serverlongtermpk[32];
  159. unsigned char servershorttermpk[32];
  160. unsigned char servercookie[96];
  161. /* shared secrets: */
  162. unsigned char clientshortserverlong[32];
  163. unsigned char clientshortservershort[32];
  164. unsigned char clientlongserverlong[32];
  165. unsigned char allzero[128] = {0};
  166. unsigned char nonce[24];
  167. unsigned char text[2048];
  168. unsigned char packet[4096];
  169. unsigned char packetip[4];
  170. unsigned char packetport[2];
  171. crypto_uint64 packetnonce;
  172. int flagreceivedmessage = 0;
  173. crypto_uint64 receivednonce = 0;
  174. struct pollfd p[3];
  175. int fdwd = -1;
  176. int tochild[2] = {-1,-1};
  177. int fromchild[2] = {-1,-1};
  178. pid_t child = -1;
  179. int childstatus = 0;
  180. unsigned char childbuf[4096];
  181. long long childbuflen = 0;
  182. unsigned char childmessage[2048];
  183. long long childmessagelen = 0;
  184. int main(int argc,char **argv)
  185. {
  186. long long hellopackets;
  187. long long r;
  188. long long nextaction;
  189. signal(SIGPIPE,SIG_IGN);
  190. if (!argv[0]) die_usage(0);
  191. for (;;) {
  192. char *x;
  193. if (!argv[1]) break;
  194. if (argv[1][0] != '-') break;
  195. x = *++argv;
  196. if (x[0] == '-' && x[1] == 0) break;
  197. if (x[0] == '-' && x[1] == '-' && x[2] == 0) break;
  198. while (*++x) {
  199. if (*x == 'q') { flagverbose = 0; continue; }
  200. if (*x == 'Q') { flagverbose = 1; continue; }
  201. if (*x == 'v') { if (flagverbose == 2) flagverbose = 3; else flagverbose = 2; continue; }
  202. if (*x == 'c') {
  203. if (x[1]) { keydir = x + 1; break; }
  204. if (argv[1]) { keydir = *++argv; break; }
  205. }
  206. die_usage(0);
  207. }
  208. }
  209. if (!nameparse(servername,*++argv)) die_usage("sname must be at most 255 bytes, at most 63 bytes between dots");
  210. if (!hexparse(serverlongtermpk,32,*++argv)) die_usage("pk must be exactly 64 hex characters");
  211. if (!multiipparse(serverip,*++argv)) die_usage("ip must be a comma-separated series of IPv4 addresses");
  212. if (!portparse(serverport,*++argv)) die_usage("port must be an integer between 0 and 65535");
  213. if (!hexparse(serverextension,16,*++argv)) die_usage("ext must be exactly 32 hex characters");
  214. if (!*++argv) die_usage("missing prog");
  215. for (;;) {
  216. r = open_read("/dev/null");
  217. if (r == -1) die_fatal("unable to open /dev/null",0,0);
  218. if (r > 9) { close(r); break; }
  219. }
  220. if (keydir) {
  221. fdwd = open_cwd();
  222. if (fdwd == -1) die_fatal("unable to open current working directory",0,0);
  223. if (chdir(keydir) == -1) die_fatal("unable to change to directory",keydir,0);
  224. if (load("publickey",clientlongtermpk,sizeof clientlongtermpk) == -1) die_fatal("unable to read public key from",keydir,0);
  225. if (load(".expertsonly/secretkey",clientlongtermsk,sizeof clientlongtermsk) == -1) die_fatal("unable to read secret key from",keydir,0);
  226. } else {
  227. crypto_box_keypair(clientlongtermpk,clientlongtermsk);
  228. }
  229. crypto_box_keypair(clientshorttermpk,clientshorttermsk);
  230. clientshorttermnonce = randommod(281474976710656LL);
  231. crypto_box_beforenm(clientshortserverlong,serverlongtermpk,clientshorttermsk);
  232. crypto_box_beforenm(clientlongserverlong,serverlongtermpk,clientlongtermsk);
  233. udpfd = socket_udp();
  234. if (udpfd == -1) die_fatal("unable to create socket",0,0);
  235. for (hellopackets = 0;hellopackets < NUMIP;++hellopackets) {
  236. recent = nanoseconds();
  237. /* send a Hello packet: */
  238. clientextension_init();
  239. clientshorttermnonce_update();
  240. byte_copy(nonce,16,"CurveCP-client-H");
  241. uint64_pack(nonce + 16,clientshorttermnonce);
  242. byte_copy(packet,8,"QvnQ5XlH");
  243. byte_copy(packet + 8,16,serverextension);
  244. byte_copy(packet + 24,16,clientextension);
  245. byte_copy(packet + 40,32,clientshorttermpk);
  246. byte_copy(packet + 72,64,allzero);
  247. byte_copy(packet + 136,8,nonce + 16);
  248. crypto_box_afternm(text,allzero,96,nonce,clientshortserverlong);
  249. byte_copy(packet + 144,80,text + 16);
  250. socket_send(udpfd,packet,224,serverip + 4 * hellopackets,serverport);
  251. nextaction = recent + hellowait[hellopackets] + randommod(hellowait[hellopackets]);
  252. for (;;) {
  253. long long timeout = nextaction - recent;
  254. if (timeout <= 0) break;
  255. p[0].fd = udpfd;
  256. p[0].events = POLLIN;
  257. if (poll(p,1,timeout / 1000000 + 1) < 0) p[0].revents = 0;
  258. do { /* try receiving a Cookie packet: */
  259. if (!p[0].revents) break;
  260. r = socket_recv(udpfd,packet,sizeof packet,packetip,packetport);
  261. if (r != 200) break;
  262. if (!(byte_isequal(packetip,4,serverip + 4 * hellopackets) &
  263. byte_isequal(packetport,2,serverport) &
  264. byte_isequal(packet,8,"RL3aNMXK") &
  265. byte_isequal(packet + 8,16,clientextension) &
  266. byte_isequal(packet + 24,16,serverextension)
  267. )) break;
  268. byte_copy(nonce,8,"CurveCPK");
  269. byte_copy(nonce + 8,16,packet + 40);
  270. byte_zero(text,16);
  271. byte_copy(text + 16,144,packet + 56);
  272. if (crypto_box_open_afternm(text,text,160,nonce,clientshortserverlong)) break;
  273. byte_copy(servershorttermpk,32,text + 32);
  274. byte_copy(servercookie,96,text + 64);
  275. byte_copy(serverip,4,serverip + 4 * hellopackets);
  276. goto receivedcookie;
  277. } while (0);
  278. recent = nanoseconds();
  279. }
  280. }
  281. errno = ETIMEDOUT; die_fatal("no response from server",0,0);
  282. receivedcookie:
  283. crypto_box_beforenm(clientshortservershort,servershorttermpk,clientshorttermsk);
  284. byte_copy(nonce,8,"CurveCPV");
  285. if (keydir) {
  286. if (safenonce(nonce + 8,0) == -1) die_fatal("nonce-generation disaster",0,0);
  287. } else {
  288. randombytes(nonce + 8,16);
  289. }
  290. byte_zero(text,32);
  291. byte_copy(text + 32,32,clientshorttermpk);
  292. crypto_box_afternm(text,text,64,nonce,clientlongserverlong);
  293. byte_copy(vouch,16,nonce + 8);
  294. byte_copy(vouch + 16,48,text + 16);
  295. /* server is responding, so start child: */
  296. if (open_pipe(tochild) == -1) die_fatal("unable to create pipe",0,0);
  297. if (open_pipe(fromchild) == -1) die_fatal("unable to create pipe",0,0);
  298. child = fork();
  299. if (child == -1) die_fatal("unable to fork",0,0);
  300. if (child == 0) {
  301. if (keydir) if (fchdir(fdwd) == -1) die_fatal("unable to chdir to original directory",0,0);
  302. close(8);
  303. if (dup(tochild[0]) != 8) die_fatal("unable to dup",0,0);
  304. close(9);
  305. if (dup(fromchild[1]) != 9) die_fatal("unable to dup",0,0);
  306. /* XXX: set up environment variables */
  307. signal(SIGPIPE,SIG_DFL);
  308. execvp(*argv,argv);
  309. die_fatal("unable to run",*argv,0);
  310. }
  311. close(fromchild[1]);
  312. close(tochild[0]);
  313. for (;;) {
  314. p[0].fd = udpfd;
  315. p[0].events = POLLIN;
  316. p[1].fd = fromchild[0];
  317. p[1].events = POLLIN;
  318. if (poll(p,2,-1) < 0) {
  319. p[0].revents = 0;
  320. p[1].revents = 0;
  321. }
  322. do { /* try receiving a Message packet: */
  323. if (!p[0].revents) break;
  324. r = socket_recv(udpfd,packet,sizeof packet,packetip,packetport);
  325. if (r < 80) break;
  326. if (r > 1152) break;
  327. if (r & 15) break;
  328. packetnonce = uint64_unpack(packet + 40);
  329. if (flagreceivedmessage && packetnonce <= receivednonce) break;
  330. if (!(byte_isequal(packetip,4,serverip + 4 * hellopackets) &
  331. byte_isequal(packetport,2,serverport) &
  332. byte_isequal(packet,8,"RL3aNMXM") &
  333. byte_isequal(packet + 8,16,clientextension) &
  334. byte_isequal(packet + 24,16,serverextension)
  335. )) break;
  336. byte_copy(nonce,16,"CurveCP-server-M");
  337. byte_copy(nonce + 16,8,packet + 40);
  338. byte_zero(text,16);
  339. byte_copy(text + 16,r - 48,packet + 48);
  340. if (crypto_box_open_afternm(text,text,r - 32,nonce,clientshortservershort)) break;
  341. if (!flagreceivedmessage) {
  342. flagreceivedmessage = 1;
  343. randombytes(clientlongtermpk,sizeof clientlongtermpk);
  344. randombytes(vouch,sizeof vouch);
  345. randombytes(servername,sizeof servername);
  346. randombytes(servercookie,sizeof servercookie);
  347. }
  348. receivednonce = packetnonce;
  349. text[31] = (r - 64) >> 4;
  350. /* child is responsible for reading all data immediately, so we won't block: */
  351. if (writeall(tochild[1],text + 31,r - 63) == -1) goto done;
  352. } while (0);
  353. do { /* try receiving data from child: */
  354. long long i;
  355. if (!p[1].revents) break;
  356. r = read(fromchild[0],childbuf,sizeof childbuf);
  357. if (r == -1) if (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN) break;
  358. if (r <= 0) goto done;
  359. childbuflen = r;
  360. for (i = 0;i < childbuflen;++i) {
  361. if (childmessagelen < 0) goto done;
  362. if (childmessagelen >= sizeof childmessage) goto done;
  363. childmessage[childmessagelen++] = childbuf[i];
  364. if (childmessage[0] & 128) goto done;
  365. if (childmessagelen == 1 + 16 * (unsigned long long) childmessage[0]) {
  366. clientextension_init();
  367. clientshorttermnonce_update();
  368. uint64_pack(nonce + 16,clientshorttermnonce);
  369. if (flagreceivedmessage) {
  370. r = childmessagelen - 1;
  371. if (r < 16) goto done;
  372. if (r > 1088) goto done;
  373. byte_copy(nonce,16,"CurveCP-client-M");
  374. byte_zero(text,32);
  375. byte_copy(text + 32,r,childmessage + 1);
  376. crypto_box_afternm(text,text,r + 32,nonce,clientshortservershort);
  377. byte_copy(packet,8,"QvnQ5XlM");
  378. byte_copy(packet + 8,16,serverextension);
  379. byte_copy(packet + 24,16,clientextension);
  380. byte_copy(packet + 40,32,clientshorttermpk);
  381. byte_copy(packet + 72,8,nonce + 16);
  382. byte_copy(packet + 80,r + 16,text + 16);
  383. socket_send(udpfd,packet,r + 96,serverip,serverport);
  384. } else {
  385. r = childmessagelen - 1;
  386. if (r < 16) goto done;
  387. if (r > 640) goto done;
  388. byte_copy(nonce,16,"CurveCP-client-I");
  389. byte_zero(text,32);
  390. byte_copy(text + 32,32,clientlongtermpk);
  391. byte_copy(text + 64,64,vouch);
  392. byte_copy(text + 128,256,servername);
  393. byte_copy(text + 384,r,childmessage + 1);
  394. crypto_box_afternm(text,text,r + 384,nonce,clientshortservershort);
  395. byte_copy(packet,8,"QvnQ5XlI");
  396. byte_copy(packet + 8,16,serverextension);
  397. byte_copy(packet + 24,16,clientextension);
  398. byte_copy(packet + 40,32,clientshorttermpk);
  399. byte_copy(packet + 72,96,servercookie);
  400. byte_copy(packet + 168,8,nonce + 16);
  401. byte_copy(packet + 176,r + 368,text + 16);
  402. socket_send(udpfd,packet,r + 544,serverip,serverport);
  403. }
  404. childmessagelen = 0;
  405. }
  406. }
  407. } while (0);
  408. }
  409. done:
  410. do {
  411. r = waitpid(child,&childstatus,0);
  412. } while (r == -1 && errno == EINTR);
  413. if (!WIFEXITED(childstatus)) { errno = 0; die_fatal("process killed by signal",0,0); }
  414. return WEXITSTATUS(childstatus);
  415. }