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"
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
{
16 // A successful SetupEnrollment or FinishEnrollment response should contain this
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.";
33 if (!device_info
.has_key_handle()) {
34 VLOG(1) << "Expected key_handle field in GcmDeviceInfo.";
38 if (!device_info
.has_long_device_id()) {
39 VLOG(1) << "Expected long_device_id field in GcmDeviceInfo.";
43 if (!device_info
.has_device_type()) {
44 VLOG(1) << "Expected device_type field in GcmDeviceInfo.";
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();
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.";
83 device_info_
= device_info
;
84 invocation_reason_
= invocation_reason
;
87 if (!ValidateDeviceInfo(device_info
)) {
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);
121 if (response
.infos_size() == 0) {
122 VLOG(1) << "No response info returned by server for SetupEnrollment";
123 callback_
.Run(false);
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);
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