version 3.0
This commit is contained in:
commit
d837490606
209 changed files with 19662 additions and 0 deletions
233
ssh/ssh_algorithm_negotiation.cc
Normal file
233
ssh/ssh_algorithm_negotiation.cc
Normal file
|
|
@ -0,0 +1,233 @@
|
|||
/*
|
||||
* Copyright (c) 2011-2012 Juli Mallett. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <common/buffer.h>
|
||||
#include <common/endian.h>
|
||||
|
||||
#include <crypto/crypto_random.h>
|
||||
|
||||
#include <ssh/ssh_algorithm_negotiation.h>
|
||||
#include <ssh/ssh_compression.h>
|
||||
#include <ssh/ssh_encryption.h>
|
||||
#include <ssh/ssh_key_exchange.h>
|
||||
#include <ssh/ssh_language.h>
|
||||
#include <ssh/ssh_mac.h>
|
||||
#include <ssh/ssh_protocol.h>
|
||||
#include <ssh/ssh_server_host_key.h>
|
||||
#include <ssh/ssh_session.h>
|
||||
#include <ssh/ssh_filter.h>
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// //
|
||||
// File: ssh_algorithm_negotiation.cc //
|
||||
// Description: SSH algorithm selection at session start //
|
||||
// Project: WANProxy XTech //
|
||||
// Adapted by: Andreu Vidal Bramfeld-Software //
|
||||
// Last modified: 2015-04-01 //
|
||||
// //
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace {
|
||||
template<typename T>
|
||||
std::vector<Buffer> names(const std::list<T>& list)
|
||||
{
|
||||
typename std::list<T>::const_iterator it;
|
||||
std::vector<Buffer> vec;
|
||||
|
||||
for (it = list.begin(); it != list.end(); ++it) {
|
||||
const T alg = *it;
|
||||
vec.push_back(alg->name());
|
||||
}
|
||||
return (vec);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool choose_algorithm(SSH::Role role,
|
||||
T *chosenp,
|
||||
std::list<T>& algorithm_list,
|
||||
Buffer *in, const std::string& type)
|
||||
{
|
||||
std::vector<Buffer> local_algorithms = names(algorithm_list);
|
||||
std::vector<Buffer> remote_algorithms;
|
||||
if (!SSH::NameList::decode(remote_algorithms, in)) {
|
||||
ERROR("/ssh/algorithm/negotiation") << "Failed to decode " << type << " name-list.";
|
||||
return (false);
|
||||
}
|
||||
|
||||
if (remote_algorithms.empty() && local_algorithms.empty()) {
|
||||
DEBUG("/ssh/algorithm/negotiation") << "Neither client nor server has any preference in " << type << " algorithms.";
|
||||
return (true);
|
||||
}
|
||||
|
||||
const std::vector<Buffer> *client_algorithms;
|
||||
const std::vector<Buffer> *server_algorithms;
|
||||
if (role == SSH::ClientRole) {
|
||||
client_algorithms = &local_algorithms;
|
||||
server_algorithms = &remote_algorithms;
|
||||
} else {
|
||||
client_algorithms = &remote_algorithms;
|
||||
server_algorithms = &local_algorithms;
|
||||
}
|
||||
|
||||
std::vector<Buffer>::const_iterator it;
|
||||
for (it = client_algorithms->begin();
|
||||
it != client_algorithms->end(); ++it) {
|
||||
std::vector<Buffer>::const_iterator it2;
|
||||
|
||||
for (it2 = server_algorithms->begin();
|
||||
it2 != server_algorithms->end(); ++it2) {
|
||||
const Buffer& server = *it2;
|
||||
if (!it->equal(&server))
|
||||
continue;
|
||||
std::string algorithm;
|
||||
it->extract(algorithm);
|
||||
|
||||
typename std::list<T>::const_iterator ait;
|
||||
for (ait = algorithm_list.begin(); ait != algorithm_list.end(); ++ait) {
|
||||
const T alg = *ait;
|
||||
if (alg->name() != algorithm)
|
||||
continue;
|
||||
|
||||
*chosenp = alg->clone();
|
||||
|
||||
DEBUG("/ssh/algorithm/negotiation") << "Selected " << type << " algorithm " << algorithm;
|
||||
return (true);
|
||||
}
|
||||
NOTREACHED("/ssh/algorithm/negotiation");
|
||||
}
|
||||
}
|
||||
|
||||
ERROR("/ssh/algorithm/negotiation") << "Failed to choose " << type << " algorithm.";
|
||||
return (false);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SSH::AlgorithmNegotiation::add_algorithms(void)
|
||||
{
|
||||
SSH::KeyExchange::add_algorithms(session_);
|
||||
if (session_->role_ == ClientRole)
|
||||
SSH::ServerHostKey::add_client_algorithms(session_);
|
||||
SSH::Encryption::add_algorithms(session_);
|
||||
SSH::MAC::add_algorithms(session_);
|
||||
add_algorithm(SSH::Compression::none());
|
||||
/* XXX Add languages? */
|
||||
}
|
||||
|
||||
bool
|
||||
SSH::AlgorithmNegotiation::input(Filter* sender, Buffer *in)
|
||||
{
|
||||
Buffer packet;
|
||||
|
||||
switch (in->peek()) {
|
||||
case SSH::Message::KeyExchangeInitializationMessage:
|
||||
session_->remote_kexinit(*in);
|
||||
if (!choose_algorithms(in)) {
|
||||
ERROR(log_) << "Unable to negotiate algorithms.";
|
||||
return (false);
|
||||
}
|
||||
DEBUG(log_) << "Chose algorithms.";
|
||||
|
||||
if (session_->role_ == ClientRole && session_->chosen_algorithms_.key_exchange_ != NULL) {
|
||||
Buffer out;
|
||||
if (!session_->chosen_algorithms_.key_exchange_->init(&out)) {
|
||||
ERROR(log_) << "Could not start new key exchange.";
|
||||
return (false);
|
||||
}
|
||||
if (!out.empty())
|
||||
sender->produce(out);
|
||||
}
|
||||
return (true);
|
||||
case SSH::Message::NewKeysMessage:
|
||||
packet.append(SSH::Message::NewKeysMessage);
|
||||
sender->produce(packet);
|
||||
|
||||
session_->activate_chosen();
|
||||
DEBUG(log_) << "Switched to new keys.";
|
||||
return (true);
|
||||
default:
|
||||
DEBUG(log_) << "Unsupported algorithm negotiation message:" << std::endl << in->hexdump();
|
||||
return (false);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
SSH::AlgorithmNegotiation::init(Buffer *out)
|
||||
{
|
||||
ASSERT(log_, out->empty());
|
||||
|
||||
Buffer cookie;
|
||||
if (!CryptoRandomMethod::default_method->generate(CryptoTypeRNG, 16, &cookie))
|
||||
return (false);
|
||||
|
||||
out->append(SSH::Message::KeyExchangeInitializationMessage);
|
||||
out->append(cookie);
|
||||
SSH::NameList::encode(out, names(algorithms_.key_exchange_list_));
|
||||
SSH::NameList::encode(out, names(algorithms_.server_host_key_list_));
|
||||
SSH::NameList::encode(out, names(algorithms_.encryption_client_to_server_list_));
|
||||
SSH::NameList::encode(out, names(algorithms_.encryption_server_to_client_list_));
|
||||
SSH::NameList::encode(out, names(algorithms_.mac_client_to_server_list_));
|
||||
SSH::NameList::encode(out, names(algorithms_.mac_server_to_client_list_));
|
||||
SSH::NameList::encode(out, names(algorithms_.compression_client_to_server_list_));
|
||||
SSH::NameList::encode(out, names(algorithms_.compression_server_to_client_list_));
|
||||
SSH::NameList::encode(out, names(algorithms_.language_client_to_server_list_));
|
||||
SSH::NameList::encode(out, names(algorithms_.language_server_to_client_list_));
|
||||
out->append(SSH::Boolean::False);
|
||||
uint32_t reserved(0);
|
||||
out->append(&reserved);
|
||||
|
||||
session_->local_kexinit(*out);
|
||||
|
||||
return (true);
|
||||
}
|
||||
|
||||
bool
|
||||
SSH::AlgorithmNegotiation::choose_algorithms(Buffer *in)
|
||||
{
|
||||
in->skip(17);
|
||||
|
||||
if (!choose_algorithm(session_->role_, &session_->chosen_algorithms_.key_exchange_, algorithms_.key_exchange_list_, in, "Key Exchange"))
|
||||
return (false);
|
||||
if (!choose_algorithm(session_->role_, &session_->chosen_algorithms_.server_host_key_, algorithms_.server_host_key_list_, in, "Server Host Key"))
|
||||
return (false);
|
||||
if (!choose_algorithm(session_->role_, &session_->chosen_algorithms_.client_to_server_.encryption_, algorithms_.encryption_client_to_server_list_, in, "Encryption (Client->Server)"))
|
||||
return (false);
|
||||
if (!choose_algorithm(session_->role_, &session_->chosen_algorithms_.server_to_client_.encryption_, algorithms_.encryption_server_to_client_list_, in, "Encryption (Server->Client)"))
|
||||
return (false);
|
||||
if (!choose_algorithm(session_->role_, &session_->chosen_algorithms_.client_to_server_.mac_, algorithms_.mac_client_to_server_list_, in, "MAC (Client->Server)"))
|
||||
return (false);
|
||||
if (!choose_algorithm(session_->role_, &session_->chosen_algorithms_.server_to_client_.mac_, algorithms_.mac_server_to_client_list_, in, "MAC (Server->Client)"))
|
||||
return (false);
|
||||
if (!choose_algorithm(session_->role_, &session_->chosen_algorithms_.client_to_server_.compression_, algorithms_.compression_client_to_server_list_, in, "Compression (Client->Server)"))
|
||||
return (false);
|
||||
if (!choose_algorithm(session_->role_, &session_->chosen_algorithms_.server_to_client_.compression_, algorithms_.compression_server_to_client_list_, in, "Compression (Server->Client)"))
|
||||
return (false);
|
||||
if (!choose_algorithm(session_->role_, &session_->chosen_algorithms_.client_to_server_.language_, algorithms_.language_client_to_server_list_, in, "Language (Client->Server)"))
|
||||
return (false);
|
||||
if (!choose_algorithm(session_->role_, &session_->chosen_algorithms_.server_to_client_.language_, algorithms_.language_server_to_client_list_, in, "Language (Server->Client)"))
|
||||
return (false);
|
||||
|
||||
return (true);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue