[#1744] Integrating some of the needed regular expression patterns in order

to parse the attribute line as defined in RFC4568. Still need to support
multiple inline: fields and multiple session-params. Added testing file
for the SdesNegotiator class. Still need to write proper unit tests.
This commit is contained in:
pierre-luc
2009-09-08 00:28:46 -04:00
parent a0a3b79901
commit 582b1049cf
3 changed files with 139 additions and 123 deletions

View File

@ -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)
{
}
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;
while (pos != std::string::npos && lineSplitted.size() != 4) {
token = line.substr(pos+1);
lineSplitted.push_back(token);
token = line.substr(0, pos);
line = token;
pos = line.rfind(WSP);
}
lineSplitted.push_back(line);
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;
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)
Regex tagPattern, cryptoSuitePattern, keyParamsPattern, sessionParamPattern;
try {
tagPattern = "^a=crypto:(?P<tag>[0-9]{1,9})";
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
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.");
}
// Take each line from the vector
// and parse its content
std::vector<std::string>::iterator iter;
for (iter = _remoteAttribute.begin(); iter != _remoteAttribute.end(); iter++) {
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;
}
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");
}
// 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");
}
// 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");
}
// 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");
}
// 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 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.");
}
int tagIndex;
std::istringstream ss(index);
ss >> tagIndex;
if (ss.fail()) {
throw std::runtime_error("Bad conversion");
}
// 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;
}
}
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
}
}
}