Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit df3926e0 authored by Selene Huang's avatar Selene Huang Committed by Automerger Merge Worker
Browse files

Merge "Add attestation certificate parsing and validate for IC vts." am: 2ea80dc8 am: 66f76e3c

Change-Id: I02b74a2180df1dea8ed1ac258917d79eac7d1d55
parents 33569f0b 66f76e3c
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -8,10 +8,16 @@ cc_test {
        "VtsHalIdentityEndToEndTest.cpp",
        "VtsIWritableIdentityCredentialTests.cpp",
        "VtsIdentityTestUtils.cpp",
        "VtsAttestationTests.cpp",
        "VtsAttestationParserSupport.cpp",
    ],
    shared_libs: [
        "android.hardware.keymaster@4.0",
        "libbinder",
        "libcrypto",
        "libkeymaster_portable",
        "libsoft_attestation_cert",
        "libpuresoftkeymasterdevice",
    ],
    static_libs: [
        "libcppbor",
+187 −0
Original line number Diff line number Diff line
/*
 * Copyright 2019, 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 "VtsAttestationParserSupport.h"

#include <aidl/Gtest.h>
#include <map>

namespace android::hardware::identity::test_utils {

using std::endl;
using std::map;
using std::optional;
using std::string;
using std::vector;

using ::android::sp;
using ::android::String16;
using ::android::binder::Status;

using ::keymaster::ASN1_OBJECT_Ptr;
using ::keymaster::AuthorizationSet;
using ::keymaster::EVP_PKEY_Ptr;
using ::keymaster::kAttestionRecordOid;
using ::keymaster::TAG_ATTESTATION_APPLICATION_ID;
using ::keymaster::TAG_IDENTITY_CREDENTIAL_KEY;
using ::keymaster::TAG_INCLUDE_UNIQUE_ID;
using ::keymaster::TypedTag;
using ::keymaster::X509_Ptr;

using support::certificateChainSplit;

optional<keymaster_cert_chain_t> AttestationCertificateParser::certificateChainToKeymasterChain(
        const vector<Certificate>& certificates) {
    if (certificates.size() <= 0) {
        return {};
    }

    keymaster_cert_chain_t kCert;
    kCert.entry_count = certificates.size();
    kCert.entries = (keymaster_blob_t*)malloc(sizeof(keymaster_blob_t) * kCert.entry_count);

    int index = 0;
    for (const auto& c : certificates) {
        kCert.entries[index].data_length = c.encodedCertificate.size();
        uint8_t* data = (uint8_t*)malloc(c.encodedCertificate.size());

        memcpy(data, c.encodedCertificate.data(), c.encodedCertificate.size());
        kCert.entries[index].data = (const uint8_t*)data;
        index++;
    }

    return kCert;
}

bool AttestationCertificateParser::parse() {
    optional<keymaster_cert_chain_t> cert_chain = certificateChainToKeymasterChain(origCertChain_);
    if (!cert_chain) {
        return false;
    }

    if (cert_chain.value().entry_count < 3) {
        return false;
    }

    if (!verifyChain(cert_chain.value())) {
        return false;
    }

    if (!verifyAttestationRecord(cert_chain.value().entries[0])) {
        return false;
    }

    keymaster_free_cert_chain(&cert_chain.value());
    return true;
}

ASN1_OCTET_STRING* AttestationCertificateParser::getAttestationRecord(X509* certificate) {
    ASN1_OBJECT_Ptr oid(OBJ_txt2obj(kAttestionRecordOid, 1));
    if (!oid.get()) return nullptr;

    int location = X509_get_ext_by_OBJ(certificate, oid.get(), -1);
    if (location == -1) return nullptr;

    X509_EXTENSION* attest_rec_ext = X509_get_ext(certificate, location);
    if (!attest_rec_ext) return nullptr;

    ASN1_OCTET_STRING* attest_rec = X509_EXTENSION_get_data(attest_rec_ext);
    return attest_rec;
}

X509* AttestationCertificateParser::parseCertBlob(const keymaster_blob_t& blob) {
    const uint8_t* p = blob.data;
    return d2i_X509(nullptr, &p, blob.data_length);
}

bool AttestationCertificateParser::verifyAttestationRecord(
        const keymaster_blob_t& attestation_cert) {
    X509_Ptr cert(parseCertBlob(attestation_cert));
    if (!cert.get()) {
        return false;
    }

    ASN1_OCTET_STRING* attest_rec = getAttestationRecord(cert.get());
    if (!attest_rec) {
        return false;
    }

    keymaster_blob_t att_unique_id = {};
    keymaster_blob_t att_challenge;
    keymaster_error_t ret = parse_attestation_record(
            attest_rec->data, attest_rec->length, &att_attestation_version_,
            &att_attestation_security_level_, &att_keymaster_version_,
            &att_keymaster_security_level_, &att_challenge, &att_sw_enforced_, &att_hw_enforced_,
            &att_unique_id);
    if (ret) {
        return false;
    }

    att_challenge_.assign(att_challenge.data, att_challenge.data + att_challenge.data_length);
    return true;
}

uint32_t AttestationCertificateParser::getKeymasterVersion() {
    return att_keymaster_version_;
}

uint32_t AttestationCertificateParser::getAttestationVersion() {
    return att_attestation_version_;
}

vector<uint8_t> AttestationCertificateParser::getAttestationChallenge() {
    return att_challenge_;
}

keymaster_security_level_t AttestationCertificateParser::getKeymasterSecurityLevel() {
    return att_keymaster_security_level_;
}

keymaster_security_level_t AttestationCertificateParser::getAttestationSecurityLevel() {
    return att_attestation_security_level_;
}

// Verify the Attestation certificates are correctly chained.
bool AttestationCertificateParser::verifyChain(const keymaster_cert_chain_t& chain) {
    for (size_t i = 0; i < chain.entry_count - 1; ++i) {
        keymaster_blob_t& key_cert_blob = chain.entries[i];
        keymaster_blob_t& signing_cert_blob = chain.entries[i + 1];

        X509_Ptr key_cert(parseCertBlob(key_cert_blob));
        X509_Ptr signing_cert(parseCertBlob(signing_cert_blob));
        if (!key_cert.get() || !signing_cert.get()) {
            return false;
        }

        EVP_PKEY_Ptr signing_pubkey(X509_get_pubkey(signing_cert.get()));
        if (!signing_pubkey.get()) return false;

        if (X509_verify(key_cert.get(), signing_pubkey.get()) != 1) {
            return false;
        }

        if (i + 1 == chain.entry_count - 1) {
            // Last entry is self-signed.
            if (X509_verify(signing_cert.get(), signing_pubkey.get()) != 1) {
                return false;
            }
        }
    }

    return true;
}

}  // namespace android::hardware::identity::test_utils
+122 −0
Original line number Diff line number Diff line

/*
 * Copyright 2019, 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.
 */

#ifndef VTS_ATTESTATION_PARSER_SUPPORT_H
#define VTS_ATTESTATION_PARSER_SUPPORT_H

//#include <aidl/Gtest.h>
#include <android/hardware/identity/IIdentityCredentialStore.h>
#include <android/hardware/identity/support/IdentityCredentialSupport.h>
#include <android/hardware/keymaster/4.0/types.h>
#include <hardware/keymaster_defs.h>
#include <keymaster/android_keymaster_utils.h>
#include <keymaster/authorization_set.h>
#include <keymaster/contexts/pure_soft_keymaster_context.h>
#include <keymaster/contexts/soft_attestation_cert.h>
#include <keymaster/keymaster_tags.h>
#include <keymaster/km_openssl/attestation_utils.h>
#include <vector>

namespace android::hardware::identity::test_utils {

using ::std::optional;
using ::std::string;
using ::std::vector;

using ::keymaster::AuthorizationSet;
using ::keymaster::TypedTag;

class AttestationCertificateParser {
  public:
    AttestationCertificateParser(const vector<Certificate>& certChain)
        : origCertChain_(certChain) {}

    bool parse();

    uint32_t getKeymasterVersion();
    uint32_t getAttestationVersion();
    vector<uint8_t> getAttestationChallenge();
    keymaster_security_level_t getKeymasterSecurityLevel();
    keymaster_security_level_t getAttestationSecurityLevel();

    template <keymaster_tag_t Tag>
    bool getSwEnforcedBool(TypedTag<KM_BOOL, Tag> tag) {
        if (att_sw_enforced_.GetTagValue(tag)) {
            return true;
        }

        return false;
    }

    template <keymaster_tag_t Tag>
    bool getHwEnforcedBool(TypedTag<KM_BOOL, Tag> tag) {
        if (att_hw_enforced_.GetTagValue(tag)) {
            return true;
        }

        return false;
    }

    template <keymaster_tag_t Tag>
    optional<vector<uint8_t>> getHwEnforcedBlob(TypedTag<KM_BYTES, Tag> tag) {
        keymaster_blob_t blob;
        if (att_hw_enforced_.GetTagValue(tag, &blob)) {
            return {};
        }

        vector<uint8_t> ret(blob.data, blob.data + blob.data_length);
        return ret;
    }

    template <keymaster_tag_t Tag>
    optional<vector<uint8_t>> getSwEnforcedBlob(TypedTag<KM_BYTES, Tag> tag) {
        keymaster_blob_t blob;
        if (!att_sw_enforced_.GetTagValue(tag, &blob)) {
            return {};
        }

        vector<uint8_t> ret(blob.data, blob.data + blob.data_length);
        return ret;
    }

  private:
    // Helper functions.
    bool verifyChain(const keymaster_cert_chain_t& chain);

    ASN1_OCTET_STRING* getAttestationRecord(X509* certificate);

    X509* parseCertBlob(const keymaster_blob_t& blob);

    bool verifyAttestationRecord(const keymaster_blob_t& attestation_cert);

    optional<keymaster_cert_chain_t> certificateChainToKeymasterChain(
            const vector<Certificate>& certificates);

    // Private variables.
    vector<Certificate> origCertChain_;
    AuthorizationSet att_sw_enforced_;
    AuthorizationSet att_hw_enforced_;
    uint32_t att_attestation_version_;
    uint32_t att_keymaster_version_;
    keymaster_security_level_t att_attestation_security_level_;
    keymaster_security_level_t att_keymaster_security_level_;
    vector<uint8_t> att_challenge_;
};

}  // namespace android::hardware::identity::test_utils

#endif  // VTS_ATTESTATION_PARSER_SUPPORT_H
+188 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 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.
 */

#define LOG_TAG "VtsAttestationTests"

#include <aidl/Gtest.h>
#include <aidl/Vintf.h>
#include <android-base/logging.h>
#include <android/hardware/identity/IIdentityCredentialStore.h>
#include <android/hardware/identity/support/IdentityCredentialSupport.h>
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
#include <cppbor.h>
#include <cppbor_parse.h>
#include <gtest/gtest.h>
#include <future>
#include <map>

#include "VtsAttestationParserSupport.h"
#include "VtsIdentityTestUtils.h"

namespace android::hardware::identity {

using std::endl;
using std::map;
using std::optional;
using std::string;
using std::vector;

using ::android::sp;
using ::android::String16;
using ::android::binder::Status;

using test_utils::AttestationCertificateParser;
using test_utils::setupWritableCredential;
using test_utils::validateAttestationCertificate;

// This file verifies the Identity Credential VTS Attestation Certificate
// generated.
class VtsAttestationTests : public testing::TestWithParam<std::string> {
  public:
    virtual void SetUp() override {
        credentialStore_ = android::waitForDeclaredService<IIdentityCredentialStore>(
                String16(GetParam().c_str()));
        ASSERT_NE(credentialStore_, nullptr);
    }

    sp<IIdentityCredentialStore> credentialStore_;
};

TEST_P(VtsAttestationTests, verifyAttestationWithEmptyChallengeEmptyId) {
    Status result;

    HardwareInformation hwInfo;
    ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk());

    sp<IWritableIdentityCredential> writableCredential;
    ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));

    vector<uint8_t> attestationChallenge;
    vector<Certificate> attestationCertificate;
    vector<uint8_t> attestationApplicationId = {};
    result = writableCredential->getAttestationCertificate(
            attestationApplicationId, attestationChallenge, &attestationCertificate);

    ASSERT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage()
                               << endl;

    EXPECT_TRUE(validateAttestationCertificate(attestationCertificate, attestationChallenge,
                                               attestationApplicationId, hwInfo));
}

