1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include <string> 6 #include <crypto/p224_spake.h> 7 8 #include "base/logging.h" 9 #include "testing/gtest/include/gtest/gtest.h" 10 11 namespace crypto { 12 13 namespace { 14 15 bool RunExchange(P224EncryptedKeyExchange* client, 16 P224EncryptedKeyExchange* server) { 17 for (;;) { 18 std::string client_message, server_message; 19 client_message = client->GetMessage(); 20 server_message = server->GetMessage(); 21 22 P224EncryptedKeyExchange::Result client_result, server_result; 23 client_result = client->ProcessMessage(server_message); 24 server_result = server->ProcessMessage(client_message); 25 26 // Check that we never hit the case where only one succeeds. 27 if ((client_result == P224EncryptedKeyExchange::kResultSuccess) ^ 28 (server_result == P224EncryptedKeyExchange::kResultSuccess)) { 29 CHECK(false) << "Parties differ on whether authentication was successful"; 30 } 31 32 if (client_result == P224EncryptedKeyExchange::kResultFailed || 33 server_result == P224EncryptedKeyExchange::kResultFailed) { 34 return false; 35 } 36 37 if (client_result == P224EncryptedKeyExchange::kResultSuccess && 38 server_result == P224EncryptedKeyExchange::kResultSuccess) { 39 return true; 40 } 41 42 CHECK_EQ(P224EncryptedKeyExchange::kResultPending, client_result); 43 CHECK_EQ(P224EncryptedKeyExchange::kResultPending, server_result); 44 } 45 } 46 47 const char kPassword[] = "foo"; 48 49 } // namespace 50 51 TEST(MutualAuth, CorrectAuth) { 52 P224EncryptedKeyExchange client( 53 P224EncryptedKeyExchange::kPeerTypeClient, kPassword); 54 P224EncryptedKeyExchange server( 55 P224EncryptedKeyExchange::kPeerTypeServer, kPassword); 56 57 EXPECT_TRUE(RunExchange(&client, &server)); 58 EXPECT_EQ(client.GetKey(), server.GetKey()); 59 } 60 61 TEST(MutualAuth, IncorrectPassword) { 62 P224EncryptedKeyExchange client( 63 P224EncryptedKeyExchange::kPeerTypeClient, 64 kPassword); 65 P224EncryptedKeyExchange server( 66 P224EncryptedKeyExchange::kPeerTypeServer, 67 "wrongpassword"); 68 69 EXPECT_FALSE(RunExchange(&client, &server)); 70 } 71 72 TEST(MutualAuth, Fuzz) { 73 static const unsigned kIterations = 40; 74 75 for (unsigned i = 0; i < kIterations; i++) { 76 P224EncryptedKeyExchange client( 77 P224EncryptedKeyExchange::kPeerTypeClient, kPassword); 78 P224EncryptedKeyExchange server( 79 P224EncryptedKeyExchange::kPeerTypeServer, kPassword); 80 81 // We'll only be testing small values of i, but we don't want that to bias 82 // the test coverage. So we disperse the value of i by multiplying by the 83 // FNV, 32-bit prime, producing a poor-man's PRNG. 84 const uint32 rand = i * 16777619; 85 86 for (unsigned round = 0;; round++) { 87 std::string client_message, server_message; 88 client_message = client.GetMessage(); 89 server_message = server.GetMessage(); 90 91 if ((rand & 1) == round) { 92 const bool server_or_client = rand & 2; 93 std::string* m = server_or_client ? &server_message : &client_message; 94 if (rand & 4) { 95 // Truncate 96 *m = m->substr(0, (i >> 3) % m->size()); 97 } else { 98 // Corrupt 99 const size_t bits = m->size() * 8; 100 const size_t bit_to_corrupt = (rand >> 3) % bits; 101 const_cast<char*>(m->data())[bit_to_corrupt / 8] ^= 102 1 << (bit_to_corrupt % 8); 103 } 104 } 105 106 P224EncryptedKeyExchange::Result client_result, server_result; 107 client_result = client.ProcessMessage(server_message); 108 server_result = server.ProcessMessage(client_message); 109 110 // If we have corrupted anything, we expect the authentication to fail, 111 // although one side can succeed if we happen to corrupt the second round 112 // message to the other. 113 ASSERT_FALSE( 114 client_result == P224EncryptedKeyExchange::kResultSuccess && 115 server_result == P224EncryptedKeyExchange::kResultSuccess); 116 117 if (client_result == P224EncryptedKeyExchange::kResultFailed || 118 server_result == P224EncryptedKeyExchange::kResultFailed) { 119 break; 120 } 121 122 ASSERT_EQ(P224EncryptedKeyExchange::kResultPending, 123 client_result); 124 ASSERT_EQ(P224EncryptedKeyExchange::kResultPending, 125 server_result); 126 } 127 } 128 } 129 130 } // namespace crypto 131