//
// Copyright (C) 2014 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

#include <string>

#include <gtest/gtest.h>

#include "trunks/password_authorization_delegate.h"

namespace trunks {

// This test looks at initialization of the delegate with no password.
// It should initailize with a zero length internal password buffer.
TEST(PasswordAuthorizationDelegateTest, NullInitialization) {
  PasswordAuthorizationDelegate delegate("");
  EXPECT_EQ(delegate.password_.size, 0);
}

// This test checks the generation of an authorization structure by the
// delegate. It compared the serialized structure generated by the delegate
// to the expected authorization string.
TEST(PasswordAuthorizationDelegateTest, SerializationTest) {
  std::string expected_auth("\x40\x00\x00\x09"  // session_handle = TPM_RS_PW
                            "\x00\x00"          // nonce = zero length buffer
                            "\x01"     // session_attributes = continueSession
                            "\x00\x06"          // password length
                            "secret",           // password
                            15);
  PasswordAuthorizationDelegate delegate("secret");
  std::string authorization;
  std::string command_hash;
  bool authorization_result = delegate.GetCommandAuthorization(command_hash,
                                                               false, false,
                                                               &authorization);
  EXPECT_EQ(authorization_result, true);
  EXPECT_EQ(authorization.length(), expected_auth.length());
  EXPECT_EQ(expected_auth.compare(authorization), 0);
}

// This test looks at the delegate's ability to parse and check authorization
// responses when the response is well formed.
TEST(PasswordAuthorizationDelegateTest, ParseGoodParams) {
  std::string auth_response("\x00\x00"   // nonceTpm = zero length buffer
                            "\x01"       // session_attributes = continueSession
                            "\x00\x00",  // hmac = zero length buffer
                            5);
  PasswordAuthorizationDelegate delegate("secret");
  std::string response_hash;
  bool authorization_result = delegate.CheckResponseAuthorization(
      response_hash,
      auth_response);
  EXPECT_EQ(authorization_result, true);
}

// This test checks the delegate's ability to correctly identify an incorrect
// authorization response.
TEST(PasswordAuthorizationDelegateTest, ParseBadParams) {
  std::string auth_response("\x00\x00"  // nonceTpm = zero length buffer
                            "\x01"      // session_attributes = continueSession
                            "\x00\x06"  // password length
                            "secret",   // password
                            11);
  PasswordAuthorizationDelegate delegate("secret");
  std::string response_hash;
  bool authorization_result = delegate.CheckResponseAuthorization(
      response_hash,
      auth_response);
  EXPECT_EQ(authorization_result, false);
}

// This test confirms that after encrypting and decrypting a parameter,
// we get the original parameter back.
TEST(PasswordAuthorizationDelegateTest, EncryptDecrypt) {
  PasswordAuthorizationDelegate delegate("secret");
  std::string plaintext_parameter("parameter");
  std::string encrypted_parameter(plaintext_parameter);
  ASSERT_EQ(plaintext_parameter.compare(encrypted_parameter), 0);
  delegate.EncryptCommandParameter(&encrypted_parameter);
  delegate.DecryptResponseParameter(&encrypted_parameter);
  EXPECT_EQ(plaintext_parameter.compare(encrypted_parameter), 0);
}

}  // namespace trunks