fido_cable_handshake_handler.cc 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. // Copyright 2018 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. #include "device/fido/cable/fido_cable_handshake_handler.h"
  5. #include <algorithm>
  6. #include <tuple>
  7. #include <utility>
  8. #include "base/bind.h"
  9. #include "base/containers/span.h"
  10. #include "base/strings/string_number_conversions.h"
  11. #include "base/threading/thread_task_runner_handle.h"
  12. #include "components/cbor/reader.h"
  13. #include "components/cbor/values.h"
  14. #include "components/cbor/writer.h"
  15. #include "components/device_event_log/device_event_log.h"
  16. #include "crypto/aead.h"
  17. #include "crypto/hkdf.h"
  18. #include "crypto/hmac.h"
  19. #include "crypto/random.h"
  20. #include "crypto/sha2.h"
  21. #include "device/fido/cable/fido_cable_device.h"
  22. #include "device/fido/cable/noise.h"
  23. #include "device/fido/cable/v2_handshake.h"
  24. #include "device/fido/fido_constants.h"
  25. #include "device/fido/fido_parsing_utils.h"
  26. #include "third_party/boringssl/src/include/openssl/digest.h"
  27. #include "third_party/boringssl/src/include/openssl/ec_key.h"
  28. #include "third_party/boringssl/src/include/openssl/ecdh.h"
  29. #include "third_party/boringssl/src/include/openssl/hkdf.h"
  30. #include "third_party/boringssl/src/include/openssl/obj.h"
  31. #include "third_party/boringssl/src/include/openssl/sha.h"
  32. namespace device {
  33. namespace {
  34. // Length of CBOR encoded authenticator hello message concatenated with
  35. // 16 byte message authentication code.
  36. constexpr size_t kCableAuthenticatorHandshakeMessageSize = 66;
  37. // Length of CBOR encoded client hello message concatenated with 16 byte message
  38. // authenticator code.
  39. constexpr size_t kClientHelloMessageSize = 58;
  40. constexpr size_t kCableHandshakeMacMessageSize = 16;
  41. absl::optional<std::array<uint8_t, kClientHelloMessageSize>>
  42. ConstructHandshakeMessage(base::StringPiece handshake_key,
  43. base::span<const uint8_t, 16> client_random_nonce) {
  44. cbor::Value::MapValue map;
  45. map.emplace(0, kCableClientHelloMessage);
  46. map.emplace(1, client_random_nonce);
  47. auto client_hello = cbor::Writer::Write(cbor::Value(std::move(map)));
  48. DCHECK(client_hello);
  49. crypto::HMAC hmac(crypto::HMAC::SHA256);
  50. if (!hmac.Init(handshake_key))
  51. return absl::nullopt;
  52. std::array<uint8_t, 32> client_hello_mac;
  53. if (!hmac.Sign(fido_parsing_utils::ConvertToStringPiece(*client_hello),
  54. client_hello_mac.data(), client_hello_mac.size())) {
  55. return absl::nullopt;
  56. }
  57. DCHECK_EQ(kClientHelloMessageSize,
  58. client_hello->size() + kCableHandshakeMacMessageSize);
  59. std::array<uint8_t, kClientHelloMessageSize> handshake_message;
  60. std::copy(client_hello->begin(), client_hello->end(),
  61. handshake_message.begin());
  62. std::copy(client_hello_mac.begin(),
  63. client_hello_mac.begin() + kCableHandshakeMacMessageSize,
  64. handshake_message.begin() + client_hello->size());
  65. return handshake_message;
  66. }
  67. } // namespace
  68. FidoCableHandshakeHandler::~FidoCableHandshakeHandler() {}
  69. FidoCableV1HandshakeHandler::FidoCableV1HandshakeHandler(
  70. FidoCableDevice* cable_device,
  71. base::span<const uint8_t, 8> nonce,
  72. base::span<const uint8_t, 32> session_pre_key)
  73. : cable_device_(cable_device),
  74. nonce_(fido_parsing_utils::Materialize(nonce)),
  75. session_pre_key_(fido_parsing_utils::Materialize(session_pre_key)),
  76. handshake_key_(crypto::HkdfSha256(
  77. fido_parsing_utils::ConvertToStringPiece(session_pre_key_),
  78. fido_parsing_utils::ConvertToStringPiece(nonce_),
  79. kCableHandshakeKeyInfo,
  80. /*derived_key_size=*/32)) {
  81. crypto::RandBytes(client_session_random_.data(),
  82. client_session_random_.size());
  83. }
  84. FidoCableV1HandshakeHandler::~FidoCableV1HandshakeHandler() = default;
  85. void FidoCableV1HandshakeHandler::InitiateCableHandshake(
  86. FidoDevice::DeviceCallback callback) {
  87. auto handshake_message =
  88. ConstructHandshakeMessage(handshake_key_, client_session_random_);
  89. if (!handshake_message) {
  90. base::ThreadTaskRunnerHandle::Get()->PostTask(
  91. FROM_HERE, base::BindOnce(std::move(callback), absl::nullopt));
  92. return;
  93. }
  94. FIDO_LOG(DEBUG) << "Sending the caBLE handshake message";
  95. cable_device_->SendHandshakeMessage(
  96. fido_parsing_utils::Materialize(*handshake_message), std::move(callback));
  97. }
  98. bool FidoCableV1HandshakeHandler::ValidateAuthenticatorHandshakeMessage(
  99. base::span<const uint8_t> response) {
  100. crypto::HMAC hmac(crypto::HMAC::SHA256);
  101. if (!hmac.Init(handshake_key_))
  102. return false;
  103. if (response.size() != kCableAuthenticatorHandshakeMessageSize) {
  104. return false;
  105. }
  106. const auto authenticator_hello = response.first(
  107. kCableAuthenticatorHandshakeMessageSize - kCableHandshakeMacMessageSize);
  108. if (!hmac.VerifyTruncated(
  109. fido_parsing_utils::ConvertToStringPiece(authenticator_hello),
  110. fido_parsing_utils::ConvertToStringPiece(
  111. response.subspan(authenticator_hello.size())))) {
  112. return false;
  113. }
  114. const auto authenticator_hello_cbor = cbor::Reader::Read(authenticator_hello);
  115. if (!authenticator_hello_cbor || !authenticator_hello_cbor->is_map() ||
  116. authenticator_hello_cbor->GetMap().size() != 2) {
  117. return false;
  118. }
  119. const auto authenticator_hello_msg =
  120. authenticator_hello_cbor->GetMap().find(cbor::Value(0));
  121. if (authenticator_hello_msg == authenticator_hello_cbor->GetMap().end() ||
  122. !authenticator_hello_msg->second.is_string() ||
  123. authenticator_hello_msg->second.GetString() !=
  124. kCableAuthenticatorHelloMessage) {
  125. return false;
  126. }
  127. const auto authenticator_random_nonce =
  128. authenticator_hello_cbor->GetMap().find(cbor::Value(1));
  129. if (authenticator_random_nonce == authenticator_hello_cbor->GetMap().end() ||
  130. !authenticator_random_nonce->second.is_bytestring() ||
  131. authenticator_random_nonce->second.GetBytestring().size() != 16) {
  132. return false;
  133. }
  134. cable_device_->SetV1EncryptionData(
  135. base::make_span<32>(
  136. GetEncryptionKeyAfterSuccessfulHandshake(base::make_span<16>(
  137. authenticator_random_nonce->second.GetBytestring()))),
  138. nonce_);
  139. return true;
  140. }
  141. std::vector<uint8_t>
  142. FidoCableV1HandshakeHandler::GetEncryptionKeyAfterSuccessfulHandshake(
  143. base::span<const uint8_t, 16> authenticator_random_nonce) const {
  144. std::vector<uint8_t> nonce_message;
  145. fido_parsing_utils::Append(&nonce_message, nonce_);
  146. fido_parsing_utils::Append(&nonce_message, client_session_random_);
  147. fido_parsing_utils::Append(&nonce_message, authenticator_random_nonce);
  148. return crypto::HkdfSha256(session_pre_key_, crypto::SHA256Hash(nonce_message),
  149. kCableDeviceEncryptionKeyInfo,
  150. /*derived_key_length=*/32);
  151. }
  152. } // namespace device