OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2017 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. | |
4 | |
5 #include "components/webauth/authenticator_impl.h" | |
6 | |
7 #include <memory> | |
8 | |
9 #include "base/json/json_writer.h" | |
10 #include "base/memory/ptr_util.h" | |
11 #include "content/public/browser/render_frame_host.h" | |
12 #include "content/public/browser/web_contents.h" | |
13 #include "crypto/sha2.h" | |
14 #include "mojo/public/cpp/bindings/strong_binding.h" | |
15 | |
16 using content::RenderFrameHost; | |
17 using content::WebContents; | |
18 | |
19 namespace webauth { | |
20 | |
21 const char kGetAssertionType[] = "navigator.id.getAssertion"; | |
22 | |
23 // JSON key values | |
24 const char kTypeKey[] = "type"; | |
25 const char kChallengeKey[] = "challenge"; | |
26 const char kOriginKey[] = "origin"; | |
27 const char kCidPubkeyKey[] = "cid_pubkey"; | |
28 | |
29 // Serializes the |value| to a JSON string and returns the result. | |
30 std::string SerializeValueToJson(const base::Value& value) { | |
31 std::string json; | |
32 base::JSONWriter::Write(value, &json); | |
33 return json; | |
34 } | |
35 | |
36 // static | |
37 void AuthenticatorImpl::Create(RenderFrameHost* render_frame_host, | |
38 mojom::AuthenticatorRequest request) { | |
39 auto authenticator_impl = | |
40 base::WrapUnique(new AuthenticatorImpl(render_frame_host)); | |
41 mojo::MakeStrongBinding(std::move(authenticator_impl), std::move(request)); | |
42 } | |
43 | |
44 AuthenticatorImpl::~AuthenticatorImpl() { | |
45 if (!connection_error_handler_.is_null()) | |
46 connection_error_handler_.Run(); | |
47 } | |
48 | |
49 AuthenticatorImpl::AuthenticatorImpl(RenderFrameHost* render_frame_host) { | |
50 DCHECK(render_frame_host); | |
51 set_connection_error_handler(base::Bind( | |
52 &AuthenticatorImpl::OnConnectionTerminated, base::Unretained(this))); | |
53 callerOrigin_ = render_frame_host->GetLastCommittedOrigin(); | |
54 } | |
55 | |
56 // mojom:Authenticator | |
57 void AuthenticatorImpl::MakeCredential( | |
58 mojom::RelyingPartyAccountPtr account, | |
59 std::vector<mojom::ScopedCredentialParametersPtr> parameters, | |
60 const std::vector<uint8_t>& challenge, | |
61 mojom::ScopedCredentialOptionsPtr options, | |
62 MakeCredentialCallback callback) { | |
63 std::string effectiveDomain; | |
64 std::string relyingPartyId; | |
65 std::string clientDataJSON; | |
66 base::DictionaryValue clientData; | |
jochen (gone - plz use gerrit)
2017/05/30 12:03:02
should all be like effective_domain etc..
kpaulhamus
2017/05/31 20:56:05
Done.
| |
67 | |
68 // Steps 3 & 4 of https://w3c.github.io/webauthn/#makeCredential | |
69 // opaque origin | |
70 if (callerOrigin_.Serialize() == "") { | |
jochen (gone - plz use gerrit)
2017/05/30 12:03:02
caller_origin_.unique()
kpaulhamus
2017/05/31 20:56:05
Done.
| |
71 std::move(callback).Run(mojom::AuthenticatorStatus::NOT_ALLOWED_ERROR, | |
72 NULL); | |
73 return; | |
74 } | |
75 | |
76 if (!options->relying_party_id) { | |
77 relyingPartyId = callerOrigin_.Serialize(); | |
78 } else { | |
79 effectiveDomain = callerOrigin_.host(); | |
80 | |
81 if (effectiveDomain.empty()) { | |
82 std::move(callback).Run(mojom::AuthenticatorStatus::SECURITY_ERROR, NULL); | |
83 return; | |
84 } | |
85 // TODO(kpaulhamus): Check if relyingPartyId is a registrable domain | |
86 // suffix of and equal to effectiveDomain and set relyingPartyId | |
87 // appropriately. | |
88 relyingPartyId = options->relying_party_id.value_or(std::string()); | |
89 } | |
90 | |
91 // TODO(kpaulhamus): Check ScopedCredentialParameter's type and | |
92 // algorithmIdentifier after algorithmIdentifier is added to mojom to | |
93 // make sure it is U2F_V2. | |
94 | |
95 clientData.SetString(kTypeKey, kGetAssertionType); | |
96 clientData.SetString( | |
97 kChallengeKey, | |
98 base::StringPiece(reinterpret_cast<const char*>(challenge.data()), | |
99 challenge.size())); | |
100 clientData.SetString(kOriginKey, relyingPartyId); | |
101 // Channel ID is optional, and missing if the browser doesn't support it. | |
102 // It is present and set to the constant "unused" if the browser | |
103 // supports Channel ID but is not using it to talk to the origin. | |
104 // TODO(kpaulhamus): Fetch and add the Channel ID public key used to | |
105 // communicate with the origin. | |
106 clientData.SetString(kCidPubkeyKey, "unused"); | |
107 | |
108 // SHA-256 hash the JSON data structure | |
109 clientDataJSON = SerializeValueToJson(clientData); | |
110 std::string clientDataHash = crypto::SHA256HashString(clientDataJSON); | |
111 | |
112 auto copyable_callback = base::AdaptCallbackForRepeating(std::move(callback)); | |
113 | |
114 // Step 16 of https://w3c.github.io/webauthn/#makeCredential | |
115 timeout_callback_.Reset(base::Bind(&AuthenticatorImpl::OnTimeout, | |
116 base::Unretained(this), | |
117 copyable_callback)); | |
118 | |
119 // base::Unretained(this), Passed(&callback))); | |
120 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( | |
121 FROM_HERE, timeout_callback_.callback(), | |
122 base::TimeDelta::FromSecondsD(options->adjusted_timeout)); | |
123 | |
124 // Per fido-u2f-raw-message-formats: | |
125 // The challenge parameter is the SHA-256 hash of the Client Data, | |
126 // a stringified JSON data structure that the FIDO Client prepares. | |
127 // Among other things, the Client Data contains the challenge from the | |
128 // relying party (hence the name of the parameter). | |
129 // The application parameter is the SHA-256 hash of the UTF-8 encoding of | |
130 // the application identity of the application requesting the registration | |
131 /* | |
132 U2fRegister(clientDataHash, app_param, base::Bind( | |
133 &AuthenticatorImpl::onRegister, weak_factory_.GetWeakPtr(), | |
134 std::move(clientDataJSON), callback)); | |
135 */ | |
136 | |
137 timeout_callback_.Cancel(); | |
138 std::move(callback).Run(mojom::AuthenticatorStatus::NOT_ALLOWED_ERROR, NULL); | |
139 } | |
140 | |
141 // Callback to handle the async response from a U2fDevice. | |
142 void AuthenticatorImpl::OnRegister(MakeCredentialCallback callback, | |
143 std::string& clientDataJSON, | |
144 uint8_t status_code, | |
145 std::vector<uint8_t> data) { | |
146 timeout_callback_.Cancel(); | |
147 std::move(callback).Run(mojom::AuthenticatorStatus::NOT_ALLOWED_ERROR, NULL); | |
148 } | |
149 | |
150 // Runs when timer expires and cancels all issued requests to a U2fDevice. | |
151 void AuthenticatorImpl::OnTimeout(MakeCredentialCallback callback) { | |
152 std::move(callback).Run(mojom::AuthenticatorStatus::NOT_ALLOWED_ERROR, NULL); | |
153 } | |
154 | |
155 void AuthenticatorImpl::OnConnectionTerminated() { | |
156 // Closures and cleanup due to either a browser-side error or | |
157 // as a result of the connection_error_handler, which can mean | |
158 // that the renderer has decided to close the pipe for various | |
159 // reasons. | |
160 } | |
161 } // namespace webauth | |
OLD | NEW |