Commit bc0839e5 authored by Maksim Ivanov's avatar Maksim Ivanov Committed by Commit Bot

Implement CryptohomeKeyDelegate D-Bus service

Create the CryptohomeKeyDelegate service that is run by Chrome.
Implement the ChallengeKey method that handles the challenge request
from cryptohomed by sending it to a certificate provider.

This is part of the "smart card based user sign-in" feature. When using
this feature, the users will authenticate not via manually entered
passwords, but instead based on the challenge-response protocol: the
actual encryption secret is handled only by cryptohomed and the TPM
chip, meanwhile Chrome only receives one-time challenges and returns
back their signatures generated by the smart card.

Bug: 826417
Change-Id: I8d52256377f29172ea631c880576bbded84bf120
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1674096
Commit-Queue: Maksim Ivanov <emaxx@chromium.org>
Reviewed-by: default avatarRyo Hashimoto <hashimoto@chromium.org>
Reviewed-by: default avatarAchuith Bhandarkar <achuith@chromium.org>
Reviewed-by: default avatarPavol Marko <pmarko@chromium.org>
Cr-Commit-Position: refs/heads/master@{#672754}
parent 222f8198
...@@ -763,6 +763,8 @@ source_set("chromeos") { ...@@ -763,6 +763,8 @@ source_set("chromeos") {
"dbus/chrome_features_service_provider.h", "dbus/chrome_features_service_provider.h",
"dbus/component_updater_service_provider.cc", "dbus/component_updater_service_provider.cc",
"dbus/component_updater_service_provider.h", "dbus/component_updater_service_provider.h",
"dbus/cryptohome_key_delegate_service_provider.cc",
"dbus/cryptohome_key_delegate_service_provider.h",
"dbus/dbus_helper.cc", "dbus/dbus_helper.cc",
"dbus/dbus_helper.h", "dbus/dbus_helper.h",
"dbus/drive_file_stream_service_provider.cc", "dbus/drive_file_stream_service_provider.cc",
......
...@@ -47,6 +47,7 @@ ...@@ -47,6 +47,7 @@
#include "chrome/browser/chromeos/boot_times_recorder.h" #include "chrome/browser/chromeos/boot_times_recorder.h"
#include "chrome/browser/chromeos/dbus/chrome_features_service_provider.h" #include "chrome/browser/chromeos/dbus/chrome_features_service_provider.h"
#include "chrome/browser/chromeos/dbus/component_updater_service_provider.h" #include "chrome/browser/chromeos/dbus/component_updater_service_provider.h"
#include "chrome/browser/chromeos/dbus/cryptohome_key_delegate_service_provider.h"
#include "chrome/browser/chromeos/dbus/dbus_helper.h" #include "chrome/browser/chromeos/dbus/dbus_helper.h"
#include "chrome/browser/chromeos/dbus/drive_file_stream_service_provider.h" #include "chrome/browser/chromeos/dbus/drive_file_stream_service_provider.h"
#include "chrome/browser/chromeos/dbus/kiosk_info_service_provider.h" #include "chrome/browser/chromeos/dbus/kiosk_info_service_provider.h"
...@@ -355,6 +356,12 @@ class DBusServices { ...@@ -355,6 +356,12 @@ class DBusServices {
CrosDBusService::CreateServiceProviderList( CrosDBusService::CreateServiceProviderList(
std::make_unique<DriveFileStreamServiceProvider>())); std::make_unique<DriveFileStreamServiceProvider>()));
cryptohome_key_delegate_service_ = CrosDBusService::Create(
system_bus, CryptohomeKeyDelegateServiceProvider::kServiceName,
dbus::ObjectPath(CryptohomeKeyDelegateServiceProvider::kServicePath),
CrosDBusService::CreateServiceProviderList(
std::make_unique<CryptohomeKeyDelegateServiceProvider>()));
if (arc::IsArcVmEnabled()) { if (arc::IsArcVmEnabled()) {
libvda_service_ = CrosDBusService::Create( libvda_service_ = CrosDBusService::Create(
system_bus, libvda::kLibvdaServiceName, system_bus, libvda::kLibvdaServiceName,
...@@ -402,6 +409,7 @@ class DBusServices { ...@@ -402,6 +409,7 @@ class DBusServices {
chrome_features_service_.reset(); chrome_features_service_.reset();
vm_applications_service_.reset(); vm_applications_service_.reset();
drive_file_stream_service_.reset(); drive_file_stream_service_.reset();
cryptohome_key_delegate_service_.reset();
ProcessDataCollector::Shutdown(); ProcessDataCollector::Shutdown();
PowerDataCollector::Shutdown(); PowerDataCollector::Shutdown();
PowerPolicyController::Shutdown(); PowerPolicyController::Shutdown();
...@@ -419,6 +427,7 @@ class DBusServices { ...@@ -419,6 +427,7 @@ class DBusServices {
std::unique_ptr<CrosDBusService> chrome_features_service_; std::unique_ptr<CrosDBusService> chrome_features_service_;
std::unique_ptr<CrosDBusService> vm_applications_service_; std::unique_ptr<CrosDBusService> vm_applications_service_;
std::unique_ptr<CrosDBusService> drive_file_stream_service_; std::unique_ptr<CrosDBusService> drive_file_stream_service_;
std::unique_ptr<CrosDBusService> cryptohome_key_delegate_service_;
std::unique_ptr<CrosDBusService> libvda_service_; std::unique_ptr<CrosDBusService> libvda_service_;
DISALLOW_COPY_AND_ASSIGN(DBusServices); DISALLOW_COPY_AND_ASSIGN(DBusServices);
......
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/chromeos/dbus/cryptohome_key_delegate_service_provider.h"
#include <cstdint>
#include <memory>
#include <string>
#include <vector>
#include "base/bind.h"
#include "base/logging.h"
#include "base/stl_util.h"
#include "chrome/browser/chromeos/certificate_provider/certificate_provider_service.h"
#include "chrome/browser/chromeos/certificate_provider/certificate_provider_service_factory.h"
#include "chrome/browser/chromeos/profiles/profile_helper.h"
#include "chrome/browser/profiles/profile.h"
#include "chromeos/dbus/cryptohome/key.pb.h"
#include "chromeos/dbus/cryptohome/rpc.pb.h"
#include "dbus/message.h"
#include "net/base/net_errors.h"
#include "third_party/boringssl/src/include/openssl/digest.h"
#include "third_party/boringssl/src/include/openssl/ssl.h"
#include "third_party/cros_system_api/dbus/cryptohome/dbus-constants.h"
namespace chromeos {
const char CryptohomeKeyDelegateServiceProvider::kServiceName[] =
"org.chromium.CryptohomeKeyDelegate";
const char CryptohomeKeyDelegateServiceProvider::kServicePath[] =
"/org/chromium/CryptohomeKeyDelegate";
namespace {
// Converts the cryptohome challenge algorithm enum into the TLS 1.3
// SignatureScheme.
bool ChallengeSignatureAlgorithmToSslAlgorithm(
cryptohome::ChallengeSignatureAlgorithm challenge_algorithm,
uint16_t* ssl_algorithm) {
switch (challenge_algorithm) {
case cryptohome::CHALLENGE_RSASSA_PKCS1_V1_5_SHA1:
*ssl_algorithm = SSL_SIGN_RSA_PKCS1_SHA1;
return true;
case cryptohome::CHALLENGE_RSASSA_PKCS1_V1_5_SHA256:
*ssl_algorithm = SSL_SIGN_RSA_PKCS1_SHA256;
return true;
case cryptohome::CHALLENGE_RSASSA_PKCS1_V1_5_SHA384:
*ssl_algorithm = SSL_SIGN_RSA_PKCS1_SHA384;
return true;
case cryptohome::CHALLENGE_RSASSA_PKCS1_V1_5_SHA512:
*ssl_algorithm = SSL_SIGN_RSA_PKCS1_SHA512;
return true;
default:
LOG(ERROR) << "Unknown cryptohome key challenge algorithm: "
<< challenge_algorithm;
return false;
}
}
// Builds the digest of the given input, using the hashing algorithm that is
// required for the given signature algorithm.
bool BuildDigestToSign(const std::string& input,
uint16_t ssl_algorithm,
std::vector<uint8_t>* digest) {
DCHECK(!input.empty());
const EVP_MD* md = SSL_get_signature_algorithm_digest(ssl_algorithm);
if (!md)
return false;
digest->resize(EVP_MAX_MD_SIZE);
unsigned digest_len = 0;
if (!EVP_Digest(input.data(), input.size(), digest->data(), &digest_len, md,
nullptr)) {
digest->clear();
return false;
}
digest->resize(digest_len);
return true;
}
// Completes the "ChallengeKey" D-Bus call of the |CHALLENGE_TYPE_SIGNATURE|
// type with the given signature, or with an error if the signature wasn't
// successfully generated.
void CompleteSignatureKeyChallenge(
dbus::MethodCall* method_call,
dbus::ExportedObject::ResponseSender response_sender,
net::Error error,
const std::vector<uint8_t>& signature) {
if (error != net::OK || signature.empty()) {
response_sender.Run(dbus::ErrorResponse::FromMethodCall(
method_call, DBUS_ERROR_FAILED, "Failed to generate the signature"));
return;
}
cryptohome::KeyChallengeResponse challenge_response;
challenge_response.mutable_signature_response_data()->set_signature(
signature.data(), signature.size());
std::unique_ptr<dbus::Response> response =
dbus::Response::FromMethodCall(method_call);
dbus::MessageWriter writer(response.get());
writer.AppendProtoAsArrayOfBytes(challenge_response);
response_sender.Run(std::move(response));
}
// Handles the "ChallengeKey" D-Bus call for the request of the
// |CHALLENGE_TYPE_SIGNATURE| type.
void HandleSignatureKeyChallenge(
dbus::MethodCall* method_call,
const cryptohome::SignatureKeyChallengeRequestData& challenge_request_data,
dbus::ExportedObject::ResponseSender response_sender) {
if (challenge_request_data.data_to_sign().empty()) {
response_sender.Run(dbus::ErrorResponse::FromMethodCall(
method_call, DBUS_ERROR_INVALID_ARGS, "Missing data to sign"));
return;
}
if (challenge_request_data.public_key_spki_der().empty()) {
response_sender.Run(dbus::ErrorResponse::FromMethodCall(
method_call, DBUS_ERROR_INVALID_ARGS, "Missing public key"));
return;
}
if (!challenge_request_data.has_signature_algorithm()) {
response_sender.Run(dbus::ErrorResponse::FromMethodCall(
method_call, DBUS_ERROR_INVALID_ARGS, "Missing signature algorithm"));
return;
}
uint16_t ssl_algorithm = 0;
if (!ChallengeSignatureAlgorithmToSslAlgorithm(
challenge_request_data.signature_algorithm(), &ssl_algorithm)) {
response_sender.Run(dbus::ErrorResponse::FromMethodCall(
method_call, DBUS_ERROR_FAILED, "Unknown signature algorithm"));
return;
}
// Handle the challenge request by delivering it to one of the sign-in
// certificateProvider subscribers (e.g., smart card middleware extensions).
// The sign-in profile is used since it's where the needed extensions are
// installed (e.g., for the smart card based login they are force-installed
// via the DeviceLoginScreenExtensions admin policy).
Profile* signin_profile = ProfileHelper::GetSigninProfile();
CertificateProviderService* certificate_provider_service =
CertificateProviderServiceFactory::GetForBrowserContext(signin_profile);
if (!certificate_provider_service) {
response_sender.Run(dbus::ErrorResponse::FromMethodCall(
method_call, DBUS_ERROR_FAILED,
"Missing certificate provider service"));
return;
}
std::vector<uint16_t> supported_ssl_algorithms;
if (!certificate_provider_service->GetSupportedAlgorithmsBySpki(
challenge_request_data.public_key_spki_der(),
&supported_ssl_algorithms)) {
response_sender.Run(dbus::ErrorResponse::FromMethodCall(
method_call, DBUS_ERROR_FAILED, "Key is unavailable"));
return;
}
if (!base::Contains(supported_ssl_algorithms, ssl_algorithm)) {
response_sender.Run(dbus::ErrorResponse::FromMethodCall(
method_call, DBUS_ERROR_FAILED, "Unsupported algorithm"));
return;
}
std::vector<uint8_t> digest;
if (!BuildDigestToSign(challenge_request_data.data_to_sign(), ssl_algorithm,
&digest)) {
response_sender.Run(dbus::ErrorResponse::FromMethodCall(
method_call, DBUS_ERROR_FAILED, "Failed to build digest"));
return;
}
certificate_provider_service->RequestSignatureBySpki(
challenge_request_data.public_key_spki_der(), ssl_algorithm, digest,
base::BindOnce(&CompleteSignatureKeyChallenge,
base::Unretained(method_call), response_sender));
}
} // namespace
CryptohomeKeyDelegateServiceProvider::CryptohomeKeyDelegateServiceProvider() =
default;
CryptohomeKeyDelegateServiceProvider::~CryptohomeKeyDelegateServiceProvider() =
default;
void CryptohomeKeyDelegateServiceProvider::Start(
scoped_refptr<dbus::ExportedObject> exported_object) {
exported_object->ExportMethod(
cryptohome::kCryptohomeKeyDelegateInterface,
cryptohome::kCryptohomeKeyDelegateChallengeKey,
base::BindRepeating(
&CryptohomeKeyDelegateServiceProvider::HandleChallengeKey,
weak_ptr_factory_.GetWeakPtr()),
base::BindRepeating([](const std::string& interface_name,
const std::string& method_name, bool success) {
LOG_IF(ERROR, !success)
<< "Failed to export " << interface_name << "." << method_name;
}));
}
void CryptohomeKeyDelegateServiceProvider::HandleChallengeKey(
dbus::MethodCall* method_call,
dbus::ExportedObject::ResponseSender response_sender) {
dbus::MessageReader reader(method_call);
cryptohome::AccountIdentifier account_identifier;
if (!reader.PopArrayOfBytesAsProto(&account_identifier)) {
response_sender.Run(dbus::ErrorResponse::FromMethodCall(
method_call, DBUS_ERROR_INVALID_ARGS,
"Unable to parse AccountIdentifier from request"));
return;
}
// For now |account_identifier| is not used.
cryptohome::KeyChallengeRequest request;
if (!reader.PopArrayOfBytesAsProto(&request)) {
response_sender.Run(dbus::ErrorResponse::FromMethodCall(
method_call, DBUS_ERROR_INVALID_ARGS,
"Unable to parse KeyChallengeRequest from request"));
return;
}
if (!request.has_challenge_type()) {
response_sender.Run(dbus::ErrorResponse::FromMethodCall(
method_call, DBUS_ERROR_INVALID_ARGS, "Missing challenge type"));
return;
}
if (request.challenge_type() ==
cryptohome::KeyChallengeRequest::CHALLENGE_TYPE_SIGNATURE) {
if (!request.has_signature_request_data()) {
response_sender.Run(dbus::ErrorResponse::FromMethodCall(
method_call, DBUS_ERROR_INVALID_ARGS,
"Missing signature request data"));
return;
}
HandleSignatureKeyChallenge(method_call, request.signature_request_data(),
response_sender);
return;
}
response_sender.Run(dbus::ErrorResponse::FromMethodCall(
method_call, DBUS_ERROR_FAILED, "Unknown challenge type"));
}
} // namespace chromeos
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_CHROMEOS_DBUS_CRYPTOHOME_KEY_DELEGATE_SERVICE_PROVIDER_H_
#define CHROME_BROWSER_CHROMEOS_DBUS_CRYPTOHOME_KEY_DELEGATE_SERVICE_PROVIDER_H_
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "chromeos/dbus/services/cros_dbus_service.h"
#include "dbus/exported_object.h"
namespace dbus {
class MethodCall;
}
namespace chromeos {
// Provider for the org.chromium.CryptohomeKeyDelegateInterface service
// implementation.
//
// This service is called by the cryptohomed daemon for operations related to
// user protection keys. See the interface definition in the Chrome OS repo in
// src/platform2/cryptohome/dbus_bindings/
// org.chromium.CryptohomeKeyDelegateInterface.xml .
class CryptohomeKeyDelegateServiceProvider final
: public CrosDBusService::ServiceProviderInterface {
public:
// Name of the provided D-Bus service.
static const char kServiceName[];
// Path of the provided D-Bus service.
static const char kServicePath[];
CryptohomeKeyDelegateServiceProvider();
~CryptohomeKeyDelegateServiceProvider() override;
// CrosDBusService::ServiceProviderInterface overrides:
void Start(scoped_refptr<dbus::ExportedObject> exported_object) override;
private:
// Implements the "ChallengeKey" D-Bus method.
void HandleChallengeKey(dbus::MethodCall* method_call,
dbus::ExportedObject::ResponseSender response_sender);
// Must be the last member.
base::WeakPtrFactory<CryptohomeKeyDelegateServiceProvider> weak_ptr_factory_{
this};
DISALLOW_COPY_AND_ASSIGN(CryptohomeKeyDelegateServiceProvider);
};
} // namespace chromeos
#endif // CHROME_BROWSER_CHROMEOS_DBUS_CRYPTOHOME_KEY_DELEGATE_SERVICE_PROVIDER_H_
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment