diff --git a/sflphone-common/src/sip/SdesNegotiator.cpp b/sflphone-common/src/sip/SdesNegotiator.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4f7d4a4b0bc2a336c31e6ce474ed3010999c213a --- /dev/null +++ b/sflphone-common/src/sip/SdesNegotiator.cpp @@ -0,0 +1,173 @@ +/* + * 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 "regex.h" + +#include <iostream> +#include <sstream> +#include <algorithm> +#include <stdexcept> + +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) + { + + } + + 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; + 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 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 + + + } + + + } + + bool SdesNegotiator::negotiate(void) + { + parse(); + } +} diff --git a/sflphone-common/src/sip/SdesNegotiator.h b/sflphone-common/src/sip/SdesNegotiator.h new file mode 100644 index 0000000000000000000000000000000000000000..a88811c6d2cb67f4cdbcf42c9dc3d24d1c524abd --- /dev/null +++ b/sflphone-common/src/sip/SdesNegotiator.h @@ -0,0 +1,106 @@ +/* + * 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. + */ +#ifndef __SFL_SDES_NEGOTIATOR_H__ +#define __SFL_SDES_NEGOTIATOR_H__ + +#include <vector> +#include <string> + +namespace sfl { + + enum CipherMode { + AESCounterMode, + AESF8Mode + }; + + enum MACMode { + HMACSHA1 + }; + + enum KeyMethod { + Inline + // url, maybe at some point + }; + + struct CryptoSuiteDefinition { + char * name; + int masterKeyLength; + int masterSaltLength; + int srtpLifetime; + int srtcpLifetime; + CipherMode cipher; + int encryptionKeyLength; + MACMode mac; + int srtpAuthTagLength; + int srtcpAuthTagLength; + int srtpAuthKeyLength; + int srtcpAuthKeyLen; + }; + + /** + * List of accepted Crypto-Suites + * as defined in RFC4568 (6.2) + */ + const CryptoSuiteDefinition CryptoSuites[3] = { + {"AES_CM_128_HMAC_SHA1_80", 128, 112, 48, 31, AESCounterMode, 128, HMACSHA1, 80, 80, 160, 160 }, + {"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 SdesNegotiator + { + /** + * Constructor for an SDES crypto attributes + * negotiator. + * + * @param attribute + * A vector of crypto attributes as defined in + * RFC4568. This string will be parsed + * and a crypto context will be created + * from it. + */ + + public: + SdesNegotiator(const std::vector<CryptoSuiteDefinition>& localCapabilites, const std::vector<std::string>& remoteAttribute); + ~SdesNegotiator() { }; + + public: + bool negotiate(void); + + private: + /** + * A vector list containing the remote attributes. + * Multiple crypto lines can be sent, and the + * prefered method is then chosen from that list. + */ + std::vector<std::string> _remoteAttribute; + std::vector<CryptoSuiteDefinition> _localCapabilities; + + + + private: + bool parse(void); + CryptoAttribute * tokenize(const std::string& attributeLine); + }; +} +#endif