From df8bacead583ee57f3d22140591527f07dfa550b Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Sat, 17 Oct 2015 02:10:35 +0200 Subject: [PATCH] Implement a key exchange mechanism --- README.md | 11 +- auth.c | 718 +++++++++++++++++++++++++++----------------------- auth.h | 6 +- cfg_file.y | 6 +- lfd_encrypt.c | 32 +-- lib.c | 4 +- server.c | 3 + vtun.h | 5 +- 8 files changed, 422 insertions(+), 363 deletions(-) diff --git a/README.md b/README.md index 8d7e000..cb14e66 100644 --- a/README.md +++ b/README.md @@ -8,10 +8,11 @@ compiled until version 1.0.4 is out). * Unauthenticated encryption schemes were replaced with aesni and pclmulqdq-accelerated AES256-GCM. +* The static, shared key was replaced by an ephemeral keys exchange with +Curve25519. The PSK is now only used to sign ephemeral public keys and +parameters. + * Protection against replay attacks was added. -* More secure key derivation and initial handshake. - -* Passwords are not kept in memory. - -* Guarded memory allocations for secrets. +* Passwords are not kept in memory, guarded memory allocations are +used for secrets. diff --git a/auth.c b/auth.c index 747e99b..02fda52 100644 --- a/auth.c +++ b/auth.c @@ -1,28 +1,23 @@ /* - VTun - Virtual Tunnel over TCP/IP network. - - Copyright (C) 1998-2008 Maxim Krasnyansky - - VTun has been derived from VPPP package by Maxim Krasnyansky. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - */ - -/* - * $Id: auth.c,v 1.9.2.5 2013/07/07 19:54:20 mtbishop Exp $ - */ - -/* - * Challenge based authentication. - * Thanx to Chris Todd for the good idea. + * Key exchange + * + * Client <-> Server + * + * -> "CKEY " || host || " " || ts || Cpk || Hk(ts || Cpk) + * <- "SKEY " || Spk || Hk(Spk || Hk(ts || Cpk)) + * -> "CACK " || Hk("CACK" || Hk(Spk || Hk(ts || Cpk))) + * <- "FLAGS " || flags || " " || Hk(flags || Hk("CACK" || Hk(Spk || Hk(ts || Cpk)))) + * + * session_key = Hk(DH) + * + * ts: current timestamp, 4 big-endian bytes + * (Cpk, Csk): client public/secret ephemeral key pair + * (Spk, Ssk): server public/secret ephemeral key pair + * Hk: keyed hash function, key derived from the PSK + * + * DH function: Curve25519 + * Keyed hash function: Blake2b + * KDF: Scrypt */ #include "config.h" @@ -51,60 +46,38 @@ #include #endif +#include + #include "vtun.h" #include "lib.h" #include "lock.h" #include "auth.h" -/* Encryption and Decryption of the challenge key */ -#include - static int derive_key(struct vtun_host *host) { - unsigned char salt[crypto_pwhash_scryptsalsa208sha256_SALTBYTES]; - int ret = -1; - size_t bin_len; + unsigned char salt[crypto_pwhash_scryptsalsa208sha256_SALTBYTES]; + int ret = -1; + size_t bin_len; - if (host->key != NULL) { - return 0; - } - if ((host->key = sodium_malloc(HOST_KEYBYTES)) == NULL) { - return -1; - } + if (host->akey != NULL) { + return 0; + } + if ((host->akey = sodium_malloc(crypto_generichash_KEYBYTES)) == NULL) { + return -1; + } + memset(salt, 0xd1, sizeof salt); + if (crypto_pwhash_scryptsalsa208sha256(host->akey, HOST_KEYBYTES, + host->passwd, strlen(host->passwd), salt, + crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_INTERACTIVE, + crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_INTERACTIVE) == 0) { + ret = 0; + } + sodium_memzero(host->passwd, strlen(host->passwd)); + free(host->passwd); + host->passwd = NULL; + vtun_syslog(LOG_DEBUG, "Key ready for host [%s]", host->host); - sodium_hex2bin(host->key, HOST_KEYBYTES, host->passwd, - strlen(host->passwd), "", &bin_len, NULL); - if (bin_len == HOST_KEYBYTES) { - vtun_syslog(LOG_ERR,"supplied password is long enough to be the secret"); - return 0; - } - - memset(salt, 0xd1, sizeof salt); - if (crypto_pwhash_scryptsalsa208sha256 - (host->key, HOST_KEYBYTES, host->passwd, strlen(host->passwd), salt, - crypto_pwhash_scryptsalsa208sha256_OPSLIMIT_INTERACTIVE, - crypto_pwhash_scryptsalsa208sha256_MEMLIMIT_INTERACTIVE) == 0) { - ret = 0; - } - - sodium_memzero(host->passwd, strlen(host->passwd)); - free(host->passwd); - host->passwd = NULL; - vtun_syslog(LOG_DEBUG,"Key ready for host %s.", host->host); - - return ret; -} - -static void gen_chal(char *chal) -{ - randombytes_buf((unsigned char *) chal, VTUN_CHAL_SIZE); -} - -static void auth_chal(char *chal, const struct vtun_host *host) -{ - crypto_generichash((unsigned char *) chal, VTUN_CHAL_SIZE, - (const unsigned char *) chal, - VTUN_CHAL_SIZE, host->key, HOST_KEYBYTES); + return ret; } /* @@ -115,296 +88,389 @@ static void auth_chal(char *chal, const struct vtun_host *host) static char *bf2cf(struct vtun_host *host) { - static char str[20], *ptr = str; + static char str[20], * ptr = str; - *(ptr++) = '<'; + *(ptr++) = '<'; - switch( host->flags & VTUN_PROT_MASK ){ - case VTUN_TCP: - *(ptr++) = 'T'; - break; + switch (host->flags & VTUN_PROT_MASK) { + case VTUN_TCP: + *(ptr++) = 'T'; + break; - case VTUN_UDP: - *(ptr++) = 'U'; - break; - } + case VTUN_UDP: + *(ptr++) = 'U'; + break; + } + switch (host->flags & VTUN_TYPE_MASK) { + case VTUN_TTY: + *(ptr++) = 't'; + break; + case VTUN_PIPE: + *(ptr++) = 'p'; + break; + case VTUN_ETHER: + *(ptr++) = 'e'; + break; + case VTUN_TUN: + *(ptr++) = 'u'; + break; + } + if ((host->flags & VTUN_SHAPE) /* && host->spd_in */) + ptr += sprintf(ptr, "S%d", host->spd_in); - switch( host->flags & VTUN_TYPE_MASK ){ - case VTUN_TTY: - *(ptr++) = 't'; - break; + if (host->flags & VTUN_ZLIB) + ptr += sprintf(ptr, "C%d", host->zlevel); - case VTUN_PIPE: - *(ptr++) = 'p'; - break; + if (host->flags & VTUN_LZO) + ptr += sprintf(ptr, "L%d", host->zlevel); - case VTUN_ETHER: - *(ptr++) = 'e'; - break; + if (host->flags & VTUN_KEEP_ALIVE) + *(ptr++) = 'K'; - case VTUN_TUN: - *(ptr++) = 'u'; - break; - } + if (host->flags & VTUN_ENCRYPT) { + ptr += sprintf(ptr, "E%d", host->cipher); + } - if( (host->flags & VTUN_SHAPE) /* && host->spd_in */) - ptr += sprintf(ptr,"S%d",host->spd_in); + strcat(ptr, ">"); - if( host->flags & VTUN_ZLIB ) - ptr += sprintf(ptr,"C%d", host->zlevel); - - if( host->flags & VTUN_LZO ) - ptr += sprintf(ptr,"L%d", host->zlevel); - - if( host->flags & VTUN_KEEP_ALIVE ) - *(ptr++) = 'K'; - - if( host->flags & VTUN_ENCRYPT ) { - ptr += sprintf(ptr,"E%d", host->cipher); - } - - strcat(ptr,">"); - - return str; -} - -/* return 1 on success, otherwise 0 - Example: - FLAGS: -*/ - -static int cf2bf(char *str, struct vtun_host *host) -{ - char *ptr, *p; - int s; - - if( (ptr = strchr(str,'<')) ){ - vtun_syslog(LOG_DEBUG,"Remote Server sends %s.", ptr); - ptr++; - while(*ptr){ - switch(*ptr++){ - case 't': - host->flags |= VTUN_TTY; - break; - case 'p': - host->flags |= VTUN_PIPE; - break; - case 'e': - host->flags |= VTUN_ETHER; - break; - case 'u': - host->flags |= VTUN_TUN; - break; - case 'U': - host->flags &= ~VTUN_PROT_MASK; - host->flags |= VTUN_UDP; - break; - case 'T': - host->flags &= ~VTUN_PROT_MASK; - host->flags |= VTUN_TCP; - break; - case 'K': - host->flags |= VTUN_KEEP_ALIVE; - break; - case 'C': - if((s = strtol(ptr,&p,10)) == ERANGE || ptr == p) - return 0; - host->flags |= VTUN_ZLIB; - host->zlevel = s; - ptr = p; - break; - case 'L': - if((s = strtol(ptr,&p,10)) == ERANGE || ptr == p) - return 0; - host->flags |= VTUN_LZO; - host->zlevel = s; - ptr = p; - break; - case 'E': - /* new form is 'E10', old form is 'E', so remove the - ptr==p check */ - if((s = strtol(ptr,&p,10)) == ERANGE) { - vtun_syslog(LOG_ERR,"Garbled encryption method. Bailing out."); - return 0; - } - host->flags |= VTUN_ENCRYPT; - host->cipher = s; - ptr = p; - break; - case 'S': - if((s = strtol(ptr,&p,10)) == ERANGE || ptr == p) - return 0; - if( s ){ - host->flags |= VTUN_SHAPE; - host->spd_out = s; - } - ptr = p; - break; - case 'F': - /* reserved for Feature transmit */ - break; - case '>': - return 1; - default: - return 0; - } - } - } - return 0; + return str; } /* - * Functions to convert binary key data to character string. - * string format: + * return 0 on success, otherwise -1 + * Example: FLAGS: */ - -static char *cl2cs(char *chal) +static int cf2bf(char *str, struct vtun_host *host) { - static char str[VTUN_CHAL_SIZE*2+3], *chr="abcdefghijklmnop"; - register char *ptr = str; - register int i; + char *ptr, *p; + int s; - *(ptr++) = '<'; - for(i=0; i> 4) ]; - *(ptr++) = chr[ (chal[i] & 0x0f) ]; - } - - *(ptr++) = '>'; - *ptr = '\0'; - - return str; -} - -static int cs2cl(char *str, char *chal) -{ - register char *ptr = str; - register int i; - - if( !(ptr = strchr(str,'<')) ) - return 0; - ptr++; - if( !strtok(ptr,">") || strlen(ptr) != VTUN_CHAL_SIZE*2 ) - return 0; - - for(i=0; i= 20) { + return -1; + } + if ((ptr = strchr(str, '<'))) { + vtun_syslog(LOG_DEBUG, "Remote Server sends %s.", ptr); + ptr++; + while (*ptr) { + switch (*ptr++) { + case 't': + host->flags |= VTUN_TTY; + break; + case 'p': + host->flags |= VTUN_PIPE; + break; + case 'e': + host->flags |= VTUN_ETHER; + break; + case 'u': + host->flags |= VTUN_TUN; + break; + case 'U': + host->flags &= ~VTUN_PROT_MASK; + host->flags |= VTUN_UDP; + break; + case 'T': + host->flags &= ~VTUN_PROT_MASK; + host->flags |= VTUN_TCP; + break; + case 'K': + host->flags |= VTUN_KEEP_ALIVE; + break; + case 'C': + if ((s = strtol(ptr, &p, 10)) == ERANGE || ptr == p) { + return -1; + } + host->flags |= VTUN_ZLIB; + host->zlevel = s; + ptr = p; + break; + case 'L': + if ((s = strtol(ptr, &p, 10)) == ERANGE || ptr == p) { + return -1; + } + host->flags |= VTUN_LZO; + host->zlevel = s; + ptr = p; + break; + case 'E': + /* new form is 'E10', old form is 'E', so remove the + ptr==p check */ + if ((s = strtol(ptr, &p, 10)) == ERANGE) { + vtun_syslog(LOG_ERR, "Garbled encryption method. Bailing out."); + return -1; + } + host->flags |= VTUN_ENCRYPT; + host->cipher = s; + ptr = p; + break; + case 'S': + if ((s = strtol(ptr, &p, 10)) == ERANGE || ptr == p) { + return -1; + } + if (s > 0) { + host->flags |= VTUN_SHAPE; + host->spd_out = s; + } + ptr = p; + break; + case 'F': + /* reserved for Feature transmit */ + break; + case '>': + return 0; + default: + return -1; + } + } + } + return -1; } /* Authentication (Server side) */ -struct vtun_host * auth_server(int fd) +struct vtun_host *auth_server(int fd) { - char chal_req[VTUN_CHAL_SIZE], chal_res[VTUN_CHAL_SIZE]; - char buf[VTUN_MESG_SIZE], *str1, *str2; - struct vtun_host *h = NULL; - char *host = NULL; - int stage; + char buf[VTUN_MESG_SIZE], *str1, *str2, *str3; + unsigned char cack[crypto_generichash_BYTES]; + unsigned char client_pk[crypto_scalarmult_BYTES]; + unsigned char server_pk[crypto_scalarmult_BYTES]; + unsigned char server_sk[crypto_scalarmult_SCALARBYTES]; + unsigned char ckey[4 + crypto_scalarmult_BYTES + crypto_generichash_BYTES]; + unsigned char dhkey[crypto_scalarmult_BYTES]; + unsigned char skey[crypto_scalarmult_BYTES + crypto_generichash_BYTES]; + char skey_hex[2 * (crypto_scalarmult_BYTES + crypto_generichash_BYTES) + 1]; + unsigned char hash[crypto_generichash_BYTES]; + unsigned char flhash[crypto_generichash_BYTES]; + char flhash_hex[2 * crypto_generichash_BYTES + 1]; + struct vtun_host *host = NULL; + char *flags; + char *host_name = NULL; + crypto_generichash_state st; + time_t client_now; + size_t bin_len; + int stage; + int success = 0; - set_title("authentication"); + set_title("authentication"); - print_p(fd,"VTUN server ver %s\n",VTUN_VER); + print_p(fd, "VTUN server ver %s\n", VTUN_VER); - stage = ST_HOST; + stage = ST_STEP2; - while( readn_t(fd, buf, VTUN_MESG_SIZE, vtun.timeout) > 0 ){ - buf[sizeof(buf)-1]='\0'; - strtok(buf,"\r\n"); + while (readn_t(fd, buf, VTUN_MESG_SIZE, vtun.timeout) > 0) { + buf[sizeof(buf) - 1] = '\0'; + strtok(buf, "\r\n"); + if (!(str1 = strtok(buf, " :"))) { + break; + } + if (!(str2 = strtok(NULL, " :"))) { + break; + } + switch (stage) { + case ST_STEP2: + if (!strcmp(str1, "CKEY")) { + if (!(str3 = strtok(NULL, " \t"))) { + break; + } + sodium_hex2bin(ckey, sizeof ckey, str3, strlen(str3), "", &bin_len, NULL); + if (bin_len != sizeof ckey) { + break; + } + client_now = ((time_t) ckey[0]) << 24 | ((time_t) ckey[1]) << 16 | + ((time_t) ckey[2]) << 9 | ((time_t) ckey[3]); + (void) client_now; + host_name = str2; + if ((host = find_host(host_name)) == NULL || derive_key(host) != 0) { + break; + } + crypto_generichash(hash, sizeof hash, + ckey, 4 + crypto_scalarmult_BYTES, + host->akey, crypto_generichash_KEYBYTES); + if (sodium_memcmp(hash, ckey + 4 + crypto_scalarmult_BYTES, sizeof hash) != 0) { + break; + } + memcpy(client_pk, ckey + 4, sizeof client_pk); + randombytes_buf(server_sk, crypto_scalarmult_SCALARBYTES); + crypto_scalarmult_base(server_pk, server_sk); + memcpy(skey, server_pk, sizeof server_pk); + memcpy(skey + crypto_scalarmult_BYTES, hash, sizeof hash); + crypto_generichash(skey + crypto_scalarmult_BYTES, crypto_scalarmult_BYTES, + skey, sizeof skey, + host->akey, crypto_generichash_KEYBYTES); + sodium_bin2hex(skey_hex, sizeof skey_hex, skey, sizeof skey); + print_p(fd, "SKEY: %s\n", skey_hex); + stage = ST_STEP3; + continue; + } + break; - if( !(str1=strtok(buf," :")) ) - break; - if( !(str2=strtok(NULL," :")) ) - break; + case ST_STEP3: + if (!strcmp(str1, "CACK")) { + sodium_hex2bin(cack, sizeof cack, str2, strlen(str2), "", &bin_len, NULL); + if (bin_len != sizeof cack) { + break; + } + crypto_generichash_init(&st, host->akey, crypto_generichash_KEYBYTES, + crypto_generichash_BYTES); + crypto_generichash_update(&st, (const unsigned char *) "CACK", 4); + crypto_generichash_update(&st, skey, sizeof skey); + crypto_generichash_final(&st, hash, sizeof hash); + if (sodium_memcmp(hash, cack, sizeof hash) != 0) { + break; + } + /* Lock host */ + if (lock_host(host) < 0) { + /* Multiple connections are denied */ + host = NULL; + break; + } + flags = bf2cf(host); + crypto_generichash_init(&st, host->akey, crypto_generichash_KEYBYTES, + crypto_generichash_BYTES); + crypto_generichash_update(&st, (const unsigned char *) flags, strlen(flags)); + crypto_generichash_update(&st, cack, sizeof cack); + crypto_generichash_final(&st, flhash, sizeof flhash); + sodium_bin2hex(flhash_hex, sizeof flhash_hex, flhash, sizeof flhash); + print_p(fd, "FLAGS: %s %s\n", flags, flhash_hex); - switch( stage ){ - case ST_HOST: - if( !strcmp(str1,"HOST") ){ - host = strdup(str2); - - gen_chal(chal_req); - print_p(fd,"OK CHAL: %s\n", cl2cs(chal_req)); - - stage = ST_CHAL; - continue; - } - break; - case ST_CHAL: - if( !strcmp(str1,"CHAL") ){ - if( !cs2cl(str2,chal_res) ) - break; - - if( !(h = find_host(host)) ) - break; - derive_key(h); - auth_chal(chal_req, h); - - if( !sodium_memcmp(chal_req, chal_res, VTUN_CHAL_SIZE) ){ - /* Auth successeful. */ - - /* Lock host */ - if( lock_host(h) < 0 ){ - /* Multiple connections are denied */ - h = NULL; - break; - } - print_p(fd,"OK FLAGS: %s\n", bf2cf(h)); - } else - h = NULL; - } - break; - } - break; - } - - if( host ) - free(host); - - if( !h ) - print_p(fd,"ERR\n"); - - return h; + crypto_scalarmult(dhkey, server_sk, client_pk); + sodium_memzero(server_sk, sizeof server_sk); + if ((host->key = sodium_malloc(HOST_KEYBYTES)) == NULL) { + abort(); + } + crypto_generichash(host->key, HOST_KEYBYTES, dhkey, sizeof dhkey, + host->akey, crypto_generichash_KEYBYTES); + sodium_memzero(dhkey, sizeof dhkey); + success = 1; + } + break; + } + break; + } + if (success == 0) { + print_p(fd, "ERR\n"); + host = NULL; + } + return host; } /* Authentication (Client side) */ int auth_client(int fd, struct vtun_host *host) { - char buf[VTUN_MESG_SIZE], chal[VTUN_CHAL_SIZE]; - int stage, success=0 ; + char buf[VTUN_MESG_SIZE], *str1, *str2, *str3; + unsigned char cack[crypto_generichash_BYTES]; + char cack_hex[2 * crypto_generichash_BYTES + 1]; + unsigned char flhash[crypto_generichash_BYTES]; + unsigned char hash[crypto_generichash_BYTES]; + unsigned char client_pk[crypto_scalarmult_BYTES]; + unsigned char client_sk[crypto_scalarmult_SCALARBYTES]; + unsigned char server_pk[crypto_scalarmult_BYTES]; + unsigned char dhkey[crypto_scalarmult_BYTES]; + unsigned char ckey[4 + crypto_scalarmult_BYTES + crypto_generichash_BYTES]; + char ckey_hex[2 * (4 + crypto_scalarmult_BYTES + crypto_generichash_BYTES) + 1]; + unsigned char skey[crypto_scalarmult_BYTES + crypto_generichash_BYTES]; + crypto_generichash_state st; + time_t now; + size_t bin_len; + int stage; + int success = 0; - stage = ST_INIT; + stage = ST_INIT; - while( readn_t(fd, buf, VTUN_MESG_SIZE, vtun.timeout) > 0 ){ - buf[sizeof(buf)-1]='\0'; - switch( stage ){ - case ST_INIT: - if( !strncmp(buf,"VTUN",4) ){ - stage = ST_HOST; - print_p(fd,"HOST: %s\n",host->host); - continue; - } - break; + if (derive_key(host) != 0) { + return 0; + } + while (readn_t(fd, buf, VTUN_MESG_SIZE, vtun.timeout) > 0) { + buf[sizeof(buf) - 1] = '\0'; + strtok(buf, "\r\n"); + if (!(str1 = strtok(buf, " :"))) { + break; + } + if (!(str2 = strtok(NULL, " :"))) { + break; + } + switch (stage) { + case ST_INIT: + if (!strcmp(str1, "VTUN")) { + now = time(NULL); + randombytes_buf(client_sk, crypto_scalarmult_SCALARBYTES); + crypto_scalarmult_base(client_pk, client_sk); + ckey[0] = (unsigned char)(now >> 24); + ckey[1] = (unsigned char)(now >> 16); + ckey[2] = (unsigned char)(now >> 8); + ckey[3] = (unsigned char)(now); + memcpy(ckey + 4, client_pk, crypto_scalarmult_BYTES); + crypto_generichash(ckey + 4 + crypto_scalarmult_BYTES, crypto_generichash_BYTES, + ckey, 4 + crypto_scalarmult_BYTES, + host->akey, crypto_generichash_KEYBYTES); + sodium_bin2hex(ckey_hex, sizeof ckey_hex, ckey, sizeof ckey); + stage = ST_STEP2; + print_p(fd, "CKEY: %s %s\n", host->host, ckey_hex); + continue; + } + break; - case ST_HOST: - if( !strncmp(buf,"OK",2) && cs2cl(buf,chal)){ - stage = ST_CHAL; - derive_key(host); - auth_chal(chal, host); - print_p(fd,"CHAL: %s\n", cl2cs(chal)); + case ST_STEP2: + if (!strcmp(str1, "SKEY")) { + sodium_hex2bin(skey, sizeof skey, str2, strlen(str2), "", &bin_len, NULL); + if (bin_len != sizeof skey) { + break; + } + crypto_generichash_init(&st, host->akey, crypto_generichash_KEYBYTES, + crypto_generichash_BYTES); + crypto_generichash_update(&st, skey, crypto_scalarmult_BYTES); + crypto_generichash_update(&st, ckey + 4 + crypto_scalarmult_BYTES, + crypto_generichash_BYTES); + crypto_generichash_final(&st, hash, sizeof hash); + if (sodium_memcmp(hash, skey + crypto_scalarmult_BYTES, sizeof hash) != 0) { + break; + } + memcpy(server_pk, skey, sizeof server_pk); + crypto_generichash_init(&st, host->akey, crypto_generichash_KEYBYTES, + crypto_generichash_BYTES); + crypto_generichash_update(&st, (const unsigned char *) "CACK", 4); + crypto_generichash_update(&st, skey, sizeof skey); + crypto_generichash_final(&st, cack, sizeof cack); + sodium_bin2hex(cack_hex, sizeof cack_hex, cack, sizeof cack); + print_p(fd, "CACK: %s\n", cack_hex); + stage = ST_STEP3; + continue; + } + break; - continue; - } - break; + case ST_STEP3: + if (!strcmp(str1, "FLAGS")) { + if (!(str3 = strtok(NULL, " \t"))) { + break; + } + sodium_hex2bin(flhash, sizeof flhash, str3, strlen(str3), "", &bin_len, NULL); + if (bin_len != sizeof flhash) { + break; + } + if (cf2bf(str2, host) != 0) { + break; + } + crypto_generichash_init(&st, host->akey, crypto_generichash_KEYBYTES, + crypto_generichash_BYTES); + crypto_generichash_update(&st, (const unsigned char *) str2, strlen(str2)); + crypto_generichash_update(&st, cack, sizeof cack); + crypto_generichash_final(&st, hash, sizeof hash); + if (sodium_memcmp(hash, flhash, sizeof hash) != 0) { + break; + } + crypto_scalarmult(dhkey, client_sk, server_pk); + sodium_memzero(client_sk, sizeof client_sk); + if ((host->key = sodium_malloc(HOST_KEYBYTES)) == NULL) { + abort(); + } + crypto_generichash(host->key, HOST_KEYBYTES, dhkey, sizeof dhkey, + host->akey, crypto_generichash_KEYBYTES); + sodium_memzero(dhkey, sizeof dhkey); + success = 1; + } + break; + } + break; + } - case ST_CHAL: - if( !strncmp(buf,"OK",2) && cf2bf(buf,host) ) - success = 1; - break; - } - break; - } - - return success; + return success; } diff --git a/auth.h b/auth.h index 113a935..4ff4c5a 100644 --- a/auth.h +++ b/auth.h @@ -20,11 +20,9 @@ * $Id: auth.h,v 1.3.2.2 2008/01/07 22:35:19 mtbishop Exp $ */ -#define VTUN_CHAL_SIZE 16 - #define ST_INIT 0 -#define ST_HOST 1 -#define ST_CHAL 2 +#define ST_STEP2 1 +#define ST_STEP3 2 struct vtun_host * auth_server(int fd); int auth_client(int fd, struct vtun_host *host); diff --git a/cfg_file.y b/cfg_file.y index 8ac1c86..9ce4375 100644 --- a/cfg_file.y +++ b/cfg_file.y @@ -29,6 +29,7 @@ #include #include +#include #include "compat.h" #include "vtun.h" @@ -107,6 +108,7 @@ statement: '\n' memcpy(parse_host, &default_host, sizeof(struct vtun_host)); parse_host->host = strdup($1); parse_host->passwd = NULL; + parse_host->akey = NULL; parse_host->key = NULL; parse_host->sopt.host = strdup($1); @@ -574,7 +576,9 @@ int free_host(void *d, void *u) return 1; free(h->host); - free(h->passwd); + free(h->passwd); + sodium_free(h->akey); + sodium_free(h->key); llist_free(&h->up, free_cmd, NULL); llist_free(&h->down, free_cmd, NULL); diff --git a/lfd_encrypt.c b/lfd_encrypt.c index b4baab9..4ff90b5 100644 --- a/lfd_encrypt.c +++ b/lfd_encrypt.c @@ -35,16 +35,6 @@ typedef struct CryptoCtx { static CryptoCtx ctx; -static int -derive_key(unsigned char *key, size_t key_size, struct vtun_host *host) -{ - crypto_generichash(key, key_size, host->key, HOST_KEYBYTES, NULL, 0U); - sodium_free(host->key); - host->key = NULL; - - return 0; -} - static int init_nonce(unsigned char *nonce, size_t nonce_size) { @@ -69,18 +59,12 @@ init_nonce(unsigned char *nonce, size_t nonce_size) static int alloc_encrypt(struct vtun_host *host) { - unsigned char *key; - - if (sodium_init() < 0) { - return -1; - } - key = sodium_malloc(crypto_aead_KEYBYTES); ctx.state = sodium_malloc(sizeof *ctx.state); ctx.message = sodium_malloc(MESSAGE_MAX_SIZE); ctx.ciphertext = sodium_malloc(CIPHERTEXT_MAX_TOTAL_SIZE); ctx.nonce = sodium_malloc(crypto_aead_NPUBBYTES); ctx.previous_decrypted_nonce = sodium_malloc(crypto_aead_NPUBBYTES); - if (key == NULL || ctx.state == NULL || ctx.message == NULL || + if (host->key == NULL || ctx.state == NULL || ctx.message == NULL || ctx.ciphertext == NULL || ctx.ciphertext == NULL || ctx.nonce == NULL || ctx.previous_decrypted_nonce == NULL) { abort(); @@ -88,11 +72,9 @@ alloc_encrypt(struct vtun_host *host) if (init_nonce(ctx.nonce, crypto_aead_NPUBBYTES) != 0) { return -1; } - if (derive_key(key, crypto_aead_KEYBYTES, host) != 0) { - return -1; - } - crypto_aead_aes256gcm_beforenm(ctx.state, key); - sodium_free(key); + crypto_aead_aes256gcm_beforenm(ctx.state, host->key); + sodium_free(host->key); + host->key = NULL; return 0; } @@ -134,7 +116,8 @@ encrypt_buf(int message_len_, char *message_, char ** const ciphertext_p) crypto_aead_aes256gcm_encrypt_afternm(ctx.ciphertext, &ciphertext_len, message, message_len, NULL, 0ULL, - NULL, ctx.nonce, ctx.state); + NULL, ctx.nonce, + (const crypto_aead_aes256gcm_state *) ctx.state); memcpy(ctx.ciphertext + message_len + crypto_aead_ABYTES, ctx.nonce, crypto_aead_NPUBBYTES); sodium_increment(ctx.nonce, crypto_aead_NPUBBYTES); @@ -160,7 +143,8 @@ decrypt_buf(int ciphertext_len_, char *ciphertext_, char ** const message_p) if (is_lower_or_equal(nonce, ctx.previous_decrypted_nonce, crypto_aead_NPUBBYTES) || crypto_aead_aes256gcm_decrypt_afternm(ctx.message, &message_len, NULL, ciphertext, ciphertext_len, - NULL, 0ULL, nonce, ctx.state) != 0) { + NULL, 0ULL, nonce, + (const crypto_aead_aes256gcm_state *) ctx.state) != 0) { return -1; } memcpy(ctx.previous_decrypted_nonce, nonce, crypto_aead_NPUBBYTES); diff --git a/lib.c b/lib.c index acdd344..5a6a9ba 100644 --- a/lib.c +++ b/lib.c @@ -122,7 +122,9 @@ int print_p(int fd,const char *fmt, ...) /* print the argument string */ va_start(ap, fmt); - vsnprintf(buf,sizeof(buf)-1, fmt, ap); + if (vsnprintf(buf,sizeof(buf)-1, fmt, ap) >= VTUN_MESG_SIZE) + abort(); + va_end(ap); return write_n(fd, buf, sizeof(buf)); diff --git a/server.c b/server.c index 68af55a..5131619 100644 --- a/server.c +++ b/server.c @@ -43,6 +43,8 @@ #include #endif +#include + #include "vtun.h" #include "lib.h" #include "lock.h" @@ -66,6 +68,7 @@ static void connection(int sock) char *ip; int opt; + randombytes_stir(); opt = sizeof(struct sockaddr_in); if( getpeername(sock, (struct sockaddr *) &cl_addr, &opt) ){ vtun_syslog(LOG_ERR, "Can't get peer name"); diff --git a/vtun.h b/vtun.h index bca56b4..cd58820 100644 --- a/vtun.h +++ b/vtun.h @@ -87,7 +87,8 @@ struct vtun_addr { struct vtun_host { char *host; char *passwd; - unsigned char *key; + unsigned char *akey; + unsigned char *key; char *dev; llist up; @@ -171,7 +172,7 @@ extern llist host_list; #define VTUN_BAD_FRAME 0x8000 /* Authentication message size */ -#define VTUN_MESG_SIZE 50 +#define VTUN_MESG_SIZE 256 /* Support for multiple connections */ #define VTUN_MULTI_DENY 0 /* no */