From 4b65bb3fc0cfa55cf0533406877da20fb4da9e7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Remko=20Tron=C3=A7on?= Date: Fri, 10 Dec 2010 18:17:16 +0100 Subject: Added TLS channel binding support to SCRAMSHA1ClientAuthenticator. 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) { stream->writeElement(boost::shared_ptr(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 SCRAMSHA1ClientAuthenticator::getResponse() const { @@ -50,7 +50,11 @@ boost::optional 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 +#include #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 getResponse() const; virtual bool setChallenge(const boost::optional&); @@ -38,5 +41,7 @@ namespace Swift { ByteArray authMessage; ByteArray saltedPassword; ByteArray serverSignature; + bool useChannelBinding; + boost::optional 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", ""); -- cgit v0.10.2-6-g49f6