Commit fab5ba9e authored by Josh Nohle's avatar Josh Nohle Committed by Commit Bot

Revert "Use existing kUserKeyPair keys during key creation, if possible."

This reverts commit 657a8c53.

Reason for revert: ASAN errors; container overflow

Original change's description:
> Use existing kUserKeyPair keys during key creation, if possible.
> 
> In CyptAuth v2 Enrollment, the user key pair--also known as
> CryptAuthKeyBundle::Name::kUserKeyPair or "PublicKey"--has special
> standing in order to 1) accommodate any existing key from v1 Enrollment
> and 2) enforce that the key is not rotated. Only one user key pair
> should exist in its key bundle, and it should be an active, P-256 key
> with handle "device_key".
> 
> It is possible that CryptAuth could request the creation of a new user
> key pair even if the client sends information about an existing key in
> the SyncKeysRequest. If this happens, the client should re-use the
> existing user key pair key material when creating a new key. At the end
> of the enrollment flow, the existing key will be replaced with this new
> key that has the same public/private keys, but possibly with a new key
> directive.
> 
> It might seem more efficient to simply ignore the key-creation request,
> but the method outlined above natually fits into the enrollment flow,
> the key directive will be updated, and the client will be able to
> provide CryptAuth with an EnrollKeys request, which it might be
> expected.
> 
> Bug: 899080
> Change-Id: I3a4a63aa902090698ecb619bc7af78ff1e790c23
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1504121
> Commit-Queue: Josh Nohle <nohle@chromium.org>
> Reviewed-by: Kyle Horimoto <khorimoto@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#638327}

TBR=khorimoto@chromium.org,nohle@chromium.org

