| // |
| // Copyright (C) 2015 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 "attestation/server/attestation_service.h" |
| |
| #include <string> |
| |
| #include <base/callback.h> |
| #include <brillo/bind_lambda.h> |
| #include <brillo/data_encoding.h> |
| #include <brillo/http/http_utils.h> |
| #include <brillo/mime_utils.h> |
| #include <crypto/sha2.h> |
| extern "C" { |
| #include <vboot/crossystem.h> |
| } |
| |
| #include "attestation/common/attestation_ca.pb.h" |
| #include "attestation/common/database.pb.h" |
| #include "attestation/common/tpm_utility_factory.h" |
| #include "attestation/server/database_impl.h" |
| |
| namespace { |
| |
| #ifndef USE_TEST_ACA |
| // Google Attestation Certificate Authority (ACA) production instance. |
| const char kACAWebOrigin[] = "https://chromeos-ca.gstatic.com"; |
| const char kACAPublicKey[] = |
| "A2976637E113CC457013F4334312A416395B08D4B2A9724FC9BAD65D0290F39C" |
| "866D1163C2CD6474A24A55403C968CF78FA153C338179407FE568C6E550949B1" |
| "B3A80731BA9311EC16F8F66060A2C550914D252DB90B44D19BC6C15E923FFCFB" |
| "E8A366038772803EE57C7D7E5B3D5E8090BF0960D4F6A6644CB9A456708508F0" |
| "6C19245486C3A49F807AB07C65D5E9954F4F8832BC9F882E9EE1AAA2621B1F43" |
| "4083FD98758745CBFFD6F55DA699B2EE983307C14C9990DDFB48897F26DF8FB2" |
| "CFFF03E631E62FAE59CBF89525EDACD1F7BBE0BA478B5418E756FF3E14AC9970" |
| "D334DB04A1DF267D2343C75E5D282A287060D345981ABDA0B2506AD882579FEF"; |
| const char kACAPublicKeyID[] = "\x00\xc7\x0e\x50\xb1"; |
| #else |
| // Google Attestation Certificate Authority (ACA) test instance. |
| const char kACAWebOrigin[] = "https://asbestos-qa.corp.google.com"; |
| const char kACAPublicKey[] = |
| "A1D50D088994000492B5F3ED8A9C5FC8772706219F4C063B2F6A8C6B74D3AD6B" |
| "212A53D01DABB34A6261288540D420D3BA59ED279D859DE6227A7AB6BD88FADD" |
| "FC3078D465F4DF97E03A52A587BD0165AE3B180FE7B255B7BEDC1BE81CB1383F" |
| "E9E46F9312B1EF28F4025E7D332E33F4416525FEB8F0FC7B815E8FBB79CDABE6" |
| "327B5A155FEF13F559A7086CB8A543D72AD6ECAEE2E704FF28824149D7F4E393" |
| "D3C74E721ACA97F7ADBE2CCF7B4BCC165F7380F48065F2C8370F25F066091259" |
| "D14EA362BAF236E3CD8771A94BDEDA3900577143A238AB92B6C55F11DEFAFB31" |
| "7D1DC5B6AE210C52B008D87F2A7BFF6EB5C4FB32D6ECEC6505796173951A3167"; |
| const char kACAPublicKeyID[] = "\x00\xc2\xb0\x56\x2d"; |
| #endif |
| const size_t kNonceSize = 20; // As per TPM_NONCE definition. |
| const int kNumTemporalValues = 5; |
| |
| std::string GetHardwareID() { |
| char buffer[VB_MAX_STRING_PROPERTY]; |
| const char* property = |
| VbGetSystemPropertyString("hwid", buffer, arraysize(buffer)); |
| if (property != nullptr) { |
| return std::string(property); |
| } |
| LOG(WARNING) << "Could not read hwid property."; |
| return std::string(); |
| } |
| |
| } // namespace |
| |
| namespace attestation { |
| |
| AttestationService::AttestationService() |
| : attestation_ca_origin_(kACAWebOrigin), weak_factory_(this) {} |
| |
| bool AttestationService::Initialize() { |
| if (!worker_thread_) { |
| worker_thread_.reset(new base::Thread("Attestation Service Worker")); |
| worker_thread_->StartWithOptions( |
| base::Thread::Options(base::MessageLoop::TYPE_IO, 0)); |
| LOG(INFO) << "Attestation service started."; |
| } |
| worker_thread_->task_runner()->PostTask( |
| FROM_HERE, |
| base::Bind(&AttestationService::InitializeTask, base::Unretained(this))); |
| return true; |
| } |
| |
| void AttestationService::InitializeTask() { |
| if (!tpm_utility_) { |
| default_tpm_utility_.reset(TpmUtilityFactory::New()); |
| CHECK(default_tpm_utility_->Initialize()); |
| tpm_utility_ = default_tpm_utility_.get(); |
| } |
| if (!crypto_utility_) { |
| default_crypto_utility_.reset(new CryptoUtilityImpl(tpm_utility_)); |
| crypto_utility_ = default_crypto_utility_.get(); |
| } |
| if (!database_) { |
| default_database_.reset(new DatabaseImpl(crypto_utility_)); |
| default_database_->Initialize(); |
| database_ = default_database_.get(); |
| } |
| if (!key_store_) { |
| pkcs11_token_manager_.reset(new chaps::TokenManagerClient()); |
| default_key_store_.reset(new Pkcs11KeyStore(pkcs11_token_manager_.get())); |
| key_store_ = default_key_store_.get(); |
| } |
| if (hwid_.empty()) { |
| hwid_ = GetHardwareID(); |
| } |
| if (!IsPreparedForEnrollment()) { |
| worker_thread_->task_runner()->PostTask( |
| FROM_HERE, base::Bind(&AttestationService::PrepareForEnrollment, |
| base::Unretained(this))); |
| } |
| } |
| |
| void AttestationService::CreateGoogleAttestedKey( |
| const CreateGoogleAttestedKeyRequest& request, |
| const CreateGoogleAttestedKeyCallback& callback) { |
| auto result = std::make_shared<CreateGoogleAttestedKeyReply>(); |
| base::Closure task = |
| base::Bind(&AttestationService::CreateGoogleAttestedKeyTask, |
| base::Unretained(this), request, result); |
| base::Closure reply = base::Bind( |
| &AttestationService::TaskRelayCallback<CreateGoogleAttestedKeyReply>, |
| GetWeakPtr(), callback, result); |
| worker_thread_->task_runner()->PostTaskAndReply(FROM_HERE, task, reply); |
| } |
| |
| void AttestationService::CreateGoogleAttestedKeyTask( |
| const CreateGoogleAttestedKeyRequest& request, |
| const std::shared_ptr<CreateGoogleAttestedKeyReply>& result) { |
| LOG(INFO) << "Creating attested key: " << request.key_label(); |
| if (!IsPreparedForEnrollment()) { |
| LOG(ERROR) << "Attestation: TPM is not ready."; |
| result->set_status(STATUS_NOT_READY); |
| return; |
| } |
| if (!IsEnrolled()) { |
| std::string enroll_request; |
| if (!CreateEnrollRequestInternal(&enroll_request)) { |
| result->set_status(STATUS_UNEXPECTED_DEVICE_ERROR); |
| return; |
| } |
| std::string enroll_reply; |
| if (!SendACARequestAndBlock(kEnroll, enroll_request, &enroll_reply)) { |
| result->set_status(STATUS_CA_NOT_AVAILABLE); |
| return; |
| } |
| std::string server_error; |
| if (!FinishEnrollInternal(enroll_reply, &server_error)) { |
| if (server_error.empty()) { |
| result->set_status(STATUS_UNEXPECTED_DEVICE_ERROR); |
| return; |
| } |
| result->set_status(STATUS_REQUEST_DENIED_BY_CA); |
| result->set_server_error(server_error); |
| return; |
| } |
| } |
| CertifiedKey key; |
| if (!CreateKey(request.username(), request.key_label(), request.key_type(), |
| request.key_usage(), &key)) { |
| result->set_status(STATUS_UNEXPECTED_DEVICE_ERROR); |
| return; |
| } |
| std::string certificate_request; |
| std::string message_id; |
| if (!CreateCertificateRequestInternal(request.username(), key, |
| request.certificate_profile(), request.origin(), |
| &certificate_request, &message_id)) { |
| result->set_status(STATUS_UNEXPECTED_DEVICE_ERROR); |
| return; |
| } |
| std::string certificate_reply; |
| if (!SendACARequestAndBlock(kGetCertificate, certificate_request, |
| &certificate_reply)) { |
| result->set_status(STATUS_CA_NOT_AVAILABLE); |
| return; |
| } |
| std::string certificate_chain; |
| std::string server_error; |
| if (!FinishCertificateRequestInternal(certificate_reply, request.username(), |
| request.key_label(), message_id, &key, |
| &certificate_chain, &server_error)) { |
| if (server_error.empty()) { |
| result->set_status(STATUS_UNEXPECTED_DEVICE_ERROR); |
| return; |
| } |
| result->set_status(STATUS_REQUEST_DENIED_BY_CA); |
| result->set_server_error(server_error); |
| return; |
| } |
| result->set_certificate_chain(certificate_chain); |
| } |
| |
| void AttestationService::GetKeyInfo(const GetKeyInfoRequest& request, |
| const GetKeyInfoCallback& callback) { |
| auto result = std::make_shared<GetKeyInfoReply>(); |
| base::Closure task = base::Bind(&AttestationService::GetKeyInfoTask, |
| base::Unretained(this), request, result); |
| base::Closure reply = |
| base::Bind(&AttestationService::TaskRelayCallback<GetKeyInfoReply>, |
| GetWeakPtr(), callback, result); |
| worker_thread_->task_runner()->PostTaskAndReply(FROM_HERE, task, reply); |
| } |
| |
| void AttestationService::GetKeyInfoTask( |
| const GetKeyInfoRequest& request, |
| const std::shared_ptr<GetKeyInfoReply>& result) { |
| CertifiedKey key; |
| if (!FindKeyByLabel(request.username(), request.key_label(), &key)) { |
| result->set_status(STATUS_INVALID_PARAMETER); |
| return; |
| } |
| std::string public_key_info; |
| if (!GetSubjectPublicKeyInfo(key.key_type(), key.public_key(), |
| &public_key_info)) { |
| LOG(ERROR) << __func__ << ": Bad public key."; |
| result->set_status(STATUS_UNEXPECTED_DEVICE_ERROR); |
| return; |
| } |
| result->set_key_type(key.key_type()); |
| result->set_key_usage(key.key_usage()); |
| result->set_public_key(public_key_info); |
| result->set_certify_info(key.certified_key_info()); |
| result->set_certify_info_signature(key.certified_key_proof()); |
| if (key.has_intermediate_ca_cert()) { |
| result->set_certificate(CreatePEMCertificateChain(key)); |
| } else { |
| result->set_certificate(key.certified_key_credential()); |
| } |
| } |
| |
| void AttestationService::GetEndorsementInfo( |
| const GetEndorsementInfoRequest& request, |
| const GetEndorsementInfoCallback& callback) { |
| auto result = std::make_shared<GetEndorsementInfoReply>(); |
| base::Closure task = base::Bind(&AttestationService::GetEndorsementInfoTask, |
| base::Unretained(this), request, result); |
| base::Closure reply = base::Bind( |
| &AttestationService::TaskRelayCallback<GetEndorsementInfoReply>, |
| GetWeakPtr(), callback, result); |
| worker_thread_->task_runner()->PostTaskAndReply(FROM_HERE, task, reply); |
| } |
| |
| void AttestationService::GetEndorsementInfoTask( |
| const GetEndorsementInfoRequest& request, |
| const std::shared_ptr<GetEndorsementInfoReply>& result) { |
| if (request.key_type() != KEY_TYPE_RSA) { |
| result->set_status(STATUS_INVALID_PARAMETER); |
| return; |
| } |
| auto database_pb = database_->GetProtobuf(); |
| if (!database_pb.has_credentials() || |
| !database_pb.credentials().has_endorsement_public_key()) { |
| // Try to read the public key directly. |
| std::string public_key; |
| if (!tpm_utility_->GetEndorsementPublicKey(KEY_TYPE_RSA, &public_key)) { |
| result->set_status(STATUS_NOT_AVAILABLE); |
| return; |
| } |
| database_pb.mutable_credentials()->set_endorsement_public_key(public_key); |
| } |
| std::string public_key_info; |
| if (!GetSubjectPublicKeyInfo( |
| request.key_type(), |
| database_pb.credentials().endorsement_public_key(), |
| &public_key_info)) { |
| LOG(ERROR) << __func__ << ": Bad public key."; |
| result->set_status(STATUS_UNEXPECTED_DEVICE_ERROR); |
| return; |
| } |
| result->set_ek_public_key(public_key_info); |
| if (database_pb.credentials().has_endorsement_credential()) { |
| result->set_ek_certificate( |
| database_pb.credentials().endorsement_credential()); |
| } |
| } |
| |
| void AttestationService::GetAttestationKeyInfo( |
| const GetAttestationKeyInfoRequest& request, |
| const GetAttestationKeyInfoCallback& callback) { |
| auto result = std::make_shared<GetAttestationKeyInfoReply>(); |
| base::Closure task = |
| base::Bind(&AttestationService::GetAttestationKeyInfoTask, |
| base::Unretained(this), request, result); |
| base::Closure reply = base::Bind( |
| &AttestationService::TaskRelayCallback<GetAttestationKeyInfoReply>, |
| GetWeakPtr(), callback, result); |
| worker_thread_->task_runner()->PostTaskAndReply(FROM_HERE, task, reply); |
| } |
| |
| void AttestationService::GetAttestationKeyInfoTask( |
| const GetAttestationKeyInfoRequest& request, |
| const std::shared_ptr<GetAttestationKeyInfoReply>& result) { |
| if (request.key_type() != KEY_TYPE_RSA) { |
| result->set_status(STATUS_INVALID_PARAMETER); |
| return; |
| } |
| auto database_pb = database_->GetProtobuf(); |
| if (!IsPreparedForEnrollment() || !database_pb.has_identity_key()) { |
| result->set_status(STATUS_NOT_AVAILABLE); |
| return; |
| } |
| if (database_pb.identity_key().has_identity_public_key()) { |
| std::string public_key_info; |
| if (!GetSubjectPublicKeyInfo( |
| request.key_type(), |
| database_pb.identity_key().identity_public_key(), |
| &public_key_info)) { |
| LOG(ERROR) << __func__ << ": Bad public key."; |
| result->set_status(STATUS_UNEXPECTED_DEVICE_ERROR); |
| return; |
| } |
| result->set_public_key(public_key_info); |
| } |
| if (database_pb.has_identity_binding() && |
| database_pb.identity_binding().has_identity_public_key()) { |
| result->set_public_key_tpm_format( |
| database_pb.identity_binding().identity_public_key()); |
| } |
| if (database_pb.identity_key().has_identity_credential()) { |
| result->set_certificate(database_pb.identity_key().identity_credential()); |
| } |
| if (database_pb.has_pcr0_quote()) { |
| *result->mutable_pcr0_quote() = database_pb.pcr0_quote(); |
| } |
| if (database_pb.has_pcr1_quote()) { |
| *result->mutable_pcr1_quote() = database_pb.pcr1_quote(); |
| } |
| } |
| |
| void AttestationService::ActivateAttestationKey( |
| const ActivateAttestationKeyRequest& request, |
| const ActivateAttestationKeyCallback& callback) { |
| auto result = std::make_shared<ActivateAttestationKeyReply>(); |
| base::Closure task = |
| base::Bind(&AttestationService::ActivateAttestationKeyTask, |
| base::Unretained(this), request, result); |
| base::Closure reply = base::Bind( |
| &AttestationService::TaskRelayCallback<ActivateAttestationKeyReply>, |
| GetWeakPtr(), callback, result); |
| worker_thread_->task_runner()->PostTaskAndReply(FROM_HERE, task, reply); |
| } |
| |
| void AttestationService::ActivateAttestationKeyTask( |
| const ActivateAttestationKeyRequest& request, |
| const std::shared_ptr<ActivateAttestationKeyReply>& result) { |
| if (request.key_type() != KEY_TYPE_RSA) { |
| result->set_status(STATUS_INVALID_PARAMETER); |
| LOG(ERROR) << __func__ << ": Only RSA currently supported."; |
| return; |
| } |
| if (request.encrypted_certificate().tpm_version() != |
| tpm_utility_->GetVersion()) { |
| result->set_status(STATUS_INVALID_PARAMETER); |
| LOG(ERROR) << __func__ << ": TPM version mismatch."; |
| return; |
| } |
| std::string certificate; |
| if (!ActivateAttestationKeyInternal(request.encrypted_certificate(), |
| request.save_certificate(), |
| &certificate)) { |
| result->set_status(STATUS_UNEXPECTED_DEVICE_ERROR); |
| return; |
| } |
| result->set_certificate(certificate); |
| } |
| |
| void AttestationService::CreateCertifiableKey( |
| const CreateCertifiableKeyRequest& request, |
| const CreateCertifiableKeyCallback& callback) { |
| auto result = std::make_shared<CreateCertifiableKeyReply>(); |
| base::Closure task = base::Bind(&AttestationService::CreateCertifiableKeyTask, |
| base::Unretained(this), request, result); |
| base::Closure reply = base::Bind( |
| &AttestationService::TaskRelayCallback<CreateCertifiableKeyReply>, |
| GetWeakPtr(), callback, result); |
| worker_thread_->task_runner()->PostTaskAndReply(FROM_HERE, task, reply); |
| } |
| |
| void AttestationService::CreateCertifiableKeyTask( |
| const CreateCertifiableKeyRequest& request, |
| const std::shared_ptr<CreateCertifiableKeyReply>& result) { |
| CertifiedKey key; |
| if (!CreateKey(request.username(), request.key_label(), request.key_type(), |
| request.key_usage(), &key)) { |
| result->set_status(STATUS_UNEXPECTED_DEVICE_ERROR); |
| return; |
| } |
| std::string public_key_info; |
| if (!GetSubjectPublicKeyInfo(key.key_type(), key.public_key(), |
| &public_key_info)) { |
| LOG(ERROR) << __func__ << ": Bad public key."; |
| result->set_status(STATUS_UNEXPECTED_DEVICE_ERROR); |
| return; |
| } |
| result->set_public_key(public_key_info); |
| result->set_certify_info(key.certified_key_info()); |
| result->set_certify_info_signature(key.certified_key_proof()); |
| } |
| |
| void AttestationService::Decrypt(const DecryptRequest& request, |
| const DecryptCallback& callback) { |
| auto result = std::make_shared<DecryptReply>(); |
| base::Closure task = base::Bind(&AttestationService::DecryptTask, |
| base::Unretained(this), request, result); |
| base::Closure reply = |
| base::Bind(&AttestationService::TaskRelayCallback<DecryptReply>, |
| GetWeakPtr(), callback, result); |
| worker_thread_->task_runner()->PostTaskAndReply(FROM_HERE, task, reply); |
| } |
| |
| void AttestationService::DecryptTask( |
| const DecryptRequest& request, |
| const std::shared_ptr<DecryptReply>& result) { |
| CertifiedKey key; |
| if (!FindKeyByLabel(request.username(), request.key_label(), &key)) { |
| result->set_status(STATUS_INVALID_PARAMETER); |
| return; |
| } |
| std::string data; |
| if (!tpm_utility_->Unbind(key.key_blob(), request.encrypted_data(), &data)) { |
| result->set_status(STATUS_UNEXPECTED_DEVICE_ERROR); |
| return; |
| } |
| result->set_decrypted_data(data); |
| } |
| |
| void AttestationService::Sign(const SignRequest& request, |
| const SignCallback& callback) { |
| auto result = std::make_shared<SignReply>(); |
| base::Closure task = base::Bind(&AttestationService::SignTask, |
| base::Unretained(this), request, result); |
| base::Closure reply = |
| base::Bind(&AttestationService::TaskRelayCallback<SignReply>, |
| GetWeakPtr(), callback, result); |
| worker_thread_->task_runner()->PostTaskAndReply(FROM_HERE, task, reply); |
| } |
| |
| void AttestationService::SignTask(const SignRequest& request, |
| const std::shared_ptr<SignReply>& result) { |
| CertifiedKey key; |
| if (!FindKeyByLabel(request.username(), request.key_label(), &key)) { |
| result->set_status(STATUS_INVALID_PARAMETER); |
| return; |
| } |
| std::string signature; |
| if (!tpm_utility_->Sign(key.key_blob(), request.data_to_sign(), &signature)) { |
| result->set_status(STATUS_UNEXPECTED_DEVICE_ERROR); |
| return; |
| } |
| result->set_signature(signature); |
| } |
| |
| void AttestationService::RegisterKeyWithChapsToken( |
| const RegisterKeyWithChapsTokenRequest& request, |
| const RegisterKeyWithChapsTokenCallback& callback) { |
| auto result = std::make_shared<RegisterKeyWithChapsTokenReply>(); |
| base::Closure task = |
| base::Bind(&AttestationService::RegisterKeyWithChapsTokenTask, |
| base::Unretained(this), request, result); |
| base::Closure reply = base::Bind( |
| &AttestationService::TaskRelayCallback<RegisterKeyWithChapsTokenReply>, |
| GetWeakPtr(), callback, result); |
| worker_thread_->task_runner()->PostTaskAndReply(FROM_HERE, task, reply); |
| } |
| |
| void AttestationService::RegisterKeyWithChapsTokenTask( |
| const RegisterKeyWithChapsTokenRequest& request, |
| const std::shared_ptr<RegisterKeyWithChapsTokenReply>& result) { |
| CertifiedKey key; |
| if (!FindKeyByLabel(request.username(), request.key_label(), &key)) { |
| result->set_status(STATUS_INVALID_PARAMETER); |
| return; |
| } |
| if (!key_store_->Register(request.username(), request.key_label(), |
| key.key_type(), key.key_usage(), key.key_blob(), |
| key.public_key(), key.certified_key_credential())) { |
| result->set_status(STATUS_UNEXPECTED_DEVICE_ERROR); |
| return; |
| } |
| if (key.has_intermediate_ca_cert() && |
| !key_store_->RegisterCertificate(request.username(), |
| key.intermediate_ca_cert())) { |
| result->set_status(STATUS_UNEXPECTED_DEVICE_ERROR); |
| return; |
| } |
| for (int i = 0; i < key.additional_intermediate_ca_cert_size(); ++i) { |
| if (!key_store_->RegisterCertificate( |
| request.username(), key.additional_intermediate_ca_cert(i))) { |
| result->set_status(STATUS_UNEXPECTED_DEVICE_ERROR); |
| return; |
| } |
| } |
| DeleteKey(request.username(), request.key_label()); |
| } |
| |
| void AttestationService::WaitUntilIdleForTesting() { |
| while (!worker_thread_->message_loop()->IsIdleForTesting()) { |
| base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(10)); |
| } |
| } |
| |
| bool AttestationService::IsPreparedForEnrollment() { |
| if (!tpm_utility_->IsTpmReady()) { |
| return false; |
| } |
| auto database_pb = database_->GetProtobuf(); |
| if (!database_pb.has_credentials()) { |
| return false; |
| } |
| return ( |
| database_pb.credentials().has_endorsement_credential() || |
| database_pb.credentials().has_default_encrypted_endorsement_credential()); |
| } |
| |
| bool AttestationService::IsEnrolled() { |
| auto database_pb = database_->GetProtobuf(); |
| return database_pb.has_identity_key() && |
| database_pb.identity_key().has_identity_credential(); |
| } |
| |
| bool AttestationService::CreateEnrollRequestInternal(std::string* enroll_request) { |
| if (!IsPreparedForEnrollment()) { |
| LOG(ERROR) << __func__ << ": Enrollment is not possible, attestation data " |
| << "does not exist."; |
| return false; |
| } |
| auto database_pb = database_->GetProtobuf(); |
| AttestationEnrollmentRequest request_pb; |
| request_pb.set_tpm_version(tpm_utility_->GetVersion()); |
| *request_pb.mutable_encrypted_endorsement_credential() = |
| database_pb.credentials().default_encrypted_endorsement_credential(); |
| request_pb.set_identity_public_key( |
| database_pb.identity_binding().identity_public_key()); |
| *request_pb.mutable_pcr0_quote() = database_pb.pcr0_quote(); |
| *request_pb.mutable_pcr1_quote() = database_pb.pcr1_quote(); |
| if (!request_pb.SerializeToString(enroll_request)) { |
| LOG(ERROR) << __func__ << ": Failed to serialize protobuf."; |
| return false; |
| } |
| return true; |
| } |
| |
| bool AttestationService::FinishEnrollInternal(const std::string& enroll_response, |
| std::string* server_error) { |
| if (!tpm_utility_->IsTpmReady()) { |
| return false; |
| } |
| AttestationEnrollmentResponse response_pb; |
| if (!response_pb.ParseFromString(enroll_response)) { |
| LOG(ERROR) << __func__ << ": Failed to parse response from CA."; |
| return false; |
| } |
| if (response_pb.status() != OK) { |
| *server_error = response_pb.detail(); |
| LOG(ERROR) << __func__ |
| << ": Error received from CA: " << response_pb.detail(); |
| return false; |
| } |
| if (response_pb.encrypted_identity_credential().tpm_version() != |
| tpm_utility_->GetVersion()) { |
| LOG(ERROR) << __func__ << ": TPM version mismatch."; |
| return false; |
| } |
| if (!ActivateAttestationKeyInternal( |
| response_pb.encrypted_identity_credential(), |
| true /* save_certificate */, nullptr /* certificate */)) { |
| return false; |
| } |
| LOG(INFO) << "Attestation: Enrollment complete."; |
| return true; |
| } |
| |
| bool AttestationService::CreateCertificateRequestInternal( |
| const std::string& username, |
| const CertifiedKey& key, |
| CertificateProfile profile, |
| const std::string& origin, |
| std::string* certificate_request, |
| std::string* message_id) { |
| if (!tpm_utility_->IsTpmReady()) { |
| return false; |
| } |
| if (!IsEnrolled()) { |
| LOG(ERROR) << __func__ << ": Device is not enrolled for attestation."; |
| return false; |
| } |
| AttestationCertificateRequest request_pb; |
| if (!crypto_utility_->GetRandom(kNonceSize, message_id)) { |
| LOG(ERROR) << __func__ << ": GetRandom(message_id) failed."; |
| return false; |
| } |
| request_pb.set_tpm_version(tpm_utility_->GetVersion()); |
| request_pb.set_message_id(*message_id); |
| auto database_pb = database_->GetProtobuf(); |
| request_pb.set_identity_credential( |
| database_pb.identity_key().identity_credential()); |
| request_pb.set_profile(profile); |
| if (!origin.empty() && |
| (profile == CONTENT_PROTECTION_CERTIFICATE_WITH_STABLE_ID)) { |
| request_pb.set_origin(origin); |
| request_pb.set_temporal_index(ChooseTemporalIndex(username, origin)); |
| } |
| request_pb.set_certified_public_key(key.public_key_tpm_format()); |
| request_pb.set_certified_key_info(key.certified_key_info()); |
| request_pb.set_certified_key_proof(key.certified_key_proof()); |
| if (!request_pb.SerializeToString(certificate_request)) { |
| LOG(ERROR) << __func__ << ": Failed to serialize protobuf."; |
| return false; |
| } |
| return true; |
| } |
| |
| bool AttestationService::FinishCertificateRequestInternal( |
| const std::string& certificate_response, |
| const std::string& username, |
| const std::string& key_label, |
| const std::string& message_id, |
| CertifiedKey* key, |
| std::string* certificate_chain, |
| std::string* server_error) { |
| if (!tpm_utility_->IsTpmReady()) { |
| return false; |
| } |
| AttestationCertificateResponse response_pb; |
| if (!response_pb.ParseFromString(certificate_response)) { |
| LOG(ERROR) << __func__ << ": Failed to parse response from Attestation CA."; |
| return false; |
| } |
| if (response_pb.status() != OK) { |
| *server_error = response_pb.detail(); |
| LOG(ERROR) << __func__ << ": Error received from Attestation CA: " |
| << response_pb.detail(); |
| return false; |
| } |
| if (message_id != response_pb.message_id()) { |
| LOG(ERROR) << __func__ << ": Message ID mismatch."; |
| return false; |
| } |
| |
| // Finish populating the CertifiedKey protobuf and store it. |
| key->set_certified_key_credential(response_pb.certified_key_credential()); |
| key->set_intermediate_ca_cert(response_pb.intermediate_ca_cert()); |
| key->mutable_additional_intermediate_ca_cert()->MergeFrom( |
| response_pb.additional_intermediate_ca_cert()); |
| if (!SaveKey(username, key_label, *key)) { |
| return false; |
| } |
| LOG(INFO) << "Attestation: Certified key credential received and stored."; |
| *certificate_chain = CreatePEMCertificateChain(*key); |
| return true; |
| } |
| |
| bool AttestationService::SendACARequestAndBlock(ACARequestType request_type, |
| const std::string& request, |
| std::string* reply) { |
| std::shared_ptr<brillo::http::Transport> transport = http_transport_; |
| if (!transport) { |
| transport = brillo::http::Transport::CreateDefault(); |
| } |
| std::unique_ptr<brillo::http::Response> response = PostBinaryAndBlock( |
| GetACAURL(request_type), request.data(), request.size(), |
| brillo::mime::application::kOctet_stream, {}, // headers |
| transport, |
| nullptr); // error |
| if (!response || !response->IsSuccessful()) { |
| LOG(ERROR) << "HTTP request to Attestation CA failed."; |
| return false; |
| } |
| *reply = response->ExtractDataAsString(); |
| return true; |
| } |
| |
| bool AttestationService::FindKeyByLabel(const std::string& username, |
| const std::string& key_label, |
| CertifiedKey* key) { |
| if (!username.empty()) { |
| std::string key_data; |
| if (!key_store_->Read(username, key_label, &key_data)) { |
| LOG(INFO) << "Key not found: " << key_label; |
| return false; |
| } |
| if (key && !key->ParseFromString(key_data)) { |
| LOG(ERROR) << "Failed to parse key: " << key_label; |
| return false; |
| } |
| return true; |
| } |
| auto database_pb = database_->GetProtobuf(); |
| for (int i = 0; i < database_pb.device_keys_size(); ++i) { |
| if (database_pb.device_keys(i).key_name() == key_label) { |
| *key = database_pb.device_keys(i); |
| return true; |
| } |
| } |
| LOG(INFO) << "Key not found: " << key_label; |
| return false; |
| } |
| |
| bool AttestationService::CreateKey(const std::string& username, |
| const std::string& key_label, |
| KeyType key_type, |
| KeyUsage key_usage, |
| CertifiedKey* key) { |
| std::string nonce; |
| if (!crypto_utility_->GetRandom(kNonceSize, &nonce)) { |
| LOG(ERROR) << __func__ << ": GetRandom(nonce) failed."; |
| return false; |
| } |
| std::string key_blob; |
| std::string public_key; |
| std::string public_key_tpm_format; |
| std::string key_info; |
| std::string proof; |
| auto database_pb = database_->GetProtobuf(); |
| if (!tpm_utility_->CreateCertifiedKey( |
| key_type, key_usage, database_pb.identity_key().identity_key_blob(), |
| nonce, &key_blob, &public_key, &public_key_tpm_format, &key_info, |
| &proof)) { |
| return false; |
| } |
| key->set_key_blob(key_blob); |
| key->set_public_key(public_key); |
| key->set_key_name(key_label); |
| key->set_public_key_tpm_format(public_key_tpm_format); |
| key->set_certified_key_info(key_info); |
| key->set_certified_key_proof(proof); |
| key->set_key_type(key_type); |
| key->set_key_usage(key_usage); |
| return SaveKey(username, key_label, *key); |
| } |
| |
| bool AttestationService::SaveKey(const std::string& username, |
| const std::string& key_label, |
| const CertifiedKey& key) { |
| if (!username.empty()) { |
| std::string key_data; |
| if (!key.SerializeToString(&key_data)) { |
| LOG(ERROR) << __func__ << ": Failed to serialize protobuf."; |
| return false; |
| } |
| if (!key_store_->Write(username, key_label, key_data)) { |
| LOG(ERROR) << __func__ << ": Failed to store certified key for user."; |
| return false; |
| } |
| } else { |
| if (!AddDeviceKey(key_label, key)) { |
| LOG(ERROR) << __func__ << ": Failed to store certified key for device."; |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| void AttestationService::DeleteKey(const std::string& username, |
| const std::string& key_label) { |
| if (!username.empty()) { |
| key_store_->Delete(username, key_label); |
| } else { |
| RemoveDeviceKey(key_label); |
| } |
| } |
| |
| bool AttestationService::AddDeviceKey(const std::string& key_label, |
| const CertifiedKey& key) { |
| // If a key by this name already exists, reuse the field. |
| auto* database_pb = database_->GetMutableProtobuf(); |
| bool found = false; |
| for (int i = 0; i < database_pb->device_keys_size(); ++i) { |
| if (database_pb->device_keys(i).key_name() == key_label) { |
| found = true; |
| *database_pb->mutable_device_keys(i) = key; |
| break; |
| } |
| } |
| if (!found) |
| *database_pb->add_device_keys() = key; |
| return database_->SaveChanges(); |
| } |
| |
| void AttestationService::RemoveDeviceKey(const std::string& key_label) { |
| auto* database_pb = database_->GetMutableProtobuf(); |
| bool found = false; |
| for (int i = 0; i < database_pb->device_keys_size(); ++i) { |
| if (database_pb->device_keys(i).key_name() == key_label) { |
| found = true; |
| int last = database_pb->device_keys_size() - 1; |
| if (i < last) { |
| database_pb->mutable_device_keys()->SwapElements(i, last); |
| } |
| database_pb->mutable_device_keys()->RemoveLast(); |
| break; |
| } |
| } |
| if (found) { |
| if (!database_->SaveChanges()) { |
| LOG(WARNING) << __func__ << ": Failed to persist key deletion."; |
| } |
| } |
| } |
| |
| std::string AttestationService::CreatePEMCertificateChain( |
| const CertifiedKey& key) { |
| if (key.certified_key_credential().empty()) { |
| LOG(WARNING) << "Certificate is empty."; |
| return std::string(); |
| } |
| std::string pem = CreatePEMCertificate(key.certified_key_credential()); |
| if (!key.intermediate_ca_cert().empty()) { |
| pem += "\n"; |
| pem += CreatePEMCertificate(key.intermediate_ca_cert()); |
| } |
| for (int i = 0; i < key.additional_intermediate_ca_cert_size(); ++i) { |
| pem += "\n"; |
| pem += CreatePEMCertificate(key.additional_intermediate_ca_cert(i)); |
| } |
| return pem; |
| } |
| |
| std::string AttestationService::CreatePEMCertificate( |
| const std::string& certificate) { |
| const char kBeginCertificate[] = "-----BEGIN CERTIFICATE-----\n"; |
| const char kEndCertificate[] = "-----END CERTIFICATE-----"; |
| |
| std::string pem = kBeginCertificate; |
| pem += brillo::data_encoding::Base64EncodeWrapLines(certificate); |
| pem += kEndCertificate; |
| return pem; |
| } |
| |
| int AttestationService::ChooseTemporalIndex(const std::string& user, |
| const std::string& origin) { |
| std::string user_hash = crypto::SHA256HashString(user); |
| std::string origin_hash = crypto::SHA256HashString(origin); |
| int histogram[kNumTemporalValues] = {}; |
| auto database_pb = database_->GetProtobuf(); |
| for (int i = 0; i < database_pb.temporal_index_record_size(); ++i) { |
| const AttestationDatabase::TemporalIndexRecord& record = |
| database_pb.temporal_index_record(i); |
| // Ignore out-of-range index values. |
| if (record.temporal_index() < 0 || |
| record.temporal_index() >= kNumTemporalValues) |
| continue; |
| if (record.origin_hash() == origin_hash) { |
| if (record.user_hash() == user_hash) { |
| // We've previously chosen this index for this user, reuse it. |
| return record.temporal_index(); |
| } else { |
| // We've previously chosen this index for another user. |
| ++histogram[record.temporal_index()]; |
| } |
| } |
| } |
| int least_used_index = 0; |
| for (int i = 1; i < kNumTemporalValues; ++i) { |
| if (histogram[i] < histogram[least_used_index]) |
| least_used_index = i; |
| } |
| if (histogram[least_used_index] > 0) { |
| LOG(WARNING) << "Unique origin-specific identifiers have been exhausted."; |
| } |
| // Record our choice for later reference. |
| AttestationDatabase::TemporalIndexRecord* new_record = |
| database_pb.add_temporal_index_record(); |
| new_record->set_origin_hash(origin_hash); |
| new_record->set_user_hash(user_hash); |
| new_record->set_temporal_index(least_used_index); |
| database_->SaveChanges(); |
| return least_used_index; |
| } |
| |
| std::string AttestationService::GetACAURL(ACARequestType request_type) const { |
| std::string url = attestation_ca_origin_; |
| switch (request_type) { |
| case kEnroll: |
| url += "/enroll"; |
| break; |
| case kGetCertificate: |
| url += "/sign"; |
| break; |
| default: |
| NOTREACHED(); |
| } |
| return url; |
| } |
| |
| bool AttestationService::GetSubjectPublicKeyInfo( |
| KeyType key_type, |
| const std::string& public_key, |
| std::string* public_key_info) const { |
| // Only RSA is supported currently. |
| if (key_type != KEY_TYPE_RSA) { |
| return false; |
| } |
| return crypto_utility_->GetRSASubjectPublicKeyInfo(public_key, |
| public_key_info); |
| } |
| |
| void AttestationService::PrepareForEnrollment() { |
| if (IsPreparedForEnrollment()) { |
| return; |
| } |
| if (!tpm_utility_->IsTpmReady()) { |
| // Try again later. |
| worker_thread_->task_runner()->PostDelayedTask( |
| FROM_HERE, base::Bind(&AttestationService::PrepareForEnrollment, |
| base::Unretained(this)), |
| base::TimeDelta::FromSeconds(3)); |
| return; |
| } |
| base::TimeTicks start = base::TimeTicks::Now(); |
| LOG(INFO) << "Attestation: Preparing for enrollment..."; |
| // Gather information about the endorsement key. |
| std::string rsa_ek_public_key; |
| if (!tpm_utility_->GetEndorsementPublicKey(KEY_TYPE_RSA, |
| &rsa_ek_public_key)) { |
| LOG(ERROR) << "Attestation: Failed to get RSA EK public key."; |
| return; |
| } |
| std::string ecc_ek_public_key; |
| if (!tpm_utility_->GetEndorsementPublicKey(KEY_TYPE_ECC, |
| &ecc_ek_public_key)) { |
| LOG(WARNING) << "Attestation: Failed to get ECC EK public key."; |
| } |
| std::string rsa_ek_certificate; |
| if (!tpm_utility_->GetEndorsementCertificate(KEY_TYPE_RSA, |
| &rsa_ek_certificate)) { |
| LOG(ERROR) << "Attestation: Failed to get RSA EK certificate."; |
| return; |
| } |
| std::string ecc_ek_certificate; |
| if (!tpm_utility_->GetEndorsementCertificate(KEY_TYPE_ECC, |
| &ecc_ek_certificate)) { |
| LOG(WARNING) << "Attestation: Failed to get ECC EK certificate."; |
| } |
| // Create an identity key. |
| std::string rsa_identity_public_key; |
| std::string rsa_identity_key_blob; |
| if (!tpm_utility_->CreateRestrictedKey(KEY_TYPE_RSA, KEY_USAGE_SIGN, |
| &rsa_identity_public_key, |
| &rsa_identity_key_blob)) { |
| LOG(ERROR) << "Attestation: Failed to create RSA AIK."; |
| return; |
| } |
| std::string rsa_identity_public_key_der; |
| if (!tpm_utility_->GetRSAPublicKeyFromTpmPublicKey( |
| rsa_identity_public_key, &rsa_identity_public_key_der)) { |
| LOG(ERROR) << "Attestation: Failed to parse AIK public key."; |
| return; |
| } |
| // Quote PCRs. These quotes are intended to be valid for the lifetime of the |
| // identity key so they do not need external data. This only works when |
| // firmware ensures that these PCRs will not change unless the TPM owner is |
| // cleared. |
| std::string quoted_pcr_value0; |
| std::string quoted_data0; |
| std::string quote0; |
| if (!tpm_utility_->QuotePCR(0, rsa_identity_key_blob, "ed_pcr_value0, |
| "ed_data0, "e0)) { |
| LOG(ERROR) << "Attestation: Failed to generate quote for PCR_0."; |
| return; |
| } |
| std::string quoted_pcr_value1; |
| std::string quoted_data1; |
| std::string quote1; |
| if (!tpm_utility_->QuotePCR(1, rsa_identity_key_blob, "ed_pcr_value1, |
| "ed_data1, "e1)) { |
| LOG(ERROR) << "Attestation: Failed to generate quote for PCR_1."; |
| return; |
| } |
| // Store all this in the attestation database. |
| AttestationDatabase* database_pb = database_->GetMutableProtobuf(); |
| TPMCredentials* credentials_pb = database_pb->mutable_credentials(); |
| credentials_pb->set_endorsement_public_key(rsa_ek_public_key); |
| credentials_pb->set_endorsement_credential(rsa_ek_certificate); |
| credentials_pb->set_ecc_endorsement_public_key(ecc_ek_public_key); |
| credentials_pb->set_ecc_endorsement_credential(ecc_ek_certificate); |
| |
| if (!crypto_utility_->EncryptCertificateForGoogle( |
| rsa_ek_certificate, kACAPublicKey, |
| std::string(kACAPublicKeyID, arraysize(kACAPublicKeyID) - 1), |
| credentials_pb->mutable_default_encrypted_endorsement_credential())) { |
| LOG(ERROR) << "Attestation: Failed to encrypt EK certificate."; |
| return; |
| } |
| IdentityKey* key_pb = database_pb->mutable_identity_key(); |
| key_pb->set_identity_public_key(rsa_identity_public_key_der); |
| key_pb->set_identity_key_blob(rsa_identity_key_blob); |
| IdentityBinding* binding_pb = database_pb->mutable_identity_binding(); |
| binding_pb->set_identity_public_key_der(rsa_identity_public_key_der); |
| binding_pb->set_identity_public_key(rsa_identity_public_key); |
| Quote* quote_pb0 = database_pb->mutable_pcr0_quote(); |
| quote_pb0->set_quote(quote0); |
| quote_pb0->set_quoted_data(quoted_data0); |
| quote_pb0->set_quoted_pcr_value(quoted_pcr_value0); |
| Quote* quote_pb1 = database_pb->mutable_pcr1_quote(); |
| quote_pb1->set_quote(quote1); |
| quote_pb1->set_quoted_data(quoted_data1); |
| quote_pb1->set_quoted_pcr_value(quoted_pcr_value1); |
| quote_pb1->set_pcr_source_hint(hwid_); |
| if (!database_->SaveChanges()) { |
| LOG(ERROR) << "Attestation: Failed to write database."; |
| return; |
| } |
| base::TimeDelta delta = (base::TimeTicks::Now() - start); |
| LOG(INFO) << "Attestation: Prepared successfully (" << delta.InMilliseconds() |
| << "ms)."; |
| } |
| |
| bool AttestationService::ActivateAttestationKeyInternal( |
| const EncryptedIdentityCredential& encrypted_certificate, |
| bool save_certificate, |
| std::string* certificate) { |
| std::string certificate_local; |
| auto database_pb = database_->GetProtobuf(); |
| if (encrypted_certificate.tpm_version() == TPM_1_2) { |
| // TPM 1.2 style activate. |
| if (!tpm_utility_->ActivateIdentity( |
| database_pb.delegate().blob(), database_pb.delegate().secret(), |
| database_pb.identity_key().identity_key_blob(), |
| encrypted_certificate.asym_ca_contents(), |
| encrypted_certificate.sym_ca_attestation(), |
| &certificate_local)) { |
| LOG(ERROR) << __func__ << ": Failed to activate identity."; |
| return false; |
| } |
| } else { |
| // TPM 2.0 style activate. |
| std::string credential; |
| if (!tpm_utility_->ActivateIdentityForTpm2( |
| KEY_TYPE_RSA, database_pb.identity_key().identity_key_blob(), |
| encrypted_certificate.encrypted_seed(), |
| encrypted_certificate.credential_mac(), |
| encrypted_certificate.wrapped_certificate().wrapped_key(), |
| &credential)) { |
| LOG(ERROR) << __func__ << ": Failed to activate identity."; |
| return false; |
| } |
| if (!crypto_utility_->DecryptIdentityCertificateForTpm2( |
| credential, encrypted_certificate.wrapped_certificate(), |
| &certificate_local)) { |
| LOG(ERROR) << __func__ << ": Failed to decrypt identity certificate."; |
| return false; |
| } |
| } |
| if (save_certificate) { |
| database_->GetMutableProtobuf() |
| ->mutable_identity_key() |
| ->set_identity_credential(certificate_local); |
| if (!database_->SaveChanges()) { |
| LOG(ERROR) << __func__ << ": Failed to persist database changes."; |
| return false; |
| } |
| } |
| if (certificate) { |
| *certificate = certificate_local; |
| } |
| return true; |
| } |
| |
| void AttestationService::GetStatus( |
| const GetStatusRequest& request, |
| const GetStatusCallback& callback) { |
| auto result = std::make_shared<GetStatusReply>(); |
| base::Closure task = |
| base::Bind(&AttestationService::GetStatusTask, |
| base::Unretained(this), request, result); |
| base::Closure reply = base::Bind( |
| &AttestationService::TaskRelayCallback<GetStatusReply>, |
| GetWeakPtr(), callback, result); |
| worker_thread_->task_runner()->PostTaskAndReply(FROM_HERE, task, reply); |
| } |
| |
| void AttestationService::GetStatusTask( |
| const GetStatusRequest& request, |
| const std::shared_ptr<GetStatusReply>& result) { |
| LOG(ERROR) << __func__ << ": Not implemented."; |
| result->set_status(STATUS_NOT_SUPPORTED); |
| } |
| |
| void AttestationService::Verify( |
| const VerifyRequest& request, |
| const VerifyCallback& callback) { |
| auto result = std::make_shared<VerifyReply>(); |
| base::Closure task = |
| base::Bind(&AttestationService::VerifyTask, |
| base::Unretained(this), request, result); |
| base::Closure reply = base::Bind( |
| &AttestationService::TaskRelayCallback<VerifyReply>, |
| GetWeakPtr(), callback, result); |
| worker_thread_->task_runner()->PostTaskAndReply(FROM_HERE, task, reply); |
| } |
| |
| void AttestationService::VerifyTask( |
| const VerifyRequest& request, |
| const std::shared_ptr<VerifyReply>& result) { |
| LOG(ERROR) << __func__ << ": Not implemented."; |
| result->set_status(STATUS_NOT_SUPPORTED); |
| } |
| |
| void AttestationService::CreateEnrollRequest( |
| const CreateEnrollRequestRequest& request, |
| const CreateEnrollRequestCallback& callback) { |
| auto result = std::make_shared<CreateEnrollRequestReply>(); |
| base::Closure task = |
| base::Bind(&AttestationService::CreateEnrollRequestTask, |
| base::Unretained(this), request, result); |
| base::Closure reply = base::Bind( |
| &AttestationService::TaskRelayCallback<CreateEnrollRequestReply>, |
| GetWeakPtr(), callback, result); |
| worker_thread_->task_runner()->PostTaskAndReply(FROM_HERE, task, reply); |
| } |
| |
| void AttestationService::CreateEnrollRequestTask( |
| const CreateEnrollRequestRequest& request, |
| const std::shared_ptr<CreateEnrollRequestReply>& result) { |
| LOG(ERROR) << __func__ << ": Not implemented."; |
| result->set_status(STATUS_NOT_SUPPORTED); |
| } |
| |
| void AttestationService::FinishEnroll( |
| const FinishEnrollRequest& request, |
| const FinishEnrollCallback& callback) { |
| auto result = std::make_shared<FinishEnrollReply>(); |
| base::Closure task = |
| base::Bind(&AttestationService::FinishEnrollTask, |
| base::Unretained(this), request, result); |
| base::Closure reply = base::Bind( |
| &AttestationService::TaskRelayCallback<FinishEnrollReply>, |
| GetWeakPtr(), callback, result); |
| worker_thread_->task_runner()->PostTaskAndReply(FROM_HERE, task, reply); |
| } |
| |
| void AttestationService::FinishEnrollTask( |
| const FinishEnrollRequest& request, |
| const std::shared_ptr<FinishEnrollReply>& result) { |
| LOG(ERROR) << __func__ << ": Not implemented."; |
| result->set_status(STATUS_NOT_SUPPORTED); |
| } |
| |
| void AttestationService::CreateCertificateRequest( |
| const CreateCertificateRequestRequest& request, |
| const CreateCertificateRequestCallback& callback) { |
| auto result = std::make_shared<CreateCertificateRequestReply>(); |
| base::Closure task = |
| base::Bind(&AttestationService::CreateCertificateRequestTask, |
| base::Unretained(this), request, result); |
| base::Closure reply = base::Bind( |
| &AttestationService::TaskRelayCallback<CreateCertificateRequestReply>, |
| GetWeakPtr(), callback, result); |
| worker_thread_->task_runner()->PostTaskAndReply(FROM_HERE, task, reply); |
| } |
| |
| void AttestationService::CreateCertificateRequestTask( |
| const CreateCertificateRequestRequest& request, |
| const std::shared_ptr<CreateCertificateRequestReply>& result) { |
| LOG(ERROR) << __func__ << ": Not implemented."; |
| result->set_status(STATUS_NOT_SUPPORTED); |
| } |
| |
| void AttestationService::FinishCertificateRequest( |
| const FinishCertificateRequestRequest& request, |
| const FinishCertificateRequestCallback& callback) { |
| auto result = std::make_shared<FinishCertificateRequestReply>(); |
| base::Closure task = |
| base::Bind(&AttestationService::FinishCertificateRequestTask, |
| base::Unretained(this), request, result); |
| base::Closure reply = base::Bind( |
| &AttestationService::TaskRelayCallback<FinishCertificateRequestReply>, |
| GetWeakPtr(), callback, result); |
| worker_thread_->task_runner()->PostTaskAndReply(FROM_HERE, task, reply); |
| } |
| |
| void AttestationService::FinishCertificateRequestTask( |
| const FinishCertificateRequestRequest& request, |
| const std::shared_ptr<FinishCertificateRequestReply>& result) { |
| LOG(ERROR) << __func__ << ": Not implemented."; |
| result->set_status(STATUS_NOT_SUPPORTED); |
| } |
| |
| void AttestationService::SignEnterpriseChallenge( |
| const SignEnterpriseChallengeRequest& request, |
| const SignEnterpriseChallengeCallback& callback) { |
| auto result = std::make_shared<SignEnterpriseChallengeReply>(); |
| base::Closure task = |
| base::Bind(&AttestationService::SignEnterpriseChallengeTask, |
| base::Unretained(this), request, result); |
| base::Closure reply = base::Bind( |
| &AttestationService::TaskRelayCallback<SignEnterpriseChallengeReply>, |
| GetWeakPtr(), callback, result); |
| worker_thread_->task_runner()->PostTaskAndReply(FROM_HERE, task, reply); |
| } |
| |
| void AttestationService::SignEnterpriseChallengeTask( |
| const SignEnterpriseChallengeRequest& request, |
| const std::shared_ptr<SignEnterpriseChallengeReply>& result) { |
| LOG(ERROR) << __func__ << ": Not implemented."; |
| result->set_status(STATUS_NOT_SUPPORTED); |
| } |
| |
| void AttestationService::SignSimpleChallenge( |
| const SignSimpleChallengeRequest& request, |
| const SignSimpleChallengeCallback& callback) { |
| auto result = std::make_shared<SignSimpleChallengeReply>(); |
| base::Closure task = |
| base::Bind(&AttestationService::SignSimpleChallengeTask, |
| base::Unretained(this), request, result); |
| base::Closure reply = base::Bind( |
| &AttestationService::TaskRelayCallback<SignSimpleChallengeReply>, |
| GetWeakPtr(), callback, result); |
| worker_thread_->task_runner()->PostTaskAndReply(FROM_HERE, task, reply); |
| } |
| |
| void AttestationService::SignSimpleChallengeTask( |
| const SignSimpleChallengeRequest& request, |
| const std::shared_ptr<SignSimpleChallengeReply>& result) { |
| LOG(ERROR) << __func__ << ": Not implemented."; |
| result->set_status(STATUS_NOT_SUPPORTED); |
| } |
| |
| void AttestationService::SetKeyPayload( |
| const SetKeyPayloadRequest& request, |
| const SetKeyPayloadCallback& callback) { |
| auto result = std::make_shared<SetKeyPayloadReply>(); |
| base::Closure task = |
| base::Bind(&AttestationService::SetKeyPayloadTask, |
| base::Unretained(this), request, result); |
| base::Closure reply = base::Bind( |
| &AttestationService::TaskRelayCallback<SetKeyPayloadReply>, |
| GetWeakPtr(), callback, result); |
| worker_thread_->task_runner()->PostTaskAndReply(FROM_HERE, task, reply); |
| } |
| |
| void AttestationService::SetKeyPayloadTask( |
| const SetKeyPayloadRequest& request, |
| const std::shared_ptr<SetKeyPayloadReply>& result) { |
| LOG(ERROR) << __func__ << ": Not implemented."; |
| result->set_status(STATUS_NOT_SUPPORTED); |
| } |
| |
| void AttestationService::DeleteKeys( |
| const DeleteKeysRequest& request, |
| const DeleteKeysCallback& callback) { |
| auto result = std::make_shared<DeleteKeysReply>(); |
| base::Closure task = |
| base::Bind(&AttestationService::DeleteKeysTask, |
| base::Unretained(this), request, result); |
| base::Closure reply = base::Bind( |
| &AttestationService::TaskRelayCallback<DeleteKeysReply>, |
| GetWeakPtr(), callback, result); |
| worker_thread_->task_runner()->PostTaskAndReply(FROM_HERE, task, reply); |
| } |
| |
| void AttestationService::DeleteKeysTask( |
| const DeleteKeysRequest& request, |
| const std::shared_ptr<DeleteKeysReply>& result) { |
| LOG(ERROR) << __func__ << ": Not implemented."; |
| result->set_status(STATUS_NOT_SUPPORTED); |
| } |
| |
| void AttestationService::ResetIdentity( |
| const ResetIdentityRequest& request, |
| const ResetIdentityCallback& callback) { |
| auto result = std::make_shared<ResetIdentityReply>(); |
| base::Closure task = |
| base::Bind(&AttestationService::ResetIdentityTask, |
| base::Unretained(this), request, result); |
| base::Closure reply = base::Bind( |
| &AttestationService::TaskRelayCallback<ResetIdentityReply>, |
| GetWeakPtr(), callback, result); |
| worker_thread_->task_runner()->PostTaskAndReply(FROM_HERE, task, reply); |
| } |
| |
| void AttestationService::ResetIdentityTask( |
| const ResetIdentityRequest& request, |
| const std::shared_ptr<ResetIdentityReply>& result) { |
| LOG(ERROR) << __func__ << ": Not implemented."; |
| result->set_status(STATUS_NOT_SUPPORTED); |
| } |
| |
| base::WeakPtr<AttestationService> AttestationService::GetWeakPtr() { |
| return weak_factory_.GetWeakPtr(); |
| } |
| |
| } // namespace attestation |