1 /*
2  * Copyright 2021, The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "host/libs/confui/sign.h"
18 
19 #include <openssl/hmac.h>
20 #include <openssl/sha.h>
21 
22 #include <string>
23 
24 #include <android-base/logging.h>
25 
26 #include "common/libs/confui/confui.h"
27 #include "common/libs/fs/shared_fd.h"
28 #include "common/libs/security/confui_sign.h"
29 #include "host/commands/kernel_log_monitor/utils.h"
30 #include "host/libs/config/cuttlefish_config.h"
31 #include "host/libs/confui/sign_utils.h"
32 
33 namespace cuttlefish {
34 namespace confui {
35 namespace {
GetSecureEnvSocketPath()36 std::string GetSecureEnvSocketPath() {
37   auto config = cuttlefish::CuttlefishConfig::Get();
38   CHECK(config) << "Config must not be null";
39   auto instance = config->ForDefaultInstance();
40   return instance.PerInstanceInternalUdsPath("confui_sign.sock");
41 }
42 
43 /**
44  * the secure_env signing server may be on slightly later than
45  * confirmation UI host/webRTC process.
46  */
ConnectToSecureEnv()47 SharedFD ConnectToSecureEnv() {
48   auto socket_path = GetSecureEnvSocketPath();
49   SharedFD socket_to_secure_env =
50       SharedFD::SocketLocalClient(socket_path, false, SOCK_STREAM);
51   return socket_to_secure_env;
52 }
53 }  // end of namespace
54 
55 class HMacImplementation {
56  public:
57   static std::optional<support::hmac_t> hmac256(
58       const support::auth_token_key_t& key,
59       std::initializer_list<support::ByteBufferProxy> buffers);
60 };
61 
hmac256(const support::auth_token_key_t & key,std::initializer_list<support::ByteBufferProxy> buffers)62 std::optional<support::hmac_t> HMacImplementation::hmac256(
63     const support::auth_token_key_t& key,
64     std::initializer_list<support::ByteBufferProxy> buffers) {
65   HMAC_CTX hmacCtx;
66   HMAC_CTX_init(&hmacCtx);
67   if (!HMAC_Init_ex(&hmacCtx, key.data(), key.size(), EVP_sha256(), nullptr)) {
68     return {};
69   }
70   for (auto& buffer : buffers) {
71     if (!HMAC_Update(&hmacCtx, buffer.data(), buffer.size())) {
72       return {};
73     }
74   }
75   support::hmac_t result;
76   if (!HMAC_Final(&hmacCtx, result.data(), nullptr)) {
77     return {};
78   }
79   return result;
80 }
81 
82 /**
83  * The test key is 32byte word with all bytes set to TestKeyBits::BYTE.
84  */
85 enum class TestKeyBits : uint8_t {
86   BYTE = 165 /* 0xA5 */,
87 };
88 
TestSign(const std::vector<std::uint8_t> & message)89 std::optional<std::vector<std::uint8_t>> TestSign(
90     const std::vector<std::uint8_t>& message) {
91   // the same as userConfirm()
92   using namespace support;
93   auth_token_key_t key;
94   key.fill(static_cast<std::uint8_t>(TestKeyBits::BYTE));
95   using HMacer = HMacImplementation;
96   auto confirm_signed_opt =
97       HMacer::hmac256(key, {"confirmation token", message});
98   if (!confirm_signed_opt) {
99     return std::nullopt;
100   }
101   auto confirm_signed = confirm_signed_opt.value();
102   return {
103       std::vector<std::uint8_t>(confirm_signed.begin(), confirm_signed.end())};
104 }
105 
Sign(const std::vector<std::uint8_t> & message)106 std::optional<std::vector<std::uint8_t>> Sign(
107     const std::vector<std::uint8_t>& message) {
108   SharedFD socket_to_secure_env = ConnectToSecureEnv();
109   if (!socket_to_secure_env->IsOpen()) {
110     ConfUiLog(ERROR) << "Failed to connect to secure_env signing server.";
111     return std::nullopt;
112   }
113   ConfUiSignRequester sign_client(socket_to_secure_env);
114   // request signature
115   sign_client.Request(message);
116   auto response_opt = sign_client.Receive();
117   if (!response_opt) {
118     ConfUiLog(ERROR) << "Received nullopt";
119     return std::nullopt;
120   }
121   // respond should be either error code or the signature
122   auto response = std::move(response_opt.value());
123   if (response.error_ != SignMessageError::kOk) {
124     ConfUiLog(ERROR) << "Response was received with non-OK error code";
125     return std::nullopt;
126   }
127   return {response.payload_};
128 }
129 }  // namespace confui
130 }  // end of namespace cuttlefish
131