TEST_P(VtsAttestationTests, verifyAttestationWithEmptyChallengeNonemptyId) {
    Status result;

    HardwareInformation hwInfo;
    ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk());

    sp<IWritableIdentityCredential> writableCredential;
    ASSERT_TRUE(setupWritableCredential(writableCredential, credentialStore_));

    vector<uint8_t> attestationChallenge;
    vector<Certificate> attestationCertificate;
    string applicationId = "Attestation Verification";
    vector<uint8_t> attestationApplicationId = {applicationId.begin(), applicationId.end()};

    result = writableCredential->getAttestationCertificate(
            attestationApplicationId, attestationChallenge, &attestationCertificate);

    ASSERT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage()
                               << endl;
    EXPECT_TRUE(validateAttestationCertificate(attestationCertificate, attestationChallenge,
                                               attestationApplicationId, hwInfo));
}

TEST_P(VtsAttestationTests, verifyAttestationWithNonemptyChallengeEmptyId) {
    Status result;

    HardwareInformation hwInfo;
    ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk());

    sp<IWritableIdentityCredential> writableCredential;
    ASSERT_TRUE(setupWritableCredential(writableCredential, credentialStore_));

    string challenge = "NotSoRandomChallenge";
    vector<uint8_t> attestationChallenge(challenge.begin(), challenge.end());
    vector<Certificate> attestationCertificate;
    vector<uint8_t> attestationApplicationId = {};

    result = writableCredential->getAttestationCertificate(
            attestationApplicationId, attestationChallenge, &attestationCertificate);

    ASSERT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage()
                               << endl;

    EXPECT_TRUE(validateAttestationCertificate(attestationCertificate, attestationChallenge,
                                               attestationApplicationId, hwInfo));
}

