-
johan authored60047fe5
/*
* Copyright (c) 2010-2025 Belledonne Communications SARL.
*
* This file is part of Liblinphone
* (see https://gitlab.linphone.org/BC/public/liblinphone).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "bctoolbox/defs.h"
#include "account/account.h"
#include "auth-info/auth-info.h"
#include "auth-info/bearer-token.h"
#include "c-wrapper/c-wrapper.h"
#include "http/http-client.h"
#include "linphone/api/c-auth-info.h"
#include "linphone/core.h"
#include "linphone/lpconfig.h"
#include "sal/sal.h"
// TODO: From coreapi. Remove me later.
#include "private.h"
using namespace ::LinphonePrivate;
/**
* Destroys a LinphoneAuthInfo object.
**/
void linphone_auth_info_destroy(LinphoneAuthInfo *obj) {
belle_sip_object_unref(obj);
}
static char *remove_quotes(char *input) {
char *tmp;
if (*input == '"') input++;
tmp = strchr(input, '"');
if (tmp) *tmp = '\0';
return input;
}
static bool_t realm_match(const char *realm1, const char *realm2) {
if (realm1 == NULL && realm2 == NULL) return TRUE;
if (realm1 != NULL && realm2 != NULL) {
if (strcmp(realm1, realm2) == 0) return TRUE;
else {
char tmp1[128];
char tmp2[128];
char *p1, *p2;
strncpy(tmp1, realm1, sizeof(tmp1) - 1);
strncpy(tmp2, realm2, sizeof(tmp2) - 1);
p1 = remove_quotes(tmp1);
p2 = remove_quotes(tmp2);
return strcmp(p1, p2) == 0;
}
}
return FALSE;
}
7172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
/* Check if the LinphoneAuthInfo candidate is compatible with the requested algorithm. */
static bool_t check_algorithm_compatibility(const LinphoneAuthInfo *ai, const char *algorithm) {
const char *ai_algorithm = linphone_auth_info_get_algorithm(ai);
if (algorithm == NULL) return TRUE;
if (linphone_auth_info_get_password(ai) != NULL) {
/* We have the clear text password, so if the user didn't requested a specific algorithm, we can satisfy all
* algorithms.*/
if (ai_algorithm == NULL) return TRUE;
} else if (linphone_auth_info_get_ha1(ai)) {
/* If we don't have the clear text password but the ha1, and if algorithm is empty in LinphoneAuthInfo
* for backward compatibility, we assume it is MD5. */
if (ai_algorithm == NULL && strcasecmp(algorithm, "MD5") == 0) return TRUE;
} /*else*/
/* In all other cases, algorithm must match. */
if (ai_algorithm && strcasecmp(algorithm, ai_algorithm) == 0) return TRUE; /* algorithm do match */
return FALSE;
}
static LinphoneAuthInfo *find_auth_info(LinphoneCore *lc,
const char *username,
const char *realm,
const char *domain,
const char *algorithm,
bool_t ignore_realm) {
bctbx_list_t *elem;
LinphoneAuthInfo *ret = NULL;
if (!username && !realm && !domain && !algorithm) {
ms_error("Looking for an auth info but all search criterias are null!");
return NULL;
}
for (elem = lc->auth_info; elem != NULL; elem = elem->next) {
LinphoneAuthInfo *pinfo = (LinphoneAuthInfo *)elem->data;
if (!username || (username && linphone_auth_info_get_username(pinfo) &&
strcmp(username, linphone_auth_info_get_username(pinfo)) == 0)) {
if (!check_algorithm_compatibility(pinfo, algorithm)) {
continue;
}
if (realm && domain) {
if (linphone_auth_info_get_realm(pinfo) && realm_match(realm, linphone_auth_info_get_realm(pinfo)) &&
linphone_auth_info_get_domain(pinfo) && strcmp(domain, linphone_auth_info_get_domain(pinfo)) == 0) {
return pinfo;
}
} else if (realm) {
if (linphone_auth_info_get_realm(pinfo) && realm_match(realm, linphone_auth_info_get_realm(pinfo))) {
if (ret != NULL) {
ms_warning("find_auth_info(): Non unique realm found for %s", username);
return NULL;
}
ret = pinfo;
}
} else if (domain && linphone_auth_info_get_domain(pinfo) &&
strcmp(domain, linphone_auth_info_get_domain(pinfo)) == 0 &&
(linphone_auth_info_get_ha1(pinfo) == NULL || ignore_realm)) {
return pinfo;
} else if (!domain && (linphone_auth_info_get_ha1(pinfo) == NULL || ignore_realm)) {
return pinfo;
}
}
}
return ret;
}
LinphoneAuthInfo *
_linphone_core_find_indexed_tls_auth_info(LinphoneCore *lc, const char *username, const char *domain) {
bctbx_list_t *elem;
141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
for (elem = lc->auth_info; elem != NULL; elem = elem->next) {
LinphoneAuthInfo *pinfo = (LinphoneAuthInfo *)elem->data;
// if auth info holds tls_cert and key or a path to them
if ((linphone_auth_info_get_tls_cert(pinfo) && linphone_auth_info_get_tls_key(pinfo)) ||
(linphone_auth_info_get_tls_cert_path(pinfo) && linphone_auth_info_get_tls_key_path(pinfo))) {
// check it matches requested username/domain, when username is NULL, just check the domain
if (((username == NULL) || (username && linphone_auth_info_get_username(pinfo) &&
(strcmp(username, linphone_auth_info_get_username(pinfo)) == 0))) &&
(domain && linphone_auth_info_get_domain(pinfo) &&
(strcmp(domain, linphone_auth_info_get_domain(pinfo)) == 0))) {
return pinfo;
}
}
}
return NULL;
}
LinphoneAuthInfo *_linphone_core_find_tls_auth_info(LinphoneCore *lc) {
bctbx_list_t *elem;
for (elem = lc->auth_info; elem != NULL; elem = elem->next) {
LinphoneAuthInfo *pinfo = (LinphoneAuthInfo *)elem->data;
if (linphone_auth_info_get_tls_cert(pinfo) && linphone_auth_info_get_tls_key(pinfo)) {
return pinfo;
} else if (linphone_auth_info_get_tls_cert_path(pinfo) && linphone_auth_info_get_tls_key_path(pinfo)) {
return pinfo;
}
}
return NULL;
}
LinphoneAuthInfo *_linphone_core_find_auth_info(LinphoneCore *lc,
const char *realm,
const char *username,
const char *domain,
const char *algorithm,
bool_t ignore_realm) {
LinphoneAuthInfo *ai = NULL;
if (realm) {
ai = find_auth_info(lc, username, realm, NULL, algorithm, FALSE);
if (ai == NULL && domain) {
ai = find_auth_info(lc, username, realm, domain, algorithm, FALSE);
}
}
if (ai == NULL && domain != NULL) {
ai = find_auth_info(lc, username, NULL, domain, algorithm, ignore_realm);
}
if (ai == NULL) {
ai = find_auth_info(lc, username, NULL, NULL, algorithm, ignore_realm);
}
if (ai && ((linphone_auth_info_get_expires(ai) != 0) && (linphone_auth_info_get_expires(ai) <= time(nullptr)))) {
lc->auth_info = bctbx_list_remove(lc->auth_info, ai);
linphone_auth_info_unref(ai);
linphone_core_write_auth_infos(lc);
ai = NULL;
}
if (ai)
ms_message("linphone_core_find_auth_info(): returning auth info username=%s, realm=%s",
linphone_auth_info_get_username(ai) ? linphone_auth_info_get_username(ai) : "",
linphone_auth_info_get_realm(ai) ? linphone_auth_info_get_realm(ai) : "");
return ai;
}
const LinphoneAuthInfo *
linphone_core_find_auth_info(LinphoneCore *lc, const char *realm, const char *username, const char *domain) {
return _linphone_core_find_auth_info(lc, realm, username, domain, NULL, TRUE);
}
const LinphoneAuthInfo *linphone_core_find_auth_info_to_be_replaced(LinphoneCore *lc, const LinphoneAuthInfo *other) {
211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
bctbx_list_t *elem;
const AuthInfo *cppOther = AuthInfo::toCpp(other);
for (elem = lc->auth_info; elem != NULL; elem = elem->next) {
AuthInfo *pinfo = AuthInfo::toCpp((LinphoneAuthInfo *)elem->data);
if (cppOther->getUsername() != pinfo->getUsername()) continue;
if (cppOther->getRealm() != pinfo->getRealm()) continue;
if (cppOther->getDomain() != pinfo->getDomain()) continue;
if ((cppOther->getAccessToken() != nullptr) ^ (pinfo->getAccessToken() != nullptr))
continue; /* not of the same type */
return pinfo->toC();
}
return nullptr;
}
LinphoneAuthInfo *
_linphone_core_find_bearer_auth_info(LinphoneCore *lc, const char *realm, const char *username, const char *domain) {
bctbx_list_t *elem;
LinphoneAuthInfo *ret = NULL;
for (elem = lc->auth_info; elem != NULL; elem = elem->next) {
LinphoneAuthInfo *pinfo = (LinphoneAuthInfo *)elem->data;
if (!AuthInfo::toCpp(pinfo)->getAccessToken() && !AuthInfo::toCpp(pinfo)->getRefreshToken()) continue;
if (!username || (username && linphone_auth_info_get_username(pinfo) &&
strcmp(username, linphone_auth_info_get_username(pinfo)) == 0)) {
if (realm && domain) {
if (linphone_auth_info_get_realm(pinfo) && realm_match(realm, linphone_auth_info_get_realm(pinfo)) &&
linphone_auth_info_get_domain(pinfo) && strcmp(domain, linphone_auth_info_get_domain(pinfo)) == 0) {
ret = pinfo;
break;
}
}
if (realm && linphone_auth_info_get_realm(pinfo) &&
realm_match(realm, linphone_auth_info_get_realm(pinfo))) {
if (ret != NULL) {
ms_warning("Non unique realm found for %s", username ? username : "");
}
ret = pinfo;
} else if (domain && linphone_auth_info_get_domain(pinfo) &&
strcmp(domain, linphone_auth_info_get_domain(pinfo)) == 0) {
ret = pinfo;
}
}
}
if (ret) {
ms_message("_linphone_core_find_bearer_auth_info(): returning auth info username=%s, realm=%s, domain=%s",
AuthInfo::toCpp(ret)->getUsername().c_str(), AuthInfo::toCpp(ret)->getRealm().c_str(),
AuthInfo::toCpp(ret)->getDomain().c_str());
} else if (username && (realm || domain)) {
/* do the search without username. Not so elegant to use recursion here. */
ret = _linphone_core_find_bearer_auth_info(lc, realm, NULL, domain);
}
return ret;
}
/*the auth info is expected to be in the core's list*/
void linphone_core_write_auth_info(LinphoneCore *lc, LinphoneAuthInfo *ai) {
int i;
bctbx_list_t *elem = lc->auth_info;
if (!lc->sip_conf.save_auth_info || linphone_config_is_readonly(lc->config)) return;
for (i = 0; elem != NULL; elem = elem->next, i++) {
if (ai == elem->data) {
linphone_auth_info_write_config(lc->config, ai, i);
}
}
}
281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
void linphone_core_write_auth_infos(LinphoneCore *lc) {
bctbx_list_t *elem;
int i;
auto state = linphone_core_get_global_state(lc);
if (state == LinphoneGlobalShutdown || state == LinphoneGlobalOn) {
if (!lc->sip_conf.save_auth_info || linphone_config_is_readonly(lc->config)) return;
for (elem = lc->auth_info, i = 0; elem != NULL; elem = bctbx_list_next(elem), i++) {
LinphoneAuthInfo *ai = (LinphoneAuthInfo *)(elem->data);
linphone_auth_info_write_config(lc->config, ai, i);
}
linphone_auth_info_write_config(lc->config, NULL, i); /* mark the end */
}
}
LinphoneAuthInfo *linphone_core_create_auth_info(BCTBX_UNUSED(LinphoneCore *lc),
const char *username,
const char *userid,
const char *passwd,
const char *ha1,
const char *realm,
const char *domain) {
return linphone_auth_info_new(username, userid, passwd, ha1, realm, domain);
}
void linphone_core_add_auth_info(LinphoneCore *lc, const LinphoneAuthInfo *info) {
LinphoneAuthInfo *ai = NULL;
size_t restarted_op_count = 0;
bool_t updating = FALSE;
if (!linphone_auth_info_get_tls_key(info) && !linphone_auth_info_get_tls_key_path(info) &&
!linphone_auth_info_get_ha1(info) && !linphone_auth_info_get_password(info) &&
!linphone_auth_info_get_access_token(info) && !linphone_auth_info_get_refresh_token(info)) {
ms_error(
"linphone_core_add_auth_info(): info supplied with empty password, ha1, TLS client/key or bearer token.");
return;
}
/* find if we are attempting to modify an existing auth info */
ai = (LinphoneAuthInfo *)linphone_core_find_auth_info_to_be_replaced(lc, info);
if (ai != NULL) {
lInfo() << "linphone_core_add_auth_info(): replacing existing auth info.";
lc->auth_info = bctbx_list_remove(lc->auth_info, ai);
linphone_auth_info_unref(ai);
updating = TRUE;
}
lc->auth_info = bctbx_list_append(lc->auth_info, linphone_auth_info_clone(info));
/* retry pending authentication operations */
auto pendingAuths = lc->sal->getPendingAuths();
if (!pendingAuths.empty()) {
lInfo() << "Restarting operations pending authentications...";
}
for (const auto &op : pendingAuths) {
LinphoneAuthInfo *ai;
const SalAuthInfo *req_sai = op->getAuthRequested();
ai = (LinphoneAuthInfo *)_linphone_core_find_auth_info(lc, req_sai->realm, req_sai->username, req_sai->domain,
req_sai->algorithm, FALSE);
if (ai) {
/*account case*/
const bctbx_list_t *account;
for (account = linphone_core_get_account_list(lc); account != NULL; account = account->next) {
if (account->data == op->getUserPointer()) {
LinphonePrivate::Account::toCpp((LinphoneAccount *)account->data)
->setState(LinphoneRegistrationProgress, "Authentication...");
break;
}
}
op->authenticate();
351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
restarted_op_count++;
}
}
restarted_op_count += L_GET_CPP_PTR_FROM_C_OBJECT(lc)->getHttpClient().retryPendingRequests();
if (!pendingAuths.empty() || restarted_op_count > 0) {
ms_message("linphone_core_add_auth_info(): restarted [%i] operation(s) after %s auth info for\n"
"\tusername: [%s]\n"
"\trealm [%s]\n"
"\tdomain [%s]\n",
(int)restarted_op_count, updating ? "updating" : "adding",
linphone_auth_info_get_username(info) ? linphone_auth_info_get_username(info) : "",
linphone_auth_info_get_realm(info) ? linphone_auth_info_get_realm(info) : "",
linphone_auth_info_get_domain(info) ? linphone_auth_info_get_domain(info) : "");
}
linphone_core_write_auth_infos(lc);
}
void linphone_core_abort_authentication(LinphoneCore *lc, BCTBX_UNUSED(const LinphoneAuthInfo *info)) {
size_t count = L_GET_CPP_PTR_FROM_C_OBJECT(lc)->getHttpClient().abortPendingRequests();
lInfo() << "Aborting " << count << " requests awaiting authentication information.";
}
void linphone_core_remove_auth_info(LinphoneCore *lc, const LinphoneAuthInfo *info) {
LinphoneAuthInfo *r;
r = (LinphoneAuthInfo *)linphone_core_find_auth_info(lc, linphone_auth_info_get_realm(info),
linphone_auth_info_get_username(info),
linphone_auth_info_get_domain(info));
if (r) {
lc->auth_info = bctbx_list_remove(lc->auth_info, r);
linphone_auth_info_unref(r);
linphone_core_write_auth_infos(lc);
}
}
const bctbx_list_t *linphone_core_get_auth_info_list(const LinphoneCore *lc) {
return lc->auth_info;
}
void linphone_core_clear_all_auth_info(LinphoneCore *lc) {
bctbx_list_t *elem;
int i;
for (i = 0, elem = lc->auth_info; elem != NULL; elem = bctbx_list_next(elem), i++) {
LinphoneAuthInfo *info = (LinphoneAuthInfo *)elem->data;
linphone_auth_info_unref(info);
linphone_auth_info_write_config(lc->config, NULL, i);
}
bctbx_list_free(lc->auth_info);
lc->auth_info = NULL;
}
void linphone_auth_info_fill_belle_sip_event(const LinphoneAuthInfo *auth_info, belle_sip_auth_event *event) {
if (auth_info) {
const char *auth_username = linphone_auth_info_get_username(auth_info);
const char *auth_user_id = linphone_auth_info_get_userid(auth_info);
const char *auth_password = linphone_auth_info_get_password(auth_info);
const char *auth_ha1 = linphone_auth_info_get_ha1(auth_info);
const char *auth_algo = linphone_auth_info_get_algorithm(auth_info);
const LinphoneBearerToken *access_token = linphone_auth_info_get_access_token(auth_info);
belle_sip_auth_event_set_username(event, auth_username);
belle_sip_auth_event_set_userid(event, auth_user_id);
belle_sip_auth_event_set_passwd(event, auth_password);
belle_sip_auth_event_set_ha1(event, auth_ha1);
belle_sip_auth_event_set_algorithm(event, auth_algo);
if (access_token) {
belle_sip_auth_event_set_bearer_token(event,
LinphonePrivate::BearerToken::toCpp(access_token)->getImpl()->toC());
}
}
421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490
}
/**
* @brief Fill the requested authentication event from the given linphone core
* If the authentication event is a TLS one, username(optionnal) and domain should be given as parameter
*
* @Warning This function assumes the authentication information were already provided to the core (at application start
* or when registering on flexisip) and won't call the linphone_core_notify_authentication_requested to give the
* application an other chance to fill the auth_info into the core.
*
* @param[in] lc The linphone core used to access the auth_info
* @param[in/out] event The belle sip auth event to fill with requested authentication credentials
* @param[in] username Used only when auth mode is TLS to get a matching client certificate. If empty, look for
* any certificate matching domain nane
* @param[in] domain Used only when auth mode is TLS to get a matching client certificate.
* @return an AuthStatus value
* @note It is not possible to know whether the TLS server requested a client certificate: true is always returned for
* TLS authentication.
*/
AuthStatus linphone_core_fill_belle_sip_auth_event(LinphoneCore *lc,
belle_sip_auth_event *event,
const char *username,
const char *domain) {
AuthStatus status = AuthStatus::NoAuth;
const char *realm = belle_sip_auth_event_get_realm(event);
const char *ae_username = belle_sip_auth_event_get_username(event);
const char *ae_domain = belle_sip_auth_event_get_domain(event);
LinphoneAuthMethod requestedMethod = LinphoneAuthHttpDigest;
int try_count = belle_sip_auth_event_get_try_count(event);
int max_tries = 2;
switch (belle_sip_auth_event_get_mode(event)) {
case BELLE_SIP_AUTH_MODE_HTTP_DIGEST: {
const char *algorithm = belle_sip_auth_event_get_algorithm(event);
const LinphoneAuthInfo *auth_info =
_linphone_core_find_auth_info(lc, realm, ae_username, ae_domain, algorithm, TRUE);
if (auth_info) {
linphone_auth_info_fill_belle_sip_event(auth_info, event);
status = AuthStatus::Done;
}
max_tries = 2; /* server nonce may change, we can two consecutive 401.*/
requestedMethod = LinphoneAuthHttpDigest;
} break;
case BELLE_SIP_AUTH_MODE_HTTP_BASIC: {
const char *algorithm = belle_sip_auth_event_get_algorithm(event);
const LinphoneAuthInfo *auth_info =
_linphone_core_find_auth_info(lc, realm, ae_username, ae_domain, algorithm, FALSE);
if (auth_info) {
linphone_auth_info_fill_belle_sip_event(auth_info, event);
status = AuthStatus::Done;
}
max_tries = 1;
requestedMethod = LinphoneAuthBasic;
} break;
case BELLE_SIP_AUTH_MODE_HTTP_BEARER: {
max_tries = 1;
const LinphoneAuthInfo *auth_info = _linphone_core_find_bearer_auth_info(lc, realm, ae_username, ae_domain);
if (auth_info) {
auto bearerToken = AuthInfo::toCpp(auth_info)->getAccessToken();
auto refreshToken = AuthInfo::toCpp(auth_info)->getRefreshToken();
if (refreshToken &&
(bearerToken->isExpired() || (bearerToken->getExpirationTime() == 0 && try_count >= 1))) {
/* We know that the access token is expired, or we have a failure with the access token.
* As we have a refresh token, make a refresh attempt */
lInfo() << "Token is or might be expired, using refresh token to get new one.";
if (L_GET_CPP_PTR_FROM_C_OBJECT(lc)->refreshTokens(
AuthInfo::toCpp(const_cast<LinphoneAuthInfo *>(auth_info))->getSharedFromThis())) {
status = AuthStatus::Pending;
} else status = AuthStatus::NoAuth;
} else {
491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560
linphone_auth_info_fill_belle_sip_event(auth_info, event);
status = AuthStatus::Done;
}
max_tries = refreshToken ? 2 : 1;
}
requestedMethod = LinphoneAuthBearer;
} break;
case BELLE_SIP_AUTH_MODE_TLS: {
/* extract username and domain from the GRUU stored in userData->username */
const char *cert_chain_path = nullptr;
const char *key_path = nullptr;
const char *cert_chain = nullptr;
const char *key = nullptr;
const LinphoneAuthInfo *auth_info;
if (domain == NULL) domain = ae_domain;
auth_info = _linphone_core_find_indexed_tls_auth_info(lc, username, domain);
if (auth_info) { /* tls_auth_info found something */
if (linphone_auth_info_get_tls_cert(auth_info) && linphone_auth_info_get_tls_key(auth_info)) {
cert_chain = linphone_auth_info_get_tls_cert(auth_info);
key = linphone_auth_info_get_tls_key(auth_info);
} else if (linphone_auth_info_get_tls_cert_path(auth_info) &&
linphone_auth_info_get_tls_key_path(auth_info)) {
cert_chain_path = linphone_auth_info_get_tls_cert_path(auth_info);
key_path = linphone_auth_info_get_tls_key_path(auth_info);
}
} else { /* get directly from linphonecore
or given in the sip/client_cert_chain in the config file, no username/domain associated with it,
last resort try it shall work if we have only one user */
cert_chain = linphone_core_get_tls_cert(lc);
key = linphone_core_get_tls_key(lc);
if (!cert_chain || !key) {
cert_chain_path = linphone_core_get_tls_cert_path(lc);
key_path = linphone_core_get_tls_key_path(lc);
}
}
if (cert_chain != nullptr && key != nullptr) {
belle_sip_certificates_chain_t *bs_cert_chain = belle_sip_certificates_chain_parse(
cert_chain, strlen(cert_chain), BELLE_SIP_CERTIFICATE_RAW_FORMAT_PEM);
belle_sip_signing_key_t *bs_key = belle_sip_signing_key_parse(key, strlen(key), nullptr);
if (bs_cert_chain && bs_key) {
belle_sip_auth_event_set_signing_key(event, bs_key);
belle_sip_auth_event_set_client_certificates_chain(event, bs_cert_chain);
}
} else if (cert_chain_path != nullptr && key_path != nullptr) {
belle_sip_certificates_chain_t *bs_cert_chain =
belle_sip_certificates_chain_parse_file(cert_chain_path, BELLE_SIP_CERTIFICATE_RAW_FORMAT_PEM);
belle_sip_signing_key_t *bs_key = belle_sip_signing_key_parse_file(key_path, nullptr);
if (bs_cert_chain && bs_key) {
belle_sip_auth_event_set_signing_key(event, bs_key);
belle_sip_auth_event_set_client_certificates_chain(event, bs_cert_chain);
}
} else {
lInfo() << "No TLS client certificate to propose.";
// To enable callback:
// - create an AuthInfo object with username and domain
// - call linphone_core_notify_authentication_requested on it to give the app a chance to fill the
// auth_info.
// - call again _linphone_core_find_indexed_tls_auth_info to retrieve the auth_info set by the
// callback. Not done as we assume that authentication on flexisip server was performed before so the
// application layer already got a chance to set the correct auth_info in the core
// THIS IS NOT TRUE ANYMORE: Flexisip auth is performed after the access to the lime server as the
// register is performed after the lime user creation.
}
status =
AuthStatus::Done; // since we can't know if server requested a client certificate, assume all is good.
requestedMethod = LinphoneAuthTls;
max_tries = 1;
} break;
default:
561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599
lError() << "Connection gets an auth event of unexpected type";
status = AuthStatus::NoAuth;
break;
}
if (status == AuthStatus::NoAuth || try_count >= max_tries) {
/* We do not prompt the application for authentication info for http services, because it may happen
* for various kind of events but user is not expected to supply them on the fly.
* However, for provisioning process, for which bearer or digest is likely to be requested,
* we notify the application.
* The provisioning is then suspended until authentication information is supplied, or
* authentication is aborted using linphone_core_abort_authentication().
*/
if (linphone_core_get_global_state(lc) == LinphoneGlobalConfiguring) {
LinphoneAuthInfo *ai =
linphone_factory_create_auth_info(linphone_factory_get(), ae_username,
belle_sip_auth_event_get_userid(event), NULL, NULL, realm, ae_domain);
linphone_auth_info_set_algorithm(ai, belle_sip_auth_event_get_algorithm(event));
linphone_auth_info_set_authorization_server(ai, belle_sip_auth_event_get_authz_server(event));
linphone_core_notify_authentication_requested(lc, ai, requestedMethod);
linphone_auth_info_unref(ai);
status = AuthStatus::Pending;
}
}
return status;
}
void linphone_core_set_digest_authentication_policy(LinphoneCore *core, LinphoneDigestAuthenticationPolicy *policy) {
belle_sip_stack_t *stack = reinterpret_cast<belle_sip_stack_t *>(core->sal->getStackImpl());
belle_sip_stack_set_digest_authentication_policy(stack, (belle_sip_digest_authentication_policy_t *)policy);
if (linphone_core_ready(core)) {
linphone_digest_authentication_policy_save(policy, core->config);
}
}
const LinphoneDigestAuthenticationPolicy *linphone_core_get_digest_authentication_policy(const LinphoneCore *core) {
belle_sip_stack_t *stack = reinterpret_cast<belle_sip_stack_t *>(core->sal->getStackImpl());
return (const LinphoneDigestAuthenticationPolicy *)belle_sip_stack_get_digest_authentication_policy(stack);
}