diff options
-rw-r--r-- | src/Makefile | 2 | ||||
-rw-r--r-- | src/key_derivation.c | 213 | ||||
-rw-r--r-- | src/key_derivation.h | 17 | ||||
-rw-r--r-- | src/uanytun.c | 22 |
4 files changed, 171 insertions, 83 deletions
diff --git a/src/Makefile b/src/Makefile index 975c375..3b3be02 100644 --- a/src/Makefile +++ b/src/Makefile @@ -42,7 +42,7 @@ ifeq ($(TARGET),Linux) LDFLAGS += -ldl endif ifeq ($(TARGET),OpenBSD) - CCFLAGS += -I/usr/local/include -DNO_UDPV6 -DNO_SEC_MEM + CCFLAGS += -I/usr/local/include -DNO_UDPV6 LDFLAGS += -L/usr/local/lib endif diff --git a/src/key_derivation.c b/src/key_derivation.c index 5e3f2c5..49fb2a2 100644 --- a/src/key_derivation.c +++ b/src/key_derivation.c @@ -38,29 +38,39 @@ #include "log.h" +#include <stdlib.h> #include <string.h> #include <gmp.h> -int key_derivation_init(key_derivation_t* kd, const char* type, u_int8_t* key, u_int32_t key_len, u_int8_t* salt, u_int32_t salt_len) +int key_derivation_init(key_derivation_t* kd, const char* type, int8_t ld_kdr, u_int8_t* key, u_int32_t key_len, u_int8_t* salt, u_int32_t salt_len) { if(!kd) return -1; - kd->type_ = unknown; + kd->type_ = kd_unknown; if(!strcmp(type, "null")) - kd->type_ = null; + kd->type_ = kd_null; else if(!strcmp(type, "aes-ctr")) - kd->type_ = aes_ctr; + kd->type_ = kd_aes_ctr; else { log_printf(ERR, "unknown key derivation type"); return -1; } - kd->ld_kdr_ = -1; + kd->ld_kdr_ = ld_kdr; + if(ld_kdr > (sizeof(seq_nr_t) * 8)) + kd->ld_kdr_ = sizeof(seq_nr_t) * 8; + kd->key_length_ = key_len * sizeof(key[0]) * 8; kd->handle_ = 0; + int i; + for(i = 0; i<KD_LABEL_COUNT; ++i) { + kd->key_store_[i].buf_ = NULL; + kd->key_store_[i].length_ = 0; + } + if(!key) { kd->master_key_.buf_ = NULL; kd->master_key_.length_ = 0; @@ -89,8 +99,11 @@ int key_derivation_init(key_derivation_t* kd, const char* type, u_int8_t* key, u } int ret = 0; - if(kd->type_ == aes_ctr) - ret = key_derivation_aesctr_init(kd, key, key_len, salt, salt_len); + if(kd->type_ == kd_aes_ctr) + ret = key_derivation_aesctr_init(kd, kd->key_length_); + + if(ret) + key_derivation_close(kd); return ret; } @@ -100,53 +113,78 @@ void key_derivation_close(key_derivation_t* kd) if(!kd) return; - if(kd->type_ == aes_ctr) + if(kd->type_ == kd_aes_ctr) key_derivation_aesctr_close(kd); if(kd->master_key_.buf_) free(kd->master_key_.buf_); if(kd->master_salt_.buf_) free(kd->master_salt_.buf_); + + int i; + for(i = 0; i<KD_LABEL_COUNT; ++i) { + if(kd->key_store_[i].buf_) + free(kd->key_store_[i].buf_); + } } -void key_derivation_generate(key_derivation_t* kd, satp_prf_label_t label, seq_nr_t seq_nr, u_int8_t* key, u_int32_t len) +int key_derivation_generate(key_derivation_t* kd, satp_prf_label_t label, seq_nr_t seq_nr, u_int8_t* key, u_int32_t len) { - if(!kd) - return; + if(!kd || !key) + return -1; + + if(label >= KD_LABEL_COUNT) { + log_printf(ERR, "label 0x%02X out of range", label); + return -1; + } - if(kd->type_ == null) - key_derivation_null_generate(key, len); - else if(kd->type_ == aes_ctr) - key_derivation_aesctr_generate(kd, label, seq_nr, key, len); + int ret = 0; + if(kd->type_ == kd_null) + ret = key_derivation_null_generate(key, len); + else if(kd->type_ == kd_aes_ctr) + ret = key_derivation_aesctr_generate(kd, label, seq_nr, key, len); else { - log_printf(ERR, "unknown cipher type"); - return; + log_printf(ERR, "unknown key derivation type"); + return -1; } + return ret; } /* ---------------- NULL Key Derivation ---------------- */ -void key_derivation_null_generate(u_int8_t* key, u_int32_t len) +int key_derivation_null_generate(u_int8_t* key, u_int32_t len) { memset(key, 0, len); + return 0; } /* ---------------- AES-Ctr Key Derivation ---------------- */ -int key_derivation_aesctr_init(key_derivation_t* kd, u_int8_t* key, u_int32_t key_len, u_int8_t* salt, u_int32_t salt_len) +int key_derivation_aesctr_init(key_derivation_t* kd, u_int16_t key_length) { if(!kd) return -1; - gcry_error_t err = gcry_cipher_open(&kd->handle_, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CTR, 0); + int algo; + switch(key_length) { + case 128: algo = GCRY_CIPHER_AES128; break; + case 192: algo = GCRY_CIPHER_AES192; break; + case 256: algo = GCRY_CIPHER_AES256; break; + default: { + log_printf(ERR, "key length of %d Bits is not supported", key_length); + return -1; + } + } + + gcry_error_t err = gcry_cipher_open(&kd->handle_, algo, GCRY_CIPHER_MODE_CTR, 0); if(err) { - log_printf(ERR, "failed to open cipher: %s/%s", gcry_strerror(err), gcry_strsource(err)); + log_printf(ERR, "failed to open key derivation cipher: %s/%s", gcry_strerror(err), gcry_strsource(err)); return -1; } err = gcry_cipher_setkey(kd->handle_, kd->master_key_.buf_, kd->master_key_.length_); if(err) { - log_printf(ERR, "failed to set cipher key: %s/%s", gcry_strerror(err), gcry_strsource(err)); + log_printf(ERR, "failed to set key derivation key: %s/%s", gcry_strerror(err), gcry_strsource(err)); return -1; } @@ -162,27 +200,21 @@ void key_derivation_aesctr_close(key_derivation_t* kd) gcry_cipher_close(kd->handle_); } -buffer_t key_derivation_aesctr_calc_ctr(key_derivation_t* kd, satp_prf_label_t label, seq_nr_t seq_nr) +int key_derivation_aesctr_calc_ctr(key_derivation_t* kd, buffer_t* result, satp_prf_label_t label, seq_nr_t seq_nr) { - buffer_t result; - result.buf_ = NULL; - result.length_ = 0; - - if(!kd) - return result; + if(!kd || !result) + return -1; - // see at: http://tools.ietf.org/html/rfc3711#section-4.3 - // * Let r = index DIV key_derivation_rate (with DIV as defined above). - // * Let key_id = <label> || r. - // * Let x = key_id XOR master_salt, where key_id and master_salt are - // aligned so that their least significant bits agree (right- - // alignment). - // + result->buf_ = NULL; + result->length_ = 0; - mpz_t ctr, key_id, r; + mpz_t ctr, key_id, r, seq; mpz_init2(ctr, 128); mpz_init2(key_id, 128); mpz_init2(r, 128); + mpz_init2(seq, (sizeof(seq_nr_t) * 8)); + + mpz_set_ui(seq, seq_nr); int faked_msb = 0; if(!kd->master_salt_.buf_[0]) @@ -190,19 +222,31 @@ buffer_t key_derivation_aesctr_calc_ctr(key_derivation_t* kd, satp_prf_label_t l if(kd->ld_kdr_ == -1) mpz_set_ui(r, 0); - else { - mpz_t seq; - mpz_init2(seq, 32); - mpz_set_ui(seq, seq_nr); - - mpz_set_ui(r, 1); - mpz_mul_2exp(r, r, kd->ld_kdr_); - - mpz_fdiv_q(r, seq, r); - - mpz_clear(seq); + else + mpz_fdiv_q_2exp(r, seq, kd->ld_kdr_); + + if(kd->key_store_[label].buf_ && seq_nr) { + if(!mpz_cmp_ui(r, 0)) { + mpz_clear(seq); + mpz_clear(ctr); + mpz_clear(key_id); + mpz_clear(r); + return 0; + } + + mpz_t mod; + mpz_init2(mod, (sizeof(seq_nr) * 8)); + mpz_fdiv_r(mod, seq, r); + if(mpz_cmp_ui(mod, 0)) { + mpz_clear(seq); + mpz_clear(mod); + mpz_clear(ctr); + mpz_clear(key_id); + mpz_clear(r); + return 0; + } + mpz_clear(mod); } -/* TODO: generate key only if index % r == 0, except it is the first time */ mpz_set_ui(key_id, label); mpz_mul_2exp(key_id, key_id, 48); @@ -213,49 +257,88 @@ buffer_t key_derivation_aesctr_calc_ctr(key_derivation_t* kd, satp_prf_label_t l mpz_xor(ctr, ctr, key_id); mpz_mul_2exp(ctr, ctr, 16); - result.buf_ = mpz_export(NULL, (size_t*)&result.length_, 1, 1, 0, 0, ctr); + if(result->buf_) + free(result->buf_); + result->buf_ = mpz_export(NULL, (size_t*)&(result->length_), 1, 1, 0, 0, ctr); if(faked_msb) { kd->master_salt_.buf_[0] = 0; - result.buf_[0] = 0; + result->buf_[0] = 0; } + mpz_clear(seq); mpz_clear(ctr); mpz_clear(key_id); mpz_clear(r); - return result; + return 1; } -void key_derivation_aesctr_generate(key_derivation_t* kd, satp_prf_label_t label, seq_nr_t seq_nr, u_int8_t* key, u_int32_t len) +int key_derivation_aesctr_generate(key_derivation_t* kd, satp_prf_label_t label, seq_nr_t seq_nr, u_int8_t* key, u_int32_t len) { if(!kd || !kd->master_key_.buf_ || !kd->master_salt_.buf_) { - log_printf(ERR, "cipher not initialized or no key or salt set"); - return; + log_printf(ERR, "key derivation not initialized or no key or salt set"); + return -1; } gcry_error_t err = gcry_cipher_reset(kd->handle_); if(err) { - log_printf(ERR, "failed to reset cipher: %s/%s", gcry_strerror(err), gcry_strsource(err)); - return; + log_printf(ERR, "failed to reset key derivation cipher: %s/%s", gcry_strerror(err), gcry_strsource(err)); + return -1; } - buffer_t ctr = key_derivation_aesctr_calc_ctr(kd, label, seq_nr); - if(!ctr.buf_) { - log_printf(ERR, "failed to calculate cipher CTR"); - return; + buffer_t ctr; + ctr.buf_ = NULL; + ctr.length_ = 0; + int ret = key_derivation_aesctr_calc_ctr(kd, &ctr, label, seq_nr); + if(ret < 0) { + log_printf(ERR, "failed to calculate key derivation CTR"); + return -1; } + else if(!ret) { + if(len > kd->key_store_[label].length_) { + log_printf(WARNING, "stored (old) key for label 0x%02X is to short, filling with zeros", label); + memset(key, 0, len); + len = kd->key_store_[label].length_; + } + memcpy(key, kd->key_store_[label].buf_, len); + return 0; + } + err = gcry_cipher_setctr(kd->handle_, ctr.buf_, ctr.length_); free(ctr.buf_); if(err) { - log_printf(ERR, "failed to set cipher CTR: %s/%s", gcry_strerror(err), gcry_strsource(err)); - return; + log_printf(ERR, "failed to set key derivation CTR: %s/%s", gcry_strerror(err), gcry_strsource(err)); + return -1; } memset(key, 0, len); err = gcry_cipher_encrypt(kd->handle_, key, len, NULL, 0); if(err) { - log_printf(ERR, "failed to generate cipher bitstream: %s/%s", gcry_strerror(err), gcry_strsource(err)); - return; + log_printf(ERR, "failed to generate key derivation bitstream: %s/%s", gcry_strerror(err), gcry_strsource(err)); + return -1; + } + + if(!kd->key_store_[label].buf_) { + kd->key_store_[label].length_ = 0; + kd->key_store_[label].buf_ = malloc(len); + if(!kd->key_store_[label].buf_) { + log_printf(ERR, "memory error at key derivation"); + return -2; + } + kd->key_store_[label].length_ = len; } + else if(kd->key_store_[label].length_ < len) { + u_int8_t* tmp = realloc(kd->key_store_[label].buf_, len); + if(!tmp) { + log_printf(ERR, "memory error at key derivation"); + return -2; + } + kd->key_store_[label].buf_ = tmp; + kd->key_store_[label].length_ = len; + } + + memcpy(kd->key_store_[label].buf_, key, len); + + return 0; } diff --git a/src/key_derivation.h b/src/key_derivation.h index 6e1a1e3..21f069d 100644 --- a/src/key_derivation.h +++ b/src/key_derivation.h @@ -37,6 +37,7 @@ #include <gcrypt.h> +#define KD_LABEL_COUNT 3 enum satp_prf_label_enum { LABEL_SATP_ENCRYPTION = 0x00, LABEL_SATP_MSG_AUTH = 0x01, @@ -44,27 +45,29 @@ enum satp_prf_label_enum { }; typedef enum satp_prf_label_enum satp_prf_label_t; -enum key_derivation_type_enum { unknown, null, aes_ctr }; +enum key_derivation_type_enum { kd_unknown, kd_null, kd_aes_ctr }; typedef enum key_derivation_type_enum key_derivation_type_t; struct key_derivation_struct { key_derivation_type_t type_; int8_t ld_kdr_; + u_int16_t key_length_; buffer_t master_key_; buffer_t master_salt_; gcry_cipher_hd_t handle_; + buffer_t key_store_[KD_LABEL_COUNT]; }; typedef struct key_derivation_struct key_derivation_t; -int key_derivation_init(key_derivation_t* kd, const char* type, u_int8_t* key, u_int32_t key_len, u_int8_t* salt, u_int32_t salt_len); +int key_derivation_init(key_derivation_t* kd, const char* type, int8_t ld_kdr, u_int8_t* key, u_int32_t key_len, u_int8_t* salt, u_int32_t salt_len); void key_derivation_close(key_derivation_t* kd); -void key_derivation_generate(key_derivation_t* kd, satp_prf_label_t label, seq_nr_t seq_nr, u_int8_t* key, u_int32_t len); +int key_derivation_generate(key_derivation_t* kd, satp_prf_label_t label, seq_nr_t seq_nr, u_int8_t* key, u_int32_t len); -void key_derivation_null_generate(u_int8_t* key, u_int32_t len); +int key_derivation_null_generate(u_int8_t* key, u_int32_t len); -int key_derivation_aesctr_init(key_derivation_t* kd, u_int8_t* key, u_int32_t key_len, u_int8_t* salt, u_int32_t salt_len); +int key_derivation_aesctr_init(key_derivation_t* kd, u_int16_t key_length); void key_derivation_aesctr_close(key_derivation_t* kd); -buffer_t key_derivation_aesctr_calc_ctr(key_derivation_t* kd, satp_prf_label_t label, seq_nr_t seq_nr); -void key_derivation_aesctr_generate(key_derivation_t* kd, satp_prf_label_t label, seq_nr_t seq_nr, u_int8_t* key, u_int32_t len); +int key_derivation_aesctr_calc_ctr(key_derivation_t* kd, buffer_t* result, satp_prf_label_t label, seq_nr_t seq_nr); +int key_derivation_aesctr_generate(key_derivation_t* kd, satp_prf_label_t label, seq_nr_t seq_nr, u_int8_t* key, u_int32_t len); #endif diff --git a/src/uanytun.c b/src/uanytun.c index 244ffbd..08a5f3e 100644 --- a/src/uanytun.c +++ b/src/uanytun.c @@ -51,6 +51,7 @@ #include "seq_window.h" #include "cipher.h" +#include "key_derivation.h" #include "daemon.h" #include "sysexec.h" @@ -67,19 +68,11 @@ int init_libgcrypt() return -1; } -#ifndef NO_SEC_MEM - gcry_error_t err = gcry_control(GCRYCTL_INIT_SECMEM, 16384, 0); - if(err) { - log_printf(ERR, "failed to initialize secure memory: %s/%s", gcry_strerror(err), gcry_strsource(err)); - return -1; - } -#else gcry_error_t err = gcry_control(GCRYCTL_DISABLE_SECMEM, 0); if(err) { log_printf(ERR, "failed to disable secure memory: %s/%s", gcry_strerror(err), gcry_strsource(err)); return -1; } -#endif err = gcry_control(GCRYCTL_INITIALIZATION_FINISHED); if(err) { @@ -112,6 +105,13 @@ int main_loop(tun_device_t* dev, udp_socket_t* sock, options_t* opt) return_value = ret; } + key_derivation_t kd; + ret = key_derivation_init(&kd, opt->kd_prf_, 0, opt->key_.buf_, opt->key_.length_, opt->salt_.buf_, opt->salt_.length_); + if(ret) { + log_printf(ERR, "could not initialize cipher of type %s", opt->kd_prf_); + return_value = ret; + } + seq_win_t seq_win; ret = seq_win_init(&seq_win, opt->seq_window_size_); if(ret) { @@ -217,8 +217,11 @@ int main_loop(tun_device_t* dev, udp_socket_t* sock, options_t* opt) void print_hex_dump(const u_int8_t* buf, u_int32_t len) { - u_int32_t i; + if(!buf) { + printf("(NULL)"); + } + u_int32_t i; for(i=0; i < len; i++) { printf("%02X ", buf[i]); if(!((i+1)%8)) @@ -229,7 +232,6 @@ void print_hex_dump(const u_int8_t* buf, u_int32_t len) printf("\n"); } - int main(int argc, char* argv[]) { log_init("uanytun", DAEMON); |