TEST_P(VtsAttestationTests, verifyAttestationWithNonemptyChallengeNonemptyId) {
    Status result;

    HardwareInformation hwInfo;
    ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk());

    sp<IWritableIdentityCredential> writableCredential;
    ASSERT_TRUE(setupWritableCredential(writableCredential, credentialStore_));

    string challenge = "NotSoRandomChallenge1NotSoRandomChallenge1NotSoRandomChallenge1";
    vector<uint8_t> attestationChallenge(challenge.begin(), challenge.end());
    vector<Certificate> attestationCertificate;
    string applicationId = "Attestation Verification";
    vector<uint8_t> attestationApplicationId = {applicationId.begin(), applicationId.end()};

    result = writableCredential->getAttestationCertificate(
            attestationApplicationId, attestationChallenge, &attestationCertificate);

    ASSERT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage()
                               << endl;

    EXPECT_TRUE(validateAttestationCertificate(attestationCertificate, attestationChallenge,
                                               attestationApplicationId, hwInfo));
}

TEST_P(VtsAttestationTests, verifyAttestationWithVeryShortChallengeAndId) {
    Status result;

    HardwareInformation hwInfo;
    ASSERT_TRUE(credentialStore_->getHardwareInformation(&hwInfo).isOk());

    sp<IWritableIdentityCredential> writableCredential;
    ASSERT_TRUE(setupWritableCredential(writableCredential, credentialStore_));

    string challenge = "c";
    vector<uint8_t> attestationChallenge(challenge.begin(), challenge.end());
    vector<Certificate> attestationCertificate;
    string applicationId = "i";
    vector<uint8_t> attestationApplicationId = {applicationId.begin(), applicationId.end()};

    result = writableCredential->getAttestationCertificate(
            attestationApplicationId, attestationChallenge, &attestationCertificate);

    ASSERT_TRUE(result.isOk()) << result.exceptionCode() << "; " << result.exceptionMessage()
                               << endl;

    EXPECT_TRUE(validateAttestationCertificate(attestationCertificate, attestationChallenge,
                                               attestationApplicationId, hwInfo));
}

