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

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

Add attestation certificate parsing and validate for IC vts. am: 38ca6961

Change-Id: If7849f60445fb8264cab812cccb9f0d75bcc58cb
parents ff94f1a5 38ca6961
Loading
Loading
Loading
Loading
+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