From 18180cafdc664035e14bc30abb199b06c6976012 Mon Sep 17 00:00:00 2001 From: mom040267 Date: Sun, 24 Aug 2014 08:43:58 +0000 Subject: [PATCH] working on oauth --- src/client/ns_turn_msg.c | 214 ++++++++++++++++++++++++++++++ src/client/ns_turn_msg.h | 3 + src/client/ns_turn_msg_defs_new.h | 81 ++++++++++- turndb/schema.sql | 13 ++ turndb/schema.userdb.redis | 2 +- 5 files changed, 308 insertions(+), 5 deletions(-) diff --git a/src/client/ns_turn_msg.c b/src/client/ns_turn_msg.c index c6e49c8a..6b96daff 100644 --- a/src/client/ns_turn_msg.c +++ b/src/client/ns_turn_msg.c @@ -1631,4 +1631,218 @@ int stun_attr_add_padding_str(u08bits *buf, size_t *len, u16bits padding_len) return stun_attr_add_str(buf, len, STUN_ATTRIBUTE_PADDING, avalue, padding_len); } +/* OAUTH */ + +static void remove_spaces(char *s) +{ + char *sfns = s; + while(*sfns) { + if(*sfns != ' ') + break; + ++sfns; + } + if(*sfns) { + if(sfns != s) { + while(*sfns && (*sfns != ' ')) { + *s = *sfns; + ++s; + ++sfns; + }; + *s = 0; + } else { + while(*s) { + if(*s == ' ') { + *s = 0; + break; + } + ++s; + } + } + } +} + +static void normalize_algorithm(char *s) +{ + char c = *s; + while(c) { + if(c=='_') c='-'; + else if((c>='a')&&(c<='z')) { + c = c - 'a' + 'A'; + } + ++s; + c = *s; + } +} + +static size_t calculate_enc_key_length(ENC_ALG a) +{ + switch(a) { + case AES_128_CBC: + return 16; + case AES_256_CBC: + return 32; + default: + ; + }; + + return 32; +} + +static size_t calculate_auth_key_length(AUTH_ALG a) +{ + switch(a) { + case AUTH_ALG_HMAC_SHA_1: + return 20; + case AUTH_ALG_HMAC_SHA_256_128: + return 32; + case AUTH_ALG_HMAC_SHA_256: + return 32; + default: + ; + }; + + return 32; +} + +static int calculate_key(char *key, size_t key_size, char *new_key, size_t new_key_size, SHATYPE shatype, + char *err_msg, size_t err_msg_size) +{ + //Extract: + u08bits prk[128]; + unsigned int prk_len = 0; + stun_calculate_hmac((const u08bits *)key, key_size, (const u08bits *)"", 0, prk, &prk_len, shatype); + + //Expand: + u08bits buf[128]; + buf[0]=1; + u08bits hmac[128]; + unsigned int hmac_len = 0; + stun_calculate_hmac((const u08bits *)buf, 1, prk, prk_len, hmac, &hmac_len, shatype); + ns_bcopy(hmac,new_key,hmac_len); + + //Check + if(new_key_size>hmac_len) { + ns_bcopy(hmac,buf,hmac_len); + buf[hmac_len]=2; + u08bits hmac1[128]; + unsigned int hmac1_len = 0; + stun_calculate_hmac((const u08bits *)buf, hmac_len+1, prk, prk_len, hmac1, &hmac1_len, shatype); + ns_bcopy(hmac1,new_key+hmac_len,hmac1_len); + if(new_key_size > (hmac_len + hmac1_len)) { + if(err_msg) { + snprintf(err_msg,err_msg_size,"Wrong HKDF procedure (key sizes): output.sz=%lu, hmac(1)=%lu, hmac(2)=%lu",(unsigned long)new_key_size,(unsigned long)hmac_len,(unsigned long)hmac1_len); + } + return -1; + } + } + + return 0; +} + +int convert_oauth_key_data(oauth_key_data *oakd, oauth_key *key, char *err_msg, size_t err_msg_size) +{ + if(oakd && key) { + + if(!(oakd->ikm_key_size)) { + if(!(oakd->as_rs_key_size)) { + if(err_msg) { + snprintf(err_msg,err_msg_size,"AS-RS key is not defined"); + } + return -1; + } + if(!(oakd->auth_key_size)) { + if(err_msg) { + snprintf(err_msg,err_msg_size,"AUTH key is not defined"); + } + return -1; + } + } + + remove_spaces(oakd->kid); + + remove_spaces(oakd->hkdf_hash_func); + remove_spaces(oakd->as_rs_alg); + remove_spaces(oakd->auth_alg); + + normalize_algorithm(oakd->hkdf_hash_func); + normalize_algorithm(oakd->as_rs_alg); + normalize_algorithm(oakd->auth_alg); + + if(!(oakd->kid[0])) { + if(err_msg) { + snprintf(err_msg,err_msg_size,"KID is not defined"); + } + return -1; + } + + ns_bzero(key,sizeof(oauth_key)); + + STRCPY(key->kid,oakd->kid); + + ns_bcopy(oakd->as_rs_key,key->as_rs_key,sizeof(key->as_rs_key)); + key->as_rs_key_size = oakd->as_rs_key_size; + ns_bcopy(oakd->auth_key,key->auth_key,sizeof(key->auth_key)); + key->auth_key_size = oakd->auth_key_size; + ns_bcopy(oakd->ikm_key,key->ikm_key,sizeof(key->ikm_key)); + key->ikm_key_size = oakd->ikm_key_size; + + key->timestamp = oakd->timestamp; + key->lifetime = oakd->lifetime; + + key->hkdf_hash_func = SHATYPE_SHA256; + if(!strcmp(oakd->hkdf_hash_func,"SHA1") || !strcmp(oakd->hkdf_hash_func,"SHA-1")) { + key->hkdf_hash_func = SHATYPE_SHA1; + } else if(!strcmp(oakd->hkdf_hash_func,"SHA256") || !strcmp(oakd->hkdf_hash_func,"SHA-256")) { + key->hkdf_hash_func = SHATYPE_SHA256; + } else if(oakd->hkdf_hash_func[0]) { + if(err_msg) { + snprintf(err_msg,err_msg_size,"Wrong HKDF hash function algorithm: %s",oakd->hkdf_hash_func); + } + return -1; + } + + key->as_rs_alg = ENC_ALG_DEFAULT; + if(!strcmp(oakd->as_rs_alg,"AES-128-CBC")) { + key->as_rs_alg = AES_128_CBC; + } else if(!strcmp(oakd->as_rs_alg,"AES-256-CBC")) { + key->as_rs_alg = AES_256_CBC; + } else if(oakd->as_rs_alg[0]) { + if(err_msg) { + snprintf(err_msg,err_msg_size,"Wrong oAuth token encryption algorithm: %s",oakd->as_rs_alg); + } + return -1; + } + + key->auth_alg = AUTH_ALG_DEFAULT; + if(!strcmp(oakd->auth_alg,"HMAC-SHA-1") || !strcmp(oakd->auth_alg,"HMAC-SHA1")) { + key->auth_alg = AUTH_ALG_HMAC_SHA_1; + } else if(!strcmp(oakd->auth_alg,"HMAC-SHA-256")) { + key->auth_alg = AUTH_ALG_HMAC_SHA_256; + } else if(!strcmp(oakd->auth_alg,"HMAC-SHA-256-128")) { + key->auth_alg = AUTH_ALG_HMAC_SHA_256_128; + } else if(oakd->auth_alg[0]) { + if(err_msg) { + snprintf(err_msg,err_msg_size,"Wrong oAuth token hash algorithm: %s",oakd->auth_alg); + } + return -1; + } + } + + if(!(key->auth_key_size)) { + key->auth_key_size = calculate_auth_key_length(key->auth_alg); + if(calculate_key(key->ikm_key,key->ikm_key_size,key->auth_key,key->auth_key_size,key->hkdf_hash_func,err_msg,err_msg_size)<0) { + return -1; + } + } + + if(!(key->as_rs_key_size)) { + key->as_rs_key_size = calculate_enc_key_length(key->as_rs_alg); + if(calculate_key(key->ikm_key,key->ikm_key_size,key->as_rs_key,key->as_rs_key_size,key->hkdf_hash_func,err_msg,err_msg_size)<0) { + return -1; + } + } + + return 0; +} + /////////////////////////////////////////////////////////////// diff --git a/src/client/ns_turn_msg.h b/src/client/ns_turn_msg.h index f8abfac8..f4a0bd83 100644 --- a/src/client/ns_turn_msg.h +++ b/src/client/ns_turn_msg.h @@ -209,6 +209,9 @@ int stun_attr_add_padding_str(u08bits *buf, size_t *len, u16bits padding_len); /* HTTP */ int is_http_get(const char *s, size_t blen); +/* OAUTH */ +int convert_oauth_key_data(oauth_key_data *oakd, oauth_key *key, char *err_msg, size_t err_msg_size); + /////////////////////////////////////////////////////////////// #ifdef __cplusplus diff --git a/src/client/ns_turn_msg_defs_new.h b/src/client/ns_turn_msg_defs_new.h index 57b64c2a..b65f9df8 100644 --- a/src/client/ns_turn_msg_defs_new.h +++ b/src/client/ns_turn_msg_defs_new.h @@ -38,6 +38,12 @@ #define STUN_ATTRIBUTE_ORIGIN (0x802F) /* <<== Origin */ +/* Bandwidth */ + +#define STUN_ATTRIBUTE_NEW_BANDWIDTH (0x8000 + STUN_ATTRIBUTE_BANDWIDTH) + +/* <<== Bandwidth */ + /* SHA AGILITY ==>> */ #define SHA1SIZEBYTES (20) @@ -46,7 +52,9 @@ #define MAXSHASIZE (128) enum _SHATYPE { - SHATYPE_SHA1 = 0, + SHATYPE_ERROR = -1, + SHATYPE_DEFAULT=0, + SHATYPE_SHA1=SHATYPE_DEFAULT, SHATYPE_SHA256 }; @@ -58,10 +66,75 @@ typedef enum _SHATYPE SHATYPE; /* <<== SHA AGILITY */ -/* Bandwidth */ +/* OAUTH TOKEN ENC ALG ==> */ -#define STUN_ATTRIBUTE_NEW_BANDWIDTH (0x8000 + STUN_ATTRIBUTE_BANDWIDTH) +enum _ENC_ALG { + ENC_ALG_ERROR=-1, + ENC_ALG_DEFAULT=0, + AES_128_CBC=ENC_ALG_DEFAULT, + AES_256_CBC, + ENG_ALG_NUM +}; -/* <<== Bandwidth */ +typedef enum _ENC_ALG ENC_ALG; + +/* <<== OAUTH TOKEN ENC ALG */ + +/* OAUTH TOKEN AUTH ALG ==> */ + +enum _AUTH_ALG { + AUTH_ALG_ERROR = -1, + AUTH_ALG_DEFAULT = 0, + AUTH_ALG_HMAC_SHA_256_128 = AUTH_ALG_DEFAULT, + AUTH_ALG_HMAC_SHA_1, + AUTH_ALG_HMAC_SHA_256 +}; + +typedef enum _AUTH_ALG AUTH_ALG; + +/* <<== OAUTH TOKEN AUTH ALG */ + +/** + * oAuth struct + */ + +#define OAUTH_KID_SIZE (128) +#define OAUTH_HASH_FUNC_SIZE (64) +#define OAUTH_ALG_SIZE (64) +#define OAUTH_KEY_SIZE (256) + +struct _oauth_key_data { + char kid[OAUTH_KID_SIZE+1]; + char ikm_key[OAUTH_KEY_SIZE+1]; + size_t ikm_key_size; + u64bits timestamp; + turn_time_t lifetime; + char hkdf_hash_func[OAUTH_HASH_FUNC_SIZE+1]; + char as_rs_alg[OAUTH_ALG_SIZE+1]; + char as_rs_key[OAUTH_KEY_SIZE+1]; + size_t as_rs_key_size; + char auth_alg[OAUTH_ALG_SIZE+1]; + char auth_key[OAUTH_KEY_SIZE+1]; + size_t auth_key_size; +}; + +typedef struct _oauth_key_data oauth_key_data; + +struct _oauth_key { + char kid[OAUTH_KID_SIZE+1]; + char ikm_key[OAUTH_KEY_SIZE+1]; + size_t ikm_key_size; + u64bits timestamp; + turn_time_t lifetime; + SHATYPE hkdf_hash_func; + ENC_ALG as_rs_alg; + char as_rs_key[OAUTH_KEY_SIZE+1]; + size_t as_rs_key_size; + AUTH_ALG auth_alg; + char auth_key[OAUTH_KEY_SIZE+1]; + size_t auth_key_size; +}; + +typedef struct _oauth_key oauth_key; #endif //__LIB_TURN_MSG_DEFS_NEW__ diff --git a/turndb/schema.sql b/turndb/schema.sql index 36dee3cc..e438bce6 100644 --- a/turndb/schema.sql +++ b/turndb/schema.sql @@ -39,3 +39,16 @@ CREATE TABLE turn_realm_option ( value varchar(128), primary key (realm,opt) ); + +CREATE TABLE oauth_key ( + kid varchar(128), + ikm_key varchar(256), + timestamp bigint, + lifetime integer, + hkdf_hash_func varchar(64), + as_rs_alg varchar(64), + as_rs_key varchar(256), + auth_alg varchar(64), + auth_key varchar(256), + primary key (kid) +); diff --git a/turndb/schema.userdb.redis b/turndb/schema.userdb.redis index 69b5f2ef..0d3cae3b 100644 --- a/turndb/schema.userdb.redis +++ b/turndb/schema.userdb.redis @@ -116,7 +116,7 @@ save IV. Redis database configuration parameters TURN Server connects to the Redis and keeps the same connection during the -TURN server lifetime. That means that we have to take care about that +TURN Server process lifetime. That means that we have to take care about that connection - it must not expire. You have to take care about Redis connection parameters, the timeout and the