From 95e158bb679abee0d04452133208d552ab5eb0c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Turnel?= Date: Wed, 13 Jun 2018 14:55:07 +0200 Subject: [PATCH 1/9] Fix Sequential forking tests If a client is unreachable, flexisip will receive a 503 if the client is local but not if it doesn't. So we have to wait a little longer for the flexisip current call timeout. --- tester/flexisip_tester.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/tester/flexisip_tester.c b/tester/flexisip_tester.c index 1a178fb7e..e96c82ee0 100644 --- a/tester/flexisip_tester.c +++ b/tester/flexisip_tester.c @@ -1659,13 +1659,14 @@ void sequential_forking_with_timeout_for_highest_priority(void) { linphone_core_invite_address(pauline->lc,marie->identity); + /*second and third devices should have received the call*/ + BC_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat.number_of_LinphoneCallIncomingReceived,1,13000)); + BC_ASSERT_TRUE(wait_for_list(lcs,&marie3->stat.number_of_LinphoneCallIncomingReceived,1,3000)); /*pauline should hear ringback*/ BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallOutgoingRinging,1,3000)); /*first device should receive nothing since it is disconnected*/ BC_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallIncomingReceived, 0, int, "%d"); - /*second and third devices should have received the call*/ - BC_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat.number_of_LinphoneCallIncomingReceived,1,3000)); - BC_ASSERT_TRUE(wait_for_list(lcs,&marie3->stat.number_of_LinphoneCallIncomingReceived,1,3000)); + LinphoneCall *call = linphone_core_get_current_call(marie3->lc); if (!BC_ASSERT_PTR_NOT_NULL(call)) goto end; @@ -1718,10 +1719,10 @@ void sequential_forking_with_no_response_for_highest_priority(void) { linphone_core_invite_address(pauline->lc,marie->identity); - /*pauline should hear ringback*/ - BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallOutgoingRinging,1,3000)); /*first device should receive the call*/ BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallIncomingReceived,1,3000)); + /*pauline should hear ringback*/ + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallOutgoingRinging,1,3000)); /*second device should have not received the call yet*/ BC_ASSERT_EQUAL(marie2->stat.number_of_LinphoneCallIncomingReceived, 0, int, "%d"); @@ -1781,12 +1782,12 @@ void sequential_forking_with_insertion_of_higher_priority(void) { linphone_core_invite_address(pauline->lc,marie->identity); + /*second device should have received the call*/ + BC_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat.number_of_LinphoneCallIncomingReceived,1,13000)); /*pauline should hear ringback*/ BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallOutgoingRinging,1,3000)); /*first device should receive nothing since it is disconnected*/ BC_ASSERT_EQUAL(marie->stat.number_of_LinphoneCallIncomingReceived, 0, int, "%d"); - /*second device should have received the call*/ - BC_ASSERT_TRUE(wait_for_list(lcs,&marie2->stat.number_of_LinphoneCallIncomingReceived,1,3000)); /*we create a new device*/ LinphoneCoreManager* marie3 = linphone_core_manager_new("marie_rc"); @@ -1864,14 +1865,14 @@ void sequential_forking_with_fallback_route(void) { /*marie invites pauline2 on the other server*/ linphone_core_invite_address(marie->lc,pauline2->identity); + /*the call should be routed to the first server with pauline account*/ + BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallIncomingReceived,1,13000)); + /*marie should hear ringback*/ BC_ASSERT_TRUE(wait_for_list(lcs,&marie->stat.number_of_LinphoneCallOutgoingRinging,1,3000)); /*pauline2 should receive nothing since it is disconnected*/ BC_ASSERT_EQUAL(pauline2->stat.number_of_LinphoneCallIncomingReceived, 0, int, "%d"); - /*the call should be routed to the first server with pauline account*/ - BC_ASSERT_TRUE(wait_for_list(lcs,&pauline->stat.number_of_LinphoneCallIncomingReceived,1,3000)); - LinphoneCall *call = linphone_core_get_current_call(pauline->lc); if (!BC_ASSERT_PTR_NOT_NULL(call)) goto end; From fca153eece6b54d92de52893451fdaff0771928d Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Mon, 12 Mar 2018 12:02:26 +0100 Subject: [PATCH 2/9] Improve RPM packaging + Put executables in bindir in RPM file when tools are enabled. --- build/rpm/liblinphone.spec.cmake | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/build/rpm/liblinphone.spec.cmake b/build/rpm/liblinphone.spec.cmake index b0f030334..f2512146c 100755 --- a/build/rpm/liblinphone.spec.cmake +++ b/build/rpm/liblinphone.spec.cmake @@ -31,6 +31,9 @@ Requires: %{pkg_prefix}ortp Requires: %{pkg_prefix}mediastreamer Requires: %{pkg_prefix}belle-sip Requires: %{pkg_prefix}belr +%if @ENABLE_VCARD@ +Requires: %{pkg_prefix}belcard +%endif %if @ENABLE_SOCI_STORAGE@ Requires: %{pkg_prefix}soci %endif @@ -83,7 +86,7 @@ rm -rf $RPM_BUILD_ROOT %files %defattr(-,root,root) %doc AUTHORS ChangeLog COPYING NEWS README.md TODO -%if @ENABLE_DAEMON@ || @ENABLE_CONSOLE_UI@ +%if @ENABLE_DAEMON@ || @ENABLE_CONSOLE_UI@ || @ENABLE_TOOLS@ %{_bindir}/* %endif %{_libdir}/*.so.* From e8cb0756002864d81b38c0878da21c94ea5f298b Mon Sep 17 00:00:00 2001 From: Ghislain MARY Date: Thu, 19 Apr 2018 17:30:51 +0200 Subject: [PATCH 3/9] Remove useless files. --- tools/generator.cc | 454 -------------------------------------- tools/generator.hh | 73 ------- tools/genwrappers.cc | 482 ----------------------------------------- tools/software-desc.cc | 43 ---- tools/software-desc.hh | 470 ---------------------------------------- 5 files changed, 1522 deletions(-) delete mode 100644 tools/generator.cc delete mode 100644 tools/generator.hh delete mode 100644 tools/genwrappers.cc delete mode 100644 tools/software-desc.cc delete mode 100644 tools/software-desc.hh diff --git a/tools/generator.cc b/tools/generator.cc deleted file mode 100644 index de8528a9e..000000000 --- a/tools/generator.cc +++ /dev/null @@ -1,454 +0,0 @@ -/* -linphone -Copyright (C) 2013 Belledonne Communications SARL -Simon Morlat (simon.morlat@linphone.org) - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -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 General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - - -#include - -#include "generator.hh" - -#ifdef _WIN32 -#include - -#define strncasecmp _strnicmp -#endif - - -string to_lower(const string &str){ - string res=str; - for(string::iterator it=res.begin();it!=res.end();++it){ - *it=tolower(*it); - } - return res; -} - -CplusplusGenerator::CplusplusGenerator(){ -} - -void CplusplusGenerator::generate(Project *proj){ - list classes=proj->getClasses(); - mCurProj=proj; -#ifndef _WIN32 - mkdir(proj->getName().c_str(),S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IROTH); -#else - _mkdir(proj->getName().c_str()); -#endif - for_each(classes.begin(),classes.end(),bind1st(mem_fun(&CplusplusGenerator::writeClass),this)); -} - -void CplusplusGenerator::writeEnumMember(ConstField *cf, bool isLast){ - writeTabs(1); - mOutfile<getName()<<"="<getValue(); - if (!isLast) mOutfile<<","; - if (!cf->getHelp().empty()) mOutfile<<"\t/**< "<getHelp()<<" */"; - mOutfile<getName()<<"/"<getName()<<".hh"; - mOutfile.open(filename.str().c_str()); - if (!mOutfile.is_open()){ - cerr<<"Could not write into "< methods=klass->getMethods(); - list constFields=klass->getConstFields(); - mCurClass=klass; - mOutfile<<"/* Wrapper generated by lp-gen-wrappers, do not edit*/"<"<getName().empty()) - mOutfile<<"namespace "<getName()<<"{"<getType()==Type::Enum){ - mOutfile<<"enum "<getName()<<"{"<::iterator cfit,next; - for (cfit=constFields.begin();cfit!=constFields.end();){ - ConstField *cf=*cfit; - writeEnumMember(cf,++cfit==constFields.end()); - } - }else{ - mOutfile<<"class "<getName()<<"{"<getName().empty()) - mOutfile<<"} //end of namespace "<getName()<getType(); - - if (type->getBasicType()==Type::Class){ - if (arg->isConst()){ - mOutfile<<"const "; - } - mOutfile<getName(); - if (arg->isPointer()) - mOutfile<<"*"; - }else if (type->getBasicType()==Type::Integer){ - mOutfile<<"int"; - }else if (type->getBasicType()==Type::Enum){ - mOutfile<getName(); - }else if (type->getBasicType()==Type::String){ - if (!isReturn) - mOutfile<<"const std::string &"; - else - mOutfile<<"std::string"; - }else if (type->getBasicType()==Type::Void){ - mOutfile<<"void"; - }else if (type->getBasicType()==Type::Boolean){ - mOutfile<<"bool"; - } - if (!isReturn && !arg->getName().empty()) - mOutfile<<" "<getName(); -} - -void CplusplusGenerator::writeTabs(int ntabs){ - int i; - for(i=0;i100 && comment[i]==' ')){ - mOutfile<isCallback()) return; - - Argument *retarg=method->getReturnArg(); - const list &args=method->getArgs(); - list::const_iterator it; - - writeTabs(1); - mOutfile<<"/**"<getHelp(),1); - mOutfile<getName()<<"("; - - for(it=args.begin();it!=args.end();++it){ - if (it!=args.begin()) mOutfile<<", "; - writeArgument(*it); - } - mOutfile<<")"; - if (method->isConst()) mOutfile<<"const"; - mOutfile<<";"< classes=proj->getClasses(); - mCurProj=proj; -#ifndef _WIN32 - remove(to_lower(proj->getName()).c_str()); - mkdir(to_lower(proj->getName()).c_str(),S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IROTH); -#else - _mkdir(to_lower(proj->getName()).c_str()); -#endif - ostringstream filename; - - /*write a file for the namespace*/ - filename<getName())<<"/"<getName())<<".js"; - mOutfile.open(filename.str().c_str()); - if (!mOutfile.is_open()){ - cerr<<"Could not write into "<getName()<getName()<<" = {};"<getName(); - if (strncasecmp(enum_name.c_str(),mCurProj->getName().c_str(),mCurProj->getName().size())==0){ - //since enum is part of the namespace, drop the namespace part of the enum if any. - enum_name.erase(0,mCurProj->getName().size()); - } - return enum_name; -} - -void JavascriptGenerator::writeEnum(Class *klass){ - if (klass->getType()!=Type::Enum) return; - - ostringstream filename; - list members=klass->getConstFields(); - list::iterator it; - string enum_name=getEnumName(klass); - - filename<getName())<<"/"<getName()<<" = "<getName()<<" || {};"<getHelp(),0); - mOutfile<getName()<<"."<getHelp().empty()){ - writeTabs(1); - mOutfile<<"/**"<getHelp(),1); - mOutfile<getName().substr(prefix_size,string::npos)<<" : "<getValue(); - if (++it!=members.end()) mOutfile<<","; - mOutfile<getName() << ".get" << enum_name << "Text = function(value) {" << endl; - mOutfile << "\tswitch (value) {" << endl; - for (it = members.begin(); it != members.end(); it++) { - ConstField *cf = *it; - mOutfile << "\tcase " << mCurProj->getName() << "." << enum_name << "." << cf->getName().substr(prefix_size, string::npos) << ":" << endl; - mOutfile << "\t\treturn \"" << cf->getName().substr(prefix_size, string::npos) << "\";" << endl; - } - mOutfile << "\tdefault:" << endl; - mOutfile << "\t\treturn \"?\";" << endl; - mOutfile << "\t}" << endl; - mOutfile << "};" << endl; - - mOutfile.close(); -} - -void JavascriptGenerator::writeClass(Class *klass){ - ostringstream filename; - - if (klass->getType()==Type::Enum) { - return; - } - const list &methods=klass->getMethods(); - if (methods.empty()) return;//skip empty classes - - filename<getName())<<"/"<getName())<<".js"; - mOutfile.open(filename.str().c_str()); - if (!mOutfile.is_open()){ - cerr<<"Could not write into "<getName().empty()) - // mOutfile<<"namespace "<getName()<<"{"<getHelp()<getName()< properties=klass->getProperties(); - for_each(properties.begin(),properties.end(),bind1st(mem_fun(&JavascriptGenerator::writeProperty),this)); - mOutfile<getName().empty()) - // mOutfile<<"} //end of namespace "<getName()<getBasicType()){ - case Type::Float: - case Type::Integer: - mOutfile<<"number"; - break; - case Type::String: - mOutfile<<"string"; - break; - case Type::Boolean: - mOutfile<<"boolean"; - break; - case Type::Class: - mOutfile<<"external:"<getName(); - break; - case Type::Enum: - mOutfile<getName()<<"."<getClass(type->getName())); - break; - case Type::Void: - mOutfile<<"void"; - break; - case Type::Callback: - break; - case Type::Array: - mOutfile<<"Array."; - break; - } -} - -void JavascriptGenerator::writeArgument(Argument *arg, ArgKind kind){ - switch(kind){ - case Normal: - mOutfile<<" * @param {"; - writeType(arg->getType()); - mOutfile<<"} "<getName()<<" - "<getHelp()<getType()); - mOutfile<<"} "<getHelp()<getType()); - mOutfile<<"} "<getName()<<" - "<getHelp()<100 && comment[i]==' ')){ - mOutfile<getName()=="userData" || prop->getName()=="userPointer") return; - mOutfile<<"/**"<getHelp(),0); - mOutfile<getType()); - mOutfile<<"} external:"<getName()<<"#"<getName()<getAttribute()==Property::ReadOnly) - mOutfile<<" * @readonly"<getReturnArg(); - const list &args=method->getArgs(); - list::const_iterator it; - - if (method->isCallback()) return; - if (method->getPropertyBehaviour()!=Method::None) return; - if (method->getName()=="ref" || method->getName()=="unref") return; - - mOutfile<<"/**"<getHelp(),0); - mOutfile<getName()<<"#"<getName()< &args=event->getArgs(); - list::const_iterator it; - - if (!event->isCallback()) return; - mOutfile<<"/**"<getHelp()),0); - mOutfile<getName()<<"#"<getName()< - -#include "software-desc.hh" - -class OutputGenerator{ -public: - virtual void generate(Project *proj)=0; -}; - -class CplusplusGenerator : public OutputGenerator{ -public: - CplusplusGenerator(); - virtual void generate(Project *proj); -private: - void writeClass(Class *klass); - void writeArgument(Argument *arg, bool isReturn=false); - void writeTabs(int ntabs); - void writeHelpComment(const std::string &comment, int ntabs); - void writeMethod(Method *method); - void writeEnumMember(ConstField *cf, bool isLast); - ofstream mOutfile; - Project *mCurProj; - Class *mCurClass; -}; - -class JavascriptGenerator : public OutputGenerator{ -public: - JavascriptGenerator(); - virtual void generate(Project *proj); -private: - void writeClass(Class *klass); - void writeEnum(Class *klass); - void writeType(Type *type); - enum ArgKind { Normal, Return, PropertyArg}; - void writeArgument(Argument *arg, ArgKind kind=Normal); - void writeTabs(int ntabs); - void writeHelpComment(const std::string &comment, int ntabs); - void writeProperty(Property *prop); - void writeMethod(Method *method); - void writeEvent(Method *event); - string getEventHelp(const string &ref); - string getEnumName(Class *klass); - ofstream mOutfile; - Project *mCurProj; - Class *mCurClass; -}; - -string to_lower(const string &str); - -#endif diff --git a/tools/genwrappers.cc b/tools/genwrappers.cc deleted file mode 100644 index d55f3dc6f..000000000 --- a/tools/genwrappers.cc +++ /dev/null @@ -1,482 +0,0 @@ -/* -linphone -Copyright (C) 2013 Belledonne Communications SARL -Simon Morlat (simon.morlat@linphone.org) - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -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 General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#include "software-desc.hh" -#include "generator.hh" - -#include -#include -#include -#include -#include -#include - - - -static bool isSpace(const char *str){ - for(;*str!='\0';++str){ - if (!isspace(*str)) return false; - } - return true; -} - -//Convenient class for examining node recursively -class XmlNode{ -public: - XmlNode(const xmlNode *node=NULL) : mNode(node){ - } - XmlNode getChild(const string &name)const{ - if (mNode==NULL) return XmlNode(); - xmlNode *it; - for(it=mNode->children;it!=NULL;it=it->next){ - if (xmlStrcmp(it->name,(const xmlChar*)name.c_str())==0) - return XmlNode(it); - } - return XmlNode(); - } - XmlNode getChildRecursive(const string &name)const{ - if (mNode==NULL) return XmlNode(); - xmlNode *it; - //find in direct children - for(it=mNode->children;it!=NULL;it=it->next){ - if (xmlStrcmp(it->name,(const xmlChar*)name.c_str())==0) - return XmlNode(it); - } - //recurse into children - for(it=mNode->children;it!=NULL;it=it->next){ - XmlNode res=XmlNode(it).getChildRecursive(name); - if (!res.isNull()) return res; - } - return XmlNode(); - } - list getChildren(const string &name)const{ - xmlNode *it; - list nodes; - - if (mNode==NULL) return nodes; - for(it=mNode->children;it!=NULL;it=it->next){ - if (xmlStrcmp(it->name,(const xmlChar*)name.c_str())==0) - nodes.push_back(XmlNode(it)); - } - if (nodes.empty()) cerr<<"getChildren() no "<content; - if (!isSpace(text)) return string(text); - } - return ""; - } - string getProp(const string &propname)const{ - if (mNode==NULL) return ""; - xmlChar *value; - value=xmlGetProp((xmlNode*)mNode,(const xmlChar*)propname.c_str()); - if (value) return string((const char*)value); - return ""; - } - bool isNull()const{ - return mNode==NULL; - } -private: - const xmlNode *mNode; -}; - -static Argument *parseArgument(XmlNode node, bool isReturn){ - string name=node.getChild("declname").getText(); - Type *type=NULL; - string typecontent=node.getChild("type").getText(); - bool isConst=false; - bool isPointer=false; - - //find documented type if any - string tname=node.getChild("type").getChild("ref").getText(); - if (!tname.empty()){ - type=Type::getType(tname); - }else type=Type::getType(typecontent); - - //find const attribute if any - if (typecontent.find("const")!=string::npos) - isConst=true; - - if (typecontent.find("*")!=string::npos) - isPointer=true; - - if (type==NULL) { - return NULL; - } - //cout<<"Parsed argument "<getBasicType()<<" "<getName()<0) - useUpper=true; - }else{ - if (useUpper) - *w++=toupper(p); - else - *w++=p; - useUpper=false; - } - } - *w++='\0'; - string ret(tmp); - delete[] tmp; - return ret; -} - -static string extractMethodName(const string &c_name, const std::string& class_name){ - string prefix=classNameToPrefix(class_name); - if (c_name.find(prefix)==0){ - return makeMethodName(c_name.substr(prefix.size(),string::npos)); - } - return ""; -} - -static string getHelpBody(XmlNode myNode){ - ostringstream result; - XmlNode brief=myNode.getChild("briefdescription"); - XmlNode detailed=myNode.getChild("detaileddescription"); - - result< args; - string help; - XmlNode funcnode(node); - XmlNode parameterlist; - list params; - list paramsHelp; - list::iterator it,helpit; - - name=funcnode.getChild("name").getText(); - params=funcnode.getChildren("param"); - parameterlist=funcnode.getChild("detaileddescription").getChildRecursive("parameterlist"); - if (parameterlist.isNull()) cerr<<"parameterlist not found"<setHelp(item.getChild("parameterdescription").getChild("para").getText()); - }else cerr<<"Undocumented parameter "<getName()<<" in function "<getType()->getBasicType()!=Type::Class) return; - className=first_arg->getType()->getName(); - methodName=extractMethodName(name,className); - if (!methodName.empty() && methodName!="destroy"){ - //cout<<"Found "<isConst(),false); - method->setHelp(help); - proj->getClass(className)->addMethod(method); - delete first_arg; - } -} - -static string findCommon(const string &c1, const string & c2){ - size_t i; - ostringstream res; - for(i=0;i params=node.getChildRecursive("parameterlist").getChildren("parameteritem"); - list::iterator it=params.begin(); - string rettype=node.getChild("type").getText(); - argsstring=argsstring.substr(argsstring.find('(')+1,string::npos); - bool cont=true; - list args; - Type *firstArgType=NULL; - - rettype=rettype.substr(0,rettype.find('(')); - Argument *retarg=new Argument(Type::getType(rettype),"",false,rettype.find('*')!=string::npos); - - do{ - size_t comma=argsstring.find(','); - size_t end=argsstring.find(')'); - if (comma!=string::npos && commasetHelp((*it).getChild("parameterdescription").getChild("para").getText()); - ++it; - } - args.push_back(argobj); - }while(cont); - - if (firstArgType->getBasicType()!=Type::Class) return; - Class *klass=proj->getClass(firstArgType->getName()); - Method *callback=new Method("", retarg, extractCallbackName(name,klass->getName()), args, false, false, true); - //cout<<"Found callback "<getName()<<" with "<setHelp(node.getChild("detaileddescription").getChild("para").getText()); - klass->addMethod(callback); - - -} - -static void parseEnum(Project *proj, XmlNode node){ - string name=node.getChild("name").getText(); - if (name[0]=='_') name.erase(0,1); - Class *klass=proj->getClass(name); - klass->setHelp(node.getChild("detaileddescription").getChild("para").getText()); - list enumValues=node.getChildren("enumvalue"); - list::iterator it; - int value = 0; - for (it=enumValues.begin();it!=enumValues.end();++it){ - string initializer = (*it).getChild("initializer").getText(); - if ((initializer.length() > 1) && (initializer.at(0) == '=')) { - std::stringstream ss; - if ((initializer.length() > 2) && (initializer.at(1) == '0')) { - if ((initializer.length() > 3) && (initializer.at(2) == 'x')) { - ss << std::hex << initializer.substr(3); - } else { - ss << std::oct << initializer.substr(2); - } - } else { - ss << std::dec << initializer.substr(1); - } - ss >> value; - } - ConstField *cf=new ConstField(Type::getType("int"),(*it).getChild("name").getText(),value); - cf->setHelp((*it).getChild("detaileddescription").getChild("para").getText()); - klass->addConstField(cf); - value++; - } - -} - -static void parseTypedef(Project *proj, xmlNode *node){ - XmlNode tdef(node); - string typecontent=tdef.getChild("type").getText(); - string name=tdef.getChild("name").getText(); - if (typecontent.find("enum")==0){ - Type::addType(Type::Enum,name); - }else if (typecontent.find("(*")!=string::npos){ - parseCallback(proj,node); - }else - proj->getClass(name)->setHelp(getHelpBody(node)); -} - -static void parseMemberDef(Project *proj, xmlNode *node){ - XmlNode member(node); - string brief; - string detailed; - string kind; - - if (member.getChild("briefdescription").getText().empty() && - member.getChild("detaileddescription").getChild("para").getText().empty()) - return; - if (member.getProp("id").find("group__")!=0) - return; - if (member.getChild("detaileddescription").getChildRecursive("xreftitle").getText()=="Deprecated") - return; - - kind=member.getProp("kind"); - if (kind=="function"){ - parseFunction(proj,node); - }else if (kind=="typedef"){ - parseTypedef(proj,node); - }else if (kind=="enum"){ - parseEnum(proj,node); - } -} - -static void inspectNode(Project *proj, xmlNode *a_node){ - xmlNode *cur_node; - - for (cur_node = a_node; cur_node != NULL ; cur_node = cur_node->next) { - if (cur_node->type == XML_ELEMENT_NODE) { - //printf("node type: Element, name: %s\n", cur_node->name); - if (strcmp((const char*)cur_node->name,"memberdef")==0 ){ - //cout<<"Found memberdef"<children) inspectNode(proj,cur_node->children); - } -} - -static int parse_file(Project *proj, const char *filename){ - xmlDoc *doc = NULL; - xmlNode *root_element = NULL; - - - /*parse the file and get the DOM */ - doc = xmlReadFile(filename, NULL, XML_PARSE_RECOVER); - - if (doc == NULL) { - cerr<<"xmlReadFile failed."< files; - list::iterator it; - - LIBXML_TEST_VERSION - - for(i=1;i file1 file2...\nParses xml files generated by doxygen to output wrappers in a specified language.\n",argv[0]); - return -1; - }else if (strcmp(argv[i],"--output")==0){ - i++; - if (strcmp(argv[i],"c++")==0){ - gen=new CplusplusGenerator(); - }else if (strcmp(argv[i],"javascript")==0){ - gen=new JavascriptGenerator(); - } - }else if (strcmp(argv[i],"--project")==0){ - i++; - projectName=argv[i]; - }else{ - files.push_back(argv[i]); - } - } - - if (gen==NULL) { - cerr<<"No output generator selected !"<analyse(); - gen->generate(proj); - return 0; -} diff --git a/tools/software-desc.cc b/tools/software-desc.cc deleted file mode 100644 index 7cf96ac48..000000000 --- a/tools/software-desc.cc +++ /dev/null @@ -1,43 +0,0 @@ -/* -linphone -Copyright (C) 2013 Belledonne Communications SARL -Simon Morlat (simon.morlat@linphone.org) - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -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 General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#include "software-desc.hh" - -Type Type::sStringType(Type::String); -Type Type::sIntegerType(Type::Integer); -Type Type::sVoidType(Type::Void); -Type Type::sBooleanType(Type::Boolean); -Type Type::sFloatType(Type::Float); -Type Type::sArrayType(Type::Array); - -std::map Type::mTypes; -const char *Type::sBasicTypeNames[]={ - "Void", - "Boolean", - "Integer", - "Float", - "String", - "Enum", - "Class", - "Callback", - "Array", - "undef", - "undef" -}; diff --git a/tools/software-desc.hh b/tools/software-desc.hh deleted file mode 100644 index c20b22425..000000000 --- a/tools/software-desc.hh +++ /dev/null @@ -1,470 +0,0 @@ -/* -linphone -Copyright (C) 2013 Belledonne Communications SARL -Simon Morlat (simon.morlat@linphone.org) - -This program is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -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 General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#ifndef software_desc_hh -#define software_desc_hh - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - - - -class Type{ -public: - enum BasicType{ - Void, - Boolean, - Integer, - Float, - String, - Enum, - Class, - Callback, - Array - }; - static const char *sBasicTypeNames[]; - static Type* addType(BasicType bt, const std::string &name){ - Type* ret; - if ((ret=mTypes[name])==0){ - //cout<<"Adding new "<mBasic=bt; - } - return ret; - } - static Type *getType(const std::std::string &tname){ - if (tname.find("(")!=std::string::npos) return NULL; //arrives when parsing function pointer declared inside function prototype - if (strstr(tname.c_str(),"char")!=0 && strchr(tname.c_str(),'*')!=0){ - return &sStringType; - }else if (tname.find("int")!=std::string::npos){ - return &sIntegerType; - }else if (tname.find("size_t")!=std::string::npos){ - return &sIntegerType; - }else if (tname.find("float")!=std::string::npos){ - return &sFloatType; - }else if (tname.find("bool_t")!=std::string::npos){ - return &sBooleanType; - }else if (tname.find("void")!=std::string::npos){ - return &sVoidType; - }else if (tname.find("enum")!=std::string::npos){ - return addType(Enum,tname.c_str()+strlen("enum ")); - }else if (tname.find("MSList")!=std::string::npos){ - return &sArrayType; - }else{/*an object?*/ - - std::string tmp=tname; - size_t pos; - - /*really ugly and slow*/ - - pos=tmp.find('*'); - if (pos!=std::string::npos) - tmp.erase(pos,1); - - pos=tmp.find("const"); - if (pos!=std::string::npos) - tmp.erase(pos,strlen("const")); - - while ((pos=tmp.find(' '))!=std::string::npos){ - tmp.erase(pos,1); - } - return addType(Class,tmp); - } - std::cerr<<"Unhandled type name"< mTypes; -}; - - - -class Argument{ -public: - Argument(Type *type, const std::string &argname, bool isConst, bool isPointer) : mType(type), mName(argname), mConst(isConst), mPointer(isPointer){ - if (!isPointer) mConst=false; - } - Type *getType()const{ - return mType; - } - bool isConst()const{ - return mConst; - } - const std::string &getName()const{ - return mName; - } - bool isPointer()const{ - return mPointer; - } - const std::string &getHelp()const{ - return mHelp; - } - void setHelp(const std::string &help){ - mHelp=help; - } -private: - - Type *mType; - std::string mName; - std::string mHelp; - bool mConst; - bool mPointer; -}; - -class Method{ -public: - enum PropertyBehaviour{ - None, - Read, - Write - }; - Method(const std::string &uid, Argument* return_arg, const std::string &name, const list &args, bool isConst, bool isStatic, bool isCallback=false){ - mUid=uid; - mReturn=return_arg; - mName=name; - mArgs=args; - mConst=isConst; - mStatic=isStatic; - mIsCallback=isCallback; - analyseProperties(); - } - void setHelp(const std::string &help){ - mHelp=help; - } - Argument *getReturnArg()const{ - return mReturn; - } - const string &getName()const{ - return mName; - } - const list &getArgs()const { - return mArgs; - } - bool isConst()const{ - return mConst; - } - bool isStatic()const{ - return mStatic; - } - bool isCallback()const{ - return mIsCallback; - } - const string &getHelp(){ - return mHelp; - } - PropertyBehaviour getPropertyBehaviour()const{ - return mPropertyBehaviour; - } - const string &getPropertyName()const{ - return mPropertyName; - } -private: - void analyseProperties(){ - size_t enabled_pos; - mPropertyBehaviour=None; - - if (mName.find("get")==0 && mArgs.size()==0){ - mPropertyName=mName.substr(3,string::npos); - if (!mPropertyName.empty()){ - mPropertyName[0]=tolower(mPropertyName[0]); - mPropertyBehaviour=Read; - } - }else if (mName.find("is")==0 && mArgs.size()==0){ - mPropertyName=mName.substr(2,string::npos); - if (!mPropertyName.empty()){ - mPropertyName[0]=tolower(mPropertyName[0]); - mPropertyBehaviour=Read; - } - }else if (mName.find("enable")==0 && mArgs.size()==1){ - mPropertyName=mName.substr(6,string::npos); - if (!mPropertyName.empty()){ - mPropertyName[0]=tolower(mPropertyName[0]); - mPropertyName+="Enabled"; - mPropertyBehaviour=Write; - } - }else if (mName.find("set")==0 && mArgs.size()==1){ - mPropertyName=mName.substr(3,string::npos); - if (!mPropertyName.empty()){ - mPropertyName[0]=tolower(mPropertyName[0]); - mPropertyBehaviour=Write; - } - }else if ((enabled_pos=mName.rfind("Enabled"))!=string::npos && mArgs.size()==0){ - size_t goodpos=mName.size()-7; - if (enabled_pos==goodpos){ - mPropertyName=mName.substr(0,goodpos); - if (!mPropertyName.empty()){ - mPropertyName+="Enabled"; - mPropertyBehaviour=Read; - } - } - } - if (mPropertyBehaviour==None) { - mPropertyName=""; - if (mName.find("create")==0) { - mName="new"+mName.substr(6,string::npos); - } - } - } - string mUid; - Argument *mReturn; - string mName; - list mArgs; - string mHelp; - string mPropertyName; /*if it can be a property*/ - PropertyBehaviour mPropertyBehaviour; - bool mConst; - bool mStatic; - bool mIsCallback; -}; - -class Property{ -public: - enum Attribute{ - ReadOnly, - ReadWrite - }; - Property(Attribute attr, const string &name, Type *type, const string &help) : mAttr(attr), mName(name), mType(type), mHelp(help){ - } - const string &getName()const{ - return mName; - } - const string &getHelp()const{ - return mHelp; - } - void setHelp(const string &help){ - mHelp=help; - } - Attribute getAttribute()const{ - return mAttr; - } - void setAttribute(Attribute attr){ - mAttr=attr; - } - Type* getType()const{ - return mType; - } -private: - Attribute mAttr; - string mName; - Type *mType; - string mHelp; -}; - -class ConstField{ -public: - ConstField(Type *type, const string &name, int value) : mType(type), mName(name), mValue(value){ - } - void setHelp(const string & help){ - mHelp=help; - } - const string &getHelp()const{ - return mHelp; - } - const string & getName()const{ - return mName; - } - Type *getType()const{ - return mType; - } - int getValue()const{ - return mValue; - } - static string getCommonPrefix(list fields){ - if (fields.size()<2) return ""; - list::iterator it; - string prefix=fields.front()->getName(); - int prefixsize; - - for (prefixsize=prefix.size();prefixsize>0;prefixsize--){ - bool isMatching=true; - prefix=prefix.substr(0,prefixsize); - - for(it=fields.begin();it!=fields.end();++it){ - ConstField *cf=*it; - if (prefix != cf->getName().substr(0,prefixsize)){ - isMatching=false; - break; - } - } - if (isMatching){ - //cout<<"enum prefix: "< -struct name_matcher{ - name_matcher(const string &name) : mName(name){} - bool operator()(_type *cf){ - return cf->getName()==mName; - } - string mName; -}; - -/*actually a class or an enum*/ -class Class{ -public: - Class(const std::string &name): mName(name){ - } - Type::BasicType getType(){ - return Type::getType(mName)->getBasicType(); - } - void addMethod(Method *method){ - if (mMethods.find(method->getName())==mMethods.end()) - mMethods.insert(make_pair(method->getName(),method)); - } - void addConstField(ConstField *field){ - list::iterator it=find_if(mConstFields.begin(),mConstFields.end(),name_matcher(field->getName())); - if (it==mConstFields.end()) - mConstFields.push_back(field); - } - void setHelp(const std::string &help){ - mHelp=help; - } - list getMethods()const{ - list ret; - map::const_iterator it; - for(it=mMethods.begin();it!=mMethods.end();++it){ - ret.push_back((*it).second); - } - return ret; - } - const list &getConstFields()const{ - return mConstFields; - } - const string &getName()const{ - return mName; - } - const string &getHelp()const{ - return mHelp; - } - list getProperties(){ - list ret; - map::const_iterator it; - for(it=mProperties.begin();it!=mProperties.end();++it){ - ret.push_back((*it).second); - } - return ret; - } - void computeProperties(){ - map::const_iterator it; - Property *prop; - for (it=mMethods.begin();it!=mMethods.end();++it){ - Method *m=(*it).second; - if (m->getPropertyBehaviour()==Method::Read){ - prop=mProperties[m->getPropertyName()]; - if (prop==NULL){ - prop=new Property(Property::ReadOnly,m->getPropertyName(),m->getReturnArg()->getType(), m->getHelp()); - mProperties[m->getPropertyName()]=prop; - } - }else if (m->getPropertyBehaviour()==Method::Write){ - prop=mProperties[m->getPropertyName()]; - if (prop==NULL){ - prop=new Property(Property::ReadWrite,m->getPropertyName(),m->getArgs().front()->getType(), m->getHelp()); - mProperties[m->getPropertyName()]=prop; - }else{ - prop->setHelp(m->getHelp()); - prop->setAttribute(Property::ReadWrite); - } - } - } - } -private: - map mMethods; - map mProperties; - list mConstFields; - string mName; - string mHelp; -}; - -class Project{ -public: - Project(const string &name="wrapper") : mName(name){ - } - Class *getClass(const std::string &name){ - Class *ret; - if ((ret=mClasses[name])==NULL){ - ret=mClasses[name]=new Class(name); - } - return ret; - } - list getClasses()const{ - list ret; - map::const_iterator it; - for(it=mClasses.begin();it!=mClasses.end();++it){ - ret.push_back((*it).second); - } - return ret; - } - const string &getName()const{ - return mName; - } - void analyse(){ - list classes=getClasses(); - for_each(classes.begin(),classes.end(),mem_fun(&Class::computeProperties)); - } - void addCallback(Method *callback){ - list::iterator it=find_if(mCallbacks.begin(),mCallbacks.end(),name_matcher(callback->getName())); - if (it==mCallbacks.end()) - mCallbacks.push_back(callback); - } - const list &getCallbacks()const{ - return mCallbacks; - } -private: - map mClasses; - list mCallbacks; - string mName; -}; - -#endif From 77eb02d39a3cc85038be112c0e3b99445b47af70 Mon Sep 17 00:00:00 2001 From: Ronan Abhamon Date: Tue, 20 Mar 2018 17:14:57 +0100 Subject: [PATCH 4/9] feat(tester/setup_tester): add test on ipv4 addresses (linphone_address_test) --- tester/setup_tester.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/tester/setup_tester.c b/tester/setup_tester.c index f213e044e..590a3c41b 100644 --- a/tester/setup_tester.c +++ b/tester/setup_tester.c @@ -122,7 +122,7 @@ static void linphone_version_test(void){ static void core_init_test(void) { LinphoneCore* lc; lc = linphone_factory_create_core_2(linphone_factory_get(),NULL,NULL,NULL, NULL, system_context); - + /* until we have good certificates on our test server... */ linphone_core_verify_server_certificates(lc,FALSE); if (BC_ASSERT_PTR_NOT_NULL(lc)) { @@ -131,8 +131,18 @@ static void core_init_test(void) { } static void linphone_address_test(void) { + LinphoneAddress *address; + linphone_address_unref(create_linphone_address(NULL)); BC_ASSERT_PTR_NULL(linphone_address_new("sip:@sip.linphone.org")); + + address = linphone_address_new("sip:90.110.127.31"); + if (!BC_ASSERT_PTR_NOT_NULL(address)) return; + linphone_address_unref(address); + + address = linphone_address_new("sip:[::ffff:90.110.127.31]"); + if (!BC_ASSERT_PTR_NOT_NULL(address)) return; + linphone_address_unref(address); } static void core_sip_transport_test(void) { From b764d64430ed311af417da4ec9a36553c6b6dfe9 Mon Sep 17 00:00:00 2001 From: Erwan Croze Date: Wed, 21 Mar 2018 17:20:33 +0100 Subject: [PATCH 5/9] Fixing leak in JNI concerning file transfert --- coreapi/linphonecore_jni.cc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/coreapi/linphonecore_jni.cc b/coreapi/linphonecore_jni.cc index 310444f69..5da325464 100644 --- a/coreapi/linphonecore_jni.cc +++ b/coreapi/linphonecore_jni.cc @@ -1530,6 +1530,9 @@ public: jcontent, jbytes, size); + if (jbytes) { + env->DeleteLocalRef(jbytes); + } if (jcontent) { env->DeleteLocalRef(jcontent); } @@ -6226,6 +6229,9 @@ static jobject create_java_linphone_content(JNIEnv *env, const LinphoneContent * env->DeleteLocalRef(contentClass); env->DeleteLocalRef(jtype); env->DeleteLocalRef(jsubtype); + if (jdata) { + env->DeleteLocalRef(jdata); + } if (jencoding) { env->DeleteLocalRef(jencoding); } @@ -6252,6 +6258,7 @@ static jobject create_java_linphone_buffer(JNIEnv *env, const LinphoneBuffer *bu } jobject jobj = env->NewObject(bufferClass, ctor, jdata, jsize); + if (jdata) env->DeleteLocalRef(jdata); env->DeleteLocalRef(bufferClass); return jobj; } From 8ebf9a3505ee6d2ffa6c9d0cd2892cf36d314982 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Sun, 1 Apr 2018 21:29:12 +0200 Subject: [PATCH 6/9] Add new property in [sip] section called "tls_certificate_subject_regexp" providing a regexp to match with TLS certificate subjects: subjectAltNames.DNS subjectAltNames.URI and CN. If nothing is matched the TLS connection is rejected. --- coreapi/linphonecore.c | 37 ++++++++++++++++++++++++++++++++-- src/c-wrapper/internal/c-sal.h | 1 + src/sal/sal.cpp | 6 ++++++ src/sal/sal.h | 4 +++- tester/register_tester.c | 31 ++++++++++++++++++++++++++++ 5 files changed, 76 insertions(+), 3 deletions(-) diff --git a/coreapi/linphonecore.c b/coreapi/linphonecore.c index 7247c5a24..bf14e10a3 100644 --- a/coreapi/linphonecore.c +++ b/coreapi/linphonecore.c @@ -42,8 +42,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include #include #include -#include -#include +#include "bctoolbox/defs.h" +#include "bctoolbox/regex.h" +#include "belr/grammarbuilder.h" #include "mediastreamer2/dtmfgen.h" #include "mediastreamer2/mediastream.h" @@ -53,6 +54,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "mediastreamer2/msjpegwriter.h" #include "mediastreamer2/msogl.h" #include "mediastreamer2/msvolume.h" + #include "bctoolbox/charconv.h" #include "chat/chat-room/client-group-chat-room-p.h" @@ -69,6 +71,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "address/address-p.h" #include "c-wrapper/c-wrapper.h" + #ifdef INET6 #ifndef _WIN32 #include @@ -1274,6 +1277,34 @@ static void sound_config_read(LinphoneCore *lc) _linphone_core_set_tone(lc,LinphoneReasonBusy,LinphoneToneBusy,NULL); } +static int _linphone_core_tls_postcheck_callback(void *data, const bctbx_x509_certificate_t *peer_cert){ + LinphoneCore *lc = (LinphoneCore *) data; + const char *tls_certificate_subject_regexp = lp_config_get_string(lc->config,"sip","tls_certificate_subject_regexp", NULL); + int ret = 0; + if (tls_certificate_subject_regexp){ + ret = -1; + /*the purpose of this handling is to a peer certificate for which there is no single subject matching the regexp given + * in the "tls_certificate_subject_regexp" property. + */ + bctbx_list_t *subjects = bctbx_x509_certificate_get_subjects(peer_cert); + bctbx_list_t *elem; + for(elem = subjects; elem != NULL; elem = elem->next){ + const char *subject = (const char *)elem->data; + ms_message("_linphone_core_tls_postcheck_callback: subject=%s", subject); + if (bctbx_is_matching_regex(subject, tls_certificate_subject_regexp)){ + ret = 0; + ms_message("_linphone_core_tls_postcheck_callback(): successful by matching '%s'", subject); + break; + } + } + bctbx_list_free_with_data(subjects, bctbx_free); + } + if (ret == -1){ + ms_message("_linphone_core_tls_postcheck_callback(): postcheck failed, nothing matched."); + } + return ret; +} + static void certificates_config_read(LinphoneCore *lc) { LinphoneFactory *factory = linphone_factory_get(); const char *data_dir = linphone_factory_get_data_resources_dir(factory); @@ -1295,6 +1326,8 @@ static void certificates_config_read(LinphoneCore *lc) { linphone_core_verify_server_certificates(lc, !!lp_config_get_int(lc->config,"sip","verify_server_certs",TRUE)); linphone_core_verify_server_cn(lc, !!lp_config_get_int(lc->config,"sip","verify_server_cn",TRUE)); bctbx_free(root_ca_path); + + lc->sal->setTlsPostcheckCallback(_linphone_core_tls_postcheck_callback, lc); } static void sip_config_read(LinphoneCore *lc) { diff --git a/src/c-wrapper/internal/c-sal.h b/src/c-wrapper/internal/c-sal.h index c7bd15ef6..77cd79a01 100644 --- a/src/c-wrapper/internal/c-sal.h +++ b/src/c-wrapper/internal/c-sal.h @@ -33,6 +33,7 @@ #include "mediastreamer2/mediastream.h" #include "ortp/rtpsession.h" #include "belle-sip/belle-sip.h" +#include "bctoolbox/crypto.h" #ifndef LINPHONE_PUBLIC #if defined(_MSC_VER) diff --git a/src/sal/sal.cpp b/src/sal/sal.cpp index 71c2e169e..193588ca4 100644 --- a/src/sal/sal.cpp +++ b/src/sal/sal.cpp @@ -469,6 +469,7 @@ void Sal::setTlsProperties(){ if (!mRootCaData.empty()) belle_tls_crypto_config_set_root_ca_data(crypto_config, mRootCaData.c_str()); if (mSslConfig != NULL) belle_tls_crypto_config_set_ssl_config(crypto_config, mSslConfig); + if (mTlsPostcheckCb) belle_tls_crypto_config_set_postcheck_callback(crypto_config, mTlsPostcheckCb, mTlsPostcheckCbData); belle_sip_tls_listening_point_set_crypto_config(tlp, crypto_config); belle_sip_object_unref(crypto_config); } @@ -707,6 +708,11 @@ void Sal::setSslConfig(void *ssl_config) { setTlsProperties(); } +void Sal::setTlsPostcheckCallback(int (*cb)(void *, const bctbx_x509_certificate_t *), void *data){ + mTlsPostcheckCb = cb; + mTlsPostcheckCbData = data; +} + int Sal::createUuid(char *uuid, size_t len) { if (generateUuid(uuid, len) == 0) { setUuid(uuid); diff --git a/src/sal/sal.h b/src/sal/sal.h index 082929f1b..1de178d5f 100644 --- a/src/sal/sal.h +++ b/src/sal/sal.h @@ -224,7 +224,7 @@ public: void verifyServerCertificates (bool value); void verifyServerCn (bool value); - + void setTlsPostcheckCallback(int (*cb)(void *, const bctbx_x509_certificate_t *), void *data); // --------------------------------------------------------------------------- // DNS resolution @@ -317,6 +317,8 @@ private: void *mSslConfig = nullptr; std::vector mSupportedContentTypes; std::string mLinphoneSpecs; + belle_tls_crypto_config_postcheck_callback_t mTlsPostcheckCb; + void *mTlsPostcheckCbData; // Cache values mutable std::string mDnsUserHostsFile; diff --git a/tester/register_tester.c b/tester/register_tester.c index e69ec1937..9865b5845 100644 --- a/tester/register_tester.c +++ b/tester/register_tester.c @@ -999,6 +999,36 @@ static void tls_certificate_failure(void){ } } +static void tls_certificate_subject_check(void){ + if (transport_supported(LinphoneTransportTls)) { + LinphoneCoreManager* lcm; + LinphoneCore *lc; + char *rootcapath = bc_tester_res("certificates/cn/cafile.pem"); + lcm=linphone_core_manager_new2("pauline_alt_rc",FALSE); + lc=lcm->lc; + linphone_core_set_root_ca(lc, rootcapath); + /*let's search for a subject that is not in the certificate, it should fail*/ + lp_config_set_string(linphone_core_get_config(lc), "sip", "tls_certificate_subject_regexp", "cotcotcot.org"); + linphone_core_set_network_reachable(lc,TRUE); + BC_ASSERT_TRUE(wait_for(lcm->lc,lcm->lc,&lcm->stat.number_of_LinphoneRegistrationFailed,1)); + + /*let's search for a subject (in subjectAltNames and CN) that exist in the certificate, it should pass*/ + lp_config_set_string(linphone_core_get_config(lc), "sip", "tls_certificate_subject_regexp", "altname.linphone.org"); + linphone_core_refresh_registers(lcm->lc); + BC_ASSERT_TRUE(wait_for(lc,lc,&lcm->stat.number_of_LinphoneRegistrationOk,1)); + linphone_core_set_network_reachable(lc,FALSE); + + /*let's search for a subject (in subjectAltNames and CN) that exist in the certificate, it should pass*/ + lp_config_set_string(linphone_core_get_config(lc), "sip", "tls_certificate_subject_regexp", "Jehan Monnier"); + linphone_core_set_network_reachable(lc,TRUE); + BC_ASSERT_TRUE(wait_for(lc,lc,&lcm->stat.number_of_LinphoneRegistrationOk,2)); + + BC_ASSERT_EQUAL(lcm->stat.number_of_LinphoneRegistrationFailed,1, int, "%d"); + linphone_core_manager_destroy(lcm); + bc_free(rootcapath); + } +} + char *read_file(const char *path) { long numbytes = 0; size_t readbytes; @@ -1331,6 +1361,7 @@ test_t register_tests[] = { TEST_NO_TAG("TLS register with alt. name certificate", tls_alt_name_register), TEST_NO_TAG("TLS register with wildcard certificate", tls_wildcard_register), TEST_NO_TAG("TLS certificate not verified",tls_certificate_failure), + TEST_NO_TAG("TLS certificate subjects check",tls_certificate_subject_check), 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), From ad30df801898584f494e0bff03ebc12900a53e47 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 3 Apr 2018 18:30:44 +0200 Subject: [PATCH 7/9] Add new flexisip test for certificate subject matching. --- tester/CMakeLists.txt | 2 + tester/certificates/client/cert3.pem | 78 ++++ tester/certificates/client/key3.pem | 28 ++ .../certificates/client/openssl-altname.cnf | 360 ++++++++++++++++++ tester/flexisip_tester.c | 39 +- 5 files changed, 501 insertions(+), 6 deletions(-) create mode 100644 tester/certificates/client/cert3.pem create mode 100644 tester/certificates/client/key3.pem create mode 100644 tester/certificates/client/openssl-altname.cnf diff --git a/tester/CMakeLists.txt b/tester/CMakeLists.txt index 5ac5eeddc..0872bb63b 100644 --- a/tester/CMakeLists.txt +++ b/tester/CMakeLists.txt @@ -71,6 +71,8 @@ set(CERTIFICATE_CLIENT_FILES certificates/client/key.pem certificates/client/cert2.pem certificates/client/key2.pem + certificates/client/cert3.pem + certificates/client/key3.pem certificates/client/cert2-signed-by-other-ca.pem ) diff --git a/tester/certificates/client/cert3.pem b/tester/certificates/client/cert3.pem new file mode 100644 index 000000000..1bffa265d --- /dev/null +++ b/tester/certificates/client/cert3.pem @@ -0,0 +1,78 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 19 (0x13) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=FR, ST=Some-State, L=Grenoble, O=Belledonne Communications, OU=LAB, CN=Jehan Monnier/emailAddress=jehan.monnier@belledonne-communications.com + Validity + Not Before: Apr 3 13:55:30 2018 GMT + Not After : Mar 31 13:55:30 2028 GMT + Subject: C=FR, ST=Some-State, L=Grenoble, O=Internet Widgits Pty Ltd, CN=sip:gandalf@sip.example.org + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + Public-Key: (2048 bit) + Modulus: + 00:c4:b0:07:de:24:1a:46:3c:63:2c:f2:a6:9a:ba: + fd:3d:e4:f0:1e:96:6c:74:f7:ad:cf:b3:3c:51:31: + 45:11:af:0a:ca:ba:f2:cc:ef:82:05:28:c3:5d:6c: + bf:65:47:27:ec:37:37:f3:ab:42:52:83:a0:e9:4f: + ef:99:cd:07:04:ee:bb:87:6d:40:a6:dd:2f:b5:79: + 1b:f1:c1:3a:22:75:29:e3:9e:64:67:ae:bf:93:36: + a9:3a:0a:00:bc:4e:b6:ab:db:83:01:7f:35:5e:52: + 2c:bc:21:52:d7:76:0b:48:1d:d7:09:90:be:1b:7c: + 98:3f:a2:70:78:48:99:95:eb:5d:95:07:ca:6f:f7: + 43:f0:c5:0d:3d:60:95:ef:6d:53:8f:7f:6c:95:2d: + 51:b5:3c:84:3a:56:57:b2:2d:d8:6e:36:fe:66:3f: + e5:80:89:6d:98:e0:67:f6:ed:65:ab:dc:ad:fb:04: + 90:2f:30:60:30:8b:9f:a1:a0:9b:b9:54:6b:ae:83: + 41:38:18:60:a3:fe:32:ef:38:46:bc:44:0b:e1:ca: + 4c:41:7e:e2:9c:35:36:eb:f7:54:83:67:c8:9f:83: + 68:00:c3:58:ee:54:be:d6:05:d1:97:c8:e1:47:c0: + 25:eb:55:a6:a0:1b:c6:86:35:ba:f5:7a:63:75:79: + 7d:d7 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + Netscape Comment: + OpenSSL Generated Certificate + X509v3 Subject Key Identifier: + 47:91:DE:5F:F9:8A:85:B5:0F:68:02:38:5D:67:3F:ED:C6:3C:F2:66 + X509v3 Authority Key Identifier: + keyid:06:5F:5D:C7:16:AF:62:F8:2D:6E:71:03:88:A0:D6:1D:2B:04:7F:BA + + X509v3 Subject Alternative Name: + URI:sip:gandalf@sip.linphone.org, URI:sip:gandalf@sip.example.org + Signature Algorithm: sha1WithRSAEncryption + 38:eb:34:2f:d3:fe:c6:8f:3f:8b:a3:4c:73:2c:84:75:1e:f0: + c0:41:6a:78:63:ad:81:99:ac:cf:9a:27:28:4f:19:3c:81:7f: + dd:81:31:f4:f3:6a:ee:6d:13:fd:99:3f:96:75:94:1f:44:e6: + 9c:1e:d8:9e:34:4d:e6:c9:1c:51:59:e2:6a:96:fc:84:95:d3: + a3:0f:d7:38:db:89:2d:df:67:58:32:88:83:e8:76:7f:5c:28: + 08:3c:75:c0:e1:ae:68:78:0c:4d:9b:71:57:ee:76:99:80:69: + 73:7f:fd:fe:ec:e5:f1:f8:92:e4:1a:c1:8e:9e:70:3e:e3:de: + 1c:2f +-----BEGIN CERTIFICATE----- +MIID9zCCA2CgAwIBAgIBEzANBgkqhkiG9w0BAQUFADCBuzELMAkGA1UEBhMCRlIx +EzARBgNVBAgMClNvbWUtU3RhdGUxETAPBgNVBAcMCEdyZW5vYmxlMSIwIAYDVQQK +DBlCZWxsZWRvbm5lIENvbW11bmljYXRpb25zMQwwCgYDVQQLDANMQUIxFjAUBgNV +BAMMDUplaGFuIE1vbm5pZXIxOjA4BgkqhkiG9w0BCQEWK2plaGFuLm1vbm5pZXJA +YmVsbGVkb25uZS1jb21tdW5pY2F0aW9ucy5jb20wHhcNMTgwNDAzMTM1NTMwWhcN +MjgwMzMxMTM1NTMwWjB+MQswCQYDVQQGEwJGUjETMBEGA1UECAwKU29tZS1TdGF0 +ZTERMA8GA1UEBwwIR3Jlbm9ibGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMg +UHR5IEx0ZDEkMCIGA1UEAwwbc2lwOmdhbmRhbGZAc2lwLmV4YW1wbGUub3JnMIIB +IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxLAH3iQaRjxjLPKmmrr9PeTw +HpZsdPetz7M8UTFFEa8KyrryzO+CBSjDXWy/ZUcn7Dc386tCUoOg6U/vmc0HBO67 +h21Apt0vtXkb8cE6InUp455kZ66/kzapOgoAvE62q9uDAX81XlIsvCFS13YLSB3X +CZC+G3yYP6JweEiZletdlQfKb/dD8MUNPWCV721Tj39slS1RtTyEOlZXsi3Ybjb+ +Zj/lgIltmOBn9u1lq9yt+wSQLzBgMIufoaCbuVRrroNBOBhgo/4y7zhGvEQL4cpM +QX7inDU26/dUg2fIn4NoAMNY7lS+1gXRl8jhR8Al61WmoBvGhjW69XpjdXl91wID +AQABo4HCMIG/MAkGA1UdEwQCMAAwLAYJYIZIAYb4QgENBB8WHU9wZW5TU0wgR2Vu +ZXJhdGVkIENlcnRpZmljYXRlMB0GA1UdDgQWBBRHkd5f+YqFtQ9oAjhdZz/txjzy +ZjAfBgNVHSMEGDAWgBQGX13HFq9i+C1ucQOIoNYdKwR/ujBEBgNVHREEPTA7hhxz +aXA6Z2FuZGFsZkBzaXAubGlucGhvbmUub3JnhhtzaXA6Z2FuZGFsZkBzaXAuZXhh +bXBsZS5vcmcwDQYJKoZIhvcNAQEFBQADgYEAOOs0L9P+xo8/i6NMcyyEdR7wwEFq +eGOtgZmsz5onKE8ZPIF/3YEx9PNq7m0T/Zk/lnWUH0TmnB7YnjRN5skcUVniapb8 +hJXTow/XONuJLd9nWDKIg+h2f1woCDx1wOGuaHgMTZtxV+52mYBpc3/9/uzl8fiS +5BrBjp5wPuPeHC8= +-----END CERTIFICATE----- diff --git a/tester/certificates/client/key3.pem b/tester/certificates/client/key3.pem new file mode 100644 index 000000000..144fdee61 --- /dev/null +++ b/tester/certificates/client/key3.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDEsAfeJBpGPGMs +8qaauv095PAelmx0963PszxRMUURrwrKuvLM74IFKMNdbL9lRyfsNzfzq0JSg6Dp +T++ZzQcE7ruHbUCm3S+1eRvxwToidSnjnmRnrr+TNqk6CgC8Trar24MBfzVeUiy8 +IVLXdgtIHdcJkL4bfJg/onB4SJmV612VB8pv90PwxQ09YJXvbVOPf2yVLVG1PIQ6 +VleyLdhuNv5mP+WAiW2Y4Gf27WWr3K37BJAvMGAwi5+hoJu5VGuug0E4GGCj/jLv +OEa8RAvhykxBfuKcNTbr91SDZ8ifg2gAw1juVL7WBdGXyOFHwCXrVaagG8aGNbr1 +emN1eX3XAgMBAAECggEAMFb/KAaBep+e1E4yyjaIxOx+Y1YfA8RXsINhoKbWTdlS +cq7tu5ZlwzTYhx6SD6ckVbbghn+hxjvZkV33CjrMrdaqukcMq7YS4qwIRStzSUK4 +b9ve22ikZt75Sm1o7t79oFFL6lNEX5Ecs4QRIyk87pV+4zfysTi3BnS65aUaMjD/ +K+zpK3pBqWcb5dUCjCUMHKw99XC+HjtKFiVWS7CXUQoF1kzTiSNtnz+yX/RBkHYZ +eVM/Gex1WtgCqt9P5zPaFstvxQO8osXZsOrSK2oRZjpiaD5FyyVOBLhTVF1cKHTS +oI89g5SO0GXq+hbfVgx90clnIyLSB83bB5czUJKYIQKBgQDn7vF5pYtF1uxZsRdk +zoDxENfKCghHq7QYULez5mzC8p8COvzXUBq9VKc1zFWhK1R6c+Nl+IXJwf59uO83 +L97cRvminEA3g/CkJet0CoHCHAZ0Z5XrZwuPAX3kjiz3XrThveAJGqO6R239kib2 +V7zXG0aQNP/1VeR1XfPm0e2+ZwKBgQDZGNKTOGI3OnbKlDPTIXhfWixSTR3EU+zE +9Udoeuut0GGZRe/aveciiBGQIrMUpIVPRYJEyP2o3R43z/ZwRjNwDUDA+s0evQ8n +2LFlpNVlN1xdcZrMv7j3hvFGbr362ZPPz7FC6H7FgeHjDq2sHGgjwJMucO0qnNuA +iNoOuLe/EQKBgA+C5HVtQ9483Hu3I0hjoy38IWJqv1kDu7ywkUifzYBQN6Avj79a +pR8qbTBk5QktW64A2CF2uIPgzINd/emj8vSqboGYj5bm5Q4lVxTgqwLvWuMoFlez +AYvj3qaNd6ZnmBNM3pHdTTvlEQ8XWjG5dnCwa0yzrraasvfCe9BhE9RbAoGAdkTu +muNxpjLEenIolZG7WP7v/FokqEssRtR09XdZo5RNR0nxdFJWc9p67vHoa4uBUIFG +iaCRiAgGKVOzJtEnvpiJuVgonOFUO1nysrQMyRpSyFlWgsrDwp2SHdPAzcLwopq8 +L/4m6gRrAd6CQKwtE6UayYcdvUQ81JY5bSG2gHECgYEAg2KU1y5lwws4rjo0HD5f +xeR5JnAVUZ5g2T99SzA1VnNy2klCVF7DorviPiZOlJBvLp0n25tGArRAHqiFSfbH +dUPWhOXiLTozP9Gb0ODAK4k1EtgISNbec1FdhTA+YBOk4CvVCvLFWr2h9yNCzNpd +TCuUz4z2lSsg1YRHT4lJJr8= +-----END PRIVATE KEY----- diff --git a/tester/certificates/client/openssl-altname.cnf b/tester/certificates/client/openssl-altname.cnf new file mode 100644 index 000000000..f97c844d7 --- /dev/null +++ b/tester/certificates/client/openssl-altname.cnf @@ -0,0 +1,360 @@ +# +# OpenSSL example configuration file. +# This is mostly being used for generation of certificate requests. +# This variant is used for generating client certificate with subjectAltName.uri. +# + +# This definition stops the following lines choking if HOME isn't +# defined. +HOME = . +RANDFILE = $ENV::HOME/.rnd + +# Extra OBJECT IDENTIFIER info: +#oid_file = $ENV::HOME/.oid +oid_section = new_oids + +# To use this configuration file with the "-extfile" option of the +# "openssl x509" utility, name here the section containing the +# X.509v3 extensions to use: +# extensions = +# (Alternatively, use a configuration file that has only +# X.509v3 extensions in its main [= default] section.) + +[ new_oids ] + +# We can add new OIDs in here for use by 'ca', 'req' and 'ts'. +# Add a simple OID like this: +# testoid1=1.2.3.4 +# Or use config file substitution like this: +# testoid2=${testoid1}.5.6 + +# Policies used by the TSA examples. +tsa_policy1 = 1.2.3.4.1 +tsa_policy2 = 1.2.3.4.5.6 +tsa_policy3 = 1.2.3.4.5.7 + +#################################################################### +[ ca ] +default_ca = CA_default # The default ca section + +#################################################################### +[ CA_default ] + +dir = . # Where everything is kept +certs = $dir/certs # Where the issued certs are kept +crl_dir = $dir/crl # Where the issued crl are kept +database = $dir/index.txt # database index file. +#unique_subject = no # Set to 'no' to allow creation of + # several ctificates with same subject. +new_certs_dir = $dir/newcerts # default place for new certs. + +certificate = $dir/cacert.pem # The CA certificate +serial = $dir/serial # The current serial number +crlnumber = $dir/crlnumber # the current crl number + # must be commented out to leave a V1 CRL +crl = $dir/crl.pem # The current CRL +private_key = $dir/private/cakey.pem# The private key +RANDFILE = $dir/private/.rand # private random number file + +x509_extensions = usr_cert # The extentions to add to the cert + +# Comment out the following two lines for the "traditional" +# (and highly broken) format. +name_opt = ca_default # Subject Name options +cert_opt = ca_default # Certificate field options + +# Extension copying option: use with caution. +# copy_extensions = copy + +# Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs +# so this is commented out by default to leave a V1 CRL. +# crlnumber must also be commented out to leave a V1 CRL. +# crl_extensions = crl_ext + +default_days = 3650 # how long to certify for +default_crl_days= 30 # how long before next CRL +default_md = sha1 # use public key default MD +preserve = no # keep passed DN ordering + +# A few difference way of specifying how similar the request should look +# For type CA, the listed attributes must be the same, and the optional +# and supplied fields are just that :-) +policy = policy_match + +# For the CA policy +[ policy_match ] +countryName = match +stateOrProvinceName = match +organizationName = match +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +# For the 'anything' policy +# At this point in time, you must list all acceptable 'object' +# types. +[ policy_anything ] +countryName = optional +stateOrProvinceName = optional +localityName = optional +organizationName = optional +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +#################################################################### +[ req ] +default_bits = 1024 +default_keyfile = privkey.pem +distinguished_name = req_distinguished_name +attributes = req_attributes +x509_extensions = v3_ca # The extentions to add to the self signed cert + +# Passwords for private keys if not present they will be prompted for +# input_password = secret +# output_password = secret + +# This sets a mask for permitted string types. There are several options. +# default: PrintableString, T61String, BMPString. +# pkix : PrintableString, BMPString (PKIX recommendation before 2004) +# utf8only: only UTF8Strings (PKIX recommendation after 2004). +# nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings). +# MASK:XXXX a literal mask value. +# WARNING: ancient versions of Netscape crash on BMPStrings or UTF8Strings. +string_mask = utf8only + +# req_extensions = v3_req # The extensions to add to a certificate request +[ req_distinguished_name ] +countryName = Country Name (2 letter code) +countryName_default = FR +countryName_min = 2 +countryName_max = 2 + +stateOrProvinceName = State or Province Name (full name) +stateOrProvinceName_default = France + +localityName = Locality Name (eg, city) +localityName_default = Grenoble + +0.organizationName = Organization Name (eg, company) +0.organizationName_default = Belledonne Communications + +# we can do this but it is not needed normally :-) +#1.organizationName = Second Organization Name (eg, company) +#1.organizationName_default = World Wide Web Pty Ltd + +organizationalUnitName = Organizational Unit Name (eg, section) +organizationalUnitName_default = LAB +#organizationalUnitName_default = + +0.commonName = Common Name (e.g. server FQDN or YOUR name) +0.commonName_max = 64 +0.commonName_default = sip2.linphone.org + +1.commonName = Common Name (e.g. server FQDN or YOUR name) +1.commonName_max = 64 +1.commonName_default = *.wildcard1.linphone.org + +emailAddress = Email Address +emailAddress_max = 64 +emailAddress_default = jehan.monnier@belledonne-communications.com + +# SET-ex3 = SET extension number 3 + +[ req_attributes ] +challengePassword = A challenge password +challengePassword_min = 4 +challengePassword_max = 20 + +unstructuredName = An optional company name + +[ usr_cert ] + +# These extensions are added when 'ca' signs a request. + +# This goes against PKIX guidelines but some CAs do it and some software +# requires this to avoid interpreting an end user certificate as a CA. + +basicConstraints=CA:FALSE + +# Here are some examples of the usage of nsCertType. If it is omitted +# the certificate can be used for anything *except* object signing. + +# This is OK for an SSL server. +# nsCertType = server + +# For an object signing certificate this would be used. +# nsCertType = objsign + +# For normal client use this is typical +# nsCertType = client, email + +# and for everything including object signing: +# nsCertType = client, email, objsign + +# This is typical in keyUsage for a client certificate. +# keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +# This will be displayed in Netscape's comment listbox. +nsComment = "OpenSSL Generated Certificate" + +# PKIX recommendations harmless if included in all certificates. +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid,issuer + +# This stuff is for subjectAltName and issuerAltname. +# Import the email address. +# subjectAltName=email:copy +# An alternative to produce certificates that aren't +# deprecated according to PKIX. +# subjectAltName=email:move + +subjectAltName=URI:sip:gandalf@sip.linphone.org, URI:sip:gandalf@sip.example.org + +# Copy subject details +# issuerAltName=issuer:copy + +#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem +#nsBaseUrl +#nsRevocationUrl +#nsRenewalUrl +#nsCaPolicyUrl +#nsSslServerName + +# This is required for TSA certificates. +# extendedKeyUsage = critical,timeStamping + +[ v3_req ] + +# Extensions to add to a certificate request + +basicConstraints = CA:FALSE +keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +[ v3_ca ] + + +# Extensions for a typical CA + + +# PKIX recommendation. + +subjectKeyIdentifier=hash + +authorityKeyIdentifier=keyid:always,issuer + +# This is what PKIX recommends but some broken software chokes on critical +# extensions. +#basicConstraints = critical,CA:true +# So we do this instead. +basicConstraints = CA:true + +# Key usage: this is typical for a CA certificate. However since it will +# prevent it being used as an test self-signed certificate it is best +# left out by default. +# keyUsage = cRLSign, keyCertSign + +# Some might want this also +# nsCertType = sslCA, emailCA + +# Include email address in subject alt name: another PKIX recommendation +# subjectAltName=email:copy +# Copy issuer details +# issuerAltName=issuer:copy + +# DER hex encoding of an extension: beware experts only! +# obj=DER:02:03 +# Where 'obj' is a standard or added object +# You can even override a supported extension: +# basicConstraints= critical, DER:30:03:01:01:FF + +[ crl_ext ] + +# CRL extensions. +# Only issuerAltName and authorityKeyIdentifier make any sense in a CRL. + +# issuerAltName=issuer:copy +authorityKeyIdentifier=keyid:always + +[ proxy_cert_ext ] +# These extensions should be added when creating a proxy certificate + +# This goes against PKIX guidelines but some CAs do it and some software +# requires this to avoid interpreting an end user certificate as a CA. + +basicConstraints=CA:FALSE + +# Here are some examples of the usage of nsCertType. If it is omitted +# the certificate can be used for anything *except* object signing. + +# This is OK for an SSL server. +# nsCertType = server + +# For an object signing certificate this would be used. +# nsCertType = objsign + +# For normal client use this is typical +# nsCertType = client, email + +# and for everything including object signing: +# nsCertType = client, email, objsign + +# This is typical in keyUsage for a client certificate. +# keyUsage = nonRepudiation, digitalSignature, keyEncipherment + +# This will be displayed in Netscape's comment listbox. +nsComment = "OpenSSL Generated Certificate" + +# PKIX recommendations harmless if included in all certificates. +subjectKeyIdentifier=hash +authorityKeyIdentifier=keyid,issuer + +# This stuff is for subjectAltName and issuerAltname. +# Import the email address. +# subjectAltName=email:copy +# An alternative to produce certificates that aren't +# deprecated according to PKIX. +# subjectAltName=email:move + +# Copy subject details +# issuerAltName=issuer:copy + +#nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem +#nsBaseUrl +#nsRevocationUrl +#nsRenewalUrl +#nsCaPolicyUrl +#nsSslServerName + +# This really needs to be in place for it to be a proxy certificate. +proxyCertInfo=critical,language:id-ppl-anyLanguage,pathlen:3,policy:foo + +#################################################################### +[ tsa ] + +default_tsa = tsa_config1 # the default TSA section + +[ tsa_config1 ] + +# These are used by the TSA reply generation only. +dir = . # TSA root directory +serial = $dir/tsaserial # The current serial number (mandatory) +crypto_device = builtin # OpenSSL engine to use for signing +signer_cert = $dir/tsacert.pem # The TSA signing certificate + # (optional) +certs = $dir/cacert.pem # Certificate chain to include in reply + # (optional) +signer_key = $dir/private/tsakey.pem # The TSA private key (optional) + +default_policy = tsa_policy1 # Policy if request did not specify it + # (optional) +other_policies = tsa_policy2, tsa_policy3 # acceptable policies (optional) +digests = md5, sha1 # Acceptable message digests (mandatory) +accuracy = secs:1, millisecs:500, microsecs:100 # (optional) +clock_precision_digits = 0 # number of digits after dot. (optional) +ordering = yes # Is ordering defined for timestamps? + # (optional, default: no) +tsa_name = yes # Must the TSA name be included in the reply? + # (optional, default: no) +ess_cert_id_chain = no # Must the ESS cert id chain be included? + # (optional, default: no) diff --git a/tester/flexisip_tester.c b/tester/flexisip_tester.c index e96c82ee0..bc85fd026 100644 --- a/tester/flexisip_tester.c +++ b/tester/flexisip_tester.c @@ -1342,14 +1342,28 @@ static void tls_authentication_requested_bad(LinphoneCore *lc, LinphoneAuthInfo } } -static void tls_client_auth_try_register(const char *identity, bool_t with_good_cert, bool_t must_work){ +static void tls_authentication_provide_altname_cert(LinphoneCore *lc, LinphoneAuthInfo *auth_info, LinphoneAuthMethod method){ + if (method == LinphoneAuthTls){ + + char *cert = bc_tester_res("certificates/client/cert3.pem"); + char *key = bc_tester_res("certificates/client/key3.pem"); + + linphone_auth_info_set_tls_cert_path(auth_info, cert); + linphone_auth_info_set_tls_key_path(auth_info, key); + linphone_core_add_auth_info(lc, auth_info); + bc_free(cert); + bc_free(key); + } +} + +static void tls_client_auth_try_register(const char *identity, LinphoneCoreAuthenticationRequestedCb cb, bool_t good_cert, bool_t must_work){ LinphoneCoreManager *lcm; LinphoneCoreCbs *cbs = linphone_factory_create_core_cbs(linphone_factory_get()); LinphoneProxyConfig *cfg; lcm = linphone_core_manager_new(NULL); - linphone_core_cbs_set_authentication_requested(cbs, with_good_cert ? tls_authentication_requested_good : tls_authentication_requested_bad); + linphone_core_cbs_set_authentication_requested(cbs, cb); linphone_core_add_callbacks(lcm->lc, cbs); linphone_core_cbs_unref(cbs); cfg = linphone_core_create_proxy_config(lcm->lc); @@ -1368,7 +1382,8 @@ static void tls_client_auth_try_register(const char *identity, bool_t with_good_ /*we should expect at least 2 "auth_requested": one for the TLS certificate, another one because the server rejects the REGISTER with 401, with eventually MD5 + SHA256 challenge*/ /*If the certificate isn't recognized at all, the connection will not happen and no SIP response will be received from server.*/ - if (with_good_cert) BC_ASSERT_GREATER(lcm->stat.number_of_auth_info_requested,2, int, "%d"); + if (good_cert) BC_ASSERT_GREATER(lcm->stat.number_of_auth_info_requested,2, int, "%d"); + else BC_ASSERT_EQUAL(lcm->stat.number_of_auth_info_requested,1, int, "%d"); } @@ -1380,9 +1395,9 @@ void tls_client_auth_bad_certificate_cn(void) { if (transport_supported(LinphoneTransportTls)) { /*first register to the proxy with galadrielle's identity, and authenticate by supplying galadrielle's certificate. * It must work.*/ - tls_client_auth_try_register("sip:galadrielle@sip.example.org", TRUE, TRUE); + tls_client_auth_try_register("sip:galadrielle@sip.example.org", tls_authentication_requested_good, TRUE, TRUE); /*now do the same thing, but trying to register as "Arwen". It must fail.*/ - tls_client_auth_try_register("sip:arwen@sip.example.org", TRUE, FALSE); + tls_client_auth_try_register("sip:arwen@sip.example.org", tls_authentication_requested_good, TRUE, FALSE); } } @@ -1390,7 +1405,18 @@ void tls_client_auth_bad_certificate(void) { if (transport_supported(LinphoneTransportTls)) { /*first register to the proxy with galadrielle's identity, and authenticate by supplying galadrielle's certificate. * It must work.*/ - tls_client_auth_try_register("sip:galadrielle@sip.example.org", FALSE, FALSE); + tls_client_auth_try_register("sip:galadrielle@sip.example.org", tls_authentication_requested_bad, FALSE, FALSE); + } +} + +/* + * This test verifies that the flexisip certificate postcheck works. + * Here, the certificate presented for gandalf is valid and matches the SIP from. However we've set the regexp in flexisip.conf to only accept + * certificates with subjects containing either galadrielle or sip:sip.example.org. + */ +static void tls_client_rejected_due_to_unmatched_subject(void){ + if (transport_supported(LinphoneTransportTls)) { + tls_client_auth_try_register("sip:gandalf@sip.example.org", tls_authentication_provide_altname_cert, TRUE, FALSE); } } @@ -1935,6 +1961,7 @@ test_t flexisip_tests[] = { TEST_ONE_TAG("Redis Publish/subscribe", redis_publish_subscribe, "Skip"), TEST_NO_TAG("TLS authentication - client rejected due to CN mismatch", tls_client_auth_bad_certificate_cn), TEST_NO_TAG("TLS authentication - client rejected due to unrecognized certificate chain", tls_client_auth_bad_certificate), + TEST_NO_TAG("TLS authentication - client rejected due to unmatched certificate subject", tls_client_rejected_due_to_unmatched_subject), TEST_NO_TAG("Transcoder", transcoder_tester), TEST_NO_TAG("Removing old tport on flexisip for the same client", test_removing_old_tport), /*TEST_NO_TAG("Resend of REFER with other devices", resend_refer_other_devices),*/ From 358fd4756fcd7b8825a6e227fe7a9d77629aad58 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Tue, 3 Apr 2018 18:34:38 +0200 Subject: [PATCH 8/9] Update test flexisip configuration. --- tester/flexisip/README | 2 ++ tester/flexisip/flexisip-generic.conf | 3 +++ tester/flexisip/flexisip.conf | 2 ++ 3 files changed, 7 insertions(+) diff --git a/tester/flexisip/README b/tester/flexisip/README index b2799db77..c4dce60b8 100644 --- a/tester/flexisip/README +++ b/tester/flexisip/README @@ -1,3 +1,5 @@ flexisip.conf : is the configuration of the flexisip running on sip2.linphone.org. It has lots of IP addresses hardcoded because this machine is running multiple instances on different IP addresses. flexisip-generic.conf : is the same configuration without any IP address hardcoded and relative paths. It can be run on any machine from the "tester" directory of linphone. +Make sure that any changes performed on one of these two files is also made on the other. + diff --git a/tester/flexisip/flexisip-generic.conf b/tester/flexisip/flexisip-generic.conf index 2795738cd..a25e61166 100644 --- a/tester/flexisip/flexisip-generic.conf +++ b/tester/flexisip/flexisip-generic.conf @@ -115,6 +115,9 @@ filter= from.uri.domain contains 'sip.example.org' || from.uri.domain contains ' # Default value: auth-domains= sip.example.org auth.example.org auth1.example.org auth2.example.org +#regexp for test "TLS authentication - client rejected due to unmatched certificate subject" of Flexisip test suite. +tls-client-certificate-required-subject=galadrielle|sip:sip.example.org + # List of whitespace separated IP which will not be challenged. diff --git a/tester/flexisip/flexisip.conf b/tester/flexisip/flexisip.conf index 682f3180b..e5b800fe2 100644 --- a/tester/flexisip/flexisip.conf +++ b/tester/flexisip/flexisip.conf @@ -115,6 +115,8 @@ filter= from.uri.domain contains 'sip.example.org' || from.uri.domain contains ' # Default value: auth-domains= sip.example.org auth.example.org auth1.example.org auth2.example.org +#regexp for test "TLS authentication - client rejected due to unmatched certificate subject" of Flexisip test suite. +tls-client-certificate-required-subject=galadrielle|sip:sip.example.org # List of whitespace separated IP which will not be challenged. From 4b95c0d570c64406b7f7e8e9a07e048188f26b74 Mon Sep 17 00:00:00 2001 From: Simon Morlat Date: Wed, 13 Jun 2018 18:07:14 +0200 Subject: [PATCH 9/9] Reimplement commit 6368bc of master branch "Fix problem where address family is not guessed as it should (if we receive the INVITE just after sending the REGISTER but before receiving the response of the REGISTER)" --- src/sal/op.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sal/op.cpp b/src/sal/op.cpp index b53be38c3..b8df469df 100644 --- a/src/sal/op.cpp +++ b/src/sal/op.cpp @@ -457,8 +457,8 @@ int SalOp::getAddressFamily() const { if (mRefresher) { - belle_sip_response_t *resp = belle_sip_transaction_get_response(tr); - belle_sip_header_via_t *via = resp ?belle_sip_message_get_header_by_type(resp,belle_sip_header_via_t):NULL; + belle_sip_message_t *msg = belle_sip_transaction_get_response(tr) ? (belle_sip_message_t*) belle_sip_transaction_get_response(tr) : (belle_sip_message_t*) belle_sip_transaction_get_request(tr); + belle_sip_header_via_t *via = msg ? belle_sip_message_get_header_by_type(msg,belle_sip_header_via_t):NULL; const char *host; if (!via){ ms_error("Unable to determine IP version from signaling operation, no via header found.");