/* * Secure OLSR plugin * http://www.olsr.org * * Copyright (c) 2004, Andreas Tønnesen(andreto@olsr.org) * All rights reserved. * * Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * Neither the name of olsrd, olsr.org nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * $Id: olsrd_secure.c,v 1.27 2007/08/02 14:37:09 bernd67 Exp $ */ /* * Dynamic linked library for the olsr.org olsr daemon */ #include "olsrd_secure.h" #include #include #include #ifdef linux #include #endif #include #include #include #include "defs.h" #include "olsr.h" #include "socket_parser.h" #include "parser.h" #include "scheduler.h" #ifdef USE_OPENSSL /* OpenSSL stuff */ #include #define CHECKSUM SHA1 #define SCHEME SHA1_INCLUDING_KEY #else /* Homebrewn checksuming */ #include "md5.h" static void MD5_checksum(const olsr_u8_t *data, const olsr_u16_t data_len, olsr_u8_t *hashbuf) { MD5_CTX context; MD5Init(&context); MD5Update(&context, data, data_len); MD5Final(hashbuf, &context); } #define CHECKSUM MD5_checksum #define SCHEME MD5_INCLUDING_KEY #endif #ifdef OS #undef OS #endif #ifdef WIN32 #define close(x) closesocket(x) #undef EWOULDBLOCK #define EWOULDBLOCK WSAEWOULDBLOCK #define OS "Windows" #endif #ifdef linux #define OS "GNU/Linux" #endif #ifdef __FreeBSD__ #define OS "FreeBSD" #endif #ifndef OS #define OS "Undefined" #endif /* Timestamp node */ struct stamp { union olsr_ip_addr addr; /* Timestamp difference */ int diff; olsr_u32_t challenge; olsr_u8_t validated; clock_t valtime; /* Validity time */ clock_t conftime; /* Reconfiguration time */ struct stamp *prev; struct stamp *next; }; /* Seconds to cache a valid timestamp entry */ #define TIMESTAMP_HOLD_TIME 30 /* Seconds to cache a not verified timestamp entry */ #define EXCHANGE_HOLD_TIME 5 static struct stamp timestamps[HASHSIZE]; char keyfile[FILENAME_MAX+1]; char aes_key[16]; /* Input interface */ static struct interface *olsr_in_if; /* Event function to register with the sceduler */ #if 0 static void olsr_event(void); #endif static int send_challenge(union olsr_ip_addr *); static int ifchange(struct interface *, int); static int send_cres(union olsr_ip_addr *, union olsr_ip_addr *, olsr_u32_t, struct stamp *); static int send_rres(union olsr_ip_addr *, union olsr_ip_addr *, olsr_u32_t); static int parse_challenge(char *); static int parse_cres(char *); static int parse_rres(char *); static int check_auth(char *, int *); #if 0 static int ipc_send(char *, int); #endif static int add_signature(olsr_u8_t *, int*); static int validate_packet(char *, int*); static void packet_parser(int); static void timeout_timestamps(void*); static int check_timestamp(union olsr_ip_addr *, time_t); static struct stamp *lookup_timestamp_entry(union olsr_ip_addr *); static int read_key_from_file(char *); /** *Do initialization here * *This function is called by the my_init *function in uolsrd_plugin.c */ int secure_plugin_init(void) { struct interface *ints; int i; /* Initialize the timestamp database */ for(i = 0; i < HASHSIZE; i++) { timestamps[i].next = ×tamps[i]; timestamps[i].prev = ×tamps[i]; } olsr_printf(1, "Timestamp database initialized\n"); if(!strlen(keyfile)) strcpy(keyfile, KEYFILE); i = read_key_from_file(keyfile); if(i < 0) { olsr_printf(1, "[ENC]Could not read key from file %s!\nExitting!\n\n", keyfile); exit(1); } if(i == 0) { olsr_printf(1, "[ENC]There was a problem reading key from file %s. Is the key long enough?\nExitting!\n\n", keyfile); exit(1); } /* Register the packet transform function */ add_ptf(&add_signature); /* register ifchange function */ add_ifchgf(&ifchange); /* Hijack OLSR socket parser functions */ ints = ifnet; while(ints) { olsr_printf(1, "[ENC]Hijacking %s socket %d\n", ints->int_name, ints->olsr_socket); fflush(stdout); remove_olsr_socket(ints->olsr_socket, olsr_input); add_olsr_socket(ints->olsr_socket, &packet_parser); /* Reducing maxmessagesize */ net_reserve_bufspace(ints, sizeof(struct s_olsrmsg)); ints = ints->int_next; } /* Register timeout - poll every 2 seconds */ olsr_register_scheduler_event(&timeout_timestamps, NULL, 2, 0 , NULL); return 1; } int plugin_ipc_init(void) { return 1; } /* * destructor - called at unload */ void secure_plugin_exit(void) { } #if 0 /** *Scheduled event */ static void olsr_event(void) { } #endif #if 0 static int ipc_send(char *data __attribute__((unused)), int size __attribute__((unused))) { return 1; } #endif /* XXX - ToDo */ static int ifchange(struct interface *ifn, int action) { switch(action) { case(IFCHG_IF_ADD): printf("SEC: interface %s added\n\n", ifn->int_name); olsr_printf(1, "[ENC]Hijacking %s socket %d\n", ifn->int_name, ifn->olsr_socket); remove_olsr_socket(ifn->olsr_socket, olsr_input); add_olsr_socket(ifn->olsr_socket, &packet_parser); /* Reducing maxmessagesize */ net_reserve_bufspace(ifn, sizeof(struct s_olsrmsg)); break; case(IFCHG_IF_REMOVE): printf("SEC: interface %s removed\n\n", ifn->int_name); olsr_printf(1, "[ENC]Removing %s socket %d\n", ifn->int_name, ifn->olsr_socket); remove_olsr_socket(ifn->olsr_socket, &packet_parser); break; case(IFCHG_IF_UPDATE): printf("SEC: interface %s updated\n\n", ifn->int_name); break; default: break; } return 0; } static void packet_parser(int fd) { /* sockaddr_in6 is bigger than sockaddr !!!! */ struct sockaddr_storage from; socklen_t fromlen; int cc; union olsr_ip_addr from_addr; union { char buf[MAXMESSAGESIZE+1]; struct olsr olsr; } inbuf; for (;;) { fromlen = sizeof(struct sockaddr_storage); cc = recvfrom(fd, (void *)&inbuf, sizeof (inbuf), 0, (struct sockaddr *)&from, &fromlen); if (cc <= 0) { if (cc < 0 && errno != EWOULDBLOCK) { olsr_printf(1, "[ENC]error recvfrom: %s", strerror(errno)); } break; } if(olsr_cnf->ip_version == AF_INET) { /* IPv4 sender address */ memcpy(&from_addr, &((struct sockaddr_in *)&from)->sin_addr.s_addr, olsr_cnf->ipsize); } else { /* IPv6 sender address */ memcpy(&from_addr, &((struct sockaddr_in6 *)&from)->sin6_addr, olsr_cnf->ipsize); } /* olsr_printf(1, "[ENC]message from %s size %d\n", olsr_ip_to_string(&from_addr), cc); */ /* are we talking to ourselves? */ if(if_ifwithaddr(&from_addr) != NULL) return; /* *setting global from addr */ //printf("Recieved data on socket %d\n", socknr); if((olsr_in_if = if_ifwithsock(fd)) == NULL) { olsr_printf(1, "[ENC]Could not find input interface for message from %s size %d\n", olsr_ip_to_string(&from_addr), cc); return ; } /* * Check for challenge/response messages */ check_auth(inbuf.buf, &cc); /* * Check signature */ if(!validate_packet(inbuf.buf, &cc)) { olsr_printf(1, "[ENC]Rejecting packet from %s\n", olsr_ip_to_string((union olsr_ip_addr *)&((struct sockaddr_in *)&from)->sin_addr.s_addr)); return; } olsr_printf(1, "[ENC]Packet from %s OK size %d\n", olsr_ip_to_string((union olsr_ip_addr *)&((struct sockaddr_in *)&from)->sin_addr.s_addr), cc); /* Fix OLSR packet header */ inbuf.olsr.olsr_packlen = htons(cc); //olsr_printf(1, "Recieved a packet from %s\n", olsr_ip_to_string((union olsr_ip_addr *)&((struct sockaddr_in *)&from)->sin_addr.s_addr)); //printf("\nCC: %d FROMLEN: %d\n\n", cc, fromlen); if ((olsr_cnf->ip_version == AF_INET) && (fromlen != sizeof (struct sockaddr_in))) break; else if ((olsr_cnf->ip_version == AF_INET6) && (fromlen != sizeof (struct sockaddr_in6))) break; /* * &from - sender * &inbuf.olsr * cc - bytes read */ parse_packet(&inbuf.olsr, cc, olsr_in_if, &from_addr); } } /** * Check a incoming OLSR packet for * challenge/responses. * They need not be verified as they * are signed in the message. * */ static int check_auth(char *pck, int *size __attribute__((unused))) { olsr_printf(3, "[ENC]Checking packet for challenge response message...\n"); switch(pck[4]) { case(TYPE_CHALLENGE): parse_challenge(&pck[4]); break; case(TYPE_CRESPONSE): parse_cres(&pck[4]); break; case(TYPE_RRESPONSE): parse_rres(&pck[4]); break; default: return 0; } return 1; } /** * Packet transform function * Build a SHA-1/MD5 hash of the original message * + the signature message(-digest) + key * * Then add the signature message to the packet and * increase the size */ int add_signature(olsr_u8_t *pck, int *size) { struct s_olsrmsg *msg; #ifdef DEBUG int i, j; char *sigmsg; #endif olsr_printf(2, "[ENC]Adding signature for packet size %d\n", *size); fflush(stdout); msg = (struct s_olsrmsg *)&pck[*size]; /* Update size */ ((struct olsr*)pck)->olsr_packlen = htons(*size + sizeof(struct s_olsrmsg)); /* Fill packet header */ msg->olsr_msgtype = MESSAGE_TYPE; msg->olsr_vtime = 0; msg->olsr_msgsize = htons(sizeof(struct s_olsrmsg)); memcpy(&msg->originator, &olsr_cnf->main_addr, olsr_cnf->ipsize); msg->ttl = 1; msg->hopcnt = 0; msg->seqno = htons(get_msg_seqno()); /* Fill subheader */ msg->sig.type = ONE_CHECKSUM; msg->sig.algorithm = SCHEME; memset(&msg->sig.reserved, 0, 2); /* Add timestamp */ msg->sig.timestamp = htonl(now.tv_sec); olsr_printf(3, "[ENC]timestamp: %ld\n", now.tv_sec); /* Set the new size */ *size = *size + sizeof(struct s_olsrmsg); { olsr_u8_t checksum_cache[512 + KEYLENGTH]; /* Create packet + key cache */ /* First the OLSR packet + signature message - digest */ memcpy(checksum_cache, pck, *size - SIGNATURE_SIZE); /* Then the key */ memcpy(&checksum_cache[*size - SIGNATURE_SIZE], aes_key, KEYLENGTH); /* Create the hash */ CHECKSUM(checksum_cache, (*size - SIGNATURE_SIZE) + KEYLENGTH, &pck[*size - SIGNATURE_SIZE]); } #ifdef DEBUG olsr_printf(1, "Signature message:\n"); j = 0; sigmsg = (char *)msg; for(i = 0; i < sizeof(struct s_olsrmsg); i++) { olsr_printf(1, " %3i", (u_char) sigmsg[i]); j++; if(j == 4) { olsr_printf(1, "\n"); j = 0; } } #endif olsr_printf(3, "[ENC] Message signed\n"); return 1; } int validate_packet(char *pck, int *size) { int packetsize; olsr_u8_t sha1_hash[SIGNATURE_SIZE]; struct s_olsrmsg *sig; time_t rec_time; #ifdef DEBUG int i, j; char *sigmsg; #endif /* Find size - signature message */ packetsize = *size - sizeof(struct s_olsrmsg); if(packetsize < 4) return 0; sig = (struct s_olsrmsg *)&pck[packetsize]; //olsr_printf(1, "Size: %d\n", packetsize); #ifdef DEBUG olsr_printf(1, "Input message:\n"); j = 0; sigmsg = (char *)sig; for(i = 0; i < sizeof(struct s_olsrmsg); i++) { olsr_printf(1, " %3i", (u_char) sigmsg[i]); j++; if(j == 4) { olsr_printf(1, "\n"); j = 0; } } #endif /* Sanity check first */ if((sig->olsr_msgtype != MESSAGE_TYPE) || (sig->olsr_vtime) || (sig->olsr_msgsize != ntohs(sizeof(struct s_olsrmsg))) || (sig->ttl != 1) || (sig->hopcnt != 0)) { olsr_printf(1, "[ENC]Packet not sane!\n"); return 0; } /* Check scheme and type */ switch(sig->sig.type) { case(ONE_CHECKSUM): switch(sig->sig.algorithm) { case(SCHEME): goto one_checksum_SHA; /* Ahhh... fix this */ break; } break; default: olsr_printf(1, "[ENC]Unsupported sceme: %d enc: %d!\n", sig->sig.type, sig->sig.algorithm); return 0; break; } //olsr_printf(1, "Packet sane...\n"); one_checksum_SHA: { olsr_u8_t checksum_cache[512 + KEYLENGTH]; /* Create packet + key cache */ /* First the OLSR packet + signature message - digest */ memcpy(checksum_cache, pck, *size - SIGNATURE_SIZE); /* Then the key */ memcpy(&checksum_cache[*size - SIGNATURE_SIZE], aes_key, KEYLENGTH); /* generate SHA-1 */ CHECKSUM(checksum_cache, *size - SIGNATURE_SIZE + KEYLENGTH, sha1_hash); } #ifdef DEBUG olsr_printf(1, "Recevied hash:\n"); sigmsg = (char *)sig->sig.signature; for(i = 0; i < SIGNATURE_SIZE; i++) { olsr_printf(1, " %3i", (u_char) sigmsg[i]); } olsr_printf(1, "\n"); olsr_printf(1, "Calculated hash:\n"); sigmsg = sha1_hash; for(i = 0; i < SIGNATURE_SIZE; i++) { olsr_printf(1, " %3i", (u_char) sigmsg[i]); } olsr_printf(1, "\n"); #endif if(memcmp(sha1_hash, sig->sig.signature, SIGNATURE_SIZE) != 0) { olsr_printf(1, "[ENC]Signature missmatch\n"); return 0; } /* Check timestamp */ rec_time = ntohl(sig->sig.timestamp); if(!check_timestamp((union olsr_ip_addr *)&sig->originator, rec_time)) { olsr_printf(1, "[ENC]Timestamp missmatch in packet from %s!\n", olsr_ip_to_string((union olsr_ip_addr *)&sig->originator)); return 0; } olsr_printf(1, "[ENC]Received timestamp %ld diff: %ld\n", rec_time, now.tv_sec - rec_time); /* Remove signature message */ *size = packetsize; return 1; } int check_timestamp(union olsr_ip_addr *originator, time_t tstamp) { struct stamp *entry; int diff; entry = lookup_timestamp_entry(originator); if(!entry) { /* Initiate timestamp negotiation */ send_challenge(originator); return 0; } if(!entry->validated) { olsr_printf(1, "[ENC]Message from non-validated host!\n"); return 0; } diff = entry->diff - (now.tv_sec - tstamp); olsr_printf(3, "[ENC]Timestamp slack: %d\n", diff); if((diff > UPPER_DIFF) || (diff < LOWER_DIFF)) { olsr_printf(1, "[ENC]Timestamp scew detected!!\n"); return 0; } /* ok - update diff */ entry->diff = ((now.tv_sec - tstamp) + entry->diff) ? ((now.tv_sec - tstamp) + entry->diff) / 2 : 0; olsr_printf(3, "[ENC]Diff set to : %d\n", entry->diff); /* update validtime */ entry->valtime = GET_TIMESTAMP(TIMESTAMP_HOLD_TIME * 1000); return 1; } /** * Create and send a timestamp * challenge message to new_host * * The host is registered in the timestamps * repository with valid=0 */ int send_challenge(union olsr_ip_addr *new_host) { struct challengemsg cmsg; struct stamp *entry; olsr_u32_t challenge, hash; olsr_printf(1, "[ENC]Building CHALLENGE message\n"); /* Set the size including OLSR packet size */ challenge = rand() << 16; challenge |= rand(); /* Fill challengemessage */ cmsg.olsr_msgtype = TYPE_CHALLENGE; cmsg.olsr_vtime = 0; cmsg.olsr_msgsize = htons(sizeof(struct challengemsg)); memcpy(&cmsg.originator, &olsr_cnf->main_addr, olsr_cnf->ipsize); cmsg.ttl = 1; cmsg.hopcnt = 0; cmsg.seqno = htons(get_msg_seqno()); /* Fill subheader */ memcpy(&cmsg.destination, new_host, olsr_cnf->ipsize); cmsg.challenge = htonl(challenge); olsr_printf(3, "[ENC]Size: %lu\n", (unsigned long)sizeof(struct challengemsg)); { olsr_u8_t checksum_cache[512 + KEYLENGTH]; /* Create packet + key cache */ /* First the OLSR packet + signature message - digest */ memcpy(checksum_cache, &cmsg, sizeof(struct challengemsg) - SIGNATURE_SIZE); /* Then the key */ memcpy(&checksum_cache[sizeof(struct challengemsg) - SIGNATURE_SIZE], aes_key, KEYLENGTH); /* Create the hash */ CHECKSUM(checksum_cache, (sizeof(struct challengemsg) - SIGNATURE_SIZE) + KEYLENGTH, cmsg.signature); } olsr_printf(3, "[ENC]Sending timestamp request to %s challenge 0x%x\n", olsr_ip_to_string(new_host), challenge); /* Add to buffer */ net_outbuffer_push(olsr_in_if, &cmsg, sizeof(struct challengemsg)); /* Send the request */ net_output(olsr_in_if); /* Create new entry */ entry = malloc(sizeof(struct stamp)); entry->diff = 0; entry->validated = 0; entry->challenge = challenge; memcpy(&entry->addr, new_host, olsr_cnf->ipsize); /* update validtime - not validated */ entry->conftime = GET_TIMESTAMP(EXCHANGE_HOLD_TIME * 1000); hash = olsr_hashing(new_host); /* Queue */ timestamps[hash].next->prev = entry; entry->next = timestamps[hash].next; timestamps[hash].next = entry; entry->prev = ×tamps[hash]; return 1; } int parse_cres(char *in_msg) { struct c_respmsg *msg; olsr_u8_t sha1_hash[SIGNATURE_SIZE]; struct stamp *entry; msg = (struct c_respmsg *)in_msg; olsr_printf(1, "[ENC]Challenge-response message received\n"); olsr_printf(3, "[ENC]To: %s\n", olsr_ip_to_string((union olsr_ip_addr *)&msg->destination)); if(if_ifwithaddr((union olsr_ip_addr *)&msg->destination) == NULL) { olsr_printf(3, "[ENC]Not for us...\n"); return 0; } olsr_printf(3, "[ENC]Challenge: 0x%lx\n", (unsigned long)ntohl(msg->challenge)); /* ntohl() returns a unsignedlong onwin32 */ /* Check signature */ { olsr_u8_t checksum_cache[512 + KEYLENGTH]; /* Create packet + key cache */ /* First the OLSR packet + signature message - digest */ memcpy(checksum_cache, msg, sizeof(struct c_respmsg) - SIGNATURE_SIZE); /* Then the key */ memcpy(&checksum_cache[sizeof(struct c_respmsg) - SIGNATURE_SIZE], aes_key, KEYLENGTH); /* Create the hash */ CHECKSUM(checksum_cache, (sizeof(struct c_respmsg) - SIGNATURE_SIZE) + KEYLENGTH, sha1_hash); } if(memcmp(sha1_hash, &msg->signature, SIGNATURE_SIZE) != 0) { olsr_printf(1, "[ENC]Signature missmatch in challenge-response!\n"); return 0; } olsr_printf(3, "[ENC]Signature verified\n"); /* Now to check the digest from the emitted challenge */ if((entry = lookup_timestamp_entry((union olsr_ip_addr *)&msg->originator)) == NULL) { olsr_printf(1, "[ENC]Received challenge-response from non-registered node %s!\n", olsr_ip_to_string((union olsr_ip_addr *)&msg->originator)); return 0; } /* Generate the digest */ olsr_printf(3, "[ENC]Entry-challenge 0x%x\n", entry->challenge); { olsr_u8_t checksum_cache[512 + KEYLENGTH]; /* First the challenge received */ memcpy(checksum_cache, &entry->challenge, 4); /* Then the local IP */ memcpy(&checksum_cache[sizeof(olsr_u32_t)], &msg->originator, olsr_cnf->ipsize); /* Create the hash */ CHECKSUM(checksum_cache, sizeof(olsr_u32_t) + olsr_cnf->ipsize, sha1_hash); } if(memcmp(msg->res_sig, sha1_hash, SIGNATURE_SIZE) != 0) { olsr_printf(1, "[ENC]Error in challenge signature from %s!\n", olsr_ip_to_string((union olsr_ip_addr *)&msg->originator)); return 0; } olsr_printf(3, "[ENC]Challenge-response signature ok\n"); /* Update entry! */ entry->challenge = 0; entry->validated = 1; entry->diff = now.tv_sec - msg->timestamp; /* update validtime - validated entry */ entry->valtime = GET_TIMESTAMP(TIMESTAMP_HOLD_TIME * 1000); olsr_printf(1, "[ENC]%s registered with diff %d!\n", olsr_ip_to_string((union olsr_ip_addr *)&msg->originator), entry->diff); /* Send response-response */ send_rres((union olsr_ip_addr *)&msg->originator, (union olsr_ip_addr *)&msg->destination, ntohl(msg->challenge)); return 1; } int parse_rres(char *in_msg) { struct r_respmsg *msg; olsr_u8_t sha1_hash[SIGNATURE_SIZE]; struct stamp *entry; msg = (struct r_respmsg *)in_msg; olsr_printf(1, "[ENC]Response-response message received\n"); olsr_printf(3, "[ENC]To: %s\n", olsr_ip_to_string((union olsr_ip_addr *)&msg->destination)); if(if_ifwithaddr((union olsr_ip_addr *)&msg->destination) == NULL) { olsr_printf(1, "[ENC]Not for us...\n"); return 0; } /* Check signature */ { olsr_u8_t checksum_cache[512 + KEYLENGTH]; /* Create packet + key cache */ /* First the OLSR packet + signature message - digest */ memcpy(checksum_cache, msg, sizeof(struct r_respmsg) - SIGNATURE_SIZE); /* Then the key */ memcpy(&checksum_cache[sizeof(struct r_respmsg) - SIGNATURE_SIZE], aes_key, KEYLENGTH); /* Create the hash */ CHECKSUM(checksum_cache, (sizeof(struct r_respmsg) - SIGNATURE_SIZE) + KEYLENGTH, sha1_hash); } if(memcmp(sha1_hash, &msg->signature, SIGNATURE_SIZE) != 0) { olsr_printf(1, "[ENC]Signature missmatch in response-response!\n"); return 0; } olsr_printf(3, "[ENC]Signature verified\n"); /* Now to check the digest from the emitted challenge */ if((entry = lookup_timestamp_entry((union olsr_ip_addr *)&msg->originator)) == NULL) { olsr_printf(1, "[ENC]Received response-response from non-registered node %s!\n", olsr_ip_to_string((union olsr_ip_addr *)&msg->originator)); return 0; } /* Generate the digest */ olsr_printf(3, "[ENC]Entry-challenge 0x%x\n", entry->challenge); { olsr_u8_t checksum_cache[512 + KEYLENGTH]; /* First the challenge received */ memcpy(checksum_cache, &entry->challenge, 4); /* Then the local IP */ memcpy(&checksum_cache[sizeof(olsr_u32_t)], &msg->originator, olsr_cnf->ipsize); /* Create the hash */ CHECKSUM(checksum_cache, sizeof(olsr_u32_t) + olsr_cnf->ipsize, sha1_hash); } if(memcmp(msg->res_sig, sha1_hash, SIGNATURE_SIZE) != 0) { olsr_printf(1, "[ENC]Error in response signature from %s!\n", olsr_ip_to_string((union olsr_ip_addr *)&msg->originator)); return 0; } olsr_printf(3, "[ENC]Challenge-response signature ok\n"); /* Update entry! */ entry->challenge = 0; entry->validated = 1; entry->diff = now.tv_sec - msg->timestamp; /* update validtime - validated entry */ entry->valtime = GET_TIMESTAMP(TIMESTAMP_HOLD_TIME * 1000); olsr_printf(1, "[ENC]%s registered with diff %d!\n", olsr_ip_to_string((union olsr_ip_addr *)&msg->originator), entry->diff); return 1; } int parse_challenge(char *in_msg) { struct challengemsg *msg; olsr_u8_t sha1_hash[SIGNATURE_SIZE]; struct stamp *entry; olsr_u32_t hash; msg = (struct challengemsg *)in_msg; olsr_printf(1, "[ENC]Challenge message received\n"); olsr_printf(3, "[ENC]To: %s\n", olsr_ip_to_string((union olsr_ip_addr *)&msg->destination)); if(if_ifwithaddr((union olsr_ip_addr *)&msg->destination) == NULL) { olsr_printf(1, "[ENC]Not for us...\n"); return 0; } /* Create entry if not registered */ if((entry = lookup_timestamp_entry((union olsr_ip_addr *)&msg->originator)) == NULL) { entry = malloc(sizeof(struct stamp)); memcpy(&entry->addr, &msg->originator, olsr_cnf->ipsize); hash = olsr_hashing((union olsr_ip_addr *)&msg->originator); /* Queue */ timestamps[hash].next->prev = entry; entry->next = timestamps[hash].next; timestamps[hash].next = entry; entry->prev = ×tamps[hash]; } else { /* Check configuration timeout */ if(!TIMED_OUT(entry->conftime)) { /* If registered - do not accept! */ olsr_printf(1, "[ENC]Challenge from registered node...dropping!\n"); return 0; } else { olsr_printf(1, "[ENC]Challenge from registered node...accepted!\n"); } } olsr_printf(3, "[ENC]Challenge: 0x%lx\n", (unsigned long)ntohl(msg->challenge)); /* ntohl() returns a unsignedlong onwin32 */ /* Check signature */ { olsr_u8_t checksum_cache[512 + KEYLENGTH]; /* Create packet + key cache */ /* First the OLSR packet + signature message - digest */ memcpy(checksum_cache, msg, sizeof(struct challengemsg) - SIGNATURE_SIZE); /* Then the key */ memcpy(&checksum_cache[sizeof(struct challengemsg) - SIGNATURE_SIZE], aes_key, KEYLENGTH); /* Create the hash */ CHECKSUM(checksum_cache, (sizeof(struct challengemsg) - SIGNATURE_SIZE) + KEYLENGTH, sha1_hash); } if(memcmp(sha1_hash, &msg->signature, SIGNATURE_SIZE) != 0) { olsr_printf(1, "[ENC]Signature missmatch in challenge!\n"); return 0; } olsr_printf(3, "[ENC]Signature verified\n"); entry->diff = 0; entry->validated = 0; /* update validtime - not validated */ entry->conftime = GET_TIMESTAMP(EXCHANGE_HOLD_TIME * 1000); /* Build and send response */ send_cres((union olsr_ip_addr *)&msg->originator, (union olsr_ip_addr *)&msg->destination, ntohl(msg->challenge), entry); return 1; } /** * Build and transmit a challenge response * message. * */ int send_cres(union olsr_ip_addr *to, union olsr_ip_addr *from, olsr_u32_t chal_in, struct stamp *entry) { struct c_respmsg crmsg; olsr_u32_t challenge; olsr_printf(1, "[ENC]Building CRESPONSE message\n"); challenge = rand() << 16; challenge |= rand(); entry->challenge = challenge; olsr_printf(3, "[ENC]Challenge-response: 0x%x\n", challenge); /* Fill challengemessage */ crmsg.olsr_msgtype = TYPE_CRESPONSE; crmsg.olsr_vtime = 0; crmsg.olsr_msgsize = htons(sizeof(struct c_respmsg)); memcpy(&crmsg.originator, &olsr_cnf->main_addr, olsr_cnf->ipsize); crmsg.ttl = 1; crmsg.hopcnt = 0; crmsg.seqno = htons(get_msg_seqno()); /* set timestamp */ crmsg.timestamp = now.tv_sec; olsr_printf(3, "[ENC]Timestamp %ld\n", crmsg.timestamp); /* Fill subheader */ memcpy(&crmsg.destination, to, olsr_cnf->ipsize); crmsg.challenge = htonl(challenge); /* Create digest of received challenge + IP */ { olsr_u8_t checksum_cache[512 + KEYLENGTH]; /* Create packet + key cache */ /* First the challenge received */ memcpy(checksum_cache, &chal_in, 4); /* Then the local IP */ memcpy(&checksum_cache[sizeof(olsr_u32_t)], from, olsr_cnf->ipsize); /* Create the hash */ CHECKSUM(checksum_cache, sizeof(olsr_u32_t) + olsr_cnf->ipsize, crmsg.res_sig); } /* Now create the digest of the message and the key */ { olsr_u8_t checksum_cache[512 + KEYLENGTH]; /* Create packet + key cache */ /* First the OLSR packet + signature message - digest */ memcpy(checksum_cache, &crmsg, sizeof(struct c_respmsg) - SIGNATURE_SIZE); /* Then the key */ memcpy(&checksum_cache[sizeof(struct c_respmsg) - SIGNATURE_SIZE], aes_key, KEYLENGTH); /* Create the hash */ CHECKSUM(checksum_cache, (sizeof(struct c_respmsg) - SIGNATURE_SIZE) + KEYLENGTH, crmsg.signature); } olsr_printf(3, "[ENC]Sending challenge response to %s challenge 0x%x\n", olsr_ip_to_string(to), challenge); /* Add to buffer */ net_outbuffer_push(olsr_in_if, &crmsg, sizeof(struct c_respmsg)); /* Send the request */ net_output(olsr_in_if); return 1; } /** * Build and transmit a response response * message. * */ static int send_rres(union olsr_ip_addr *to, union olsr_ip_addr *from, olsr_u32_t chal_in) { struct r_respmsg rrmsg; olsr_printf(1, "[ENC]Building RRESPONSE message\n"); /* Fill challengemessage */ rrmsg.olsr_msgtype = TYPE_RRESPONSE; rrmsg.olsr_vtime = 0; rrmsg.olsr_msgsize = htons(sizeof(struct r_respmsg)); memcpy(&rrmsg.originator, &olsr_cnf->main_addr, olsr_cnf->ipsize); rrmsg.ttl = 1; rrmsg.hopcnt = 0; rrmsg.seqno = htons(get_msg_seqno()); /* set timestamp */ rrmsg.timestamp = now.tv_sec; olsr_printf(3, "[ENC]Timestamp %ld\n", rrmsg.timestamp); /* Fill subheader */ memcpy(&rrmsg.destination, to, olsr_cnf->ipsize); /* Create digest of received challenge + IP */ { olsr_u8_t checksum_cache[512 + KEYLENGTH]; /* Create packet + key cache */ /* First the challenge received */ memcpy(checksum_cache, &chal_in, 4); /* Then the local IP */ memcpy(&checksum_cache[sizeof(olsr_u32_t)], from, olsr_cnf->ipsize); /* Create the hash */ CHECKSUM(checksum_cache, sizeof(olsr_u32_t) + olsr_cnf->ipsize, rrmsg.res_sig); } /* Now create the digest of the message and the key */ { olsr_u8_t checksum_cache[512 + KEYLENGTH]; /* Create packet + key cache */ /* First the OLSR packet + signature message - digest */ memcpy(checksum_cache, &rrmsg, sizeof(struct r_respmsg) - SIGNATURE_SIZE); /* Then the key */ memcpy(&checksum_cache[sizeof(struct r_respmsg) - SIGNATURE_SIZE], aes_key, KEYLENGTH); /* Create the hash */ CHECKSUM(checksum_cache, (sizeof(struct r_respmsg) - SIGNATURE_SIZE) + KEYLENGTH, rrmsg.signature); } olsr_printf(3, "[ENC]Sending response response to %s\n", olsr_ip_to_string(to)); /* add to buffer */ net_outbuffer_push(olsr_in_if, &rrmsg, sizeof(struct r_respmsg)); /* Send the request */ net_output(olsr_in_if); return 1; } static struct stamp * lookup_timestamp_entry(union olsr_ip_addr *adr) { olsr_u32_t hash; struct stamp *entry; hash = olsr_hashing(adr); for(entry = timestamps[hash].next; entry != ×tamps[hash]; entry = entry->next) { if(memcmp(&entry->addr, adr, olsr_cnf->ipsize) == 0) { olsr_printf(3, "[ENC]Match for %s\n", olsr_ip_to_string(adr)); return entry; } } olsr_printf(1, "[ENC]No match for %s\n", olsr_ip_to_string(adr)); return NULL; } /** *Find timed out entries and delete them * *@return nada */ void timeout_timestamps(void* foo __attribute__((unused))) { struct stamp *tmp_list; struct stamp *entry_to_delete; int index; for(index=0;indexvaltime)) && (TIMED_OUT(tmp_list->conftime))) { entry_to_delete = tmp_list; tmp_list = tmp_list->next; olsr_printf(1, "[ENC]timestamp info for %s timed out.. deleting it\n", olsr_ip_to_string(&entry_to_delete->addr)); /*Delete it*/ entry_to_delete->next->prev = entry_to_delete->prev; entry_to_delete->prev->next = entry_to_delete->next; free(entry_to_delete); } else tmp_list = tmp_list->next; } } return; } static int read_key_from_file(char *file) { FILE *kf; size_t keylen; keylen = 16; kf = fopen(file, "r"); olsr_printf(1, "[ENC]Reading key from file \"%s\"\n", file); if(kf == NULL) { olsr_printf(1, "[ENC]Could not open keyfile %s!\nError: %s\n", file, strerror(errno)); return -1; } if(fread(aes_key, 1, keylen, kf) != keylen) { olsr_printf(1, "[ENC]Could not read key from keyfile %s!\nError: %s\n", file, strerror(errno)); fclose(kf); return 0; } fclose(kf); return 1; }