diff --git a/coreapi/bellesip_sal/sal_impl.c b/coreapi/bellesip_sal/sal_impl.c index f1daaa1bd..af7d077c7 100644 --- a/coreapi/bellesip_sal/sal_impl.c +++ b/coreapi/bellesip_sal/sal_impl.c @@ -22,6 +22,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #ifdef HAVE_CONFIG_H #include "config.h" #endif + +typedef struct belle_sip_certificates_chain_t _SalCertificatesChain; +typedef struct belle_sip_signing_key_t _SalSigningKey; + /* rfc3323 4.2 Expressing Privacy Preferences @@ -367,14 +371,16 @@ static void process_transaction_terminated(void *user_ctx, const belle_sip_trans } -static void process_auth_requested(void *sal, belle_sip_auth_event_t *auth_event) { - SalAuthInfo* auth_info = sal_auth_info_create(auth_event); + +static void process_auth_requested(void *sal, belle_sip_auth_event_t *event) { + SalAuthInfo* auth_info = sal_auth_info_create(event); ((Sal*)sal)->callbacks.auth_requested(sal,auth_info); - belle_sip_auth_event_set_passwd(auth_event,(const char*)auth_info->password); - belle_sip_auth_event_set_ha1(auth_event,(const char*)auth_info->ha1); - belle_sip_auth_event_set_userid(auth_event,(const char*)auth_info->userid); + belle_sip_auth_event_set_passwd(event,(const char*)auth_info->password); + belle_sip_auth_event_set_ha1(event,(const char*)auth_info->ha1); + belle_sip_auth_event_set_userid(event,(const char*)auth_info->userid); + belle_sip_auth_event_set_signing_key(event,(belle_sip_signing_key_t *)auth_info->key); + belle_sip_auth_event_set_client_certificates_chain(event,(belle_sip_certificates_chain_t* )auth_info->certificates); sal_auth_info_delete(auth_info); - return; } Sal * sal_init(){ @@ -699,9 +705,21 @@ SalAuthInfo* sal_auth_info_create(belle_sip_auth_event_t* event) { auth_info->realm = ms_strdup(belle_sip_auth_event_get_realm(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 = belle_sip_auth_event_get_mode(event); return auth_info; } +SalAuthMode sal_auth_info_get_mode(const SalAuthInfo* auth_info) { return auth_info->mode; } +SalSigningKey *sal_auth_info_get_signing_key(const SalAuthInfo* auth_info) { return auth_info->key; } +SalCertificatesChain *sal_auth_info_get_certificates_chain(const SalAuthInfo* auth_info) { return auth_info->certificates; } +void sal_auth_info_set_mode(SalAuthInfo* auth_info, SalAuthMode mode) { auth_info->mode = mode; } +void sal_certificates_chain_delete(SalCertificatesChain *chain) { + belle_sip_object_unref((belle_sip_object_t *)chain); +} +void sal_signing_key_delete(SalSigningKey *key) { + belle_sip_object_unref((belle_sip_object_t *)key); +} + const char* sal_op_type_to_string(const SalOpType type) { switch(type) { case SalOpRegister: return "SalOpRegister"; @@ -852,3 +870,23 @@ void sal_resolve_cancel(Sal *sal, SalResolverContext* ctx){ void sal_enable_unconditional_answer(Sal *sal,int value) { belle_sip_provider_enable_unconditional_answer(sal->prov,value); } + +/** Parse a file containing either a certificate chain order in PEM format or a single DER cert + * @param auth_info structure where to store the result of parsing + * @param path path to certificate chain file + * @param format either PEM or DER + */ +void sal_certificates_chain_parse_file(SalAuthInfo* auth_info, const char* path, SalCertificateRawFormat format) { + auth_info->certificates = (SalCertificatesChain*) belle_sip_certificates_chain_parse_file(path, format); // + if (auth_info->certificates) belle_sip_object_ref((belle_sip_object_t *) auth_info->certificates); +} + +/** + * Parse a file containing either a private or public rsa key + * @param auth_info structure where to store the result of parsing + * @param passwd password (optionnal) + */ +void sal_signing_key_parse_file(SalAuthInfo* auth_info, const char* path, const char *passwd) { + auth_info->key = (SalSigningKey *) belle_sip_signing_key_parse_file(path, passwd); + if (auth_info->key) belle_sip_object_ref((belle_sip_object_t *) auth_info->key); +} diff --git a/coreapi/callbacks.c b/coreapi/callbacks.c index 23f9663fa..ee125717f 100644 --- a/coreapi/callbacks.c +++ b/coreapi/callbacks.c @@ -25,6 +25,13 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "mediastreamer2/mediastream.h" #include "lpconfig.h" +// stat +#ifndef WIN32 +#include +#include +#include +#endif + static void register_failure(SalOp *op, SalError error, SalReason reason, const char *details); static int media_parameters_changed(LinphoneCall *call, SalMediaDescription *oldmd, SalMediaDescription *newmd) { @@ -901,6 +908,46 @@ static void ping_reply(SalOp *op){ } } +static const char *get_client_cert_path(LinphoneCore *lc) { + static char cldir[200] = {0}; + #ifdef HAVE_GETENV + if (!cldir[0]) { + static char default_path[200] = {0}; + snprintf(default_path, sizeof(default_path), "%s%s", getenv("HOME"), "/linphone_certs"); + snprintf(cldir, sizeof(cldir), "%s", lp_config_get_string(lc->config,"sip","client_certificates_dir", default_path)); + } + #endif + return cldir; +} +static bool_t fill_auth_info_with_client_certificate(LinphoneCore *lc, SalAuthInfo* sai) { + char chain_file[200]; + char key_file[200]; + const char *path = get_client_cert_path(lc); + + snprintf(chain_file, sizeof(chain_file), "%s%s", path, "/chain.pem"); + + snprintf(key_file, sizeof(key_file), "%s%s", path, "/key.pem"); + +#ifndef WIN32 + { + // optinal check for files + struct stat st; + if (stat(key_file,&st)) { + ms_warning("No client certificate key found in %s", key_file); + return FALSE; + } + if (stat(chain_file,&st)) { + ms_warning("No client certificate chain found in %s", chain_file); + return FALSE; + } + } +#endif + + sal_certificates_chain_parse_file(sai, chain_file, SAL_CERTIFICATE_RAW_FORMAT_PEM ); + sal_signing_key_parse_file(sai, key_file, ""); + return sai->certificates && sai->key; +} + static bool_t fill_auth_info(LinphoneCore *lc, SalAuthInfo* sai) { LinphoneAuthInfo *ai=(LinphoneAuthInfo*)linphone_core_find_auth_info(lc,sai->realm,sai->username,sai->domain); if (ai) { @@ -916,18 +963,25 @@ static bool_t fill_auth_info(LinphoneCore *lc, SalAuthInfo* sai) { } static bool_t auth_requested(Sal* sal, SalAuthInfo* sai) { LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal); - if (fill_auth_info(lc,sai)) { - return TRUE; - } else { - if (lc->vtable.auth_info_requested) { - lc->vtable.auth_info_requested(lc,sai->realm,sai->username,sai->domain); - if (fill_auth_info(lc,sai)) { - return TRUE; + if (sai->mode == SalAuthModeHttpDigest) { + if (fill_auth_info(lc,sai)) { + return TRUE; + } else { + if (lc->vtable.auth_info_requested) { + lc->vtable.auth_info_requested(lc,sai->realm,sai->username,sai->domain); + if (fill_auth_info(lc,sai)) { + return TRUE; + } } + return FALSE; } + } else if (sai->mode == SalAuthModeTls) { + return fill_auth_info_with_client_certificate(lc,sai); + } else { return FALSE; } } + static void notify_refer(SalOp *op, SalReferStatus status){ LinphoneCore *lc=(LinphoneCore *)sal_get_user_pointer(sal_op_get_sal(op)); LinphoneCall *call=(LinphoneCall*) sal_op_get_user_pointer(op); diff --git a/coreapi/sal.c b/coreapi/sal.c index 49e70b3c6..69ee5b6c2 100644 --- a/coreapi/sal.c +++ b/coreapi/sal.c @@ -483,6 +483,8 @@ void sal_auth_info_delete(SalAuthInfo* auth_info) { if (auth_info->realm) ms_free(auth_info->realm); if (auth_info->domain) ms_free(auth_info->domain); if (auth_info->password) ms_free(auth_info->password); + if (auth_info->certificates) sal_certificates_chain_delete(auth_info->certificates); + if (auth_info->key) sal_signing_key_delete(auth_info->key); ms_free(auth_info); } diff --git a/include/sal/sal.h b/include/sal/sal.h index ad230c9ae..86f20c60d 100644 --- a/include/sal/sal.h +++ b/include/sal/sal.h @@ -331,6 +331,29 @@ typedef enum SalTextDeliveryStatus{ SalTextDeliveryFailed }SalTextDeliveryStatus; +/** + * auth event mode + * */ +typedef enum SalAuthMode { + SalAuthModeHttpDigest, /** Digest authentication requested*/ + SalAuthModeTls /** Client certificate requested*/ +}SalAuthMode; + +struct _SalCertificatesChain; +typedef struct _SalCertificatesChain SalCertificatesChain; +struct _SalSigningKey; +typedef struct _SalSigningKey SalSigningKey; + +/** + * Format of certificate buffer + * */ +typedef enum SalCertificateRawFormat { + SAL_CERTIFICATE_RAW_FORMAT_PEM, /** PEM format*/ + SAL_CERTIFICATE_RAW_FORMAT_DER /** ASN.1 raw format*/ +}SalCertificateRawFormat; + + + typedef struct SalAuthInfo{ char *username; char *userid; @@ -338,6 +361,9 @@ typedef struct SalAuthInfo{ char *realm; char *domain; char *ha1; + SalAuthMode mode; + SalSigningKey *key; + SalCertificatesChain *certificates; }SalAuthInfo; typedef struct SalBody{ @@ -424,6 +450,29 @@ SalAuthInfo* sal_auth_info_new(); 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]); +SalAuthMode sal_auth_info_get_mode(const SalAuthInfo* auth_info); +SalSigningKey *sal_auth_info_get_signing_key(const SalAuthInfo* auth_info); +SalCertificatesChain *sal_auth_info_get_certificates_chain(const SalAuthInfo* auth_info); +void sal_auth_info_set_mode(SalAuthInfo* auth_info, SalAuthMode mode); + +/** Parse a file containing either a certificate chain order in PEM format or a single DER cert + * @param auth_info structure where to store the result of parsing + * @param path path to certificate chain file + * @param format either PEM or DER + */ +void sal_certificates_chain_parse_file(SalAuthInfo* auth_info, const char* path, SalCertificateRawFormat format); + +/** + * Parse a file containing either a private or public rsa key + * @param auth_info structure where to store the result of parsing + * @param passwd password (optionnal) + */ +void sal_signing_key_parse_file(SalAuthInfo* auth_info, const char* path, const char *passwd); + +void sal_certificates_chain_delete(SalCertificatesChain *chain); +void sal_signing_key_delete(SalSigningKey *key); + + void sal_set_callbacks(Sal *ctx, const SalCallbacks *cbs); int sal_listen_port(Sal *ctx, const char *addr, int port, SalTransport tr, int is_secure);