summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRemko Tronçon <git@el-tramo.be>2009-11-20 22:53:40 (GMT)
committerRemko Tronçon <git@el-tramo.be>2009-11-20 22:53:40 (GMT)
commit4417a63a1acdf5f6e78655e8ae377bc24d5d8f02 (patch)
tree0c682fcc582a9f1181f436d5e5d98180fdf5387a /Swiften
parent4e944a225d91ff4622e50186120ef0bbbb3a1d69 (diff)
downloadswift-4417a63a1acdf5f6e78655e8ae377bc24d5d8f02.zip
swift-4417a63a1acdf5f6e78655e8ae377bc24d5d8f02.tar.bz2
Implement SCRAM-SHA1.
Actually found out that I implemented the old RFC. Need to reimplement SCRAM-SHA1 from scratch based on http://tools.ietf.org/html/draft-ietf-sasl-scram-10 Disabling for now.
Diffstat (limited to 'Swiften')
-rw-r--r--Swiften/Client/ClientSession.cpp19
-rw-r--r--Swiften/SASL/SCRAMSHA1ClientAuthenticator.cpp2
2 files changed, 20 insertions, 1 deletions
diff --git a/Swiften/Client/ClientSession.cpp b/Swiften/Client/ClientSession.cpp
index 06a7617..f4c4a22 100644
--- a/Swiften/Client/ClientSession.cpp
+++ b/Swiften/Client/ClientSession.cpp
@@ -1,161 +1,180 @@
#include "Swiften/Client/ClientSession.h"
#include <boost/bind.hpp>
#include "Swiften/Elements/ProtocolHeader.h"
#include "Swiften/Elements/StreamFeatures.h"
#include "Swiften/Elements/StartTLSRequest.h"
#include "Swiften/Elements/StartTLSFailure.h"
#include "Swiften/Elements/TLSProceed.h"
#include "Swiften/Elements/AuthRequest.h"
#include "Swiften/Elements/AuthSuccess.h"
#include "Swiften/Elements/AuthFailure.h"
+#include "Swiften/Elements/AuthChallenge.h"
+#include "Swiften/Elements/AuthResponse.h"
#include "Swiften/Elements/StartSession.h"
#include "Swiften/Elements/IQ.h"
#include "Swiften/Elements/ResourceBind.h"
#include "Swiften/SASL/PLAINClientAuthenticator.h"
+#include "Swiften/SASL/SCRAMSHA1ClientAuthenticator.h"
#include "Swiften/Session/SessionStream.h"
namespace Swift {
ClientSession::ClientSession(
const JID& jid,
boost::shared_ptr<SessionStream> stream) :
localJID(jid),
state(Initial),
stream(stream),
needSessionStart(false),
authenticator(NULL) {
}
void ClientSession::start() {
stream->onStreamStartReceived.connect(boost::bind(&ClientSession::handleStreamStart, shared_from_this(), _1));
stream->onElementReceived.connect(boost::bind(&ClientSession::handleElement, shared_from_this(), _1));
stream->onError.connect(boost::bind(&ClientSession::handleStreamError, shared_from_this(), _1));
stream->onTLSEncrypted.connect(boost::bind(&ClientSession::handleTLSEncrypted, shared_from_this()));
assert(state == Initial);
state = WaitingForStreamStart;
sendStreamHeader();
}
void ClientSession::sendStreamHeader() {
ProtocolHeader header;
header.setTo(getRemoteJID());
stream->writeHeader(header);
}
void ClientSession::sendElement(boost::shared_ptr<Element> element) {
stream->writeElement(element);
}
void ClientSession::handleStreamStart(const ProtocolHeader&) {
checkState(WaitingForStreamStart);
state = Negotiating;
}
void ClientSession::handleElement(boost::shared_ptr<Element> element) {
if (getState() == Initialized) {
onElementReceived(element);
}
else if (StreamFeatures* streamFeatures = dynamic_cast<StreamFeatures*>(element.get())) {
if (!checkState(Negotiating)) {
return;
}
if (streamFeatures->hasStartTLS() && stream->supportsTLSEncryption()) {
state = WaitingForEncrypt;
stream->writeElement(boost::shared_ptr<StartTLSRequest>(new StartTLSRequest()));
}
else if (streamFeatures->hasAuthenticationMechanisms()) {
if (stream->hasTLSCertificate()) {
if (streamFeatures->hasAuthenticationMechanism("EXTERNAL")) {
state = Authenticating;
stream->writeElement(boost::shared_ptr<Element>(new AuthRequest("EXTERNAL", "")));
}
else {
finishSession(Error::TLSClientCertificateError);
}
}
+ /*else if (streamFeatures->hasAuthenticationMechanism("SCRAM-SHA-1")) {
+ // FIXME: Use a real nonce
+ authenticator = new SCRAMSHA1ClientAuthenticator(ByteArray("\x01\x02\x03\x04\x05\x06\x07\x08", 8));
+ state = WaitingForCredentials;
+ onNeedCredentials();
+ }*/
else if (streamFeatures->hasAuthenticationMechanism("PLAIN")) {
authenticator = new PLAINClientAuthenticator();
state = WaitingForCredentials;
onNeedCredentials();
}
else {
finishSession(Error::NoSupportedAuthMechanismsError);
}
}
else {
// Start the session
stream->setWhitespacePingEnabled(true);
if (streamFeatures->hasSession()) {
needSessionStart = true;
}
if (streamFeatures->hasResourceBind()) {
state = BindingResource;
boost::shared_ptr<ResourceBind> resourceBind(new ResourceBind());
if (!localJID.getResource().isEmpty()) {
resourceBind->setResource(localJID.getResource());
}
stream->writeElement(IQ::createRequest(IQ::Set, JID(), "session-bind", resourceBind));
}
else if (needSessionStart) {
sendSessionStart();
}
else {
state = Initialized;
onInitialized();
}
}
}
+ else if (AuthChallenge* challenge = dynamic_cast<AuthChallenge*>(element.get())) {
+ checkState(Authenticating);
+ assert(authenticator);
+ if (authenticator->setChallenge(challenge->getValue())) {
+ stream->writeElement(boost::shared_ptr<AuthResponse>(new AuthResponse(authenticator->getResponse())));
+ }
+ else {
+ finishSession(Error::AuthenticationFailedError);
+ }
+ }
else if (dynamic_cast<AuthSuccess*>(element.get())) {
checkState(Authenticating);
state = WaitingForStreamStart;
delete authenticator;
authenticator = NULL;
stream->resetXMPPParser();
sendStreamHeader();
}
else if (dynamic_cast<AuthFailure*>(element.get())) {
delete authenticator;
authenticator = NULL;
finishSession(Error::AuthenticationFailedError);
}
else if (dynamic_cast<TLSProceed*>(element.get())) {
checkState(WaitingForEncrypt);
state = Encrypting;
stream->addTLSEncryption();
}
else if (dynamic_cast<StartTLSFailure*>(element.get())) {
finishSession(Error::TLSError);
}
else if (IQ* iq = dynamic_cast<IQ*>(element.get())) {
if (state == BindingResource) {
boost::shared_ptr<ResourceBind> resourceBind(iq->getPayload<ResourceBind>());
if (iq->getType() == IQ::Error && iq->getID() == "session-bind") {
finishSession(Error::ResourceBindError);
}
else if (!resourceBind) {
finishSession(Error::UnexpectedElementError);
}
else if (iq->getType() == IQ::Result) {
localJID = resourceBind->getJID();
if (!localJID.isValid()) {
finishSession(Error::ResourceBindError);
}
if (needSessionStart) {
sendSessionStart();
}
else {
state = Initialized;
}
}
else {
finishSession(Error::UnexpectedElementError);
}
}
else if (state == StartingSession) {
if (iq->getType() == IQ::Result) {
diff --git a/Swiften/SASL/SCRAMSHA1ClientAuthenticator.cpp b/Swiften/SASL/SCRAMSHA1ClientAuthenticator.cpp
index 3109f56..f5c55c0 100644
--- a/Swiften/SASL/SCRAMSHA1ClientAuthenticator.cpp
+++ b/Swiften/SASL/SCRAMSHA1ClientAuthenticator.cpp
@@ -1,56 +1,56 @@
#include "Swiften/SASL/SCRAMSHA1ClientAuthenticator.h"
#include <cassert>
#include "Swiften/StringCodecs/SHA1.h"
#include "Swiften/StringCodecs/HMACSHA1.h"
namespace Swift {
-SCRAMSHA1ClientAuthenticator::SCRAMSHA1ClientAuthenticator(const ByteArray& nonce) : ClientAuthenticator("SCRAM-SHA1"), step(Initial), clientnonce(nonce) {
+SCRAMSHA1ClientAuthenticator::SCRAMSHA1ClientAuthenticator(const ByteArray& nonce) : ClientAuthenticator("SCRAM-SHA-1"), step(Initial), clientnonce(nonce) {
}
ByteArray SCRAMSHA1ClientAuthenticator::getResponse() const {
if (step == Initial) {
return getInitialClientMessage();
}
else {
ByteArray mask = HMACSHA1::getResult(getClientVerifier(), initialServerMessage + getInitialClientMessage());
ByteArray p = SHA1::getBinaryHash(getPassword());
for (unsigned int i = 0; i < p.getSize(); ++i) {
p[i] ^= mask[i];
}
return p;
}
}
bool SCRAMSHA1ClientAuthenticator::setChallenge(const ByteArray& response) {
if (step == Initial) {
initialServerMessage = response;
step = Proof;
return getSalt().getSize() > 0;
}
else {
return response == HMACSHA1::getResult(getClientVerifier(), getInitialClientMessage() + initialServerMessage);
}
}
ByteArray SCRAMSHA1ClientAuthenticator::getSalt() const {
if (initialServerMessage.getSize() < 8) {
std::cerr << "ERROR: SCRAM-SHA1: Invalid server response" << std::endl;
return ByteArray();
}
else {
return ByteArray(initialServerMessage.getData(), 8);
}
}
ByteArray SCRAMSHA1ClientAuthenticator::getClientVerifier() const {
return HMACSHA1::getResult(SHA1::getBinaryHash(getPassword()), getSalt());
}
ByteArray SCRAMSHA1ClientAuthenticator::getInitialClientMessage() const {
return ByteArray(getAuthorizationID()) + '\0' + ByteArray(getAuthenticationID()) + '\0' + ByteArray(clientnonce);
}
}