summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Swiften/Client/ClientSession.cpp4
-rw-r--r--Swiften/SASL/SCRAMSHA1ClientAuthenticator.cpp23
-rw-r--r--Swiften/SASL/SCRAMSHA1ClientAuthenticator.h7
-rw-r--r--Swiften/SASL/UnitTest/SCRAMSHA1ClientAuthenticatorTest.cpp46
4 files changed, 74 insertions, 6 deletions
diff --git a/Swiften/Client/ClientSession.cpp b/Swiften/Client/ClientSession.cpp
index a7f39b6..0398012 100644
--- a/Swiften/Client/ClientSession.cpp
+++ b/Swiften/Client/ClientSession.cpp
@@ -192,10 +192,10 @@ void ClientSession::handleElement(boost::shared_ptr<Element> element) {
stream->writeElement(boost::shared_ptr<Element>(new AuthRequest("EXTERNAL", "")));
}
else if (streamFeatures->hasAuthenticationMechanism("SCRAM-SHA-1")) {
- // FIXME: Use a real nonce
std::ostringstream s;
s << boost::uuids::random_generator()();
- authenticator = new SCRAMSHA1ClientAuthenticator(s.str());
+ SCRAMSHA1ClientAuthenticator* scramAuthenticator = new SCRAMSHA1ClientAuthenticator(s.str(), false);
+ authenticator = scramAuthenticator;
state = WaitingForCredentials;
onNeedCredentials();
}
diff --git a/Swiften/SASL/SCRAMSHA1ClientAuthenticator.cpp b/Swiften/SASL/SCRAMSHA1ClientAuthenticator.cpp
index 551afd5..4e00397 100644
--- a/Swiften/SASL/SCRAMSHA1ClientAuthenticator.cpp
+++ b/Swiften/SASL/SCRAMSHA1ClientAuthenticator.cpp
@@ -35,7 +35,7 @@ static String escape(const String& s) {
}
-SCRAMSHA1ClientAuthenticator::SCRAMSHA1ClientAuthenticator(const String& nonce) : ClientAuthenticator("SCRAM-SHA-1"), step(Initial), clientnonce(nonce) {
+SCRAMSHA1ClientAuthenticator::SCRAMSHA1ClientAuthenticator(const String& nonce, bool useChannelBinding) : ClientAuthenticator("SCRAM-SHA-1"), step(Initial), clientnonce(nonce), useChannelBinding(useChannelBinding) {
}
boost::optional<ByteArray> SCRAMSHA1ClientAuthenticator::getResponse() const {
@@ -50,7 +50,11 @@ boost::optional<ByteArray> SCRAMSHA1ClientAuthenticator::getResponse() const {
for (unsigned int i = 0; i < clientProof.getSize(); ++i) {
clientProof[i] ^= clientSignature[i];
}
- ByteArray result = ByteArray("c=") + Base64::encode(getGS2Header()) + ",r=" + clientnonce + serverNonce + ",p=" + Base64::encode(clientProof);
+ ByteArray channelBindData;
+ if (useChannelBinding && tlsChannelBindingData) {
+ channelBindData = *tlsChannelBindingData;
+ }
+ ByteArray result = ByteArray("c=") + Base64::encode(getGS2Header() + channelBindData) + ",r=" + clientnonce + serverNonce + ",p=" + Base64::encode(clientProof);
return result;
}
else {
@@ -146,7 +150,20 @@ ByteArray SCRAMSHA1ClientAuthenticator::getInitialBareClientMessage() const {
}
ByteArray SCRAMSHA1ClientAuthenticator::getGS2Header() const {
- return ByteArray("n,") + (getAuthorizationID().isEmpty() ? "" : "a=" + escape(getAuthorizationID())) + ",";
+ ByteArray channelBindingHeader("n");
+ if (tlsChannelBindingData) {
+ if (useChannelBinding) {
+ channelBindingHeader = ByteArray("p=tls-server-end-point");
+ }
+ else {
+ channelBindingHeader = ByteArray("y");
+ }
+ }
+ return channelBindingHeader + ByteArray(",") + (getAuthorizationID().isEmpty() ? "" : "a=" + escape(getAuthorizationID())) + ",";
+}
+
+void SCRAMSHA1ClientAuthenticator::setTLSChannelBindingData(const ByteArray& channelBindingData) {
+ this->tlsChannelBindingData = channelBindingData;
}
}
diff --git a/Swiften/SASL/SCRAMSHA1ClientAuthenticator.h b/Swiften/SASL/SCRAMSHA1ClientAuthenticator.h
index 396cc93..b44e6b7 100644
--- a/Swiften/SASL/SCRAMSHA1ClientAuthenticator.h
+++ b/Swiften/SASL/SCRAMSHA1ClientAuthenticator.h
@@ -7,6 +7,7 @@
#pragma once
#include <map>
+#include <boost/optional.hpp>
#include "Swiften/Base/String.h"
#include "Swiften/Base/ByteArray.h"
@@ -15,7 +16,9 @@
namespace Swift {
class SCRAMSHA1ClientAuthenticator : public ClientAuthenticator {
public:
- SCRAMSHA1ClientAuthenticator(const String& nonce);
+ SCRAMSHA1ClientAuthenticator(const String& nonce, bool useChannelBinding = false);
+
+ void setTLSChannelBindingData(const ByteArray& channelBindingData);
virtual boost::optional<ByteArray> getResponse() const;
virtual bool setChallenge(const boost::optional<ByteArray>&);
@@ -38,5 +41,7 @@ namespace Swift {
ByteArray authMessage;
ByteArray saltedPassword;
ByteArray serverSignature;
+ bool useChannelBinding;
+ boost::optional<ByteArray> tlsChannelBindingData;
};
}
diff --git a/Swiften/SASL/UnitTest/SCRAMSHA1ClientAuthenticatorTest.cpp b/Swiften/SASL/UnitTest/SCRAMSHA1ClientAuthenticatorTest.cpp
index b65cdd3..0d12bd3 100644
--- a/Swiften/SASL/UnitTest/SCRAMSHA1ClientAuthenticatorTest.cpp
+++ b/Swiften/SASL/UnitTest/SCRAMSHA1ClientAuthenticatorTest.cpp
@@ -18,7 +18,11 @@ class SCRAMSHA1ClientAuthenticatorTest : public CppUnit::TestFixture {
CPPUNIT_TEST(testGetInitialResponse_UsernameHasSpecialChars);
CPPUNIT_TEST(testGetInitialResponse_WithAuthorizationID);
CPPUNIT_TEST(testGetInitialResponse_WithAuthorizationIDWithSpecialChars);
+ CPPUNIT_TEST(testGetInitialResponse_WithoutChannelBindingWithTLSChannelBindingData);
+ CPPUNIT_TEST(testGetInitialResponse_WithChannelBindingWithTLSChannelBindingData);
CPPUNIT_TEST(testGetFinalResponse);
+ CPPUNIT_TEST(testGetFinalResponse_WithoutChannelBindingWithTLSChannelBindingData);
+ CPPUNIT_TEST(testGetFinalResponse_WithChannelBindingWithTLSChannelBindingData);
CPPUNIT_TEST(testSetChallenge);
CPPUNIT_TEST(testSetChallenge_InvalidClientNonce);
CPPUNIT_TEST(testSetChallenge_OnlyClientNonce);
@@ -71,6 +75,26 @@ class SCRAMSHA1ClientAuthenticatorTest : public CppUnit::TestFixture {
CPPUNIT_ASSERT_EQUAL(String("n,a=a=3Du=2Cth,n=user,r=abcdefghABCDEFGH"), response.toString());
}
+ void testGetInitialResponse_WithoutChannelBindingWithTLSChannelBindingData() {
+ SCRAMSHA1ClientAuthenticator testling("abcdefghABCDEFGH", false);
+ testling.setTLSChannelBindingData("xyza");
+ testling.setCredentials("user", "pass", "");
+
+ ByteArray response = *testling.getResponse();
+
+ CPPUNIT_ASSERT_EQUAL(String("y,,n=user,r=abcdefghABCDEFGH"), response.toString());
+ }
+
+ void testGetInitialResponse_WithChannelBindingWithTLSChannelBindingData() {
+ SCRAMSHA1ClientAuthenticator testling("abcdefghABCDEFGH", true);
+ testling.setTLSChannelBindingData("xyza");
+ testling.setCredentials("user", "pass", "");
+
+ ByteArray response = *testling.getResponse();
+
+ CPPUNIT_ASSERT_EQUAL(String("p=tls-server-end-point,,n=user,r=abcdefghABCDEFGH"), response.toString());
+ }
+
void testGetFinalResponse() {
SCRAMSHA1ClientAuthenticator testling("abcdefgh");
testling.setCredentials("user", "pass", "");
@@ -81,6 +105,28 @@ class SCRAMSHA1ClientAuthenticatorTest : public CppUnit::TestFixture {
CPPUNIT_ASSERT_EQUAL(String("c=biws,r=abcdefghABCDEFGH,p=CZbjGDpIteIJwQNBgO0P8pKkMGY="), response.toString());
}
+ void testGetFinalResponse_WithoutChannelBindingWithTLSChannelBindingData() {
+ SCRAMSHA1ClientAuthenticator testling("abcdefgh", false);
+ testling.setCredentials("user", "pass", "");
+ testling.setTLSChannelBindingData("xyza");
+ testling.setChallenge(ByteArray("r=abcdefghABCDEFGH,s=MTIzNDU2NzgK,i=4096"));
+
+ ByteArray response = *testling.getResponse();
+
+ CPPUNIT_ASSERT_EQUAL(String("c=eSws,r=abcdefghABCDEFGH,p=JNpsiFEcxZvNZ1+FFBBqrYvYxMk="), response.toString());
+ }
+
+ void testGetFinalResponse_WithChannelBindingWithTLSChannelBindingData() {
+ SCRAMSHA1ClientAuthenticator testling("abcdefgh", true);
+ testling.setCredentials("user", "pass", "");
+ testling.setTLSChannelBindingData("xyza");
+ testling.setChallenge(ByteArray("r=abcdefghABCDEFGH,s=MTIzNDU2NzgK,i=4096"));
+
+ ByteArray response = *testling.getResponse();
+
+ CPPUNIT_ASSERT_EQUAL(String("c=cD10bHMtc2VydmVyLWVuZC1wb2ludCwseHl6YQ==,r=abcdefghABCDEFGH,p=ycZyNs03w1HlRzFmXl8dlKx3NAU="), response.toString());
+ }
+
void testSetFinalChallenge() {
SCRAMSHA1ClientAuthenticator testling("abcdefgh");
testling.setCredentials("user", "pass", "");