/* * 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