C++程序  |  219行  |  8.4 KB

/*
 * Copyright 2017 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 <stdio.h>
#include <string.h>
#include <fstream>

#include <gtest/gtest.h>

#include <base/files/file_util.h>

#include <libatap/libatap.h>

#include "atap_unittest_util.h"
#include "fake_atap_ops.h"
#include "ops/atap_ops_provider.h"

namespace atap {

uint8_t session_key[ATAP_ECDH_KEY_LEN];

// Subclass BaseAtapToolTest to check for memory leaks.
class CommandTest : public BaseAtapTest {
 public:
  CommandTest() {}

  FakeAtapOps fake_ops_;
  AtapOpsProvider ops_{&fake_ops_};

  void validate_ca_request(const uint8_t* buf,
                           uint32_t buf_size,
                           AtapOperation operation);
  void compute_session_key(const uint8_t device_public_key[ATAP_ECDH_KEY_LEN]);
  void set_curve(AtapCurveType curve) {
    curve_ = curve;
  }
  void setup_test_key() {
    std::string test_key;
    EXPECT_TRUE(base::ReadFileToString(
        base::FilePath((curve_ == ATAP_CURVE_TYPE_X25519) ? kCaX25519PrivateKey
                                                          : kCaP256PrivateKey),
        &test_key));
    fake_ops_.SetEcdhKeyForTesting(test_key.data(), test_key.length());
  }

 private:
  AtapCurveType curve_ = ATAP_CURVE_TYPE_X25519;
};

void CommandTest::compute_session_key(
    const uint8_t device_pubkey[ATAP_ECDH_KEY_LEN]) {
  uint8_t shared_secret[ATAP_ECDH_KEY_LEN];
  uint8_t ca_pubkey[ATAP_ECDH_KEY_LEN];
  AtapResult ret = fake_ops_.ecdh_shared_secret_compute(
      curve_, device_pubkey, ca_pubkey, shared_secret);
  ASSERT_EQ(ret, ATAP_RESULT_OK);
  ret = derive_session_key(ops_.atap_ops(),
                           device_pubkey,
                           ca_pubkey,
                           shared_secret,
                           "KEY",
                           session_key,
                           ATAP_AES_128_KEY_LEN);
  ASSERT_EQ(ret, ATAP_RESULT_OK);
}

void CommandTest::validate_ca_request(const uint8_t* buf,
                                      uint32_t buf_size,
                                      AtapOperation operation) {
  EXPECT_GT(buf_size, (uint32_t)ATAP_HEADER_LEN);
  uint32_t i = 4;
  uint32_t ca_request_size = *(uint32_t*)next(buf, &i, sizeof(uint32_t));
  EXPECT_EQ(buf_size - ATAP_HEADER_LEN, ca_request_size);
  uint8_t* device_pubkey = next(buf, &i, ATAP_ECDH_KEY_LEN);
  compute_session_key(device_pubkey);
  const uint8_t* iv = next(buf, &i, ATAP_GCM_IV_LEN);
  uint32_t ciphertext_len = *(uint32_t*)next(buf, &i, sizeof(uint32_t));
  EXPECT_EQ(ca_request_size - ATAP_ECDH_KEY_LEN - ATAP_GCM_IV_LEN -
                ATAP_GCM_TAG_LEN - sizeof(uint32_t),
            ciphertext_len);
  const uint8_t* ciphertext = next(buf, &i, ciphertext_len);
  uint8_t* inner = (uint8_t*)atap_malloc(ciphertext_len);
  const uint8_t* tag = next(buf, &i, ATAP_GCM_TAG_LEN);
  AtapResult ret = fake_ops_.aes_gcm_128_decrypt(
      ciphertext, ciphertext_len, iv, session_key, tag, inner);
  EXPECT_EQ(ATAP_RESULT_OK, ret);
  i = 4;
  uint32_t inner_ca_request_size =
      *(uint32_t*)next(inner, &i, sizeof(uint32_t));
  EXPECT_EQ(ciphertext_len - ATAP_HEADER_LEN, inner_ca_request_size);
  // Test operation is Issue, no authentication
  int32_t auth_cert_chain_size = *(int32_t*)next(inner, &i, sizeof(int32_t));
  EXPECT_EQ(0, auth_cert_chain_size);
  int32_t auth_signature_size = *(int32_t*)next(inner, &i, sizeof(int32_t));
  EXPECT_EQ(0, auth_signature_size);
  std::string product_id_hash_str;
  ASSERT_TRUE(base::ReadFileToString(base::FilePath(kProductIdHash),
                                     &product_id_hash_str));
  const uint8_t* product_id_hash = next(inner, &i, ATAP_SHA256_DIGEST_LEN);
  EXPECT_EQ(0,
            memcmp(product_id_hash,
                   (uint8_t*)&product_id_hash_str[0],
                   ATAP_SHA256_DIGEST_LEN));
  int32_t RSA_pubkey_len = *(int32_t*)next(inner, &i, sizeof(int32_t));
  EXPECT_EQ(0, RSA_pubkey_len);
  int32_t ECDSA_pubkey_len = *(int32_t*)next(inner, &i, sizeof(int32_t));
  EXPECT_EQ(0, ECDSA_pubkey_len);
  int32_t edDSA_pubkey_len = *(int32_t*)next(inner, &i, sizeof(int32_t));
  EXPECT_EQ(0, edDSA_pubkey_len);

  atap_free(inner);
}

TEST_F(CommandTest, GetCaRequestIssueX25519) {
  setup_test_key();
  std::string operation_start;
  ASSERT_TRUE(base::ReadFileToString(
      base::FilePath(kIssueX25519OperationStartPath), &operation_start));
  uint32_t ca_request_size;
  uint8_t* ca_request;
  AtapResult res = atap_get_ca_request(ops_.atap_ops(),
                                       (uint8_t*)&operation_start[0],
                                       operation_start.size(),
                                       &ca_request,
                                       &ca_request_size);
  EXPECT_EQ(ATAP_RESULT_OK, res);
  validate_ca_request(ca_request, ca_request_size, ATAP_OPERATION_ISSUE);
  atap_free(ca_request);
}

TEST_F(CommandTest, SetCaResponseIssueX25519) {
  setup_test_key();
  std::string inner;
  ASSERT_TRUE(base::ReadFileToString(
      base::FilePath(kIssueX25519InnerCaResponsePath), &inner));
  uint32_t ca_response_size = ATAP_HEADER_LEN + ATAP_GCM_IV_LEN +
                              sizeof(uint32_t) + inner.size() +
                              ATAP_GCM_TAG_LEN;
  uint8_t* ca_response = (uint8_t*)atap_malloc(ca_response_size);
  append_header_to_buf(ca_response, ca_response_size - ATAP_HEADER_LEN);
  uint32_t i = ATAP_HEADER_LEN;
  uint8_t* iv = next(ca_response, &i, ATAP_GCM_IV_LEN);
  fake_ops_.get_random_bytes(iv, ATAP_GCM_IV_LEN);
  uint32_t* ciphertext_len = (uint32_t*)next(ca_response, &i, sizeof(uint32_t));
  *ciphertext_len = inner.size();
  uint8_t* ciphertext = next(ca_response, &i, *ciphertext_len);
  uint8_t* tag = next(ca_response, &i, ATAP_GCM_TAG_LEN);
  AtapResult res = fake_ops_.aes_gcm_128_encrypt(
      (uint8_t*)&inner[0], inner.size(), iv, session_key, ciphertext, tag);
  ASSERT_EQ(ATAP_RESULT_OK, res);
  res = atap_set_ca_response(ops_.atap_ops(), ca_response, ca_response_size);
  EXPECT_EQ(ATAP_RESULT_OK, res);
  atap_free(ca_response);
}

TEST_F(CommandTest, GetCaRequestIssueP256) {
  set_curve(ATAP_CURVE_TYPE_P256);
  setup_test_key();
  std::string operation_start;
  ASSERT_TRUE(base::ReadFileToString(
      base::FilePath(kIssueP256OperationStartPath), &operation_start));
  uint32_t ca_request_size;
  uint8_t* ca_request;
  AtapResult res = atap_get_ca_request(ops_.atap_ops(),
                                       (uint8_t*)&operation_start[0],
                                       operation_start.size(),
                                       &ca_request,
                                       &ca_request_size);
  EXPECT_EQ(ATAP_RESULT_OK, res);
  validate_ca_request(ca_request, ca_request_size, ATAP_OPERATION_ISSUE);
  atap_free(ca_request);
}

TEST_F(CommandTest, GetCaRequestIssueX25519NoTestKey) {
  std::string operation_start;
  ASSERT_TRUE(base::ReadFileToString(
      base::FilePath(kIssueX25519OperationStartPath), &operation_start));
  uint32_t ca_request_size;
  uint8_t* ca_request;
  AtapResult res = atap_get_ca_request(ops_.atap_ops(),
                                       (uint8_t*)&operation_start[0],
                                       operation_start.size(),
                                       &ca_request,
                                       &ca_request_size);
  EXPECT_EQ(ATAP_RESULT_OK, res);
  atap_free(ca_request);
}

TEST_F(CommandTest, GetCaRequestIssueP256NoTestKey) {
  set_curve(ATAP_CURVE_TYPE_P256);
  std::string operation_start;
  ASSERT_TRUE(base::ReadFileToString(
      base::FilePath(kIssueP256OperationStartPath), &operation_start));
  uint32_t ca_request_size;
  uint8_t* ca_request;
  AtapResult res = atap_get_ca_request(ops_.atap_ops(),
                                       (uint8_t*)&operation_start[0],
                                       operation_start.size(),
                                       &ca_request,
                                       &ca_request_size);
  EXPECT_EQ(ATAP_RESULT_OK, res);
  atap_free(ca_request);
}

}  // namespace atap