diff --git a/coreapi/authentication.c b/coreapi/authentication.c index 4d8603f63..971294280 100644 --- a/coreapi/authentication.c +++ b/coreapi/authentication.c @@ -53,6 +53,19 @@ LinphoneAuthInfo *linphone_auth_info_new(const char *username, const char *useri return obj; } +LinphoneAuthInfo *linphone_auth_info_new_for_algorithm(const char *username, const char *userid, const char *passwd, const char *ha1, const char *realm, const char *domain, const char *algorithm){ + LinphoneAuthInfo *obj=linphone_auth_info_new(username,userid,passwd,ha1,realm,domain); + /* Default algorithm is MD5 if it's NULL*/ + if(algorithm && strcmp(algorithm, "MD5") && strcmp(algorithm, "SHA-256")){ + ms_error("Given algorithm %s is not correct.", algorithm); + return NULL; + } + if(algorithm){ + obj->algorithm=ms_strdup(algorithm); + } + return obj; +} + static void _linphone_auth_info_copy(LinphoneAuthInfo *dst, const LinphoneAuthInfo *src) { if (src->username) dst->username = ms_strdup(src->username); if (src->userid) dst->userid = ms_strdup(src->userid); @@ -64,6 +77,7 @@ static void _linphone_auth_info_copy(LinphoneAuthInfo *dst, const LinphoneAuthIn if (src->tls_key) dst->tls_key = ms_strdup(src->tls_key); if (src->tls_cert_path) dst->tls_cert_path = ms_strdup(src->tls_cert_path); if (src->tls_key_path) dst->tls_key_path = ms_strdup(src->tls_key_path); + if (src->algorithm) dst->algorithm = ms_strdup(src->algorithm); } LinphoneAuthInfo *linphone_auth_info_clone(const LinphoneAuthInfo *ai){ @@ -217,6 +231,7 @@ static void _linphone_auth_info_uninit(LinphoneAuthInfo *obj) { if (obj->tls_key != NULL) ms_free(obj->tls_key); if (obj->tls_cert_path != NULL) ms_free(obj->tls_cert_path); if (obj->tls_key_path != NULL) ms_free(obj->tls_key_path); + if (obj->algorithm != NULL) ms_free(obj->algorithm); } /** @@ -238,8 +253,14 @@ void linphone_auth_info_write_config(LpConfig *config, LinphoneAuthInfo *obj, in } if (!obj->ha1 && obj->realm && obj->passwd && (obj->username || obj->userid) && store_ha1_passwd) { /*compute ha1 to avoid storing clear text password*/ - obj->ha1 = reinterpret_cast(ms_malloc(33)); - sal_auth_compute_ha1(obj->userid ? obj->userid : obj->username, obj->realm, obj->passwd, obj->ha1); + if((obj->algorithm==NULL)||(!(strcmp(obj->algorithm, "MD5")))){ + obj->ha1 = reinterpret_cast(ms_malloc(33)); + sal_auth_compute_ha1(obj->userid ? obj->userid : obj->username, obj->realm, obj->passwd, obj->ha1); + } + if((obj->algorithm)&&(!(strcmp(obj->algorithm, "SHA-256")))){ + obj->ha1 = reinterpret_cast(ms_malloc(65)); + sal_auth_compute_ha1_for_algorithm(obj->userid ? obj->userid : obj->username, obj->realm, obj->passwd, obj->ha1,65, obj->algorithm); + } } if (obj->username != NULL) { lp_config_set_string(config, key, "username", obj->username); @@ -271,6 +292,9 @@ void linphone_auth_info_write_config(LpConfig *config, LinphoneAuthInfo *obj, in if (obj->tls_key_path != NULL) { lp_config_set_string(config, key, "client_cert_key", obj->tls_key_path); } + if (obj->algorithm != NULL) { + lp_config_set_string(config, key, "algorithm", obj->algorithm); + } } LinphoneAuthInfo *linphone_auth_info_new_from_config_file(LpConfig * config, int pos) @@ -455,6 +479,7 @@ void linphone_core_add_auth_info(LinphoneCore *lc, const LinphoneAuthInfo *info) sai.realm=ai->realm; sai.password=ai->passwd; sai.ha1=ai->ha1; + sai.algorithm=ai->algorithm; if (ai->tls_cert && ai->tls_key) { sal_certificates_chain_parse(&sai, ai->tls_cert, SAL_CERTIFICATE_RAW_FORMAT_PEM); sal_signing_key_parse(&sai, ai->tls_key, ""); diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index 7803b92a5..41c562183 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -65,6 +65,7 @@ SalAuthInfo* sal_auth_info_create(belle_sip_auth_event_t* event) { auth_info->username = ms_strdup(belle_sip_auth_event_get_username(event)); auth_info->domain = ms_strdup(belle_sip_auth_event_get_domain(event)); auth_info->mode = (SalAuthMode)belle_sip_auth_event_get_mode(event); + auth_info->algorithm = ms_strdup(belle_sip_auth_event_get_algorithm(event)); return auth_info; } @@ -83,6 +84,11 @@ int sal_auth_compute_ha1(const char* userid,const char* realm,const char* passwo return belle_sip_auth_helper_compute_ha1(userid, realm, password, ha1); } +int sal_auth_compute_ha1_for_algorithm(const char* userid,const char* realm,const char* password, char* ha1, + size_t size, const char* algo) { + return belle_sip_auth_helper_compute_ha1_for_algorithm(userid, realm, password, ha1, size, algo); +} + SalCustomHeader *sal_custom_header_ref(SalCustomHeader *ch){ if (ch == NULL) return NULL; belle_sip_object_ref(ch); diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 2c1d6a8c9..b6f95d591 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -526,6 +526,16 @@ static bool_t fill_auth_info(LinphoneCore *lc, SalAuthInfo* sai) { } if (ai) { if (sai->mode == SalAuthModeHttpDigest) { + /* Compare algorithm of server(sai) with algorithm of client(ai), if they are not correspondant, + exit. The default algorithm is MD5 if it's NULL. */ + if(sai->algorithm && ai->algorithm) { + if(strcmp(ai->algorithm, sai->algorithm)) + return TRUE; + } + else if((ai->algorithm && strcmp(ai->algorithm, "MD5")) || + (sai->algorithm && strcmp(sai->algorithm, "MD5"))) + return TRUE; + sai->userid = ms_strdup(ai->userid ? ai->userid : ai->username); sai->password = ai->passwd?ms_strdup(ai->passwd) : NULL; sai->ha1 = ai->ha1 ? ms_strdup(ai->ha1) : NULL; diff --git a/coreapi/private.h b/coreapi/private.h index 5b22e4fac..528b9c35a 100644 --- a/coreapi/private.h +++ b/coreapi/private.h @@ -562,6 +562,7 @@ struct _LinphoneAuthInfo char *tls_key; char *tls_cert_path; char *tls_key_path; + char *algorithm; }; typedef enum _LinphoneIsComposingState { diff --git a/include/linphone/auth_info.h b/include/linphone/auth_info.h index c14433056..0eec7924f 100644 --- a/include/linphone/auth_info.h +++ b/include/linphone/auth_info.h @@ -52,8 +52,10 @@ extern "C" { * passed through linphone_core_add_auth_info(). **/ LINPHONE_PUBLIC LinphoneAuthInfo *linphone_auth_info_new(const char *username, const char *userid, - const char *passwd, const char *ha1,const char *realm, const char *domain); - + const char *passwd, const char *ha1,const char *realm, const char *domain); + +LINPHONE_PUBLIC LinphoneAuthInfo *linphone_auth_info_new_for_algorithm(const char *username, const char *userid, + const char *passwd, const char *ha1,const char *realm, const char *domain, const char *algorithm); /** * Instantiates a new auth info with values from source. * @param[in] source The #LinphoneAuthInfo object to be cloned diff --git a/src/c-wrapper/internal/c-sal.cpp b/src/c-wrapper/internal/c-sal.cpp index 32a1633bb..69f6842fb 100644 --- a/src/c-wrapper/internal/c-sal.cpp +++ b/src/c-wrapper/internal/c-sal.cpp @@ -762,6 +762,7 @@ SalAuthInfo* sal_auth_info_clone(const SalAuthInfo* auth_info) { new_auth_info->realm=auth_info->realm?ms_strdup(auth_info->realm):NULL; new_auth_info->domain=auth_info->realm?ms_strdup(auth_info->domain):NULL; new_auth_info->password=auth_info->password?ms_strdup(auth_info->password):NULL; + new_auth_info->algorithm=auth_info->algorithm?ms_strdup(auth_info->algorithm):NULL; return new_auth_info; } @@ -774,6 +775,7 @@ void sal_auth_info_delete(SalAuthInfo* auth_info) { if (auth_info->ha1) ms_free(auth_info->ha1); if (auth_info->certificates) sal_certificates_chain_delete(auth_info->certificates); if (auth_info->key) sal_signing_key_delete(auth_info->key); + if (auth_info->algorithm) ms_free(auth_info->algorithm); ms_free(auth_info); } diff --git a/src/c-wrapper/internal/c-sal.h b/src/c-wrapper/internal/c-sal.h index 6b869f02b..10d58ad11 100644 --- a/src/c-wrapper/internal/c-sal.h +++ b/src/c-wrapper/internal/c-sal.h @@ -474,6 +474,7 @@ typedef struct SalAuthInfo{ char *realm; char *domain; char *ha1; + char *algorithm; SalAuthMode mode; belle_sip_signing_key_t *key; belle_sip_certificates_chain_t *certificates; @@ -488,6 +489,9 @@ SalAuthInfo* sal_auth_info_new(void); SalAuthInfo* sal_auth_info_clone(const SalAuthInfo* auth_info); void sal_auth_info_delete(SalAuthInfo* auth_info); LINPHONE_PUBLIC int sal_auth_compute_ha1(const char* userid,const char* realm,const char* password, char ha1[33]); +LINPHONE_PUBLIC int sal_auth_compute_ha1_for_algorithm(const char* userid,const char* realm,const char* password, char *ha1,size_t size,const char* algo); +/*LINPHONE_PUBLIC int sal_auth_compute_ha1_for_algorithm(const char* userid,const char* realm,const char* password, char *ha1, + size_t size, const char* algo);*/ SalAuthMode sal_auth_info_get_mode(const SalAuthInfo* auth_info); belle_sip_signing_key_t *sal_auth_info_get_signing_key(const SalAuthInfo* auth_info); belle_sip_certificates_chain_t *sal_auth_info_get_certificates_chain(const SalAuthInfo* auth_info); diff --git a/tester/register_tester.c b/tester/register_tester.c index a40817f89..05806abfc 100644 --- a/tester/register_tester.c +++ b/tester/register_tester.c @@ -113,7 +113,7 @@ static void register_with_refresh_base_3(LinphoneCore* lc if (counters->number_of_auth_info_requested>0 && linphone_proxy_config_get_state(proxy_cfg) == LinphoneRegistrationFailed && late_auth_info) { if (!linphone_core_get_auth_info_list(lc)) { BC_ASSERT_EQUAL(linphone_proxy_config_get_error(proxy_cfg),LinphoneReasonUnauthorized, int, "%d"); - info=linphone_auth_info_new(test_username,NULL,test_password,NULL,auth_domain,NULL); /*create authentication structure from identity*/ + info=linphone_auth_info_new(test_username,NULL,test_password,NULL,auth_domain,NULL); /*create authentication structure from identity*/ linphone_core_add_auth_info(lc,info); /*add authentication info to LinphoneCore*/ linphone_auth_info_unref(info); } @@ -165,7 +165,7 @@ static void register_with_refresh_with_send_error(void) { int retry=0; LinphoneCoreManager* lcm = create_lcm_with_auth(1); stats* counters = &lcm->stat; - LinphoneAuthInfo *info=linphone_auth_info_new(test_username,NULL,test_password,NULL,auth_domain,NULL); /*create authentication structure from identity*/ + LinphoneAuthInfo *info=linphone_auth_info_new(test_username,NULL,test_password,NULL,auth_domain,NULL); /*create authentication structure from identity*/ char route[256]; sprintf(route,"sip:%s",test_route); linphone_core_add_auth_info(lcm->lc,info); /*add authentication info to LinphoneCore*/ @@ -310,7 +310,7 @@ static void simple_tls_register(void){ static void simple_authenticated_register(void){ stats* counters; LinphoneCoreManager* lcm = create_lcm(); - LinphoneAuthInfo *info=linphone_auth_info_new(test_username,NULL,test_password,NULL,auth_domain,NULL); /*create authentication structure from identity*/ + LinphoneAuthInfo *info=linphone_auth_info_new_for_algorithm(test_username,NULL,test_password,NULL,auth_domain,NULL,NULL); /*create authentication structure from identity*/ char route[256]; sprintf(route,"sip:%s",test_route); linphone_core_add_auth_info(lcm->lc,info); /*add authentication info to LinphoneCore*/ @@ -321,6 +321,20 @@ static void simple_authenticated_register(void){ linphone_core_manager_destroy(lcm); } +static void simple_authenticated_register_for_algorithm(void){ + stats* counters; + LinphoneCoreManager* lcm = create_lcm(); + LinphoneAuthInfo *info=linphone_auth_info_new_for_algorithm(test_username,NULL,test_password,NULL,auth_domain,NULL,"SHA-256"); /*create authentication structure from identity*/ + char route[256]; + sprintf(route,"sip:%s",test_route); + linphone_core_add_auth_info(lcm->lc,info); /*add authentication info to LinphoneCore*/ + linphone_auth_info_unref(info); + counters = &lcm->stat; + register_with_refresh(lcm,FALSE,auth_domain,route); + BC_ASSERT_EQUAL(counters->number_of_auth_info_requested,0, int, "%d"); + linphone_core_manager_destroy(lcm); +} + static void ha1_authenticated_register(void){ stats* counters; LinphoneCoreManager* lcm = create_lcm(); @@ -328,7 +342,7 @@ static void ha1_authenticated_register(void){ LinphoneAuthInfo *info; char route[256]; sal_auth_compute_ha1(test_username,auth_domain,test_password,ha1); - info=linphone_auth_info_new(test_username,NULL,NULL,ha1,auth_domain,NULL); /*create authentication structure from identity*/ + info=linphone_auth_info_new_for_algorithm(test_username,NULL,NULL,ha1,auth_domain,NULL,NULL); /*create authentication structure from identity*/ sprintf(route,"sip:%s",test_route); linphone_core_add_auth_info(lcm->lc,info); /*add authentication info to LinphoneCore*/ linphone_auth_info_unref(info); @@ -338,6 +352,23 @@ static void ha1_authenticated_register(void){ linphone_core_manager_destroy(lcm); } +static void ha1_authenticated_register_for_algorithm(void){ + stats* counters; + LinphoneCoreManager* lcm = create_lcm(); + char ha1[65]; + LinphoneAuthInfo *info; + char route[256]; + sal_auth_compute_ha1_for_algorithm(test_username,auth_domain,test_password,ha1,65,"SHA-256"); + info=linphone_auth_info_new_for_algorithm(test_username,NULL,NULL,ha1,auth_domain,NULL,"SHA-256"); /*create authentication structure from identity*/ + sprintf(route,"sip:%s",test_route); + linphone_core_add_auth_info(lcm->lc,info); /*add authentication info to LinphoneCore*/ + linphone_auth_info_unref(info); + counters = &lcm->stat; + register_with_refresh(lcm,FALSE,auth_domain,route); + BC_ASSERT_EQUAL(counters->number_of_auth_info_requested,0, int, "%d"); + linphone_core_manager_destroy(lcm); +} + static void authenticated_register_with_no_initial_credentials(void){ LinphoneCoreManager *lcm; LinphoneCoreCbs *cbs = linphone_factory_create_core_cbs(linphone_factory_get()); @@ -1243,7 +1274,9 @@ test_t register_tests[] = { TEST_NO_TAG("TLS certificate given by string instead of file",tls_certificate_data), TEST_NO_TAG("TLS with non tls server",tls_with_non_tls_server), TEST_NO_TAG("Simple authenticated register", simple_authenticated_register), + TEST_NO_TAG("Simple authenticated register SHA-256", simple_authenticated_register_for_algorithm), TEST_NO_TAG("Ha1 authenticated register", ha1_authenticated_register), + TEST_NO_TAG("Ha1 authenticated register SHA-256", ha1_authenticated_register_for_algorithm), TEST_NO_TAG("Digest auth without initial credentials", authenticated_register_with_no_initial_credentials), TEST_NO_TAG("Digest auth with wrong credentials", authenticated_register_with_wrong_credentials), TEST_NO_TAG("Digest auth with wrong credentials, check if registration attempts are stopped", authenticated_register_with_wrong_credentials_2),