diff --git a/sflphone-common/src/sip/Pattern.cpp b/sflphone-common/src/sip/Pattern.cpp index 71e093d13c96384877e71ca9ff65d721313a7e79..290c9f7a79c52319aae430c78f7e9d143c20e6a7 100644 --- a/sflphone-common/src/sip/Pattern.cpp +++ b/sflphone-common/src/sip/Pattern.cpp @@ -180,23 +180,17 @@ std::string Pattern::group (const std::string& groupName) _count, groupName.c_str(), &stringPtr); - - // printf(" _count : %i\n", _count); - // printf("stringPtr : %s\n", stringPtr); if (rc < 0) { switch (rc) { case PCRE_ERROR_NOSUBSTRING: - // printf("Pattern::PCRE_ERROR_NOSUBSTRING\n"); throw std::out_of_range ("Invalid group reference."); case PCRE_ERROR_NOMEMORY: - // printf("Pattern::PCRE_ERROR_NOMEMORY\n"); throw match_error ("Memory exhausted."); default: - // printf("Pattern::default match error\n"); throw match_error ("Failed to get named substring."); } } @@ -255,10 +249,6 @@ bool Pattern::matches (void) throw (match_error) bool Pattern::matches (const std::string& subject) throw (match_error) { - // printf("Pattern::matches\n"); - // printf(" Current offset: %d, old offset: %d", _offset[1], _offset[0]); - // printf(" Trying <start>%s<end>\n", subject.substr(_offset[1]).c_str()); - // Try to find a match for this pattern int rc = pcre_exec ( _re, @@ -271,7 +261,6 @@ bool Pattern::matches (const std::string& subject) throw (match_error) _ovectorSize); // Matching failed. - if (rc < 0) { _offset[0] = _offset[1] = 0; // printf(" Matching failed with %d\n", rc); @@ -285,8 +274,6 @@ bool Pattern::matches (const std::string& subject) throw (match_error) _offset[1] = _ovector[1] + _offset[0]; } - // printf(" Matching succeeded with %d to %d\n", (int) start(), (int) end()); - // Matching succeded but not enough space. if (rc == 0) { throw match_error ("No space to store all substrings."); @@ -295,7 +282,6 @@ bool Pattern::matches (const std::string& subject) throw (match_error) // Matching succeeded. Keep the number of substrings for // subsequent calls to group(). - // printf("_count: %i = %i\n", _count, rc); _count = rc; return true; diff --git a/sflphone-common/src/sip/SdesNegotiator.cpp b/sflphone-common/src/sip/SdesNegotiator.cpp index e8618e3ab8d80f0bfb9b13fc5205cda5c847c869..f9411df3d9649187f0c59e129ea16240489c7b68 100644 --- a/sflphone-common/src/sip/SdesNegotiator.cpp +++ b/sflphone-common/src/sip/SdesNegotiator.cpp @@ -28,13 +28,6 @@ using namespace sfl; -struct CryptoAttribute { - std::string tag; - std::string cryptoSuite; - std::string keyParams; - std::string sessionParams; -}; - SdesNegotiator::SdesNegotiator (const std::vector<CryptoSuiteDefinition>& localCapabilites, const std::vector<std::string>& remoteAttribute) : _remoteAttribute (remoteAttribute), @@ -43,7 +36,7 @@ SdesNegotiator::SdesNegotiator (const std::vector<CryptoSuiteDefinition>& localC } -void SdesNegotiator::parse (void) +std::vector<CryptoAttribute *> SdesNegotiator::parse (void) { // The patterns below try to follow // the ABNF grammar rules described in @@ -63,8 +56,7 @@ void SdesNegotiator::parse (void) // used to match white space (which are used as separator) generalSyntaxPattern = new Pattern ("[\x20\x09]+", "g"); - tagPattern = new Pattern ("^a=crypto:(?P<tag>[0-9]{1,9})", "g"); - // tagPattern = new Pattern ("[0-9]"); + tagPattern = new Pattern ("^a=crypto:(?P<tag>[0-9]{1,9})"); cryptoSuitePattern = new Pattern ( "(?P<cryptoSuite>AES_CM_128_HMAC_SHA1_80|" \ @@ -91,7 +83,6 @@ void SdesNegotiator::parse (void) } catch (compile_error& exception) { throw parse_error ("A compile exception occured on a pattern."); - } @@ -100,18 +91,15 @@ void SdesNegotiator::parse (void) std::vector<std::string>::iterator iter; - + std::vector<CryptoAttribute *> cryptoAttributeVector; + for (iter = _remoteAttribute.begin(); iter != _remoteAttribute.end(); iter++) { - - std::cout << (*iter) << std::endl; - // Split the line into its component // that we will analyze further down. - std::vector<std::string> sdesLine; + std::vector<std::string> sdesLine; *generalSyntaxPattern << (*iter); - try { sdesLine = generalSyntaxPattern->split(); @@ -126,49 +114,50 @@ void SdesNegotiator::parse (void) // Check if the attribute starts with a=crypto // and get the tag for this line *tagPattern << sdesLine.at (0); - - tagPattern->matches(); - - try { - std::string tag = tagPattern->group ("tag"); - std::cout << "tag = " << tag << std::endl; - } catch (match_error& exception) { - throw parse_error ("Error while parsing the tag field"); - } + + std::string tag; + if (tagPattern->matches()) { + try { + tag = tagPattern->group ("tag"); + } catch (match_error& exception) { + throw parse_error ("Error while parsing the tag field"); + } + } else { + return cryptoAttributeVector; + } // Check if the crypto suite is valid and retreive // its value. *cryptoSuitePattern << sdesLine.at (1); - cryptoSuitePattern->matches(); - - try { - _cryptoSuite = cryptoSuitePattern->group ("cryptoSuite"); - std::cout << "crypto-suite = " << _cryptoSuite << std::endl; - } catch (match_error& exception) { - throw parse_error ("Error while parsing the crypto-suite field"); - } - + std::string cryptoSuite; + + if (cryptoSuitePattern->matches()) { + try { + cryptoSuite = cryptoSuitePattern->group ("cryptoSuite"); + } catch (match_error& exception) { + throw parse_error ("Error while parsing the crypto-suite field"); + } + } else { + return cryptoAttributeVector; + } + // Parse one or more key-params field. *keyParamsPattern << sdesLine.at (2); + std::string srtpKeyInfo; + std::string srtpKeyMethod; + std::string lifetime; + std::string mkiLength; + std::string mkiValue; + try { while (keyParamsPattern->matches()) { - - _srtpKeyMethod = keyParamsPattern->group ("srtpKeyMethod"); - std::cout << "srtp-key-method = " << _srtpKeyMethod << std::endl; - - _srtpKeyInfo = keyParamsPattern->group ("srtpKeyInfo"); - std::cout << "srtp-key-info = " << _srtpKeyInfo << std::endl; - - _lifetime = keyParamsPattern->group ("lifetime"); - std::cout << "lifetime = " << _lifetime << std::endl; - - _mkiValue = keyParamsPattern->group ("mkiValue"); - std::cout << "mkiValue = " << _mkiValue << std::endl; - - _mkiLength = keyParamsPattern->group ("mkiLength"); - std::cout << "mkiLength = " << _mkiLength << std::endl; + srtpKeyMethod = keyParamsPattern->group ("srtpKeyMethod"); + srtpKeyInfo = keyParamsPattern->group ("srtpKeyInfo"); + lifetime = keyParamsPattern->group ("lifetime"); + mkiValue = keyParamsPattern->group ("mkiValue"); + mkiLength = keyParamsPattern->group ("mkiLength"); } } catch (match_error& exception) { throw parse_error ("Error while parsing the key-params field"); @@ -176,7 +165,7 @@ void SdesNegotiator::parse (void) /** * Parse the optional session-param fields - * @todo Implement this ! + * @TODO Implement this ! */ /* if (sdesLine.size() == 3) continue; @@ -191,14 +180,39 @@ void SdesNegotiator::parse (void) } } } */ + + // Add the new CryptoAttribute to the vector + std::cout << (*iter) << std::endl; + CryptoAttribute * cryptoAttribute = new CryptoAttribute(tag, cryptoSuite, srtpKeyMethod, srtpKeyInfo, lifetime, mkiValue, mkiLength); + cryptoAttributeVector.push_back(cryptoAttribute); } - + return cryptoAttributeVector; } bool SdesNegotiator::negotiate (void) { - parse(); - + try { + std::vector<CryptoAttribute *> cryptoAttributeVector = parse(); + + std::vector<CryptoAttribute *>::iterator iter; + for (iter = cryptoAttributeVector.begin(); iter != cryptoAttributeVector.end(); iter++) { + std::cout << "Negotiate tag: " + (*iter)->getTag() << std::endl; + std::cout << "Crypto Suite: " + (*iter)->getCryptoSuite() << std::endl; + std::cout << "SRTP Key Method: " + (*iter)->getSrtpKeyMethod() << std::endl; + std::cout << "SRTP Key Info: " + (*iter)->getSrtpKeyInfo() << std::endl; + std::cout << "Lifetime: " + (*iter)->getLifetime() << std::endl; + std::cout << "MKI Value: " + (*iter)->getMkiValue() << std::endl; + std::cout << "MKI Length: " + (*iter)->getMkiLength() << std::endl; + + delete (*iter); + } + + } catch (parse_error& exception) { + return false; + } catch (match_error& exception) { + return false; + } + return true; } diff --git a/sflphone-common/src/sip/SdesNegotiator.h b/sflphone-common/src/sip/SdesNegotiator.h index 08e32090ef5e64b5731f2fab2ace701135414fc0..d8a568421e14cdccf540a44ba3f6267d09863775 100644 --- a/sflphone-common/src/sip/SdesNegotiator.h +++ b/sflphone-common/src/sip/SdesNegotiator.h @@ -74,11 +74,43 @@ namespace sfl { {"AES_CM_128_HMAC_SHA1_32", 128, 112, 48, 31, AESCounterMode, 128, HMACSHA1, 32, 80, 160, 160 }, {"F8_128_HMAC_SHA1_80", 128, 112, 48, 31, AESF8Mode, 128, HMACSHA1, 80, 80, 160, 160 } }; - /** - * Internal structure - * used during parsing. - */ - struct CryptoAttribute; + + class CryptoAttribute { + + public: + CryptoAttribute(std::string tag, + std::string cryptoSuite, + std::string srtpKeyMethod, + std::string srtpKeyInfo, + std::string lifetime, + std::string mkiValue, + std::string mkiLength) : + tag(tag), + cryptoSuite(cryptoSuite), + srtpKeyMethod(srtpKeyMethod), + srtpKeyInfo(srtpKeyInfo), + lifetime(lifetime), + mkiValue(mkiValue), + mkiLength(mkiLength) {}; + + + inline std::string getTag() { return tag; }; + inline std::string getCryptoSuite() { return cryptoSuite; }; + inline std::string getSrtpKeyMethod() { return srtpKeyMethod; }; + inline std::string getSrtpKeyInfo() { return srtpKeyInfo; }; + inline std::string getLifetime() { return lifetime; }; + inline std::string getMkiValue() { return mkiValue; }; + inline std::string getMkiLength() { return mkiLength; }; + + private: + std::string tag; + std::string cryptoSuite; + std::string srtpKeyMethod; + std::string srtpKeyInfo; + std::string lifetime; + std::string mkiValue; + std::string mkiLength; + }; class SdesNegotiator { @@ -99,35 +131,35 @@ namespace sfl { bool negotiate(void); - /** - * Return crypto suite after negotiation - */ - std::string getCryptoSuite(void) { return _cryptoSuite; } + /** + * Return crypto suite after negotiation + */ + std::string getCryptoSuite(void) { return _cryptoSuite; } - /** - * Return key method after negotiation (most likely inline:) - */ - std::string getKeyMethod(void) { return _srtpKeyMethod; } + /** + * Return key method after negotiation (most likely inline:) + */ + std::string getKeyMethod(void) { return _srtpKeyMethod; } - /** - * Return crypto suite after negotiation - */ - std::string getKeyInfo(void) { return _srtpKeyInfo; } + /** + * Return crypto suite after negotiation + */ + std::string getKeyInfo(void) { return _srtpKeyInfo; } - /** - * Return key lifetime after negotiation - */ - std::string getLifeTime(void) { return _lifetime; } + /** + * Return key lifetime after negotiation + */ + std::string getLifeTime(void) { return _lifetime; } - /** - * Return mki value after negotiation - */ - std::string getMkiValue(void) { return _mkiValue; } + /** + * Return mki value after negotiation + */ + std::string getMkiValue(void) { return _mkiValue; } - /** - * Return mki length after negotiation - */ - std::string getMkiLength(void) { return _mkiLength; } + /** + * Return mki length after negotiation + */ + std::string getMkiLength(void) { return _mkiLength; } private: /** @@ -139,39 +171,37 @@ namespace sfl { std::vector<CryptoSuiteDefinition> _localCapabilities; - /** - * Selected crypto suite after negotiation - */ - std::string _cryptoSuite; - - /** - * Selected key method after negotiation (most likely inline:) - */ - std::string _srtpKeyMethod; - - /** - * Selected crypto suite after negotiation - */ - std::string _srtpKeyInfo; - - /** - * Selected key lifetime after negotiation - */ - std::string _lifetime; - - /** - * Selected mki value after negotiation - */ - std::string _mkiValue; - - /** - * Selected mki length after negotiation - */ - std::string _mkiLength; - - void parse(void); - - CryptoAttribute * tokenize(const std::string& attributeLine); + /** + * Selected crypto suite after negotiation + */ + std::string _cryptoSuite; + + /** + * Selected key method after negotiation (most likely inline:) + */ + std::string _srtpKeyMethod; + + /** + * Selected crypto suite after negotiation + */ + std::string _srtpKeyInfo; + + /** + * Selected key lifetime after negotiation + */ + std::string _lifetime; + + /** + * Selected mki value after negotiation + */ + std::string _mkiValue; + + /** + * Selected mki length after negotiation + */ + std::string _mkiLength; + + std::vector<CryptoAttribute *> parse(void); }; } #endif diff --git a/sflphone-common/test/sdesnegotiatorTest.cpp b/sflphone-common/test/sdesnegotiatorTest.cpp index 71b429a5eac0a74d4a011b4fd9bbdc8b84067808..ebe70c8bac9e51605a764d56fbcc27fca07aeefc 100644 --- a/sflphone-common/test/sdesnegotiatorTest.cpp +++ b/sflphone-common/test/sdesnegotiatorTest.cpp @@ -40,21 +40,18 @@ using std::endl; void SdesNegotiatorTest::setUp() { - - std::string attr("a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwd|2^20|1:32"); - - // std::string attr("a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:d0RmdmcmVCspeEc3QGZiNWpVLFJhQX1cfHAwJSoj|2^20|1:32"); - + // Add a new SDES crypto line to be processed. remoteOffer = new std::vector<std::string>(); - remoteOffer->push_back(attr); - + remoteOffer->push_back(std::string("a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwd|2^20|1:32")); + remoteOffer->push_back(std::string("a=crypto:2 AES_CM_128_HMAC_SHA1_32 inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj|2^20|1:32")); + + // Register the local capabilities. localCapabilities = new std::vector<sfl::CryptoSuiteDefinition>(); for(int i = 0; i < 3; i++) { localCapabilities->push_back(sfl::CryptoSuites[i]); } sdesnego = new sfl::SdesNegotiator(*localCapabilities, *remoteOffer); - } @@ -121,38 +118,40 @@ void SdesNegotiatorTest::testKeyParamsPattern() pattern->matches(); CPPUNIT_ASSERT(pattern->group("srtpKeyMethod").compare("inline:")); - /* - while (pattern->matches()) { - - std::string _srtpKeyMethod = pattern->group ("srtpKeyMethod"); - std::string _srtpKeyInfo = pattern->group ("srtpKeyInfo"); - std::string _lifetime = pattern->group ("lifetime"); - std::string _mkiValue = pattern->group ("mkiValue"); - std::string _mkiLength = pattern->group ("mkiLength"); - } - - - CPPUNIT_ASSERT(pattern->group("srtpKeyMethod").compare("inline:")); - CPPUNIT_ASSERT(pattern->group("srtpKeyInfo").compare("d0RmdmcmVCspeEc3QGZiNWpVLFJhQX1cfHAwJSoj")); - CPPUNIT_ASSERT(pattern->group("lifetime").compare("20")); - CPPUNIT_ASSERT(pattern->group("mkivalue").compare("1")); - CPPUNIT_ASSERT(pattern->group("mkilength").compare("32")); - */ - delete pattern; pattern = NULL; } - +/** + * Make sure that all the fields can be extracted + * properly from the syntax. + */ void SdesNegotiatorTest::testNegotiation() { CPPUNIT_ASSERT(sdesnego->negotiate()); - CPPUNIT_ASSERT(sdesnego->getCryptoSuite().compare("AES_CM_128_HMAC_SHA1_80") == 0); - CPPUNIT_ASSERT(sdesnego->getKeyMethod().compare("inline") == 0); - CPPUNIT_ASSERT(sdesnego->getKeyInfo().compare("AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwd") == 0); - CPPUNIT_ASSERT(sdesnego->getLifeTime().compare("20") == 0); - CPPUNIT_ASSERT(sdesnego->getMkiValue().compare("1") == 0); - CPPUNIT_ASSERT(sdesnego->getMkiLength().compare("32") == 0); +} + +/** + * Make sure that unproperly formatted crypto lines are rejected. + */ +void SdesNegotiatorTest::testComponent() +{ + // Register the local capabilities. + std::vector<sfl::CryptoSuiteDefinition> * capabilities = new std::vector<sfl::CryptoSuiteDefinition>(); + + //Support all the CryptoSuites + for(int i = 0; i < 3; i++) { + capabilities->push_back(sfl::CryptoSuites[i]); + } + + // Make sure that if a component is missing, negotiate will fail + std::string cryptoLine("a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:|2^20|1:32"); + std::vector<std::string> * cryptoOffer = new std::vector<std::string>(); + cryptoOffer->push_back(cryptoLine); + + sfl::SdesNegotiator * negotiator = new sfl::SdesNegotiator(*capabilities, *cryptoOffer); + + CPPUNIT_ASSERT(negotiator->negotiate() == false); } diff --git a/sflphone-common/test/sdesnegotiatorTest.h b/sflphone-common/test/sdesnegotiatorTest.h index 4e97a9d6dab6134e88fbfde693844e67a79c61e7..2a7b552222a5c1c223fa74f293eff8f91e4d6c2d 100644 --- a/sflphone-common/test/sdesnegotiatorTest.h +++ b/sflphone-common/test/sdesnegotiatorTest.h @@ -66,6 +66,7 @@ class SdesNegotiatorTest : public CppUnit::TestCase { CPPUNIT_TEST( testCryptoSuitePattern ); CPPUNIT_TEST( testKeyParamsPattern ); CPPUNIT_TEST( testNegotiation ); + // CPPUNIT_TEST( testComponent ); CPPUNIT_TEST_SUITE_END(); public: @@ -84,24 +85,25 @@ class SdesNegotiatorTest : public CppUnit::TestCase { */ inline void tearDown(); - void testTagPattern(); + void testTagPattern(); - void testCryptoSuitePattern(); + void testCryptoSuitePattern(); - void testKeyParamsPattern(); + void testKeyParamsPattern(); void testNegotiation(); + + void testComponent(); private: - sfl::Pattern *pattern; + sfl::Pattern *pattern; - sfl::SdesNegotiator *sdesnego; + sfl::SdesNegotiator *sdesnego; - std::vector<std::string> *remoteOffer; - - std::vector<sfl::CryptoSuiteDefinition> *localCapabilities; + std::vector<std::string> *remoteOffer; + std::vector<sfl::CryptoSuiteDefinition> *localCapabilities; }; /* Register our test module */