From 9cccc673202703d14941b7bb4de8442ef7560b17 Mon Sep 17 00:00:00 2001 From: mom040267 Date: Mon, 15 Sep 2014 07:50:24 +0000 Subject: [PATCH] working on oauth --- src/client/ns_turn_msg.c | 222 ++++++++++++++++++++++++++++-- src/client/ns_turn_msg.h | 4 +- src/client/ns_turn_msg_defs_new.h | 5 +- turndb/schema.userdb.redis | 2 +- 4 files changed, 219 insertions(+), 14 deletions(-) diff --git a/src/client/ns_turn_msg.c b/src/client/ns_turn_msg.c index 1d47ebda..ecc02b0c 100644 --- a/src/client/ns_turn_msg.c +++ b/src/client/ns_turn_msg.c @@ -1678,7 +1678,6 @@ static size_t calculate_enc_key_length(ENC_ALG a) { switch(a) { case AES_128_CBC: - case AEAD_AES_128_CCM: case AEAD_AES_128_GCM: return 16; default: @@ -1704,6 +1703,23 @@ static size_t calculate_auth_key_length(AUTH_ALG a) return 32; } +size_t calculate_auth_output_length(AUTH_ALG a); +size_t calculate_auth_output_length(AUTH_ALG a) +{ + switch(a) { + case AUTH_ALG_HMAC_SHA_1: + return 20; + case AUTH_ALG_HMAC_SHA_256_128: + return 16; + 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) { @@ -1825,10 +1841,6 @@ int convert_oauth_key_data(oauth_key_data *oakd, oauth_key *key, char *err_msg, key->as_rs_alg = AEAD_AES_128_GCM; } else if(!strcmp(oakd->as_rs_alg,"AEAD-AES-256-GCM")) { key->as_rs_alg = AEAD_AES_256_GCM; - } else if(!strcmp(oakd->as_rs_alg,"AEAD-AES-128-CCM")) { - key->as_rs_alg = AEAD_AES_128_CCM; - } else if(!strcmp(oakd->as_rs_alg,"AEAD_AES_256_CCM")) { - key->as_rs_alg = AEAD_AES_256_CCM; } 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); @@ -1858,16 +1870,208 @@ int convert_oauth_key_data(oauth_key_data *oakd, oauth_key *key, char *err_msg, return 0; } -int decode_oauth_token(encoded_oauth_token *etoken, oauth_key *key, oauth_token *dtoken) +int decode_oauth_token(u08bits *server_name, encoded_oauth_token *etoken, oauth_key *key, oauth_token *dtoken) { //TODO return 0; } -int encode_oauth_token(encoded_oauth_token *etoken, oauth_key *key, oauth_token *dtoken) +static const EVP_CIPHER *get_cipher_type(ENC_ALG enc_alg) { - //TODO - return 0; + switch(enc_alg) { + case AES_256_CBC: + return EVP_aes_256_cbc(); + case AES_128_CBC: + return EVP_aes_128_cbc(); + case AEAD_AES_128_GCM: + return EVP_aes_128_gcm(); + case AEAD_AES_256_GCM: + return EVP_aes_256_gcm(); + default: + ; + } + return NULL; +} + +static void generate_random_nonce(unsigned char *nonce, size_t sz) { + if(!RAND_bytes(nonce, sz)<0) { + size_t i; + for(i=0;i> 1; + default: + ; + }; + } +} + +static int encode_oauth_token_normal(u08bits *server_name, encoded_oauth_token *etoken, oauth_key *key, oauth_token *dtoken) +{ + if(server_name && etoken && key && dtoken && (dtoken->enc_block.key_length<=128)) { + + unsigned char orig_field[MAX_ENCODED_OAUTH_TOKEN_SIZE]; + + size_t len = 0; + *((uint16_t*)(orig_field+len)) = nswap16(dtoken->enc_block.key_length); + len +=2; + + ns_bcopy(dtoken->enc_block.mac_key,orig_field+len,dtoken->enc_block.key_length); + len += dtoken->enc_block.key_length; + + *((uint64_t*)(orig_field+len)) = nswap64(dtoken->enc_block.timestamp); + len += 8; + + *((uint32_t*)(orig_field+len)) = nswap32(dtoken->enc_block.lifetime); + len += 4; + + const EVP_CIPHER * cipher = get_cipher_type(key->as_rs_alg); + if(!cipher) + return -1; + + unsigned char *encoded_field = (unsigned char*)etoken->token; + + EVP_CIPHER_CTX ctx; + EVP_CIPHER_CTX_init(&ctx); + EVP_EncryptInit_ex(&ctx, cipher, NULL, (unsigned char *)key->as_rs_key, NULL); + int outl=0; + EVP_EncryptUpdate(&ctx, encoded_field, &outl, orig_field, (int)len); + EVP_EncryptFinal_ex(&ctx, encoded_field + outl, &outl); + + size_t sn_len = strlen((char*)server_name); + ns_bcopy(server_name,encoded_field+outl,sn_len); + outl += sn_len; + + const EVP_MD *md = get_auth_type(key->auth_alg); + if(!md) + return -1; + + unsigned int hmac_len = EVP_MD_size(md); + if (!HMAC(md, key->auth_key, key->auth_key_size, encoded_field, outl, encoded_field + outl, &hmac_len)) { + return -1; + } + + update_hmac_len(key->auth_alg, &hmac_len); + + ns_bcopy(encoded_field + outl, encoded_field + outl - sn_len, hmac_len); + outl -= sn_len; + outl += hmac_len; //encoded+hmac + + etoken->size = outl; + + return 0; + } + return -1; +} + +static int encode_oauth_token_aead(u08bits *server_name, encoded_oauth_token *etoken, oauth_key *key, oauth_token *dtoken) +{ + if(server_name && etoken && key && dtoken && (dtoken->enc_block.key_length<128)) { + + unsigned char orig_field[MAX_ENCODED_OAUTH_TOKEN_SIZE]; + + size_t len = 0; + *((uint16_t*)(orig_field+len)) = nswap16(dtoken->enc_block.key_length); + len +=2; + + ns_bcopy(dtoken->enc_block.mac_key,orig_field+len,dtoken->enc_block.key_length); + len += dtoken->enc_block.key_length; + + *((uint64_t*)(orig_field+len)) = nswap64(dtoken->enc_block.timestamp); + len += 8; + + *((uint32_t*)(orig_field+len)) = nswap32(dtoken->enc_block.lifetime); + len += 4; + + const EVP_CIPHER * cipher = get_cipher_type(key->as_rs_alg); + if(!cipher) + return -1; + + unsigned char *encoded_field = (unsigned char*)etoken->token; + + unsigned char nonce[OAUTH_AEAD_NONCE_SIZE]; + generate_random_nonce(nonce, sizeof(nonce)); + + EVP_CIPHER_CTX ctx; + EVP_CIPHER_CTX_init(&ctx); + + /* Initialise the encryption operation. */ + if(1 != EVP_EncryptInit_ex(&ctx, cipher, NULL, NULL, NULL)) + return -1; + + /* Set IV length if default 12 bytes (96 bits) is not appropriate */ + if(1 != EVP_CIPHER_CTX_ctrl(&ctx, EVP_CTRL_GCM_SET_IVLEN, OAUTH_AEAD_NONCE_SIZE, NULL)) + return -1; + + /* Initialise key and IV */ + if(1 != EVP_EncryptInit_ex(&ctx, NULL, NULL, (unsigned char *)key->as_rs_key, nonce)) + return -1; + + int outl=0; + size_t sn_len = strlen((char*)server_name); + + /* Provide any AAD data. This can be called zero or more times as + * required + */ + if(1 != EVP_EncryptUpdate(&ctx, NULL, &outl, server_name, (int)sn_len)) + return -1; + + EVP_EncryptUpdate(&ctx, encoded_field, &outl, orig_field, (int)len); + + int tmp_outl = 0; + EVP_EncryptFinal_ex(&ctx, encoded_field + outl, &tmp_outl); + outl += tmp_outl; + + EVP_CIPHER_CTX_ctrl(&ctx, EVP_CTRL_GCM_GET_TAG, OAUTH_AEAD_TAG_SIZE, encoded_field + outl); + outl += OAUTH_AEAD_TAG_SIZE; + + ns_bcopy(nonce, encoded_field + outl, OAUTH_AEAD_NONCE_SIZE); + outl += OAUTH_AEAD_NONCE_SIZE; //encoded+hmac + + etoken->size = outl; + + return 0; + } + return -1; +} + +int encode_oauth_token(u08bits *server_name, encoded_oauth_token *etoken, oauth_key *key, oauth_token *dtoken) +{ + if(server_name && etoken && key && dtoken) { + switch(key->as_rs_alg) { + case AES_256_CBC: + case AES_128_CBC: + return encode_oauth_token_normal(server_name, etoken,key,dtoken); + case AEAD_AES_128_GCM: + case AEAD_AES_256_GCM: + return encode_oauth_token_aead(server_name, etoken,key,dtoken); + default: + fprintf(stderr,"Wrong AS_RS algorithm: %d\n",(int)key->as_rs_alg); + }; + } + return -1; } /////////////////////////////////////////////////////////////// diff --git a/src/client/ns_turn_msg.h b/src/client/ns_turn_msg.h index d7e73b10..87c6d27d 100644 --- a/src/client/ns_turn_msg.h +++ b/src/client/ns_turn_msg.h @@ -211,8 +211,8 @@ 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); -int decode_oauth_token(encoded_oauth_token *etoken, oauth_key *key, oauth_token *dtoken); -int encode_oauth_token(encoded_oauth_token *etoken, oauth_key *key, oauth_token *dtoken); +int decode_oauth_token(u08bits *server_name, encoded_oauth_token *etoken, oauth_key *key, oauth_token *dtoken); +int encode_oauth_token(u08bits *server_name, encoded_oauth_token *etoken, oauth_key *key, oauth_token *dtoken); /////////////////////////////////////////////////////////////// diff --git a/src/client/ns_turn_msg_defs_new.h b/src/client/ns_turn_msg_defs_new.h index 96551b35..8de90b14 100644 --- a/src/client/ns_turn_msg_defs_new.h +++ b/src/client/ns_turn_msg_defs_new.h @@ -75,8 +75,6 @@ enum _ENC_ALG { AES_128_CBC, AEAD_AES_128_GCM, AEAD_AES_256_GCM, - AEAD_AES_128_CCM, - AEAD_AES_256_CCM, ENG_ALG_NUM }; @@ -107,6 +105,8 @@ typedef enum _AUTH_ALG AUTH_ALG; #define OAUTH_HASH_FUNC_SIZE (64) #define OAUTH_ALG_SIZE (64) #define OAUTH_KEY_SIZE (256) +#define OAUTH_AEAD_NONCE_SIZE (12) +#define OAUTH_AEAD_TAG_SIZE (16) #define OAUTH_DEFAULT_LIFETIME (0) #define OAUTH_DEFAULT_TIMESTAMP (turn_time()) @@ -157,6 +157,7 @@ typedef struct _oauth_encrypted_block oauth_encrypted_block; struct _oauth_token { oauth_encrypted_block enc_block; uint8_t mac[MAXSHASIZE]; + size_t mac_size; }; typedef struct _oauth_token oauth_token; diff --git a/turndb/schema.userdb.redis b/turndb/schema.userdb.redis index f77e936b..371645e1 100644 --- a/turndb/schema.userdb.redis +++ b/turndb/schema.userdb.redis @@ -57,7 +57,7 @@ and they will be almost immediately "seen" by the turnserver process. as_rs_alg - oAuth token encryption algorithm; the valid values are "AES-128-CBC" and "AES-256-CBC", , "AEAD-AES-128-GCM", - "AEAD-AES-256-GCM", "AEAD-AES-128-CCM", "AEAD-AES-256-CCM". + "AEAD-AES-256-GCM". The default value is "AES-256-CBC"; as_rs_key - (optional) base64-encoded AS-RS key. If not defined, then