Files
jami-daemon/sflphone-common/src/sip/SdesNegotiator.cpp
2010-01-13 15:10:28 -05:00

205 lines
6.3 KiB
C++

/*
* Copyright (C) 2009 Savoir-Faire Linux inc.
* Author: Pierre-Luc Bacon <pierre-luc.bacon@savoirfairelinux.com>
*
* 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 3 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "SdesNegotiator.h"
#include "Pattern.h"
#include <cstdio>
#include <iostream>
#include <sstream>
#include <algorithm>
#include <stdexcept>
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),
_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)
Pattern
* generalSyntaxPattern,
* tagPattern,
* cryptoSuitePattern,
* keyParamsPattern,
* sessionParamPattern;
try {
// 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]");
cryptoSuitePattern = new Pattern (
"(?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 = new Pattern (
"(?P<srtpKeyMethod>inline|[A-Za-z0-9_]+)\\:" \
"(?P<srtpKeyInfo>[A-Za-z0-9\x2B\x2F\x3D]+|[\w\x2B\x2F\x3D]+)\\|" \
"2\\^(?P<lifetime>[0-9]+)\\|" \
"(?P<mkiValue>[0-9]+)\\:" \
"(?P<mkiLength>[0-9]{1,3})\\;?", "g");
sessionParamPattern = new Pattern (
"(?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:]]+))*", "g"); // 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;
// Split the line into its component
// that we will analyze further down.
std::vector<std::string> sdesLine;
*generalSyntaxPattern << (*iter);
try {
sdesLine = generalSyntaxPattern->split();
if (sdesLine.size() < 3) {
throw parse_error ("Missing components in SDES line");
}
} catch (match_error& exception) {
throw parse_error ("Error while analyzing the SDES line.");
}
// 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");
}
// 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");
}
// Parse one or more key-params field.
*keyParamsPattern << sdesLine.at (2);
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;
}
} catch (match_error& exception) {
throw parse_error ("Error while parsing the key-params field");
}
/**
* Parse the optional session-param fields
* @todo Implement this !
*/
/*
if (sdesLine.size() == 3) continue;
int i;
for (i = 3; i < sdesLine.size(); i++) {
sessionParamPattern << sdesLine.at(i);
while (sessionpParamPattern.matches()) {
} catch (match_error& exception) {
throw parse_error("Error while parsing the crypto-suite field");
}
}
} */
}
}
bool SdesNegotiator::negotiate (void)
{
parse();
return true;
}