INSTANTIATE_TEST_SUITE_P(
        Identity, VtsAttestationTests,
        testing::ValuesIn(android::getAidlHalInstanceNames(IIdentityCredentialStore::descriptor)),
        android::PrintInstanceNameToString);

}  // namespace android::hardware::identity
+11 −10
Original line number Diff line number Diff line
@@ -13,7 +13,7 @@
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#define LOG_TAG "VtsHalIdentityTargetTest"
#define LOG_TAG "VtsHalIdentityEndToEndTest"

#include <aidl/Gtest.h>
#include <aidl/Vintf.h>
@@ -45,6 +45,8 @@ using ::android::binder::Status;
using ::android::hardware::keymaster::HardwareAuthToken;
using ::android::hardware::keymaster::VerificationToken;

using test_utils::validateAttestationCertificate;

class IdentityAidl : public testing::TestWithParam<std::string> {
  public:
    virtual void SetUp() override {
@@ -69,13 +71,13 @@ TEST_P(IdentityAidl, createAndRetrieveCredential) {
    // part of the request data.
    vector<uint8_t> readerKey;
    optional<vector<uint8_t>> readerCertificate =
            test_utils::GenerateReaderCertificate("1234", readerKey);
            test_utils::generateReaderCertificate("1234", &readerKey);
    ASSERT_TRUE(readerCertificate);

    // Make the portrait image really big (just shy of 256 KiB) to ensure that
    // the chunking code gets exercised.
    vector<uint8_t> portraitImage;
    test_utils::SetImageData(portraitImage);
    test_utils::setImageData(portraitImage);

    // Access control profiles:
    const vector<test_utils::TestProfile> testProfiles = {// Profile 0 (reader authentication)
@@ -114,17 +116,16 @@ TEST_P(IdentityAidl, createAndRetrieveCredential) {

    string cborPretty;
    sp<IWritableIdentityCredential> writableCredential;
    ASSERT_TRUE(test_utils::SetupWritableCredential(writableCredential, credentialStore_));
    ASSERT_TRUE(test_utils::setupWritableCredential(writableCredential, credentialStore_));

    string challenge = "attestationChallenge";
    test_utils::AttestationData attData(writableCredential, challenge, {});
    ASSERT_TRUE(attData.result.isOk())
            << attData.result.exceptionCode() << "; " << attData.result.exceptionMessage() << endl;
    ASSERT_EQ(binder::Status::EX_NONE, attData.result.exceptionCode());
    ASSERT_EQ(IIdentityCredentialStore::STATUS_OK, attData.result.serviceSpecificErrorCode());

    // TODO: set it to something random and check it's in the cert chain
    ASSERT_GE(attData.attestationCertificate.size(), 2);
    EXPECT_TRUE(validateAttestationCertificate(attData.attestationCertificate,
                                               attData.attestationChallenge,
                                               attData.attestationApplicationId, hwInfo));

    // This is kinda of a hack but we need to give the size of
    // ProofOfProvisioning that we'll expect to receive.
@@ -136,7 +137,7 @@ TEST_P(IdentityAidl, createAndRetrieveCredential) {
                    .isOk());

    optional<vector<SecureAccessControlProfile>> secureProfiles =
            test_utils::AddAccessControlProfiles(writableCredential, testProfiles);
            test_utils::addAccessControlProfiles(writableCredential, testProfiles);
    ASSERT_TRUE(secureProfiles);

    // Uses TestEntryData* pointer as key and values are the encrypted blobs. This
@@ -144,7 +145,7 @@ TEST_P(IdentityAidl, createAndRetrieveCredential) {
    map<const test_utils::TestEntryData*, vector<vector<uint8_t>>> encryptedBlobs;

    for (const auto& entry : testEntries) {
        ASSERT_TRUE(test_utils::AddEntry(writableCredential, entry, hwInfo.dataChunkSize,
        ASSERT_TRUE(test_utils::addEntry(writableCredential, entry, hwInfo.dataChunkSize,
                                         encryptedBlobs, true));
    }

Loading