diff options
| -rw-r--r-- | Swiften/Client/ClientSession.cpp | 4 | ||||
| -rw-r--r-- | Swiften/SASL/SCRAMSHA1ClientAuthenticator.cpp | 23 | ||||
| -rw-r--r-- | Swiften/SASL/SCRAMSHA1ClientAuthenticator.h | 7 | ||||
| -rw-r--r-- | Swiften/SASL/UnitTest/SCRAMSHA1ClientAuthenticatorTest.cpp | 46 | 
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", ""); | 
 Swift
 Swift