Browse Source

working on oauth

mom040267 11 years ago
parent
commit
18180cafdc

+ 214 - 0
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;
+}
+
 ///////////////////////////////////////////////////////////////

+ 3 - 0
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

+ 77 - 4
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__

+ 13 - 0
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)
+);

+ 1 - 1
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