Change-Id: Ida02d62899eecc6a391e05b34bf576ff12e9541f
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: 899080
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1507279
Commit-Queue: Josh Nohle <nohle@chromium.org>
Reviewed-by: default avatarJames Hawkins <jhawkins@chromium.org>
Cr-Commit-Position: refs/heads/master@{#638393}
parent c99f13fc
...@@ -116,11 +116,7 @@ std::ostream& operator<<( ...@@ -116,11 +116,7 @@ std::ostream& operator<<(
stream << "[Error: KeyActions do not specify an active key]"; stream << "[Error: KeyActions do not specify an active key]";
break; break;
case ResultCode::kErrorKeyCreationKeyTypeNotSupported: case ResultCode::kErrorKeyCreationKeyTypeNotSupported:
stream << "[Error: Key-creation instructions specify unsupported " stream << "[Error: KeyCreation instructions specify unsupported KeyType]";
<< "KeyType]";
break;
case ResultCode::kErrorUserKeyPairCreationInstructionsInvalid:
stream << "[Error: Key-creation instructions for user key pair invalid]";
break; break;
case ResultCode::kErrorSymmetricKeyCreationMissingServerDiffieHellman: case ResultCode::kErrorSymmetricKeyCreationMissingServerDiffieHellman:
stream << "[Error: Cannot create symmetric key; missing server " stream << "[Error: Cannot create symmetric key; missing server "
......
...@@ -79,9 +79,6 @@ class CryptAuthEnrollmentResult { ...@@ -79,9 +79,6 @@ class CryptAuthEnrollmentResult {
kErrorKeyActionsDoNotSpecifyAnActiveKey, kErrorKeyActionsDoNotSpecifyAnActiveKey,
// KeyCreation instructions specify an unsupported KeyType. // KeyCreation instructions specify an unsupported KeyType.
kErrorKeyCreationKeyTypeNotSupported, kErrorKeyCreationKeyTypeNotSupported,
// Invalid key-creation instructions for user key pair. It must be P256 and
// active.
kErrorUserKeyPairCreationInstructionsInvalid,
// Cannot create a symmetric key without the server's Diffie-Hellman key. // Cannot create a symmetric key without the server's Diffie-Hellman key.
kErrorSymmetricKeyCreationMissingServerDiffieHellman, kErrorSymmetricKeyCreationMissingServerDiffieHellman,
// Failed to compute at least one key proof. // Failed to compute at least one key proof.
......
...@@ -14,22 +14,6 @@ CryptAuthKeyCreator::CreateKeyData::CreateKeyData( ...@@ -14,22 +14,6 @@ CryptAuthKeyCreator::CreateKeyData::CreateKeyData(
base::Optional<std::string> handle) base::Optional<std::string> handle)
: status(status), type(type), handle(handle) {} : status(status), type(type), handle(handle) {}
CryptAuthKeyCreator::CreateKeyData::CreateKeyData(
CryptAuthKey::Status status,
cryptauthv2::KeyType type,
const std::string& handle,
const std::string& public_key,
const std::string& private_key)
: status(status),
type(type),
handle(handle),
public_key(public_key),
private_key(private_key) {
DCHECK(!handle.empty());
DCHECK(!public_key.empty());
DCHECK(!private_key.empty());
}
CryptAuthKeyCreator::CreateKeyData::~CreateKeyData() = default; CryptAuthKeyCreator::CreateKeyData::~CreateKeyData() = default;
CryptAuthKeyCreator::CreateKeyData::CreateKeyData(const CreateKeyData&) = CryptAuthKeyCreator::CreateKeyData::CreateKeyData(const CreateKeyData&) =
......
...@@ -49,27 +49,12 @@ class CryptAuthKeyCreator { ...@@ -49,27 +49,12 @@ class CryptAuthKeyCreator {
CreateKeyData(CryptAuthKey::Status status, CreateKeyData(CryptAuthKey::Status status,
cryptauthv2::KeyType type, cryptauthv2::KeyType type,
base::Optional<std::string> handle = base::nullopt); base::Optional<std::string> handle = base::nullopt);
// Special constructor needed to handle existing user key pair. The input
// strings cannot be empty.
CreateKeyData(CryptAuthKey::Status status,
cryptauthv2::KeyType type,
const std::string& handle,
const std::string& public_key,
const std::string& private_key);
~CreateKeyData(); ~CreateKeyData();
CreateKeyData(const CreateKeyData&); CreateKeyData(const CreateKeyData&);
CryptAuthKey::Status status; CryptAuthKey::Status status;
cryptauthv2::KeyType type; cryptauthv2::KeyType type;
base::Optional<std::string> handle; base::Optional<std::string> handle;
// Special data needed to handle existing user key pair. If these are both
// non-empty strings and the key type is asymmetric, then the key creator
// will bypass the standard key creation and simply return
// CryptAuthKey(|public_key|, |private_key|, |status|, |type|, |handle|).
base::Optional<std::string> public_key;
base::Optional<std::string> private_key;
}; };
CryptAuthKeyCreator(); CryptAuthKeyCreator();
......
...@@ -4,13 +4,21 @@ ...@@ -4,13 +4,21 @@
#include "chromeos/services/device_sync/cryptauth_key_creator_impl.h" #include "chromeos/services/device_sync/cryptauth_key_creator_impl.h"
#include <memory>
#include <string>
#include <utility>
#include "base/base64.h" #include "base/base64.h"
#include "base/bind.h" #include "base/bind.h"
#include "base/containers/flat_map.h"
#include "base/memory/ptr_util.h" #include "base/memory/ptr_util.h"
#include "base/no_destructor.h" #include "base/no_destructor.h"
#include "base/optional.h"
#include "base/strings/string_util.h" #include "base/strings/string_util.h"
#include "chromeos/components/multidevice/logging/logging.h"
#include "chromeos/components/multidevice/secure_message_delegate_impl.h" #include "chromeos/components/multidevice/secure_message_delegate_impl.h"
#include "chromeos/services/device_sync/cryptauth_constants.h" #include "chromeos/services/device_sync/cryptauth_constants.h"
#include "chromeos/services/device_sync/cryptauth_key.h"
#include "chromeos/services/device_sync/proto/cryptauth_common.pb.h" #include "chromeos/services/device_sync/proto/cryptauth_common.pb.h"
#include "crypto/hkdf.h" #include "crypto/hkdf.h"
#include "crypto/random.h" #include "crypto/random.h"
...@@ -157,42 +165,30 @@ void CryptAuthKeyCreatorImpl::OnDiffieHellmanHandshakeSecretDerived( ...@@ -157,42 +165,30 @@ void CryptAuthKeyCreatorImpl::OnDiffieHellmanHandshakeSecretDerived(
void CryptAuthKeyCreatorImpl::StartKeyCreation() { void CryptAuthKeyCreatorImpl::StartKeyCreation() {
for (const auto& key_to_create : keys_to_create_) { for (const auto& key_to_create : keys_to_create_) {
const CryptAuthKeyBundle::Name& bundle_name = key_to_create.first;
const CreateKeyData& key_data = key_to_create.second;
// If the key to create is symmetric, derive a symmetric key from the // If the key to create is symmetric, derive a symmetric key from the
// Diffie-Hellman handshake secrect using HKDF. The CryptAuth v2 // Diffie-Hellman handshake secrect using HKDF. The CryptAuth v2
// Enrollment protocol specifies that the salt should be "CryptAuth // Enrollment protocol specifies that the salt should be "CryptAuth
// Enrollment" and the info should be the key handle. This process is // Enrollment" and the info should be the key handle. This process is
// synchronous, unlike SecureMessageDelegate calls. // synchronous, unlike SecureMessageDelegate calls.
if (IsValidSymmetricKeyType(key_data.type)) { if (IsValidSymmetricKeyType(key_to_create.second.type)) {
std::string handle = std::string handle = key_to_create.second.handle.has_value()
key_data.handle ? *key_data.handle : CreateRandomHandle(); ? *key_to_create.second.handle
std::string derived_symmetric_key_material = : CreateRandomHandle();
crypto::HkdfSha256(dh_handshake_secret_->symmetric_key(), std::string derived_symmetric_key_material = crypto::HkdfSha256(
dh_handshake_secret_->symmetric_key(),
kCryptAuthSymmetricKeyDerivationSalt, handle, kCryptAuthSymmetricKeyDerivationSalt, handle,
NumBytesForSymmetricKeyType(key_data.type)); NumBytesForSymmetricKeyType(key_to_create.second.type));
OnSymmetricKeyDerived(bundle_name, derived_symmetric_key_material, OnSymmetricKeyDerived(key_to_create.first, derived_symmetric_key_material,
handle); handle);
} else {
continue; DCHECK(IsValidAsymmetricKeyType(key_to_create.second.type));
}
DCHECK(IsValidAsymmetricKeyType(key_data.type));
// If the key material was explicitly set in CreateKeyData, bypass the
// standard key creation.
if (key_data.public_key && key_data.private_key) {
OnAsymmetricKeyPairGenerated(bundle_name, *key_data.public_key,
*key_data.private_key);
continue;
}
secure_message_delegate_->GenerateKeyPair( secure_message_delegate_->GenerateKeyPair(
base::Bind(&CryptAuthKeyCreatorImpl::OnAsymmetricKeyPairGenerated, base::Bind(&CryptAuthKeyCreatorImpl::OnAsymmetricKeyPairGenerated,
base::Unretained(this), key_to_create.first)); base::Unretained(this), key_to_create.first));
} }
}
} }
void CryptAuthKeyCreatorImpl::OnAsymmetricKeyPairGenerated( void CryptAuthKeyCreatorImpl::OnAsymmetricKeyPairGenerated(
......
...@@ -5,6 +5,8 @@ ...@@ -5,6 +5,8 @@
#ifndef CHROMEOS_SERVICES_DEVICE_SYNC_CRYPTAUTH_KEY_CREATOR_IMPL_H_ #ifndef CHROMEOS_SERVICES_DEVICE_SYNC_CRYPTAUTH_KEY_CREATOR_IMPL_H_
#define CHROMEOS_SERVICES_DEVICE_SYNC_CRYPTAUTH_KEY_CREATOR_IMPL_H_ #define CHROMEOS_SERVICES_DEVICE_SYNC_CRYPTAUTH_KEY_CREATOR_IMPL_H_
#include "chromeos/services/device_sync/cryptauth_key_creator.h"
#include <memory> #include <memory>
#include <string> #include <string>
#include <utility> #include <utility>
...@@ -16,7 +18,6 @@ ...@@ -16,7 +18,6 @@
#include "base/optional.h" #include "base/optional.h"
#include "chromeos/services/device_sync/cryptauth_key.h" #include "chromeos/services/device_sync/cryptauth_key.h"
#include "chromeos/services/device_sync/cryptauth_key_bundle.h" #include "chromeos/services/device_sync/cryptauth_key_bundle.h"
#include "chromeos/services/device_sync/cryptauth_key_creator.h"
namespace chromeos { namespace chromeos {
......
...@@ -254,59 +254,48 @@ bool IsSupportedKeyType(const cryptauthv2::KeyType& key_type) { ...@@ -254,59 +254,48 @@ bool IsSupportedKeyType(const cryptauthv2::KeyType& key_type) {
key_type == cryptauthv2::KeyType::P256; key_type == cryptauthv2::KeyType::P256;
} }
// The key bundle kUserKeyPair has special standing in order to 1) accommodate
// any existing key from v1 Enrollment and 2) enforce that the key is not
// rotated. As such, only one user key pair should exist in the key bundle, and
// it should be an active, P-256 key with handle
// kCryptAuthFixedUserKeyPairHandle.
//
// It is possible that CryptAuth could request the creation of a new user key
// pair even if the client sends information about an existing key in the
// SyncKeysRequest. If this happens, the client should re-use the existing user
// key pair key material when creating a new key. At the end of the enrollment
// flow, the existing key will be replaced with this new key that has the same
// public/private keys.
//
// Returns an error code if the key-creation instructions are invalid and null // Returns an error code if the key-creation instructions are invalid and null
// otherwise. // otherwise.
base::Optional<CryptAuthEnrollmentResult::ResultCode> base::Optional<CryptAuthEnrollmentResult::ResultCode>
ProcessNewUserKeyPairInstructions( ProcessKeyCreationInstructions(
CryptAuthKey::Status status, const CryptAuthKeyBundle::Name& bundle_name,
cryptauthv2::KeyType type, const SyncSingleKeyResponse& single_key_response,
const CryptAuthKey* current_active_key, const std::string& server_ephemeral_dh,
base::Optional<CryptAuthKeyCreator::CreateKeyData>* new_key_to_create) { base::Optional<CryptAuthKeyCreator::CreateKeyData>* new_key_to_create,
if (type != cryptauthv2::KeyType::P256) { base::Optional<cryptauthv2::KeyDirective>* new_key_directive) {
PA_LOG(ERROR) << "User key pair must have KeyType P256."; if (single_key_response.key_creation() == SyncSingleKeyResponse::NONE)
return base::nullopt;
if (!IsSupportedKeyType(single_key_response.key_type())) {
PA_LOG(ERROR) << "KeyType " << single_key_response.key_type() << " "
<< "not supported.";
return CryptAuthEnrollmentResult::ResultCode:: return CryptAuthEnrollmentResult::ResultCode::
kErrorUserKeyPairCreationInstructionsInvalid; kErrorKeyCreationKeyTypeNotSupported;
} }
// Because no more than one user key pair can exist in the bundle, the newly // Symmetric keys cannot be created without the server's Diffie-Hellman key.
// created key must be active. if (server_ephemeral_dh.empty() &&
if (status != CryptAuthKey::Status::kActive) { (single_key_response.key_type() == cryptauthv2::KeyType::RAW128 ||
PA_LOG(ERROR) << "New user key pair must be active."; single_key_response.key_type() == cryptauthv2::KeyType::RAW256)) {
PA_LOG(ERROR)
<< "Missing server's Diffie-Hellman key. Cannot create symmetric keys.";
return CryptAuthEnrollmentResult::ResultCode:: return CryptAuthEnrollmentResult::ResultCode::
kErrorUserKeyPairCreationInstructionsInvalid; kErrorSymmetricKeyCreationMissingServerDiffieHellman;
} }
// If a user key pair already exists in the registry, reuse the same key data. // CryptAuth demands that the key in the kUserKeyPair bundle has a fixed
if (current_active_key && current_active_key->IsAsymmetricKey() && // handle name. For other key bundles, do not specify a handle name; let
!current_active_key->private_key().empty()) { // CryptAuthKey generate a handle for us.
PA_LOG(WARNING) << "Received request to create new user key pair while one " base::Optional<std::string> new_key_handle;
<< "already exists in the key registry. Reusing existing " if (bundle_name == CryptAuthKeyBundle::Name::kUserKeyPair)
<< "key material."; new_key_handle = kCryptAuthFixedUserKeyPairHandle;
*new_key_to_create = CryptAuthKeyCreator::CreateKeyData( *new_key_to_create = CryptAuthKeyCreator::CreateKeyData(
status, type, kCryptAuthFixedUserKeyPairHandle, ConvertKeyCreationToKeyStatus(single_key_response.key_creation()),
current_active_key->public_key(), current_active_key->private_key()); single_key_response.key_type(), new_key_handle);
return base::nullopt; if (single_key_response.has_key_directive())
} *new_key_directive = single_key_response.key_directive();
// If there is no user key pair in the registry, then the user has never
// successfully enrolled via v1 or v2 Enrollment. Generate a new key pair.
*new_key_to_create = CryptAuthKeyCreator::CreateKeyData(
status, type, kCryptAuthFixedUserKeyPairHandle);
return base::nullopt; return base::nullopt;
} }
...@@ -631,51 +620,6 @@ CryptAuthV2EnrollerImpl::ProcessSingleKeyResponses( ...@@ -631,51 +620,6 @@ CryptAuthV2EnrollerImpl::ProcessSingleKeyResponses(
return error_code; return error_code;
} }
base::Optional<CryptAuthEnrollmentResult::ResultCode>
CryptAuthV2EnrollerImpl::ProcessKeyCreationInstructions(
const CryptAuthKeyBundle::Name& bundle_name,
const SyncSingleKeyResponse& single_key_response,
const std::string& server_ephemeral_dh,
base::Optional<CryptAuthKeyCreator::CreateKeyData>* new_key_to_create,
base::Optional<cryptauthv2::KeyDirective>* new_key_directive) {
if (single_key_response.key_creation() == SyncSingleKeyResponse::NONE)
return base::nullopt;
CryptAuthKey::Status status =
ConvertKeyCreationToKeyStatus(single_key_response.key_creation());
cryptauthv2::KeyType type = single_key_response.key_type();
if (!IsSupportedKeyType(type)) {
PA_LOG(ERROR) << "KeyType " << type << " not supported.";
return CryptAuthEnrollmentResult::ResultCode::
kErrorKeyCreationKeyTypeNotSupported;
}
// Symmetric keys cannot be created without the server's Diffie-Hellman key.
if (server_ephemeral_dh.empty() && (type == cryptauthv2::KeyType::RAW128 ||
type == cryptauthv2::KeyType::RAW256)) {
PA_LOG(ERROR)
<< "Missing server's Diffie-Hellman key. Cannot create symmetric keys.";
return CryptAuthEnrollmentResult::ResultCode::
kErrorSymmetricKeyCreationMissingServerDiffieHellman;
}
if (single_key_response.has_key_directive())
*new_key_directive = single_key_response.key_directive();
// Handle the user key pair special case separately below.
if (bundle_name != CryptAuthKeyBundle::Name::kUserKeyPair) {
*new_key_to_create = CryptAuthKeyCreator::CreateKeyData(status, type);
return base::nullopt;
}
DCHECK(bundle_name == CryptAuthKeyBundle::Name::kUserKeyPair);
return ProcessNewUserKeyPairInstructions(
status, type, key_registry_->GetActiveKey(bundle_name),
new_key_to_create);
}
void CryptAuthV2EnrollerImpl::OnSyncKeysFailure(NetworkRequestError error) { void CryptAuthV2EnrollerImpl::OnSyncKeysFailure(NetworkRequestError error) {
FinishAttempt(SyncKeysNetworkRequestErrorToResultCode(error)); FinishAttempt(SyncKeysNetworkRequestErrorToResultCode(error));
} }
......
...@@ -120,17 +120,6 @@ class CryptAuthV2EnrollerImpl : public CryptAuthV2Enroller { ...@@ -120,17 +120,6 @@ class CryptAuthV2EnrollerImpl : public CryptAuthV2Enroller {
base::flat_map<CryptAuthKeyBundle::Name, cryptauthv2::KeyDirective>* base::flat_map<CryptAuthKeyBundle::Name, cryptauthv2::KeyDirective>*
new_key_directives); new_key_directives);
// A function to help ProcessSingleKeyResponse() handle the key-creation
// instructions.
base::Optional<CryptAuthEnrollmentResult::ResultCode>
ProcessKeyCreationInstructions(
const CryptAuthKeyBundle::Name& bundle_name,
const cryptauthv2::SyncKeysResponse::SyncSingleKeyResponse&
single_key_response,
const std::string& server_ephemeral_dh,
base::Optional<CryptAuthKeyCreator::CreateKeyData>* new_key_to_create,
base::Optional<cryptauthv2::KeyDirective>* new_key_directive);
void OnSyncKeysFailure(NetworkRequestError error); void OnSyncKeysFailure(NetworkRequestError error);
void OnKeysCreated( void OnKeysCreated(
......
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