diff --git a/sflphone-common/src/sip/SdesNegotiator.cpp b/sflphone-common/src/sip/SdesNegotiator.cpp index 4f7d4a4b0bc2a336c31e6ce474ed3010999c213a..cedfc5e909357f13170213cafcf3ddac105c8faf 100644 --- a/sflphone-common/src/sip/SdesNegotiator.cpp +++ b/sflphone-common/src/sip/SdesNegotiator.cpp @@ -18,7 +18,7 @@ #include "SdesNegotiator.h" -#include "regex.h" +#include "Regex.h" #include <iostream> #include <sstream> @@ -34,134 +34,119 @@ namespace sfl { std::string sessionParams; }; - SdesNegotiator::SdesNegotiator(const std::vector<CryptoSuiteDefinition>& localCapabilites, const std::vector<std::string>& remoteAttribute) : + SdesNegotiator::SdesNegotiator(const std::vector<CryptoSuiteDefinition>& localCapabilites, + const std::vector<std::string>& remoteAttribute) : _remoteAttribute(remoteAttribute), _localCapabilities(localCapabilites) { } + + void SdesNegotiator::parse(void) + { + // The patterns below try to follow + // the ABNF grammar rules described in + // RFC4568 section 9.2 with the general + // syntax : + //a=crypto:tag 1*WSP crypto-suite 1*WSP key-params *(1*WSP session-param) - CryptoAttribute * SdesNegotiator::tokenize(const std::string& attributeLine) - { - // Split the line into at most - // 4 components corresponding to - // a=crypto:<tag> <crypto-suite> <key-params> [<session-params>] - size_t pos; - const char WSP = ' '; - std::string line(attributeLine); - - pos = line.rfind(WSP); - - std::string token; - std::vector<std::string> lineSplitted; + Regex tagPattern, cryptoSuitePattern, keyParamsPattern, sessionParamPattern; - while (pos != std::string::npos && lineSplitted.size() != 4) { + try { + tagPattern = "^a=crypto:(?P<tag>[0-9]{1,9})"; - token = line.substr(pos+1); - lineSplitted.push_back(token); + cryptoSuitePattern = "[\x20\x09]+(?P<cryptoSuite>AES_CM_128_HMAC_SHA1_80|" \ + "AES_CM_128_HMAC_SHA1_32|" \ + "F8_128_HMAC_SHA1_80|" \ + "[A-Za-z0-9_]+)"; // srtp-crypto-suite-ext - token = line.substr(0, pos); - line = token; - - pos = line.rfind(WSP); + keyParamsPattern = "[\x20\x09]+(?P<srtpKeyMethod>inline|[A-Za-z0-9_]+)\\:" \ + "(?P<srtpKeyInfo>[A-Za-z0-9\x2B\x2F\x3D]+)\\|" \ + "2\\^(?P<lifetime>[0-9]+)\\|" \ + "(?P<mkiValue>[0-9]+)\\:" \ + "(?P<mkiLength>[0-9]{1,3})\\;?"; + sessionParamPattern = "[\x20\x09]+(?P<sessionParam>(kdr\\=[0-9]{1,2}|" \ + "UNENCRYPTED_SRTP|" \ + "UNENCRYPTED_SRTCP|" \ + "UNAUTHENTICATED_SRTP|" \ + "FEC_ORDER=(?P<fecOrder>FEC_SRTP|SRTP_FEC)|" \ + "FEC_KEY=(?P<fecKey>" + keyParamsPattern.getPattern() + ")|" \ + "WSH=(?P<wsh>[0-9]{1,2})|" \ + "(?<!\\-)[[:graph:]]+))*"; // srtp-session-extension + + } catch(compile_error& exception) { + throw parse_error("A compile exception occured on a pattern."); + } + - lineSplitted.push_back(line); + // Take each line from the vector + // and parse its content + + std::vector<std::string>::iterator iter; + for (iter = _remoteAttribute.begin(); iter != _remoteAttribute.end(); iter++) { - CryptoAttribute * cryptoLine; - // Build up the new CryptoAttribute - try { - cryptoLine = new CryptoAttribute(); - } catch (std::bad_alloc&) { - std::cerr << "Failed create new CryptoLine" << std::endl; - throw; - } - - std::reverse(lineSplitted.begin(), lineSplitted.end()); - - cryptoLine->tag = lineSplitted.at(0); - cryptoLine->cryptoSuite = lineSplitted.at(1); - cryptoLine->keyParams = lineSplitted.at(2); - if (lineSplitted.size() == 4) { - cryptoLine->sessionParams = lineSplitted.at(3); - } - - return cryptoLine; - } - - bool SdesNegotiator::parse(void) - { - std::vector<std::string>::iterator iter; - - for (iter = _remoteAttribute.begin(); iter != _remoteAttribute.end(); iter++) { - - // Split the line into components - // and build up a CryptoAttribute - // structure. - CryptoAttribute * cryptoLine; + std::cout << (*iter) << std::endl; + + // Check if the attribute + // starts with a=crypto + // and get the tag for this line + tagPattern << (*iter); try { - cryptoLine = tokenize((*iter)); - } catch (...) { - std::cerr << "An exception occured" << std::endl; - } - - // Check if we have the right kind of attribute - if (cryptoLine->tag.find("a=crypto:") != 0) { - std::cout << cryptoLine->tag << std::endl; - throw std::runtime_error("Bad syntax"); - } - - // Find index - size_t tagPos; - tagPos = cryptoLine->tag.find(":"); - if (tagPos == std::string::npos) { - throw std::runtime_error("Bad syntax"); + 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 index; - index = cryptoLine->tag.substr(tagPos+1); - - std::cout << "index:" << index << std::endl; - // Make sure its less than 9 digit long - if (index.length() > 9) { - throw std::runtime_error("Index too long."); + // Check if the crypto + // suite is valid and retreive + // its value. + cryptoSuitePattern << (*iter); + try { + std::string 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"); } - int tagIndex; - std::istringstream ss(index); - ss >> tagIndex; - if (ss.fail()) { - throw std::runtime_error("Bad conversion"); + // Parse one or more key-params + // field. + keyParamsPattern << (*iter); + try { + std::string srtpKeyMethod = keyParamsPattern.group("srtpKeyMethod"); + std::cout << "srtp-key-method = " << srtpKeyMethod << std::endl; + + std::string srtpKeyInfo = keyParamsPattern.group("srtpKeyInfo"); + std::cout << "srtp-key-info = " << srtpKeyInfo << std::endl; + + std::string lifetime = keyParamsPattern.group("lifetime"); + std::cout << "lifetime = " << lifetime << std::endl; + + std::string mkiValue = keyParamsPattern.group("mkiValue"); + std::cout << "mkiValue = " << mkiValue << std::endl; + + std::string mkiLength = keyParamsPattern.group("mkiLength"); + std::cout << "mkiLength = " << mkiLength << std::endl; + + } catch (match_error& exception) { + throw parse_error("Error while parsing the key-params field"); } - // Check if the given crypto-suite is valid - // by looking in our list. - // Extension: 1*(ALPHA / DIGIT / "_") - int i; - for (i = 0; i < 3; i++) { - if (cryptoLine->cryptoSuite.compare(CryptoSuites[i].name) == 0) { - break; - } - } + // Parse the optional session-param + // field + sessionParamPattern << (*iter); + try { + std::string sessionParam = sessionParamPattern.group("sessionParam"); + std::cout << "srtp-session-param = " << sessionParam << std::endl; + } catch (not_found& exception){ + // Thats totally find, do nothing + } catch (match_error& exception) { + throw parse_error("Error while parsing the crypto-suite field"); + } - if (i == 3) { - std::cout << "This is an unhandled extension\n" << std::endl; - } - - // Parse the key-params - // Check it starts with a valid key-method - if (cryptoLine->keyParams.find("inline:") != 0) { - throw std::runtime_error("Unsupported key-method\n"); - } - - KeyMethod method = Inline; - - // Find concatenated key and salt values - - - } + } } diff --git a/sflphone-common/src/sip/SdesNegotiator.h b/sflphone-common/src/sip/SdesNegotiator.h index a88811c6d2cb67f4cdbcf42c9dc3d24d1c524abd..2dded5b1a7582002646dc07451ca8e8bb40fb107 100644 --- a/sflphone-common/src/sip/SdesNegotiator.h +++ b/sflphone-common/src/sip/SdesNegotiator.h @@ -18,10 +18,23 @@ #ifndef __SFL_SDES_NEGOTIATOR_H__ #define __SFL_SDES_NEGOTIATOR_H__ -#include <vector> +#include <stdexcept> #include <string> +#include <vector> namespace sfl { + + /** + * General exception object that is thrown when + * an error occured with a regular expression + * operation. + */ + class parse_error : public std::invalid_argument + { + public: + explicit parse_error(const std::string& error) : + std::invalid_argument(error) {} + }; enum CipherMode { AESCounterMode, @@ -99,7 +112,7 @@ namespace sfl { private: - bool parse(void); + void parse(void); CryptoAttribute * tokenize(const std::string& attributeLine); }; } diff --git a/sflphone-common/src/sip/testSdesNegotiator.cpp b/sflphone-common/src/sip/testSdesNegotiator.cpp new file mode 100644 index 0000000000000000000000000000000000000000..52de8b6e11a4121386510182859e9f19250a22c4 --- /dev/null +++ b/sflphone-common/src/sip/testSdesNegotiator.cpp @@ -0,0 +1,18 @@ +#include "SdesNegotiator.h" +#include <vector> +#include <iostream> + +int main(void) +{ +std::vector<sfl::CryptoSuiteDefinition> localCapabilities; +std::vector<std::string> remoteOffer; + +remoteOffer.push_back("a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:d0RmdmcmVCspeEc3QGZiNWpVLFJhQX1cfHAwJSoj|2^20|1:32"); +remoteOffer.push_back("a=crypto:1 AES_CM_128_HMAC_SHA1_32 inline:NzB4d1BINUAvLEw6UzF3WSJ+PSdFcGdUJShpX1Zj|2^20|1:32"); + +sfl::SdesNegotiator sdesNegotiator(localCapabilities, remoteOffer); + +sdesNegotiator.negotiate(); + +return 0; +}