summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/Makefile2
-rw-r--r--src/key_derivation.c213
-rw-r--r--src/key_derivation.h17
-rw-r--r--src/uanytun.c22
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);