diff options
Diffstat (limited to 'Swiften/SASL')
-rw-r--r-- | Swiften/SASL/ClientAuthenticator.cpp | 11 | ||||
-rw-r--r-- | Swiften/SASL/ClientAuthenticator.h | 43 | ||||
-rw-r--r-- | Swiften/SASL/PLAINClientAuthenticator.cpp | 16 | ||||
-rw-r--r-- | Swiften/SASL/PLAINClientAuthenticator.h | 13 | ||||
-rw-r--r-- | Swiften/SASL/PLAINMessage.cpp | 38 | ||||
-rw-r--r-- | Swiften/SASL/PLAINMessage.h | 33 | ||||
-rw-r--r-- | Swiften/SASL/SCRAMSHA1ClientAuthenticator.cpp | 143 | ||||
-rw-r--r-- | Swiften/SASL/SCRAMSHA1ClientAuthenticator.h | 36 | ||||
-rw-r--r-- | Swiften/SASL/SConscript | 12 | ||||
-rw-r--r-- | Swiften/SASL/UnitTest/PLAINClientAuthenticatorTest.cpp | 32 | ||||
-rw-r--r-- | Swiften/SASL/UnitTest/PLAINMessageTest.cpp | 61 | ||||
-rw-r--r-- | Swiften/SASL/UnitTest/SCRAMSHA1ClientAuthenticatorTest.cpp | 172 |
12 files changed, 610 insertions, 0 deletions
diff --git a/Swiften/SASL/ClientAuthenticator.cpp b/Swiften/SASL/ClientAuthenticator.cpp new file mode 100644 index 0000000..5fc9e85 --- /dev/null +++ b/Swiften/SASL/ClientAuthenticator.cpp @@ -0,0 +1,11 @@ +#include "Swiften/SASL/ClientAuthenticator.h" + +namespace Swift { + +ClientAuthenticator::ClientAuthenticator(const String& name) : name(name) { +} + +ClientAuthenticator::~ClientAuthenticator() { +} + +} diff --git a/Swiften/SASL/ClientAuthenticator.h b/Swiften/SASL/ClientAuthenticator.h new file mode 100644 index 0000000..f42a51e --- /dev/null +++ b/Swiften/SASL/ClientAuthenticator.h @@ -0,0 +1,43 @@ +#pragma once + +#include "Swiften/Base/String.h" +#include "Swiften/Base/ByteArray.h" + +namespace Swift { + class ClientAuthenticator { + public: + ClientAuthenticator(const String& name); + virtual ~ClientAuthenticator(); + + const String& getName() const { + return name; + } + + void setCredentials(const String& authcid, const String& password, const String& authzid = String()) { + this->authcid = authcid; + this->password = password; + this->authzid = authzid; + } + + virtual ByteArray getResponse() const = 0; + virtual bool setChallenge(const ByteArray&) = 0; + + const String& getAuthenticationID() const { + return authcid; + } + + const String& getAuthorizationID() const { + return authzid; + } + + const String& getPassword() const { + return password; + } + + private: + String name; + String authcid; + String password; + String authzid; + }; +} diff --git a/Swiften/SASL/PLAINClientAuthenticator.cpp b/Swiften/SASL/PLAINClientAuthenticator.cpp new file mode 100644 index 0000000..8f88c3c --- /dev/null +++ b/Swiften/SASL/PLAINClientAuthenticator.cpp @@ -0,0 +1,16 @@ +#include "Swiften/SASL/PLAINClientAuthenticator.h" + +namespace Swift { + +PLAINClientAuthenticator::PLAINClientAuthenticator() : ClientAuthenticator("PLAIN") { +} + +ByteArray PLAINClientAuthenticator::getResponse() const { + return ByteArray(getAuthorizationID()) + '\0' + ByteArray(getAuthenticationID()) + '\0' + ByteArray(getPassword()); +} + +bool PLAINClientAuthenticator::setChallenge(const ByteArray&) { + return true; +} + +} diff --git a/Swiften/SASL/PLAINClientAuthenticator.h b/Swiften/SASL/PLAINClientAuthenticator.h new file mode 100644 index 0000000..854eb30 --- /dev/null +++ b/Swiften/SASL/PLAINClientAuthenticator.h @@ -0,0 +1,13 @@ +#pragma once + +#include "Swiften/SASL/ClientAuthenticator.h" + +namespace Swift { + class PLAINClientAuthenticator : public ClientAuthenticator { + public: + PLAINClientAuthenticator(); + + virtual ByteArray getResponse() const; + virtual bool setChallenge(const ByteArray&); + }; +} diff --git a/Swiften/SASL/PLAINMessage.cpp b/Swiften/SASL/PLAINMessage.cpp new file mode 100644 index 0000000..66f8cd0 --- /dev/null +++ b/Swiften/SASL/PLAINMessage.cpp @@ -0,0 +1,38 @@ +#include "Swiften/SASL/PLAINMessage.h" + +namespace Swift { + +PLAINMessage::PLAINMessage(const String& authcid, const String& password, const String& authzid) : authcid(authcid), authzid(authzid), password(password) { +} + +PLAINMessage::PLAINMessage(const ByteArray& value) { + size_t i = 0; + while (i < value.getSize() && value[i] != '\0') { + authzid += value[i]; + ++i; + } + if (i == value.getSize()) { + return; + } + ++i; + while (i < value.getSize() && value[i] != '\0') { + authcid += value[i]; + ++i; + } + if (i == value.getSize()) { + authcid = ""; + return; + } + ++i; + while (i < value.getSize()) { + password += value[i]; + ++i; + } +} + +ByteArray PLAINMessage::getValue() const { + String s = authzid + '\0' + authcid + '\0' + password; + return ByteArray(s.getUTF8Data(), s.getUTF8Size()); +} + +} diff --git a/Swiften/SASL/PLAINMessage.h b/Swiften/SASL/PLAINMessage.h new file mode 100644 index 0000000..dd5e2ee --- /dev/null +++ b/Swiften/SASL/PLAINMessage.h @@ -0,0 +1,33 @@ +// TODO: Get rid of this +// +#pragma once + +#include "Swiften/Base/String.h" +#include "Swiften/Base/ByteArray.h" + +namespace Swift { + class PLAINMessage { + public: + PLAINMessage(const String& authcid, const String& password, const String& authzid = ""); + PLAINMessage(const ByteArray& value); + + ByteArray getValue() const; + + const String& getAuthenticationID() const { + return authcid; + } + + const String& getPassword() const { + return password; + } + + const String& getAuthorizationID() const { + return authzid; + } + + private: + String authcid; + String authzid; + String password; + }; +} diff --git a/Swiften/SASL/SCRAMSHA1ClientAuthenticator.cpp b/Swiften/SASL/SCRAMSHA1ClientAuthenticator.cpp new file mode 100644 index 0000000..5dc924e --- /dev/null +++ b/Swiften/SASL/SCRAMSHA1ClientAuthenticator.cpp @@ -0,0 +1,143 @@ +#include "Swiften/SASL/SCRAMSHA1ClientAuthenticator.h" + +#include <cassert> +#include <map> +#include <boost/lexical_cast.hpp> + +#include "Swiften/StringCodecs/SHA1.h" +#include "Swiften/StringCodecs/Base64.h" +#include "Swiften/StringCodecs/HMACSHA1.h" +#include "Swiften/StringCodecs/PBKDF2.h" +#include "Swiften/StringPrep/StringPrep.h" + +namespace Swift { + +static String escape(const String& s) { + String result; + for (size_t i = 0; i < s.getUTF8Size(); ++i) { + if (s[i] == ',') { + result += "=2C"; + } + else if (s[i] == '=') { + result += "=3D"; + } + else { + result += s[i]; + } + } + return result; +} + + +SCRAMSHA1ClientAuthenticator::SCRAMSHA1ClientAuthenticator(const String& nonce) : ClientAuthenticator("SCRAM-SHA-1"), step(Initial), clientnonce(nonce) { +} + +ByteArray SCRAMSHA1ClientAuthenticator::getResponse() const { + if (step == Initial) { + return getGS2Header() + getInitialBareClientMessage(); + } + else if (step == Proof) { + ByteArray clientKey = HMACSHA1::getResult(saltedPassword, "Client Key"); + ByteArray storedKey = SHA1::getHash(clientKey); + ByteArray clientSignature = HMACSHA1::getResult(storedKey, authMessage); + ByteArray clientProof = clientKey; + 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); + return result; + } + else { + return ByteArray(); + } +} + +bool SCRAMSHA1ClientAuthenticator::setChallenge(const ByteArray& challenge) { + if (step == Initial) { + initialServerMessage = challenge; + + std::map<char, String> keys = parseMap(String(initialServerMessage.getData(), initialServerMessage.getSize())); + + // Extract the salt + ByteArray salt = Base64::decode(keys['s']); + + // Extract the server nonce + String clientServerNonce = keys['r']; + if (clientServerNonce.getUTF8Size() <= clientnonce.getUTF8Size()) { + return false; + } + String receivedClientNonce = clientServerNonce.getSubstring(0, clientnonce.getUTF8Size()); + if (receivedClientNonce != clientnonce) { + return false; + } + serverNonce = clientServerNonce.getSubstring(clientnonce.getUTF8Size(), clientServerNonce.npos()); + + // Extract the number of iterations + int iterations = 0; + try { + iterations = boost::lexical_cast<int>(keys['i'].getUTF8String()); + } + catch (const boost::bad_lexical_cast&) { + return false; + } + if (iterations <= 0) { + return false; + } + + // Compute all the values needed for the server signature + saltedPassword = PBKDF2::encode(StringPrep::getPrepared(getPassword(), StringPrep::SASLPrep), salt, iterations); + authMessage = getInitialBareClientMessage() + "," + initialServerMessage + "," + "c=" + Base64::encode(getGS2Header()) + ",r=" + clientnonce + serverNonce; + ByteArray serverKey = HMACSHA1::getResult(saltedPassword, "Server Key"); + serverSignature = HMACSHA1::getResult(serverKey, authMessage); + + step = Proof; + return true; + } + else if (step == Proof) { + ByteArray result = ByteArray("v=") + ByteArray(Base64::encode(serverSignature)); + step = Final; + return challenge == result; + } + else { + return true; + } +} + +std::map<char, String> SCRAMSHA1ClientAuthenticator::parseMap(const String& s) { + std::map<char, String> result; + if (s.getUTF8Size() > 0) { + char key; + String value; + size_t i = 0; + bool expectKey = true; + while (i < s.getUTF8Size()) { + if (expectKey) { + key = s[i]; + expectKey = false; + i++; + } + else if (s[i] == ',') { + result[key] = value; + value = ""; + expectKey = true; + } + else { + value += s[i]; + } + i++; + } + result[key] = value; + } + return result; +} + +ByteArray SCRAMSHA1ClientAuthenticator::getInitialBareClientMessage() const { + String authenticationID = StringPrep::getPrepared(getAuthenticationID(), StringPrep::SASLPrep); + return ByteArray(String("n=" + escape(authenticationID) + ",r=" + clientnonce)); +} + +ByteArray SCRAMSHA1ClientAuthenticator::getGS2Header() const { + return ByteArray("n,") + (getAuthorizationID().isEmpty() ? "" : "a=" + escape(getAuthorizationID())) + ","; +} + +} diff --git a/Swiften/SASL/SCRAMSHA1ClientAuthenticator.h b/Swiften/SASL/SCRAMSHA1ClientAuthenticator.h new file mode 100644 index 0000000..3d28014 --- /dev/null +++ b/Swiften/SASL/SCRAMSHA1ClientAuthenticator.h @@ -0,0 +1,36 @@ +#pragma once + +#include <map> + +#include "Swiften/Base/String.h" +#include "Swiften/Base/ByteArray.h" +#include "Swiften/SASL/ClientAuthenticator.h" + +namespace Swift { + class SCRAMSHA1ClientAuthenticator : public ClientAuthenticator { + public: + SCRAMSHA1ClientAuthenticator(const String& nonce); + + virtual ByteArray getResponse() const; + virtual bool setChallenge(const ByteArray&); + + private: + ByteArray getInitialBareClientMessage() const; + ByteArray getGS2Header() const; + + static std::map<char, String> parseMap(const String&); + + private: + enum Step { + Initial, + Proof, + Final + } step; + String clientnonce; + ByteArray initialServerMessage; + ByteArray serverNonce; + ByteArray authMessage; + ByteArray saltedPassword; + ByteArray serverSignature; + }; +} diff --git a/Swiften/SASL/SConscript b/Swiften/SASL/SConscript new file mode 100644 index 0000000..22b242e --- /dev/null +++ b/Swiften/SASL/SConscript @@ -0,0 +1,12 @@ +Import("swiften_env") + +myenv = swiften_env.Clone() +myenv.MergeFlags(swiften_env["LIBIDN_FLAGS"]) + +objects = myenv.StaticObject([ + "ClientAuthenticator.cpp", + "PLAINClientAuthenticator.cpp", + "PLAINMessage.cpp", + "SCRAMSHA1ClientAuthenticator.cpp", + ]) +swiften_env.Append(SWIFTEN_OBJECTS = [objects]) diff --git a/Swiften/SASL/UnitTest/PLAINClientAuthenticatorTest.cpp b/Swiften/SASL/UnitTest/PLAINClientAuthenticatorTest.cpp new file mode 100644 index 0000000..e92cd34 --- /dev/null +++ b/Swiften/SASL/UnitTest/PLAINClientAuthenticatorTest.cpp @@ -0,0 +1,32 @@ +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> + +#include "Swiften/SASL/PLAINClientAuthenticator.h" + +using namespace Swift; + +class PLAINClientAuthenticatorTest : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(PLAINClientAuthenticatorTest); + CPPUNIT_TEST(testGetResponse_WithoutAuthzID); + CPPUNIT_TEST(testGetResponse_WithAuthzID); + CPPUNIT_TEST_SUITE_END(); + + public: + void testGetResponse_WithoutAuthzID() { + PLAINClientAuthenticator testling; + + testling.setCredentials("user", "pass"); + + CPPUNIT_ASSERT_EQUAL(testling.getResponse(), ByteArray("\0user\0pass", 10)); + } + + void testGetResponse_WithAuthzID() { + PLAINClientAuthenticator testling; + + testling.setCredentials("user", "pass", "authz"); + + CPPUNIT_ASSERT_EQUAL(testling.getResponse(), ByteArray("authz\0user\0pass", 15)); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(PLAINClientAuthenticatorTest); diff --git a/Swiften/SASL/UnitTest/PLAINMessageTest.cpp b/Swiften/SASL/UnitTest/PLAINMessageTest.cpp new file mode 100644 index 0000000..6493bd5 --- /dev/null +++ b/Swiften/SASL/UnitTest/PLAINMessageTest.cpp @@ -0,0 +1,61 @@ +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> + +#include "Swiften/SASL/PLAINMessage.h" + +using namespace Swift; + +class PLAINMessageTest : public CppUnit::TestFixture +{ + CPPUNIT_TEST_SUITE(PLAINMessageTest); + CPPUNIT_TEST(testGetValue_WithoutAuthzID); + CPPUNIT_TEST(testGetValue_WithAuthzID); + CPPUNIT_TEST(testConstructor_WithoutAuthzID); + CPPUNIT_TEST(testConstructor_WithAuthzID); + CPPUNIT_TEST(testConstructor_NoAuthcid); + CPPUNIT_TEST(testConstructor_NoPassword); + CPPUNIT_TEST_SUITE_END(); + + public: + PLAINMessageTest() {} + + void testGetValue_WithoutAuthzID() { + PLAINMessage message("user", "pass"); + CPPUNIT_ASSERT_EQUAL(message.getValue(), ByteArray("\0user\0pass", 10)); + } + + void testGetValue_WithAuthzID() { + PLAINMessage message("user", "pass", "authz"); + CPPUNIT_ASSERT_EQUAL(message.getValue(), ByteArray("authz\0user\0pass", 15)); + } + + void testConstructor_WithoutAuthzID() { + PLAINMessage message(ByteArray("\0user\0pass", 10)); + + CPPUNIT_ASSERT_EQUAL(String(""), message.getAuthorizationID()); + CPPUNIT_ASSERT_EQUAL(String("user"), message.getAuthenticationID()); + CPPUNIT_ASSERT_EQUAL(String("pass"), message.getPassword()); + } + + void testConstructor_WithAuthzID() { + PLAINMessage message(ByteArray("authz\0user\0pass", 15)); + + CPPUNIT_ASSERT_EQUAL(String("authz"), message.getAuthorizationID()); + CPPUNIT_ASSERT_EQUAL(String("user"), message.getAuthenticationID()); + CPPUNIT_ASSERT_EQUAL(String("pass"), message.getPassword()); + } + + void testConstructor_NoAuthcid() { + PLAINMessage message(ByteArray("authzid", 7)); + + CPPUNIT_ASSERT_EQUAL(String(""), message.getAuthenticationID()); + } + + void testConstructor_NoPassword() { + PLAINMessage message(ByteArray("authzid\0authcid", 15)); + + CPPUNIT_ASSERT_EQUAL(String(""), message.getAuthenticationID()); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(PLAINMessageTest); diff --git a/Swiften/SASL/UnitTest/SCRAMSHA1ClientAuthenticatorTest.cpp b/Swiften/SASL/UnitTest/SCRAMSHA1ClientAuthenticatorTest.cpp new file mode 100644 index 0000000..db69d13 --- /dev/null +++ b/Swiften/SASL/UnitTest/SCRAMSHA1ClientAuthenticatorTest.cpp @@ -0,0 +1,172 @@ +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/extensions/TestFactoryRegistry.h> + +#include "Swiften/SASL/SCRAMSHA1ClientAuthenticator.h" +#include "Swiften/Base/ByteArray.h" + +using namespace Swift; + +class SCRAMSHA1ClientAuthenticatorTest : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(SCRAMSHA1ClientAuthenticatorTest); + CPPUNIT_TEST(testGetInitialResponse); + CPPUNIT_TEST(testGetInitialResponse_UsernameHasSpecialChars); + CPPUNIT_TEST(testGetInitialResponse_WithAuthorizationID); + CPPUNIT_TEST(testGetInitialResponse_WithAuthorizationIDWithSpecialChars); + CPPUNIT_TEST(testGetFinalResponse); + CPPUNIT_TEST(testSetChallenge); + CPPUNIT_TEST(testSetChallenge_InvalidClientNonce); + CPPUNIT_TEST(testSetChallenge_OnlyClientNonce); + CPPUNIT_TEST(testSetChallenge_InvalidIterations); + CPPUNIT_TEST(testSetChallenge_ZeroIterations); + CPPUNIT_TEST(testSetChallenge_NegativeIterations); + CPPUNIT_TEST(testSetChallenge_MissingIterations); + CPPUNIT_TEST(testSetFinalChallenge); + CPPUNIT_TEST(testSetFinalChallenge_InvalidChallenge); + CPPUNIT_TEST(testGetResponseAfterFinalChallenge); + CPPUNIT_TEST_SUITE_END(); + + public: + void setUp() { + } + + void testGetInitialResponse() { + SCRAMSHA1ClientAuthenticator testling("abcdefghABCDEFGH"); + testling.setCredentials("user", "pass", ""); + + ByteArray response = testling.getResponse(); + + CPPUNIT_ASSERT_EQUAL(String("n,,n=user,r=abcdefghABCDEFGH"), testling.getResponse().toString()); + } + + void testGetInitialResponse_UsernameHasSpecialChars() { + SCRAMSHA1ClientAuthenticator testling("abcdefghABCDEFGH"); + testling.setCredentials(",us=,er=", "pass", ""); + + ByteArray response = testling.getResponse(); + + CPPUNIT_ASSERT_EQUAL(String("n,,n==2Cus=3D=2Cer=3D,r=abcdefghABCDEFGH"), testling.getResponse().toString()); + } + + void testGetInitialResponse_WithAuthorizationID() { + SCRAMSHA1ClientAuthenticator testling("abcdefghABCDEFGH"); + testling.setCredentials("user", "pass", "auth"); + + ByteArray response = testling.getResponse(); + + CPPUNIT_ASSERT_EQUAL(String("n,a=auth,n=user,r=abcdefghABCDEFGH"), testling.getResponse().toString()); + } + + void testGetInitialResponse_WithAuthorizationIDWithSpecialChars() { + SCRAMSHA1ClientAuthenticator testling("abcdefghABCDEFGH"); + testling.setCredentials("user", "pass", "a=u,th"); + + ByteArray response = testling.getResponse(); + + CPPUNIT_ASSERT_EQUAL(String("n,a=a=3Du=2Cth,n=user,r=abcdefghABCDEFGH"), testling.getResponse().toString()); + } + + void testGetFinalResponse() { + SCRAMSHA1ClientAuthenticator testling("abcdefgh"); + testling.setCredentials("user", "pass", ""); + testling.setChallenge(ByteArray("r=abcdefghABCDEFGH,s=MTIzNDU2NzgK,i=4096")); + + ByteArray response = testling.getResponse(); + + CPPUNIT_ASSERT_EQUAL(String("c=biws,r=abcdefghABCDEFGH,p=CZbjGDpIteIJwQNBgO0P8pKkMGY="), testling.getResponse().toString()); + } + + void testSetFinalChallenge() { + SCRAMSHA1ClientAuthenticator testling("abcdefgh"); + testling.setCredentials("user", "pass", ""); + testling.setChallenge(ByteArray("r=abcdefghABCDEFGH,s=MTIzNDU2NzgK,i=4096")); + + bool result = testling.setChallenge(ByteArray("v=Dd+Q20knZs9jeeK0pi1Mx1Se+yo=")); + + CPPUNIT_ASSERT(result); + } + + void testSetChallenge() { + SCRAMSHA1ClientAuthenticator testling("abcdefgh"); + testling.setCredentials("user", "pass", ""); + + bool result = testling.setChallenge(ByteArray("r=abcdefghABCDEFGH,s=MTIzNDU2NzgK,i=4096")); + + CPPUNIT_ASSERT(result); + } + + void testSetChallenge_InvalidClientNonce() { + SCRAMSHA1ClientAuthenticator testling("abcdefgh"); + testling.setCredentials("user", "pass", ""); + + bool result = testling.setChallenge(ByteArray("r=abcdefgiABCDEFGH,s=MTIzNDU2NzgK,i=4096")); + + CPPUNIT_ASSERT(!result); + } + + void testSetChallenge_OnlyClientNonce() { + SCRAMSHA1ClientAuthenticator testling("abcdefgh"); + testling.setCredentials("user", "pass", ""); + + bool result = testling.setChallenge(ByteArray("r=abcdefgh,s=MTIzNDU2NzgK,i=4096")); + + CPPUNIT_ASSERT(!result); + } + + void testSetChallenge_InvalidIterations() { + SCRAMSHA1ClientAuthenticator testling("abcdefgh"); + testling.setCredentials("user", "pass", ""); + + bool result = testling.setChallenge(ByteArray("r=abcdefghABCDEFGH,s=MTIzNDU2NzgK,i=bla")); + + CPPUNIT_ASSERT(!result); + } + + void testSetChallenge_MissingIterations() { + SCRAMSHA1ClientAuthenticator testling("abcdefgh"); + testling.setCredentials("user", "pass", ""); + + bool result = testling.setChallenge(ByteArray("r=abcdefghABCDEFGH,s=MTIzNDU2NzgK")); + + CPPUNIT_ASSERT(!result); + } + + void testSetChallenge_ZeroIterations() { + SCRAMSHA1ClientAuthenticator testling("abcdefgh"); + testling.setCredentials("user", "pass", ""); + + bool result = testling.setChallenge(ByteArray("r=abcdefghABCDEFGH,s=MTIzNDU2NzgK,i=0")); + + CPPUNIT_ASSERT(!result); + } + + void testSetChallenge_NegativeIterations() { + SCRAMSHA1ClientAuthenticator testling("abcdefgh"); + testling.setCredentials("user", "pass", ""); + + bool result = testling.setChallenge(ByteArray("r=abcdefghABCDEFGH,s=MTIzNDU2NzgK,i=-1")); + + CPPUNIT_ASSERT(!result); + } + + void testSetFinalChallenge_InvalidChallenge() { + SCRAMSHA1ClientAuthenticator testling("abcdefgh"); + testling.setCredentials("user", "pass", ""); + testling.setChallenge(ByteArray("r=abcdefghABCDEFGH,s=MTIzNDU2NzgK,i=4096")); + bool result = testling.setChallenge(ByteArray("v=e26kI69ICb6zosapLLxrER/631A=")); + + CPPUNIT_ASSERT(!result); + } + + void testGetResponseAfterFinalChallenge() { + SCRAMSHA1ClientAuthenticator testling("abcdefgh"); + testling.setCredentials("user", "pass", ""); + testling.setChallenge(ByteArray("r=abcdefghABCDEFGH,s=MTIzNDU2NzgK,i=4096")); + testling.setChallenge(ByteArray("v=Dd+Q20knZs9jeeK0pi1Mx1Se+yo=")); + + ByteArray result = testling.getResponse(); + + CPPUNIT_ASSERT_EQUAL(ByteArray(), result); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(SCRAMSHA1ClientAuthenticatorTest); |