- fixed poll emulation management
[vde.git] / vde-2 / vde_cryptcab / blowfish.c
bloba6a22a1d52654e0219b59b15bef53c4cb7ceb140
1 /*
2 * Blowfish functions
3 * Copyright © 2006 Daniele Lacamera
4 * Released under the terms of GNU GPL v.2
5 * http://www.gnu.org/copyleft/gpl.html
7 * This program is released under the GPL with the additional exemption that
8 * compiling, linking, and/or using OpenSSL is allowed.
9 */
11 #include <sys/types.h>
12 #include <sys/ioctl.h>
13 #include <sys/time.h>
14 #include "compat/poll.h"
15 #include <sys/stat.h>
16 #include <sys/time.h>
17 #include <sys/socket.h>
18 #include <net/if.h>
19 #include <netinet/in.h>
20 #include <arpa/inet.h>
21 #include <sys/socket.h>
22 #include <fcntl.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <stdlib.h>
26 #include <unistd.h>
27 #include <errno.h>
29 #include <config.h>
31 #include "blowfish.h"
32 #include "crc32.h"
34 unsigned char *crc32(unsigned char*,int);
35 static unsigned long long mycounter=1;
37 static EVP_CIPHER_CTX ctx;
38 static int nfd = -1;
39 static struct peer *list=NULL;
41 static struct itimerval TIMER = {
42 .it_interval={ .tv_sec=0, .tv_usec=0},
43 .it_value={ .tv_sec=SESSION_TIMEOUT/2, .tv_usec=0 }
47 * Add a peer to the main list.
48 * Client will have a list of one peer only,
49 * server will have a peer in the list for each "connection"
50 * it establishes.
53 void addpeer(struct peer *np)
55 np->next=list;
56 list=np;
61 * Internal, recursive functions:
63 static int _peers(struct peer *iter)
65 if(!iter)
66 return 0;
67 else
68 return 1+_peers(iter->next);
71 static void _populatepoll(struct pollfd *pfd, struct peer *iter,int index, struct peer *peerlist)
73 int datafd;
74 if(!iter)
75 return;
76 memcpy(&(peerlist[index]),iter,sizeof(struct peer));
77 datafd=vde_datafd(iter->plug);
78 if(datafd >= 0){
79 pfd[index].fd=datafd;
80 pfd[index++].events=POLLIN|POLLHUP;
81 } else {
82 vde_plug(iter);
83 usleep(100000);
84 _populatepoll(pfd,iter->next,index, peerlist);
85 return;
89 _populatepoll(pfd,iter->next,index, peerlist);
94 struct peer *_getpeer(struct sockaddr_in saddr, struct peer *sublist)
96 if(!sublist)
97 return NULL;
98 if(sublist->in_a.sin_addr.s_addr==saddr.sin_addr.s_addr && sublist->in_a.sin_port==saddr.sin_port)
99 return sublist;
100 return _getpeer(saddr,sublist->next);
104 struct peer *_getpeerbna(struct sockaddr_in saddr, struct peer *sublist)
106 if(!sublist)
107 return NULL;
108 if(sublist->handover_a.sin_addr.s_addr==saddr.sin_addr.s_addr && sublist->handover_a.sin_port==saddr.sin_port)
109 return sublist;
110 return _getpeerbna(saddr,sublist->next);
114 static struct peer *_getpeerbyid(struct datagram *pkt, struct peer *sublist)
116 if(pkt->len!=FILENAMESIZE+1)
117 return NULL;
118 if(!sublist)
119 return NULL;
120 if(strncmp((char *)pkt->data+1,sublist->id,FILENAMESIZE)==0)
121 return sublist;
122 return _getpeerbyid(pkt,sublist->next);
127 void
128 set_expire(struct peer *p)
130 gettimeofday(&(p->expire),NULL);
131 p->expire.tv_sec+=SESSION_TIMEOUT;
135 * Check progressive number validity in incoming datagram
138 isvalid_timestamp(unsigned char *block, int size, struct peer *p)
142 int i;
143 unsigned long long pktcounter=0;
144 for(i=0;i<8;i++){
145 pktcounter+=block[size-12+i]<<(i*8);
147 if(pktcounter>p->counter){
148 p->counter=pktcounter;
149 return 1;
150 }else{
151 //fprintf(stderr,"bad timestamp!\n");
152 return 0;
158 * Check CRC32 Checksum from incoming datagram
160 int
161 isvalid_crc32(unsigned char *block, int len)
163 unsigned char *crc=(unsigned char *)crc32(block,len-4);
164 if(strncmp((char*)block+(len-4),(char*)crc,4)==0){
165 free(crc);
166 return 1;
167 }else{
169 //fprintf(stderr,"bad crc32!\n");
170 free(crc);
171 return 0;
177 * Returns peer list length.
180 static int numberofpeers(){
181 struct peer *iter=list;
182 return _peers(iter);
187 struct peer *clean_peerlist(struct peer *sublist)
189 if(!sublist)
190 return NULL;
192 if(sublist->state == ST_AUTH && vde_datafd(sublist->plug) < 0){
193 struct peer *nxt=sublist->next;
194 free(sublist);
195 return nxt;
198 if(sublist->state == ST_AUTH){
199 struct timeval now;
200 gettimeofday(&now,NULL);
202 if(after(now,sublist->expire)){
203 struct peer *nxt=sublist->next;
204 vde_close(sublist->plug);
205 free(sublist);
206 return nxt;
210 sublist->next=clean_peerlist(sublist->next);
211 return sublist;
215 void
216 autocleaner(int signo)
218 struct itimerval *old=NULL;
219 list=clean_peerlist(list);
220 setitimer(ITIMER_REAL, &TIMER, old);
224 * Returns a list of all the peer in the peer list, adding their
225 * network socket to pollfd.
226 * This is called in blowfish_select, to populate the pollfd structure.
228 static struct peer *populate_peerlist(struct pollfd *pfd)
230 static struct peer *iter, *peerlist;
231 iter=list; //=clean_peerlist(list);
232 if(peerlist)
233 free(peerlist);
234 peerlist=(struct peer *) malloc( (numberofpeers()+1)*sizeof(struct peer) );
235 _populatepoll(pfd,iter,1,peerlist);
237 return peerlist;
241 * Get a pointer to the peer in the list which has the given udp address.
243 struct peer *getpeer(struct sockaddr_in saddr)
245 struct peer *iter=list;
246 return (_getpeer(saddr,iter));
250 struct peer *getpeerbynewaddr(struct sockaddr_in saddr)
252 struct peer *iter=list;
253 return (_getpeerbna(saddr,iter));
259 * Get a pointer to the peer in the list which key filename is the same of that in the login datagram.
261 struct peer *getpeerbyid(struct datagram *pkt)
263 struct peer *iter=list;
264 return (_getpeerbyid(pkt,iter));
269 * Send a plain "access denied" message to the specified peer.
271 void
272 deny_access(struct peer *p)
274 send_udp((unsigned char *)"Access Denied.\0",15,p,CMD_DENY);
278 * Main select routine.
279 * A poll will wake up whenever a new packet is available to read, either from one
280 * of the vde_plug attached, or from udp socket.
281 * Returns a struct datagram aware of its own source.
282 * Also discriminate commands from data, by first byte.
284 struct datagram *blowfish_select (int timeout)
286 unsigned peerlen;
287 int pollret;
288 static struct pollfd *pfd = NULL;
289 static struct datagram *ret = NULL;
290 static struct peer *peerlist = NULL;
291 static int i=1;
293 if (pfd)
294 free(pfd);
295 pfd=malloc((1+numberofpeers())*sizeof(struct pollfd));
297 pfd[0].fd=nfd;
298 pfd[0].events=POLLIN|POLLHUP;
299 peerlist = populate_peerlist(pfd);
302 pollret=poll(pfd,1+numberofpeers(),1000);
303 if(pollret<0){
304 if(errno==EINTR)
305 return NULL;
306 perror("poll");
307 exit(1);
309 if (!ret){
310 ret = malloc(sizeof(struct datagram));
311 bzero(ret,sizeof(struct datagram));
312 ret->orig = malloc(sizeof (struct peer));
313 bzero(ret->orig,sizeof(struct peer));
315 } while (pollret==0);
318 for(;;){
319 if (pfd[0].revents&POLLIN) {
320 unsigned char inpkt[MAXPKT];
321 unsigned char *inbuff=inpkt+1;
322 int ilen,tlen;
323 struct sockaddr_in ipaddress;
324 peerlen = sizeof(struct sockaddr_in);
325 ilen = recvfrom(nfd, inpkt, MAXPKT, 0,
326 (struct sockaddr *) &ipaddress, &peerlen);
328 ret->orig=getpeer(ipaddress);
329 if(!ret->orig){
330 ret->orig=malloc(sizeof(struct peer));
331 bzero(ret->orig,sizeof(struct peer));
332 ret->orig->in_a.sin_family = AF_INET;
333 ret->orig->in_a.sin_port = ipaddress.sin_port;
334 ret->orig->in_a.sin_addr.s_addr= ipaddress.sin_addr.s_addr;
335 ret->orig->state=ST_CLOSED;
339 if((inpkt[0]==PKT_DATA)&&
340 (ret->orig->state==ST_AUTH || ret->orig->state==ST_SERVER))
343 ret->src = SRC_BF;
344 ilen--;
346 EVP_DecryptInit (&ctx, EVP_bf_cbc (), ret->orig->key, ret->orig->iv);
348 if (EVP_DecryptUpdate (&ctx, ret->data, &ret->len, inbuff, ilen) != 1)
350 fprintf (stderr,"error in decrypt update\n");
351 return NULL;
353 if (EVP_DecryptFinal (&ctx, ret->data + ret->len, &tlen) != 1)
355 fprintf (stderr,"error in decrypt final\n");
356 return NULL;
358 EVP_CIPHER_CTX_cleanup(&ctx);
359 ret->len += tlen;
360 if( isvalid_crc32(ret->data,ret->len) && isvalid_timestamp(ret->data,ret->len,ret->orig) ){
361 ret->len-=12;
362 if(ret->orig->state==ST_AUTH)
363 set_expire(ret->orig);
364 return ret;
365 }else{
366 // deny_access(ret->orig);
367 return NULL;
369 }else if((inpkt[0]==CMD_HANDOVER)){
370 ret->src = SRC_CTL;
371 ilen--;
373 //fprintf (stderr,"Recived Handover datagram.: ");
374 EVP_DecryptInit (&ctx, EVP_bf_cbc (), ret->orig->key, ret->orig->iv);
376 if (EVP_DecryptUpdate (&ctx, ret->data+1, &ret->len, inbuff, ilen) != 1)
378 fprintf (stderr,"error in decrypt update\n");
379 return NULL;
381 if (EVP_DecryptFinal (&ctx, ret->data + 1 + ret->len, &tlen) != 1)
383 fprintf (stderr,"error in decrypt final\n");
384 return NULL;
386 EVP_CIPHER_CTX_cleanup(&ctx);
387 ret->len += tlen;
388 ret->len +=1;
389 if( isvalid_crc32(ret->data+1,ret->len-1) && isvalid_timestamp(ret->data,ret->len,ret->orig) ){
390 ret->len-=12;
391 ret->data[0]=CMD_HANDOVER;
392 //fprintf (stderr,"Valid Handover. Resending key.\n");
393 return ret;
394 }else{
395 fprintf (stderr,"Invalid Handover packet. crc32?%d, timestamp?%d \n",isvalid_crc32(ret->data+1,ret->len-1), isvalid_timestamp(ret->data,ret->len,ret->orig));
396 deny_access(ret->orig);
397 return NULL;
400 }else if(inpkt[0]&PKT_CTL){
401 ret->src = SRC_CTL;
402 memcpy(ret->data,inpkt,ilen);
403 ret->len=ilen;
404 return ret;
405 }else{
406 deny_access(ret->orig);
407 return NULL;
414 // This increment comes with "static int i" def, to ensure fairness among peers.
415 i++;
416 if(i>numberofpeers())
417 i=1;
419 if (pfd[i].revents&POLLIN) {
420 /* c=read(pfd[i].fd,ret->data,2);
421 if(c<2)
422 return NULL;
423 vde_len=0;
424 vde_len+=((unsigned char)(ret->data[0]))<<8;
425 vde_len+=(unsigned char)(ret->data[1]);
427 ret->len=2;
428 while(ret->len < (vde_len + 2)){
429 ret->len += read(pfd[i].fd, ret->data+ret->len, ((vde_len+2) - ret->len));
431 // fprintf(stderr,"Read %d.\n",vde_len);
434 ret->len = vde_recv(peerlist[i].plug, ret->data, MAXPKT,0);
436 if(ret->len<1)
437 return NULL;
439 ret->src = SRC_VDE;
440 ret->orig = &(peerlist[i]);
442 //set_expire(&(peerlist[i]));
445 return ret;
448 // list=clean_peerlist(list);
450 return NULL;
455 * Send a virtual frame to the vde_plug process associated
456 * with the peer
458 void
459 send_vdeplug(const char *data, size_t len, struct peer *p)
461 static unsigned int outbuf[MAXPKT];
462 static int outp=0;
463 static u_int16_t outlen;
464 if(len<=0)
465 return;
467 if(outp==0 && (len >=2) ){
468 outlen=2;
469 outlen+=(unsigned char)data[1];
470 outlen+=((unsigned char)(data[0]))<<8;
473 if(len>=outlen){
474 vde_send(p->plug,data,outlen,0);
475 send_vdeplug(data+outlen,len-outlen, p);
476 return;
479 memcpy(outbuf+outp,data,len);
480 outp+=len;
481 if(outp>=outlen){
482 vde_send(p->plug,(char *)outbuf,outlen,0);
487 * Include a progressive number into outgoing datagram,
488 * to prevent packet replication/injection attack.
491 void
492 set_timestamp(unsigned char *block)
494 int i;
495 for(i=0;i<8;i++){
496 block[i]=(unsigned char)(mycounter>>(i*8))&(0x00000000000000FF);
498 mycounter++;
505 * Send an udp datagram to specified peer.
507 void
508 send_udp (unsigned char *data, size_t len, struct peer *p, unsigned char flags)
511 unsigned char outpkt[MAXPKT];
512 unsigned char *outbuf=outpkt+1;
513 int olen,tlen;
514 struct sockaddr_in *destination=&(p->in_a);
515 unsigned char *crc;
516 if(flags==CMD_CHALLENGE || flags==CMD_LOGIN || flags==CMD_DENY || flags==CMD_AUTH_OK || flags==CMD_IDENTIFY){
517 memcpy(outbuf,data,len);
518 olen=len;
519 }else{
520 if(flags==PKT_DATA||flags==CMD_HANDOVER){
521 set_timestamp(data+len);
522 len+=8;
524 crc = crc32(data,len);
525 memcpy(data+len,crc32(data,len),4);
526 free(crc);
527 len+=4;
530 if(flags==CMD_HANDOVER){
532 destination=&(p->handover_a);
535 EVP_EncryptInit (&ctx, EVP_bf_cbc (), p->key, p->iv);
536 if (EVP_EncryptUpdate (&ctx, outbuf, &olen, data, len) != 1)
538 fprintf (stderr,"error in encrypt update\n");
539 return;
543 if (EVP_EncryptFinal (&ctx, outbuf + olen, &tlen) != 1)
545 fprintf (stderr,"error in encrypt final\n");
546 return;
548 EVP_CIPHER_CTX_cleanup(&ctx);
549 olen += tlen;
552 outpkt[0]=flags;
553 sendto(nfd, outpkt, olen+1, 0, (struct sockaddr *) destination,
554 sizeof(struct sockaddr_in));
558 * Generate a new blowfish key, store it in a local file and fill the fields
559 * of peer structure.
560 * Client only.
562 struct peer
563 *generate_key (struct peer *ret, char *pre_shared)
565 int i, fd=-1, od=-1, createnow=0;
566 unsigned char key[16];
567 unsigned char iv[8];
568 unsigned char c;
569 char *path;
570 char random[]="/dev/urandom";
571 if (pre_shared)
572 path=pre_shared;
573 else
574 path=random;
576 if(!ret){
577 ret=malloc(sizeof(struct peer));
578 bzero(ret,sizeof(struct peer));
579 createnow=1;
581 if ( ((fd = open (path, O_RDONLY)) == -1)||
582 ((read (fd, key, 16)) == -1) ||
583 ((read (fd, iv, 8)) == -1) )
586 perror ("Error Creating key.\n");
587 goto failure;
590 //fprintf(stderr,"128 bit key stored.\n");
592 //fprintf(stderr,"64 bit Initialization vector stored.\n");
594 for(i=0; i<FILENAMESIZE-1;i++){
595 read(fd,&c,1);
596 c=(c%25);
597 //fprintf(stderr,"c=%u\n",c);
598 ret->id[i]=(char)('a' + c);
600 ret->id[FILENAMESIZE-1]='\0';
602 close (fd);
604 if ((od = creat ("/tmp/.blowfish.key",0600)) == -1){
605 perror ("blowfish.key creat error");
606 goto failure;
608 memcpy(ret->key,key,16);
609 memcpy(ret->iv,iv,8);
610 write(od,key,16);
611 write(od,iv,8);
612 close (od);
613 return ret;
615 failure:
616 if (createnow)
617 free(ret);
618 if (fd != -1)
619 close(fd);
620 if (od != -1)
621 close(od);
622 return NULL;
627 * Send a "Challenge" 4WHS packet.
629 static void
630 send_challenge(struct peer *p)
632 int fd;
633 if ( ((fd = open ("/dev/urandom", O_RDONLY)) == -1)||
634 ((read (fd, p->challenge, 128)) != -1))
636 send_udp((unsigned char *)p->challenge,128,p,PKT_CTL|CMD_CHALLENGE);
638 p->state=ST_CHALLENGE;
639 close(fd);
643 * Send a "Auth OK" 4WHS packet.
645 static void
646 send_auth_ok(struct peer *p, void (*callback)(struct peer*))
648 send_udp(NULL,0,p,CMD_AUTH_OK);
649 p->state=ST_AUTH;
650 callback(p);
651 set_expire(p);
655 * Receive a challenge. Try to send response encrypted with local blowfish key.
657 void
658 rcv_challenge(struct datagram *pkt, struct peer *p)
660 send_udp(pkt->data+1,pkt->len-1,p,CMD_RESPONSE);
661 p->state=ST_WAIT_AUTH;
666 * Receive a login request. Send challenge.
668 void
669 rcv_login(struct datagram *pkt, struct peer *p, char *pre_shared)
671 int fd;
672 char filename[128];
673 if(!pre_shared)
674 snprintf(filename,127,"/tmp/.%s.key",pkt->data+1);
675 else
676 snprintf(filename,127,"%s",pre_shared);
679 fprintf(stderr,"Filename:%s\n",filename);
680 if (((fd = open (filename, O_RDONLY)) == -1)||
681 ((read (fd, p->key, 16)) == -1) ||
682 ((read (fd, p->iv, 8)) == -1) ){
683 perror ("blowfish.key open error");
684 deny_access(p);
685 return;
687 close(fd);
688 memcpy(p->id,pkt->data+1,FILENAMESIZE);
689 fprintf(stderr,"Sending challenge... ");
690 send_challenge(p);
691 fprintf(stderr,"OK.\n");
696 * Receive a response from challenge. Validate encryption and send "ok auth"
697 * or "access denied"
699 void
700 rcv_response(struct datagram *pkt, struct peer *p, void (*callback)(struct peer*))
702 unsigned char response[MAXPKT];
703 int rlen, tlen;
705 EVP_DecryptInit (&ctx, EVP_bf_cbc (), p->key, p->iv);
707 if (EVP_DecryptUpdate (&ctx, response, &rlen, pkt->data+1, pkt->len-1) != 1)
709 fprintf (stderr,"error in decrypt update\n");
710 return;
713 if (EVP_DecryptFinal (&ctx, response + rlen, &tlen) != 1)
715 fprintf (stderr,"error in decrypt final\n");
716 return;
718 EVP_CIPHER_CTX_cleanup(&ctx);
720 if (strncmp((char *)response,p->challenge,128)==0){
721 p->state=ST_AUTH;
722 send_auth_ok(p, callback);
725 else{
726 p->state=ST_CLOSED;
727 deny_access(p);
733 * Send a login packet. This is the first phase of 4WHS
735 void
736 blowfish_login(struct peer *p)
738 send_udp((unsigned char*)p->id,FILENAMESIZE,p,CMD_LOGIN);
742 * Initialize blowfish module.
743 * Set udp socket and initialize crypto engine & CRC32.
745 void
746 blowfish_init(int socketfd)
748 nfd=socketfd;
749 EVP_CIPHER_CTX_init (&ctx);
750 chksum_crc32gentab ();