Roll src/third_party/skia 99c7c07:4af6580
[chromium-blink-merge.git] / components / proximity_auth / cryptauth / cryptauth_enroller_impl.cc
blob729648dbbf7ebb6a3ac7d7861aa9120d8088cf50
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "components/proximity_auth/cryptauth/cryptauth_enroller_impl.h"
7 #include "base/bind.h"
8 #include "components/proximity_auth/cryptauth/cryptauth_client.h"
9 #include "components/proximity_auth/cryptauth/cryptauth_enrollment_utils.h"
10 #include "components/proximity_auth/cryptauth/secure_message_delegate.h"
12 namespace proximity_auth {
14 namespace {
16 // A successful SetupEnrollment or FinishEnrollment response should contain this
17 // status string.
18 const char kResponseStatusOk[] = "OK";
20 // The name of the "gcmV1" protocol that the enrolling device supports.
21 const char kSupportedEnrollmentTypeGcmV1[] = "gcmV1";
23 // The version field of the GcmMetadata message.
24 const int kGCMMetadataVersion = 1;
26 // Returns true if |device_info| contains the required fields for enrollment.
27 bool ValidateDeviceInfo(const cryptauth::GcmDeviceInfo& device_info) {
28 if (!device_info.has_user_public_key()) {
29 VLOG(1) << "Expected user_public_key field in GcmDeviceInfo.";
30 return false;
33 if (!device_info.has_key_handle()) {
34 VLOG(1) << "Expected key_handle field in GcmDeviceInfo.";
35 return false;
38 if (!device_info.has_long_device_id()) {
39 VLOG(1) << "Expected long_device_id field in GcmDeviceInfo.";
40 return false;
43 if (!device_info.has_device_type()) {
44 VLOG(1) << "Expected device_type field in GcmDeviceInfo.";
45 return false;
48 return true;
51 // Creates the public metadata to put in the SecureMessage that is sent to the
52 // server with the FinishEnrollment request.
53 std::string CreateEnrollmentPublicMetadata() {
54 cryptauth::GcmMetadata metadata;
55 metadata.set_version(kGCMMetadataVersion);
56 metadata.set_type(cryptauth::MessageType::ENROLLMENT);
57 return metadata.SerializeAsString();
60 } // namespace
62 CryptAuthEnrollerImpl::CryptAuthEnrollerImpl(
63 scoped_ptr<CryptAuthClientFactory> client_factory,
64 scoped_ptr<SecureMessageDelegate> secure_message_delegate_)
65 : client_factory_(client_factory.Pass()),
66 secure_message_delegate_(secure_message_delegate_.Pass()),
67 weak_ptr_factory_(this) {
70 CryptAuthEnrollerImpl::~CryptAuthEnrollerImpl() {
73 void CryptAuthEnrollerImpl::Enroll(
74 const cryptauth::GcmDeviceInfo& device_info,
75 cryptauth::InvocationReason invocation_reason,
76 const EnrollmentFinishedCallback& callback) {
77 if (!callback_.is_null()) {
78 VLOG(1) << "Enroll() already called. Do not reuse.";
79 callback.Run(false);
80 return;
83 device_info_ = device_info;
84 invocation_reason_ = invocation_reason;
85 callback_ = callback;
87 if (!ValidateDeviceInfo(device_info)) {
88 callback.Run(false);
89 return;
92 secure_message_delegate_->GenerateKeyPair(
93 base::Bind(&CryptAuthEnrollerImpl::OnKeyPairGenerated,
94 weak_ptr_factory_.GetWeakPtr()));
97 void CryptAuthEnrollerImpl::OnKeyPairGenerated(const std::string& public_key,
98 const std::string& private_key) {
99 session_public_key_ = public_key;
100 session_private_key_ = private_key;
102 cryptauth_client_ = client_factory_->CreateInstance();
103 cryptauth::SetupEnrollmentRequest request;
104 request.add_types(kSupportedEnrollmentTypeGcmV1);
105 request.set_invocation_reason(invocation_reason_);
106 cryptauth_client_->SetupEnrollment(
107 request, base::Bind(&CryptAuthEnrollerImpl::OnSetupEnrollmentSuccess,
108 weak_ptr_factory_.GetWeakPtr()),
109 base::Bind(&CryptAuthEnrollerImpl::OnSetupEnrollmentFailure,
110 weak_ptr_factory_.GetWeakPtr()));
113 void CryptAuthEnrollerImpl::OnSetupEnrollmentSuccess(
114 const cryptauth::SetupEnrollmentResponse& response) {
115 if (response.status() != kResponseStatusOk) {
116 VLOG(1) << "Unexpected status for SetupEnrollment: " << response.status();
117 callback_.Run(false);
118 return;
121 if (response.infos_size() == 0) {
122 VLOG(1) << "No response info returned by server for SetupEnrollment";
123 callback_.Run(false);
124 return;
127 setup_info_ = response.infos(0);
128 device_info_.set_enrollment_session_id(setup_info_.enrollment_session_id());
129 secure_message_delegate_->DeriveKey(
130 session_private_key_, setup_info_.server_ephemeral_key(),
131 base::Bind(&CryptAuthEnrollerImpl::OnKeyDerived,
132 weak_ptr_factory_.GetWeakPtr()));
135 void CryptAuthEnrollerImpl::OnSetupEnrollmentFailure(const std::string& error) {
136 VLOG(1) << "SetupEnrollment API failed with error: " << error;
137 callback_.Run(false);
140 void CryptAuthEnrollerImpl::OnKeyDerived(const std::string& symmetric_key) {
141 symmetric_key_ = symmetric_key;
142 SecureMessageDelegate::CreateOptions options;
143 options.encryption_scheme = securemessage::NONE;
144 options.signature_scheme = securemessage::ECDSA_P256_SHA256;
145 options.verification_key_id = session_public_key_;
147 // The inner message contains the signed device information that will be
148 // sent to CryptAuth.
149 secure_message_delegate_->CreateSecureMessage(
150 device_info_.SerializeAsString(), session_private_key_, options,
151 base::Bind(&CryptAuthEnrollerImpl::OnInnerSecureMessageCreated,
152 weak_ptr_factory_.GetWeakPtr()));
155 void CryptAuthEnrollerImpl::OnInnerSecureMessageCreated(
156 const std::string& inner_message) {
157 SecureMessageDelegate::CreateOptions options;
158 options.encryption_scheme = securemessage::AES_256_CBC;
159 options.signature_scheme = securemessage::HMAC_SHA256;
160 options.public_metadata = CreateEnrollmentPublicMetadata();
162 // The outer message encrypts and signs the inner message with the derived
163 // symmetric session key.
164 secure_message_delegate_->CreateSecureMessage(
165 inner_message, symmetric_key_, options,
166 base::Bind(&CryptAuthEnrollerImpl::OnOuterSecureMessageCreated,
167 weak_ptr_factory_.GetWeakPtr()));
170 void CryptAuthEnrollerImpl::OnOuterSecureMessageCreated(
171 const std::string& outer_message) {
172 cryptauth::FinishEnrollmentRequest request;
173 request.set_enrollment_session_id(setup_info_.enrollment_session_id());
174 request.set_enrollment_message(outer_message);
175 request.set_device_ephemeral_key(session_public_key_);
176 request.set_invocation_reason(invocation_reason_);
178 cryptauth_client_ = client_factory_->CreateInstance();
179 cryptauth_client_->FinishEnrollment(
180 request, base::Bind(&CryptAuthEnrollerImpl::OnFinishEnrollmentSuccess,
181 weak_ptr_factory_.GetWeakPtr()),
182 base::Bind(&CryptAuthEnrollerImpl::OnFinishEnrollmentFailure,
183 weak_ptr_factory_.GetWeakPtr()));
186 void CryptAuthEnrollerImpl::OnFinishEnrollmentSuccess(
187 const cryptauth::FinishEnrollmentResponse& response) {
188 if (response.status() != kResponseStatusOk) {
189 VLOG(1) << "Unexpected status for FinishEnrollment: " << response.status();
190 callback_.Run(false);
191 } else {
192 callback_.Run(true);
196 void CryptAuthEnrollerImpl::OnFinishEnrollmentFailure(
197 const std::string& error) {
198 VLOG(1) << "FinishEnrollment API failed with error: " << error;
199 callback_.Run(false);
202 } // namespace proximity_auth