working on oauth

This commit is contained in:
mom040267 2014-08-24 08:43:58 +00:00
parent 84f12a9ed4
commit 18180cafdc
5 changed files with 308 additions and 5 deletions

View File

@ -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;
}
///////////////////////////////////////////////////////////////

View File

@ -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

View File

@ -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__

View File

@ -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)
);

View File

@ -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