/* * Copyright 2008 Ben Boeckel * * 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, see . */ // Header include #include "ChallengeMediator.h" // Protocol includes #include "PacketMaker.h" // QCA includes #include // Qt includes #include #include #include Signet::Protocol::ChallengeMediator::ChallengeMediator(QTcpSocket* socket, Side side, const QStringList& receivers) : m_side(side), m_receivers(receivers), m_error(NoError), m_socket(socket) { } Signet::Protocol::ChallengeMediator::Error Signet::Protocol::ChallengeMediator::challenge(const QByteArray& id, const QByteArray& secret) { if (m_side != Client) return SideError; QByteArray clientKey; QByteArray serverKey; QByteArray clientResponse; QByteArray serverResponse; QByteArray expectedServerResponse; init(id); recvServerKey(&serverKey); if (m_error != NoError) { notifyServerFail(); return m_error; } clientKey = generateChallengeKey(); clientResponse = generateResponse(clientKey, serverKey, secret); expectedServerResponse = generateResponse(serverKey, clientKey, secret); sendClientResponse(clientKey, clientResponse); recvServerResponse(&serverResponse); if (m_error != NoError) { notifyServerFail(); return m_error; } if (serverResponse == expectedServerResponse) notifyServerPass(); else notifyServerFail(); return m_error; } Signet::Protocol::ChallengeMediator::Error Signet::Protocol::ChallengeMediator::challenged(const QByteArray& secret) { if (m_side != Server) return SideError; QByteArray clientKey; QByteArray serverKey; QByteArray clientResponse; QByteArray serverResponse; QByteArray expectedClientResponse; if (!secret.size()) notifyClientUnknown(); serverKey = generateChallengeKey(); sendServerKey(serverKey); recvClientResponse(&clientKey, &clientResponse); if (m_error != NoError) { notifyClientFail(); return m_error; } expectedClientResponse = generateResponse(clientKey, serverKey, secret); if (clientResponse != expectedClientResponse) notifyClientFail(); if (m_error != NoError) return m_error; serverResponse = generateResponse(serverKey, clientKey, secret); sendServerResponse(serverResponse); recvClientAnswer(); return m_error; } QByteArray Signet::Protocol::ChallengeMediator::generateChallengeKey() { return QUuid::createUuid().toString().toUtf8(); } QByteArray Signet::Protocol::ChallengeMediator::generateResponse(const QByteArray& key1, const QByteArray& key2, const QByteArray& secret) { if (QCA::isSupported("sha256")) { QByteArray total; total.append(key1); total.append(key2); total.append(secret); return QCA::Hash("sha256").hash(total).toByteArray(); } qFatal("SHA-256 is not supported"); return QByteArray(); } void Signet::Protocol::ChallengeMediator::init(const QByteArray& id) { PacketMaker::challenge(m_socket, id, m_receivers); } void Signet::Protocol::ChallengeMediator::sendServerKey(const QByteArray& serverKey) { PacketMaker::challengeKey(m_socket, serverKey, m_receivers); } void Signet::Protocol::ChallengeMediator::recvServerKey(QByteArray* serverKey) { QBuffer buffer(serverKey); Packet packet = PacketMaker::unwrap(m_socket); if (packet.isValid()) { if (packet.receivers() == m_receivers) { if (packet.type() == Packet::ChallengeKey) packet.rawDump(&buffer); else if (packet.type() == Packet::Denial) m_error = UnknownUser; else m_error = UnexpectedError; } else m_error = ReceiverError; } else m_error = SocketError; } void Signet::Protocol::ChallengeMediator::sendClientResponse(const QByteArray& clientKey, const QByteArray& clientResponse) { PacketMaker::challengeKey(m_socket, clientKey, m_receivers); PacketMaker::challengeResponse(m_socket, clientResponse, m_receivers); } void Signet::Protocol::ChallengeMediator::recvClientResponse(QByteArray* clientKey, QByteArray* clientResponse) { QBuffer buffer(clientKey); Packet packet = PacketMaker::unwrap(m_socket); if (packet.isValid()) { if (packet.receivers() == m_receivers) { if (packet.type() == Packet::ChallengeKey) { packet.rawDump(&buffer); buffer.setBuffer(clientResponse); packet = PacketMaker::unwrap(m_socket); if (packet.isValid()) { if (packet.type() == Packet::ChallengeResponse) packet.rawDump(&buffer); else m_error = UnexpectedError; } else m_error = SocketError; } else m_error = UnexpectedError; } else m_error = ReceiverError; } else m_error = SocketError; } void Signet::Protocol::ChallengeMediator::sendServerResponse(const QByteArray& serverResponse) { PacketMaker::challengeResponse(m_socket, serverResponse, m_receivers); } void Signet::Protocol::ChallengeMediator::recvServerResponse(QByteArray* serverResponse) { QBuffer buffer(serverResponse); Packet packet = PacketMaker::unwrap(m_socket); if (packet.isValid()) { if (packet.receivers() == m_receivers) { if (packet.type() == Packet::ChallengeResponse) packet.rawDump(&buffer); else if (packet.type() == Packet::Denial) m_error = ClientFailed; else m_error = UnexpectedError; } else m_error = ReceiverError; } else m_error = SocketError; } void Signet::Protocol::ChallengeMediator::recvClientAnswer() { Packet packet = PacketMaker::unwrap(m_socket); if (packet.isValid()) { if (packet.receivers() == m_receivers) { if (packet.type() == Packet::Denial) m_error = ServerFailed; else if (packet.type() != Packet::Acceptance) m_error = UnexpectedError; } else m_error = ReceiverError; } else m_error = SocketError; } void Signet::Protocol::ChallengeMediator::notifyServerFail() { PacketMaker::deny(m_socket, m_receivers); m_error = ServerFailed; } void Signet::Protocol::ChallengeMediator::notifyServerPass() { PacketMaker::accept(m_socket, m_receivers); } void Signet::Protocol::ChallengeMediator::notifyClientFail() { PacketMaker::deny(m_socket, m_receivers); m_error = ClientFailed; } void Signet::Protocol::ChallengeMediator::notifyClientUnknown() { PacketMaker::deny(m_socket, m_receivers); m_error = UnknownUser; }