1 // Copyright 2020 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "securegcm/d2d_connection_context_v1.h"
16
17 #include "securegcm/d2d_crypto_ops.h"
18 #include "gtest/gtest.h"
19
20 namespace securegcm {
21
22 using securemessage::CryptoOps;
23
24 namespace {
25
26 // The encode and decode keys should be 32 bytes.
27 const char kEncodeKeyData[] = "initiator_encode_key_for_aes_256";
28 const char kDecodeKeyData[] = "initiator_decode_key_for_aes_256";
29
30 } // namespace
31
32 // A friend to access the private variables of D2DConnectionContextV1.
33 class D2DConnectionContextV1Peer {
34 public:
D2DConnectionContextV1Peer(const std::string & savedSessionInfo)35 explicit D2DConnectionContextV1Peer(const std::string& savedSessionInfo) {
36 context_ = D2DConnectionContextV1::FromSavedSession(savedSessionInfo);
37 }
38
GetContext()39 D2DConnectionContextV1* GetContext() { return context_.get(); }
40
GetEncodeSequenceNumber()41 uint32_t GetEncodeSequenceNumber() {
42 return context_->encode_sequence_number_;
43 }
44
GetDecodeSequenceNumber()45 uint32_t GetDecodeSequenceNumber() {
46 return context_->decode_sequence_number_;
47 }
48
49 private:
50 std::unique_ptr<D2DConnectionContextV1> context_;
51 };
52
TEST(D2DConnectionContextionV1Test,SaveSession)53 TEST(D2DConnectionContextionV1Test, SaveSession) {
54 CryptoOps::SecretKey encodeKey = CryptoOps::SecretKey(
55 kEncodeKeyData, CryptoOps::KeyAlgorithm::AES_256_KEY);
56 CryptoOps::SecretKey decodeKey = CryptoOps::SecretKey(
57 kDecodeKeyData, CryptoOps::KeyAlgorithm::AES_256_KEY);
58
59 D2DConnectionContextV1 initiator =
60 D2DConnectionContextV1(encodeKey, decodeKey, 0, 1);
61 D2DConnectionContextV1 responder =
62 D2DConnectionContextV1(decodeKey, encodeKey, 1, 0);
63
64 std::unique_ptr<std::string> initiatorSavedSessionState =
65 initiator.SaveSession();
66 std::unique_ptr<std::string> responderSavedSessionState =
67 responder.SaveSession();
68
69 D2DConnectionContextV1Peer restoredInitiator =
70 D2DConnectionContextV1Peer(*initiatorSavedSessionState);
71 D2DConnectionContextV1Peer restoredResponder =
72 D2DConnectionContextV1Peer(*responderSavedSessionState);
73
74 // Verify internal state matches initialization.
75 EXPECT_EQ(0, restoredInitiator.GetEncodeSequenceNumber());
76 EXPECT_EQ(1, restoredInitiator.GetDecodeSequenceNumber());
77 EXPECT_EQ(1, restoredResponder.GetEncodeSequenceNumber());
78 EXPECT_EQ(0, restoredResponder.GetDecodeSequenceNumber());
79
80 EXPECT_EQ(*restoredInitiator.GetContext()->GetSessionUnique(),
81 *restoredResponder.GetContext()->GetSessionUnique());
82
83 const std::string message = "ping";
84
85 // Ensure that they can still talk to one another.
86 std::string encodedMessage =
87 *restoredInitiator.GetContext()->EncodeMessageToPeer(message);
88 std::string decodedMessage =
89 *restoredResponder.GetContext()->DecodeMessageFromPeer(encodedMessage);
90
91 EXPECT_EQ(message, decodedMessage);
92
93 encodedMessage =
94 *restoredResponder.GetContext()->EncodeMessageToPeer(message);
95 decodedMessage =
96 *restoredInitiator.GetContext()->DecodeMessageFromPeer(encodedMessage);
97
98 EXPECT_EQ(message, decodedMessage);
99 }
100
TEST(D2DConnectionContextionV1Test,SaveSession_TooShort)101 TEST(D2DConnectionContextionV1Test, SaveSession_TooShort) {
102 CryptoOps::SecretKey encodeKey = CryptoOps::SecretKey(
103 kEncodeKeyData, CryptoOps::KeyAlgorithm::AES_256_KEY);
104 CryptoOps::SecretKey decodeKey = CryptoOps::SecretKey(
105 kDecodeKeyData, CryptoOps::KeyAlgorithm::AES_256_KEY);
106
107 D2DConnectionContextV1 initiator =
108 D2DConnectionContextV1(encodeKey, decodeKey, 0, 1);
109
110 std::unique_ptr<std::string> initiatorSavedSessionState =
111 initiator.SaveSession();
112
113 // Try to rebuild the context with a shorter session state.
114 std::string shortSessionState = initiatorSavedSessionState->substr(
115 0, initiatorSavedSessionState->size() - 1);
116
117 D2DConnectionContextV1Peer restoredInitiator =
118 D2DConnectionContextV1Peer(shortSessionState);
119
120 // nullptr is returned on error. It should not crash.
121 EXPECT_EQ(restoredInitiator.GetContext(), nullptr);
122 }
123
124 } // namespace securegcm
125